Files
DorkNet/DorkNet.Server/admin-ui/src/components/Layout.tsx
T
Alexa bb04782e11 chore(deps): clear Dependabot alerts — React 19, react-router 8, Vite 7
Bumps both frontend apps (site, admin-ui):
- vite 5.4 -> 7.3.6 (pulls esbuild 0.28, patched dev-server CVEs)
- @vitejs/plugin-react 4 -> 5 (babel 7.29.7)
- postcss 8.4 -> 8.5.25
- react-router-dom 6.27 -> react-router 8.3.0 (package renamed
  upstream in v8; imports swapped in src). Fixes the open-redirect
  advisories with no patched 6.x, plus the RSC CSRF advisory
  (GHSA-qwww-vcr4-c8h2) that only 8.3.0 patches.
- react/react-dom 18.3 -> 19.2 (required by react-router 8)

npm audit: 0 vulnerabilities in both apps. tsc + vite build clean.
2026-08-02 00:57:34 +03:00

64 lines
2.4 KiB
TypeScript

import { Outlet, useLocation, useNavigate } from 'react-router';
import { useEffect, useState, useSyncExternalStore } from 'react';
import { Sidebar } from './Sidebar';
import { LogOut, Menu } from './Icons';
import { clearSession, getMe, notifyAuthChange, subscribeAuth } from '../lib/auth';
export function Layout() {
const navigate = useNavigate();
const location = useLocation();
const me = useSyncExternalStore(subscribeAuth, getMe, () => null);
const [drawerOpen, setDrawerOpen] = useState(false);
// Defensive: close the drawer on route change in case the user opens
// it then navigates via something other than the sidebar links
// (e.g. the legacy importer link in PageHeader actions). The drawer
// also closes via NavLink onClick → onNavigate, so this is a belt.
useEffect(() => { setDrawerOpen(false); }, [location.pathname]);
const logout = () => {
clearSession();
notifyAuthChange();
navigate('/login', { replace: true });
};
return (
<div className="flex h-full">
<Sidebar
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
onNavigate={() => setDrawerOpen(false)}
/>
<div className="flex flex-1 flex-col min-w-0">
<header className="flex h-14 items-center gap-2 border-b border-ink-800 bg-ink-900/60 px-3 sm:px-5">
<button
type="button"
onClick={() => setDrawerOpen(true)}
className="md:hidden rounded-md p-1.5 text-ink-200 hover:bg-ink-800"
aria-label="Open menu"
aria-expanded={drawerOpen}
>
<Menu />
</button>
<div className="flex-1 text-sm text-ink-300 truncate">
{/* Tighter copy on small screens — the "Signed in as" prefix
eats too much width on a phone. Tablet+ shows the full
phrase. */}
<span className="hidden sm:inline">Signed in as </span>
<span className="font-medium text-ink-50">
{me?.displayName ?? me?.username ?? `#${me?.id ?? '?'}`}
</span>
</div>
<button onClick={logout} className="btn-ghost text-xs shrink-0" aria-label="Sign out">
<LogOut />
<span className="hidden sm:inline">Sign out</span>
</button>
</header>
<main className="flex-1 overflow-auto px-3 sm:px-5 py-4 sm:py-6">
<Outlet />
</main>
</div>
</div>
);
}