Files
DorkNet/DorkNet.Server/admin-ui/src/components/Layout.tsx
T
Alexa d471b418b9 Import march-2020-03-10 from private repo (scrubbed 2026-05-27)
Targets Rec Room 2020.03.10 client (also serves 2020.03.06).

Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
  the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces dorknet-clientpatch-{key}.zip
  for v1-march-* Release uploads.
- .github/workflows/release.yml — on tag push publishes both
  dorknet-server-march_2020_03_10-win-x64.zip and
  dorknet-clientpatch-march_2020_03_10.zip as Release assets.

Same scrub rules as december; tools/build-patcher-zip.ps1 added to
the maintainer-side allow-list so it survives.
2026-05-27 01:06:12 +03:00

64 lines
2.4 KiB
TypeScript

import { Outlet, useLocation, useNavigate } from 'react-router-dom';
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>
);
}