From db428c04d1d92c9d4d38d20d8814b5f168aea03a Mon Sep 17 00:00:00 2001
From: Lim Chee Aun <cheeaun@gmail.com>
Date: Mon, 6 Feb 2023 23:47:58 +0800
Subject: [PATCH] Scoped keyboard shortcuts

---
 src/pages/home.jsx | 214 ++++++++++++++++++++++-----------------------
 1 file changed, 103 insertions(+), 111 deletions(-)

diff --git a/src/pages/home.jsx b/src/pages/home.jsx
index 4f332bcc..95378351 100644
--- a/src/pages/home.jsx
+++ b/src/pages/home.jsx
@@ -21,7 +21,6 @@ function Home({ hidden }) {
   useTitle('Home', '/');
   const { masto, instance } = api();
   const snapStates = useSnapshot(states);
-  const isHomeLocation = snapStates.currentLocation === '/';
   const [uiState, setUIState] = useState('default');
   const [showMore, setShowMore] = useState(false);
 
@@ -149,121 +148,103 @@ function Home({ hidden }) {
 
   const scrollableRef = useRef();
 
-  useHotkeys(
-    'j, shift+j',
-    (_, handler) => {
-      // focus on next status after active status
-      // Traverses .timeline li .status-link, focus on .status-link
-      const activeStatus = document.activeElement.closest(
+  const jRef = useHotkeys('j, shift+j', (_, handler) => {
+    // focus on next status after active status
+    // Traverses .timeline li .status-link, focus on .status-link
+    const activeStatus = document.activeElement.closest(
+      '.status-link, .status-boost-link',
+    );
+    const activeStatusRect = activeStatus?.getBoundingClientRect();
+    const allStatusLinks = Array.from(
+      scrollableRef.current.querySelectorAll(
         '.status-link, .status-boost-link',
-      );
-      const activeStatusRect = activeStatus?.getBoundingClientRect();
-      const allStatusLinks = Array.from(
-        scrollableRef.current.querySelectorAll(
-          '.status-link, .status-boost-link',
-        ),
-      );
-      if (
-        activeStatus &&
-        activeStatusRect.top < scrollableRef.current.clientHeight &&
-        activeStatusRect.bottom > 0
-      ) {
-        const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
-        let nextStatus = allStatusLinks[activeStatusIndex + 1];
-        if (handler.shift) {
-          // get next status that's not .status-boost-link
-          nextStatus = allStatusLinks.find(
-            (statusLink, index) =>
-              index > activeStatusIndex &&
-              !statusLink.classList.contains('status-boost-link'),
-          );
-        }
-        if (nextStatus) {
-          nextStatus.focus();
-          nextStatus.scrollIntoViewIfNeeded?.();
-        }
-      } else {
-        // If active status is not in viewport, get the topmost status-link in viewport
-        const topmostStatusLink = allStatusLinks.find((statusLink) => {
-          const statusLinkRect = statusLink.getBoundingClientRect();
-          return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
-        });
-        if (topmostStatusLink) {
-          topmostStatusLink.focus();
-          topmostStatusLink.scrollIntoViewIfNeeded?.();
-        }
+      ),
+    );
+    if (
+      activeStatus &&
+      activeStatusRect.top < scrollableRef.current.clientHeight &&
+      activeStatusRect.bottom > 0
+    ) {
+      const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
+      let nextStatus = allStatusLinks[activeStatusIndex + 1];
+      if (handler.shift) {
+        // get next status that's not .status-boost-link
+        nextStatus = allStatusLinks.find(
+          (statusLink, index) =>
+            index > activeStatusIndex &&
+            !statusLink.classList.contains('status-boost-link'),
+        );
       }
-    },
-    {
-      enabled: isHomeLocation,
-    },
-  );
+      if (nextStatus) {
+        nextStatus.focus();
+        nextStatus.scrollIntoViewIfNeeded?.();
+      }
+    } else {
+      // If active status is not in viewport, get the topmost status-link in viewport
+      const topmostStatusLink = allStatusLinks.find((statusLink) => {
+        const statusLinkRect = statusLink.getBoundingClientRect();
+        return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
+      });
+      if (topmostStatusLink) {
+        topmostStatusLink.focus();
+        topmostStatusLink.scrollIntoViewIfNeeded?.();
+      }
+    }
+  });
 
-  useHotkeys(
-    'k, shift+k',
-    (_, handler) => {
-      // focus on previous status after active status
-      // Traverses .timeline li .status-link, focus on .status-link
-      const activeStatus = document.activeElement.closest(
+  const kRef = useHotkeys('k, shift+k', (_, handler) => {
+    // focus on previous status after active status
+    // Traverses .timeline li .status-link, focus on .status-link
+    const activeStatus = document.activeElement.closest(
+      '.status-link, .status-boost-link',
+    );
+    const activeStatusRect = activeStatus?.getBoundingClientRect();
+    const allStatusLinks = Array.from(
+      scrollableRef.current.querySelectorAll(
         '.status-link, .status-boost-link',
-      );
-      const activeStatusRect = activeStatus?.getBoundingClientRect();
-      const allStatusLinks = Array.from(
-        scrollableRef.current.querySelectorAll(
-          '.status-link, .status-boost-link',
-        ),
-      );
-      if (
-        activeStatus &&
-        activeStatusRect.top < scrollableRef.current.clientHeight &&
-        activeStatusRect.bottom > 0
-      ) {
-        const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
-        let prevStatus = allStatusLinks[activeStatusIndex - 1];
-        if (handler.shift) {
-          // get prev status that's not .status-boost-link
-          prevStatus = allStatusLinks.findLast(
-            (statusLink, index) =>
-              index < activeStatusIndex &&
-              !statusLink.classList.contains('status-boost-link'),
-          );
-        }
-        if (prevStatus) {
-          prevStatus.focus();
-          prevStatus.scrollIntoViewIfNeeded?.();
-        }
-      } else {
-        // If active status is not in viewport, get the topmost status-link in viewport
-        const topmostStatusLink = allStatusLinks.find((statusLink) => {
-          const statusLinkRect = statusLink.getBoundingClientRect();
-          return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
-        });
-        if (topmostStatusLink) {
-          topmostStatusLink.focus();
-          topmostStatusLink.scrollIntoViewIfNeeded?.();
-        }
+      ),
+    );
+    if (
+      activeStatus &&
+      activeStatusRect.top < scrollableRef.current.clientHeight &&
+      activeStatusRect.bottom > 0
+    ) {
+      const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
+      let prevStatus = allStatusLinks[activeStatusIndex - 1];
+      if (handler.shift) {
+        // get prev status that's not .status-boost-link
+        prevStatus = allStatusLinks.findLast(
+          (statusLink, index) =>
+            index < activeStatusIndex &&
+            !statusLink.classList.contains('status-boost-link'),
+        );
       }
-    },
-    {
-      enabled: isHomeLocation,
-    },
-  );
+      if (prevStatus) {
+        prevStatus.focus();
+        prevStatus.scrollIntoViewIfNeeded?.();
+      }
+    } else {
+      // If active status is not in viewport, get the topmost status-link in viewport
+      const topmostStatusLink = allStatusLinks.find((statusLink) => {
+        const statusLinkRect = statusLink.getBoundingClientRect();
+        return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
+      });
+      if (topmostStatusLink) {
+        topmostStatusLink.focus();
+        topmostStatusLink.scrollIntoViewIfNeeded?.();
+      }
+    }
+  });
 
-  useHotkeys(
-    ['enter', 'o'],
-    () => {
-      // open active status
-      const activeStatus = document.activeElement.closest(
-        '.status-link, .status-boost-link',
-      );
-      if (activeStatus) {
-        activeStatus.click();
-      }
-    },
-    {
-      enabled: isHomeLocation,
-    },
-  );
+  const oRef = useHotkeys(['enter', 'o'], () => {
+    // open active status
+    const activeStatus = document.activeElement.closest(
+      '.status-link, .status-boost-link',
+    );
+    if (activeStatus) {
+      activeStatus.click();
+    }
+  });
 
   const {
     scrollDirection,
@@ -306,6 +287,12 @@ function Home({ hidden }) {
   const [showUpdatesButton, setShowUpdatesButton] = useState(false);
   useEffect(() => {
     const isNewAndTop = snapStates.homeNew.length > 0 && reachStart;
+    console.log(
+      'isNewAndTop',
+      isNewAndTop,
+      snapStates.homeNew.length,
+      reachStart,
+    );
     setShowUpdatesButton(isNewAndTop);
   }, [snapStates.homeNew.length]);
 
@@ -315,7 +302,12 @@ function Home({ hidden }) {
         id="home-page"
         class="deck-container"
         hidden={hidden}
-        ref={scrollableRef}
+        ref={(node) => {
+          scrollableRef.current = node;
+          jRef.current = node;
+          kRef.current = node;
+          oRef.current = node;
+        }}
         tabIndex="-1"
       >
         <div class="timeline-deck deck">