react-os-shell 4.8.0 → 4.10.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.
Files changed (57) hide show
  1. package/dist/{Browser-5ML7UNZG.js → Browser-KTPGFDE7.js} +6 -6
  2. package/dist/{Browser-5ML7UNZG.js.map → Browser-KTPGFDE7.js.map} +1 -1
  3. package/dist/{Calculator-APBKAUZ5.js → Calculator-BQQZETR7.js} +5 -5
  4. package/dist/{Calculator-APBKAUZ5.js.map → Calculator-BQQZETR7.js.map} +1 -1
  5. package/dist/ConfirmDialog-GRW3ZQQ2.js +4 -0
  6. package/dist/{ConfirmDialog-LO5WHLMD.js.map → ConfirmDialog-GRW3ZQQ2.js.map} +1 -1
  7. package/dist/{CurrencyConverter-YOWLTKY7.js → CurrencyConverter-QAC7SX3T.js} +5 -5
  8. package/dist/{CurrencyConverter-YOWLTKY7.js.map → CurrencyConverter-QAC7SX3T.js.map} +1 -1
  9. package/dist/{Documents-TGBZ4E2R.js → Documents-353VLYHV.js} +6 -6
  10. package/dist/{Documents-TGBZ4E2R.js.map → Documents-353VLYHV.js.map} +1 -1
  11. package/dist/{Files-LR5EBBSX.js → Files-QOTM6XX4.js} +8 -8
  12. package/dist/{Files-LR5EBBSX.js.map → Files-QOTM6XX4.js.map} +1 -1
  13. package/dist/{Notepad-HMTNO6IE.js → Notepad-OSEQE5B3.js} +6 -6
  14. package/dist/{Notepad-HMTNO6IE.js.map → Notepad-OSEQE5B3.js.map} +1 -1
  15. package/dist/{PomodoroTimer-NA3LPTTY.js → PomodoroTimer-U5VWYCVW.js} +6 -6
  16. package/dist/{PomodoroTimer-NA3LPTTY.js.map → PomodoroTimer-U5VWYCVW.js.map} +1 -1
  17. package/dist/{Preview-LXCNGCIK.js → Preview-MCB7KXQK.js} +6 -6
  18. package/dist/{Preview-LXCNGCIK.js.map → Preview-MCB7KXQK.js.map} +1 -1
  19. package/dist/{Sidebar-E553SOXC.js → Sidebar-ITLRERXE.js} +6 -5
  20. package/dist/Sidebar-ITLRERXE.js.map +1 -0
  21. package/dist/{Spreadsheet-VWUOANMV.js → Spreadsheet-BNNVXYL7.js} +6 -6
  22. package/dist/{Spreadsheet-VWUOANMV.js.map → Spreadsheet-BNNVXYL7.js.map} +1 -1
  23. package/dist/{Stock-OUVV3A7U.js → Stock-YVLKKFD2.js} +5 -5
  24. package/dist/{Stock-OUVV3A7U.js.map → Stock-YVLKKFD2.js.map} +1 -1
  25. package/dist/{Weather-INO44ZWL.js → Weather-QW5FVAMP.js} +5 -5
  26. package/dist/{Weather-INO44ZWL.js.map → Weather-QW5FVAMP.js.map} +1 -1
  27. package/dist/{WorldClock-K5IOWZ62.js → WorldClock-PMD62JKH.js} +5 -5
  28. package/dist/{WorldClock-K5IOWZ62.js.map → WorldClock-PMD62JKH.js.map} +1 -1
  29. package/dist/apps/index.js +18 -18
  30. package/dist/chunk-EQCNSQL4.js +7 -0
  31. package/dist/{chunk-FLHS7RBG.js.map → chunk-EQCNSQL4.js.map} +1 -1
  32. package/dist/{chunk-QAKURGOG.js → chunk-H5NDQZ4A.js} +3 -3
  33. package/dist/{chunk-QAKURGOG.js.map → chunk-H5NDQZ4A.js.map} +1 -1
  34. package/dist/{chunk-LBY7KH2W.js → chunk-HC6N2OXO.js} +3 -3
  35. package/dist/{chunk-LBY7KH2W.js.map → chunk-HC6N2OXO.js.map} +1 -1
  36. package/dist/{chunk-3NZSR3ZG.js → chunk-KILLK5UH.js} +3 -3
  37. package/dist/{chunk-3NZSR3ZG.js.map → chunk-KILLK5UH.js.map} +1 -1
  38. package/dist/{chunk-2Y6XUY65.js → chunk-P75F4NLD.js} +3 -3
  39. package/dist/{chunk-2Y6XUY65.js.map → chunk-P75F4NLD.js.map} +1 -1
  40. package/dist/{chunk-XRUVR7M7.js → chunk-QIVJUUPZ.js} +5 -5
  41. package/dist/{chunk-XRUVR7M7.js.map → chunk-QIVJUUPZ.js.map} +1 -1
  42. package/dist/{chunk-CKY62ZRU.js → chunk-QIY5BJJN.js} +13 -12
  43. package/dist/chunk-QIY5BJJN.js.map +1 -0
  44. package/dist/{chunk-DKDD5KXG.js → chunk-RVT2A2MO.js} +2 -2
  45. package/dist/chunk-RVT2A2MO.js.map +1 -0
  46. package/dist/{chunk-ITZB7RDX.js → chunk-YBRTKM4H.js} +3 -3
  47. package/dist/{chunk-ITZB7RDX.js.map → chunk-YBRTKM4H.js.map} +1 -1
  48. package/dist/index.d.ts +19 -5
  49. package/dist/index.js +197 -136
  50. package/dist/index.js.map +1 -1
  51. package/dist/styles.css +4 -3
  52. package/package.json +1 -1
  53. package/dist/ConfirmDialog-LO5WHLMD.js +0 -4
  54. package/dist/Sidebar-E553SOXC.js.map +0 -1
  55. package/dist/chunk-CKY62ZRU.js.map +0 -1
  56. package/dist/chunk-DKDD5KXG.js.map +0 -1
  57. package/dist/chunk-FLHS7RBG.js +0 -7
@@ -102,5 +102,5 @@ var GLASS_DIVIDER = "border-white/20";
102
102
  var GLASS_INPUT_BG = "glass-input-bg";
