import { useState, useEffect, useCallback } from "react"; import { getCurrentWindow, LogicalSize, LogicalPosition } from "@tauri-apps/api/window"; import { AnimatePresence, motion, MotionConfig } from "framer-motion"; import { springs, fadeSlideLeft, fadeSlideRight } from "@/lib/motion"; import { useAppStore } from "@/stores/app-store"; import { useBoardStore } from "@/stores/board-store"; import { saveSettings } from "@/lib/storage"; import { AppShell } from "@/components/layout/AppShell"; import { BoardList } from "@/components/boards/BoardList"; import { BoardView } from "@/components/board/BoardView"; import { CommandPalette } from "@/components/command-palette/CommandPalette"; import { SettingsDialog } from "@/components/settings/SettingsDialog"; import { ToastContainer } from "@/components/toast/ToastContainer"; import { ShortcutHelpModal } from "@/components/shortcuts/ShortcutHelpModal"; import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts"; import { useAnnounceStore } from "@/hooks/useAnnounce"; export default function App() { const initialized = useAppStore((s) => s.initialized); const init = useAppStore((s) => s.init); const view = useAppStore((s) => s.view); const reduceMotion = useAppStore((s) => s.settings.reduceMotion); const boardTitle = useBoardStore((s) => s.board?.title); const announcement = useAnnounceStore((s) => s.message); const [settingsOpen, setSettingsOpen] = useState(false); const [shortcutHelpOpen, setShortcutHelpOpen] = useState(false); useEffect(() => { init().then(() => { // Restore window state after settings are loaded const { settings } = useAppStore.getState(); const ws = settings.windowState; if (ws) { const appWindow = getCurrentWindow(); if (ws.maximized) { appWindow.maximize(); } else { appWindow.setSize(new LogicalSize(ws.width, ws.height)); appWindow.setPosition(new LogicalPosition(ws.x, ws.y)); } } }); }, [init]); // Flush board saves before the app window closes useEffect(() => { function handleBeforeUnload() { useBoardStore.getState().closeBoard(); } window.addEventListener("beforeunload", handleBeforeUnload); return () => { window.removeEventListener("beforeunload", handleBeforeUnload); }; }, []); // Save window state on resize/move (debounced) so it persists without blocking close useEffect(() => { const appWindow = getCurrentWindow(); let timeout: ReturnType | null = null; async function saveWindowState() { const [size, position, maximized] = await Promise.all([ appWindow.outerSize(), appWindow.outerPosition(), appWindow.isMaximized(), ]); const settings = useAppStore.getState().settings; await saveSettings({ ...settings, windowState: { x: position.x, y: position.y, width: size.width, height: size.height, maximized, }, }); } function debouncedSave() { if (timeout) clearTimeout(timeout); timeout = setTimeout(saveWindowState, 500); } const unlistenResize = appWindow.onResized(debouncedSave); const unlistenMove = appWindow.onMoved(debouncedSave); return () => { if (timeout) clearTimeout(timeout); unlistenResize.then((fn) => fn()); unlistenMove.then((fn) => fn()); }; }, []); // Listen for custom event to open settings from TopBar or command palette useEffect(() => { function handleOpenSettings() { setSettingsOpen(true); } document.addEventListener("open-settings-dialog", handleOpenSettings); return () => { document.removeEventListener("open-settings-dialog", handleOpenSettings); }; }, []); useEffect(() => { function handleOpenShortcutHelp() { setShortcutHelpOpen(true); } document.addEventListener("open-shortcut-help", handleOpenShortcutHelp); return () => { document.removeEventListener("open-shortcut-help", handleOpenShortcutHelp); }; }, []); useEffect(() => { document.title = boardTitle ? `${boardTitle} - OpenPylon` : "OpenPylon"; }, [boardTitle, view]); const handleOpenSettings = useCallback(() => { setSettingsOpen(true); }, []); useKeyboardShortcuts(); if (!initialized) { return (
Loading...
); } return (
{announcement}
{view.type === "board-list" ? ( ) : ( )}
); }