import { useCallback, useEffect, useRef, useState } from "react"; import { DrawingSidebar, DrawingsToggle } from "./components/DrawingSidebar"; import { EditorCanvas } from "./components/EditorCanvas"; import { PublicViewer } from "./components/PublicViewer"; import { usePublicDrawing } from "./hooks/usePublicDrawing"; import { useDrawingSession } from "./hooks/useDrawingSession"; import { useThemeTokenSync } from "./hooks/useThemeTokenSync"; type AppRoute = { type: "private" } | { type: "public"; slug: string }; function routeFromPath(pathname = window.location.pathname): AppRoute { if (!pathname.startsWith("/p/")) { return { type: "private" }; } const slug = pathname.slice(3); if (slug.length === 0 || slug.includes("/")) { return { type: "private" }; } return { type: "public", slug: decodeURIComponent(slug) }; } function PrivateApp() { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const appShellRef = useRef(null); const scheduleThemeTokenSync = useThemeTokenSync(appShellRef); const { drawings, activeId, activeTitle, scene, loading, error, toastMessage, editorReloadNonce, publication, publicationSlug, publicationBusy, setActiveTitle, submitTitle, handleSceneChange, selectDrawing, createDrawing, deleteDrawing, setPublicationSlug, publishPublication, disablePublication, } = useDrawingSession(); useEffect(() => { if (!scene || loading) { return; } scheduleThemeTokenSync(); }, [activeId, loading, scene, scheduleThemeTokenSync]); useEffect(() => { if (!isSidebarOpen) { return; } const onKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { setIsSidebarOpen(false); } }; window.addEventListener("keydown", onKeyDown); return () => { window.removeEventListener("keydown", onKeyDown); }; }, [isSidebarOpen]); const openSidebar = useCallback(() => { setIsSidebarOpen(true); }, []); const closeSidebar = useCallback(() => { setIsSidebarOpen(false); }, []); const handleSelectDrawing = useCallback( (drawingId: string) => { setIsSidebarOpen(false); void selectDrawing(drawingId); }, [selectDrawing], ); const handleCreateDrawing = useCallback(() => { setIsSidebarOpen(false); void createDrawing(); }, [createDrawing]); return (
{toastMessage && (
{toastMessage}
)}
void deleteDrawing(drawingId)} onTitleChange={setActiveTitle} onTitleSubmit={() => void submitTitle()} onPublicationSlugChange={setPublicationSlug} onPublish={() => void publishPublication()} onDisablePublication={() => void disablePublication()} />
); } function PublicApp({ slug }: { slug: string }) { const { drawing, loading, error } = usePublicDrawing(slug); return ; } export function App() { const route = routeFromPath(); if (route.type === "public") { return ; } return ; }