103
103
 
104
104
  export { GLASS_DIVIDER, GLASS_INPUT_BG, ShellAuthProvider, glassStyle, isReachable, isSection, navIcons, navSections, sectionIcons, setShellNavIcons, startMenuCategories, useShellAuth, visibleChildren };
105
- //# sourceMappingURL=chunk-DKDD5KXG.js.map
106
- //# sourceMappingURL=chunk-DKDD5KXG.js.map
105
+ //# sourceMappingURL=chunk-RVT2A2MO.js.map
106
+ //# sourceMappingURL=chunk-RVT2A2MO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shell/nav-types.ts","../src/shell-config/nav.tsx","../src/shell/ShellAuth.tsx","../src/utils/glass.ts"],"names":[],"mappings":"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","file":"chunk-RVT2A2MO.js","sourcesContent":["/**\n * Nav data types used by <Layout> + <StartMenu>. The actual sections, icons,\n * and categories are consumer-supplied via Layout props — the package never\n * ships nav DATA, only the shape it expects.\n */\nimport type { ReactNode } from 'react';\n\nexport interface NavItem {\n to: string;\n label: string;\n perms?: string[];\n dividerAfter?: boolean;\n /** Optional 3rd-level sub-items. Hovering the parent in <StartMenu> opens\n * a nested flyout; in <Sidebar> the parent becomes an inline sub-accordion. */\n children?: NavItem[];\n}\n\nexport interface NavSection {\n label: string;\n items: NavItem[];\n perms?: string[];\n /** Optional landing route for clicks on the section title itself\n * (e.g. R&D's `/rd` dashboard). */\n to?: string;\n /** Draw a divider under this section's row, so a consumer can split one\n * flat group into visual bands (e.g. an operator console pinned above the\n * ERP sections). Same knob as `NavItem.dividerAfter`, and drawn INSIDE the\n * section's wrapper so it stays below the row in the `flex-col-reverse`\n * Start menu a side/top taskbar renders. */\n dividerAfter?: boolean;\n}\n\nexport interface VirtualSection {\n label: string;\n items: NavItem[];\n icon?: ReactNode;\n}\n\nexport interface StartMenuCategories {\n /** Section labels rendered in the \"ERP\" group (bold, with section icon). */\n erp: string[];\n /** Section labels rendered in the \"system\" group. */\n system: string[];\n /** Optional virtual flyouts (e.g. a \"Utilities\" tray). */\n virtual?: VirtualSection[];\n /** Optional section labels pinned to the bottom of the menu, next to the user\n * profile, separated from the ERP group by a divider. */\n footer?: string[];\n /** Optional flat top-level items pinned to the bottom of the menu, next to\n * the user profile, separated from the ERP group by a divider. Unlike\n * `footer` (section labels rendered as flyouts), these render as direct\n * clickable rows — use for standalone destinations like System Preferences\n * or a bug-report link. */\n footerItems?: NavItem[];\n}\n\nexport function isSection(item: NavSection | NavItem): item is NavSection {\n return 'items' in item;\n}\n\n/** The host app's permission predicate — `useAuth().hasAnyPerm`. */\ntype HasAnyPerm = (perms: string[]) => boolean;\n\n/**\n * The sub-items of `item` this user may actually see.\n *\n * Every affordance for a nested group has to be derived from THIS list — the\n * chevron that advertises it, the hover handler that opens it, and the flyout\n * itself. Reading the raw `item.children` for the chevron while filtering only\n * for the flyout put an arrow on groups whose children were all\n * permission-hidden: hovering one highlighted the row and opened nothing.\n */\nexport function visibleChildren(item: NavItem, hasAnyPerm: HasAnyPerm): NavItem[] {\n return (item.children ?? []).filter(c => !c.perms || hasAnyPerm(c.perms));\n}\n\n/**\n * Whether a nav row leads anywhere for this user: either it's a plain\n * destination, or it's a group with at least one visible child. A group whose\n * children are all hidden has nothing to open — and by convention a group's\n * `to` is a synthetic key that never navigates, so there is nothing to fall\n * back to either. Such a row is dropped rather than rendered inert.\n */\nexport function isReachable(item: NavItem, hasAnyPerm: HasAnyPerm): boolean {\n return !item.children?.length || visibleChildren(item, hasAnyPerm).length > 0;\n}\n","/**\n * INTERNAL stub — package-side compatibility for files that legacy-imported\n * default nav data from `shell-config/nav`. The package never ships nav\n * DATA; consumers always supply `navSections` / `navIcons` / `sectionIcons` /\n * `categories` as Layout props.\n *\n * Empty defaults exported here so the copied files compile during the\n * extraction transition. Each consumer-facing field is also re-exported as\n * a TYPE alias for code that only needed the shape.\n */\nimport type { ReactNode } from 'react';\nimport type { NavItem, NavSection, StartMenuCategories, VirtualSection } from '../shell/nav-types';\n\n// Live proxy: WindowManager reads window-title icons from this module-level\n// map. Consumers register their full icon set once at app startup so the\n// title bars show the same glyphs as the start menu.\nconst _navIcons: Record<string, ReactNode> = {};\nexport const navIcons: Record<string, ReactNode> = new Proxy(_navIcons, {\n get(_t, k: string) { return _navIcons[k]; },\n has(_t, k: string) { return k in _navIcons; },\n ownKeys() { return Object.keys(_navIcons); },\n getOwnPropertyDescriptor(_t, k: string) {\n if (k in _navIcons) return { configurable: true, enumerable: true, value: _navIcons[k] };\n return undefined;\n },\n});\nexport function setShellNavIcons(icons: Record<string, ReactNode>): void {\n for (const k of Object.keys(_navIcons)) delete _navIcons[k];\n Object.assign(_navIcons, icons);\n}\n\nexport const sectionIcons: Record<string, ReactNode> = {};\nexport const navSections: (NavSection | NavItem)[] = [];\nexport const startMenuCategories: StartMenuCategories = { erp: [], system: [], virtual: [], footer: [] };\n\nexport { isSection } from '../shell/nav-types';\nexport type { NavItem, NavSection, StartMenuCategories, VirtualSection };\n","/**\n * Shell-side auth surface — JUST permission checking. The shell never\n * authenticates anyone or holds tokens; it only asks \"is the current user\n * allowed to see this nav item?\".\n *\n * Consumer wraps the app:\n *\n * <ShellAuthProvider value={{ hasAnyPerm: (perms) => myAuth.has(...perms) }}>\n * <Layout ... />\n * </ShellAuthProvider>\n *\n * When no provider is mounted, every permission check returns true — useful\n * for demos and consumers that don't gate their UI.\n */\nimport { createContext, useContext, type ReactNode } from 'react';\n\nexport interface ShellAuth {\n /** Returns true if the current user has any of the listed permission codes. */\n hasAnyPerm: (perms: string[]) => boolean;\n}\n\nconst DEFAULT: ShellAuth = { hasAnyPerm: () => true };\n\nconst ShellAuthContext = createContext<ShellAuth>(DEFAULT);\n\nexport function ShellAuthProvider({ value, children }: { value: ShellAuth; children: ReactNode }) {\n return <ShellAuthContext.Provider value={value}>{children}</ShellAuthContext.Provider>;\n}\n\nexport function useShellAuth(): ShellAuth {\n return useContext(ShellAuthContext);\n}\n","import type { CSSProperties } from 'react';\n\n/** Read the system menu opacity from CSS custom property set by Layout */\nfunction getMenuOpacity(): number {\n try {\n const val = getComputedStyle(document.documentElement).getPropertyValue('--menu-opacity')?.trim();\n if (val) return parseFloat(val);\n } catch {}\n return 0.95;\n}\n\nfunction isDarkTheme(): boolean {\n try {\n return document.documentElement.getAttribute('data-theme') === 'dark';\n } catch {\n return false;\n }\n}\n\n/** Whether the \"Reduce transparency\" preference is active (root class set by\n * Layout). When on, glass surfaces render solid + blur-free — the blur is the\n * GPU-expensive part, and dropping it is the point of the setting. */\nfunction reduceTransparency(): boolean {\n try {\n return document.documentElement.classList.contains('rosh-reduce-transparency');\n } catch {\n return false;\n }\n}\n\n/** Frosted glass style — shared across all menus, popups, and glass UI elements.\n * Reads --menu-opacity CSS variable set by the theme system, and adapts the\n * base tint to dark mode so menus don't stay light-cream when text is light. */\nexport function glassStyle(opacity?: number): CSSProperties {\n const o = opacity ?? getMenuOpacity();\n if (reduceTransparency()) {\n // Reduce-transparency: a fully opaque, blur-free surface. No\n // backdrop-filter (the expensive part on low-end GPUs) and a solid\n // background so menus/popups stay legible over any wallpaper. The global\n // stylesheet rule also strips backdrop-filter, but returning a solid\n // background here is what keeps the surface from reading as washed-out\n // translucent glass with the blur gone.\n return isDarkTheme()\n ? {\n background: '#1e1e2e',\n border: '1px solid rgba(255,255,255,0.12)',\n boxShadow: '0 8px 24px rgba(0,0,0,0.5)',\n }\n : {\n background: '#ffffff',\n border: '1px solid rgba(0,0,0,0.12)',\n boxShadow: '0 8px 24px rgba(0,0,0,0.18)',\n };\n }\n if (isDarkTheme()) {\n // Dark frosted glass — Catppuccin-aligned base (#1e1e2e / 30,30,46) with\n // a subtle gradient and lighter inner highlight.\n return {\n background: `linear-gradient(135deg, rgba(30,30,46,${o * 0.85}) 0%, rgba(24,24,37,${o * 0.75}) 50%, rgba(30,30,46,${o * 0.85}) 100%)`,\n backdropFilter: 'blur(40px) saturate(1.6)',\n WebkitBackdropFilter: 'blur(40px) saturate(1.6)',\n border: '1px solid rgba(255,255,255,0.08)',\n boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.06), inset 0 -1px 0 rgba(0,0,0,0.4), 0 8px 32px rgba(0,0,0,0.5), 0 2px 8px rgba(0,0,0,0.3)',\n };\n }\n return {\n background: `linear-gradient(135deg, rgba(255,255,255,${o * 0.85}) 0%, rgba(255,255,255,${o * 0.65}) 50%, rgba(255,255,255,${o * 0.75}) 100%)`,\n backdropFilter: 'blur(40px) saturate(1.8)',\n WebkitBackdropFilter: 'blur(40px) saturate(1.8)',\n border: '1px solid rgba(255,255,255,0.35)',\n boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -1px 0 rgba(255,255,255,0.1), 0 8px 32px rgba(0,0,0,0.15), 0 2px 8px rgba(0,0,0,0.08)',\n };\n}\n\n/** Glass divider border color */\nexport const GLASS_DIVIDER = 'border-white/20';\n\n/** Glass input/search bar background — declared in styles.css so it can adapt\n * to dark mode (a flat `bg-white/15` reads as a too-bright tile on the dark\n * glass gradient). */\nexport const GLASS_INPUT_BG = 'glass-input-bg';\n"]}
@@ -1,4 +1,4 @@
1
- import { Modal } from './chunk-CKY62ZRU.js';
1
+ import { Modal } from './chunk-QIY5BJJN.js';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
 
