From 81ebb610965ac519a6fd18ac83a4706e03986e69 Mon Sep 17 00:00:00 2001
From: Lim Chee Aun <cheeaun@gmail.com>
Date: Fri, 10 Feb 2023 13:39:46 +0800
Subject: [PATCH] Sneak in this little menu
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

And… fix title leak bug
---
 src/app.css                 |  8 +++++++
 src/components/icon.jsx     |  1 +
 src/components/link.jsx     |  6 +++--
 src/components/timeline.jsx | 48 ++++++++++++++++++++++++++++++++++++-
 src/pages/following.jsx     |  4 ++--
 src/pages/home.jsx          | 18 +-------------
 6 files changed, 63 insertions(+), 22 deletions(-)

diff --git a/src/app.css b/src/app.css
index 57189fcb..bad39b57 100644
--- a/src/app.css
+++ b/src/app.css
@@ -998,10 +998,18 @@ button.carousel-dot:is(.active, [disabled].active) {
 }
 .szh-menu .szh-menu__item {
   padding: 8px 16px !important;
+  transition: all 0.1s ease-in-out;
 }
 .szh-menu .szh-menu__item * {
   vertical-align: middle;
 }
+.szh-menu .szh-menu__item a {
+  display: block;
+  color: inherit;
+  text-decoration: none;
+  padding: 8px 16px !important;
+  margin: -8px -16px !important;
+}
 .szh-menu
   .szh-menu__item:not(.szh-menu__item--disabled, .szh-menu__item--hover) {
   color: var(--text-color);
diff --git a/src/components/icon.jsx b/src/components/icon.jsx
index 088050d8..896c1dba 100644
--- a/src/components/icon.jsx
+++ b/src/components/icon.jsx
@@ -48,6 +48,7 @@ const ICONS = {
   thread: 'mingcute:route-line',
   group: 'mingcute:group-line',
   bot: 'mingcute:android-2-line',
+  menu: 'mingcute:rows-4-line',
 };
 
 const modules = import.meta.glob('/node_modules/@iconify-icons/mingcute/*.js');
diff --git a/src/components/link.jsx b/src/components/link.jsx
index c55084c6..ba4886d7 100644
--- a/src/components/link.jsx
+++ b/src/components/link.jsx
@@ -1,3 +1,4 @@
+import { forwardRef } from 'preact/compat';
 import { useLocation } from 'react-router-dom';
 
 import states from '../utils/states';
@@ -10,7 +11,7 @@ import states from '../utils/states';
    3. Not using <Link state/> because it modifies history.state that *persists* across page reloads. I don't need that, so using valtio's states instead.
 */
 
-const Link = (props) => {
+const Link = forwardRef((props, ref) => {
   let routerLocation;
   try {
     routerLocation = useLocation();
@@ -21,6 +22,7 @@ const Link = (props) => {
   const isActive = hash === to;
   return (
     <a
+      ref={ref}
       href={`#${to}`}
       {...restProps}
       class={`${props.class || ''} ${isActive ? 'is-active' : ''}`}
@@ -30,6 +32,6 @@ const Link = (props) => {
       }}
     />
   );
-};
+});
 
 export default Link;
diff --git a/src/components/timeline.jsx b/src/components/timeline.jsx
index c0fb39b7..b5a5c835 100644
--- a/src/components/timeline.jsx
+++ b/src/components/timeline.jsx
@@ -1,7 +1,9 @@
+import { FocusableItem, Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
 import { useEffect, useRef, useState } from 'preact/hooks';
 import { useHotkeys } from 'react-hotkeys-hook';
 import { useDebouncedCallback } from 'use-debounce';
 
+import states from '../utils/states';
 import useInterval from '../utils/useInterval';
 import usePageVisibility from '../utils/usePageVisibility';
 import useScroll from '../utils/useScroll';
@@ -254,7 +256,35 @@ function Timeline({
         >
           <div class="header-grid">
             <div class="header-side">
-              {headerStart || (
+              <Menu
+                menuButton={
+                  <button type="button" class="button plain">
+                    <Icon icon="menu" size="l" />
+                  </button>
+                }
+              >
+                <MenuLink to="/">
+                  <Icon icon="home" size="l" /> <span>Home</span>
+                </MenuLink>
+                <MenuLink to="/b">
+                  <Icon icon="bookmark" size="l" /> <span>Bookmarks</span>
+                </MenuLink>
+                <MenuLink to="/f">
+                  <Icon icon="heart" size="l" /> <span>Favourites</span>
+                </MenuLink>
+                <MenuDivider />
+                <MenuItem
+                  onClick={() => {
+                    states.showSettings = true;
+                  }}
+                >
+                  <Icon icon="gear" size="l" alt="Settings" />{' '}
+                  <span>Settings</span>
+                </MenuItem>
+              </Menu>
+              {headerStart !== null && headerStart !== undefined ? (
+                headerStart
+              ) : (
                 <Link to="/" class="button plain">
                   <Icon icon="home" size="l" />
                 </Link>
@@ -379,6 +409,22 @@ function Timeline({
   );
 }
 
+function MenuLink(props) {
+  return (
+    <FocusableItem>
+      {({ ref, closeMenu }) => (
+        <Link
+          {...props}
+          ref={ref}
+          onClick={({ detail }) =>
+            closeMenu(detail === 0 ? 'Enter' : undefined)
+          }
+        />
+      )}
+    </FocusableItem>
+  );
+}
+
 function groupBoosts(values) {
   let newValues = [];
   let boostStash = [];
diff --git a/src/pages/following.jsx b/src/pages/following.jsx
index 85c536e7..c9954e39 100644
--- a/src/pages/following.jsx
+++ b/src/pages/following.jsx
@@ -11,8 +11,8 @@ import useTitle from '../utils/useTitle';
 
 const LIMIT = 20;
 
-function Following({ title, id, headerStart }) {
-  useTitle('Following', '/l/f');
+function Following({ title, path, id, headerStart }) {
+  useTitle(title || 'Following', path, '/l/f');
   const { masto, instance } = api();
   const snapStates = useSnapshot(states);
   const homeIterator = useRef();
diff --git a/src/pages/home.jsx b/src/pages/home.jsx
index a4dcf1c3..41292527 100644
--- a/src/pages/home.jsx
+++ b/src/pages/home.jsx
@@ -24,23 +24,7 @@ function Home() {
 
   return (
     <>
-      <Following
-        title="Home"
-        id="home"
-        headerStart={
-          <button
-            type="button"
-            class="plain"
-            onClick={(e) => {
-              e.preventDefault();
-              e.stopPropagation();
-              states.showSettings = true;
-            }}
-          >
-            <Icon icon="gear" size="l" alt="Settings" />
-          </button>
-        }
-      />
+      <Following title="Home" path="/" id="home" headerStart={false} />
       <button
         // hidden={scrollDirection === 'end' && !nearReachStart}
         type="button"