/* ============================================================================ App — client-side view switching + global ⌘K command palette ========================================================================== */ // Backdrop patterns baked in for production: hero grid on, newsletter grid off. const TWEAKS = { newsletterPattern: false, heroPattern: true }; function App() { const [route, setRoute] = React.useState("home"); const [post, setPost] = React.useState(null); const tweaks = TWEAKS; // theme, lifted so both the toggle and the palette action share it const [theme, setTheme] = React.useState( () => document.documentElement.getAttribute("data-theme") || "light" ); React.useEffect(() => { document.documentElement.setAttribute("data-theme", theme); }, [theme]); const toggleTheme = React.useCallback(() => setTheme((t) => (t === "dark" ? "light" : "dark")), []); // writing tag filter, lifted so palette "Browse #tag" actions can set it const [writingFilter, setWritingFilter] = React.useState("all"); // command palette const [searchOpen, setSearchOpen] = React.useState(false); const go = React.useCallback((id) => { setRoute(id); window.scrollTo({ top: 0, left: 0, behavior: "instant" in window ? "instant" : "auto" }); }, []); const openPost = React.useCallback((p) => { setPost(p); setRoute("article"); window.scrollTo({ top: 0, left: 0 }); }, []); const goWriting = React.useCallback((tag) => { setWritingFilter(tag || "all"); go("writing"); }, [go]); // global keyboard: ⌘K / Ctrl+K toggles, "/" opens when not typing React.useEffect(() => { const onKey = (e) => { const k = e.key.toLowerCase(); if ((e.metaKey || e.ctrlKey) && k === "k") { e.preventDefault(); setSearchOpen((o) => !o); return; } const tag = (e.target && e.target.tagName) || ""; const typing = tag === "INPUT" || tag === "TEXTAREA" || (e.target && e.target.isContentEditable); if (e.key === "/" && !typing && !searchOpen) { e.preventDefault(); setSearchOpen(true); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [searchOpen]); // map article route back to "writing" for nav highlighting const navRoute = route === "article" ? "writing" : route; let view; switch (route) { case "writing": view = ; break; case "article": view = ; break; case "projects": view = ; break; case "about": view = ; break; case "photos": view = ; break; case "subscribe":view = ; break; default: view = setSearchOpen(true)} tweaks={tweaks} />; } return ( setSearchOpen(true)} /> {view}