4
4
  var DEFAULT_APPEARANCE = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };
@@ -138,5 +138,5 @@ function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceCha
138
138
  }
139
139
 
140
140
  export { WidgetSettingsModal, loadAppearance };
141
- //# sourceMappingURL=chunk-ITZB7RDX.js.map
142
- //# sourceMappingURL=chunk-ITZB7RDX.js.map
141
+ //# sourceMappingURL=chunk-YBRTKM4H.js.map
142
+ //# sourceMappingURL=chunk-YBRTKM4H.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":"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","file":"chunk-ITZB7RDX.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":";;;AASO,IAAM,kBAAA,GAAuC,EAAE,aAAA,EAAe,EAAA,EAAI,iBAAiB,EAAA,EAAI,UAAA,EAAY,CAAA,EAAG,YAAA,EAAc,CAAA,EAAE;AAEtH,SAAS,eAAe,GAAA,EAA+B;AAC5D,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,aAAa,OAAA,CAAQ,GAAG,KAAK,EAAE,CAAA;AAExD,IAAA,IAAI,KAAA,CAAM,IAAA,IAAQ,IAAA,IAAQ,KAAA,CAAM,cAAc,IAAA,EAAM;AAClD,MAAA,KAAA,CAAM,aAAa,KAAA,CAAM,IAAA;AACzB,MAAA,KAAA,CAAM,eAAe,KAAA,CAAM,IAAA;AAC3B,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACf;AACA,IAAA,OAAO,EAAE,GAAG,kBAAA,EAAoB,GAAG,KAAA,EAAM;AAAA,EAC3C,CAAA,CAAA,MACM;AAAE,IAAA,OAAO,kBAAA;AAAA,EAAoB;AACrC;AAGe,SAAR,mBAAA,CAAqC,EAAE,IAAA,EAAM,OAAA,EAAS,OAAO,UAAA,EAAY,kBAAA,EAAoB,MAAA,EAAQ,QAAA,EAAS,EAQlH;AACD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,MAAM,GAAA,GAAM,sFAAA;AACZ,EAAA,MAAM,GAAA,GAAM,yDAAA;AAEZ,EAAA,uBACE,GAAA,CAAC,SAAI,aAAA,EAAe,CAAA,CAAA,KAAK,EAAE,eAAA,EAAgB,EAAG,aAAA,EAAe,CAAA,CAAA,KAAK,CAAA,CAAE,eAAA,IACpE,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,MAAY,OAAA,EAAkB,KAAA,EAAc,MAAK,IAAA,EACtD,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACZ,QAAA,EAAA;AAAA,IAAA,QAAA;AAAA,yBAGA,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,sBACnE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,0BAC9D,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,GAAA,EAAK,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,UAAK,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,qCAAQ,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,kBAAA,UAAA,CAAW,aAAA;AAAA,kBAAc;AAAA,iBAAA,EAAC;AAAA,eAAA,EAAO,CAAA;AAAA,8BACjF,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,OAAA;AAAA,kBAAQ,GAAA,EAAK,EAAA;AAAA,kBAAI,GAAA,EAAK,GAAA;AAAA,kBAAK,OAAO,UAAA,CAAW,aAAA;AAAA,kBACvD,QAAA,EAAU,CAAA,CAAA,KAAK,kBAAA,CAAmB,EAAE,GAAG,UAAA,EAAY,aAAA,EAAe,CAAC,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,kBAAG,SAAA,EAAW;AAAA;AAAA;AAAK,aAAA,EAC1G,CAAA;AAAA,iCACC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,GAAA,EAAK,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,UAAK,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,qCAAQ,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,kBAAA,UAAA,CAAW,UAAA;AAAA,kBAAW;AAAA,iBAAA,EAAE;AAAA,eAAA,EAAO,CAAA;AAAA,8BAC5E,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,OAAA;AAAA,kBAAQ,GAAA,EAAK,CAAA;AAAA,kBAAG,GAAA,EAAK,EAAA;AAAA,kBAAI,OAAO,UAAA,CAAW,UAAA;AAAA,kBACrD,QAAA,EAAU,CAAA,CAAA,KAAK,kBAAA,CAAmB,EAAE,GAAG,UAAA,EAAY,UAAA,EAAY,CAAC,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,kBAAG,SAAA,EAAW;AAAA;AAAA;AAAK,aAAA,EACvG;AAAA,WAAA,EACF;AAAA,SAAA,EACF,CAAA;AAAA,6BACC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA,UAAA,EAAQ,CAAA;AAAA,0BAChE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,GAAA,EAAK,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,UAAK,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,qCAAQ,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,kBAAA,UAAA,CAAW,eAAA;AAAA,kBAAgB;AAAA,iBAAA,EAAC;AAAA,eAAA,EAAO,CAAA;AAAA,8BACnF,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,OAAA;AAAA,kBAAQ,GAAA,EAAK,EAAA;AAAA,kBAAI,GAAA,EAAK,GAAA;AAAA,kBAAK,OAAO,UAAA,CAAW,eAAA;AAAA,kBACvD,QAAA,EAAU,CAAA,CAAA,KAAK,kBAAA,CAAmB,EAAE,GAAG,UAAA,EAAY,eAAA,EAAiB,CAAC,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,kBAAG,SAAA,EAAW;AAAA;AAAA;AAAK,aAAA,EAC5G,CAAA;AAAA,iCACC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,GAAA,EAAK,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,UAAK,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,qCAAQ,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,kBAAA,UAAA,CAAW,YAAA;AAAA,kBAAa;AAAA,iBAAA,EAAE;AAAA,eAAA,EAAO,CAAA;AAAA,8BAC9E,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,OAAA;AAAA,kBAAQ,GAAA,EAAK,CAAA;AAAA,kBAAG,GAAA,EAAK,EAAA;AAAA,kBAAI,OAAO,UAAA,CAAW,YAAA;AAAA,kBACrD,QAAA,EAAU,CAAA,CAAA,KAAK,kBAAA,CAAmB,EAAE,GAAG,UAAA,EAAY,YAAA,EAAc,CAAC,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,kBAAG,SAAA,EAAW;AAAA;AAAA;AAAK,aAAA,EACzG;AAAA,WAAA,EACF;AAAA,SAAA,EACF;AAAA,OAAA,EACF;AAAA,KAAA,EACF,CAAA;AAAA,oBAGA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAAO,OAAA,EAAS,MAAA;AAAA,UACf,SAAA,EAAU,gGAAA;AAAA,UAAiG,QAAA,EAAA;AAAA;AAAA,OAAI;AAAA,sBACjH,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAAO,OAAA,EAAS,OAAA;AAAA,UACf,SAAA,EAAU,6GAAA;AAAA,UAA8G,QAAA,EAAA;AAAA;AAAA;AAAM,KAAA,EAClI;AAAA,GAAA,EACF,GACF,CAAA,EACA,CAAA;AAEJ","file":"chunk-YBRTKM4H.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -44,6 +44,12 @@ interface NavSection {
44
44
  /** Optional landing route for clicks on the section title itself
45
45
  * (e.g. R&D's `/rd` dashboard). */
