react-os-shell 4.7.2 → 4.9.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 (58) hide show
  1. package/dist/{Browser-26KXGB6N.js → Browser-7AQ7Y4Z7.js} +6 -6
  2. package/dist/{Browser-26KXGB6N.js.map → Browser-7AQ7Y4Z7.js.map} +1 -1
  3. package/dist/{Calculator-APBKAUZ5.js → Calculator-B7KJQ2NF.js} +5 -5
  4. package/dist/{Calculator-APBKAUZ5.js.map → Calculator-B7KJQ2NF.js.map} +1 -1
  5. package/dist/ConfirmDialog-U5H3MP3M.js +4 -0
  6. package/dist/{ConfirmDialog-LO5WHLMD.js.map → ConfirmDialog-U5H3MP3M.js.map} +1 -1
  7. package/dist/{CurrencyConverter-YOWLTKY7.js → CurrencyConverter-AILEZUIU.js} +5 -5
  8. package/dist/{CurrencyConverter-YOWLTKY7.js.map → CurrencyConverter-AILEZUIU.js.map} +1 -1
  9. package/dist/{Documents-ZYVQKDBZ.js → Documents-IX6JISOV.js} +6 -6
  10. package/dist/{Documents-ZYVQKDBZ.js.map → Documents-IX6JISOV.js.map} +1 -1
  11. package/dist/{Files-BBXCHRQ5.js → Files-O7WK4TQG.js} +8 -8
  12. package/dist/{Files-BBXCHRQ5.js.map → Files-O7WK4TQG.js.map} +1 -1
  13. package/dist/{Notepad-XDOIP42K.js → Notepad-LO7FRU34.js} +6 -6
  14. package/dist/{Notepad-XDOIP42K.js.map → Notepad-LO7FRU34.js.map} +1 -1
  15. package/dist/{PomodoroTimer-NA3LPTTY.js → PomodoroTimer-DSVXJ7D4.js} +6 -6
  16. package/dist/{PomodoroTimer-NA3LPTTY.js.map → PomodoroTimer-DSVXJ7D4.js.map} +1 -1
  17. package/dist/{Preview-2A3CTDLY.js → Preview-QCAN5EU3.js} +6 -6
  18. package/dist/{Preview-2A3CTDLY.js.map → Preview-QCAN5EU3.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-4DTKZJHG.js → Spreadsheet-SUP2H2B4.js} +6 -6
  22. package/dist/{Spreadsheet-4DTKZJHG.js.map → Spreadsheet-SUP2H2B4.js.map} +1 -1
  23. package/dist/{Stock-OUVV3A7U.js → Stock-UT2JMEVS.js} +5 -5
  24. package/dist/{Stock-OUVV3A7U.js.map → Stock-UT2JMEVS.js.map} +1 -1
  25. package/dist/{Weather-INO44ZWL.js → Weather-37TNIYWI.js} +5 -5
  26. package/dist/{Weather-INO44ZWL.js.map → Weather-37TNIYWI.js.map} +1 -1
  27. package/dist/{WorldClock-K5IOWZ62.js → WorldClock-EESGFXPN.js} +5 -5
  28. package/dist/{WorldClock-K5IOWZ62.js.map → WorldClock-EESGFXPN.js.map} +1 -1
  29. package/dist/apps/index.js +18 -18
  30. package/dist/{chunk-ITZB7RDX.js → chunk-BOTXJSDK.js} +3 -3
  31. package/dist/{chunk-ITZB7RDX.js.map → chunk-BOTXJSDK.js.map} +1 -1
  32. package/dist/{chunk-CKY62ZRU.js → chunk-G6AUDFI4.js} +4 -4
  33. package/dist/{chunk-CKY62ZRU.js.map → chunk-G6AUDFI4.js.map} +1 -1
  34. package/dist/{chunk-QAKURGOG.js → chunk-H5NDQZ4A.js} +3 -3
  35. package/dist/{chunk-QAKURGOG.js.map → chunk-H5NDQZ4A.js.map} +1 -1
  36. package/dist/{chunk-LBY7KH2W.js → chunk-HC6N2OXO.js} +3 -3
  37. package/dist/{chunk-LBY7KH2W.js.map → chunk-HC6N2OXO.js.map} +1 -1
  38. package/dist/{chunk-3NZSR3ZG.js → chunk-KILLK5UH.js} +3 -3
  39. package/dist/{chunk-3NZSR3ZG.js.map → chunk-KILLK5UH.js.map} +1 -1
  40. package/dist/chunk-NQTQPOT4.js +7 -0
  41. package/dist/{chunk-A24AESZY.js.map → chunk-NQTQPOT4.js.map} +1 -1
  42. package/dist/{chunk-DKDD5KXG.js → chunk-RVT2A2MO.js} +2 -2
  43. package/dist/chunk-RVT2A2MO.js.map +1 -0
  44. package/dist/{chunk-4AQTXUSO.js → chunk-TIKW3XWE.js} +5 -5
  45. package/dist/{chunk-4AQTXUSO.js.map → chunk-TIKW3XWE.js.map} +1 -1
  46. package/dist/{chunk-2Y6XUY65.js → chunk-UH3H3KAN.js} +3 -3
  47. package/dist/{chunk-2Y6XUY65.js.map → chunk-UH3H3KAN.js.map} +1 -1
  48. package/dist/index.d.ts +6 -0
  49. package/dist/index.js +179 -136
  50. package/dist/index.js.map +1 -1
  51. package/dist/markup/index.d.ts +71 -15
  52. package/dist/markup/index.js +4 -9
  53. package/dist/markup/index.js.map +1 -1
  54. package/package.json +3 -2
  55. package/dist/ConfirmDialog-LO5WHLMD.js +0 -4
  56. package/dist/Sidebar-E553SOXC.js.map +0 -1
  57. package/dist/chunk-A24AESZY.js +0 -7
  58. package/dist/chunk-DKDD5KXG.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { navIcons } from './chunk-DKDD5KXG.js';
1
+ import { navIcons } from './chunk-RVT2A2MO.js';
2
2
  import { isValidElement, cloneElement } from 'react';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
 
@@ -167,5 +167,5 @@ function consumeFilesViewRequest() {
167
167
  }
168
168
 
169
169
  export { DesktopItemMiniIcon, FILES_OPEN_DESKTOP_FOLDER_EVENT, FILES_SHOW_TRASH_EVENT, FileIconTile, FolderGlyph, consumeFilesViewRequest, desktopItemTypeLabel, getDesktopFoldersSnapshot, peekFilesViewRequest, publishDesktopFolders, requestFilesDesktopFolderView, requestFilesTrashView, subscribeDesktopFolders };
