feat: establish unified administration and model context baseline

This commit is contained in:
Codex
2026-09-12 18:03:15 +02:00
parent 840344706f
commit f52bf22e05
74 changed files with 2334 additions and 523 deletions
+25 -16
View File
@@ -1,23 +1,32 @@
import { useEffect, useState, useSyncExternalStore, type ReactNode } from "react";
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";
const query = "(max-width: 767px)";
function subscribe(listener: () => void) {
const media = window.matchMedia(query);
media.addEventListener("change", listener);
return () => media.removeEventListener("change", listener);
}
const isNarrow = () => window.matchMedia(query).matches;
/** Keep the archive content readable on phones, using the shared accessible dialog. */
export function ArchiveNavigation({ surface, children }: { surface: string; children: ReactNode }) {
const narrow = useSyncExternalStore(subscribe, isNarrow, () => false);
/** 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]);
if (!narrow || !["memory-management", "evidence-management"].includes(surface)) return children;
return <Dialog open={open} onOpenChange={setOpen}>
<div className="fixed inset-x-0 top-0 z-30 flex h-12 items-center justify-between border-b bg-background px-4">
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>
@@ -26,5 +35,5 @@ export function ArchiveNavigation({ surface, children }: { surface: string; chil
<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>;
</Dialog></>;
}