46
46
  to?: string;
47
+ /** Draw a divider under this section's row, so a consumer can split one
48
+ * flat group into visual bands (e.g. an operator console pinned above the
49
+ * ERP sections). Same knob as `NavItem.dividerAfter`, and drawn INSIDE the
50
+ * section's wrapper so it stays below the row in the `flex-col-reverse`
51
+ * Start menu a side/top taskbar renders. */
52
+ dividerAfter?: boolean;
47
53
  }
48
54
  interface VirtualSection {
49
55
  label: string;
@@ -225,11 +231,16 @@ interface ModalProps {
225
231
  openedFromKey?: string;
226
232
  /** Per-section window accent (SG#00372): an `R G B` triple (e.g.
227
233
  * '91 141 190'). When set, the panel publishes it as the
228
- * `--window-accent-rgb` CSS custom property and renders a thin accent
229
- * stripe across the top of the title bar, so overlapping windows from
234
+ * `--window-accent-rgb` CSS custom property, and if the user has turned
235
+ * the `window_accent_stripe` preference on renders a thin accent stripe
236
+ * between the title bar and the body, so overlapping windows from
230
237
  * different app sections are distinguishable at a glance. The header
231
238
  * itself stays theme-neutral — themes and the user's custom header
232
- * colour are untouched. Absent = exactly the previous rendering. */
239
+ * colour are untouched. Absent = exactly the previous rendering.
240
+ *
241
+ * The CSS custom property is published whenever `accentRgb` is passed,
242
+ * independent of the preference, so consumer CSS can key off the section
243
+ * accent even with the stripe switched off. */
233
244
  accentRgb?: string;
234
245
  children: React.ReactNode;
235
246
  }
@@ -956,8 +967,11 @@ declare function WindowManagerProvider({ children, windowAccentForRoute }: {
956
967
  children: ReactNode;
957
968
  /** SG#00372: optional per-section window accent. Called with each open
958
969
  * window's route ('/sales-orders', '/payments', …); return an `R G B`
959
- * triple (e.g. '91 141 190') to give that window a thin accent stripe on
960
- * its title bar (see Modal's `accentRgb`), or undefined for no accent.
970
+ * triple (e.g. '91 141 190') to give that window a thin accent stripe
971
+ * between its title bar and body (see Modal's `accentRgb`), or undefined
972
+ * for no accent. The stripe is drawn only for users who have switched it
973
+ * on in Customization → Windows; the mapping is still worth wiring
974
+ * regardless, since it also publishes `--window-accent-rgb` per window.
961
975
  * The consumer owns the route→section→colour mapping; omitting the prop
962
976
  * keeps every window exactly as before. */
963
977
  windowAccentForRoute?: (route: string) => string | undefined;
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
1
  import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-DINNWYVB.js';
2
2
  export { Breadcrumbs } from './chunk-DINNWYVB.js';
3
- import { subscribePomo, getPomoSnapshot } from './chunk-2Y6XUY65.js';
4
- export { setShellTodoProvider } from './chunk-2Y6XUY65.js';
3
+ import { subscribePomo, getPomoSnapshot } from './chunk-P75F4NLD.js';
4
+ export { setShellTodoProvider } from './chunk-P75F4NLD.js';
5
5
  import { SidebarLayout } from './chunk-YG45DAUT.js';
6
6
  export { SidebarLayout } from './chunk-YG45DAUT.js';
7
7
  export { ImageAnnotator_default as ImageAnnotator } from './chunk-QU5L5ZYM.js';
8
8
  import { toast_default } from './chunk-VENYVK3L.js';
9
9
  export { toast_default as toast } from './chunk-VENYVK3L.js';
10
- import { publishDesktopFolders, requestFilesTrashView, FolderGlyph, requestFilesDesktopFolderView, FileIconTile } from './chunk-QAKURGOG.js';
10
+ import { publishDesktopFolders, requestFilesTrashView, FolderGlyph, requestFilesDesktopFolderView, FileIconTile } from './chunk-H5NDQZ4A.js';
11
11
  import { setPdfPreview } from './chunk-BV6SQ46N.js';
12
12
  import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, setSoundForType, previewSound, setAllSounds, playLogout } from './chunk-D7PYW2QS.js';
13
- import { useAuth } from './chunk-3NZSR3ZG.js';
14
- export { setShellAuthBridge } from './chunk-3NZSR3ZG.js';
13
+ import { useAuth } from './chunk-KILLK5UH.js';
14
+ export { setShellAuthBridge } from './chunk-KILLK5UH.js';
15
15
  import { EditableGrid } from './chunk-GP4Y3VCB.js';
16
16
  export { EditableGrid } from './chunk-GP4Y3VCB.js';
17
17
  import './chunk-4SQU5YV6.js';
18
- import { APP_VERSION, VERSION } from './chunk-FLHS7RBG.js';
19
- export { VERSION } from './chunk-FLHS7RBG.js';
20
- import { registerModalEscapeInterceptor, useIsMobile, cancelWindowFront, requestWindowFront, useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, WINDOW_REGISTRY, isPageEntry, Modal, setPerfCollecting, drainPerfEvents, useShellPrefs, markMenuOpen, SIDEBAR_STRIP_W, forgetMaximizedWindowBoxes, ModalActions, useModalActive, client_default, LoadingSpinner, isShellApiClientConfigured, useUndo, CancelButton, setWindowPosition } from './chunk-CKY62ZRU.js';
21
- export { CancelButton, ConfirmProvider, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, UndoProvider, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, beginWindowGesture, commitExposeHighlight, confirm, confirmDestructive, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, markMenuOpen, prompt, registerModalEscapeInterceptor, requestWindowFront, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useIsActiveWindow, useLocalStoragePrefs, useModalActive, useShellPrefs, useUndo, useUndoable, useUndoableState, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-CKY62ZRU.js';
22
- import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, isReachable, sectionIcons, useShellAuth, visibleChildren } from './chunk-DKDD5KXG.js';
23
- export { GLASS_DIVIDER, GLASS_INPUT_BG, ShellAuthProvider, glassStyle, setShellNavIcons, useShellAuth } from './chunk-DKDD5KXG.js';
18
+ import { APP_VERSION, VERSION } from './chunk-EQCNSQL4.js';
19
+ export { VERSION } from './chunk-EQCNSQL4.js';
20
+ import { registerModalEscapeInterceptor, useIsMobile, cancelWindowFront, requestWindowFront, useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, WINDOW_REGISTRY, isPageEntry, Modal, setPerfCollecting, drainPerfEvents, useShellPrefs, markMenuOpen, SIDEBAR_STRIP_W, forgetMaximizedWindowBoxes, ModalActions, useModalActive, client_default, LoadingSpinner, isShellApiClientConfigured, useUndo, CancelButton, setWindowPosition } from './chunk-QIY5BJJN.js';
21
+ export { CancelButton, ConfirmProvider, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, UndoProvider, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, beginWindowGesture, commitExposeHighlight, confirm, confirmDestructive, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, markMenuOpen, prompt, registerModalEscapeInterceptor, requestWindowFront, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useIsActiveWindow, useLocalStoragePrefs, useModalActive, useShellPrefs, useUndo, useUndoable, useUndoableState, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-QIY5BJJN.js';
22
+ import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, isReachable, sectionIcons, useShellAuth, visibleChildren } from './chunk-RVT2A2MO.js';
23
+ export { GLASS_DIVIDER, GLASS_INPUT_BG, ShellAuthProvider, glassStyle, setShellNavIcons, useShellAuth } from './chunk-RVT2A2MO.js';
24
24
  import { createContext, lazy, forwardRef, useCallback, useState, useRef, useId, useEffect, useLayoutEffect, useSyncExternalStore, useMemo, useContext, isValidElement, cloneElement, Suspense, Fragment as Fragment$1, Children } from 'react';
25
25
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
26
26
  import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
@@ -3809,18 +3809,21 @@ function StartMenu({
3809
3809
  const items = getVisibleItems(section);
3810
3810
  if (items.length === 0) return null;
3811
3811
  const isHovered = hoveredSection === section.label;
3812
- return /* @__PURE__ */ jsx(
3812
+ return /* @__PURE__ */ jsxs(
3813
3813
  "div",
3814
3814
  {
3815
3815
  onMouseEnter: (e) => handleSectionHover(section.label, e),
3816
3816
  onMouseLeave: () => {
3817
3817
  hoverTimeout.current = setTimeout(() => setHoveredSection(null), 200);
3818
3818
  },
3819
- children: /* @__PURE__ */ jsxs("button", { className: `${itemCls} transition-colors ${isHovered ? "bg-blue-50 text-blue-700" : "text-gray-700 hover:bg-blue-50 hover:text-blue-700"}`, children: [
3820
- secIcon(section.label),
3821
- /* @__PURE__ */ jsx("span", { className: isErp ? "font-medium" : "", children: section.label }),
3822
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 ml-auto text-gray-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) })
3823
- ] })
3819
+ children: [
3820
+ /* @__PURE__ */ jsxs("button", { className: `${itemCls} transition-colors ${isHovered ? "bg-blue-50 text-blue-700" : "text-gray-700 hover:bg-blue-50 hover:text-blue-700"}`, children: [
3821
+ secIcon(section.label),
3822
+ /* @__PURE__ */ jsx("span", { className: isErp ? "font-medium" : "", children: section.label }),
3823
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 ml-auto text-gray-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) })
3824
+ ] }),
3825
+ section.dividerAfter && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" })
3826
+ ]
3824
3827
  },