170
- //# sourceMappingURL=chunk-QAKURGOG.js.map
171
- //# sourceMappingURL=chunk-QAKURGOG.js.map
170
+ //# sourceMappingURL=chunk-H5NDQZ4A.js.map
171
+ //# sourceMappingURL=chunk-H5NDQZ4A.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/desktopIcons.tsx"],"names":[],"mappings":"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","file":"chunk-QAKURGOG.js","sourcesContent":["/**\n * Shared desktop-icon building blocks.\n *\n * Desktop.tsx renders the desktop surface; Files.tsx renders desktop shortcut\n * folders inside the Files app. Both import the icon tiles, entity-icon config\n * and the desktop-folder bridge from here so the surfaces never visually\n * diverge — and so Desktop and Files never import each other (that would be an\n * import cycle).\n */\nimport { isValidElement, cloneElement, type ReactElement, type ReactNode } from 'react';\nimport { navIcons } from '../shell-config/nav';\nimport type { PreviewFileKind } from '../utils/openPreviewFile';\n\n// ── Gradient tiles ──────────────────────────────────────────────────────────\n// Per-app colored tile background, shared by the mobile home grid and the\n// desktop \"page\" shortcuts. Tailwind's JIT scans the source so each gradient\n// class string must appear in full somewhere — keep them inline.\nexport const ICON_GRADIENTS = [\n 'from-blue-500 to-blue-700',\n 'from-indigo-500 to-purple-600',\n 'from-purple-500 to-pink-600',\n 'from-pink-500 to-rose-600',\n 'from-red-500 to-rose-600',\n 'from-orange-500 to-red-600',\n 'from-amber-500 to-orange-600',\n 'from-yellow-500 to-amber-500',\n 'from-lime-500 to-green-600',\n 'from-green-500 to-emerald-600',\n 'from-emerald-500 to-teal-600',\n 'from-teal-500 to-cyan-600',\n 'from-cyan-500 to-sky-600',\n 'from-sky-500 to-blue-600',\n 'from-violet-500 to-fuchsia-600',\n];\n\nexport function hashGradient(seed: string): string {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h << 5) - h + seed.charCodeAt(i);\n return ICON_GRADIENTS[Math.abs(h) % ICON_GRADIENTS.length];\n}\n\n// ── Entity icon config ──────────────────────────────────────────────────────\nexport const ENTITY_ICON_COLORS: Record<string, string> = {\n order: 'text-blue-600', purchase_order: 'text-purple-600', invoice: 'text-green-600',\n client: 'text-indigo-600', manufacturer: 'text-orange-600', shipment: 'text-teal-600',\n part_number: 'text-gray-600', project: 'text-pink-600', mould: 'text-red-600',\n design: 'text-cyan-600', brand: 'text-amber-600', price_sheet: 'text-emerald-600',\n folder: 'text-yellow-600', page: 'text-blue-500',\n};\nexport const ENTITY_ICONS: Record<string, string> = {\n order: 'SO', purchase_order: 'PO', invoice: 'INV', client: 'CLI',\n manufacturer: 'MFR', shipment: 'DN', part_number: 'PN', project: 'PRJ',\n mould: 'MLD', design: 'DSN', brand: 'BRD', price_sheet: 'PS',\n vendor_invoice: 'VI', vendor_payment: 'VP', warranty_claim: 'WC',\n qc_report: 'QC', vendor_shipment: 'GRN', bank_account: 'BA',\n wheel_finish: 'WF', weight_log: 'WL', production_progress: 'PP',\n vendor_price_sheet: 'VPS', proposal: 'PR', folder: 'FLD',\n};\n\n// Glyphs and colors for the auto-tracked preview shortcuts that live in the\n// Documents folder. Keyed by `fileKind`, not `entityType`.\nexport const PREVIEW_FILE_CODES: Record<PreviewFileKind, string> = {\n pdf: 'PDF', dxf: 'DXF', '3d': 'STP', image: 'IMG', csv: 'CSV',\n};\nexport const PREVIEW_FILE_COLORS: Record<PreviewFileKind, string> = {\n pdf: 'text-red-600', dxf: 'text-blue-600', '3d': 'text-purple-600',\n image: 'text-emerald-600', csv: 'text-green-600',\n};\n\nexport interface DesktopItem {\n entityType: string;\n entityId: string;\n label: string;\n x?: number;\n y?: number;\n folderId?: string; // if inside a folder\n // Legacy free-form position inside the old folder window (pixels, relative\n // to the folder body). Folders now open in the Files app, which lists items\n // in a table — kept so previously-persisted shortcuts keep parsing.\n folderX?: number;\n folderY?: number;\n // Set for `entityType: 'preview-file'` shortcuts auto-recorded when the\n // user previews a file. `filePath` is the server-relative path passed\n // back into `openPreviewFile` on shortcut click.\n filePath?: string;\n fileKind?: PreviewFileKind;\n}\n\n/** Solid amber folder — the exact glyph the Files app uses for folders, so\n * desktop folders and Files-app folders read as the same object. */\nexport function FolderGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M2.25 7.125A2.25 2.25 0 014.5 4.875h4.504c.61 0 1.193.243 1.624.673l1.494 1.494a.75.75 0 00.53.22h7.098A2.25 2.25 0 0122 9.51v8.366A2.25 2.25 0 0119.75 20.125H4.25A2.25 2.25 0 012 17.875V7.125z\" />\n </svg>\n );\n}\n\n/** Page shortcuts reuse the consumer-registered nav icons; historically the\n * label was tried first, then the route. */\nfunction pageGlyph(entityId?: string, label?: string): ReactNode {\n return (label && navIcons[label]) || (entityId ? navIcons[entityId] : undefined);\n}\n\nconst PAGE_FALLBACK_GLYPH = (\n <svg className=\"h-7 w-7\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6z\" />\n </svg>\n);\n\n// Shared 48×48 tile used by the desktop icon renderer (and anything else\n// that needs a full-size shortcut tile), so all surfaces stay in sync.\nexport function FileIconTile({ entityType, isSelected, entityId, label, fileKind }: {\n entityType: string;\n isSelected: boolean;\n entityId?: string;\n label?: string;\n fileKind?: PreviewFileKind;\n}) {\n const isPreviewFile = entityType === 'preview-file' && fileKind;\n const previewColor = isPreviewFile ? PREVIEW_FILE_COLORS[fileKind!] : null;\n const previewCode = isPreviewFile ? PREVIEW_FILE_CODES[fileKind!] : null;\n if (entityType === 'folder') {\n return (\n <div className={`w-12 h-12 flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <FolderGlyph className=\"h-12 w-12 text-amber-500 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]\" />\n </div>\n );\n }\n if (entityType === 'page') {\n // App shortcut — colored gradient tile with the white nav glyph, same\n // treatment as the mobile home grid (and the same hash seed, the route,\n // so an app keeps its color across surfaces).\n const icon = pageGlyph(entityId, label);\n const gradient = hashGradient(entityId || label || 'page');\n return (\n <div className={`w-12 h-12 flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <span className={`h-11 w-11 rounded-xl bg-gradient-to-br ${gradient} flex items-center justify-center text-white border border-white/30 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]`}>\n {icon && isValidElement(icon)\n ? cloneElement(icon as ReactElement, { className: 'h-7 w-7 text-white' })\n : PAGE_FALLBACK_GLYPH}\n </span>\n </div>\n );\n }\n return (\n <div className={`w-12 h-12 relative flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <svg className={`w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${previewColor ?? ENTITY_ICON_COLORS[entityType] ?? 'text-gray-500'}`} viewBox=\"0 0 40 48\" fill=\"none\">\n <path d=\"M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z\" fill=\"white\" fillOpacity=\"0.92\" />\n <path d=\"M26 0l10 10H30a4 4 0 01-4-4V0z\" fill=\"currentColor\" fillOpacity=\"0.2\" />\n <path d=\"M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeOpacity=\"0.5\" />\n </svg>\n <span className={`absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${previewColor ?? ENTITY_ICON_COLORS[entityType] ?? 'text-gray-600'}`}>\n {previewCode ?? ENTITY_ICONS[entityType] ?? entityType.slice(0, 3).toUpperCase()}\n </span>\n </div>\n );\n}\n\n/** Compact row icon for desktop shortcuts listed inside the Files app. */\nexport function DesktopItemMiniIcon({ item }: { item: DesktopItem }) {\n if (item.entityType === 'folder') {\n return <FolderGlyph className=\"h-4 w-4 shrink-0 text-amber-500\" />;\n }\n if (item.entityType === 'page') {\n const icon = pageGlyph(item.entityId, item.label);\n return (\n <span className={`h-4 w-4 rounded bg-gradient-to-br ${hashGradient(item.entityId || item.label || 'page')} flex items-center justify-center text-white shrink-0`}>\n {icon && isValidElement(icon)\n ? cloneElement(icon as ReactElement, { className: 'h-3 w-3 text-white' })\n : <span className=\"h-1.5 w-1.5 rounded-[2px] border border-white/80\" />}\n </span>\n );\n }\n const color = (item.entityType === 'preview-file' && item.fileKind\n ? PREVIEW_FILE_COLORS[item.fileKind]\n : ENTITY_ICON_COLORS[item.entityType]) ?? 'text-gray-400';\n return (\n <svg className={`h-4 w-4 shrink-0 ${color}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" />\n </svg>\n );\n}\n\n/** Short type tag shown in the Files-app listing of a desktop folder. */\nexport function desktopItemTypeLabel(item: DesktopItem): string {\n if (item.entityType === 'preview-file' && item.fileKind) return PREVIEW_FILE_CODES[item.fileKind];\n if (item.entityType === 'page') return 'App';\n if (item.entityType === 'folder') return 'Folder';\n return ENTITY_ICONS[item.entityType] ?? item.entityType.slice(0, 3).toUpperCase();\n}\n\n// ── Desktop-folder bridge ───────────────────────────────────────────────────\n//\n// Desktop folders are virtual — shortcut collections persisted in the user's\n// prefs, not directories on the file server. The Files app shows them anyway\n// (sidebar section + folder listing), so Desktop publishes its live folder\n// state here and Files subscribes via useSyncExternalStore. Mutations route\n// back through the callbacks so persistence stays in Desktop's host-aware\n// save path.\n\nexport interface DesktopFoldersSnapshot {\n folders: { id: string; name: string; itemCount: number }[];\n itemsByFolder: Record<string, DesktopItem[]>;\n /** Clear `folderId` on these shortcuts — they reappear on the desktop. */\n moveToDesktop: (items: DesktopItem[]) => void;\n /** Delete these shortcuts entirely. */\n removeShortcuts: (items: DesktopItem[]) => void;\n}\n\nlet desktopFoldersSnapshot: DesktopFoldersSnapshot | null = null;\nconst desktopFoldersListeners = new Set<() => void>();\n\nexport function publishDesktopFolders(next: DesktopFoldersSnapshot | null) {\n desktopFoldersSnapshot = next;\n desktopFoldersListeners.forEach(l => l());\n}\n\nexport function subscribeDesktopFolders(listener: () => void): () => void {\n desktopFoldersListeners.add(listener);\n return () => { desktopFoldersListeners.delete(listener); };\n}\n\nexport function getDesktopFoldersSnapshot(): DesktopFoldersSnapshot | null {\n return desktopFoldersSnapshot;\n}\n\n// ── Files-app view side channel ─────────────────────────────────────────────\n//\n// Used by the desktop Trash icon and desktop folders to open the Files app\n// on a specific view. Two cases handled:\n// 1) Files isn't open yet — the flag below is read once on first mount.\n// 2) Files is already open — the event tells the live instance to flip view.\n// The caller follows up with `openPage('/files')` either way.\n\nexport type FilesViewRequest = 'trash' | { view: 'desktop-folder'; folderId: string };\n\nexport const FILES_VIEW_FLAG = '__REACT_OS_SHELL_FILES_VIEW__';\nexport const FILES_SHOW_TRASH_EVENT = 'react-os-shell:files-show-trash';\nexport const FILES_OPEN_DESKTOP_FOLDER_EVENT = 'react-os-shell:files-open-desktop-folder';\n\nexport function requestFilesTrashView() {\n if (typeof window === 'undefined') return;\n (window as any)[FILES_VIEW_FLAG] = 'trash' satisfies FilesViewRequest;\n window.dispatchEvent(new CustomEvent(FILES_SHOW_TRASH_EVENT));\n}\n\nexport function requestFilesDesktopFolderView(folderId: string) {\n if (typeof window === 'undefined') return;\n (window as any)[FILES_VIEW_FLAG] = { view: 'desktop-folder', folderId } satisfies FilesViewRequest;\n window.dispatchEvent(new CustomEvent(FILES_OPEN_DESKTOP_FOLDER_EVENT, { detail: { folderId } }));\n}\n\n/** Read the pending view request without clearing it. Side-effect free so\n * it is safe inside a `useState` initializer (StrictMode double-invokes\n * those; a read-and-clear there would hand the second invocation null). */\nexport function peekFilesViewRequest(): FilesViewRequest | null {\n if (typeof window === 'undefined') return null;\n const raw = (window as any)[FILES_VIEW_FLAG];\n if (raw === 'trash') return 'trash';\n if (raw && typeof raw === 'object' && raw.view === 'desktop-folder' && typeof raw.folderId === 'string') return raw;\n return null;\n}\n\n/** Read-and-clear the pending view request (Files calls this once mounted). */\nexport function consumeFilesViewRequest(): FilesViewRequest | null {\n const req = peekFilesViewRequest();\n if (typeof window !== 'undefined') (window as any)[FILES_VIEW_FLAG] = null;\n return req;\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/desktopIcons.tsx"],"names":[],"mappings":";;;;AAiBO,IAAM,cAAA,GAAiB;AAAA,EAC5B,2BAAA;AAAA,EACA,+BAAA;AAAA,EACA,6BAAA;AAAA,EACA,2BAAA;AAAA,EACA,0BAAA;AAAA,EACA,4BAAA;AAAA,EACA,8BAAA;AAAA,EACA,8BAAA;AAAA,EACA,4BAAA;AAAA,EACA,+BAAA;AAAA,EACA,8BAAA;AAAA,EACA,2BAAA;AAAA,EACA,0BAAA;AAAA,EACA,0BAAA;AAAA,EACA;AACF,CAAA;AAEO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,CAAA,EAAA,EAAK,CAAA,GAAA,CAAK,CAAA,IAAK,CAAA,IAAK,CAAA,GAAI,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA;AAC1E,EAAA,OAAO,eAAe,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,eAAe,MAAM,CAAA;AAC3D;AAGO,IAAM,kBAAA,GAA6C;AAAA,EACxD,KAAA,EAAO,eAAA;AAAA,EAAiB,cAAA,EAAgB,iBAAA;AAAA,EAAmB,OAAA,EAAS,gBAAA;AAAA,EACpE,MAAA,EAAQ,iBAAA;AAAA,EAAmB,YAAA,EAAc,iBAAA;AAAA,EAAmB,QAAA,EAAU,eAAA;AAAA,EACtE,WAAA,EAAa,eAAA;AAAA,EAAiB,OAAA,EAAS,eAAA;AAAA,EAAiB,KAAA,EAAO,cAAA;AAAA,EAC/D,MAAA,EAAQ,eAAA;AAAA,EAAiB,KAAA,EAAO,gBAAA;AAAA,EAAkB,WAAA,EAAa,kBAAA;AAAA,EAC/D,MAAA,EAAQ,iBAAA;AAAA,EAAmB,IAAA,EAAM;AACnC,CAAA;AACO,IAAM,YAAA,GAAuC;AAAA,EAClD,KAAA,EAAO,IAAA;AAAA,EAAM,cAAA,EAAgB,IAAA;AAAA,EAAM,OAAA,EAAS,KAAA;AAAA,EAAO,MAAA,EAAQ,KAAA;AAAA,EAC3D,YAAA,EAAc,KAAA;AAAA,EAAO,QAAA,EAAU,IAAA;AAAA,EAAM,WAAA,EAAa,IAAA;AAAA,EAAM,OAAA,EAAS,KAAA;AAAA,EACjE,KAAA,EAAO,KAAA;AAAA,EAAO,MAAA,EAAQ,KAAA;AAAA,EAAO,KAAA,EAAO,KAAA;AAAA,EAAO,WAAA,EAAa,IAAA;AAAA,EACxD,cAAA,EAAgB,IAAA;AAAA,EAAM,cAAA,EAAgB,IAAA;AAAA,EAAM,cAAA,EAAgB,IAAA;AAAA,EAC5D,SAAA,EAAW,IAAA;AAAA,EAAM,eAAA,EAAiB,KAAA;AAAA,EAAO,YAAA,EAAc,IAAA;AAAA,EACvD,YAAA,EAAc,IAAA;AAAA,EAAM,UAAA,EAAY,IAAA;AAAA,EAAM,mBAAA,EAAqB,IAAA;AAAA,EAC3D,kBAAA,EAAoB,KAAA;AAAA,EAAO,QAAA,EAAU,IAAA;AAAA,EAAM,MAAA,EAAQ;AACrD,CAAA;AAIO,IAAM,kBAAA,GAAsD;AAAA,EACjE,GAAA,EAAK,KAAA;AAAA,EAAO,GAAA,EAAK,KAAA;AAAA,EAAO,IAAA,EAAM,KAAA;AAAA,EAAO,KAAA,EAAO,KAAA;AAAA,EAAO,GAAA,EAAK;AAC1D,CAAA;AACO,IAAM,mBAAA,GAAuD;AAAA,EAClE,GAAA,EAAK,cAAA;AAAA,EAAgB,GAAA,EAAK,eAAA;AAAA,EAAiB,IAAA,EAAM,iBAAA;AAAA,EACjD,KAAA,EAAO,kBAAA;AAAA,EAAoB,GAAA,EAAK;AAClC,CAAA;AAuBO,SAAS,WAAA,CAAY,EAAE,SAAA,EAAU,EAA2B;AACjE,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAsB,IAAA,EAAK,cAAA,EAAe,OAAA,EAAQ,WAAA,EACrD,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,mMAAA,EAAoM,CAAA,EAC9M,CAAA;AAEJ;AAIA,SAAS,SAAA,CAAU,UAAmB,KAAA,EAA2B;AAC/D,EAAA,OAAQ,SAAS,QAAA,CAAS,KAAK,MAAO,QAAA,GAAW,QAAA,CAAS,QAAQ,CAAA,GAAI,MAAA,CAAA;AACxE;AAEA,IAAM,mBAAA,uBACH,KAAA,EAAA,EAAI,SAAA,EAAU,WAAU,IAAA,EAAK,MAAA,EAAO,SAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EAC1F,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oHAAA,EAAqH,CAAA,EAC5K,CAAA;AAKK,SAAS,aAAa,EAAE,UAAA,EAAY,YAAY,QAAA,EAAU,KAAA,EAAO,UAAS,EAM9E;AACD,EAAA,MAAM,aAAA,GAAgB,eAAe,cAAA,IAAkB,QAAA;AACvD,EAAA,MAAM,YAAA,GAAe,aAAA,GAAgB,mBAAA,CAAoB,QAAS,CAAA,GAAI,IAAA;AACtE,EAAA,MAAM,WAAA,GAAc,aAAA,GAAgB,kBAAA,CAAmB,QAAS,CAAA,GAAI,IAAA;AACpE,EAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,IAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,2CAAA,EAA8C,UAAA,GAAa,gDAAA,GAAmD,EAAE,CAAA,CAAA,EAC9H,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,kEAAA,EAAmE,CAAA,EAC5F,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,eAAe,MAAA,EAAQ;AAIzB,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,QAAA,EAAU,KAAK,CAAA;AACtC,IAAA,MAAM,QAAA,GAAW,YAAA,CAAa,QAAA,IAAY,KAAA,IAAS,MAAM,CAAA;AACzD,IAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,2CAAA,EAA8C,UAAA,GAAa,gDAAA,GAAmD,EAAE,CAAA,CAAA,EAC9H,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,CAAA,uCAAA,EAA0C,QAAQ,+GAChE,QAAA,EAAA,IAAA,IAAQ,cAAA,CAAe,IAAI,CAAA,GACxB,YAAA,CAAa,IAAA,EAAsB,EAAE,SAAA,EAAW,oBAAA,EAAsB,CAAA,GACtE,mBAAA,EACN,CAAA,EACF,CAAA;AAAA,EAEJ;AACA,EAAA,4BACG,KAAA,EAAA,EAAI,SAAA,EAAW,uDAAuD,UAAA,GAAa,gDAAA,GAAmD,EAAE,CAAA,CAAA,EACvI,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,kDAAA,EAAqD,YAAA,IAAgB,kBAAA,CAAmB,UAAU,CAAA,IAAK,eAAe,CAAA,CAAA,EAAI,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EACjK,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAK,CAAA,EAAE,6DAAA,EAA8D,IAAA,EAAK,OAAA,EAAQ,aAAY,MAAA,EAAO,CAAA;AAAA,0BACrG,MAAA,EAAA,EAAK,CAAA,EAAE,kCAAiC,IAAA,EAAK,cAAA,EAAe,aAAY,KAAA,EAAM,CAAA;AAAA,sBAC/E,GAAA,CAAC,UAAK,CAAA,EAAE,6DAAA,EAA8D,QAAO,cAAA,EAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,KAAA,EAAM;AAAA,KAAA,EACpI,CAAA;AAAA,oBACA,GAAA,CAAC,UAAK,SAAA,EAAW,CAAA,4EAAA,EAA+E,gBAAgB,kBAAA,CAAmB,UAAU,KAAK,eAAe,CAAA,CAAA,EAC9J,yBAAe,YAAA,CAAa,UAAU,KAAK,UAAA,CAAW,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,aAAY,EACjF;AAAA,GAAA,EACF,CAAA;AAEJ;AAGO,SAAS,mBAAA,CAAoB,EAAE,IAAA,EAAK,EAA0B;AACnE,EAAA,IAAI,IAAA,CAAK,eAAe,QAAA,EAAU;AAChC,IAAA,uBAAO,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,iCAAA,EAAkC,CAAA;AAAA,EAClE;AACA,EAAA,IAAI,IAAA,CAAK,eAAe,MAAA,EAAQ;AAC9B,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,IAAA,CAAK,QAAA,EAAU,KAAK,KAAK,CAAA;AAChD,IAAA,uBACE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,CAAA,kCAAA,EAAqC,YAAA,CAAa,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,KAAA,IAAS,MAAM,CAAC,CAAA,qDAAA,CAAA,EACtG,QAAA,EAAA,IAAA,IAAQ,cAAA,CAAe,IAAI,CAAA,GACxB,YAAA,CAAa,IAAA,EAAsB,EAAE,SAAA,EAAW,oBAAA,EAAsB,CAAA,mBACtE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kDAAA,EAAmD,CAAA,EACzE,CAAA;AAAA,EAEJ;AACA,EAAA,MAAM,KAAA,GAAA,CAAS,IAAA,CAAK,UAAA,KAAe,cAAA,IAAkB,IAAA,CAAK,QAAA,GACtD,mBAAA,CAAoB,IAAA,CAAK,QAAQ,CAAA,GACjC,kBAAA,CAAmB,IAAA,CAAK,UAAU,CAAA,KAAM,eAAA;AAC5C,EAAA,uBACE,GAAA,CAAC,SAAI,SAAA,EAAW,CAAA,iBAAA,EAAoB,KAAK,CAAA,CAAA,EAAI,IAAA,EAAK,MAAA,EAAO,OAAA,EAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EAC9G,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,8PAAA,EAA+P,CAAA,EACtT,CAAA;AAEJ;AAGO,SAAS,qBAAqB,IAAA,EAA2B;AAC9D,EAAA,IAAI,IAAA,CAAK,eAAe,cAAA,IAAkB,IAAA,CAAK,UAAU,OAAO,kBAAA,CAAmB,KAAK,QAAQ,CAAA;AAChG,EAAA,IAAI,IAAA,CAAK,UAAA,KAAe,MAAA,EAAQ,OAAO,KAAA;AACvC,EAAA,IAAI,IAAA,CAAK,UAAA,KAAe,QAAA,EAAU,OAAO,QAAA;AACzC,EAAA,OAAO,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA,IAAK,IAAA,CAAK,WAAW,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,WAAA,EAAY;AAClF;AAoBA,IAAI,sBAAA,GAAwD,IAAA;AAC5D,IAAM,uBAAA,uBAA8B,GAAA,EAAgB;AAE7C,SAAS,sBAAsB,IAAA,EAAqC;AACzE,EAAA,sBAAA,GAAyB,IAAA;AACzB,EAAA,uBAAA,CAAwB,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAA,EAAG,CAAA;AAC1C;AAEO,SAAS,wBAAwB,QAAA,EAAkC;AACxE,EAAA,uBAAA,CAAwB,IAAI,QAAQ,CAAA;AACpC,EAAA,OAAO,MAAM;AAAE,IAAA,uBAAA,CAAwB,OAAO,QAAQ,CAAA;AAAA,EAAG,CAAA;AAC3D;AAEO,SAAS,yBAAA,GAA2D;AACzE,EAAA,OAAO,sBAAA;AACT;AAYO,IAAM,eAAA,GAAkB,+BAAA;AACxB,IAAM,sBAAA,GAAyB;AAC/B,IAAM,+BAAA,GAAkC;AAExC,SAAS,qBAAA,GAAwB;AACtC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAC,MAAA,CAAe,eAAe,CAAA,GAAI,OAAA;AACnC,EAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,sBAAsB,CAAC,CAAA;AAC9D;AAEO,SAAS,8BAA8B,QAAA,EAAkB;AAC9D,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAC,OAAe,eAAe,CAAA,GAAI,EAAE,IAAA,EAAM,kBAAkB,QAAA,EAAS;AACtE,EAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,+BAAA,EAAiC,EAAE,QAAQ,EAAE,QAAA,EAAS,EAAG,CAAC,CAAA;AACjG;AAKO,SAAS,oBAAA,GAAgD;AAC9D,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,MAAM,GAAA,GAAO,OAAe,eAAe,CAAA;AAC3C,EAAA,IAAI,GAAA,KAAQ,SAAS,OAAO,OAAA;AAC5B,EAAA,IAAI,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,IAAA,KAAS,gBAAA,IAAoB,OAAO,GAAA,CAAI,QAAA,KAAa,QAAA,EAAU,OAAO,GAAA;AAChH,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,uBAAA,GAAmD;AACjE,EAAA,MAAM,MAAM,oBAAA,EAAqB;AACjC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAc,MAAA,CAAe,eAAe,CAAA,GAAI,IAAA;AACtE,EAAA,OAAO,GAAA;AACT","file":"chunk-H5NDQZ4A.js","sourcesContent":["/**\n * Shared desktop-icon building blocks.\n *\n * Desktop.tsx renders the desktop surface; Files.tsx renders desktop shortcut\n * folders inside the Files app. Both import the icon tiles, entity-icon config\n * and the desktop-folder bridge from here so the surfaces never visually\n * diverge — and so Desktop and Files never import each other (that would be an\n * import cycle).\n */\nimport { isValidElement, cloneElement, type ReactElement, type ReactNode } from 'react';\nimport { navIcons } from '../shell-config/nav';\nimport type { PreviewFileKind } from '../utils/openPreviewFile';\n\n// ── Gradient tiles ──────────────────────────────────────────────────────────\n// Per-app colored tile background, shared by the mobile home grid and the\n// desktop \"page\" shortcuts. Tailwind's JIT scans the source so each gradient\n// class string must appear in full somewhere — keep them inline.\nexport const ICON_GRADIENTS = [\n 'from-blue-500 to-blue-700',\n 'from-indigo-500 to-purple-600',\n 'from-purple-500 to-pink-600',\n 'from-pink-500 to-rose-600',\n 'from-red-500 to-rose-600',\n 'from-orange-500 to-red-600',\n 'from-amber-500 to-orange-600',\n 'from-yellow-500 to-amber-500',\n 'from-lime-500 to-green-600',\n 'from-green-500 to-emerald-600',\n 'from-emerald-500 to-teal-600',\n 'from-teal-500 to-cyan-600',\n 'from-cyan-500 to-sky-600',\n 'from-sky-500 to-blue-600',\n 'from-violet-500 to-fuchsia-600',\n];\n\nexport function hashGradient(seed: string): string {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h << 5) - h + seed.charCodeAt(i);\n return ICON_GRADIENTS[Math.abs(h) % ICON_GRADIENTS.length];\n}\n\n// ── Entity icon config ──────────────────────────────────────────────────────\nexport const ENTITY_ICON_COLORS: Record<string, string> = {\n order: 'text-blue-600', purchase_order: 'text-purple-600', invoice: 'text-green-600',\n client: 'text-indigo-600', manufacturer: 'text-orange-600', shipment: 'text-teal-600',\n part_number: 'text-gray-600', project: 'text-pink-600', mould: 'text-red-600',\n design: 'text-cyan-600', brand: 'text-amber-600', price_sheet: 'text-emerald-600',\n folder: 'text-yellow-600', page: 'text-blue-500',\n};\nexport const ENTITY_ICONS: Record<string, string> = {\n order: 'SO', purchase_order: 'PO', invoice: 'INV', client: 'CLI',\n manufacturer: 'MFR', shipment: 'DN', part_number: 'PN', project: 'PRJ',\n mould: 'MLD', design: 'DSN', brand: 'BRD', price_sheet: 'PS',\n vendor_invoice: 'VI', vendor_payment: 'VP', warranty_claim: 'WC',\n qc_report: 'QC', vendor_shipment: 'GRN', bank_account: 'BA',\n wheel_finish: 'WF', weight_log: 'WL', production_progress: 'PP',\n vendor_price_sheet: 'VPS', proposal: 'PR', folder: 'FLD',\n};\n\n// Glyphs and colors for the auto-tracked preview shortcuts that live in the\n// Documents folder. Keyed by `fileKind`, not `entityType`.\nexport const PREVIEW_FILE_CODES: Record<PreviewFileKind, string> = {\n pdf: 'PDF', dxf: 'DXF', '3d': 'STP', image: 'IMG', csv: 'CSV',\n};\nexport const PREVIEW_FILE_COLORS: Record<PreviewFileKind, string> = {\n pdf: 'text-red-600', dxf: 'text-blue-600', '3d': 'text-purple-600',\n image: 'text-emerald-600', csv: 'text-green-600',\n};\n\nexport interface DesktopItem {\n entityType: string;\n entityId: string;\n label: string;\n x?: number;\n y?: number;\n folderId?: string; // if inside a folder\n // Legacy free-form position inside the old folder window (pixels, relative\n // to the folder body). Folders now open in the Files app, which lists items\n // in a table — kept so previously-persisted shortcuts keep parsing.\n folderX?: number;\n folderY?: number;\n // Set for `entityType: 'preview-file'` shortcuts auto-recorded when the\n // user previews a file. `filePath` is the server-relative path passed\n // back into `openPreviewFile` on shortcut click.\n filePath?: string;\n fileKind?: PreviewFileKind;\n}\n\n/** Solid amber folder — the exact glyph the Files app uses for folders, so\n * desktop folders and Files-app folders read as the same object. */\nexport function FolderGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M2.25 7.125A2.25 2.25 0 014.5 4.875h4.504c.61 0 1.193.243 1.624.673l1.494 1.494a.75.75 0 00.53.22h7.098A2.25 2.25 0 0122 9.51v8.366A2.25 2.25 0 0119.75 20.125H4.25A2.25 2.25 0 012 17.875V7.125z\" />\n </svg>\n );\n}\n\n/** Page shortcuts reuse the consumer-registered nav icons; historically the\n * label was tried first, then the route. */\nfunction pageGlyph(entityId?: string, label?: string): ReactNode {\n return (label && navIcons[label]) || (entityId ? navIcons[entityId] : undefined);\n}\n\nconst PAGE_FALLBACK_GLYPH = (\n <svg className=\"h-7 w-7\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6z\" />\n </svg>\n);\n\n// Shared 48×48 tile used by the desktop icon renderer (and anything else\n// that needs a full-size shortcut tile), so all surfaces stay in sync.\nexport function FileIconTile({ entityType, isSelected, entityId, label, fileKind }: {\n entityType: string;\n isSelected: boolean;\n entityId?: string;\n label?: string;\n fileKind?: PreviewFileKind;\n}) {\n const isPreviewFile = entityType === 'preview-file' && fileKind;\n const previewColor = isPreviewFile ? PREVIEW_FILE_COLORS[fileKind!] : null;\n const previewCode = isPreviewFile ? PREVIEW_FILE_CODES[fileKind!] : null;\n if (entityType === 'folder') {\n return (\n <div className={`w-12 h-12 flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <FolderGlyph className=\"h-12 w-12 text-amber-500 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]\" />\n </div>\n );\n }\n if (entityType === 'page') {\n // App shortcut — colored gradient tile with the white nav glyph, same\n // treatment as the mobile home grid (and the same hash seed, the route,\n // so an app keeps its color across surfaces).\n const icon = pageGlyph(entityId, label);\n const gradient = hashGradient(entityId || label || 'page');\n return (\n <div className={`w-12 h-12 flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <span className={`h-11 w-11 rounded-xl bg-gradient-to-br ${gradient} flex items-center justify-center text-white border border-white/30 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]`}>\n {icon && isValidElement(icon)\n ? cloneElement(icon as ReactElement, { className: 'h-7 w-7 text-white' })\n : PAGE_FALLBACK_GLYPH}\n </span>\n </div>\n );\n }\n return (\n <div className={`w-12 h-12 relative flex items-center justify-center ${isSelected ? 'rounded-lg bg-blue-400/30 ring-2 ring-blue-500' : ''}`}>\n <svg className={`w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${previewColor ?? ENTITY_ICON_COLORS[entityType] ?? 'text-gray-500'}`} viewBox=\"0 0 40 48\" fill=\"none\">\n <path d=\"M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z\" fill=\"white\" fillOpacity=\"0.92\" />\n <path d=\"M26 0l10 10H30a4 4 0 01-4-4V0z\" fill=\"currentColor\" fillOpacity=\"0.2\" />\n <path d=\"M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeOpacity=\"0.5\" />\n </svg>\n <span className={`absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${previewColor ?? ENTITY_ICON_COLORS[entityType] ?? 'text-gray-600'}`}>\n {previewCode ?? ENTITY_ICONS[entityType] ?? entityType.slice(0, 3).toUpperCase()}\n </span>\n </div>\n );\n}\n\n/** Compact row icon for desktop shortcuts listed inside the Files app. */\nexport function DesktopItemMiniIcon({ item }: { item: DesktopItem }) {\n if (item.entityType === 'folder') {\n return <FolderGlyph className=\"h-4 w-4 shrink-0 text-amber-500\" />;\n }\n if (item.entityType === 'page') {\n const icon = pageGlyph(item.entityId, item.label);\n return (\n <span className={`h-4 w-4 rounded bg-gradient-to-br ${hashGradient(item.entityId || item.label || 'page')} flex items-center justify-center text-white shrink-0`}>\n {icon && isValidElement(icon)\n ? cloneElement(icon as ReactElement, { className: 'h-3 w-3 text-white' })\n : <span className=\"h-1.5 w-1.5 rounded-[2px] border border-white/80\" />}\n </span>\n );\n }\n const color = (item.entityType === 'preview-file' && item.fileKind\n ? PREVIEW_FILE_COLORS[item.fileKind]\n : ENTITY_ICON_COLORS[item.entityType]) ?? 'text-gray-400';\n return (\n <svg className={`h-4 w-4 shrink-0 ${color}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" />\n </svg>\n );\n}\n\n/** Short type tag shown in the Files-app listing of a desktop folder. */\nexport function desktopItemTypeLabel(item: DesktopItem): string {\n if (item.entityType === 'preview-file' && item.fileKind) return PREVIEW_FILE_CODES[item.fileKind];\n if (item.entityType === 'page') return 'App';\n if (item.entityType === 'folder') return 'Folder';\n return ENTITY_ICONS[item.entityType] ?? item.entityType.slice(0, 3).toUpperCase();\n}\n\n// ── Desktop-folder bridge ───────────────────────────────────────────────────\n//\n// Desktop folders are virtual — shortcut collections persisted in the user's\n// prefs, not directories on the file server. The Files app shows them anyway\n// (sidebar section + folder listing), so Desktop publishes its live folder\n// state here and Files subscribes via useSyncExternalStore. Mutations route\n// back through the callbacks so persistence stays in Desktop's host-aware\n// save path.\n\nexport interface DesktopFoldersSnapshot {\n folders: { id: string; name: string; itemCount: number }[];\n itemsByFolder: Record<string, DesktopItem[]>;\n /** Clear `folderId` on these shortcuts — they reappear on the desktop. */\n moveToDesktop: (items: DesktopItem[]) => void;\n /** Delete these shortcuts entirely. */\n removeShortcuts: (items: DesktopItem[]) => void;\n}\n\nlet desktopFoldersSnapshot: DesktopFoldersSnapshot | null = null;\nconst desktopFoldersListeners = new Set<() => void>();\n\nexport function publishDesktopFolders(next: DesktopFoldersSnapshot | null) {\n desktopFoldersSnapshot = next;\n desktopFoldersListeners.forEach(l => l());\n}\n\nexport function subscribeDesktopFolders(listener: () => void): () => void {\n desktopFoldersListeners.add(listener);\n return () => { desktopFoldersListeners.delete(listener); };\n}\n\nexport function getDesktopFoldersSnapshot(): DesktopFoldersSnapshot | null {\n return desktopFoldersSnapshot;\n}\n\n// ── Files-app view side channel ─────────────────────────────────────────────\n//\n// Used by the desktop Trash icon and desktop folders to open the Files app\n// on a specific view. Two cases handled:\n// 1) Files isn't open yet — the flag below is read once on first mount.\n// 2) Files is already open — the event tells the live instance to flip view.\n// The caller follows up with `openPage('/files')` either way.\n\nexport type FilesViewRequest = 'trash' | { view: 'desktop-folder'; folderId: string };\n\nexport const FILES_VIEW_FLAG = '__REACT_OS_SHELL_FILES_VIEW__';\nexport const FILES_SHOW_TRASH_EVENT = 'react-os-shell:files-show-trash';\nexport const FILES_OPEN_DESKTOP_FOLDER_EVENT = 'react-os-shell:files-open-desktop-folder';\n\nexport function requestFilesTrashView() {\n if (typeof window === 'undefined') return;\n (window as any)[FILES_VIEW_FLAG] = 'trash' satisfies FilesViewRequest;\n window.dispatchEvent(new CustomEvent(FILES_SHOW_TRASH_EVENT));\n}\n\nexport function requestFilesDesktopFolderView(folderId: string) {\n if (typeof window === 'undefined') return;\n (window as any)[FILES_VIEW_FLAG] = { view: 'desktop-folder', folderId } satisfies FilesViewRequest;\n window.dispatchEvent(new CustomEvent(FILES_OPEN_DESKTOP_FOLDER_EVENT, { detail: { folderId } }));\n}\n\n/** Read the pending view request without clearing it. Side-effect free so\n * it is safe inside a `useState` initializer (StrictMode double-invokes\n * those; a read-and-clear there would hand the second invocation null). */\nexport function peekFilesViewRequest(): FilesViewRequest | null {\n if (typeof window === 'undefined') return null;\n const raw = (window as any)[FILES_VIEW_FLAG];\n if (raw === 'trash') return 'trash';\n if (raw && typeof raw === 'object' && raw.view === 'desktop-folder' && typeof raw.folderId === 'string') return raw;\n return null;\n}\n\n/** Read-and-clear the pending view request (Files calls this once mounted). */\nexport function consumeFilesViewRequest(): FilesViewRequest | null {\n const req = peekFilesViewRequest();\n if (typeof window !== 'undefined') (window as any)[FILES_VIEW_FLAG] = null;\n return req;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { requestFilesTrashView } from './chunk-QAKURGOG.js';
1
+ import { requestFilesTrashView } from './chunk-H5NDQZ4A.js';
2
2
 
