@togo-framework/ui-desktop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/desktop/DesktopShell.tsx","../src/components/desktop/TopBar.tsx","../src/components/desktop/TogoMenu.tsx","../src/components/desktop/WeatherWidget.tsx","../src/components/desktop/Spotlight.tsx","../src/components/desktop/Dock.tsx","../src/components/desktop/DesktopIconGrid.tsx","../src/components/desktop/DesktopIcon.tsx","../src/components/desktop/DesktopContextMenu.tsx","../src/components/desktop/WindowManager.tsx","../src/components/desktop/Window.tsx","../src/components/desktop/Launchpad.tsx","../src/components/desktop/NotificationCenter.tsx","../src/components/desktop/NotificationBell.tsx","../src/components/desktop/OSLoginScreen.tsx","../src/hooks/useOSSession.ts","../src/hooks/useOSApps.ts"],"sourcesContent":["'use client'\n\n// DesktopShell — top-level OS-shell layout: full-bleed wallpaper background\n// (image over gradient, from DesktopPrefs.wallpaper via `theme/wallpapers.ts`),\n// a <TopBar/> (togo menu + weather + spotlight + clock→notifications), a content\n// area with desktop icons + open <Window/>s, a <Dock/> (Launchpad + apps +\n// Trash), a <Spotlight/> app launcher, and a <NotificationCenter/> sideover.\n// Assumes a <ThemeProvider> sits above it (same convention as AppLayout).\n\nimport * as React from \"react\";\nimport { wallpaperCss } from \"@togo-framework/ui-core\";\nimport { TopBar, type TopBarProps } from \"./TopBar\";\nimport { Dock } from \"./Dock\";\nimport { DesktopIconGrid } from \"./DesktopIconGrid\";\nimport { DesktopContextMenu, type DesktopContextAction } from \"./DesktopContextMenu\";\nimport { WindowManagerProvider, WindowManager, useWindowManager } from \"./WindowManager\";\nimport { Spotlight } from \"./Spotlight\";\nimport { Launchpad } from \"./Launchpad\";\nimport { NotificationCenter } from \"./NotificationCenter\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\nimport type { DesktopPrefs } from \"../../hooks/useOSSession\";\nimport type { OSNotification } from \"./NotificationBell\";\nimport { cn } from \"@togo-framework/ui-core\";\n\nexport interface DesktopShellProps {\n /** Current desktop preferences (wallpaper, dock_pinned, ...) — e.g. from useOSSession(). */\n prefs: DesktopPrefs;\n /** Installed apps — e.g. from useOSApps(). */\n apps: OSApp[];\n /** Renders window content for a given app slug. */\n renderApp: (app: OSApp) => React.ReactNode;\n /** Top-bar props (me / logout / weather / menu callbacks / notifications data). */\n topBar: Omit<TopBarProps, \"className\" | \"onOpenSpotlight\" | \"onOpenNotifications\">;\n /** Notifications for the sideover (same list the bell uses). */\n notifications?: OSNotification[];\n unreadCount?: number;\n onMarkRead?: (id: string) => void;\n onMarkAllRead?: () => void;\n onNavigate?: (url: string) => void;\n onContextAction?: (action: DesktopContextAction) => void;\n /** Opens the Trash (dock). */\n onTrash?: () => void;\n /** Saved desktop-icon positions (DesktopPrefs.icon_positions). */\n iconPositions?: Record<string, { x: number; y: number }>;\n /** Persist a desktop-icon position after a drag. */\n onIconMove?: (slug: string, pos: { x: number; y: number }) => void;\n /** Slugs hidden from the desktop (DesktopPrefs.desktop_hidden). */\n desktopHidden?: string[];\n /** Remove an app icon from the desktop. */\n onRemoveDesktopIcon?: (slug: string) => void;\n /** Add an app icon back to the desktop (from Launchpad). */\n onAddDesktopIcon?: (slug: string) => void;\n /** Pin an app to the dock (from Launchpad). */\n onPinDock?: (slug: string) => void;\n /** Unpin an app from the dock (dock/Launchpad context menu). */\n onUnpinDock?: (slug: string) => void;\n /**\n * Called once the shell is mounted, with an imperative API so the host page\n * can open app windows from outside the shell (e.g. a top-bar shortcut).\n */\n onReady?: (api: DesktopApi) => void;\n className?: string;\n}\n\n/** Imperative handle exposed via DesktopShellProps.onReady. */\nexport interface DesktopApi {\n /**\n * Open (or restore/focus) a registered app by slug, optionally deep-linking to\n * a section inside it (e.g. open(\"prefs\", \"wallpaper\") jumps Settings straight\n * to the Wallpaper pane). The app reads the target via useWindowSection().\n */\n open: (slug: string, section?: string) => void;\n /** Open (or restore/focus) an arbitrary window not backed by an installed app. */\n openWindow: (opts: {\n slug: string;\n title: string;\n icon?: string;\n width?: number;\n height?: number;\n content: React.ReactNode;\n section?: string;\n }) => void;\n}\n\nexport function DesktopShell({\n prefs,\n apps,\n renderApp,\n topBar,\n notifications = [],\n unreadCount = 0,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n onContextAction,\n onTrash,\n onReady,\n iconPositions,\n onIconMove,\n desktopHidden,\n onRemoveDesktopIcon,\n onAddDesktopIcon,\n onPinDock,\n onUnpinDock,\n className,\n}: DesktopShellProps) {\n const [spotlightOpen, setSpotlightOpen] = React.useState(false);\n const [launchpadOpen, setLaunchpadOpen] = React.useState(false);\n const [notifOpen, setNotifOpen] = React.useState(false);\n\n return (\n <WindowManagerProvider>\n <div\n className={cn(\"fixed inset-0 overflow-hidden\", className)}\n style={{ background: wallpaperCss(prefs.wallpaper) }}\n >\n <DesktopContent\n apps={apps}\n pinned={prefs.dock_pinned}\n renderApp={renderApp}\n topBar={topBar}\n notifications={notifications}\n unreadCount={unreadCount}\n onMarkRead={onMarkRead}\n onMarkAllRead={onMarkAllRead}\n onNavigate={onNavigate}\n onContextAction={onContextAction}\n onTrash={onTrash}\n onReady={onReady}\n iconPositions={iconPositions}\n onIconMove={onIconMove}\n desktopHidden={desktopHidden}\n onRemoveDesktopIcon={onRemoveDesktopIcon}\n onAddDesktopIcon={onAddDesktopIcon}\n onPinDock={onPinDock}\n onUnpinDock={onUnpinDock}\n spotlightOpen={spotlightOpen}\n setSpotlightOpen={setSpotlightOpen}\n launchpadOpen={launchpadOpen}\n setLaunchpadOpen={setLaunchpadOpen}\n notifOpen={notifOpen}\n setNotifOpen={setNotifOpen}\n />\n </div>\n </WindowManagerProvider>\n );\n}\n\n// Content area — needs useWindowManager(), so it lives below the provider.\nfunction DesktopContent({\n apps,\n pinned,\n renderApp,\n topBar,\n notifications,\n unreadCount,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n onContextAction,\n onTrash,\n onReady,\n iconPositions,\n onIconMove,\n desktopHidden,\n onRemoveDesktopIcon,\n onAddDesktopIcon,\n onPinDock,\n onUnpinDock,\n spotlightOpen,\n setSpotlightOpen,\n launchpadOpen,\n setLaunchpadOpen,\n notifOpen,\n setNotifOpen,\n}: {\n apps: OSApp[];\n pinned: string[];\n renderApp: (app: OSApp) => React.ReactNode;\n topBar: DesktopShellProps[\"topBar\"];\n notifications: OSNotification[];\n unreadCount: number;\n onMarkRead?: (id: string) => void;\n onMarkAllRead?: () => void;\n onNavigate?: (url: string) => void;\n onContextAction?: (action: DesktopContextAction) => void;\n onTrash?: () => void;\n onReady?: (api: DesktopApi) => void;\n iconPositions?: Record<string, { x: number; y: number }>;\n onIconMove?: (slug: string, pos: { x: number; y: number }) => void;\n desktopHidden?: string[];\n onRemoveDesktopIcon?: (slug: string) => void;\n onAddDesktopIcon?: (slug: string) => void;\n onPinDock?: (slug: string) => void;\n onUnpinDock?: (slug: string) => void;\n spotlightOpen: boolean;\n setSpotlightOpen: (v: boolean) => void;\n launchpadOpen: boolean;\n setLaunchpadOpen: (v: boolean) => void;\n notifOpen: boolean;\n setNotifOpen: (v: boolean) => void;\n}) {\n const wm = useWindowManager();\n const bySlug = React.useMemo(() => new Map(apps.map((a) => [a.slug, a])), [apps]);\n\n const launch = React.useCallback(\n (slug: string, section?: string) => {\n const app = bySlug.get(slug);\n if (!app) return;\n if (wm.isOpen(slug)) {\n // Already open — restore (if minimized) and bring to front, without\n // remounting its content. Re-target its section if a deep-link was given.\n wm.restore(slug);\n if (section) wm.setSection(slug, section);\n return;\n }\n wm.open(slug, {\n title: app.name,\n icon: app.icon,\n resizable: app.window?.resizable ?? true,\n width: app.window?.width,\n height: app.window?.height,\n content: renderApp(app),\n section,\n });\n },\n [bySlug, wm, renderApp],\n );\n\n const openWindow = React.useCallback(\n (opts: { slug: string; title: string; icon?: string; width?: number; height?: number; content: React.ReactNode; section?: string }) => {\n if (wm.isOpen(opts.slug)) {\n wm.restore(opts.slug);\n if (opts.section) wm.setSection(opts.slug, opts.section);\n return;\n }\n wm.open(opts.slug, { title: opts.title, icon: opts.icon, width: opts.width, height: opts.height, content: opts.content, section: opts.section });\n },\n [wm],\n );\n\n // Expose an imperative opener to the host page (top-bar shortcuts, etc.).\n const onReadyRef = React.useRef(onReady);\n onReadyRef.current = onReady;\n React.useEffect(() => {\n onReadyRef.current?.({ open: launch, openWindow });\n }, [launch, openWindow]);\n\n const openSlugs = wm.windows.map((w) => w.slug);\n // Dock: pinned apps, or every installed app when nothing is pinned yet.\n const dockSlugs = pinned.length > 0 ? pinned : apps.map((a) => a.slug);\n\n return (\n <>\n <TopBar\n {...topBar}\n notifications={notifications}\n unreadCount={unreadCount}\n onMarkRead={onMarkRead}\n onMarkAllRead={onMarkAllRead}\n onNavigate={onNavigate}\n onOpenSpotlight={() => setSpotlightOpen(true)}\n onOpenNotifications={() => setNotifOpen(true)}\n />\n\n <DesktopContextMenu onAction={(a) => onContextAction?.(a)} className=\"absolute inset-0 top-9\">\n <div className=\"relative h-full w-full\">\n <DesktopIconGrid\n apps={apps}\n onOpen={launch}\n positions={iconPositions}\n onMove={onIconMove}\n hidden={desktopHidden}\n onRemove={onRemoveDesktopIcon}\n />\n </div>\n </DesktopContextMenu>\n\n <WindowManager />\n\n <Dock\n apps={apps}\n pinned={dockSlugs}\n openSlugs={openSlugs}\n onLaunch={launch}\n onCloseApp={(slug) => wm.close(slug)}\n onUnpin={onUnpinDock}\n onLaunchpad={() => setLaunchpadOpen(true)}\n onTrash={onTrash}\n />\n\n <Launchpad\n open={launchpadOpen}\n onOpenChange={setLaunchpadOpen}\n apps={apps}\n pinned={dockSlugs}\n hidden={desktopHidden}\n onLaunch={launch}\n onPin={onPinDock}\n onUnpin={onUnpinDock}\n onAddToDesktop={onAddDesktopIcon}\n onRemoveFromDesktop={onRemoveDesktopIcon}\n />\n\n <Spotlight open={spotlightOpen} onOpenChange={setSpotlightOpen} apps={apps} onLaunch={launch} />\n\n <NotificationCenter\n open={notifOpen}\n onOpenChange={setNotifOpen}\n notifications={notifications}\n unreadCount={unreadCount}\n onMarkRead={onMarkRead}\n onMarkAllRead={onMarkAllRead}\n onNavigate={onNavigate}\n />\n </>\n );\n}\n\nDesktopShell.displayName = \"DesktopShell\";\n","'use client'\n\n// TopBar — the OS menu bar. Leading side: the togo \"Apple menu\" (About /\n// Settings / power / logout). Trailing side: weather, a Spotlight search\n// trigger, the ThemePicker, a notification bell, an avatar menu, and the live\n// clock (moved to the far end, macOS-style, and clickable to open the\n// Notification Center sideover).\n\nimport * as React from \"react\";\nimport { LogOut, User } from \"lucide-react\";\nimport { Avatar, AvatarFallback } from \"@togo-framework/ui-core\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@togo-framework/ui-core\";\nimport type { OSNotification } from \"./NotificationBell\";\nimport { TogoMenu, type TogoMenuProps } from \"./TogoMenu\";\nimport { WeatherWidget, type WeatherData } from \"./WeatherWidget\";\nimport { SpotlightTrigger } from \"./Spotlight\";\nimport { cn } from \"@togo-framework/ui-core\";\n\nexport interface TopBarProps {\n me: { email: string } | null;\n onLogout: () => void;\n onProfile?: () => void;\n\n // togo (Apple-style) menu — omit to hide the leading menu.\n menu?: Omit<TogoMenuProps, \"onLogout\"> & { enabled?: boolean };\n\n // Notifications\n notifications?: OSNotification[];\n unreadCount?: number;\n onMarkRead?: (id: string) => void;\n onMarkAllRead?: () => void;\n onFetchNotifications?: () => void;\n onNavigate?: (url: string) => void;\n /** Clicking the clock (and, if provided, the bell) opens the notification center. */\n onOpenNotifications?: () => void;\n\n // Spotlight\n onOpenSpotlight?: () => void;\n\n // Weather\n weather?: WeatherData | null;\n onWeatherClick?: () => void;\n\n className?: string;\n}\n\nfunction useClock() {\n const [now, setNow] = React.useState(() => new Date());\n React.useEffect(() => {\n const id = setInterval(() => setNow(new Date()), 1000 * 15);\n return () => clearInterval(id);\n }, []);\n return now;\n}\n\nexport function TopBar({\n me,\n onLogout,\n onProfile,\n menu,\n onOpenNotifications,\n onOpenSpotlight,\n weather,\n onWeatherClick,\n className,\n}: TopBarProps) {\n const now = useClock();\n const clock = now.toLocaleTimeString([], { hour: \"numeric\", minute: \"2-digit\" });\n const dateStr = now.toLocaleDateString([], { weekday: \"short\", month: \"short\", day: \"numeric\" });\n const initial = me?.email?.[0]?.toUpperCase() ?? \"?\";\n\n return (\n <div\n className={cn(\n \"fixed inset-x-0 top-0 z-50 flex h-9 items-center justify-between gap-3 bg-black/25 px-2 text-xs text-white backdrop-blur-lg\",\n className,\n )}\n >\n {/* Leading: togo menu */}\n <div className=\"flex items-center gap-1\">\n {menu?.enabled !== false && (\n <TogoMenu {...menu} onLogout={onLogout} />\n )}\n </div>\n\n {/* Trailing: weather · spotlight · avatar · clock */}\n <div className=\"flex items-center gap-0.5\">\n <WeatherWidget weather={weather} onClick={onWeatherClick} className=\"text-white/90\" />\n\n {onOpenSpotlight && (\n <SpotlightTrigger\n onClick={onOpenSpotlight}\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-white/90 transition hover:bg-white/10\"\n />\n )}\n\n {me && (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-2 rounded-full p-0.5 outline-none transition hover:bg-white/10\">\n <Avatar className=\"h-6 w-6\">\n <AvatarFallback className=\"bg-white/20 text-[10px] text-white\">{initial}</AvatarFallback>\n </Avatar>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-56\">\n <div className=\"truncate px-2 py-1.5 text-xs text-muted-foreground\">{me.email}</div>\n <DropdownMenuSeparator />\n {onProfile && (\n <DropdownMenuItem onClick={onProfile}>\n <User className=\"me-2 h-4 w-4\" />\n Profile\n </DropdownMenuItem>\n )}\n <DropdownMenuItem className=\"text-destructive\" onClick={onLogout}>\n <LogOut className=\"me-2 h-4 w-4\" />\n Sign out\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Clock — far end, click to open the Notification Center (macOS-style). */}\n <button\n type=\"button\"\n onClick={onOpenNotifications}\n className=\"flex items-center gap-2 rounded-md px-2 py-1 font-medium transition hover:bg-white/10\"\n title=\"Open Notification Center\"\n >\n <span className=\"hidden text-white/80 sm:inline\">{dateStr}</span>\n <span>{clock}</span>\n </button>\n </div>\n </div>\n );\n}\n\nTopBar.displayName = \"TopBar\";\n","'use client'\n\n// TogoMenu — the \"Apple menu\" of the togo desktop: a logo button in the top-bar\n// leading corner that opens a dropdown (About, System Settings, Sleep / Restart\n// / Shut Down, Log Out). All actions are prop-driven callbacks.\n\nimport * as React from \"react\";\nimport { Layers, Info, Settings, Moon, RotateCcw, Power, LogOut } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@togo-framework/ui-core\";\n\nexport interface TogoMenuProps {\n /** Logo glyph (defaults to the togo layers mark). */\n logo?: React.ReactNode;\n label?: string;\n onAbout?: () => void;\n onSettings?: () => void;\n onSleep?: () => void;\n onRestart?: () => void;\n onShutDown?: () => void;\n onLogout?: () => void;\n}\n\nexport function TogoMenu({\n logo,\n label = \"togo\",\n onAbout,\n onSettings,\n onSleep,\n onRestart,\n onShutDown,\n onLogout,\n}: TogoMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-1.5 rounded-md px-2 py-1 font-semibold outline-none transition hover:bg-white/10\">\n <span className=\"text-primary\">{logo ?? <Layers className=\"h-4 w-4\" />}</span>\n <span className=\"text-sm\">{label}</span>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {onAbout && (\n <DropdownMenuItem onClick={onAbout}>\n <Info className=\"me-2 h-4 w-4\" />\n About This Desktop\n </DropdownMenuItem>\n )}\n {onSettings && (\n <DropdownMenuItem onClick={onSettings}>\n <Settings className=\"me-2 h-4 w-4\" />\n System Settings…\n </DropdownMenuItem>\n )}\n {(onAbout || onSettings) && (onSleep || onRestart || onShutDown || onLogout) && <DropdownMenuSeparator />}\n {onSleep && (\n <DropdownMenuItem onClick={onSleep}>\n <Moon className=\"me-2 h-4 w-4\" />\n Sleep\n </DropdownMenuItem>\n )}\n {onRestart && (\n <DropdownMenuItem onClick={onRestart}>\n <RotateCcw className=\"me-2 h-4 w-4\" />\n Restart…\n </DropdownMenuItem>\n )}\n {onShutDown && (\n <DropdownMenuItem onClick={onShutDown}>\n <Power className=\"me-2 h-4 w-4\" />\n Shut Down…\n </DropdownMenuItem>\n )}\n {onLogout && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"text-destructive\" onClick={onLogout}>\n <LogOut className=\"me-2 h-4 w-4\" />\n Log Out\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nTogoMenu.displayName = \"TogoMenu\";\n","'use client'\n\n// WeatherWidget — a compact top-bar weather readout (icon + temperature). Data\n// is prop-driven so the consuming app can wire any source (e.g. the weather OS\n// app / open-meteo). Renders nothing until data arrives (keeps the bar clean).\n\nimport * as React from \"react\";\nimport { Cloud, CloudRain, CloudSnow, CloudLightning, Sun, CloudSun, CloudFog } from \"lucide-react\";\n\nexport type WeatherCondition = \"clear\" | \"cloudy\" | \"rain\" | \"snow\" | \"storm\" | \"fog\" | \"partly\";\n\nexport interface WeatherData {\n /** Temperature already formatted's numeric value (°). */\n temp: number;\n condition: WeatherCondition;\n location?: string;\n /** Unit label, default \"°\". */\n unit?: string;\n}\n\nconst ICONS: Record<WeatherCondition, React.ComponentType<{ className?: string }>> = {\n clear: Sun,\n partly: CloudSun,\n cloudy: Cloud,\n rain: CloudRain,\n snow: CloudSnow,\n storm: CloudLightning,\n fog: CloudFog,\n};\n\nexport interface WeatherWidgetProps {\n weather?: WeatherData | null;\n onClick?: () => void;\n className?: string;\n}\n\nexport function WeatherWidget({ weather, onClick, className }: WeatherWidgetProps) {\n if (!weather) return null;\n const Icon = ICONS[weather.condition] ?? Cloud;\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={weather.location ? `${weather.location} — ${weather.condition}` : weather.condition}\n className={[\"flex items-center gap-1.5 rounded-md px-2 py-1 transition hover:bg-white/10\", className].filter(Boolean).join(\" \")}\n >\n <Icon className=\"h-4 w-4\" />\n <span className=\"tabular-nums\">{Math.round(weather.temp)}{weather.unit ?? \"°\"}</span>\n </button>\n );\n}\n\nWeatherWidget.displayName = \"WeatherWidget\";\n","'use client'\n\n// Spotlight — a macOS-style search palette (Cmd/Ctrl+K or the top-bar search\n// button). A rounded search field drops in near the top-center over a blurred\n// backdrop, scaling + fading in like macOS Spotlight. Lists installed OS apps,\n// filters as you type, launches on select. Built on cmdk's Command primitives\n// (NOT the shared Dialog) so the open animation is fully custom.\n\nimport * as React from \"react\";\nimport { Search } from \"lucide-react\";\nimport {\n Command,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n} from \"@togo-framework/ui-core\";\nimport { DynamicIcon } from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\n\nexport interface SpotlightProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n apps: OSApp[];\n onLaunch: (slug: string) => void;\n}\n\nexport function Spotlight({ open, onOpenChange, apps, onLaunch }: SpotlightProps) {\n const [mounted, setMounted] = React.useState(open);\n const [shown, setShown] = React.useState(false);\n\n // Cmd/Ctrl+K toggles Spotlight globally; Escape closes.\n React.useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === \"k\") {\n e.preventDefault();\n onOpenChange(!open);\n } else if (e.key === \"Escape\" && open) {\n onOpenChange(false);\n }\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onOpenChange]);\n\n // Mount/unmount with an enter/exit animation (matches Launchpad).\n React.useEffect(() => {\n if (open) {\n setMounted(true);\n const t = setTimeout(() => setShown(true), 10);\n return () => clearTimeout(t);\n }\n setShown(false);\n const t = setTimeout(() => setMounted(false), 200);\n return () => clearTimeout(t);\n }, [open]);\n\n if (!mounted) return null;\n\n return (\n <div\n className={cn(\n \"fixed inset-0 z-[70] flex items-start justify-center bg-black/30 backdrop-blur-md transition-opacity duration-200\",\n shown ? \"opacity-100\" : \"opacity-0\",\n )}\n onClick={(e) => { if (e.target === e.currentTarget) onOpenChange(false); }}\n >\n <div\n className={cn(\n \"mt-[16vh] w-[92vw] max-w-xl origin-top overflow-hidden rounded-2xl border border-border/60 bg-popover/90 shadow-2xl backdrop-blur-2xl transition-all duration-200 ease-out\",\n shown ? \"translate-y-0 scale-100 opacity-100\" : \"-translate-y-3 scale-95 opacity-0\",\n )}\n >\n <Command className=\"bg-transparent [&_[cmdk-input]]:h-12\">\n <CommandInput autoFocus placeholder=\"Spotlight Search\" className=\"text-base\" />\n <CommandList className=\"max-h-[50vh]\">\n <CommandEmpty>No apps found.</CommandEmpty>\n <CommandGroup heading=\"Applications\">\n {apps.map((app) => (\n <CommandItem\n key={app.slug}\n value={`${app.name} ${app.slug} ${app.category}`}\n onSelect={() => { onLaunch(app.slug); onOpenChange(false); }}\n className=\"gap-3\"\n >\n <span\n className=\"flex h-9 w-9 items-center justify-center rounded-[10px] text-white ring-1 ring-inset ring-white/25\"\n style={{ backgroundImage: `linear-gradient(160deg, ${app.color || \"#64748b\"}, ${app.color || \"#64748b\"}bb)` }}\n >\n <DynamicIcon name={app.icon} size={18} />\n </span>\n <span className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">{app.name}</span>\n <span className=\"text-xs capitalize text-muted-foreground\">{app.category}</span>\n </span>\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </div>\n </div>\n );\n}\n\nSpotlight.displayName = \"Spotlight\";\n\n/** Small icon button that opens Spotlight (for the top bar). */\nexport function SpotlightTrigger({ onClick, className }: { onClick: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title=\"Search (⌘K)\"\n className={className}\n aria-label=\"Open Spotlight search\"\n >\n <Search className=\"h-4 w-4\" />\n </button>\n );\n}\n","'use client'\n\n// Dock — bottom, macOS-style, rounded floating bar. A Launchpad button opens\n// Spotlight; then app icons (pinned + open) launch on click; then a Trash bin\n// at the trailing end. Always visible.\n\nimport * as React from \"react\";\nimport { LayoutGrid, Trash2, SquareArrowOutUpRight, X, PinOff } from \"lucide-react\";\nimport { DynamicIcon } from \"@togo-framework/ui-core\";\nimport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n} from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\n\nexport interface DockProps {\n /** All installed apps (used to resolve name/icon/color for pinned slugs). */\n apps: OSApp[];\n /** Slugs to show, in order (pinned, or all installed apps as a fallback). */\n pinned: string[];\n /** Slugs of currently-open windows — shown with an \"open\" indicator dot. */\n openSlugs?: string[];\n onLaunch: (slug: string) => void;\n /** Right-click → Quit on a running app icon. */\n onCloseApp?: (slug: string) => void;\n /** Right-click → Remove from Dock (unpin). */\n onUnpin?: (slug: string) => void;\n /** Opens the Launchpad / app directory (leading icon). */\n onLaunchpad?: () => void;\n /** Opens the Trash (trailing icon). */\n onTrash?: () => void;\n className?: string;\n}\n\ninterface DockButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n label: string;\n color?: string;\n isOpen?: boolean;\n}\n\nconst DockButton = React.forwardRef<HTMLButtonElement, DockButtonProps>(\n ({ label, color, isOpen, children, ...rest }, ref) => {\n const base = color || \"#64748b\";\n return (\n <button\n ref={ref}\n type=\"button\"\n title={label}\n {...rest}\n className=\"group relative flex flex-col items-center transition-transform duration-150 ease-out hover:-translate-y-1.5\"\n >\n {/* Solid squircle so the icon reads clearly on ANY wallpaper (macOS style):\n a color gradient fill, a white icon, an inset highlight ring. */}\n <span\n className=\"flex h-11 w-11 items-center justify-center rounded-[14px] text-white shadow-md ring-1 ring-inset ring-white/25 transition-shadow group-hover:shadow-xl\"\n style={{ backgroundImage: `linear-gradient(160deg, ${base}, ${base}bb)` }}\n >\n <span className=\"drop-shadow-[0_1px_1px_rgba(0,0,0,0.35)]\">{children}</span>\n </span>\n <span className={cn(\"mt-1 h-1 w-1 rounded-full bg-white/90 transition-opacity\", isOpen ? \"opacity-100\" : \"opacity-0\")} />\n </button>\n );\n },\n);\nDockButton.displayName = \"DockButton\";\n\nexport function Dock({ apps, pinned, openSlugs = [], onLaunch, onCloseApp, onUnpin, onLaunchpad, onTrash, className }: DockProps) {\n const bySlug = React.useMemo(() => new Map(apps.map((a) => [a.slug, a])), [apps]);\n const slugs = React.useMemo(() => {\n const seen = new Set<string>();\n const ordered: string[] = [];\n for (const s of [...pinned, ...openSlugs]) {\n if (!seen.has(s) && bySlug.has(s)) {\n seen.add(s);\n ordered.push(s);\n }\n }\n return ordered;\n }, [pinned, openSlugs, bySlug]);\n\n return (\n <div className={cn(\"pointer-events-none fixed inset-x-0 bottom-3 z-40 flex justify-center px-2\", className)}>\n <div className=\"no-scrollbar pointer-events-auto flex max-w-full items-end gap-1.5 overflow-x-auto rounded-2xl border border-white/15 bg-black/25 px-2.5 py-2 shadow-2xl backdrop-blur-2xl\">\n {onLaunchpad && (\n <>\n <DockButton label=\"Launchpad\" color=\"#6366f1\" onClick={onLaunchpad}>\n <LayoutGrid className=\"h-5 w-5\" />\n </DockButton>\n {(slugs.length > 0 || onTrash) && <span className=\"mx-1 h-9 w-px self-center bg-white/15\" />}\n </>\n )}\n\n {slugs.map((slug) => {\n const app = bySlug.get(slug)!;\n const running = openSlugs.includes(slug);\n return (\n <ContextMenu key={slug}>\n <ContextMenuTrigger asChild>\n <DockButton label={app.name} color={app.color} isOpen={running} onClick={() => onLaunch(slug)}>\n <DynamicIcon name={app.icon} size={22} />\n </DockButton>\n </ContextMenuTrigger>\n <ContextMenuContent className=\"w-40\">\n <ContextMenuItem onClick={() => onLaunch(slug)}>\n <SquareArrowOutUpRight className=\"me-2 h-4 w-4\" />\n {running ? \"Show\" : \"Open\"}\n </ContextMenuItem>\n {onUnpin && (\n <ContextMenuItem onClick={() => onUnpin(slug)}>\n <PinOff className=\"me-2 h-4 w-4\" />\n Remove from Dock\n </ContextMenuItem>\n )}\n {running && onCloseApp && (\n <ContextMenuItem className=\"text-destructive\" onClick={() => onCloseApp(slug)}>\n <X className=\"me-2 h-4 w-4\" />\n Quit {app.name}\n </ContextMenuItem>\n )}\n </ContextMenuContent>\n </ContextMenu>\n );\n })}\n\n {onTrash && (\n <>\n <span className=\"mx-1 h-9 w-px self-center bg-white/15\" />\n <DockButton label=\"Trash\" onClick={onTrash}>\n <Trash2 className=\"h-5 w-5 text-white/80\" />\n </DockButton>\n </>\n )}\n </div>\n </div>\n );\n}\n\nDock.displayName = \"Dock\";\n","'use client'\n\n// DesktopIconGrid — desktop icons for installed OS apps. A single tap/click\n// opens the app (mobile-friendly); double-click also works. When `onMove` is\n// provided, icons are freely draggable and their positions are reported back\n// (persisted by the host as DesktopPrefs.icon_positions); otherwise they lay out\n// in a simple auto-grid. Right-click / long-press an icon to remove it from the\n// desktop (via `onRemove`).\n\nimport * as React from \"react\";\nimport { SquareArrowOutUpRight, Trash2 } from \"lucide-react\";\nimport { DesktopIcon } from \"./DesktopIcon\";\nimport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n} from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\n\nexport interface IconPos { x: number; y: number; }\n\nexport interface DesktopIconGridProps {\n apps: OSApp[];\n onOpen: (slug: string) => void;\n /** Saved per-slug positions (DesktopPrefs.icon_positions). */\n positions?: Record<string, IconPos>;\n /** Called when an icon is dragged to a new position. Enables drag mode. */\n onMove?: (slug: string, pos: IconPos) => void;\n /** Slugs hidden from the desktop (DesktopPrefs.desktop_hidden). */\n hidden?: string[];\n /** Right-click → Remove from Desktop. */\n onRemove?: (slug: string) => void;\n className?: string;\n}\n\nconst CELL_W = 88;\nconst CELL_H = 104;\nconst TOP = 48;\nconst LEFT = 16;\n\nfunction clampPos(p: IconPos): IconPos {\n if (typeof window === \"undefined\") return p;\n const x = Math.min(Math.max(p.x, 8), window.innerWidth - CELL_W);\n const y = Math.min(Math.max(p.y, TOP), window.innerHeight - CELL_H - 72);\n return { x, y };\n}\n\n// Default auto-layout: fill top-down columns from the top-left.\nfunction defaultPos(index: number): IconPos {\n const perCol = Math.max(3, Math.floor((typeof window !== \"undefined\" ? window.innerHeight - TOP - 120 : 600) / CELL_H));\n const col = Math.floor(index / perCol);\n const row = index % perCol;\n return { x: LEFT + col * CELL_W, y: TOP + row * CELL_H };\n}\n\nfunction IconMenu({ app, onOpen, onRemove, children }: { app: OSApp; onOpen: (s: string) => void; onRemove?: (s: string) => void; children: React.ReactNode }) {\n if (!onRemove) return <>{children}</>;\n return (\n <ContextMenu>\n <ContextMenuTrigger asChild>{children}</ContextMenuTrigger>\n <ContextMenuContent className=\"w-48\">\n <ContextMenuItem onClick={() => onOpen(app.slug)}>\n <SquareArrowOutUpRight className=\"me-2 h-4 w-4\" />\n Open\n </ContextMenuItem>\n <ContextMenuItem className=\"text-destructive\" onClick={() => onRemove(app.slug)}>\n <Trash2 className=\"me-2 h-4 w-4\" />\n Remove from Desktop\n </ContextMenuItem>\n </ContextMenuContent>\n </ContextMenu>\n );\n}\n\nexport function DesktopIconGrid({ apps, onOpen, positions, onMove, hidden = [], onRemove, className }: DesktopIconGridProps) {\n const [selected, setSelected] = React.useState<string | null>(null);\n const hiddenSet = React.useMemo(() => new Set(hidden), [hidden]);\n const visible = React.useMemo(\n () => apps.filter((a) => a.enabled && !hiddenSet.has(a.slug)),\n [apps, hiddenSet],\n );\n\n // Grid mode (no drag) — simple auto-fill grid.\n if (!onMove) {\n return (\n <div\n className={cn(\"grid auto-rows-max grid-cols-[repeat(auto-fill,5rem)] gap-1 p-4\", className)}\n onClick={(e) => { if (e.target === e.currentTarget) setSelected(null); }}\n >\n {visible.map((app) => (\n <IconMenu key={app.slug} app={app} onOpen={onOpen} onRemove={onRemove}>\n <DesktopIcon app={app} onOpen={onOpen} tapToOpen selected={selected === app.slug} onSelect={setSelected} />\n </IconMenu>\n ))}\n </div>\n );\n }\n\n // Free-drag mode — absolutely positioned, pointer-capture drag.\n return (\n <div\n className={cn(\"absolute inset-0\", className)}\n onPointerDown={(e) => { if (e.target === e.currentTarget) setSelected(null); }}\n >\n {visible.map((app, i) => (\n <PositionedIcon\n key={app.slug}\n app={app}\n pos={positions?.[app.slug] ?? defaultPos(i)}\n onOpen={onOpen}\n onMove={onMove}\n onRemove={onRemove}\n selected={selected === app.slug}\n onSelect={setSelected}\n />\n ))}\n </div>\n );\n}\n\nfunction PositionedIcon({\n app,\n pos,\n onOpen,\n onMove,\n onRemove,\n selected,\n onSelect,\n}: {\n app: OSApp;\n pos: IconPos;\n onOpen: (slug: string) => void;\n onMove: (slug: string, pos: IconPos) => void;\n onRemove?: (slug: string) => void;\n selected: boolean;\n onSelect: (slug: string) => void;\n}) {\n const [live, setLive] = React.useState(pos);\n const dragging = React.useRef(false);\n React.useEffect(() => { if (!dragging.current) setLive(pos); }, [pos]);\n\n const onPointerDown = (e: React.PointerEvent) => {\n if (e.button !== 0) return; // let right-click open the context menu\n onSelect(app.slug);\n const el = e.currentTarget as HTMLElement;\n const startX = e.clientX;\n const startY = e.clientY;\n const orig = live;\n let moved = false;\n let captured = false;\n const move = (ev: PointerEvent) => {\n const dx = ev.clientX - startX;\n const dy = ev.clientY - startY;\n if (!moved && (Math.abs(dx) > 4 || Math.abs(dy) > 4)) {\n moved = true;\n dragging.current = true;\n // Only capture once a real drag starts, so a plain tap still fires a\n // click/open (capturing on down suppresses synthetic click/dblclick).\n el.setPointerCapture(e.pointerId);\n captured = true;\n }\n if (dragging.current) setLive(clampPos({ x: orig.x + dx, y: orig.y + dy }));\n };\n const up = () => {\n el.removeEventListener(\"pointermove\", move);\n el.removeEventListener(\"pointerup\", up);\n if (captured) el.releasePointerCapture?.(e.pointerId);\n if (moved) {\n dragging.current = false;\n setLive((p) => { onMove(app.slug, p); return p; });\n } else {\n // A tap/click with no drag → open the app.\n onOpen(app.slug);\n }\n };\n el.addEventListener(\"pointermove\", move);\n el.addEventListener(\"pointerup\", up);\n };\n\n return (\n <IconMenu app={app} onOpen={onOpen} onRemove={onRemove}>\n <div className=\"absolute touch-none\" style={{ left: live.x, top: live.y }} onPointerDown={onPointerDown}>\n <DesktopIcon app={app} onOpen={onOpen} selected={selected} />\n </div>\n </IconMenu>\n );\n}\n\nDesktopIconGrid.displayName = \"DesktopIconGrid\";\n","'use client'\n\n// DesktopIcon — a single desktop icon (icon glyph + label). Double-click\n// (or Enter/Space when focused) calls `onOpen`.\n\nimport * as React from \"react\";\nimport { DynamicIcon } from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\n\nexport interface DesktopIconProps {\n app: OSApp;\n onOpen: (slug: string) => void;\n selected?: boolean;\n onSelect?: (slug: string) => void;\n /** Open on a single click/tap (mobile-friendly) instead of double-click. */\n tapToOpen?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function DesktopIcon({ app, onOpen, selected, onSelect, tapToOpen, className, style }: DesktopIconProps) {\n return (\n <button\n type=\"button\"\n style={style}\n className={cn(\n \"flex w-20 select-none flex-col items-center gap-1 rounded-lg p-2 text-center outline-none\",\n selected ? \"bg-primary/20\" : \"hover:bg-white/10 focus-visible:bg-white/10\",\n className,\n )}\n onClick={() => { onSelect?.(app.slug); if (tapToOpen) onOpen(app.slug); }}\n onDoubleClick={() => onOpen(app.slug)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onOpen(app.slug);\n }\n }}\n >\n <span\n className=\"flex h-12 w-12 items-center justify-center rounded-[14px] text-white shadow-md ring-1 ring-inset ring-white/25\"\n style={{ backgroundImage: `linear-gradient(160deg, ${app.color || \"#64748b\"}, ${app.color || \"#64748b\"}bb)` }}\n >\n <span className=\"drop-shadow-[0_1px_1px_rgba(0,0,0,0.35)]\">\n <DynamicIcon name={app.icon} size={24} />\n </span>\n </span>\n <span className=\"line-clamp-2 text-xs font-medium text-white [text-shadow:0_1px_3px_rgba(0,0,0,0.7)]\">{app.name}</span>\n </button>\n );\n}\n\nDesktopIcon.displayName = \"DesktopIcon\";\n","'use client'\n\n// DesktopContextMenu — right-click context menu wrapper around the desktop\n// surface. Placeholder items only; the consuming app wires real behaviour\n// via `onAction`.\n\nimport * as React from \"react\";\nimport { Image as ImageIcon, Palette, RefreshCw } from \"lucide-react\";\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuSeparator,\n ContextMenuTrigger,\n} from \"@togo-framework/ui-core\";\n\nexport type DesktopContextAction = \"change-wallpaper\" | \"personalize\" | \"refresh\";\n\nexport interface DesktopContextMenuProps {\n onAction: (action: DesktopContextAction) => void;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function DesktopContextMenu({ onAction, children, className }: DesktopContextMenuProps) {\n return (\n <ContextMenu>\n <ContextMenuTrigger className={className}>{children}</ContextMenuTrigger>\n <ContextMenuContent className=\"w-52\">\n <ContextMenuItem onClick={() => onAction(\"change-wallpaper\")}>\n <ImageIcon className=\"me-2 h-4 w-4\" />\n Change wallpaper\n </ContextMenuItem>\n <ContextMenuItem onClick={() => onAction(\"personalize\")}>\n <Palette className=\"me-2 h-4 w-4\" />\n Personalize\n </ContextMenuItem>\n <ContextMenuSeparator />\n <ContextMenuItem onClick={() => onAction(\"refresh\")}>\n <RefreshCw className=\"me-2 h-4 w-4\" />\n Refresh\n </ContextMenuItem>\n </ContextMenuContent>\n </ContextMenu>\n );\n}\n\nDesktopContextMenu.displayName = \"DesktopContextMenu\";\n","'use client'\n\n// WindowManager — tracks the list of open windows keyed by app slug\n// (open/close/focus/minimize/maximize/z-order) and renders one <Window/> per\n// open entry. Deliberately simple/pragmatic (a small context + hook), not a\n// generic pub-sub framework.\n\nimport * as React from \"react\";\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport { Window, clampWindowRect, type WindowRect } from \"./Window\";\n\nexport interface OpenWindowOptions {\n title: string;\n icon?: string;\n resizable?: boolean;\n width?: number;\n height?: number;\n content: React.ReactNode;\n /**\n * Deep-link target inside the app — e.g. open Settings straight to\n * \"wallpaper\". The app reads it via useWindowSection().\n */\n section?: string;\n}\n\ninterface WindowEntry extends OpenWindowOptions {\n slug: string;\n rect: WindowRect;\n minimized: boolean;\n maximized: boolean;\n z: number;\n /** Bumps every time `section` is (re)targeted, so apps re-navigate even to the same section. */\n sectionNonce: number;\n}\n\nexport interface WindowManagerContextValue {\n windows: WindowEntry[];\n open: (slug: string, opts: OpenWindowOptions) => void;\n close: (slug: string) => void;\n focus: (slug: string) => void;\n minimize: (slug: string) => void;\n /** Un-minimize + bring to front (without replacing content). */\n restore: (slug: string) => void;\n toggleMaximize: (slug: string) => void;\n isOpen: (slug: string) => boolean;\n isMinimized: (slug: string) => boolean;\n /** Deep-link an already-open window to a section (bumps its nonce so apps re-navigate). */\n setSection: (slug: string, section: string) => void;\n /** @internal used by <WindowManager/> to persist drag/resize geometry. */\n updateRect: (slug: string, rect: WindowRect) => void;\n}\n\n/** Section deep-link exposed to app window content. */\nexport interface WindowSection {\n slug: string;\n section?: string;\n nonce: number;\n}\n\nconst WindowSectionContext = createContext<WindowSection>({ slug: \"\", nonce: 0 });\n\n/**\n * Read the deep-link section targeted for the current app window (e.g. Settings\n * opened straight to \"wallpaper\"). `nonce` changes on every (re)target — react\n * to it so re-opening to the same section still navigates. Returns an empty\n * section outside a window.\n */\nexport function useWindowSection(): WindowSection {\n return useContext(WindowSectionContext);\n}\n\nconst WindowManagerContext = createContext<WindowManagerContextValue | null>(null);\n\nlet zCounter = 10;\n\nfunction defaultRect(width = 640, height = 440): WindowRect {\n const vw = typeof window !== \"undefined\" ? window.innerWidth : 1280;\n const vh = typeof window !== \"undefined\" ? window.innerHeight : 800;\n const x = Math.max(24, (vw - width) / 2 + (Math.random() * 40 - 20));\n const y = Math.max(24, (vh - height) / 2 + (Math.random() * 40 - 20));\n return clampWindowRect({ x, y, w: width, h: height });\n}\n\nexport function WindowManagerProvider({ children }: { children: React.ReactNode }) {\n const [windows, setWindows] = useState<WindowEntry[]>([]);\n const slugsRef = useRef<Set<string>>(new Set());\n\n const open = useCallback((slug: string, opts: OpenWindowOptions) => {\n setWindows((prev) => {\n const existing = prev.find((w) => w.slug === slug);\n zCounter += 1;\n if (existing) {\n return prev.map((w) =>\n w.slug === slug\n ? { ...w, ...opts, minimized: false, z: zCounter, sectionNonce: w.sectionNonce + 1 }\n : w,\n );\n }\n slugsRef.current.add(slug);\n return [\n ...prev,\n {\n slug,\n ...opts,\n rect: defaultRect(opts.width, opts.height),\n minimized: false,\n maximized: false,\n z: zCounter,\n sectionNonce: 0,\n },\n ];\n });\n }, []);\n\n const close = useCallback((slug: string) => {\n slugsRef.current.delete(slug);\n setWindows((prev) => prev.filter((w) => w.slug !== slug));\n }, []);\n\n const focus = useCallback((slug: string) => {\n zCounter += 1;\n const z = zCounter;\n setWindows((prev) => prev.map((w) => (w.slug === slug ? { ...w, z } : w)));\n }, []);\n\n const minimize = useCallback((slug: string) => {\n setWindows((prev) => prev.map((w) => (w.slug === slug ? { ...w, minimized: !w.minimized } : w)));\n }, []);\n\n const restore = useCallback((slug: string) => {\n zCounter += 1;\n const z = zCounter;\n setWindows((prev) => prev.map((w) => (w.slug === slug ? { ...w, minimized: false, z } : w)));\n }, []);\n\n const toggleMaximize = useCallback((slug: string) => {\n setWindows((prev) => prev.map((w) => (w.slug === slug ? { ...w, maximized: !w.maximized } : w)));\n }, []);\n\n const isOpen = useCallback((slug: string) => slugsRef.current.has(slug), []);\n const isMinimized = useCallback(\n (slug: string) => windows.find((w) => w.slug === slug)?.minimized ?? false,\n [windows],\n );\n\n const setSection = useCallback((slug: string, section: string) => {\n setWindows((prev) =>\n prev.map((w) => (w.slug === slug ? { ...w, section, sectionNonce: w.sectionNonce + 1 } : w)),\n );\n }, []);\n\n const updateRect = useCallback((slug: string, rect: WindowRect) => {\n setWindows((prev) => prev.map((e) => (e.slug === slug ? { ...e, rect } : e)));\n }, []);\n\n const value = useMemo<WindowManagerContextValue>(\n () => ({ windows, open, close, focus, minimize, restore, toggleMaximize, isOpen, isMinimized, setSection, updateRect }),\n [windows, open, close, focus, minimize, restore, toggleMaximize, isOpen, isMinimized, setSection, updateRect],\n );\n\n return (\n <WindowManagerContext.Provider value={value}>\n {children}\n </WindowManagerContext.Provider>\n );\n}\n\n/** Access the window manager API. Must be used within <WindowManagerProvider>. */\nexport function useWindowManager(): WindowManagerContextValue {\n const ctx = useContext(WindowManagerContext);\n if (!ctx) throw new Error(\"useWindowManager must be used within a <WindowManagerProvider>\");\n return ctx;\n}\n\n/**\n * WindowManager — renders one <Window/> per open entry tracked by the\n * nearest <WindowManagerProvider>. Place this once inside the desktop's\n * content area (DesktopShell does this for you).\n */\nexport function WindowManager() {\n const { windows, close, minimize, toggleMaximize, focus, updateRect } = useWindowManager();\n\n return (\n <>\n {windows.map((w) => (\n <Window\n key={w.slug}\n title={w.title}\n icon={w.icon}\n rect={w.rect}\n resizable={w.resizable ?? true}\n minimized={w.minimized}\n maximized={w.maximized}\n zIndex={w.z}\n onRectChange={(rect) => updateRect(w.slug, rect)}\n onClose={() => close(w.slug)}\n onMinimize={() => minimize(w.slug)}\n onMaximizeToggle={() => toggleMaximize(w.slug)}\n onFocus={() => focus(w.slug)}\n >\n <WindowSectionContext.Provider value={{ slug: w.slug, section: w.section, nonce: w.sectionNonce }}>\n {w.content}\n </WindowSectionContext.Provider>\n </Window>\n ))}\n </>\n );\n}\n\nWindowManagerProvider.displayName = \"WindowManagerProvider\";\nWindowManager.displayName = \"WindowManager\";\n","'use client'\n\n// Window — generic draggable/resizable window chrome. Drag (title bar) and\n// resize (edges + corners) use POINTER CAPTURE on the grabbed element, so the\n// gesture keeps tracking even when the pointer leaves the element / window —\n// the robust approach. Includes open/close/minimize animation states and a\n// traffic-light control cluster.\n\nimport * as React from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { X, Minus, Plus } from \"lucide-react\";\nimport { DynamicIcon } from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\n\nexport interface WindowRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nconst MIN_W = 320;\nconst MIN_H = 220;\n// Chrome insets: the top bar (~36px) and the floating Dock at the bottom. Windows\n// live BETWEEN them, so they never slip under the dock (\"push windows to the top\").\nconst TOP_INSET = 40;\nconst DOCK_INSET = 92;\n\nexport function clampWindowRect(r: WindowRect): WindowRect {\n if (typeof window === \"undefined\") return r;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const w = Math.min(Math.max(r.w, MIN_W), vw - 16);\n const h = Math.min(Math.max(r.h, MIN_H), vh - TOP_INSET - DOCK_INSET);\n const x = Math.min(Math.max(r.x, 8), Math.max(8, vw - w - 8));\n const y = Math.min(Math.max(r.y, TOP_INSET), Math.max(TOP_INSET, vh - h - DOCK_INSET));\n return { x, y, w, h };\n}\n\n// Which edges a resize handle drags.\ntype ResizeDir = \"e\" | \"s\" | \"se\" | \"w\" | \"n\" | \"nw\" | \"ne\" | \"sw\";\n\nexport interface WindowProps {\n title: string;\n icon?: string;\n rect: WindowRect;\n onRectChange: (rect: WindowRect) => void;\n resizable?: boolean;\n minimized?: boolean;\n zIndex?: number;\n onClose: () => void;\n onMinimize?: () => void;\n onMaximizeToggle?: () => void;\n maximized?: boolean;\n onFocus?: () => void;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport function Window({\n title,\n icon,\n rect,\n onRectChange,\n resizable = true,\n minimized = false,\n zIndex = 10,\n onClose,\n onMinimize,\n onMaximizeToggle,\n maximized = false,\n onFocus,\n className,\n children,\n}: WindowProps) {\n const [live, setLive] = useState<WindowRect>(rect);\n const dragging = useRef(false);\n // 'enter' plays the open animation; 'exit' plays close/minimize before unmount.\n const [phase, setPhase] = useState<\"enter\" | \"shown\">(\"enter\");\n const prevMinimized = useRef(minimized);\n // Snap zone preview while dragging the title bar (\"max\" | \"left\" | \"right\").\n const [snapHint, setSnapHint] = useState<null | \"max\" | \"left\" | \"right\">(null);\n // On phones the window fills the screen (iOS-style) — no drag/resize/snap.\n const [isMobile, setIsMobile] = useState(false);\n useEffect(() => {\n const mq = window.matchMedia(\"(max-width: 640px)\");\n const on = () => setIsMobile(mq.matches);\n on();\n mq.addEventListener(\"change\", on);\n return () => mq.removeEventListener(\"change\", on);\n }, []);\n\n useEffect(() => {\n if (!dragging.current) setLive(rect);\n }, [rect]);\n\n useEffect(() => {\n const t = setTimeout(() => setPhase(\"shown\"), 10);\n return () => clearTimeout(t);\n }, []);\n\n // Re-clamp on viewport resize so windows never drift off-screen.\n useEffect(() => {\n const onResize = () => setLive((r) => clampWindowRect(r));\n window.addEventListener(\"resize\", onResize);\n return () => window.removeEventListener(\"resize\", onResize);\n }, []);\n\n // Generic pointer-capture gesture. `apply` maps the pointer delta to a rect.\n const beginGesture = useCallback(\n (apply: (orig: WindowRect, dx: number, dy: number) => WindowRect) =>\n (e: React.PointerEvent) => {\n if (maximized) return;\n e.preventDefault();\n e.stopPropagation();\n onFocus?.();\n const orig = live;\n const startX = e.clientX;\n const startY = e.clientY;\n const el = e.currentTarget as HTMLElement;\n el.setPointerCapture(e.pointerId);\n dragging.current = true;\n\n const move = (ev: PointerEvent) => {\n setLive(clampWindowRect(apply(orig, ev.clientX - startX, ev.clientY - startY)));\n };\n const up = () => {\n dragging.current = false;\n el.removeEventListener(\"pointermove\", move);\n el.removeEventListener(\"pointerup\", up);\n el.removeEventListener(\"pointercancel\", up);\n setLive((r) => {\n onRectChange(r);\n return r;\n });\n };\n el.addEventListener(\"pointermove\", move);\n el.addEventListener(\"pointerup\", up);\n el.addEventListener(\"pointercancel\", up);\n },\n [maximized, live, onFocus, onRectChange],\n );\n\n // snapRect computes the target rect for a snap zone.\n const snapRect = useCallback((zone: \"max\" | \"left\" | \"right\"): WindowRect => {\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const h = vh - TOP_INSET - DOCK_INSET;\n if (zone === \"left\") return { x: 8, y: TOP_INSET, w: vw / 2 - 12, h };\n if (zone === \"right\") return { x: vw / 2 + 4, y: TOP_INSET, w: vw / 2 - 12, h };\n return { x: 8, y: TOP_INSET, w: vw - 16, h };\n }, []);\n\n // Title-bar drag with edge snapping (top = maximize, sides = half-tile).\n const onDragTitle = useCallback(\n (e: React.PointerEvent) => {\n if (maximized || isMobile) return;\n e.preventDefault();\n e.stopPropagation();\n onFocus?.();\n const orig = live;\n const startX = e.clientX;\n const startY = e.clientY;\n const el = e.currentTarget as HTMLElement;\n el.setPointerCapture(e.pointerId);\n dragging.current = true;\n\n const zoneFor = (x: number, y: number): \"max\" | \"left\" | \"right\" | null => {\n if (y <= 6) return \"max\";\n if (x <= 6) return \"left\";\n if (x >= window.innerWidth - 6) return \"right\";\n return null;\n };\n\n const move = (ev: PointerEvent) => {\n setLive(clampWindowRect({ ...orig, x: orig.x + (ev.clientX - startX), y: orig.y + (ev.clientY - startY) }));\n setSnapHint(zoneFor(ev.clientX, ev.clientY));\n };\n const up = (ev: PointerEvent) => {\n dragging.current = false;\n el.removeEventListener(\"pointermove\", move);\n el.removeEventListener(\"pointerup\", up);\n el.removeEventListener(\"pointercancel\", up);\n const zone = zoneFor(ev.clientX, ev.clientY);\n setSnapHint(null);\n if (zone) {\n const r = snapRect(zone);\n setLive(r);\n onRectChange(r);\n } else {\n setLive((r) => { onRectChange(r); return r; });\n }\n };\n el.addEventListener(\"pointermove\", move);\n el.addEventListener(\"pointerup\", up);\n el.addEventListener(\"pointercancel\", up);\n },\n [maximized, isMobile, live, onFocus, onRectChange, snapRect],\n );\n\n const resizeHandlers: Record<ResizeDir, (o: WindowRect, dx: number, dy: number) => WindowRect> = {\n e: (o, dx) => ({ ...o, w: o.w + dx }),\n s: (o, _dx, dy) => ({ ...o, h: o.h + dy }),\n se: (o, dx, dy) => ({ ...o, w: o.w + dx, h: o.h + dy }),\n w: (o, dx) => ({ ...o, x: o.x + dx, w: o.w - dx }),\n n: (o, _dx, dy) => ({ ...o, y: o.y + dy, h: o.h - dy }),\n nw: (o, dx, dy) => ({ ...o, x: o.x + dx, y: o.y + dy, w: o.w - dx, h: o.h - dy }),\n ne: (o, dx, dy) => ({ ...o, y: o.y + dy, w: o.w + dx, h: o.h - dy }),\n sw: (o, dx, dy) => ({ ...o, x: o.x + dx, w: o.w - dx, h: o.h + dy }),\n };\n\n const style = useMemo<React.CSSProperties>(() => {\n // Phone: fill the screen edge-to-edge below the top bar, above the dock.\n if (isMobile) return { left: 0, top: TOP_INSET, right: 0, bottom: DOCK_INSET, width: \"auto\", height: \"auto\", zIndex };\n if (maximized) return { left: 8, top: TOP_INSET, right: 8, bottom: DOCK_INSET, width: \"auto\", height: \"auto\", zIndex };\n return { left: live.x, top: live.y, width: live.w, height: live.h, zIndex };\n }, [isMobile, maximized, live, zIndex]);\n\n prevMinimized.current = minimized;\n const animating = phase === \"enter\";\n\n const snapPreview = snapHint\n ? (() => {\n const r = snapRect(snapHint);\n return (\n <div\n className=\"pointer-events-none fixed rounded-xl border-2 border-primary/70 bg-primary/15 backdrop-blur-sm transition-all duration-100\"\n style={{ left: r.x, top: r.y, width: r.w, height: r.h, zIndex: zIndex - 1 }}\n aria-hidden=\"true\"\n />\n );\n })()\n : null;\n\n // Kept mounted while minimized (preserves app state); flies down toward the\n // dock via transform so minimize/restore animate. Dock shows the running app.\n return (\n <>\n {snapPreview}\n <div\n className={cn(\n \"fixed flex flex-col overflow-hidden border border-border bg-card/95 shadow-2xl backdrop-blur-xl\",\n isMobile ? \"rounded-none\" : \"rounded-xl\",\n \"origin-bottom transition-[opacity,transform] duration-200 ease-out\",\n minimized\n ? \"pointer-events-none translate-y-[45vh] scale-50 opacity-0\"\n : animating\n ? \"scale-95 opacity-0\"\n : \"scale-100 opacity-100\",\n className,\n )}\n style={style}\n aria-hidden={minimized}\n onPointerDown={() => onFocus?.()}\n role=\"dialog\"\n aria-label={title}\n >\n {/* Title bar — drag handle + macOS traffic lights */}\n <div\n className=\"flex shrink-0 cursor-grab select-none items-center gap-2 border-b border-border bg-background/70 px-3 py-2 active:cursor-grabbing\"\n onPointerDown={onDragTitle}\n onDoubleClick={onMaximizeToggle}\n >\n <div className=\"group/lights flex items-center gap-1.5\" onPointerDown={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={onClose}\n className=\"flex h-3 w-3 items-center justify-center rounded-full bg-[#ff5f57] text-[#7a0d02] transition hover:brightness-95\"\n >\n <X className=\"h-2 w-2 opacity-0 transition-opacity group-hover/lights:opacity-100\" strokeWidth={3} />\n </button>\n <button\n type=\"button\"\n aria-label=\"Minimize\"\n onClick={onMinimize}\n className=\"flex h-3 w-3 items-center justify-center rounded-full bg-[#febc2e] text-[#985712] transition hover:brightness-95\"\n >\n <Minus className=\"h-2 w-2 opacity-0 transition-opacity group-hover/lights:opacity-100\" strokeWidth={3} />\n </button>\n <button\n type=\"button\"\n aria-label=\"Maximize\"\n onClick={onMaximizeToggle}\n className=\"flex h-3 w-3 items-center justify-center rounded-full bg-[#28c840] text-[#0b6118] transition hover:brightness-95\"\n >\n <Plus className=\"h-2 w-2 opacity-0 transition-opacity group-hover/lights:opacity-100\" strokeWidth={3} />\n </button>\n </div>\n {icon && <DynamicIcon name={icon} size={14} className=\"ms-1 shrink-0 text-muted-foreground\" />}\n <span className=\"flex-1 truncate text-center text-xs font-medium text-foreground\">{title}</span>\n <span className=\"w-12\" aria-hidden=\"true\" />\n </div>\n\n {/* Content */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <React.Suspense fallback={<WindowSpinner />}>{children}</React.Suspense>\n </div>\n\n {/* Resize handles (edges + corners) — desktop only */}\n {resizable && !maximized && !isMobile && (\n <>\n <div onPointerDown={beginGesture(resizeHandlers.n)} className=\"absolute inset-x-2 top-0 h-1.5 cursor-ns-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.s)} className=\"absolute inset-x-2 bottom-0 h-1.5 cursor-ns-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.w)} className=\"absolute inset-y-2 left-0 w-1.5 cursor-ew-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.e)} className=\"absolute inset-y-2 right-0 w-1.5 cursor-ew-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.nw)} className=\"absolute left-0 top-0 h-3 w-3 cursor-nwse-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.ne)} className=\"absolute right-0 top-0 h-3 w-3 cursor-nesw-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.sw)} className=\"absolute bottom-0 left-0 h-3 w-3 cursor-nesw-resize touch-none\" />\n <div onPointerDown={beginGesture(resizeHandlers.se)} className=\"absolute bottom-0 right-0 h-3.5 w-3.5 cursor-nwse-resize touch-none\" />\n </>\n )}\n </div>\n </>\n );\n}\n\nWindow.displayName = \"Window\";\n\n/** Centered loading spinner used as the window content fallback. */\nexport function WindowSpinner() {\n return (\n <div className=\"flex h-full min-h-[160px] w-full items-center justify-center\">\n <span className=\"h-7 w-7 animate-spin rounded-full border-2 border-muted border-t-primary\" aria-label=\"Loading\" />\n </div>\n );\n}\n","'use client'\n\n// Launchpad — a full-screen macOS-style app directory. Opens over a blurred\n// backdrop with a scale/fade-in animation. A tap/click launches an app; a\n// right-click / long-press opens a context menu to pin/unpin from the Dock or\n// add/remove from the Desktop. A search box filters apps (like macOS Launchpad).\n\nimport * as React from \"react\";\nimport { Search, Pin, PinOff, MonitorUp, MonitorX } from \"lucide-react\";\nimport { DynamicIcon } from \"@togo-framework/ui-core\";\nimport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n} from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport type { OSApp } from \"../../hooks/useOSApps\";\n\nexport interface LaunchpadProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n apps: OSApp[];\n /** Slugs currently pinned to the dock. */\n pinned?: string[];\n /** Slugs currently hidden from the desktop. */\n hidden?: string[];\n onLaunch: (slug: string) => void;\n onPin?: (slug: string) => void;\n onUnpin?: (slug: string) => void;\n onAddToDesktop?: (slug: string) => void;\n onRemoveFromDesktop?: (slug: string) => void;\n}\n\nexport function Launchpad({\n open,\n onOpenChange,\n apps,\n pinned = [],\n hidden = [],\n onLaunch,\n onPin,\n onUnpin,\n onAddToDesktop,\n onRemoveFromDesktop,\n}: LaunchpadProps) {\n const [mounted, setMounted] = React.useState(open);\n const [shown, setShown] = React.useState(false);\n const [query, setQuery] = React.useState(\"\");\n const pinnedSet = React.useMemo(() => new Set(pinned), [pinned]);\n const hiddenSet = React.useMemo(() => new Set(hidden), [hidden]);\n\n React.useEffect(() => {\n if (open) {\n setMounted(true);\n const t = setTimeout(() => setShown(true), 10);\n return () => clearTimeout(t);\n }\n setShown(false);\n const t = setTimeout(() => { setMounted(false); setQuery(\"\"); }, 200);\n return () => clearTimeout(t);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === \"Escape\") onOpenChange(false); };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [open, onOpenChange]);\n\n if (!mounted) return null;\n\n const q = query.trim().toLowerCase();\n const list = apps.filter((a) => a.enabled && (!q || a.name.toLowerCase().includes(q)));\n\n const launch = (slug: string) => { onLaunch(slug); onOpenChange(false); };\n\n return (\n <div\n className={cn(\n \"fixed inset-0 z-[60] flex flex-col items-center bg-black/40 backdrop-blur-2xl transition-opacity duration-200\",\n shown ? \"opacity-100\" : \"opacity-0\",\n )}\n onClick={(e) => { if (e.target === e.currentTarget) onOpenChange(false); }}\n >\n {/* Search */}\n <div className=\"mt-14 mb-8 w-full max-w-sm px-4\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-white/70\" />\n <input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search\"\n className=\"w-full rounded-xl border border-white/20 bg-white/10 py-2 ps-9 pe-3 text-center text-sm text-white placeholder:text-white/60 outline-none backdrop-blur-md focus:border-white/40\"\n />\n </div>\n </div>\n\n {/* App grid */}\n <div\n className={cn(\n \"grid w-full max-w-5xl grid-cols-3 gap-x-4 gap-y-8 overflow-y-auto px-6 pb-24 transition-transform duration-200 ease-out sm:grid-cols-5 md:grid-cols-6 lg:grid-cols-7\",\n shown ? \"scale-100\" : \"scale-90\",\n )}\n >\n {list.map((app) => {\n const isPinned = pinnedSet.has(app.slug);\n const onDesktop = !hiddenSet.has(app.slug);\n return (\n <ContextMenu key={app.slug}>\n <ContextMenuTrigger asChild>\n <button\n type=\"button\"\n onClick={() => launch(app.slug)}\n className=\"group flex select-none flex-col items-center gap-2 rounded-2xl p-2 outline-none transition hover:scale-105 focus-visible:scale-105\"\n >\n <span\n className=\"flex h-16 w-16 items-center justify-center rounded-[22px] text-white shadow-lg ring-1 ring-inset ring-white/25\"\n style={{ backgroundImage: `linear-gradient(160deg, ${app.color || \"#64748b\"}, ${app.color || \"#64748b\"}bb)` }}\n >\n <span className=\"drop-shadow-[0_1px_2px_rgba(0,0,0,0.4)]\">\n <DynamicIcon name={app.icon} size={32} />\n </span>\n </span>\n <span className=\"line-clamp-1 text-xs font-medium text-white [text-shadow:0_1px_3px_rgba(0,0,0,0.7)]\">{app.name}</span>\n </button>\n </ContextMenuTrigger>\n <ContextMenuContent className=\"w-52\">\n {isPinned\n ? onUnpin && (\n <ContextMenuItem onClick={() => onUnpin(app.slug)}>\n <PinOff className=\"me-2 h-4 w-4\" /> Remove from Dock\n </ContextMenuItem>\n )\n : onPin && (\n <ContextMenuItem onClick={() => onPin(app.slug)}>\n <Pin className=\"me-2 h-4 w-4\" /> Keep in Dock\n </ContextMenuItem>\n )}\n {onDesktop\n ? onRemoveFromDesktop && (\n <ContextMenuItem onClick={() => onRemoveFromDesktop(app.slug)}>\n <MonitorX className=\"me-2 h-4 w-4\" /> Remove from Desktop\n </ContextMenuItem>\n )\n : onAddToDesktop && (\n <ContextMenuItem onClick={() => onAddToDesktop(app.slug)}>\n <MonitorUp className=\"me-2 h-4 w-4\" /> Add to Desktop\n </ContextMenuItem>\n )}\n </ContextMenuContent>\n </ContextMenu>\n );\n })}\n {list.length === 0 && (\n <p className=\"col-span-full py-16 text-center text-sm text-white/70\">No apps match “{query}”.</p>\n )}\n </div>\n </div>\n );\n}\n\nLaunchpad.displayName = \"Launchpad\";\n","'use client'\n\n// NotificationCenter — a macOS-style right-side \"sideover\" panel listing the\n// user's notifications. Opened by clicking the top-bar clock (or the bell).\n// Transport-agnostic: the consuming app feeds notifications + callbacks.\n\nimport * as React from \"react\";\nimport { Bell, Check, CheckCheck } from \"lucide-react\";\nimport { Sheet, SheetContent, SheetHeader, SheetTitle } from \"@togo-framework/ui-core\";\nimport { Button } from \"@togo-framework/ui-core\";\nimport { ScrollArea } from \"@togo-framework/ui-core\";\nimport { formatRelativeTime } from \"@togo-framework/ui-core\";\nimport type { OSNotification } from \"./NotificationBell\";\n\nexport interface NotificationCenterProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n notifications: OSNotification[];\n unreadCount?: number;\n onMarkRead?: (id: string) => void;\n onMarkAllRead?: () => void;\n onNavigate?: (url: string) => void;\n /** Optional slot rendered at the top (e.g. a weather / calendar widget). */\n header?: React.ReactNode;\n}\n\nexport function NotificationCenter({\n open,\n onOpenChange,\n notifications,\n unreadCount = 0,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n header,\n}: NotificationCenterProps) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"w-full gap-0 border-white/10 bg-background/95 p-0 backdrop-blur-xl sm:max-w-sm\">\n <SheetHeader className=\"flex flex-row items-center justify-between gap-2 border-b border-border px-4 py-3\">\n <SheetTitle className=\"flex items-center gap-2 text-base\">\n <Bell className=\"h-4 w-4\" />\n Notifications\n {unreadCount > 0 && (\n <span className=\"rounded-full bg-primary px-1.5 py-0.5 text-[10px] font-semibold text-primary-foreground\">\n {unreadCount}\n </span>\n )}\n </SheetTitle>\n {notifications.length > 0 && onMarkAllRead && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 gap-1 text-xs\" onClick={onMarkAllRead}>\n <CheckCheck className=\"h-3.5 w-3.5\" />\n Mark all read\n </Button>\n )}\n </SheetHeader>\n\n {header && <div className=\"border-b border-border p-4\">{header}</div>}\n\n <ScrollArea className=\"h-[calc(100vh-8rem)]\">\n {notifications.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center gap-2 py-20 text-center text-muted-foreground\">\n <Bell className=\"h-8 w-8 opacity-40\" />\n <p className=\"text-sm\">You're all caught up</p>\n </div>\n ) : (\n <ul className=\"divide-y divide-border\">\n {notifications.map((n) => (\n <li\n key={n.id}\n className={cnRow(n.read)}\n onClick={() => {\n if (!n.read) onMarkRead?.(n.id);\n if (n.action_url) onNavigate?.(n.action_url);\n }}\n >\n <div className=\"flex items-start gap-3\">\n {!n.read && <span className=\"mt-1.5 h-2 w-2 shrink-0 rounded-full bg-primary\" aria-hidden=\"true\" />}\n <div className={n.read ? \"ps-5\" : \"\"}>\n <p className=\"text-sm font-medium text-foreground\">{n.title}</p>\n {n.body && <p className=\"mt-0.5 text-xs text-muted-foreground\">{n.body}</p>}\n <p className=\"mt-1 text-[11px] text-muted-foreground/70\">{formatRelativeTime(n.created_at)}</p>\n </div>\n {!n.read && onMarkRead && (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onMarkRead(n.id); }}\n className=\"ms-auto text-muted-foreground hover:text-foreground\"\n title=\"Mark read\"\n >\n <Check className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n </ScrollArea>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction cnRow(read: boolean): string {\n return [\n \"cursor-pointer px-4 py-3 transition-colors hover:bg-accent/50\",\n read ? \"opacity-70\" : \"\",\n ].filter(Boolean).join(\" \");\n}\n\nNotificationCenter.displayName = \"NotificationCenter\";\n","'use client'\n\n// NotificationBell — bell icon + unread badge + a popover list of\n// notifications. Transport-agnostic: the consuming app wires onFetch/onMarkRead\n// /onMarkAllRead to its own /api/notifications* endpoints (notification-center\n// plugin) — this component holds no fetch logic of its own.\n\nimport * as React from \"react\";\nimport { Bell, Check } from \"lucide-react\";\nimport { Button } from \"@togo-framework/ui-core\";\nimport { Badge } from \"@togo-framework/ui-core\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@togo-framework/ui-core\";\nimport { ScrollArea } from \"@togo-framework/ui-core\";\nimport { cn } from \"@togo-framework/ui-core\";\nimport { formatRelativeTime } from \"@togo-framework/ui-core\";\n\nexport interface OSNotification {\n id: string;\n type: string;\n title: string;\n body?: string;\n action_url?: string;\n read: boolean;\n created_at: string;\n}\n\nexport interface NotificationBellProps {\n notifications: OSNotification[];\n unreadCount: number;\n onMarkRead: (id: string) => void;\n onMarkAllRead: () => void;\n /** Called when the popover is opened — the consumer fetches fresh data. */\n onFetch?: () => void;\n onNavigate?: (url: string) => void;\n className?: string;\n}\n\nexport function NotificationBell({\n notifications,\n unreadCount,\n onMarkRead,\n onMarkAllRead,\n onFetch,\n onNavigate,\n className,\n}: NotificationBellProps) {\n const [open, setOpen] = React.useState(false);\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) onFetch?.();\n }}\n >\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className={cn(\"relative h-8 w-8\", className)} aria-label=\"Notifications\">\n <Bell className=\"h-4 w-4\" />\n {unreadCount > 0 && (\n <Badge\n variant=\"destructive\"\n className=\"absolute -right-1 -top-1 h-4 min-w-4 justify-center px-1 text-[9px] leading-none\"\n >\n {unreadCount > 99 ? \"99+\" : unreadCount}\n </Badge>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-80 p-0\">\n <div className=\"flex items-center justify-between border-b border-border p-3\">\n <p className=\"text-sm font-medium text-foreground\">Notifications</p>\n {unreadCount > 0 && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground\"\n >\n <Check className=\"h-3 w-3\" /> Mark all read\n </button>\n )}\n </div>\n <ScrollArea className=\"max-h-80\">\n <div className=\"p-1.5\">\n {notifications.length === 0 ? (\n <p className=\"py-6 text-center text-xs text-muted-foreground\">No notifications</p>\n ) : (\n notifications.map((n) => (\n <button\n key={n.id}\n type=\"button\"\n onClick={() => {\n if (!n.read) onMarkRead(n.id);\n if (n.action_url) onNavigate?.(n.action_url);\n }}\n className={cn(\n \"flex w-full flex-col gap-0.5 rounded-md px-2.5 py-2 text-start hover:bg-muted\",\n !n.read && \"bg-primary/5\",\n )}\n >\n <span className=\"flex items-center gap-2\">\n {!n.read && <span className=\"h-1.5 w-1.5 shrink-0 rounded-full bg-primary\" />}\n <span className=\"text-xs font-medium text-foreground\">{n.title}</span>\n </span>\n {n.body && <span className=\"line-clamp-2 text-xs text-muted-foreground\">{n.body}</span>}\n <span className=\"text-[10px] text-muted-foreground/70\">{formatRelativeTime(n.created_at)}</span>\n </button>\n ))\n )}\n </div>\n </ScrollArea>\n </PopoverContent>\n </Popover>\n );\n}\n\nNotificationBell.displayName = \"NotificationBell\";\n","'use client'\n\n// OSLoginScreen — a real desktop-OS login/lock screen (Windows/macOS/Linux\n// style): full-bleed wallpaper (image over gradient), a live ticking clock with\n// a greeting, and a centered frosted-glass card asking for a username +\n// password TOGETHER (single screen — not a corporate email-first wizard). It\n// talks to togo auth through the provided `authClient` (login / optional\n// one-click devLogin).\n//\n// Pass a `lockedUser` to switch to the macOS-style \"click your avatar, enter\n// your credentials\" unlock flow (reuses the existing LockScreen /\n// PasswordLockScreen components).\n\nimport * as React from \"react\";\nimport { ShieldCheck, Loader2, ArrowRight, Power, RotateCcw, Moon } from \"lucide-react\";\nimport { wallpaperCss } from \"@togo-framework/ui-core\";\nimport { Input } from \"@togo-framework/ui-core\";\nimport { Label } from \"@togo-framework/ui-core\";\nimport { Button } from \"@togo-framework/ui-core\";\nimport {\n PasswordInput,\n LockScreen,\n type LockScreenUser,\n PasswordLockScreen,\n type PasswordLockScreenUser,\n type UnlockCredentials,\n type AuthClient,\n} from \"@togo-framework/ui-auth\";\nimport { cn } from \"@togo-framework/ui-core\";\n\n/** Minimal brand shape for the login crest (name may be bilingual). */\nexport interface OSLoginBrand {\n name?: string | { en: string; ar: string };\n tagline?: { en: string; ar: string };\n icon?: React.ReactNode | null;\n}\n\nexport interface OSLoginScreenProps {\n /** Wallpaper id from `theme/wallpapers.ts` (defaults to \"aurora\"). */\n wallpaper?: string;\n /**\n * Optional background image URL, layered ON TOP of the gradient wallpaper\n * (cover/center). If it fails to load, the gradient shows through — so the\n * screen never ends up blank.\n */\n backgroundImage?: string;\n language?: \"en\" | \"ar\";\n brand?: OSLoginBrand;\n className?: string;\n\n // ── Sign-in form (username + password) ───────────────────────────────────\n authClient?: AuthClient;\n onSuccess?: () => void;\n /** Optional \"Create account\" affordance. */\n onRegister?: () => void;\n\n // ── Locked-session flow (avatar + PIN or avatar + password) ──────────────\n /** When set, renders LockScreen/PasswordLockScreen instead of the sign-in form. */\n lockedUser?: (LockScreenUser | PasswordLockScreenUser) & { usePassword?: boolean };\n onUnlockPin?: (pin: string) => Promise<void>;\n onUnlockPassword?: (creds: UnlockCredentials) => Promise<void>;\n onSignOut?: () => void;\n onForceLogout?: () => void;\n hasTOTP?: boolean;\n}\n\nfunction brandName(brand: OSLoginBrand | undefined, ar: boolean): string {\n const n = brand?.name;\n if (!n) return \"togo OS\";\n if (typeof n === \"string\") return n;\n return (ar ? n.ar || n.en : n.en || n.ar) ?? \"togo OS\";\n}\n\nfunction greeting(hour: number, ar: boolean): string {\n if (hour < 12) return ar ? \"صباح الخير\" : \"Good morning\";\n if (hour < 18) return ar ? \"مساء الخير\" : \"Good afternoon\";\n return ar ? \"مساء الخير\" : \"Good evening\";\n}\n\n// LiveClock — a real ticking clock (updates every second), isolated in its own\n// component so only it re-renders each tick (the sign-in form is untouched).\n// Big time with a blinking separator + live seconds, a time-of-day greeting, and\n// the full date — the signature \"lock screen\" element.\nfunction LiveClock({ ar }: { ar: boolean }) {\n const [now, setNow] = React.useState<Date | null>(null);\n React.useEffect(() => {\n setNow(new Date());\n const id = setInterval(() => setNow(new Date()), 1000);\n return () => clearInterval(id);\n }, []);\n\n if (!now) return <div className=\"h-[136px]\" aria-hidden=\"true\" />;\n\n const locale = ar ? \"ar\" : \"en-US\";\n const hh = now.getHours();\n const h12 = ((hh + 11) % 12) + 1;\n const mm = now.getMinutes();\n const ss = now.getSeconds();\n const ampm = hh < 12 ? \"AM\" : \"PM\";\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const blink = ss % 2 === 0; // blink the separator each second\n const dateStr = now.toLocaleDateString(locale, { weekday: \"long\", month: \"long\", day: \"numeric\" });\n\n return (\n <div className=\"flex flex-col items-center text-white drop-shadow-[0_2px_12px_rgba(0,0,0,0.55)]\">\n <div className=\"mb-1 text-sm font-medium uppercase tracking-[0.2em] text-white/70\">\n {greeting(hh, ar)}\n </div>\n <div className=\"flex items-start font-semibold tabular-nums leading-none tracking-tight\" aria-live=\"off\">\n <span className=\"text-[5.5rem]\">{ar ? pad(hh) : h12}</span>\n <span className={cn(\"text-[5.5rem] transition-opacity duration-200\", blink ? \"opacity-100\" : \"opacity-25\")}>:</span>\n <span className=\"text-[5.5rem]\">{pad(mm)}</span>\n <span className=\"ms-2 mt-3 flex flex-col items-start gap-1\">\n <span className=\"rounded bg-white/15 px-1.5 py-0.5 text-lg tabular-nums\">{pad(ss)}</span>\n {!ar && <span className=\"ps-0.5 text-xs font-medium tracking-widest text-white/70\">{ampm}</span>}\n </span>\n </div>\n <div className=\"mt-2 text-lg font-medium capitalize text-white/85\">{dateStr}</div>\n </div>\n );\n}\n\nexport function OSLoginScreen({\n wallpaper = \"aurora\",\n backgroundImage,\n language = \"en\",\n brand,\n className,\n authClient,\n onSuccess,\n onRegister,\n lockedUser,\n onUnlockPin,\n onUnlockPassword,\n onSignOut,\n onForceLogout,\n hasTOTP,\n}: OSLoginScreenProps) {\n const ar = language === \"ar\";\n const dir = ar ? \"rtl\" : \"ltr\";\n const gradient = wallpaperCss(wallpaper);\n // Image layered over the gradient (image wins where it loads; gradient shows\n // through if the image 404s or is offline — never a blank screen).\n const background = backgroundImage\n ? `url(\"${backgroundImage}\") center / cover no-repeat, ${gradient}`\n : gradient;\n\n const [email, setEmail] = React.useState(\"\");\n const [password, setPassword] = React.useState(\"\");\n const [error, setError] = React.useState(\"\");\n const [busy, setBusy] = React.useState(false);\n const [devBusy, setDevBusy] = React.useState(false);\n\n // ── Locked-session flow: reuse the existing lock-screen components ──────────\n if (lockedUser) {\n return (\n <div className={cn(\"fixed inset-0 flex items-center justify-center\", className)} style={{ background }} dir={dir}>\n <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm\" aria-hidden=\"true\" />\n <div className=\"relative z-10\">\n {lockedUser.usePassword && onUnlockPassword ? (\n <PasswordLockScreen\n user={lockedUser}\n onUnlock={onUnlockPassword}\n onSignOut={onSignOut ?? (() => {})}\n onForceLogout={onForceLogout}\n language={language}\n hasTOTP={hasTOTP}\n />\n ) : (\n <LockScreen\n user={lockedUser}\n onUnlock={onUnlockPin ?? (async () => {})}\n onSignOut={onSignOut ?? (() => {})}\n language={language}\n />\n )}\n </div>\n </div>\n );\n }\n\n const crest = brand && \"icon\" in brand && brand.icon !== undefined\n ? brand.icon\n : <ShieldCheck className=\"h-8 w-8\" strokeWidth={1.75} />;\n\n async function submit(e: React.FormEvent) {\n e.preventDefault();\n if (!authClient) return;\n setBusy(true);\n setError(\"\");\n try {\n const res = await authClient.login(email.trim(), password);\n if (res.challenge === \"none\") onSuccess?.();\n else setError(ar ? \"هذا الحساب يتطلب تحققاً إضافياً.\" : \"This account requires an extra verification step.\");\n } catch (err: unknown) {\n const msg = (err as { message?: string })?.message ?? \"\";\n setError(msg || (ar ? \"البريد الإلكتروني أو كلمة المرور غير صحيحة.\" : \"Incorrect email or password.\"));\n } finally {\n setBusy(false);\n }\n }\n\n async function devLogin() {\n if (!authClient?.devLogin) return;\n setDevBusy(true);\n setError(\"\");\n try {\n await authClient.devLogin();\n onSuccess?.();\n } catch {\n setError(ar ? \"تعذّر الدخول كمطوّر.\" : \"Dev login failed.\");\n } finally {\n setDevBusy(false);\n }\n }\n\n return (\n <div\n className={cn(\"fixed inset-0 flex flex-col items-center justify-center overflow-hidden\", className)}\n style={{ background }}\n dir={dir}\n >\n {/* Legibility scrim + subtle vignette over the wallpaper image. */}\n <div className=\"absolute inset-0 bg-gradient-to-b from-black/30 via-black/15 to-black/60\" aria-hidden=\"true\" />\n <div\n className=\"absolute inset-0\"\n style={{ background: \"radial-gradient(120% 80% at 50% 30%, transparent 40%, rgba(0,0,0,0.45) 100%)\" }}\n aria-hidden=\"true\"\n />\n\n {/* Centered column: live clock + sign-in card. */}\n <div className=\"relative z-10 flex w-full max-w-sm flex-col items-center gap-8 px-6\">\n <LiveClock ar={ar} />\n\n <div className=\"w-full rounded-3xl border border-white/20 bg-white/10 p-7 shadow-[0_20px_60px_-15px_rgba(0,0,0,0.6)] backdrop-blur-2xl\">\n <div className=\"flex flex-col items-center gap-3 text-center text-white\">\n <div className=\"flex h-[68px] w-[68px] items-center justify-center rounded-full border border-white/30 bg-gradient-to-br from-white/25 to-white/5 text-white shadow-inner ring-1 ring-white/10\">\n {crest}\n </div>\n <div>\n <div className=\"text-lg font-semibold\">{brandName(brand, ar)}</div>\n {brand?.tagline && (\n <div className=\"text-sm text-white/70\">{ar ? brand.tagline.ar : brand.tagline.en}</div>\n )}\n </div>\n </div>\n\n <form onSubmit={submit} className=\"mt-6 flex flex-col gap-4\">\n {error && (\n <div role=\"alert\" className=\"rounded-lg border border-red-300/40 bg-red-500/20 px-3 py-2 text-sm text-white\">\n {error}\n </div>\n )}\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"os-login-email\" className=\"text-sm font-medium text-white/90\">\n {ar ? \"اسم المستخدم أو البريد\" : \"Username or email\"}\n </Label>\n <Input\n id=\"os-login-email\"\n type=\"email\"\n dir=\"ltr\"\n autoComplete=\"username\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n disabled={busy}\n required\n autoFocus\n className=\"border-white/25 bg-white/10 text-white placeholder:text-white/50 focus-visible:ring-white/40\"\n />\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"os-login-password\" className=\"text-sm font-medium text-white/90\">\n {ar ? \"كلمة المرور\" : \"Password\"}\n </Label>\n <PasswordInput\n id=\"os-login-password\"\n language={language}\n autoComplete=\"current-password\"\n placeholder={ar ? \"أدخل كلمة المرور\" : \"Enter your password\"}\n value={password}\n onChange={(e) => setPassword((e as React.ChangeEvent<HTMLInputElement>).target.value)}\n disabled={busy}\n required\n className=\"border-white/25 bg-white/10 text-white placeholder:text-white/50 focus-visible:ring-white/40\"\n />\n </div>\n\n <Button\n type=\"submit\"\n disabled={busy}\n className=\"w-full gap-2 bg-white font-semibold text-slate-900 shadow-lg transition hover:bg-white/90\"\n >\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <ArrowRight className=\"h-4 w-4 rtl:rotate-180\" />}\n {busy ? (ar ? \"جارٍ تسجيل الدخول…\" : \"Signing in…\") : (ar ? \"تسجيل الدخول\" : \"Sign in\")}\n </Button>\n\n {authClient?.devLogin && (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={devLogin}\n disabled={devBusy}\n className=\"w-full gap-2 border-white/25 bg-transparent text-white hover:bg-white/10 hover:text-white\"\n >\n {devBusy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : null}\n {ar ? \"الدخول كمطوّر\" : \"Continue as developer\"}\n </Button>\n )}\n </form>\n\n {onRegister && (\n <p className=\"mt-5 text-center text-sm text-white/70\">\n {ar ? \"ليس لديك حساب؟ \" : \"No account? \"}\n <button type=\"button\" onClick={onRegister} className=\"font-medium text-white underline-offset-4 hover:underline\">\n {ar ? \"أنشئ واحداً\" : \"Create one\"}\n </button>\n </p>\n )}\n </div>\n </div>\n\n {/* OS-style power controls (decorative) — bottom center, like a real login. */}\n <div className=\"absolute inset-x-0 bottom-7 z-10 flex items-center justify-center gap-5\" aria-hidden=\"true\">\n {[Moon, RotateCcw, Power].map((Icon, i) => (\n <button\n key={i}\n type=\"button\"\n tabIndex={-1}\n className=\"flex h-10 w-10 items-center justify-center rounded-full border border-white/15 bg-white/10 text-white/70 backdrop-blur-md transition hover:bg-white/20 hover:text-white\"\n >\n <Icon className=\"h-4 w-4\" />\n </button>\n ))}\n </div>\n </div>\n );\n}\n\nOSLoginScreen.displayName = \"OSLoginScreen\";\n","'use client'\n\n// useOSSession — talks to the `os` plugin's /api/os/session endpoint.\n// GET on mount, PUT to persist. Same-origin cookie session (credentials:\n// \"include\"), JSON content type — mirrors the fetch-wrapper conventions used\n// by demo/web/src/lib/auth.ts and dashboard/web/lib/auth.ts, but kept generic\n// here (no CSRF token machinery — GET/PUT on a same-origin API).\n\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport interface DesktopPrefs {\n theme: string;\n accent: string;\n wallpaper: string;\n lock_wallpaper: string;\n dock_pinned: string[];\n desktop_hidden: string[];\n icon_positions: Record<string, { x: number; y: number }>;\n}\n\nconst DEFAULT_PREFS: DesktopPrefs = {\n theme: \"dark\",\n accent: \"#1FC7DC\",\n wallpaper: \"aurora\",\n lock_wallpaper: \"monterey\",\n dock_pinned: [],\n desktop_hidden: [],\n icon_positions: {},\n};\n\nexport interface UseOSSessionResult {\n prefs: DesktopPrefs;\n setPrefs: (prefs: DesktopPrefs | ((prev: DesktopPrefs) => DesktopPrefs)) => void;\n /** Persists the current `prefs` (or an explicit override) via PUT. */\n save: (next?: DesktopPrefs) => Promise<void>;\n loading: boolean;\n error: string | null;\n}\n\nexport function useOSSession(basePath = \"/api/os/session\"): UseOSSessionResult {\n const [prefs, setPrefs] = useState<DesktopPrefs>(DEFAULT_PREFS);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const res = await fetch(basePath, { credentials: \"include\" });\n if (!res.ok) throw new Error(`request failed (${res.status})`);\n const data = await res.json();\n if (!cancelled) setPrefs({ ...DEFAULT_PREFS, ...data });\n } catch (e) {\n if (!cancelled) setError(e instanceof Error ? e.message : \"failed to load session\");\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [basePath]);\n\n const save = useCallback(\n async (next?: DesktopPrefs) => {\n const body = next ?? prefs;\n const res = await fetch(basePath, {\n method: \"PUT\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw new Error(`save failed (${res.status})`);\n const data = await res.json().catch(() => body);\n setPrefs({ ...DEFAULT_PREFS, ...data });\n },\n [basePath, prefs],\n );\n\n return { prefs, setPrefs, save, loading, error };\n}\n","'use client'\n\n// useOSApps — talks to the `os` plugin's /api/os/apps endpoint (list of\n// installed OS apps: dock/desktop entries + their window defaults).\n\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport interface OSAppWindow {\n width: number;\n height: number;\n resizable: boolean;\n}\n\nexport interface OSApp {\n slug: string;\n name: string;\n icon: string;\n color: string;\n category: string;\n window: OSAppWindow;\n enabled: boolean;\n}\n\nexport interface UseOSAppsResult {\n apps: OSApp[];\n loading: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n}\n\nexport function useOSApps(basePath = \"/api/os/apps\"): UseOSAppsResult {\n const [apps, setApps] = useState<OSApp[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const refetch = useCallback(async () => {\n setLoading(true);\n try {\n const res = await fetch(basePath, { credentials: \"include\" });\n if (!res.ok) throw new Error(`request failed (${res.status})`);\n const data = await res.json();\n setApps(Array.isArray(data) ? data : (data.apps ?? []));\n setError(null);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"failed to load apps\");\n } finally {\n setLoading(false);\n }\n }, [basePath]);\n\n useEffect(() => {\n refetch();\n }, [refetch]);\n\n return { apps, loading, error, refetch };\n}\n"],"mappings":"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","names":["React","React","LogOut","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","jsx","jsxs","jsx","jsxs","t","cn","jsx","jsxs","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuSeparator","DropdownMenuItem","LogOut","React","DynamicIcon","cn","Fragment","jsx","jsxs","React","SquareArrowOutUpRight","Trash2","DynamicIcon","cn","jsx","jsxs","ContextMenu","ContextMenuTrigger","ContextMenuContent","ContextMenuItem","cn","Fragment","jsx","jsxs","SquareArrowOutUpRight","Trash2","ContextMenu","ContextMenuContent","ContextMenuItem","ContextMenuTrigger","jsx","jsxs","useCallback","useMemo","useRef","useState","React","useEffect","useMemo","useRef","useState","X","DynamicIcon","cn","Fragment","jsx","jsxs","Fragment","jsx","useState","useRef","useCallback","useMemo","React","Search","PinOff","DynamicIcon","ContextMenu","ContextMenuTrigger","ContextMenuContent","ContextMenuItem","cn","jsx","jsxs","t","jsx","jsxs","cn","Fragment","jsx","jsxs","React","Bell","Check","Button","ScrollArea","cn","formatRelativeTime","jsx","jsxs","React","Power","RotateCcw","Moon","wallpaperCss","Button","cn","jsx","jsxs","useCallback","useEffect","useState","useCallback","useEffect","useState"]}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@togo-framework/ui-desktop",
3
+ "version": "0.1.0",
4
+ "description": "togo UI kit — OS-like desktop shell (dock, windows, spotlight, launchpad, login screen) on top of the `os` plugin. Depends on @togo-framework/ui-core and @togo-framework/ui-auth.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": ["dist"],
17
+ "sideEffects": false,
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "typecheck": "tsc --noEmit",
22
+ "prepare": "tsup"
23
+ },
24
+ "peerDependencies": {
25
+ "lucide-react": ">=0.400.0",
26
+ "react": ">=18",
27
+ "react-dom": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@togo-framework/ui-core": "^0.1.2",
31
+ "@togo-framework/ui-auth": "^0.1.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/react": "^19.0.0",
35
+ "@types/react-dom": "^19.0.0",
36
+ "lucide-react": "^0.462.0",
37
+ "react": "^19.0.0",
38
+ "react-dom": "^19.0.0",
39
+ "tsup": "^8.3.0",
40
+ "typescript": "^5.6.0"
41
+ }
42
+ }