3825
3828
  section.label
3826
3829
  );
@@ -4141,7 +4144,7 @@ function MobileAppLanding({
4141
4144
  }
4142
4145
  );
4143
4146
  }
4144
- var Sidebar = lazy(() => import('./Sidebar-E553SOXC.js'));
4147
+ var Sidebar = lazy(() => import('./Sidebar-ITLRERXE.js'));
4145
4148
  function useFavorites(wallpapers) {
4146
4149
  const { prefs, save } = useShellPrefs();
4147
4150
  const favorites = prefs.favorite_pages || [];
@@ -5135,6 +5138,24 @@ function Customization({ omit, section } = {}) {
5135
5138
  }
5136
5139
  )
5137
5140
  ] }),
5141
+ /* @__PURE__ */ jsxs("div", { children: [
5142
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3", children: "Windows" }),
5143
+ /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 cursor-pointer", children: [
5144
+ /* @__PURE__ */ jsx(
5145
+ "input",
5146
+ {
5147
+ type: "checkbox",
5148
+ checked: !!pref("window_accent_stripe"),
5149
+ onChange: (e) => savePref("window_accent_stripe", e.target.checked),
5150
+ className: "h-4 w-4 mt-0.5 rounded border-gray-300 text-blue-600"
5151
+ }
5152
+ ),
5153
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-700", children: [
5154
+ "Show section colour stripe",
5155
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-gray-400", children: "Draws a thin coloured line between a window's title bar and its content, one colour per area of the app, so overlapping windows are easier to tell apart at a glance." })
5156
+ ] })
5157
+ ] })
5158
+ ] }),
5138
5159
  /* @__PURE__ */ jsxs("div", { children: [
5139
5160
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3", children: "Diagnostics" }),
5140
5161
  /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 cursor-pointer", children: [
@@ -7607,6 +7628,18 @@ var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"
7607
7628
  var YEARS_PER_PAGE = 12;
7608
7629
  var yearPageStart = (y) => Math.floor(y / YEARS_PER_PAGE) * YEARS_PER_PAGE;
7609
7630
  var pad = (n) => String(n).padStart(2, "0");
7631
+ var EDGE_MARGIN = 8;
7632
+ function clipBounds(el) {
7633
+ for (let node = el.parentElement; node; node = node.parentElement) {
7634
+ const style = getComputedStyle(node);
7635
+ const overflowX = style.overflowX || style.overflow;
7636
+ if (overflowX && overflowX !== "visible") {
7637
+ const rect = node.getBoundingClientRect();
7638
+ if (rect.width > 0) return { left: rect.left, right: rect.right };
7639
+ }
7640
+ }
7641
+ return { left: 0, right: window.innerWidth };
7642
+ }
7610
7643
  function toISODate2(d) {
7611
7644
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
7612
7645
  }
@@ -7631,6 +7664,8 @@ function DateRangePicker({
7631
7664
  const [tempTo, setTempTo] = useState(to);
7632
7665
  const [activePreset, setActivePreset] = useState(null);
7633
7666
  const ref = useRef(null);
7667
+ const panelRef = useRef(null);
7668
+ const [align, setAlign] = useState("left");
7634
7669
  const now = /* @__PURE__ */ new Date();
7635
7670
  const [month, setMonth] = useState(from ? parseDate(from).getMonth() : now.getMonth());
7636
7671
  const [year, setYear] = useState(from ? parseDate(from).getFullYear() : now.getFullYear());
@@ -7640,6 +7675,22 @@ function DateRangePicker({
7640
7675
  useClickOutside(ref, useCallback(() => {
7641
7676
  if (open) setOpen(false);
7642
7677
  }, [open]));
7678
+ useLayoutEffect(() => {
7679
+ if (!open) return;
7680
+ const place = () => {
7681
+ const anchor = ref.current, panel = panelRef.current;
7682
+ if (!anchor || !panel) return;
7683
+ const trigger = anchor.getBoundingClientRect();
7684
+ const width = panel.getBoundingClientRect().width;
7685
+ const bounds = clipBounds(anchor);
7686
+ const fitsLeftAligned = trigger.left + width <= bounds.right - EDGE_MARGIN;
7687
+ const fitsRightAligned = trigger.right - width >= bounds.left + EDGE_MARGIN;
7688
+ setAlign(fitsLeftAligned || !fitsRightAligned ? "left" : "right");
7689
+ };
7690
+ place();
7691
+ window.addEventListener("resize", place);
7692
+ return () => window.removeEventListener("resize", place);
7693
+ }, [open]);
7643
7694
  const handleOpen = () => {
7644
7695
  setTempFrom(from);
7645
7696
  setTempTo(to);
@@ -7793,135 +7844,145 @@ function DateRangePicker({
7793
7844
  ]
7794
7845
  }
7795
7846
  ),
7796
- open && /* @__PURE__ */ jsxs("div", { className: "absolute z-50 mt-1 rounded-2xl p-4", style: { right: 0, ...glassStyle() }, children: [
7797
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-3", children: [
7798
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7799
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "From" }),
7800
- /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempFrom ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempFrom ? displayDate(tempFrom) : "Start" })
7801
- ] }),
7802
- /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2014" }),
7803
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7804
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "To" }),
7805
- /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempTo ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempTo ? displayDate(tempTo) : "End" })
7806
- ] })
7807
- ] }),
7808
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
7809
- /* @__PURE__ */ jsxs("div", { className: "w-64", children: [
7810
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2 px-1", children: [
7811
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleStep(-1), "aria-label": "Previous", className: "p-1 rounded-full hover:bg-gray-100 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) }) }),
7812
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm font-semibold text-gray-800", children: [
7813
- view === "days" && /* @__PURE__ */ jsx(
7814
- "button",
7815
- {
7816
- type: "button",
7817
- onClick: () => setView("months"),
7818
- className: "px-1.5 py-0.5 rounded-md hover:bg-gray-100 transition-colors",
7819
- children: monthName
7820
- }
7821
- ),
7822
- view === "years" ? /* @__PURE__ */ jsxs("span", { className: "px-1.5 py-0.5", children: [
7823
- yearPage,
7824
- " \u2013 ",
7825
- yearPage + YEARS_PER_PAGE - 1
7826
- ] }) : /* @__PURE__ */ jsx(
7827
- "button",
7828
- {
7829
- type: "button",
7830
- onClick: openYears,
7831
- className: "px-1.5 py-0.5 rounded-md hover:bg-gray-100 transition-colors",
7832
- children: year
7833
- }
7834
- )
7847
+ open && /* @__PURE__ */ jsxs(
7848
+ "div",
7849
+ {
7850
+ ref: panelRef,
7851
+ role: "dialog",
7852
+ "aria-label": "Date range",
7853
+ className: "absolute z-50 mt-1 rounded-2xl p-4",
7854
+ style: { ...align === "right" ? { right: 0 } : { left: 0 }, ...glassStyle() },
7855
+ children: [
7856
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-3", children: [
7857
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7858
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "From" }),
7859
+ /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempFrom ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempFrom ? displayDate(tempFrom) : "Start" })
7835
7860
  ] }),
