import { useQuery } from "@tanstack/react-query"; import { LogOut, Menu } from "lucide-react"; import { useEffect, useState } from "react"; import { Link, NavLink, Outlet, useLocation, useNavigationType } from "react-router-dom"; import { CommandPalette } from "@/components/CommandPalette"; import { StatusFooter } from "@/components/StatusFooter"; import { StatusPill } from "@/components/StatusPill"; import { api } from "@/lib/api"; import { cn } from "@/lib/cn"; import type { SystemStatus } from "@/lib/types"; import { useAuth } from "@/store/auth"; import { useE621 } from "@/store/e621"; import { useUi } from "@/store/ui"; export function AppShell() { const user = useAuth((state) => state.user); const logout = useAuth((state) => state.logout); const toggleSidebar = useUi((state) => state.toggleSidebar); const loadE621 = useE621((state) => state.load); const location = useLocation(); const [paletteOpen, setPaletteOpen] = useState(false); useEffect(() => { void loadE621(); }, [loadE621]); const statusQuery = useQuery({ queryKey: ["status"], queryFn: () => api("/api/status/"), refetchInterval: 5_000, staleTime: 4_000, }); const status = statusQuery.data; useEffect(() => { function handleKeyDown(event: KeyboardEvent) { const modifier = event.ctrlKey || event.metaKey; if (modifier && event.key.toLowerCase() === "b") { event.preventDefault(); toggleSidebar(); return; } if (modifier && event.key.toLowerCase() === "k") { event.preventDefault(); setPaletteOpen((open) => !open); return; } if (event.key === "Escape") { setPaletteOpen(false); } } window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [toggleSidebar]); const showSidebarToggle = location.pathname === "/" || location.pathname === "/online"; const navItems = [ { to: "/", label: "Library" }, { to: "/online", label: "Online" }, { to: "/pools", label: "Pools" }, ...(user ? [{ to: "/followed", label: "Followed" }] : []), ...(user ? [{ to: "/similar", label: "Similar" }] : []), ...(user?.can_upload ? [ { to: "/upload", label: "Upload" }, { to: "/duplicates", label: "Duplicates" }, { to: "/delete", label: "Delete" }, ] : []), ...(user && (user.is_staff || user.is_superuser || user.role === "staff") ? [ { to: "/stats", label: "Stats" }, { to: "/users", label: "Users" }, ] : []), ]; const navigationType = useNavigationType(); useEffect(() => { // New navigations start at the top; history back/forward keeps position. if (navigationType === "POP") return; window.scrollTo({ top: 0 }); }, [location.pathname, navigationType]); return (
J621 {showSidebarToggle ? ( ) : null}
{user ? ( <> {user.avatar_url ? ( {user.username} ) : ( {user.username.slice(0, 1).toUpperCase()} )} {user.username} ) : ( Log in )}
setPaletteOpen(false)} />
); }