refactor side nav to make it composable
This commit is contained in:
@@ -1,43 +0,0 @@
|
|||||||
import { Link, useRouterState, useNavigate } from "@tanstack/react-router"
|
|
||||||
import { useMnemonics } from "~/hooks/use-mnemonics"
|
|
||||||
|
|
||||||
function SideNav({ enableMnemonics }: { enableMnemonics: boolean }) {
|
|
||||||
const navigate = useNavigate()
|
|
||||||
|
|
||||||
useMnemonics(
|
|
||||||
{
|
|
||||||
b: () => navigate({ to: "/bookmarks" }),
|
|
||||||
c: () => navigate({ to: "/collections" }),
|
|
||||||
},
|
|
||||||
{ ignore: () => !enableMnemonics },
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<aside className="mb-4 md:mb-0 md:mr-24 text-start">
|
|
||||||
<nav className="mb-8">
|
|
||||||
<ul className="flex flex-col space-y-2">
|
|
||||||
<NavItem to="/bookmarks" label="BOOKMARKS" />
|
|
||||||
<NavItem to="/collections" label="COLLECTIONS" />
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function NavItem({ to, label }: { to: string; label: string }) {
|
|
||||||
const currentPath = useRouterState({ select: (state) => state.location.pathname })
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<Link to={to}>
|
|
||||||
<span className="font-bold">[{currentPath === to ? "•" : " "}]</span>{" "}
|
|
||||||
<span className={currentPath === to ? "font-bold" : ""}>
|
|
||||||
<span className="underline">{label.charAt(0)}</span>
|
|
||||||
{label.substring(1)}
|
|
||||||
</span>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export { SideNav }
|
|
@@ -9,11 +9,11 @@ import { useTags } from "~/bookmark/api.ts"
|
|||||||
import { Button } from "~/components/button"
|
import { Button } from "~/components/button"
|
||||||
import { LoadingSpinner } from "~/components/loading-spinner"
|
import { LoadingSpinner } from "~/components/loading-spinner"
|
||||||
import { Message, MessageVariant } from "~/components/message.tsx"
|
import { Message, MessageVariant } from "~/components/message.tsx"
|
||||||
|
import { SideNav, SideNavItem } from "~/components/side-nav"
|
||||||
import { useDocumentEvent } from "~/hooks/use-document-event.ts"
|
import { useDocumentEvent } from "~/hooks/use-document-event.ts"
|
||||||
import { useMnemonics } from "~/hooks/use-mnemonics.ts"
|
import { useMnemonics } from "~/hooks/use-mnemonics.ts"
|
||||||
import { BookmarkList } from "./-bookmark-list"
|
import { BookmarkList } from "./-bookmark-list"
|
||||||
import { ActionBarContentKind, DialogKind, WindowKind, useBookmarkPageStore } from "./-store"
|
import { ActionBarContentKind, DialogKind, WindowKind, useBookmarkPageStore } from "./-store"
|
||||||
import { SideNav } from "~/app/-side-nav"
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/bookmarks/")({
|
export const Route = createFileRoute("/bookmarks/")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
@@ -40,11 +40,27 @@ function BookmarkListPane() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _SideNav() {
|
function _SideNav() {
|
||||||
const hasDialog = useBookmarkPageStore((state) => state.dialog.kind !== DialogKind.None)
|
const navigate = useNavigate()
|
||||||
const isSearchBarActive = useBookmarkPageStore(
|
|
||||||
(state) => state.actionBarContent.kind === ActionBarContentKind.SearchBar,
|
useMnemonics(
|
||||||
|
{
|
||||||
|
b: () => navigate({ to: "/bookmarks" }),
|
||||||
|
c: () => navigate({ to: "/collections" }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignore: () => {
|
||||||
|
const state = useBookmarkPageStore.getState()
|
||||||
|
return state.dialog.kind !== DialogKind.None || state.actionBarContent.kind === ActionBarContentKind.SearchBar
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SideNav>
|
||||||
|
<SideNavItem to="/bookmarks" label="BOOKMARKS" active />
|
||||||
|
<SideNavItem to="/collections" label="COLLECTIONS" />
|
||||||
|
</SideNav>
|
||||||
)
|
)
|
||||||
return <SideNav enableMnemonics={!hasDialog && !isSearchBarActive} />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function BookmarkListContainer() {
|
function BookmarkListContainer() {
|
||||||
|
@@ -6,12 +6,12 @@ import { useLogOut } from "~/auth"
|
|||||||
import { useCollections } from "~/collection/api"
|
import { useCollections } from "~/collection/api"
|
||||||
import { Button } from "~/components/button"
|
import { Button } from "~/components/button"
|
||||||
import { LoadingSpinner } from "~/components/loading-spinner"
|
import { LoadingSpinner } from "~/components/loading-spinner"
|
||||||
|
import { SideNav, SideNavItem } from "~/components/side-nav"
|
||||||
import { useMnemonics } from "~/hooks/use-mnemonics"
|
import { useMnemonics } from "~/hooks/use-mnemonics"
|
||||||
import { CollectionList } from "./-collection-list"
|
import { CollectionList } from "./-collection-list"
|
||||||
import { AddCollectionDialog } from "./-dialogs/add-collection-dialog"
|
import { AddCollectionDialog } from "./-dialogs/add-collection-dialog"
|
||||||
import { DeleteCollectionDialog } from "./-dialogs/delete-collection-dialog"
|
import { DeleteCollectionDialog } from "./-dialogs/delete-collection-dialog"
|
||||||
import { DialogKind, WindowKind, useCollectionPageStore } from "./-store"
|
import { DialogKind, WindowKind, useCollectionPageStore } from "./-store"
|
||||||
import { SideNav } from "~/app/-side-nav"
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/collections/")({
|
export const Route = createFileRoute("/collections/")({
|
||||||
component: CollectionsPage,
|
component: CollectionsPage,
|
||||||
@@ -52,8 +52,27 @@ function CollectionsPane() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _SideNav() {
|
function _SideNav() {
|
||||||
const hasDialog = useCollectionPageStore((state) => state.dialog.kind !== DialogKind.None)
|
const navigate = useNavigate()
|
||||||
return <SideNav enableMnemonics={!hasDialog} />
|
|
||||||
|
useMnemonics(
|
||||||
|
{
|
||||||
|
b: () => navigate({ to: "/bookmarks" }),
|
||||||
|
c: () => navigate({ to: "/collections" }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignore: () => {
|
||||||
|
const state = useCollectionPageStore.getState()
|
||||||
|
return state.dialog.kind !== DialogKind.None
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SideNav>
|
||||||
|
<SideNavItem to="/bookmarks" label="BOOKMARKS" />
|
||||||
|
<SideNavItem to="/collections" label="COLLECTIONS" active />
|
||||||
|
</SideNav>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function CollectionsContainer() {
|
function CollectionsContainer() {
|
||||||
|
27
packages/web/src/components/side-nav.tsx
Normal file
27
packages/web/src/components/side-nav.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Link } from "@tanstack/react-router"
|
||||||
|
|
||||||
|
function SideNav({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<aside className="mb-4 md:mb-0 md:mr-24 text-start">
|
||||||
|
<nav className="mb-8">
|
||||||
|
<ul className="flex flex-col space-y-2">{children}</ul>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SideNavItem({ to, label, active = false }: { to: string; label: string; active?: boolean }) {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<Link to={to}>
|
||||||
|
<span className="font-bold">[{active ? "•" : " "}]</span>{" "}
|
||||||
|
<span className={active ? "font-bold" : ""}>
|
||||||
|
<span className="underline">{label.charAt(0)}</span>
|
||||||
|
{label.substring(1)}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SideNav, SideNavItem }
|
Reference in New Issue
Block a user