Files
provenance/frontend/components/app-shell.tsx
T
justin 1164841950 Global Import in the menu; mobile drawer nav
- Add a top-level "Import" entry to the sidebar and a global /import page, so
  you can start a tree from a GEDCOM without first creating an empty one. The
  import flow now picks its destination (new tree, or an existing one) — the
  tree-scoped page reuses the same <GedcomImport> with a fixed destination and
  keeps Export.
- Extract the sidebar chrome into <AppShell> and give small screens a working
  menu: a hamburger opens the full sidebar as a slide-in drawer (it was just a
  logo + "Trees" link before). Used by both /trees and /import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 10:40:01 -04:00

57 lines
2.0 KiB
TypeScript

"use client";
import { Menu } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { AppSidebar } from "@/components/app-sidebar";
/**
* App chrome: a fixed sidebar on md+, and on small screens a top bar with a
* hamburger that opens the same sidebar as a slide-in drawer.
*/
export function AppShell({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false);
return (
<div className="flex min-h-screen">
<aside className="sticky top-0 hidden h-screen w-64 shrink-0 border-r border-[var(--border)] bg-[var(--surface)] md:flex md:flex-col">
<AppSidebar />
</aside>
<div className="flex min-w-0 flex-1 flex-col">
{/* Mobile top bar */}
<div className="flex items-center gap-3 border-b border-[var(--border)] bg-[var(--surface)] px-4 py-3 md:hidden">
<button
onClick={() => setOpen(true)}
aria-label="Open menu"
className="text-[var(--muted)] hover:text-[var(--foreground)]"
>
<Menu className="h-6 w-6" />
</button>
<Link href="/" aria-label="Provenance — home">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/provenance-logo-plain.svg" alt="Provenance" className="h-6 w-auto" />
</Link>
</div>
{/* Mobile drawer */}
{open && (
<div className="fixed inset-0 z-50 md:hidden">
<div
className="absolute inset-0 bg-black/40"
onClick={() => setOpen(false)}
aria-hidden
/>
<aside className="absolute left-0 top-0 h-full w-72 max-w-[85%] border-r border-[var(--border)] bg-[var(--surface)] shadow-xl">
<AppSidebar onNavigate={() => setOpen(false)} />
</aside>
</div>
)}
<div className="mx-auto w-full max-w-4xl px-6 py-10 md:px-10">{children}</div>
</div>
</div>
);
}