7836
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleStep(1), "aria-label": "Next", className: "p-1 rounded-full hover:bg-gray-100 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) }) })
7861
+ /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2014" }),
7862
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7863
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "To" }),
7864
+ /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempTo ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempTo ? displayDate(tempTo) : "End" })
7865
+ ] })
7837
7866
  ] }),
7838
- /* @__PURE__ */ jsxs("div", { className: "min-h-[13.75rem]", children: [
7839
- view === "days" && /* @__PURE__ */ jsxs(Fragment, { children: [
7840
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-xs font-medium text-gray-500 mb-1", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx("div", { className: "py-1", children: d }, d)) }),
7841
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-sm", children: cells.map((c, i) => {
7842
- const isStart = c.date === tempFrom;
7843
- const isEnd = c.date === tempTo;
7844
- const isSelected = isStart || isEnd;
7845
- const inRange = isInRange(c.date);
7846
- return /* @__PURE__ */ jsx(
7847
- "button",
7848
- {
7849
- type: "button",
7850
- onClick: () => handleCalendarSelect(c.date),
7851
- className: `py-1.5 rounded-md transition-colors ${!c.current ? "text-gray-300" : isSelected ? "bg-blue-600 text-white font-semibold" : inRange ? "bg-blue-100 text-blue-800" : "text-gray-700 hover:bg-gray-100"}`,
7852
- children: c.day
7853
- },
7854
- i
7855
- );
7856
- }) })
7867
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
7868
+ /* @__PURE__ */ jsxs("div", { className: "w-64", children: [
7869
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2 px-1", children: [
7870
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleStep(-1), "aria-label": "Previous", className: "p-1 rounded-full hover:bg-gray-100 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) }) }),
7871
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm font-semibold text-gray-800", children: [
7872
+ view === "days" && /* @__PURE__ */ jsx(
7873
+ "button",
7874
+ {
7875
+ type: "button",
7876
+ onClick: () => setView("months"),
7877
+ className: "px-1.5 py-0.5 rounded-md hover:bg-gray-100 transition-colors",
7878
+ children: monthName
7879
+ }
7880
+ ),
7881
+ view === "years" ? /* @__PURE__ */ jsxs("span", { className: "px-1.5 py-0.5", children: [
7882
+ yearPage,
7883
+ " \u2013 ",
7884
+ yearPage + YEARS_PER_PAGE - 1
7885
+ ] }) : /* @__PURE__ */ jsx(
7886
+ "button",
7887
+ {
7888
+ type: "button",
7889
+ onClick: openYears,
7890
+ className: "px-1.5 py-0.5 rounded-md hover:bg-gray-100 transition-colors",
7891
+ children: year
7892
+ }
7893
+ )
7894
+ ] }),
7895
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleStep(1), "aria-label": "Next", className: "p-1 rounded-full hover:bg-gray-100 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) }) })
7896
+ ] }),
7897
+ /* @__PURE__ */ jsxs("div", { className: "min-h-[13.75rem]", children: [
7898
+ view === "days" && /* @__PURE__ */ jsxs(Fragment, { children: [
7899
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-xs font-medium text-gray-500 mb-1", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx("div", { className: "py-1", children: d }, d)) }),
7900
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-sm", children: cells.map((c, i) => {
7901
+ const isStart = c.date === tempFrom;
7902
+ const isEnd = c.date === tempTo;
7903
+ const isSelected = isStart || isEnd;
7904
+ const inRange = isInRange(c.date);
7905
+ return /* @__PURE__ */ jsx(
7906
+ "button",
7907
+ {
7908
+ type: "button",
7909
+ onClick: () => handleCalendarSelect(c.date),
7910
+ className: `py-1.5 rounded-md transition-colors ${!c.current ? "text-gray-300" : isSelected ? "bg-blue-600 text-white font-semibold" : inRange ? "bg-blue-100 text-blue-800" : "text-gray-700 hover:bg-gray-100"}`,
7911
+ children: c.day
7912
+ },
7913
+ i
7914
+ );
7915
+ }) })
7916
+ ] }),
7917
+ view === "months" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: MONTH_NAMES.map((name, m) => {
7918
+ const isCurrent = m === month;
7919
+ const isThisMonth = m === now.getMonth() && year === now.getFullYear();
7920
+ return /* @__PURE__ */ jsx(
7921
+ "button",
7922
+ {
7923
+ type: "button",
7924
+ onClick: () => selectMonth(m),
7925
+ className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisMonth ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
7926
+ children: name
7927
+ },
7928
+ name
7929
+ );
7930
+ }) }),
7931
+ view === "years" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPage + i).map((y) => {
7932
+ const isCurrent = y === year;
7933
+ const isThisYear = y === now.getFullYear();
7934
+ return /* @__PURE__ */ jsx(
7935
+ "button",
7936
+ {
7937
+ type: "button",
7938
+ onClick: () => selectYear(y),
7939
+ className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisYear ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
7940
+ children: y
7941
+ },
7942
+ y
7943
+ );
7944
+ }) })
7945
+ ] })
7857
7946
  ] }),
