85b303e387
Drag the floating AI-chat window onto the sidebar and release over it to DOCK it — the window pins to the live navbar rect, overlaying the page tree; a drop-zone highlight shows while dragging over it. Closing the chat re-shows the tree. Undock via a header button or by dragging the docked window back onto content (pops out floating at the drop point). The docked/floating mode persists in localStorage and the docked window follows the navbar width (manual resize, space<->shared route change) via a ResizeObserver + sidebar-toggle/transitionend re-sync; when the navbar is collapsed/absent the window falls back to floating instead of vanishing. Dock/undock only flips a mode atom + geometry — ChatThread is never remounted, so an in-flight response stream is not interrupted. Frontend only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
949 B
TypeScript
30 lines
949 B
TypeScript
import { atomWithWebStorage } from "@/lib/jotai-helper.ts";
|
|
import { atom } from "jotai";
|
|
|
|
// Stable DOM id set on the app-shell navbar (<AppShell.Navbar>). Declared here —
|
|
// alongside the sidebar atoms — rather than in the chat window so the AI chat
|
|
// window can reference the navbar by id without importing the app shell (which
|
|
// would create a shell -> chat-window -> shell import cycle).
|
|
export const APP_NAVBAR_ID = "app-shell-navbar";
|
|
|
|
export const mobileSidebarAtom = atom<boolean>(false);
|
|
|
|
export const desktopSidebarAtom = atomWithWebStorage<boolean>(
|
|
"showSidebar",
|
|
true,
|
|
);
|
|
|
|
export const desktopAsideAtom = atom<boolean>(false);
|
|
|
|
// Valid `tab` values: "" | "comments" | "toc" | "details"
|
|
type AsideStateType = {
|
|
tab: string;
|
|
isAsideOpen: boolean;
|
|
};
|
|
|
|
export const asideStateAtom = atom<AsideStateType>({
|
|
tab: "",
|
|
isAsideOpen: false,
|
|
});
|
|
|
|
export const sidebarWidthAtom = atomWithWebStorage<number>('sidebarWidth', 300); |