3
3
  // src/apps/_filesShared.ts
4
4
  var filesDemoTree = null;
@@ -13,5 +13,5 @@ function openFilesInTrashMode() {
13
13
  }
14
14
 
15
15
  export { getFilesDemoTree, openFilesInTrashMode, setFilesDemoTree };
16
- //# sourceMappingURL=chunk-LBY7KH2W.js.map
17
- //# sourceMappingURL=chunk-LBY7KH2W.js.map
16
+ //# sourceMappingURL=chunk-HC6N2OXO.js.map
17
+ //# sourceMappingURL=chunk-HC6N2OXO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/apps/_filesShared.ts"],"names":[],"mappings":";;;AAwBA,IAAI,aAAA,GAAwC,IAAA;AAErC,SAAS,iBAAiB,IAAA,EAA8B;AAC7D,EAAA,aAAA,GAAgB,IAAA;AAClB;AAGO,SAAS,gBAAA,GAA2C;AACzD,EAAA,OAAO,aAAA;AACT;AAKO,SAAS,oBAAA,GAAuB;AACrC,EAAA,qBAAA,EAAsB;AACxB","file":"chunk-LBY7KH2W.js","sourcesContent":["/**\n * Files app config — the tiny consumer-facing surface of the Files app\n * (demo-tree injection + trash-mode open). Lives apart from Files.tsx so\n * importing these from `react-os-shell/apps` never drags the Files\n * implementation into a host's startup bundle; the Files window component\n * stays behind its React.lazy dynamic import.\n */\nimport { requestFilesTrashView } from '../shell/desktopIcons';\n\n/**\n * Demo filesystem. When a consumer (e.g. the demo app) injects a static tree\n * via `setFilesDemoTree`, Files browses it in-memory — no file server needed.\n * Browse-only: upload / new-folder / rename / delete / trash are hidden while a\n * demo tree is set. Consumers with a real file server never call it, so their\n * behaviour is unchanged.\n */\nexport interface FilesDemoNode {\n name: string;\n kind: 'file' | 'folder';\n size?: number;\n modifiedAt?: string;\n children?: FilesDemoNode[];\n}\n\nlet filesDemoTree: FilesDemoNode[] | null = null;\n\nexport function setFilesDemoTree(tree: FilesDemoNode[] | null) {\n filesDemoTree = tree;\n}\n\n/** @internal Current injected demo tree, if any — read by Files.tsx. */\nexport function getFilesDemoTree(): FilesDemoNode[] | null {\n return filesDemoTree;\n}\n\n// Side-channel for opening Files on a specific view (trash, desktop folder).\n// The flag + event plumbing lives in shell/desktopIcons.tsx; this wrapper is\n// kept because consumers import it from the package.\nexport function openFilesInTrashMode() {\n requestFilesTrashView();\n}\n"]}
1
+ {"version":3,"sources":["../src/apps/_filesShared.ts"],"names":[],"mappings":";;;AAwBA,IAAI,aAAA,GAAwC,IAAA;AAErC,SAAS,iBAAiB,IAAA,EAA8B;AAC7D,EAAA,aAAA,GAAgB,IAAA;AAClB;AAGO,SAAS,gBAAA,GAA2C;AACzD,EAAA,OAAO,aAAA;AACT;AAKO,SAAS,oBAAA,GAAuB;AACrC,EAAA,qBAAA,EAAsB;AACxB","file":"chunk-HC6N2OXO.js","sourcesContent":["/**\n * Files app config — the tiny consumer-facing surface of the Files app\n * (demo-tree injection + trash-mode open). Lives apart from Files.tsx so\n * importing these from `react-os-shell/apps` never drags the Files\n * implementation into a host's startup bundle; the Files window component\n * stays behind its React.lazy dynamic import.\n */\nimport { requestFilesTrashView } from '../shell/desktopIcons';\n\n/**\n * Demo filesystem. When a consumer (e.g. the demo app) injects a static tree\n * via `setFilesDemoTree`, Files browses it in-memory — no file server needed.\n * Browse-only: upload / new-folder / rename / delete / trash are hidden while a\n * demo tree is set. Consumers with a real file server never call it, so their\n * behaviour is unchanged.\n */\nexport interface FilesDemoNode {\n name: string;\n kind: 'file' | 'folder';\n size?: number;\n modifiedAt?: string;\n children?: FilesDemoNode[];\n}\n\nlet filesDemoTree: FilesDemoNode[] | null = null;\n\nexport function setFilesDemoTree(tree: FilesDemoNode[] | null) {\n filesDemoTree = tree;\n}\n\n/** @internal Current injected demo tree, if any — read by Files.tsx. */\nexport function getFilesDemoTree(): FilesDemoNode[] | null {\n return filesDemoTree;\n}\n\n// Side-channel for opening Files on a specific view (trash, desktop folder).\n// The flag + event plumbing lives in shell/desktopIcons.tsx; this wrapper is\n// kept because consumers import it from the package.\nexport function openFilesInTrashMode() {\n requestFilesTrashView();\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { useShellAuth } from './chunk-DKDD5KXG.js';
1
+ import { useShellAuth } from './chunk-RVT2A2MO.js';
2
2
 
3
3
  // src/contexts/AuthContext.tsx
4
4
  var _authBridge = {};
@@ -16,5 +16,5 @@ function useAuth() {
16
16
  }
17
17
 
18
18
  export { setShellAuthBridge, useAuth };
19
- //# sourceMappingURL=chunk-3NZSR3ZG.js.map
20
- //# sourceMappingURL=chunk-3NZSR3ZG.js.map
19
+ //# sourceMappingURL=chunk-KILLK5UH.js.map
20
+ //# sourceMappingURL=chunk-KILLK5UH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contexts/AuthContext.tsx"],"names":[],"mappings":";;;AAoBA,IAAI,cAAyD,EAAC;AAGvD,SAAS,mBAAmB,MAAA,EAAmD;AACpF,EAAA,WAAA,GAAc,MAAA;AAChB;AAEO,SAAS,OAAA,GAAU;AACxB,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,YAAA,EAAa;AACpC,EAAA,OAAO;AAAA,IACL,MAAM,WAAA,CAAY,IAAA;AAAA,IAClB,MAAA,EAAQ,WAAA,CAAY,MAAA,KAAW,MAAM;AAAA,IAAC,CAAA,CAAA;AAAA,IACtC;AAAA,GACF;AACF","file":"chunk-3NZSR3ZG.js","sourcesContent":["/**\n * INTERNAL stub — bridges legacy `useAuth()` calls inside the shell to the\n * new <ShellAuthProvider> contract.\n *\n * The shell only ever uses `hasAnyPerm` for nav-item visibility plus `user`\n * + `logout` for the profile menu. Consumers pass these in via\n * <ShellAuthProvider value={{...}}> at the App root.\n *\n * Long-term this file is removed when call sites migrate to `useShellAuth()`\n * + Layout's `user` / `onLogout` props directly.\n */\nimport { useShellAuth } from '../shell/ShellAuth';\n\ninterface ShellUser {\n email?: string;\n first_name?: string;\n last_name?: string;\n avatar_url?: string;\n}\n\nlet _authBridge: { user?: ShellUser; logout?: () => void } = {};\n\n/** Consumer registers user-identity + logout handler once at app startup. */\nexport function setShellAuthBridge(bridge: { user?: ShellUser; logout?: () => void }) {\n _authBridge = bridge;\n}\n\nexport function useAuth() {\n const { hasAnyPerm } = useShellAuth();\n return {\n user: _authBridge.user,\n logout: _authBridge.logout ?? (() => {}),\n hasAnyPerm,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/contexts/AuthContext.tsx"],"names":[],"mappings":";;;AAoBA,IAAI,cAAyD,EAAC;AAGvD,SAAS,mBAAmB,MAAA,EAAmD;AACpF,EAAA,WAAA,GAAc,MAAA;AAChB;AAEO,SAAS,OAAA,GAAU;AACxB,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,YAAA,EAAa;AACpC,EAAA,OAAO;AAAA,IACL,MAAM,WAAA,CAAY,IAAA;AAAA,IAClB,MAAA,EAAQ,WAAA,CAAY,MAAA,KAAW,MAAM;AAAA,IAAC,CAAA,CAAA;AAAA,IACtC;AAAA,GACF;AACF","file":"chunk-KILLK5UH.js","sourcesContent":["/**\n * INTERNAL stub — bridges legacy `useAuth()` calls inside the shell to the\n * new <ShellAuthProvider> contract.\n *\n * The shell only ever uses `hasAnyPerm` for nav-item visibility plus `user`\n * + `logout` for the profile menu. Consumers pass these in via\n * <ShellAuthProvider value={{...}}> at the App root.\n *\n * Long-term this file is removed when call sites migrate to `useShellAuth()`\n * + Layout's `user` / `onLogout` props directly.\n */\nimport { useShellAuth } from '../shell/ShellAuth';\n\ninterface ShellUser {\n email?: string;\n first_name?: string;\n last_name?: string;\n avatar_url?: string;\n}\n\nlet _authBridge: { user?: ShellUser; logout?: () => void } = {};\n\n/** Consumer registers user-identity + logout handler once at app startup. */\nexport function setShellAuthBridge(bridge: { user?: ShellUser; logout?: () => void }) {\n _authBridge = bridge;\n}\n\nexport function useAuth() {\n const { hasAnyPerm } = useShellAuth();\n return {\n user: _authBridge.user,\n logout: _authBridge.logout ?? (() => {}),\n hasAnyPerm,\n };\n}\n"]}
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var VERSION = "4.9.0" ;
3
+ var APP_VERSION = VERSION;
4
+
5
+ export { APP_VERSION, VERSION };
6
+ //# sourceMappingURL=chunk-NQTQPOT4.js.map
7
+ //# sourceMappingURL=chunk-NQTQPOT4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,OAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-A24AESZY.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
1
+ {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,OAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-NQTQPOT4.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
@@ -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,6 +1,6 @@
1
- import { VERSION } from './chunk-A24AESZY.js';
2
- import { useWindowMenuItem, Modal } from './chunk-CKY62ZRU.js';
3
- import { navIcons } from './chunk-DKDD5KXG.js';
1
+ import { VERSION } from './chunk-NQTQPOT4.js';
2
+ import { useWindowMenuItem, Modal } from './chunk-G6AUDFI4.js';
3
+ import { navIcons } from './chunk-RVT2A2MO.js';
4
4
  import { useState, useCallback, isValidElement, cloneElement } from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
@@ -75,5 +75,5 @@ function AboutApp({ app }) {
75
75
  }
76
76
 
77
77
  export { AboutApp, BUILTIN_APP_INFO };
78
- //# sourceMappingURL=chunk-4AQTXUSO.js.map
79
- //# sourceMappingURL=chunk-4AQTXUSO.js.map
78
+ //# sourceMappingURL=chunk-TIKW3XWE.js.map
79
+ //# sourceMappingURL=chunk-TIKW3XWE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/apps/_about.tsx"],"names":[],"mappings":"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","file":"chunk-4AQTXUSO.js","sourcesContent":["/**\n * Shared \"About\" dialog for the bundled apps.\n *\n * Each bundled app carries its own version (independent of the package\n * version) so app-level changes can be tracked without bumping every app at\n * once. `<AboutApp app=\"…\" />` registers an \"About <Name>\" item in the\n * window title menu and renders the dialog: app icon, name, app version and\n * the react-os-shell attribution + shell version.\n *\n * Bump an app's version in `BUILTIN_APP_INFO` whenever that app's behaviour\n * changes, alongside the package-level CHANGELOG entry.\n */\nimport { useCallback, useState, isValidElement, cloneElement, type ReactElement } from 'react';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport { navIcons } from '../shell-config/nav';\nimport { VERSION } from '../version';\n\nexport interface BuiltinAppInfo {\n /** Display name — matches the window-registry label. */\n name: string;\n /** App version, independent of the package version. */\n version: string;\n /** One-line summary shown in the About dialog. */\n description: string;\n /** Registry route — used to look up the consumer-registered nav icon. */\n route: string;\n}\n\nexport const BUILTIN_APP_INFO = {\n spreadsheet: {\n name: 'Spreadsheets',\n version: '1.1.0',\n route: '/spreadsheet',\n description: 'Multi-sheet spreadsheet editor with CSV / TSV import and export.',\n },\n notepad: {\n name: 'Notepad',\n version: '1.0.0',\n route: '/notepad',\n description: 'Color-coded notes with checklists, desktop stickies and entity autolinking.',\n },\n documents: {\n name: 'Documents',\n version: '1.1.0',\n route: '/documents',\n description: 'Letter-page editor for Word documents and plain-text files — images, lists, alignment.',\n },\n preview: {\n name: 'Preview',\n version: '1.2.1',\n route: '/preview',\n description: 'Viewer for PDF documents, images, DXF drawings and 3D models — CAD-style measuring with object snap and an AutoCAD-like command bar.',\n },\n files: {\n name: 'Files',\n version: '1.1.0',\n route: '/files',\n description: 'Personal file manager with folders, uploads, quota, trash and desktop shortcut folders.',\n },\n browser: {\n name: 'Browser',\n version: '1.0.1',\n route: '/browser',\n description: 'Minimal web browser with bookmarks, history and navigation bar.',\n },\n} satisfies Record<string, BuiltinAppInfo>;\n\nexport type BuiltinAppId = keyof typeof BUILTIN_APP_INFO;\n\nconst ABOUT_MENU_ICON = (\n <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n </svg>\n);\n\n// Generic window glyph shown when the consumer hasn't registered a nav icon\n// for the app's route (same fallback shape as the Modal title bar).\nconst FALLBACK_APP_ICON = (\n <svg className=\"h-9 w-9\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6.75A2.25 2.25 0 016 4.5h12a2.25 2.25 0 012.25 2.25v10.5A2.25 2.25 0 0118 19.5H6a2.25 2.25 0 01-2.25-2.25V6.75z M3.75 9h16.5\" />\n </svg>\n);\n\n/** Registers \"About <Name>\" in the window title menu and renders the dialog.\n * Render anywhere inside the app's window. */\nexport default function AboutApp({ app }: { app: BuiltinAppId }) {\n const info = BUILTIN_APP_INFO[app];\n const [open, setOpen] = useState(false);\n const openDialog = useCallback(() => setOpen(true), []);\n useWindowMenuItem(`About ${info.name}`, openDialog, ABOUT_MENU_ICON);\n\n if (!open) return null;\n\n const registered = navIcons[info.route];\n const appIcon = isValidElement(registered)\n ? cloneElement(registered as ReactElement, { className: 'h-9 w-9' } as any)\n : FALLBACK_APP_ICON;\n\n return (\n <Modal open onClose={() => setOpen(false)} title={`About ${info.name}`} size=\"sm\" compact bodyScroll={false} autoHeight dimensions={[320, 320]}>\n <div className=\"flex flex-col items-center text-center px-5 pt-5 pb-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gray-100 text-gray-600 shrink-0\">\n {appIcon}\n </div>\n <h2 className=\"mt-3 text-lg font-bold text-gray-900\">{info.name}</h2>\n <p className=\"text-[11px] font-mono text-gray-400\">Version {info.version}</p>\n <p className=\"mt-2 text-xs text-gray-500 leading-relaxed\">{info.description}</p>\n <div className=\"mt-4 pt-3 border-t border-gray-200 w-full\">\n <p className=\"text-[11px] text-gray-500\">\n Part of the <span className=\"font-medium text-gray-700\">react-os-shell</span> desktop environment\n </p>\n {VERSION && <p className=\"mt-0.5 text-[10px] font-mono text-gray-400\">shell v{VERSION}</p>}\n </div>\n </div>\n </Modal>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/apps/_about.tsx"],"names":[],"mappings":"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","file":"chunk-TIKW3XWE.js","sourcesContent":["/**\n * Shared \"About\" dialog for the bundled apps.\n *\n * Each bundled app carries its own version (independent of the package\n * version) so app-level changes can be tracked without bumping every app at\n * once. `<AboutApp app=\"…\" />` registers an \"About <Name>\" item in the\n * window title menu and renders the dialog: app icon, name, app version and\n * the react-os-shell attribution + shell version.\n *\n * Bump an app's version in `BUILTIN_APP_INFO` whenever that app's behaviour\n * changes, alongside the package-level CHANGELOG entry.\n */\nimport { useCallback, useState, isValidElement, cloneElement, type ReactElement } from 'react';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport { navIcons } from '../shell-config/nav';\nimport { VERSION } from '../version';\n\nexport interface BuiltinAppInfo {\n /** Display name — matches the window-registry label. */\n name: string;\n /** App version, independent of the package version. */\n version: string;\n /** One-line summary shown in the About dialog. */\n description: string;\n /** Registry route — used to look up the consumer-registered nav icon. */\n route: string;\n}\n\nexport const BUILTIN_APP_INFO = {\n spreadsheet: {\n name: 'Spreadsheets',\n version: '1.1.0',\n route: '/spreadsheet',\n description: 'Multi-sheet spreadsheet editor with CSV / TSV import and export.',\n },\n notepad: {\n name: 'Notepad',\n version: '1.0.0',\n route: '/notepad',\n description: 'Color-coded notes with checklists, desktop stickies and entity autolinking.',\n },\n documents: {\n name: 'Documents',\n version: '1.1.0',\n route: '/documents',\n description: 'Letter-page editor for Word documents and plain-text files — images, lists, alignment.',\n },\n preview: {\n name: 'Preview',\n version: '1.2.1',\n route: '/preview',\n description: 'Viewer for PDF documents, images, DXF drawings and 3D models — CAD-style measuring with object snap and an AutoCAD-like command bar.',\n },\n files: {\n name: 'Files',\n version: '1.1.0',\n route: '/files',\n description: 'Personal file manager with folders, uploads, quota, trash and desktop shortcut folders.',\n },\n browser: {\n name: 'Browser',\n version: '1.0.1',\n route: '/browser',\n description: 'Minimal web browser with bookmarks, history and navigation bar.',\n },\n} satisfies Record<string, BuiltinAppInfo>;\n\nexport type BuiltinAppId = keyof typeof BUILTIN_APP_INFO;\n\nconst ABOUT_MENU_ICON = (\n <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n </svg>\n);\n\n// Generic window glyph shown when the consumer hasn't registered a nav icon\n// for the app's route (same fallback shape as the Modal title bar).\nconst FALLBACK_APP_ICON = (\n <svg className=\"h-9 w-9\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6.75A2.25 2.25 0 016 4.5h12a2.25 2.25 0 012.25 2.25v10.5A2.25 2.25 0 0118 19.5H6a2.25 2.25 0 01-2.25-2.25V6.75z M3.75 9h16.5\" />\n </svg>\n);\n\n/** Registers \"About <Name>\" in the window title menu and renders the dialog.\n * Render anywhere inside the app's window. */\nexport default function AboutApp({ app }: { app: BuiltinAppId }) {\n const info = BUILTIN_APP_INFO[app];\n const [open, setOpen] = useState(false);\n const openDialog = useCallback(() => setOpen(true), []);\n useWindowMenuItem(`About ${info.name}`, openDialog, ABOUT_MENU_ICON);\n\n if (!open) return null;\n\n const registered = navIcons[info.route];\n const appIcon = isValidElement(registered)\n ? cloneElement(registered as ReactElement, { className: 'h-9 w-9' } as any)\n : FALLBACK_APP_ICON;\n\n return (\n <Modal open onClose={() => setOpen(false)} title={`About ${info.name}`} size=\"sm\" compact bodyScroll={false} autoHeight dimensions={[320, 320]}>\n <div className=\"flex flex-col items-center text-center px-5 pt-5 pb-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gray-100 text-gray-600 shrink-0\">\n {appIcon}\n </div>\n <h2 className=\"mt-3 text-lg font-bold text-gray-900\">{info.name}</h2>\n <p className=\"text-[11px] font-mono text-gray-400\">Version {info.version}</p>\n <p className=\"mt-2 text-xs text-gray-500 leading-relaxed\">{info.description}</p>\n <div className=\"mt-4 pt-3 border-t border-gray-200 w-full\">\n <p className=\"text-[11px] text-gray-500\">\n Part of the <span className=\"font-medium text-gray-700\">react-os-shell</span> desktop environment\n </p>\n {VERSION && <p className=\"mt-0.5 text-[10px] font-mono text-gray-400\">shell v{VERSION}</p>}\n </div>\n </div>\n </Modal>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { toast_default } from './chunk-VENYVK3L.js';
2
- import { useShellPrefs } from './chunk-CKY62ZRU.js';
2
+ import { useShellPrefs } from './chunk-G6AUDFI4.js';
3
3
  import { useSyncExternalStore, useCallback, useMemo } from 'react';
4
4
 
5
5
  // src/shell/pomodoroStore.ts
@@ -545,5 +545,5 @@ function migratePomodoroTasksOnce(currentTasks, setAllTasks) {
545
545
  }
546
546
 
547
547
  export { ALARM_OPTIONS, FOCUS_SOUND_OPTIONS, getPomoSnapshot, migratePomodoroTasksOnce, playAlarm, pomoPause, pomoStart, pomoSwitchMode, previewFocusSound, setPomoAlarm, setPomoAlarmConfig, setPomoBehaviour, setPomoDurations, setPomoFocusSound, setShellTodoProvider, subscribePomo, useTodoTasks };
548
- //# sourceMappingURL=chunk-2Y6XUY65.js.map
549
- //# sourceMappingURL=chunk-2Y6XUY65.js.map
548
+ //# sourceMappingURL=chunk-UH3H3KAN.js.map
549
+ //# sourceMappingURL=chunk-UH3H3KAN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/pomodoroStore.ts","../src/apps/_todoStore.ts"],"names":[],"mappings":"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","file":"chunk-2Y6XUY65.js","sourcesContent":["/**\n * Pomodoro store — module-level singleton that owns the timer state and\n * tick loop. Lifting the state above the widget means:\n *\n * 1. The taskbar indicator (`TaskbarPomodoro`) can subscribe even when\n * the widget itself is closed.\n * 2. The timer keeps running if the user closes / reopens the widget;\n * no progress is lost mid-session.\n *\n * The widget acts as a pure controller: it reads the snapshot via\n * `useSyncExternalStore` and calls the action functions below to drive\n * state transitions.\n *\n * The alarm sound on session-end is synthesised through the WebAudio API\n * (no audio file assets to bundle / license). All the presets are tuned\n * to be soft — gentle decay, low peak gain — so they don't startle. The\n * focus-time ambient sound (white / pink / brown noise) is synthesised\n * the same way and looped through an AudioBufferSourceNode.\n */\n\nimport toast from './toast';\n\nexport type Mode = 'focus' | 'short' | 'long';\nexport type AlarmSound = 'bell' | 'chime' | 'bowl' | 'wind-chimes' | 'off';\nexport type FocusSound =\n | 'none'\n | 'white' | 'pink' | 'brown'\n | 'tick-fast' | 'tick-slow'\n | 'rain' | 'fireplace';\n\nexport interface PomoDurations {\n /** Focus block, in seconds. */\n focus: number;\n /** Short break, in seconds. */\n short: number;\n /** Long break, in seconds. Triggered every Nth focus where N is\n * `longBreakInterval` from `setPomoBehaviour`. */\n long: number;\n}\n\nexport interface PomoBehaviour {\n /** When a focus block ends, automatically start the break. */\n autoStartBreaks: boolean;\n /** When a break ends, automatically start the next focus block. */\n autoStartPomodoros: boolean;\n /** Long break is taken after every Nth focus block. Default 4. */\n longBreakInterval: number;\n}\n\nexport interface PomoSnapshot {\n running: boolean;\n /** Seconds remaining in the current block. */\n remaining: number;\n mode: Mode;\n /** Seconds in the full current block — used for progress %. */\n total: number;\n /** Pomodoros completed since the page loaded. */\n streak: number;\n /** Today's lifetime count (persisted to localStorage). */\n count: number;\n}\n\nexport const ALARM_OPTIONS: { id: AlarmSound; label: string; description: string }[] = [\n { id: 'bell', label: 'Bell', description: 'Soft bell with one harmonic' },\n { id: 'chime', label: 'Chime', description: 'Two-note ascending chime' },\n { id: 'bowl', label: 'Singing Bowl', description: 'Long-decay meditation tone' },\n { id: 'wind-chimes', label: 'Wind Chimes', description: 'Four soft tones in succession' },\n { id: 'off', label: 'Off (silent)', description: 'No sound — only desktop notification' },\n];\n\nexport const FOCUS_SOUND_OPTIONS: { id: FocusSound; label: string }[] = [\n { id: 'none', label: 'None' },\n { id: 'tick-fast', label: 'Ticking Fast' },\n { id: 'tick-slow', label: 'Ticking Slow' },\n { id: 'rain', label: 'Rain' },\n { id: 'fireplace', label: 'Fireplace' },\n { id: 'white', label: 'White Noise' },\n { id: 'pink', label: 'Pink Noise' },\n { id: 'brown', label: 'Brown Noise' },\n];\n\nconst todayKey = () => `pomodoro-${new Date().toISOString().slice(0, 10)}`;\nconst loadCount = () => {\n try { return parseInt(localStorage.getItem(todayKey()) || '0', 10) || 0; } catch { return 0; }\n};\nconst saveCount = (n: number) => {\n try { localStorage.setItem(todayKey(), String(n)); } catch {}\n};\n\nlet _durations: PomoDurations = { focus: 25 * 60, short: 5 * 60, long: 15 * 60 };\nlet _alarm: AlarmSound = 'bell';\nlet _alarmVolume = 100; // 0–100\nlet _alarmRepeat = 1; // 1–5\nlet _focusSoundType: FocusSound = 'none';\nlet _focusVolume = 50; // 0–100\nlet _behaviour: PomoBehaviour = { autoStartBreaks: false, autoStartPomodoros: false, longBreakInterval: 4 };\n\nlet _state: PomoSnapshot = {\n running: false,\n remaining: _durations.focus,\n mode: 'focus',\n total: _durations.focus,\n streak: 0,\n count: typeof localStorage !== 'undefined' ? loadCount() : 0,\n};\n\nlet _intervalId: ReturnType<typeof setInterval> | null = null;\nconst _listeners = new Set<() => void>();\n\nconst _notify = () => _listeners.forEach(l => l());\nconst _set = (s: Partial<PomoSnapshot>) => { _state = { ..._state, ...s }; _notify(); };\n\nexport function getPomoSnapshot(): PomoSnapshot { return _state; }\nexport function subscribePomo(l: () => void) { _listeners.add(l); return () => { _listeners.delete(l); }; }\n\nexport function setPomoDurations(d: PomoDurations) {\n _durations = d;\n // If the user changed durations while not running and at the start of the\n // block, sync the visible time to the new value.\n if (!_state.running && _state.remaining === _state.total) {\n _set({ remaining: d[_state.mode], total: d[_state.mode] });\n }\n}\nexport function getPomoDurations(): PomoDurations { return _durations; }\n\nexport function setPomoAlarm(a: AlarmSound) { _alarm = a; }\nexport function getPomoAlarm(): AlarmSound { return _alarm; }\n\n/** Configure the alarm playback volume (0–100) and repeat count (1–5).\n * Used at session-end. The standalone `playAlarm()` preview button can\n * still pass overrides. */\nexport function setPomoAlarmConfig(volume: number, repeat: number) {\n _alarmVolume = Math.max(0, Math.min(100, Math.round(volume)));\n _alarmRepeat = Math.max(1, Math.min(5, Math.round(repeat)));\n}\nexport function getPomoAlarmConfig() { return { volume: _alarmVolume, repeat: _alarmRepeat }; }\n\nexport function setPomoBehaviour(b: PomoBehaviour) {\n _behaviour = {\n autoStartBreaks: !!b.autoStartBreaks,\n autoStartPomodoros: !!b.autoStartPomodoros,\n longBreakInterval: Math.max(1, Math.min(20, Math.round(b.longBreakInterval || 4))),\n };\n}\nexport function getPomoBehaviour(): PomoBehaviour { return _behaviour; }\n\n/** Configure the ambient focus-time sound. If a focus block is currently\n * running the audio is hot-swapped to the new settings. */\nexport function setPomoFocusSound(type: FocusSound, volume: number) {\n _focusSoundType = type;\n _focusVolume = Math.max(0, Math.min(100, Math.round(volume)));\n // Hot-swap if focus mode is currently running.\n if (_state.running && _state.mode === 'focus') {\n stopFocusAudio();\n startFocusAudio();\n } else if (type === 'none' || _focusVolume === 0) {\n stopFocusAudio();\n }\n}\nexport function getPomoFocusSound() { return { type: _focusSoundType, volume: _focusVolume }; }\n\nexport function pomoStart() {\n if (_state.running) return;\n _set({ running: true });\n _intervalId = setInterval(_tick, 1000);\n if (_state.mode === 'focus') startFocusAudio();\n}\nexport function pomoPause() {\n if (!_state.running && _intervalId === null) return;\n if (_intervalId !== null) { clearInterval(_intervalId); _intervalId = null; }\n _set({ running: false });\n stopFocusAudio();\n}\nexport function pomoReset() {\n pomoPause();\n _set({ remaining: _durations[_state.mode], total: _durations[_state.mode] });\n}\nexport function pomoSwitchMode(m: Mode) {\n pomoPause();\n _set({ mode: m, remaining: _durations[m], total: _durations[m] });\n}\n\nfunction _tick() {\n if (_state.remaining <= 1) {\n _onSessionEnd();\n return;\n }\n _set({ remaining: _state.remaining - 1 });\n}\n\nfunction _onSessionEnd() {\n if (_intervalId !== null) { clearInterval(_intervalId); _intervalId = null; }\n stopFocusAudio();\n playAlarm(_alarm, { volume: _alarmVolume, repeat: _alarmRepeat });\n\n // Notify the user three ways so they don't miss it:\n // 1. The alarm sound (already fired above).\n // 2. A native OS notification — fires even when the tab is in the\n // background, but only if the user granted permission.\n // 3. The in-app toast — guaranteed to render whenever the page is\n // open, regardless of OS permission state.\n const justFinishedFocus = _state.mode === 'focus';\n const headline = justFinishedFocus ? 'Pomodoro complete — time for a break! 🍅' : 'Break\\'s over — back to work!';\n if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {\n try { new Notification(headline); } catch {}\n }\n try { toast.info(headline); } catch {}\n\n if (_state.mode === 'focus') {\n const nextStreak = _state.streak + 1;\n const newCount = _state.count + 1;\n saveCount(newCount);\n const nextMode: Mode = nextStreak % _behaviour.longBreakInterval === 0 ? 'long' : 'short';\n _set({\n running: false,\n streak: nextStreak,\n count: newCount,\n mode: nextMode,\n remaining: _durations[nextMode],\n total: _durations[nextMode],\n });\n if (_behaviour.autoStartBreaks) setTimeout(() => pomoStart(), 50);\n } else {\n _set({\n running: false,\n mode: 'focus',\n remaining: _durations.focus,\n total: _durations.focus,\n });\n if (_behaviour.autoStartPomodoros) setTimeout(() => pomoStart(), 50);\n }\n}\n\n/** Synthesise the chosen alarm via WebAudio. All presets are tuned soft —\n * exponential decay to near-silence, peak gain ≤ 0.22. The `volume`\n * option scales the peak (0-100). The `repeat` option plays the cue\n * several times with a 2.5 s gap between starts. */\nexport function playAlarm(kind: AlarmSound = _alarm, opts: { volume?: number; repeat?: number } = {}) {\n if (kind === 'off') return;\n const volScale = Math.max(0, Math.min(100, opts.volume ?? 100)) / 100;\n if (volScale === 0) return;\n const repeat = Math.max(1, Math.min(5, opts.repeat ?? 1));\n for (let i = 0; i < repeat; i++) {\n setTimeout(() => _playAlarmOnce(kind, volScale), i * 2500);\n }\n}\n\nfunction _playAlarmOnce(kind: AlarmSound, volScale: number) {\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const playNote = (freq: number, start: number, duration: number, vol = 0.22, type: OscillatorType = 'sine') => {\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain); gain.connect(ctx.destination);\n osc.type = type;\n osc.frequency.value = freq;\n const t0 = ctx.currentTime + start;\n gain.gain.setValueAtTime(0, t0);\n gain.gain.linearRampToValueAtTime(vol * volScale, t0 + 0.03);\n gain.gain.exponentialRampToValueAtTime(0.0001, t0 + duration);\n osc.start(t0);\n osc.stop(t0 + duration);\n };\n let totalDuration = 2;\n if (kind === 'bell') {\n playNote(880, 0, 1.8);\n playNote(1320, 0, 1.4, 0.10);\n totalDuration = 2;\n } else if (kind === 'chime') {\n playNote(659.25, 0, 0.7); // E5\n playNote(880, 0.20, 1.3); // A5\n totalDuration = 2;\n } else if (kind === 'bowl') {\n playNote(440, 0, 3.4, 0.22);\n playNote(660, 0, 3.0, 0.08);\n playNote(880, 0.05, 2.8, 0.05);\n totalDuration = 4;\n } else if (kind === 'wind-chimes') {\n playNote(1175, 0, 1.1, 0.16); // D6\n playNote(880, 0.15, 1.3, 0.16); // A5\n playNote(1318, 0.30, 1.5, 0.16); // E6\n playNote(1047, 0.50, 1.7, 0.13); // C6\n totalDuration = 3;\n }\n setTimeout(() => { try { ctx.close(); } catch {} }, totalDuration * 1000 + 500);\n } catch {}\n}\n\n// ── Ambient focus-time sound ──\nlet _focusAudio: { ctx: AudioContext; src: AudioBufferSourceNode; gain: GainNode } | null = null;\n\n/** Per-type volume cap. Sparse signals (ticking, fireplace pops) need a\n * higher gain to perceive at the same loudness as a continuous noise\n * texture. The user-facing slider always shows 0–100; this multiplier\n * is the headroom mapping. */\nconst FOCUS_VOL_CAP: Record<FocusSound, number> = {\n none: 0,\n white: 0.30,\n pink: 0.30,\n brown: 0.30,\n 'tick-fast': 0.60,\n 'tick-slow': 0.60,\n rain: 0.40,\n fireplace: 0.50,\n};\n\nfunction _makeNoiseBuffer(ctx: AudioContext, type: FocusSound): AudioBuffer | null {\n if (type === 'none') return null;\n const sr = ctx.sampleRate;\n // Noise textures use a 2 s loop. Ticking, rain, and fireplace use 4 s\n // so multiple ticks / pops fit in one cycle and the loop seam is masked\n // by the texture itself.\n const dur = (type === 'white' || type === 'pink' || type === 'brown') ? 2 : 4;\n const len = sr * dur;\n const buffer = ctx.createBuffer(1, len, sr);\n const data = buffer.getChannelData(0);\n\n if (type === 'white') {\n for (let i = 0; i < len; i++) data[i] = (Math.random() * 2 - 1) * 0.5;\n\n } else if (type === 'pink') {\n // Paul Kellet's filter — cheap pink-noise approximation.\n let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n b0 = 0.99886 * b0 + w * 0.0555179;\n b1 = 0.99332 * b1 + w * 0.0750759;\n b2 = 0.96900 * b2 + w * 0.1538520;\n b3 = 0.86650 * b3 + w * 0.3104856;\n b4 = 0.55000 * b4 + w * 0.5329522;\n b5 = -0.7616 * b5 - w * 0.0168980;\n data[i] = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + w * 0.5362) * 0.11 * 0.55;\n b6 = w * 0.115926;\n }\n\n } else if (type === 'brown') {\n // 1/f² — leaky integrator on white noise.\n let last = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n last = (last + 0.02 * w) / 1.02;\n data[i] = last * 3.5 * 0.5;\n }\n\n } else if (type === 'tick-fast' || type === 'tick-slow') {\n // Wall-clock tick: brief noise burst with a sharp exponential decay.\n // Two intervals are even divisors of the 4 s buffer, so the loop is\n // perfectly seamless.\n const intervalSec = type === 'tick-fast' ? 0.5 : 1.0;\n const tickSamples = Math.floor(sr * 0.045);\n for (let t = 0; t < dur; t += intervalSec) {\n const start = Math.floor(t * sr);\n for (let i = 0; i < tickSamples && start + i < len; i++) {\n const env = Math.exp(-i / sr * 180); // ~5 ms attack, ~25 ms decay tail\n const noise = Math.random() * 2 - 1;\n // Mix sharp click (filtered noise) with a faint sine to add body.\n const tone = Math.sin(2 * Math.PI * 1100 * (i / sr));\n data[start + i] += (noise * 0.7 + tone * 0.25) * env * 0.55;\n }\n }\n\n } else if (type === 'rain') {\n // High-pass filtered white noise (the \"patter\") plus a slow tremolo\n // for occasional gusts.\n let prev = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n const filtered = w - prev * 0.93; // high-pass\n prev = w;\n const gust = 0.7 + 0.3 * Math.sin((i / sr) * 2 * Math.PI * 0.25);\n data[i] = filtered * gust * 0.4;\n }\n\n } else if (type === 'fireplace') {\n // Brown-noise rumble underneath, plus randomly-spaced \"pops\" (short\n // noise transients with sharp decay) for the crackle.\n let last = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n last = (last + 0.02 * w) / 1.02;\n data[i] = last * 1.6;\n }\n let next = Math.random() * 0.4 * sr;\n while (next < len) {\n const popLen = Math.floor((0.012 + Math.random() * 0.05) * sr);\n const popVol = 0.35 + Math.random() * 0.45;\n const popPos = Math.floor(next);\n for (let i = 0; i < popLen && popPos + i < len; i++) {\n const env = Math.exp(-i / sr * 90);\n data[popPos + i] += (Math.random() * 2 - 1) * env * popVol;\n }\n // Next pop somewhere between 80 ms and 700 ms later.\n next += (0.08 + Math.random() * 0.62) * sr;\n }\n }\n\n return buffer;\n}\n\nfunction startFocusAudio() {\n if (_focusAudio) return;\n if (_focusSoundType === 'none' || _focusVolume === 0) return;\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const buffer = _makeNoiseBuffer(ctx, _focusSoundType);\n if (!buffer) { try { ctx.close(); } catch {} return; }\n const src = ctx.createBufferSource();\n src.buffer = buffer;\n src.loop = true;\n const gain = ctx.createGain();\n gain.gain.value = (_focusVolume / 100) * FOCUS_VOL_CAP[_focusSoundType];\n src.connect(gain).connect(ctx.destination);\n src.start();\n _focusAudio = { ctx, src, gain };\n } catch {}\n}\n\nfunction stopFocusAudio() {\n if (!_focusAudio) return;\n try { _focusAudio.src.stop(); } catch {}\n try { _focusAudio.ctx.close(); } catch {}\n _focusAudio = null;\n}\n\n/** Play the configured ambient focus sound for ~3 s as a preview. Used by\n * the Settings UI when the user adjusts the dropdown / volume slider. */\nexport function previewFocusSound(type: FocusSound, volume: number) {\n if (type === 'none' || volume === 0) return;\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const buffer = _makeNoiseBuffer(ctx, type);\n if (!buffer) { try { ctx.close(); } catch {} return; }\n const src = ctx.createBufferSource();\n src.buffer = buffer;\n src.loop = true;\n const gain = ctx.createGain();\n gain.gain.value = (volume / 100) * FOCUS_VOL_CAP[type];\n src.connect(gain).connect(ctx.destination);\n src.start();\n setTimeout(() => {\n try { src.stop(); } catch {}\n try { ctx.close(); } catch {}\n }, 3000);\n } catch {}\n}\n","/**\n * Shared task store for the Todo List app and the Pomodoro widget — both\n * read/write the same list via `useTodoTasks()`.\n *\n * Two backends:\n * • Default: `useShellPrefs()` → `prefs.todo_tasks` (per-user prefs blob).\n * • Opt-in: a consumer-supplied `TodoProvider` registered with\n * `setShellTodoProvider(...)`. When set, the three apps read/write through\n * it instead — letting an ERP make the shell's tasks the SAME records as\n * its own task table, and tag each with a `contextLabel` badge (e.g.\n * \"Deal: Acme\"). Mirrors `setShellApiClient`.\n *\n * `migratePomodoroTasksOnce()` folds legacy `localStorage.pomodoro_tasks`\n * into the prefs store on first Pomodoro mount (no-op in provider mode).\n */\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport type { TodoTask } from './_todoTypes';\n\nconst POMODORO_LEGACY_KEY = 'pomodoro_tasks';\nconst POMODORO_LEGACY_MIGRATED_FLAG = 'pomodoro_tasks_migrated';\n\nfunction uid(): string {\n return Math.random().toString(36).slice(2, 11);\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport interface UseTodoTasks {\n tasks: TodoTask[];\n /** Add a new task. Returns the id of the freshly-added task. */\n addTask: (input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }) => string;\n /** Patch any subset of fields on a task by id. `updatedAt` is auto-bumped. */\n updateTask: (id: string, patch: Partial<TodoTask>) => void;\n /** Remove a task by id. Used by both Pomodoro's kebab menu and TodoList's delete action. */\n removeTask: (id: string) => void;\n /** Flip `done`. Same as `updateTask(id, { done: !done })` but faster to type at call sites. */\n toggleDone: (id: string) => void;\n /** Replace the entire list. Used by Google Tasks sync after a pull. */\n setAllTasks: (tasks: TodoTask[]) => void;\n}\n\n/**\n * A consumer-supplied task backend. Registering one (opt-in) routes every\n * shell task surface through it instead of the prefs blob. Methods map to/from\n * the shell's `TodoTask` shape, including the optional `source`/`contextLabel`.\n */\nexport interface TodoProvider {\n list(): Promise<TodoTask[]>;\n create(input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }): Promise<TodoTask>;\n update(id: string, patch: Partial<TodoTask>): Promise<TodoTask>;\n remove(id: string): Promise<void>;\n}\n\n// ── Module-level provider store (shared across all consumers) ──\nlet provider: TodoProvider | null = null;\nlet cache: TodoTask[] = [];\nlet loaded = false;\nlet inflight: Promise<void> | null = null;\nconst listeners = new Set<() => void>();\n\nfunction emit(): void {\n for (const l of listeners) l();\n}\n\nfunction setCache(next: TodoTask[]): void {\n cache = next;\n emit();\n}\n\nfunction refresh(): Promise<void> {\n const p = provider;\n if (!p) {\n cache = [];\n loaded = true;\n emit();\n return Promise.resolve();\n }\n inflight = p\n .list()\n .then(rows => {\n if (provider === p) {\n cache = rows;\n loaded = true;\n emit();\n }\n })\n .catch(() => {\n if (provider === p) {\n loaded = true;\n emit();\n }\n })\n .finally(() => {\n inflight = null;\n });\n return inflight;\n}\n\n/** Register (or clear with `null`) the backend task provider. Opt-in. */\nexport function setShellTodoProvider(next: TodoProvider | null): void {\n provider = next;\n cache = [];\n loaded = false;\n if (next) refresh();\n else emit();\n}\n\nexport function hasShellTodoProvider(): boolean {\n return provider !== null;\n}\n\nfunction subscribe(cb: () => void): () => void {\n listeners.add(cb);\n if (provider && !loaded && !inflight) refresh();\n return () => {\n listeners.delete(cb);\n };\n}\n\nfunction getSnapshot(): TodoTask[] {\n return cache;\n}\n\n// ── Prefs-backed implementation (default / fallback) ──\nfunction usePrefsTodoTasks(): UseTodoTasks {\n const { prefs, save } = useShellPrefs();\n const tasks: TodoTask[] = useMemo(() => {\n const raw = prefs.todo_tasks;\n return Array.isArray(raw) ? (raw as TodoTask[]) : [];\n }, [prefs.todo_tasks]);\n\n const writeTasks = useCallback((next: TodoTask[]) => {\n save({ todo_tasks: next });\n }, [save]);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const id = uid();\n const ts = nowIso();\n const task: TodoTask = { done: false, ...input, name: input.name.trim(), id, createdAt: ts, updatedAt: ts };\n writeTasks([...tasks, task]);\n return id;\n }, [tasks, writeTasks]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n writeTasks(tasks.map(t => (t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t)));\n }, [tasks, writeTasks]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n writeTasks(tasks.filter(t => t.id !== id));\n }, [tasks, writeTasks]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n const target = tasks.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [tasks, updateTask]);\n\n return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };\n}\n\n// ── Public hook (provider-aware) ──\nexport function useTodoTasks(): UseTodoTasks {\n // Both hooks always run (rules of hooks); the active impl is chosen below.\n const prefsImpl = usePrefsTodoTasks();\n const providerTasks = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const p = provider;\n if (!p) return prefsImpl.addTask(input);\n const tempId = 'tmp-' + uid();\n const ts = nowIso();\n const optimistic: TodoTask = { done: false, ...input, name: input.name.trim(), id: tempId, createdAt: ts, updatedAt: ts };\n setCache([...cache, optimistic]);\n p.create({ ...input, name: input.name.trim() })\n // Merge so server-owned fields win but client-only fields (estimated/\n // completed/notes the backend may not persist) survive the round-trip.\n .then(saved => setCache(cache.map(t => (t.id === tempId ? { ...optimistic, ...saved } : t))))\n .catch(() => setCache(cache.filter(t => t.id !== tempId)));\n return tempId;\n }, [prefsImpl]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n const p = provider;\n if (!p) return prefsImpl.updateTask(id, patch);\n setCache(cache.map(t => (t.id === id ? { ...t, ...patch, id, updatedAt: nowIso() } : t)));\n p.update(id, patch).catch(() => { refresh(); });\n }, [prefsImpl]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n const p = provider;\n if (!p) return prefsImpl.removeTask(id);\n const prev = cache;\n setCache(cache.filter(t => t.id !== id));\n p.remove(id).catch(() => setCache(prev));\n }, [prefsImpl]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n if (!provider) return prefsImpl.toggleDone(id);\n const target = cache.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [prefsImpl, updateTask]);\n\n const setAllTasks = useCallback<UseTodoTasks['setAllTasks']>((next) => {\n // Provider owns persistence — bulk replace (Google Tasks sync) is a no-op there.\n if (!provider) prefsImpl.setAllTasks(next);\n }, [prefsImpl]);\n\n if (!hasShellTodoProvider()) return prefsImpl;\n return { tasks: providerTasks, addTask, updateTask, removeTask, toggleDone, setAllTasks };\n}\n\n/**\n * One-time migration: pull any tasks the Pomodoro widget previously\n * persisted to `localStorage.pomodoro_tasks` into the shared store.\n * No-op when a provider is registered (the provider owns persistence).\n */\nexport function migratePomodoroTasksOnce(\n currentTasks: TodoTask[],\n setAllTasks: (next: TodoTask[]) => void,\n): void {\n try {\n if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;\n const raw = localStorage.getItem(POMODORO_LEGACY_KEY);\n if (!raw) {\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const legacy: Array<{ id?: string; name?: string; estimated?: number; completed?: number; done?: boolean }>\n = JSON.parse(raw);\n if (!Array.isArray(legacy) || legacy.length === 0) {\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const ts = nowIso();\n const migrated: TodoTask[] = legacy\n .filter(t => typeof t?.name === 'string')\n .map(t => ({\n id: t.id || uid(),\n name: String(t.name),\n done: !!t.done,\n estimated: typeof t.estimated === 'number' ? t.estimated : undefined,\n completed: typeof t.completed === 'number' ? t.completed : undefined,\n createdAt: ts,\n updatedAt: ts,\n }));\n const existingIds = new Set(currentTasks.map(t => t.id));\n const additions = migrated.filter(t => !existingIds.has(t.id));\n setAllTasks([...additions, ...currentTasks]);\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n } catch {\n try { localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1'); } catch {}\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/pomodoroStore.ts","../src/apps/_todoStore.ts"],"names":[],"mappings":";;;;;AA8DO,IAAM,aAAA,GAA0E;AAAA,EACrF,EAAE,EAAA,EAAI,MAAA,EAAe,KAAA,EAAO,MAAA,EAAiB,aAAa,6BAAA,EAA8B;AAAA,EACxF,EAAE,EAAA,EAAI,OAAA,EAAe,KAAA,EAAO,OAAA,EAAiB,aAAa,0BAAA,EAA2B;AAAA,EACrF,EAAE,EAAA,EAAI,MAAA,EAAe,KAAA,EAAO,cAAA,EAAiB,aAAa,4BAAA,EAA6B;AAAA,EACvF,EAAE,EAAA,EAAI,aAAA,EAAe,KAAA,EAAO,aAAA,EAAiB,aAAa,+BAAA,EAAgC;AAAA,EAC1F,EAAE,EAAA,EAAI,KAAA,EAAe,KAAA,EAAO,cAAA,EAAiB,aAAa,2CAAA;AAC5D;AAEO,IAAM,mBAAA,GAA2D;AAAA,EACtE,EAAE,EAAA,EAAI,MAAA,EAAc,KAAA,EAAO,MAAA,EAAO;AAAA,EAClC,EAAE,EAAA,EAAI,WAAA,EAAc,KAAA,EAAO,cAAA,EAAe;AAAA,EAC1C,EAAE,EAAA,EAAI,WAAA,EAAc,KAAA,EAAO,cAAA,EAAe;AAAA,EAC1C,EAAE,EAAA,EAAI,MAAA,EAAc,KAAA,EAAO,MAAA,EAAO;AAAA,EAClC,EAAE,EAAA,EAAI,WAAA,EAAc,KAAA,EAAO,WAAA,EAAY;AAAA,EACvC,EAAE,EAAA,EAAI,OAAA,EAAc,KAAA,EAAO,aAAA,EAAc;AAAA,EACzC,EAAE,EAAA,EAAI,MAAA,EAAc,KAAA,EAAO,YAAA,EAAa;AAAA,EACxC,EAAE,EAAA,EAAI,OAAA,EAAc,KAAA,EAAO,aAAA;AAC7B;AAEA,IAAM,QAAA,GAAW,MAAM,CAAA,SAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACxE,IAAM,YAAY,MAAM;AACtB,EAAA,IAAI;AAAE,IAAA,OAAO,QAAA,CAAS,aAAa,OAAA,CAAQ,QAAA,EAAU,CAAA,IAAK,GAAA,EAAK,EAAE,CAAA,IAAK,CAAA;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,CAAA;AAAA,EAAG;AAC/F,CAAA;AACA,IAAM,SAAA,GAAY,CAAC,CAAA,KAAc;AAC/B,EAAA,IAAI;AAAE,IAAA,YAAA,CAAa,OAAA,CAAQ,QAAA,EAAS,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAA,EAAC;AAC9D,CAAA;AAEA,IAAI,UAAA,GAA4B,EAAE,KAAA,EAAO,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,GAAI,EAAA,EAAI,IAAA,EAAM,EAAA,GAAK,EAAA,EAAG;AAC/E,IAAI,MAAA,GAAqB,MAAA;AACzB,IAAI,YAAA,GAAe,GAAA;AACnB,IAAI,YAAA,GAAe,CAAA;AACnB,IAAI,eAAA,GAA8B,MAAA;AAClC,IAAI,YAAA,GAAe,EAAA;AACnB,IAAI,aAA4B,EAAE,eAAA,EAAiB,OAAO,kBAAA,EAAoB,KAAA,EAAO,mBAAmB,CAAA,EAAE;AAE1G,IAAI,MAAA,GAAuB;AAAA,EACzB,OAAA,EAAS,KAAA;AAAA,EACT,WAAW,UAAA,CAAW,KAAA;AAAA,EACtB,IAAA,EAAM,OAAA;AAAA,EACN,OAAO,UAAA,CAAW,KAAA;AAAA,EAClB,MAAA,EAAQ,CAAA;AAAA,EACR,KAAA,EAAO,OAAO,YAAA,KAAiB,WAAA,GAAc,WAAU,GAAI;AAC7D,CAAA;AAEA,IAAI,WAAA,GAAqD,IAAA;AACzD,IAAM,UAAA,uBAAiB,GAAA,EAAgB;AAEvC,IAAM,UAAU,MAAM,UAAA,CAAW,OAAA,CAAQ,CAAA,CAAA,KAAK,GAAG,CAAA;AACjD,IAAM,IAAA,GAAO,CAAC,CAAA,KAA6B;AAAE,EAAA,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,GAAG,CAAA,EAAE;AAAG,EAAA,OAAA,EAAQ;AAAG,CAAA;AAE/E,SAAS,eAAA,GAAgC;AAAE,EAAA,OAAO,MAAA;AAAQ;AAC1D,SAAS,cAAc,CAAA,EAAe;AAAE,EAAA,UAAA,CAAW,IAAI,CAAC,CAAA;AAAG,EAAA,OAAO,MAAM;AAAE,IAAA,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,EAAG,CAAA;AAAG;AAEnG,SAAS,iBAAiB,CAAA,EAAkB;AACjD,EAAA,UAAA,GAAa,CAAA;AAGb,EAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,SAAA,KAAc,OAAO,KAAA,EAAO;AACxD,IAAA,IAAA,CAAK,EAAE,SAAA,EAAW,CAAA,CAAE,MAAA,CAAO,IAAI,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,MAAA,CAAO,IAAI,CAAA,EAAG,CAAA;AAAA,EAC3D;AACF;AAGO,SAAS,aAAa,CAAA,EAAe;AAAE,EAAA,MAAA,GAAS,CAAA;AAAG;AAMnD,SAAS,kBAAA,CAAmB,QAAgB,MAAA,EAAgB;AACjE,EAAA,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA;AAC5D,EAAA,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA;AAC5D;AAGO,SAAS,iBAAiB,CAAA,EAAkB;AACjD,EAAA,UAAA,GAAa;AAAA,IACX,eAAA,EAAiB,CAAC,CAAC,CAAA,CAAE,eAAA;AAAA,IACrB,kBAAA,EAAoB,CAAC,CAAC,CAAA,CAAE,kBAAA;AAAA,IACxB,iBAAA,EAAmB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,iBAAA,IAAqB,CAAC,CAAC,CAAC;AAAA,GACnF;AACF;AAKO,SAAS,iBAAA,CAAkB,MAAkB,MAAA,EAAgB;AAClE,EAAA,eAAA,GAAkB,IAAA;AAClB,EAAA,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA;AAE5D,EAAA,IAAI,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,IAAA,KAAS,OAAA,EAAS;AAC7C,IAAA,cAAA,EAAe;AACf,IAAA,eAAA,EAAgB;AAAA,EAClB,CAAA,MAAA,IAAW,IAAA,KAAS,MAAA,IAAU,YAAA,KAAiB,CAAA,EAAG;AAChD,IAAA,cAAA,EAAe;AAAA,EACjB;AACF;AAGO,SAAS,SAAA,GAAY;AAC1B,EAAA,IAAI,OAAO,OAAA,EAAS;AACpB,EAAA,IAAA,CAAK,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AACtB,EAAA,WAAA,GAAc,WAAA,CAAY,OAAO,GAAI,CAAA;AACrC,EAAA,IAAI,MAAA,CAAO,IAAA,KAAS,OAAA,EAAS,eAAA,EAAgB;AAC/C;AACO,SAAS,SAAA,GAAY;AAC1B,EAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,WAAA,KAAgB,IAAA,EAAM;AAC7C,EAAA,IAAI,gBAAgB,IAAA,EAAM;AAAE,IAAA,aAAA,CAAc,WAAW,CAAA;AAAG,IAAA,WAAA,GAAc,IAAA;AAAA,EAAM;AAC5E,EAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAA,EAAO,CAAA;AACvB,EAAA,cAAA,EAAe;AACjB;AAKO,SAAS,eAAe,CAAA,EAAS;AACtC,EAAA,SAAA,EAAU;AACV,EAAA,IAAA,CAAK,EAAE,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,UAAA,CAAW,CAAC,CAAA,EAAG,KAAA,EAAO,UAAA,CAAW,CAAC,CAAA,EAAG,CAAA;AAClE;AAEA,SAAS,KAAA,GAAQ;AACf,EAAA,IAAI,MAAA,CAAO,aAAa,CAAA,EAAG;AACzB,IAAA,aAAA,EAAc;AACd,IAAA;AAAA,EACF;AACA,EAAA,IAAA,CAAK,EAAE,SAAA,EAAW,MAAA,CAAO,SAAA,GAAY,GAAG,CAAA;AAC1C;AAEA,SAAS,aAAA,GAAgB;AACvB,EAAA,IAAI,gBAAgB,IAAA,EAAM;AAAE,IAAA,aAAA,CAAc,WAAW,CAAA;AAAG,IAAA,WAAA,GAAc,IAAA;AAAA,EAAM;AAC5E,EAAA,cAAA,EAAe;AACf,EAAA,SAAA,CAAU,QAAQ,EAAE,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,cAAc,CAAA;AAQhE,EAAA,MAAM,iBAAA,GAAoB,OAAO,IAAA,KAAS,OAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,oBAAoB,sDAAA,GAA6C,mCAAA;AAClF,EAAA,IAAI,OAAO,YAAA,KAAiB,WAAA,IAAe,YAAA,CAAa,eAAe,SAAA,EAAW;AAChF,IAAA,IAAI;AAAE,MAAA,IAAI,aAAa,QAAQ,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAC;AAAA,EAC7C;AACA,EAAA,IAAI;AAAE,IAAA,aAAA,CAAM,KAAK,QAAQ,CAAA;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAA,EAAC;AAErC,EAAA,IAAI,MAAA,CAAO,SAAS,OAAA,EAAS;AAC3B,IAAA,MAAM,UAAA,GAAa,OAAO,MAAA,GAAS,CAAA;AACnC,IAAA,MAAM,QAAA,GAAW,OAAO,KAAA,GAAQ,CAAA;AAChC,IAAA,SAAA,CAAU,QAAQ,CAAA;AAClB,IAAA,MAAM,QAAA,GAAiB,UAAA,GAAa,UAAA,CAAW,iBAAA,KAAsB,IAAI,MAAA,GAAS,OAAA;AAClF,IAAA,IAAA,CAAK;AAAA,MACH,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,UAAA;AAAA,MACR,KAAA,EAAO,QAAA;AAAA,MACP,IAAA,EAAM,QAAA;AAAA,MACN,SAAA,EAAW,WAAW,QAAQ,CAAA;AAAA,MAC9B,KAAA,EAAO,WAAW,QAAQ;AAAA,KAC3B,CAAA;AACD,IAAA,IAAI,WAAW,eAAA,EAAiB,UAAA,CAAW,MAAM,SAAA,IAAa,EAAE,CAAA;AAAA,EAClE,CAAA,MAAO;AACL,IAAA,IAAA,CAAK;AAAA,MACH,OAAA,EAAS,KAAA;AAAA,MACT,IAAA,EAAM,OAAA;AAAA,MACN,WAAW,UAAA,CAAW,KAAA;AAAA,MACtB,OAAO,UAAA,CAAW;AAAA,KACnB,CAAA;AACD,IAAA,IAAI,WAAW,kBAAA,EAAoB,UAAA,CAAW,MAAM,SAAA,IAAa,EAAE,CAAA;AAAA,EACrE;AACF;AAMO,SAAS,SAAA,CAAU,IAAA,GAAmB,MAAA,EAAQ,IAAA,GAA6C,EAAC,EAAG;AACpG,EAAA,IAAI,SAAS,KAAA,EAAO;AACpB,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,MAAA,IAAU,GAAG,CAAC,CAAA,GAAI,GAAA;AAClE,EAAA,IAAI,aAAa,CAAA,EAAG;AACpB,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,MAAA,IAAU,CAAC,CAAC,CAAA;AACxD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,IAAA,UAAA,CAAW,MAAM,cAAA,CAAe,IAAA,EAAM,QAAQ,CAAA,EAAG,IAAI,IAAI,CAAA;AAAA,EAC3D;AACF;AAEA,SAAS,cAAA,CAAe,MAAkB,QAAA,EAAkB;AAC1D,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAA6B,MAAA,CAAe,YAAA,IAAiB,MAAA,CAAe,kBAAA;AAClF,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,GAAA,GAAM,IAAI,IAAA,EAAK;AACrB,IAAA,MAAM,QAAA,GAAW,CAAC,IAAA,EAAc,KAAA,EAAe,UAAkB,GAAA,GAAM,IAAA,EAAM,OAAuB,MAAA,KAAW;AAC7G,MAAA,MAAM,GAAA,GAAM,IAAI,gBAAA,EAAiB;AACjC,MAAA,MAAM,IAAA,GAAO,IAAI,UAAA,EAAW;AAC5B,MAAA,GAAA,CAAI,QAAQ,IAAI,CAAA;AAAG,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,WAAW,CAAA;AAC/C,MAAA,GAAA,CAAI,IAAA,GAAO,IAAA;AACX,MAAA,GAAA,CAAI,UAAU,KAAA,GAAQ,IAAA;AACtB,MAAA,MAAM,EAAA,GAAK,IAAI,WAAA,GAAc,KAAA;AAC7B,MAAA,IAAA,CAAK,IAAA,CAAK,cAAA,CAAe,CAAA,EAAG,EAAE,CAAA;AAC9B,MAAA,IAAA,CAAK,IAAA,CAAK,uBAAA,CAAwB,GAAA,GAAM,QAAA,EAAU,KAAK,IAAI,CAAA;AAC3D,MAAA,IAAA,CAAK,IAAA,CAAK,4BAAA,CAA6B,IAAA,EAAQ,EAAA,GAAK,QAAQ,CAAA;AAC5D,MAAA,GAAA,CAAI,MAAM,EAAE,CAAA;AACZ,MAAA,GAAA,CAAI,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,IACxB,CAAA;AACA,IAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,IAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,MAAA,QAAA,CAAS,GAAA,EAAK,GAAG,GAAG,CAAA;AACpB,MAAA,QAAA,CAAS,IAAA,EAAM,CAAA,EAAG,GAAA,EAAK,GAAI,CAAA;AAC3B,MAAA,aAAA,GAAgB,CAAA;AAAA,IAClB,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,QAAA,CAAS,MAAA,EAAQ,GAAG,GAAG,CAAA;AACvB,MAAA,QAAA,CAAS,GAAA,EAAK,KAAM,GAAG,CAAA;AACvB,MAAA,aAAA,GAAgB,CAAA;AAAA,IAClB,CAAA,MAAA,IAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,QAAA,CAAS,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,IAAI,CAAA;AAC1B,MAAA,QAAA,CAAS,GAAA,EAAK,CAAA,EAAG,CAAA,EAAK,IAAI,CAAA;AAC1B,MAAA,QAAA,CAAS,GAAA,EAAK,IAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAC7B,MAAA,aAAA,GAAgB,CAAA;AAAA,IAClB,CAAA,MAAA,IAAW,SAAS,aAAA,EAAe;AACjC,MAAA,QAAA,CAAS,IAAA,EAAM,CAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAC9B,MAAA,QAAA,CAAS,GAAA,EAAM,IAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAC9B,MAAA,QAAA,CAAS,IAAA,EAAM,GAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAC9B,MAAA,QAAA,CAAS,IAAA,EAAM,GAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAC9B,MAAA,aAAA,GAAgB,CAAA;AAAA,IAClB;AACA,IAAA,UAAA,CAAW,MAAM;AAAE,MAAA,IAAI;AAAE,QAAA,GAAA,CAAI,KAAA,EAAM;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAA,IAAE,CAAA,EAAG,aAAA,GAAgB,GAAA,GAAO,GAAG,CAAA;AAAA,EAChF,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX;AAGA,IAAI,WAAA,GAAwF,IAAA;AAM5F,IAAM,aAAA,GAA4C;AAAA,EAChD,IAAA,EAAa,CAAA;AAAA,EACb,KAAA,EAAa,GAAA;AAAA,EACb,IAAA,EAAa,GAAA;AAAA,EACb,KAAA,EAAa,GAAA;AAAA,EACb,WAAA,EAAa,GAAA;AAAA,EACb,WAAA,EAAa,GAAA;AAAA,EACb,IAAA,EAAa,GAAA;AAAA,EACb,SAAA,EAAa;AACf,CAAA;AAEA,SAAS,gBAAA,CAAiB,KAAmB,IAAA,EAAsC;AACjF,EAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA;AAC5B,EAAA,MAAM,KAAK,GAAA,CAAI,UAAA;AAIf,EAAA,MAAM,MAAO,IAAA,KAAS,OAAA,IAAW,SAAS,MAAA,IAAU,IAAA,KAAS,UAAW,CAAA,GAAI,CAAA;AAC5E,EAAA,MAAM,MAAM,EAAA,GAAK,GAAA;AACjB,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,YAAA,CAAa,CAAA,EAAG,KAAK,EAAE,CAAA;AAC1C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,cAAA,CAAe,CAAC,CAAA;AAEpC,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK,IAAA,CAAK,CAAC,CAAA,GAAA,CAAK,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA,IAAK,GAAA;AAAA,EAEpE,CAAA,MAAA,IAAW,SAAS,MAAA,EAAQ;AAE1B,IAAA,IAAI,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAA;AACzD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA;AAC9B,MAAA,EAAA,GAAK,OAAA,GAAU,KAAK,CAAA,GAAI,SAAA;AACxB,MAAA,EAAA,GAAK,OAAA,GAAU,KAAK,CAAA,GAAI,SAAA;AACxB,MAAA,EAAA,GAAK,KAAA,GAAU,KAAK,CAAA,GAAI,QAAA;AACxB,MAAA,EAAA,GAAK,MAAA,GAAU,KAAK,CAAA,GAAI,SAAA;AACxB,MAAA,EAAA,GAAK,IAAA,GAAU,KAAK,CAAA,GAAI,SAAA;AACxB,MAAA,EAAA,GAAK,OAAA,GAAU,KAAK,CAAA,GAAI,QAAA;AACxB,MAAA,IAAA,CAAK,CAAC,CAAA,GAAA,CAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,CAAA,GAAI,MAAA,IAAU,IAAA,GAAO,IAAA;AACnE,MAAA,EAAA,GAAK,CAAA,GAAI,QAAA;AAAA,IACX;AAAA,EAEF,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAE3B,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA;AAC9B,MAAA,IAAA,GAAA,CAAQ,IAAA,GAAO,OAAO,CAAA,IAAK,IAAA;AAC3B,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,GAAO,GAAA,GAAM,GAAA;AAAA,IACzB;AAAA,EAEF,CAAA,MAAA,IAAW,IAAA,KAAS,WAAA,IAAe,IAAA,KAAS,WAAA,EAAa;AAIvD,IAAA,MAAM,WAAA,GAAc,IAAA,KAAS,WAAA,GAAc,GAAA,GAAM,CAAA;AACjD,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,KAAK,CAAA;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,KAAK,WAAA,EAAa;AACzC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,EAAE,CAAA;AAC/B,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,eAAe,KAAA,GAAQ,CAAA,GAAI,KAAK,CAAA,EAAA,EAAK;AACvD,QAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,KAAK,GAAG,CAAA;AAClC,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA;AAElC,QAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,GAAI,KAAK,EAAA,GAAK,IAAA,IAAQ,IAAI,EAAA,CAAG,CAAA;AACnD,QAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,IAAA,CAAM,QAAQ,GAAA,GAAM,IAAA,GAAO,QAAQ,GAAA,GAAM,IAAA;AAAA,MACzD;AAAA,IACF;AAAA,EAEF,CAAA,MAAA,IAAW,SAAS,MAAA,EAAQ;AAG1B,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA;AAC9B,MAAA,MAAM,QAAA,GAAW,IAAI,IAAA,GAAO,IAAA;AAC5B,MAAA,IAAA,GAAO,CAAA;AACP,MAAA,MAAM,IAAA,GAAO,GAAA,GAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAK,IAAI,EAAA,GAAM,CAAA,GAAI,IAAA,CAAK,EAAA,GAAK,IAAI,CAAA;AAC/D,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,QAAA,GAAW,IAAA,GAAO,GAAA;AAAA,IAC9B;AAAA,EAEF,CAAA,MAAA,IAAW,SAAS,WAAA,EAAa;AAG/B,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO,GAAI,CAAA,GAAI,CAAA;AAC9B,MAAA,IAAA,GAAA,CAAQ,IAAA,GAAO,OAAO,CAAA,IAAK,IAAA;AAC3B,MAAA,IAAA,CAAK,CAAC,IAAI,IAAA,GAAO,GAAA;AAAA,IACnB;AACA,IAAA,IAAI,IAAA,GAAO,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,GAAM,EAAA;AACjC,IAAA,OAAO,OAAO,GAAA,EAAK;AACjB,MAAA,MAAM,MAAA,GAAS,KAAK,KAAA,CAAA,CAAO,KAAA,GAAQ,KAAK,MAAA,EAAO,GAAI,QAAQ,EAAE,CAAA;AAC7D,MAAA,MAAM,MAAA,GAAS,IAAA,GAAO,IAAA,CAAK,MAAA,EAAO,GAAI,IAAA;AACtC,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,UAAU,MAAA,GAAS,CAAA,GAAI,KAAK,CAAA,EAAA,EAAK;AACnD,QAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,KAAK,EAAE,CAAA;AACjC,QAAA,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,IAAA,CAAM,IAAA,CAAK,QAAO,GAAI,CAAA,GAAI,KAAK,GAAA,GAAM,MAAA;AAAA,MACtD;AAEA,MAAA,IAAA,IAAA,CAAS,IAAA,GAAO,IAAA,CAAK,MAAA,EAAO,GAAI,IAAA,IAAQ,EAAA;AAAA,IAC1C;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,eAAA,GAAkB;AACzB,EAAA,IAAI,WAAA,EAAa;AACjB,EAAA,IAAI,eAAA,KAAoB,MAAA,IAAU,YAAA,KAAiB,CAAA,EAAG;AACtD,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAA6B,MAAA,CAAe,YAAA,IAAiB,MAAA,CAAe,kBAAA;AAClF,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,GAAA,GAAM,IAAI,IAAA,EAAK;AACrB,IAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,GAAA,EAAK,eAAe,CAAA;AACpD,IAAA,IAAI,CAAC,MAAA,EAAQ;AAAE,MAAA,IAAI;AAAE,QAAA,GAAA,CAAI,KAAA,EAAM;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAE,MAAA;AAAA,IAAQ;AACrD,IAAA,MAAM,GAAA,GAAM,IAAI,kBAAA,EAAmB;AACnC,IAAA,GAAA,CAAI,MAAA,GAAS,MAAA;AACb,IAAA,GAAA,CAAI,IAAA,GAAO,IAAA;AACX,IAAA,MAAM,IAAA,GAAO,IAAI,UAAA,EAAW;AAC5B,IAAA,IAAA,CAAK,IAAA,CAAK,KAAA,GAAS,YAAA,GAAe,GAAA,GAAO,cAAc,eAAe,CAAA;AACtE,IAAA,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAA,CAAE,OAAA,CAAQ,IAAI,WAAW,CAAA;AACzC,IAAA,GAAA,CAAI,KAAA,EAAM;AACV,IAAA,WAAA,GAAc,EAAE,GAAA,EAAK,GAAA,EAAK,IAAA,EAAK;AAAA,EACjC,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX;AAEA,SAAS,cAAA,GAAiB;AACxB,EAAA,IAAI,CAAC,WAAA,EAAa;AAClB,EAAA,IAAI;AAAE,IAAA,WAAA,CAAY,IAAI,IAAA,EAAK;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAA,EAAC;AACvC,EAAA,IAAI;AAAE,IAAA,WAAA,CAAY,IAAI,KAAA,EAAM;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAA,EAAC;AACxC,EAAA,WAAA,GAAc,IAAA;AAChB;AAIO,SAAS,iBAAA,CAAkB,MAAkB,MAAA,EAAgB;AAClE,EAAA,IAAI,IAAA,KAAS,MAAA,IAAU,MAAA,KAAW,CAAA,EAAG;AACrC,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAA6B,MAAA,CAAe,YAAA,IAAiB,MAAA,CAAe,kBAAA;AAClF,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,GAAA,GAAM,IAAI,IAAA,EAAK;AACrB,IAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,GAAA,EAAK,IAAI,CAAA;AACzC,IAAA,IAAI,CAAC,MAAA,EAAQ;AAAE,MAAA,IAAI;AAAE,QAAA,GAAA,CAAI,KAAA,EAAM;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAE,MAAA;AAAA,IAAQ;AACrD,IAAA,MAAM,GAAA,GAAM,IAAI,kBAAA,EAAmB;AACnC,IAAA,GAAA,CAAI,MAAA,GAAS,MAAA;AACb,IAAA,GAAA,CAAI,IAAA,GAAO,IAAA;AACX,IAAA,MAAM,IAAA,GAAO,IAAI,UAAA,EAAW;AAC5B,IAAA,IAAA,CAAK,IAAA,CAAK,KAAA,GAAS,MAAA,GAAS,GAAA,GAAO,cAAc,IAAI,CAAA;AACrD,IAAA,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAA,CAAE,OAAA,CAAQ,IAAI,WAAW,CAAA;AACzC,IAAA,GAAA,CAAI,KAAA,EAAM;AACV,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,IAAI;AAAE,QAAA,GAAA,CAAI,IAAA,EAAK;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AAC3B,MAAA,IAAI;AAAE,QAAA,GAAA,CAAI,KAAA,EAAM;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAA,IAC9B,GAAG,GAAI,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX;AC/aA,IAAM,mBAAA,GAAsB,gBAAA;AAC5B,IAAM,6BAAA,GAAgC,yBAAA;AAEtC,SAAS,GAAA,GAAc;AACrB,EAAA,OAAO,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAC/C;AAEA,SAAS,MAAA,GAAiB;AACxB,EAAA,OAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAChC;AA6BA,IAAI,QAAA,GAAgC,IAAA;AACpC,IAAI,QAAoB,EAAC;AACzB,IAAI,MAAA,GAAS,KAAA;AACb,IAAI,QAAA,GAAiC,IAAA;AACrC,IAAM,SAAA,uBAAgB,GAAA,EAAgB;AAEtC,SAAS,IAAA,GAAa;AACpB,EAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAC/B;AAEA,SAAS,SAAS,IAAA,EAAwB;AACxC,EAAA,KAAA,GAAQ,IAAA;AACR,EAAA,IAAA,EAAK;AACP;AAEA,SAAS,OAAA,GAAyB;AAChC,EAAA,MAAM,CAAA,GAAI,QAAA;AACV,EAAA,IAAI,CAAC,CAAA,EAAG;AACN,IAAA,KAAA,GAAQ,EAAC;AACT,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,QAAQ,OAAA,EAAQ;AAAA,EACzB;AACA,EAAA,QAAA,GAAW,CAAA,CACR,IAAA,EAAK,CACL,IAAA,CAAK,CAAA,IAAA,KAAQ;AACZ,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA,KAAA,GAAQ,IAAA;AACR,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,IAAA,EAAK;AAAA,IACP;AAAA,EACF,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,IAAA,EAAK;AAAA,IACP;AAAA,EACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,IAAA,QAAA,GAAW,IAAA;AAAA,EACb,CAAC,CAAA;AACH,EAAA,OAAO,QAAA;AACT;AAGO,SAAS,qBAAqB,IAAA,EAAiC;AACpE,EAAA,QAAA,GAAW,IAAA;AACX,EAAA,KAAA,GAAQ,EAAC;AACT,EAAA,MAAA,GAAS,KAAA;AACT,EAAA,IAAI,MAAM,OAAA,EAAQ;AAAA,OACb,IAAA,EAAK;AACZ;AAEO,SAAS,oBAAA,GAAgC;AAC9C,EAAA,OAAO,QAAA,KAAa,IAAA;AACtB;AAEA,SAAS,UAAU,EAAA,EAA4B;AAC7C,EAAA,SAAA,CAAU,IAAI,EAAE,CAAA;AAChB,EAAA,IAAI,QAAA,IAAY,CAAC,MAAA,IAAU,CAAC,UAAU,OAAA,EAAQ;AAC9C,EAAA,OAAO,MAAM;AACX,IAAA,SAAA,CAAU,OAAO,EAAE,CAAA;AAAA,EACrB,CAAA;AACF;AAEA,SAAS,WAAA,GAA0B;AACjC,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,iBAAA,GAAkC;AACzC,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAK,GAAI,aAAA,EAAc;AACtC,EAAA,MAAM,KAAA,GAAoB,QAAQ,MAAM;AACtC,IAAA,MAAM,MAAM,KAAA,CAAM,UAAA;AAClB,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,GAAK,MAAqB,EAAC;AAAA,EACrD,CAAA,EAAG,CAAC,KAAA,CAAM,UAAU,CAAC,CAAA;AAErB,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,CAAC,IAAA,KAAqB;AACnD,IAAA,IAAA,CAAK,EAAE,UAAA,EAAY,IAAA,EAAM,CAAA;AAAA,EAC3B,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,OAAA,GAAU,WAAA,CAAqC,CAAC,KAAA,KAAU;AAC9D,IAAA,MAAM,KAAK,GAAA,EAAI;AACf,IAAA,MAAM,KAAK,MAAA,EAAO;AAClB,IAAA,MAAM,IAAA,GAAiB,EAAE,IAAA,EAAM,KAAA,EAAO,GAAG,KAAA,EAAO,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,MAAK,EAAG,EAAA,EAAI,SAAA,EAAW,EAAA,EAAI,WAAW,EAAA,EAAG;AAC1G,IAAA,UAAA,CAAW,CAAC,GAAG,KAAA,EAAO,IAAI,CAAC,CAAA;AAC3B,IAAA,OAAO,EAAA;AAAA,EACT,CAAA,EAAG,CAAC,KAAA,EAAO,UAAU,CAAC,CAAA;AAEtB,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,EAAI,KAAA,KAAU;AACxE,IAAA,UAAA,CAAW,MAAM,GAAA,CAAI,CAAA,CAAA,KAAM,EAAE,EAAA,KAAO,EAAA,GAAK,EAAE,GAAG,CAAA,EAAG,GAAG,KAAA,EAAO,EAAA,EAAI,EAAE,EAAA,EAAI,SAAA,EAAW,QAAO,EAAE,GAAI,CAAE,CAAC,CAAA;AAAA,EAClG,CAAA,EAAG,CAAC,KAAA,EAAO,UAAU,CAAC,CAAA;AAEtB,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,KAAO;AACjE,IAAA,UAAA,CAAW,MAAM,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AAAA,EAC3C,CAAA,EAAG,CAAC,KAAA,EAAO,UAAU,CAAC,CAAA;AAEtB,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,KAAO;AACjE,IAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,EAAE,CAAA;AAC1C,IAAA,IAAI,MAAA,aAAmB,EAAA,EAAI,EAAE,MAAM,CAAC,MAAA,CAAO,MAAM,CAAA;AAAA,EACnD,CAAA,EAAG,CAAC,KAAA,EAAO,UAAU,CAAC,CAAA;AAEtB,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,YAAY,UAAA,EAAY,UAAA,EAAY,aAAa,UAAA,EAAW;AACvF;AAGO,SAAS,YAAA,GAA6B;AAE3C,EAAA,MAAM,YAAY,iBAAA,EAAkB;AACpC,EAAA,MAAM,aAAA,GAAgB,oBAAA,CAAqB,SAAA,EAAW,WAAA,EAAa,WAAW,CAAA;AAE9E,EAAA,MAAM,OAAA,GAAU,WAAA,CAAqC,CAAC,KAAA,KAAU;AAC9D,IAAA,MAAM,CAAA,GAAI,QAAA;AACV,IAAA,IAAI,CAAC,CAAA,EAAG,OAAO,SAAA,CAAU,QAAQ,KAAK,CAAA;AACtC,IAAA,MAAM,MAAA,GAAS,SAAS,GAAA,EAAI;AAC5B,IAAA,MAAM,KAAK,MAAA,EAAO;AAClB,IAAA,MAAM,aAAuB,EAAE,IAAA,EAAM,KAAA,EAAO,GAAG,OAAO,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,IAAA,IAAQ,EAAA,EAAI,MAAA,EAAQ,SAAA,EAAW,EAAA,EAAI,WAAW,EAAA,EAAG;AACxH,IAAA,QAAA,CAAS,CAAC,GAAG,KAAA,EAAO,UAAU,CAAC,CAAA;AAC/B,IAAA,CAAA,CAAE,OAAO,EAAE,GAAG,OAAO,IAAA,EAAM,KAAA,CAAM,KAAK,IAAA,EAAK,EAAG,CAAA,CAG3C,KAAK,CAAA,KAAA,KAAS,QAAA,CAAS,MAAM,GAAA,CAAI,CAAA,CAAA,KAAM,EAAE,EAAA,KAAO,MAAA,GAAS,EAAE,GAAG,YAAY,GAAG,KAAA,KAAU,CAAE,CAAC,CAAC,CAAA,CAC3F,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,EAAA,KAAO,MAAM,CAAC,CAAC,CAAA;AAC3D,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,EAAI,KAAA,KAAU;AACxE,IAAA,MAAM,CAAA,GAAI,QAAA;AACV,IAAA,IAAI,CAAC,CAAA,EAAG,OAAO,SAAA,CAAU,UAAA,CAAW,IAAI,KAAK,CAAA;AAC7C,IAAA,QAAA,CAAS,MAAM,GAAA,CAAI,CAAA,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,KAAK,EAAE,GAAG,CAAA,EAAG,GAAG,OAAO,EAAA,EAAI,SAAA,EAAW,QAAO,EAAE,GAAI,CAAE,CAAC,CAAA;AACxF,IAAA,CAAA,CAAE,MAAA,CAAO,EAAA,EAAI,KAAK,CAAA,CAAE,MAAM,MAAM;AAAE,MAAA,OAAA,EAAQ;AAAA,IAAG,CAAC,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,KAAO;AACjE,IAAA,MAAM,CAAA,GAAI,QAAA;AACV,IAAA,IAAI,CAAC,CAAA,EAAG,OAAO,SAAA,CAAU,WAAW,EAAE,CAAA;AACtC,IAAA,MAAM,IAAA,GAAO,KAAA;AACb,IAAA,QAAA,CAAS,MAAM,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AACvC,IAAA,CAAA,CAAE,OAAO,EAAE,CAAA,CAAE,MAAM,MAAM,QAAA,CAAS,IAAI,CAAC,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,UAAA,GAAa,WAAA,CAAwC,CAAC,EAAA,KAAO;AACjE,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,SAAA,CAAU,WAAW,EAAE,CAAA;AAC7C,IAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,EAAE,CAAA;AAC1C,IAAA,IAAI,MAAA,aAAmB,EAAA,EAAI,EAAE,MAAM,CAAC,MAAA,CAAO,MAAM,CAAA;AAAA,EACnD,CAAA,EAAG,CAAC,SAAA,EAAW,UAAU,CAAC,CAAA;AAE1B,EAAA,MAAM,WAAA,GAAc,WAAA,CAAyC,CAAC,IAAA,KAAS;AAErE,IAAA,IAAI,CAAC,QAAA,EAAU,SAAA,CAAU,WAAA,CAAY,IAAI,CAAA;AAAA,EAC3C,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,IAAI,CAAC,oBAAA,EAAqB,EAAG,OAAO,SAAA;AACpC,EAAA,OAAO,EAAE,KAAA,EAAO,aAAA,EAAe,SAAS,UAAA,EAAY,UAAA,EAAY,YAAY,WAAA,EAAY;AAC1F;AAOO,SAAS,wBAAA,CACd,cACA,WAAA,EACM;AACN,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,OAAA,CAAQ,6BAA6B,CAAA,EAAG;AACzD,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,mBAAmB,CAAA;AACpD,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,YAAA,CAAa,OAAA,CAAQ,+BAA+B,GAAG,CAAA;AACvD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GACF,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAClB,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AACjD,MAAA,YAAA,CAAa,WAAW,mBAAmB,CAAA;AAC3C,MAAA,YAAA,CAAa,OAAA,CAAQ,+BAA+B,GAAG,CAAA;AACvD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAK,MAAA,EAAO;AAClB,IAAA,MAAM,QAAA,GAAuB,MAAA,CAC1B,MAAA,CAAO,CAAA,CAAA,KAAK,OAAO,GAAG,IAAA,KAAS,QAAQ,CAAA,CACvC,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MACT,EAAA,EAAI,CAAA,CAAE,EAAA,IAAM,GAAA,EAAI;AAAA,MAChB,IAAA,EAAM,MAAA,CAAO,CAAA,CAAE,IAAI,CAAA;AAAA,MACnB,IAAA,EAAM,CAAC,CAAC,CAAA,CAAE,IAAA;AAAA,MACV,WAAW,OAAO,CAAA,CAAE,SAAA,KAAc,QAAA,GAAW,EAAE,SAAA,GAAY,KAAA,CAAA;AAAA,MAC3D,WAAW,OAAO,CAAA,CAAE,SAAA,KAAc,QAAA,GAAW,EAAE,SAAA,GAAY,KAAA,CAAA;AAAA,MAC3D,SAAA,EAAW,EAAA;AAAA,MACX,SAAA,EAAW;AAAA,KACb,CAAE,CAAA;AACJ,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,YAAA,CAAa,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAC,CAAA;AACvD,IAAA,MAAM,SAAA,GAAY,SAAS,MAAA,CAAO,CAAA,CAAA,KAAK,CAAC,WAAA,CAAY,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAC7D,IAAA,WAAA,CAAY,CAAC,GAAG,SAAA,EAAW,GAAG,YAAY,CAAC,CAAA;AAC3C,IAAA,YAAA,CAAa,WAAW,mBAAmB,CAAA;AAC3C,IAAA,YAAA,CAAa,OAAA,CAAQ,+BAA+B,GAAG,CAAA;AAAA,EACzD,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI;AAAE,MAAA,YAAA,CAAa,OAAA,CAAQ,+BAA+B,GAAG,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAC;AAAA,EAC3E;AACF","file":"chunk-UH3H3KAN.js","sourcesContent":["/**\n * Pomodoro store — module-level singleton that owns the timer state and\n * tick loop. Lifting the state above the widget means:\n *\n * 1. The taskbar indicator (`TaskbarPomodoro`) can subscribe even when\n * the widget itself is closed.\n * 2. The timer keeps running if the user closes / reopens the widget;\n * no progress is lost mid-session.\n *\n * The widget acts as a pure controller: it reads the snapshot via\n * `useSyncExternalStore` and calls the action functions below to drive\n * state transitions.\n *\n * The alarm sound on session-end is synthesised through the WebAudio API\n * (no audio file assets to bundle / license). All the presets are tuned\n * to be soft — gentle decay, low peak gain — so they don't startle. The\n * focus-time ambient sound (white / pink / brown noise) is synthesised\n * the same way and looped through an AudioBufferSourceNode.\n */\n\nimport toast from './toast';\n\nexport type Mode = 'focus' | 'short' | 'long';\nexport type AlarmSound = 'bell' | 'chime' | 'bowl' | 'wind-chimes' | 'off';\nexport type FocusSound =\n | 'none'\n | 'white' | 'pink' | 'brown'\n | 'tick-fast' | 'tick-slow'\n | 'rain' | 'fireplace';\n\nexport interface PomoDurations {\n /** Focus block, in seconds. */\n focus: number;\n /** Short break, in seconds. */\n short: number;\n /** Long break, in seconds. Triggered every Nth focus where N is\n * `longBreakInterval` from `setPomoBehaviour`. */\n long: number;\n}\n\nexport interface PomoBehaviour {\n /** When a focus block ends, automatically start the break. */\n autoStartBreaks: boolean;\n /** When a break ends, automatically start the next focus block. */\n autoStartPomodoros: boolean;\n /** Long break is taken after every Nth focus block. Default 4. */\n longBreakInterval: number;\n}\n\nexport interface PomoSnapshot {\n running: boolean;\n /** Seconds remaining in the current block. */\n remaining: number;\n mode: Mode;\n /** Seconds in the full current block — used for progress %. */\n total: number;\n /** Pomodoros completed since the page loaded. */\n streak: number;\n /** Today's lifetime count (persisted to localStorage). */\n count: number;\n}\n\nexport const ALARM_OPTIONS: { id: AlarmSound; label: string; description: string }[] = [\n { id: 'bell', label: 'Bell', description: 'Soft bell with one harmonic' },\n { id: 'chime', label: 'Chime', description: 'Two-note ascending chime' },\n { id: 'bowl', label: 'Singing Bowl', description: 'Long-decay meditation tone' },\n { id: 'wind-chimes', label: 'Wind Chimes', description: 'Four soft tones in succession' },\n { id: 'off', label: 'Off (silent)', description: 'No sound — only desktop notification' },\n];\n\nexport const FOCUS_SOUND_OPTIONS: { id: FocusSound; label: string }[] = [\n { id: 'none', label: 'None' },\n { id: 'tick-fast', label: 'Ticking Fast' },\n { id: 'tick-slow', label: 'Ticking Slow' },\n { id: 'rain', label: 'Rain' },\n { id: 'fireplace', label: 'Fireplace' },\n { id: 'white', label: 'White Noise' },\n { id: 'pink', label: 'Pink Noise' },\n { id: 'brown', label: 'Brown Noise' },\n];\n\nconst todayKey = () => `pomodoro-${new Date().toISOString().slice(0, 10)}`;\nconst loadCount = () => {\n try { return parseInt(localStorage.getItem(todayKey()) || '0', 10) || 0; } catch { return 0; }\n};\nconst saveCount = (n: number) => {\n try { localStorage.setItem(todayKey(), String(n)); } catch {}\n};\n\nlet _durations: PomoDurations = { focus: 25 * 60, short: 5 * 60, long: 15 * 60 };\nlet _alarm: AlarmSound = 'bell';\nlet _alarmVolume = 100; // 0–100\nlet _alarmRepeat = 1; // 1–5\nlet _focusSoundType: FocusSound = 'none';\nlet _focusVolume = 50; // 0–100\nlet _behaviour: PomoBehaviour = { autoStartBreaks: false, autoStartPomodoros: false, longBreakInterval: 4 };\n\nlet _state: PomoSnapshot = {\n running: false,\n remaining: _durations.focus,\n mode: 'focus',\n total: _durations.focus,\n streak: 0,\n count: typeof localStorage !== 'undefined' ? loadCount() : 0,\n};\n\nlet _intervalId: ReturnType<typeof setInterval> | null = null;\nconst _listeners = new Set<() => void>();\n\nconst _notify = () => _listeners.forEach(l => l());\nconst _set = (s: Partial<PomoSnapshot>) => { _state = { ..._state, ...s }; _notify(); };\n\nexport function getPomoSnapshot(): PomoSnapshot { return _state; }\nexport function subscribePomo(l: () => void) { _listeners.add(l); return () => { _listeners.delete(l); }; }\n\nexport function setPomoDurations(d: PomoDurations) {\n _durations = d;\n // If the user changed durations while not running and at the start of the\n // block, sync the visible time to the new value.\n if (!_state.running && _state.remaining === _state.total) {\n _set({ remaining: d[_state.mode], total: d[_state.mode] });\n }\n}\nexport function getPomoDurations(): PomoDurations { return _durations; }\n\nexport function setPomoAlarm(a: AlarmSound) { _alarm = a; }\nexport function getPomoAlarm(): AlarmSound { return _alarm; }\n\n/** Configure the alarm playback volume (0–100) and repeat count (1–5).\n * Used at session-end. The standalone `playAlarm()` preview button can\n * still pass overrides. */\nexport function setPomoAlarmConfig(volume: number, repeat: number) {\n _alarmVolume = Math.max(0, Math.min(100, Math.round(volume)));\n _alarmRepeat = Math.max(1, Math.min(5, Math.round(repeat)));\n}\nexport function getPomoAlarmConfig() { return { volume: _alarmVolume, repeat: _alarmRepeat }; }\n\nexport function setPomoBehaviour(b: PomoBehaviour) {\n _behaviour = {\n autoStartBreaks: !!b.autoStartBreaks,\n autoStartPomodoros: !!b.autoStartPomodoros,\n longBreakInterval: Math.max(1, Math.min(20, Math.round(b.longBreakInterval || 4))),\n };\n}\nexport function getPomoBehaviour(): PomoBehaviour { return _behaviour; }\n\n/** Configure the ambient focus-time sound. If a focus block is currently\n * running the audio is hot-swapped to the new settings. */\nexport function setPomoFocusSound(type: FocusSound, volume: number) {\n _focusSoundType = type;\n _focusVolume = Math.max(0, Math.min(100, Math.round(volume)));\n // Hot-swap if focus mode is currently running.\n if (_state.running && _state.mode === 'focus') {\n stopFocusAudio();\n startFocusAudio();\n } else if (type === 'none' || _focusVolume === 0) {\n stopFocusAudio();\n }\n}\nexport function getPomoFocusSound() { return { type: _focusSoundType, volume: _focusVolume }; }\n\nexport function pomoStart() {\n if (_state.running) return;\n _set({ running: true });\n _intervalId = setInterval(_tick, 1000);\n if (_state.mode === 'focus') startFocusAudio();\n}\nexport function pomoPause() {\n if (!_state.running && _intervalId === null) return;\n if (_intervalId !== null) { clearInterval(_intervalId); _intervalId = null; }\n _set({ running: false });\n stopFocusAudio();\n}\nexport function pomoReset() {\n pomoPause();\n _set({ remaining: _durations[_state.mode], total: _durations[_state.mode] });\n}\nexport function pomoSwitchMode(m: Mode) {\n pomoPause();\n _set({ mode: m, remaining: _durations[m], total: _durations[m] });\n}\n\nfunction _tick() {\n if (_state.remaining <= 1) {\n _onSessionEnd();\n return;\n }\n _set({ remaining: _state.remaining - 1 });\n}\n\nfunction _onSessionEnd() {\n if (_intervalId !== null) { clearInterval(_intervalId); _intervalId = null; }\n stopFocusAudio();\n playAlarm(_alarm, { volume: _alarmVolume, repeat: _alarmRepeat });\n\n // Notify the user three ways so they don't miss it:\n // 1. The alarm sound (already fired above).\n // 2. A native OS notification — fires even when the tab is in the\n // background, but only if the user granted permission.\n // 3. The in-app toast — guaranteed to render whenever the page is\n // open, regardless of OS permission state.\n const justFinishedFocus = _state.mode === 'focus';\n const headline = justFinishedFocus ? 'Pomodoro complete — time for a break! 🍅' : 'Break\\'s over — back to work!';\n if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {\n try { new Notification(headline); } catch {}\n }\n try { toast.info(headline); } catch {}\n\n if (_state.mode === 'focus') {\n const nextStreak = _state.streak + 1;\n const newCount = _state.count + 1;\n saveCount(newCount);\n const nextMode: Mode = nextStreak % _behaviour.longBreakInterval === 0 ? 'long' : 'short';\n _set({\n running: false,\n streak: nextStreak,\n count: newCount,\n mode: nextMode,\n remaining: _durations[nextMode],\n total: _durations[nextMode],\n });\n if (_behaviour.autoStartBreaks) setTimeout(() => pomoStart(), 50);\n } else {\n _set({\n running: false,\n mode: 'focus',\n remaining: _durations.focus,\n total: _durations.focus,\n });\n if (_behaviour.autoStartPomodoros) setTimeout(() => pomoStart(), 50);\n }\n}\n\n/** Synthesise the chosen alarm via WebAudio. All presets are tuned soft —\n * exponential decay to near-silence, peak gain ≤ 0.22. The `volume`\n * option scales the peak (0-100). The `repeat` option plays the cue\n * several times with a 2.5 s gap between starts. */\nexport function playAlarm(kind: AlarmSound = _alarm, opts: { volume?: number; repeat?: number } = {}) {\n if (kind === 'off') return;\n const volScale = Math.max(0, Math.min(100, opts.volume ?? 100)) / 100;\n if (volScale === 0) return;\n const repeat = Math.max(1, Math.min(5, opts.repeat ?? 1));\n for (let i = 0; i < repeat; i++) {\n setTimeout(() => _playAlarmOnce(kind, volScale), i * 2500);\n }\n}\n\nfunction _playAlarmOnce(kind: AlarmSound, volScale: number) {\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const playNote = (freq: number, start: number, duration: number, vol = 0.22, type: OscillatorType = 'sine') => {\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain); gain.connect(ctx.destination);\n osc.type = type;\n osc.frequency.value = freq;\n const t0 = ctx.currentTime + start;\n gain.gain.setValueAtTime(0, t0);\n gain.gain.linearRampToValueAtTime(vol * volScale, t0 + 0.03);\n gain.gain.exponentialRampToValueAtTime(0.0001, t0 + duration);\n osc.start(t0);\n osc.stop(t0 + duration);\n };\n let totalDuration = 2;\n if (kind === 'bell') {\n playNote(880, 0, 1.8);\n playNote(1320, 0, 1.4, 0.10);\n totalDuration = 2;\n } else if (kind === 'chime') {\n playNote(659.25, 0, 0.7); // E5\n playNote(880, 0.20, 1.3); // A5\n totalDuration = 2;\n } else if (kind === 'bowl') {\n playNote(440, 0, 3.4, 0.22);\n playNote(660, 0, 3.0, 0.08);\n playNote(880, 0.05, 2.8, 0.05);\n totalDuration = 4;\n } else if (kind === 'wind-chimes') {\n playNote(1175, 0, 1.1, 0.16); // D6\n playNote(880, 0.15, 1.3, 0.16); // A5\n playNote(1318, 0.30, 1.5, 0.16); // E6\n playNote(1047, 0.50, 1.7, 0.13); // C6\n totalDuration = 3;\n }\n setTimeout(() => { try { ctx.close(); } catch {} }, totalDuration * 1000 + 500);\n } catch {}\n}\n\n// ── Ambient focus-time sound ──\nlet _focusAudio: { ctx: AudioContext; src: AudioBufferSourceNode; gain: GainNode } | null = null;\n\n/** Per-type volume cap. Sparse signals (ticking, fireplace pops) need a\n * higher gain to perceive at the same loudness as a continuous noise\n * texture. The user-facing slider always shows 0–100; this multiplier\n * is the headroom mapping. */\nconst FOCUS_VOL_CAP: Record<FocusSound, number> = {\n none: 0,\n white: 0.30,\n pink: 0.30,\n brown: 0.30,\n 'tick-fast': 0.60,\n 'tick-slow': 0.60,\n rain: 0.40,\n fireplace: 0.50,\n};\n\nfunction _makeNoiseBuffer(ctx: AudioContext, type: FocusSound): AudioBuffer | null {\n if (type === 'none') return null;\n const sr = ctx.sampleRate;\n // Noise textures use a 2 s loop. Ticking, rain, and fireplace use 4 s\n // so multiple ticks / pops fit in one cycle and the loop seam is masked\n // by the texture itself.\n const dur = (type === 'white' || type === 'pink' || type === 'brown') ? 2 : 4;\n const len = sr * dur;\n const buffer = ctx.createBuffer(1, len, sr);\n const data = buffer.getChannelData(0);\n\n if (type === 'white') {\n for (let i = 0; i < len; i++) data[i] = (Math.random() * 2 - 1) * 0.5;\n\n } else if (type === 'pink') {\n // Paul Kellet's filter — cheap pink-noise approximation.\n let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n b0 = 0.99886 * b0 + w * 0.0555179;\n b1 = 0.99332 * b1 + w * 0.0750759;\n b2 = 0.96900 * b2 + w * 0.1538520;\n b3 = 0.86650 * b3 + w * 0.3104856;\n b4 = 0.55000 * b4 + w * 0.5329522;\n b5 = -0.7616 * b5 - w * 0.0168980;\n data[i] = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + w * 0.5362) * 0.11 * 0.55;\n b6 = w * 0.115926;\n }\n\n } else if (type === 'brown') {\n // 1/f² — leaky integrator on white noise.\n let last = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n last = (last + 0.02 * w) / 1.02;\n data[i] = last * 3.5 * 0.5;\n }\n\n } else if (type === 'tick-fast' || type === 'tick-slow') {\n // Wall-clock tick: brief noise burst with a sharp exponential decay.\n // Two intervals are even divisors of the 4 s buffer, so the loop is\n // perfectly seamless.\n const intervalSec = type === 'tick-fast' ? 0.5 : 1.0;\n const tickSamples = Math.floor(sr * 0.045);\n for (let t = 0; t < dur; t += intervalSec) {\n const start = Math.floor(t * sr);\n for (let i = 0; i < tickSamples && start + i < len; i++) {\n const env = Math.exp(-i / sr * 180); // ~5 ms attack, ~25 ms decay tail\n const noise = Math.random() * 2 - 1;\n // Mix sharp click (filtered noise) with a faint sine to add body.\n const tone = Math.sin(2 * Math.PI * 1100 * (i / sr));\n data[start + i] += (noise * 0.7 + tone * 0.25) * env * 0.55;\n }\n }\n\n } else if (type === 'rain') {\n // High-pass filtered white noise (the \"patter\") plus a slow tremolo\n // for occasional gusts.\n let prev = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n const filtered = w - prev * 0.93; // high-pass\n prev = w;\n const gust = 0.7 + 0.3 * Math.sin((i / sr) * 2 * Math.PI * 0.25);\n data[i] = filtered * gust * 0.4;\n }\n\n } else if (type === 'fireplace') {\n // Brown-noise rumble underneath, plus randomly-spaced \"pops\" (short\n // noise transients with sharp decay) for the crackle.\n let last = 0;\n for (let i = 0; i < len; i++) {\n const w = Math.random() * 2 - 1;\n last = (last + 0.02 * w) / 1.02;\n data[i] = last * 1.6;\n }\n let next = Math.random() * 0.4 * sr;\n while (next < len) {\n const popLen = Math.floor((0.012 + Math.random() * 0.05) * sr);\n const popVol = 0.35 + Math.random() * 0.45;\n const popPos = Math.floor(next);\n for (let i = 0; i < popLen && popPos + i < len; i++) {\n const env = Math.exp(-i / sr * 90);\n data[popPos + i] += (Math.random() * 2 - 1) * env * popVol;\n }\n // Next pop somewhere between 80 ms and 700 ms later.\n next += (0.08 + Math.random() * 0.62) * sr;\n }\n }\n\n return buffer;\n}\n\nfunction startFocusAudio() {\n if (_focusAudio) return;\n if (_focusSoundType === 'none' || _focusVolume === 0) return;\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const buffer = _makeNoiseBuffer(ctx, _focusSoundType);\n if (!buffer) { try { ctx.close(); } catch {} return; }\n const src = ctx.createBufferSource();\n src.buffer = buffer;\n src.loop = true;\n const gain = ctx.createGain();\n gain.gain.value = (_focusVolume / 100) * FOCUS_VOL_CAP[_focusSoundType];\n src.connect(gain).connect(ctx.destination);\n src.start();\n _focusAudio = { ctx, src, gain };\n } catch {}\n}\n\nfunction stopFocusAudio() {\n if (!_focusAudio) return;\n try { _focusAudio.src.stop(); } catch {}\n try { _focusAudio.ctx.close(); } catch {}\n _focusAudio = null;\n}\n\n/** Play the configured ambient focus sound for ~3 s as a preview. Used by\n * the Settings UI when the user adjusts the dropdown / volume slider. */\nexport function previewFocusSound(type: FocusSound, volume: number) {\n if (type === 'none' || volume === 0) return;\n try {\n const Ctor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!Ctor) return;\n const ctx = new Ctor();\n const buffer = _makeNoiseBuffer(ctx, type);\n if (!buffer) { try { ctx.close(); } catch {} return; }\n const src = ctx.createBufferSource();\n src.buffer = buffer;\n src.loop = true;\n const gain = ctx.createGain();\n gain.gain.value = (volume / 100) * FOCUS_VOL_CAP[type];\n src.connect(gain).connect(ctx.destination);\n src.start();\n setTimeout(() => {\n try { src.stop(); } catch {}\n try { ctx.close(); } catch {}\n }, 3000);\n } catch {}\n}\n","/**\n * Shared task store for the Todo List app and the Pomodoro widget — both\n * read/write the same list via `useTodoTasks()`.\n *\n * Two backends:\n * • Default: `useShellPrefs()` → `prefs.todo_tasks` (per-user prefs blob).\n * • Opt-in: a consumer-supplied `TodoProvider` registered with\n * `setShellTodoProvider(...)`. When set, the three apps read/write through\n * it instead — letting an ERP make the shell's tasks the SAME records as\n * its own task table, and tag each with a `contextLabel` badge (e.g.\n * \"Deal: Acme\"). Mirrors `setShellApiClient`.\n *\n * `migratePomodoroTasksOnce()` folds legacy `localStorage.pomodoro_tasks`\n * into the prefs store on first Pomodoro mount (no-op in provider mode).\n */\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport type { TodoTask } from './_todoTypes';\n\nconst POMODORO_LEGACY_KEY = 'pomodoro_tasks';\nconst POMODORO_LEGACY_MIGRATED_FLAG = 'pomodoro_tasks_migrated';\n\nfunction uid(): string {\n return Math.random().toString(36).slice(2, 11);\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport interface UseTodoTasks {\n tasks: TodoTask[];\n /** Add a new task. Returns the id of the freshly-added task. */\n addTask: (input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }) => string;\n /** Patch any subset of fields on a task by id. `updatedAt` is auto-bumped. */\n updateTask: (id: string, patch: Partial<TodoTask>) => void;\n /** Remove a task by id. Used by both Pomodoro's kebab menu and TodoList's delete action. */\n removeTask: (id: string) => void;\n /** Flip `done`. Same as `updateTask(id, { done: !done })` but faster to type at call sites. */\n toggleDone: (id: string) => void;\n /** Replace the entire list. Used by Google Tasks sync after a pull. */\n setAllTasks: (tasks: TodoTask[]) => void;\n}\n\n/**\n * A consumer-supplied task backend. Registering one (opt-in) routes every\n * shell task surface through it instead of the prefs blob. Methods map to/from\n * the shell's `TodoTask` shape, including the optional `source`/`contextLabel`.\n */\nexport interface TodoProvider {\n list(): Promise<TodoTask[]>;\n create(input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }): Promise<TodoTask>;\n update(id: string, patch: Partial<TodoTask>): Promise<TodoTask>;\n remove(id: string): Promise<void>;\n}\n\n// ── Module-level provider store (shared across all consumers) ──\nlet provider: TodoProvider | null = null;\nlet cache: TodoTask[] = [];\nlet loaded = false;\nlet inflight: Promise<void> | null = null;\nconst listeners = new Set<() => void>();\n\nfunction emit(): void {\n for (const l of listeners) l();\n}\n\nfunction setCache(next: TodoTask[]): void {\n cache = next;\n emit();\n}\n\nfunction refresh(): Promise<void> {\n const p = provider;\n if (!p) {\n cache = [];\n loaded = true;\n emit();\n return Promise.resolve();\n }\n inflight = p\n .list()\n .then(rows => {\n if (provider === p) {\n cache = rows;\n loaded = true;\n emit();\n }\n })\n .catch(() => {\n if (provider === p) {\n loaded = true;\n emit();\n }\n })\n .finally(() => {\n inflight = null;\n });\n return inflight;\n}\n\n/** Register (or clear with `null`) the backend task provider. Opt-in. */\nexport function setShellTodoProvider(next: TodoProvider | null): void {\n provider = next;\n cache = [];\n loaded = false;\n if (next) refresh();\n else emit();\n}\n\nexport function hasShellTodoProvider(): boolean {\n return provider !== null;\n}\n\nfunction subscribe(cb: () => void): () => void {\n listeners.add(cb);\n if (provider && !loaded && !inflight) refresh();\n return () => {\n listeners.delete(cb);\n };\n}\n\nfunction getSnapshot(): TodoTask[] {\n return cache;\n}\n\n// ── Prefs-backed implementation (default / fallback) ──\nfunction usePrefsTodoTasks(): UseTodoTasks {\n const { prefs, save } = useShellPrefs();\n const tasks: TodoTask[] = useMemo(() => {\n const raw = prefs.todo_tasks;\n return Array.isArray(raw) ? (raw as TodoTask[]) : [];\n }, [prefs.todo_tasks]);\n\n const writeTasks = useCallback((next: TodoTask[]) => {\n save({ todo_tasks: next });\n }, [save]);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const id = uid();\n const ts = nowIso();\n const task: TodoTask = { done: false, ...input, name: input.name.trim(), id, createdAt: ts, updatedAt: ts };\n writeTasks([...tasks, task]);\n return id;\n }, [tasks, writeTasks]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n writeTasks(tasks.map(t => (t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t)));\n }, [tasks, writeTasks]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n writeTasks(tasks.filter(t => t.id !== id));\n }, [tasks, writeTasks]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n const target = tasks.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [tasks, updateTask]);\n\n return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };\n}\n\n// ── Public hook (provider-aware) ──\nexport function useTodoTasks(): UseTodoTasks {\n // Both hooks always run (rules of hooks); the active impl is chosen below.\n const prefsImpl = usePrefsTodoTasks();\n const providerTasks = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const p = provider;\n if (!p) return prefsImpl.addTask(input);\n const tempId = 'tmp-' + uid();\n const ts = nowIso();\n const optimistic: TodoTask = { done: false, ...input, name: input.name.trim(), id: tempId, createdAt: ts, updatedAt: ts };\n setCache([...cache, optimistic]);\n p.create({ ...input, name: input.name.trim() })\n // Merge so server-owned fields win but client-only fields (estimated/\n // completed/notes the backend may not persist) survive the round-trip.\n .then(saved => setCache(cache.map(t => (t.id === tempId ? { ...optimistic, ...saved } : t))))\n .catch(() => setCache(cache.filter(t => t.id !== tempId)));\n return tempId;\n }, [prefsImpl]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n const p = provider;\n if (!p) return prefsImpl.updateTask(id, patch);\n setCache(cache.map(t => (t.id === id ? { ...t, ...patch, id, updatedAt: nowIso() } : t)));\n p.update(id, patch).catch(() => { refresh(); });\n }, [prefsImpl]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n const p = provider;\n if (!p) return prefsImpl.removeTask(id);\n const prev = cache;\n setCache(cache.filter(t => t.id !== id));\n p.remove(id).catch(() => setCache(prev));\n }, [prefsImpl]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n if (!provider) return prefsImpl.toggleDone(id);\n const target = cache.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [prefsImpl, updateTask]);\n\n const setAllTasks = useCallback<UseTodoTasks['setAllTasks']>((next) => {\n // Provider owns persistence — bulk replace (Google Tasks sync) is a no-op there.\n if (!provider) prefsImpl.setAllTasks(next);\n }, [prefsImpl]);\n\n if (!hasShellTodoProvider()) return prefsImpl;\n return { tasks: providerTasks, addTask, updateTask, removeTask, toggleDone, setAllTasks };\n}\n\n/**\n * One-time migration: pull any tasks the Pomodoro widget previously\n * persisted to `localStorage.pomodoro_tasks` into the shared store.\n * No-op when a provider is registered (the provider owns persistence).\n */\nexport function migratePomodoroTasksOnce(\n currentTasks: TodoTask[],\n setAllTasks: (next: TodoTask[]) => void,\n): void {\n try {\n if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;\n const raw = localStorage.getItem(POMODORO_LEGACY_KEY);\n if (!raw) {\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const legacy: Array<{ id?: string; name?: string; estimated?: number; completed?: number; done?: boolean }>\n = JSON.parse(raw);\n if (!Array.isArray(legacy) || legacy.length === 0) {\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const ts = nowIso();\n const migrated: TodoTask[] = legacy\n .filter(t => typeof t?.name === 'string')\n .map(t => ({\n id: t.id || uid(),\n name: String(t.name),\n done: !!t.done,\n estimated: typeof t.estimated === 'number' ? t.estimated : undefined,\n completed: typeof t.completed === 'number' ? t.completed : undefined,\n createdAt: ts,\n updatedAt: ts,\n }));\n const existingIds = new Set(currentTasks.map(t => t.id));\n const additions = migrated.filter(t => !existingIds.has(t.id));\n setAllTasks([...additions, ...currentTasks]);\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n } catch {\n try { localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1'); } catch {}\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;