7858
- view === "months" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: MONTH_NAMES.map((name, m) => {
7859
- const isCurrent = m === month;
7860
- const isThisMonth = m === now.getMonth() && year === now.getFullYear();
7861
- return /* @__PURE__ */ jsx(
7947
+ /* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
7948
+ PRESET_LABELS.map((label) => /* @__PURE__ */ jsx(
7862
7949
  "button",
7863
7950
  {
7864
7951
  type: "button",
7865
- onClick: () => selectMonth(m),
7866
- className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisMonth ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
7867
- children: name
7952
+ onClick: () => handlePreset(label),
7953
+ className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === label ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
7954
+ children: label
7868
7955
  },
7869
- name
7870
- );
7871
- }) }),
7872
- view === "years" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPage + i).map((y) => {
7873
- const isCurrent = y === year;
7874
- const isThisYear = y === now.getFullYear();
7875
- return /* @__PURE__ */ jsx(
7956
+ label
7957
+ )),
7958
+ /* @__PURE__ */ jsx(
7876
7959
  "button",
7877
7960
  {
7878
7961
  type: "button",
7879
- onClick: () => selectYear(y),
7880
- className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisYear ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
7881
- children: y
7882
- },
7883
- y
7884
- );
7885
- }) })
7962
+ onClick: () => setActivePreset("Custom"),
7963
+ className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === "Custom" ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
7964
+ children: "Custom"
7965
+ }
7966
+ )
7967
+ ] })
7968
+ ] }),
7969
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4 pt-3 border-t border-gray-200", children: [
7970
+ clearable && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleClear, className: "px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700", children: "Clear" }),
7971
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setOpen(false), className: "px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50", children: "Cancel" }),
7972
+ /* @__PURE__ */ jsx(
7973
+ "button",
7974
+ {
7975
+ type: "button",
7976
+ onClick: handleApply,
7977
+ disabled: !tempFrom || !tempTo,
7978
+ className: "px-4 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 disabled:opacity-50",
7979
+ children: "Apply"
7980
+ }
7981
+ )
7886
7982
  ] })
