40 lines
2.1 KiB
TypeScript
40 lines
2.1 KiB
TypeScript
import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
|
import { Button } from "../components/ui/button";
|
|
import { Dialog, DialogContent, DialogDescription, DialogTitle, DialogTrigger } from "../components/ui/dialog";
|
|
|
|
/** Measure the embedded application, which can be narrower than the viewport. */
|
|
export function ArchiveNavigation({ surface, forceDrawer = false, children }: { surface: string; forceDrawer?: boolean; children: ReactNode }) {
|
|
const marker = useRef<HTMLSpanElement>(null);
|
|
const [narrow, setNarrow] = useState(false);
|
|
const [open, setOpen] = useState(false);
|
|
useLayoutEffect(() => {
|
|
const shell = marker.current?.closest<HTMLElement>(".thot-app-shell");
|
|
if (!shell) return;
|
|
const update = () => {
|
|
const width = shell.getBoundingClientRect().width || window.innerWidth;
|
|
const collapsed = forceDrawer || width < (surface === "core" ? 768 : 1000);
|
|
setNarrow(collapsed);
|
|
shell.dataset.administrationNarrow = String(collapsed);
|
|
};
|
|
update();
|
|
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(update) : null;
|
|
observer?.observe(shell);
|
|
window.addEventListener("resize", update);
|
|
return () => { observer?.disconnect(); window.removeEventListener("resize", update); delete shell.dataset.administrationNarrow; };
|
|
}, [surface, forceDrawer]);
|
|
useEffect(() => { setOpen(false); }, [surface, narrow]);
|
|
const anchor = <span ref={marker} hidden />;
|
|
if (!narrow) return <>{anchor}{children}</>;
|
|
return <>{anchor}<Dialog open={open} onOpenChange={setOpen}>
|
|
<div className="thot-administration-mobile-nav">
|
|
<span className="font-heading font-semibold">ThothII</span>
|
|
<DialogTrigger render={<Button variant="outline" size="sm" />}>Navigation</DialogTrigger>
|
|
</div>
|
|
<DialogContent className="flex max-h-[calc(100dvh-2rem)] flex-col">
|
|
<DialogTitle>Navigation</DialogTitle>
|
|
<DialogDescription className="sr-only">Choose an administration page or a session.</DialogDescription>
|
|
<div className="min-h-0 overflow-y-auto [&>aside]:w-full">{children}</div>
|
|
</DialogContent>
|
|
</Dialog></>;
|
|
}
|