7887
- ] }),
7888
- /* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
7889
- PRESET_LABELS.map((label) => /* @__PURE__ */ jsx(
7890
- "button",
7891
- {
7892
- type: "button",
7893
- onClick: () => handlePreset(label),
7894
- className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === label ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
7895
- children: label
7896
- },
7897
- label
7898
- )),
7899
- /* @__PURE__ */ jsx(
7900
- "button",
7901
- {
7902
- type: "button",
7903
- onClick: () => setActivePreset("Custom"),
7904
- className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === "Custom" ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
7905
- children: "Custom"
7906
- }
7907
- )
7908
- ] })
7909
- ] }),
7910
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4 pt-3 border-t border-gray-200", children: [
7911
- clearable && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleClear, className: "px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700", children: "Clear" }),
7912
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setOpen(false), className: "px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50", children: "Cancel" }),
7913
- /* @__PURE__ */ jsx(
7914
- "button",
7915
- {
7916
- type: "button",
7917
- onClick: handleApply,
7918
- disabled: !tempFrom || !tempTo,
7919
- className: "px-4 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 disabled:opacity-50",
7920
- children: "Apply"
7921
- }
7922
- )
7923
- ] })
7924
- ] })
7983
+ ]
7984
+ }
7985
+ )
7925
7986
  ] });
7926
7987
  }
7927
7988
  function Card({ children, header, footer, padded = true, className = "" }) {