react-os-shell 0.2.62 → 0.2.64

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 (68) hide show
  1. package/dist/{Browser-46QICOBV.js → Browser-OL4SV34L.js} +4 -3
  2. package/dist/Browser-OL4SV34L.js.map +1 -0
  3. package/dist/{Calculator-2454MDQH.js → Calculator-VALSEOQD.js} +5 -4
  4. package/dist/Calculator-VALSEOQD.js.map +1 -0
  5. package/dist/{Calendar-NOVX5TSS.js → Calendar-I4OLRGNW.js} +4 -3
  6. package/dist/Calendar-I4OLRGNW.js.map +1 -0
  7. package/dist/{CurrencyConverter-LVUXSR57.js → CurrencyConverter-3DLJRL24.js} +5 -4
  8. package/dist/CurrencyConverter-3DLJRL24.js.map +1 -0
  9. package/dist/{Documents-QJDM3JQZ.js → Documents-JLIRD3ML.js} +4 -3
  10. package/dist/Documents-JLIRD3ML.js.map +1 -0
  11. package/dist/{Email-N27XXAW3.js → Email-PN2CNRLE.js} +5 -4
  12. package/dist/Email-PN2CNRLE.js.map +1 -0
  13. package/dist/Files-VQCZUKNU.js +12 -0
  14. package/dist/{Files-W3PU2D6S.js.map → Files-VQCZUKNU.js.map} +1 -1
  15. package/dist/{Minesweeper-Q4UYGWYG.js → Minesweeper-IGIPALMP.js} +4 -3
  16. package/dist/Minesweeper-IGIPALMP.js.map +1 -0
  17. package/dist/{Notepad-XU7VIXYV.js → Notepad-Q5SSDZNW.js} +4 -3
  18. package/dist/Notepad-Q5SSDZNW.js.map +1 -0
  19. package/dist/{PomodoroTimer-4UXR4OLK.js → PomodoroTimer-PD2HIZMT.js} +5 -4
  20. package/dist/PomodoroTimer-PD2HIZMT.js.map +1 -0
  21. package/dist/Preview-WFIQOE3T.js +8 -0
  22. package/dist/{Preview-EOZK5EBA.js.map → Preview-WFIQOE3T.js.map} +1 -1
  23. package/dist/Sidebar-4V6NQROQ.js +234 -0
  24. package/dist/Sidebar-4V6NQROQ.js.map +1 -0
  25. package/dist/Spreadsheet-Y5LACQRY.js +7 -0
  26. package/dist/{Spreadsheet-2GWD45U4.js.map → Spreadsheet-Y5LACQRY.js.map} +1 -1
  27. package/dist/{Weather-6GOXYALT.js → Weather-GEA3GBQQ.js} +5 -4
  28. package/dist/Weather-GEA3GBQQ.js.map +1 -0
  29. package/dist/{WorldClock-35S3SRPP.js → WorldClock-W2ENBGFS.js} +5 -4
  30. package/dist/WorldClock-W2ENBGFS.js.map +1 -0
  31. package/dist/apps/index.js +21 -19
  32. package/dist/apps/index.js.map +1 -1
  33. package/dist/chunk-2RIRISNW.js +46 -0
  34. package/dist/chunk-2RIRISNW.js.map +1 -0
  35. package/dist/{chunk-RGAFGLUW.js → chunk-4CFEJ4CC.js} +5 -72
  36. package/dist/chunk-4CFEJ4CC.js.map +1 -0
  37. package/dist/chunk-ADJ3CERD.js +31 -0
  38. package/dist/chunk-ADJ3CERD.js.map +1 -0
  39. package/dist/{chunk-ST7KKB2W.js → chunk-BUJKR34D.js} +3 -3
  40. package/dist/{chunk-ST7KKB2W.js.map → chunk-BUJKR34D.js.map} +1 -1
  41. package/dist/{chunk-NGGVYK5F.js → chunk-JDRZX27J.js} +11 -19
  42. package/dist/chunk-JDRZX27J.js.map +1 -0
  43. package/dist/{chunk-BZQALPHC.js → chunk-MY5PL6MK.js} +3 -3
  44. package/dist/{chunk-BZQALPHC.js.map → chunk-MY5PL6MK.js.map} +1 -1
  45. package/dist/chunk-SSA762W5.js +71 -0
  46. package/dist/chunk-SSA762W5.js.map +1 -0
  47. package/dist/{chunk-VH7LZ3JT.js → chunk-VDNTGVGH.js} +3 -3
  48. package/dist/{chunk-VH7LZ3JT.js.map → chunk-VDNTGVGH.js.map} +1 -1
  49. package/dist/index.d.ts +4 -0
  50. package/dist/index.js +134 -303
  51. package/dist/index.js.map +1 -1
  52. package/package.json +1 -1
  53. package/dist/Browser-46QICOBV.js.map +0 -1
  54. package/dist/Calculator-2454MDQH.js.map +0 -1
  55. package/dist/Calendar-NOVX5TSS.js.map +0 -1
  56. package/dist/CurrencyConverter-LVUXSR57.js.map +0 -1
  57. package/dist/Documents-QJDM3JQZ.js.map +0 -1
  58. package/dist/Email-N27XXAW3.js.map +0 -1
  59. package/dist/Files-W3PU2D6S.js +0 -8
  60. package/dist/Minesweeper-Q4UYGWYG.js.map +0 -1
  61. package/dist/Notepad-XU7VIXYV.js.map +0 -1
  62. package/dist/PomodoroTimer-4UXR4OLK.js.map +0 -1
  63. package/dist/Preview-EOZK5EBA.js +0 -7
  64. package/dist/Spreadsheet-2GWD45U4.js +0 -6
  65. package/dist/Weather-6GOXYALT.js.map +0 -1
  66. package/dist/WorldClock-35S3SRPP.js.map +0 -1
  67. package/dist/chunk-NGGVYK5F.js.map +0 -1
  68. package/dist/chunk-RGAFGLUW.js.map +0 -1
package/dist/index.js CHANGED
@@ -5,16 +5,22 @@ import { subscribePomo, getPomoSnapshot } from './chunk-MK3HLUO4.js';
5
5
  import { useGoogleAuth } from './chunk-MVWEL34Y.js';
6
6
  import { useShellPrefs } from './chunk-36VM54SC.js';
7
7
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
8
+ import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-2RIRISNW.js';
8
9
  import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
9
- export { EditableGrid } from './chunk-GP4Y3VCB.js';
10
- import { setPdfPreview } from './chunk-ST7KKB2W.js';
10
+ import { setPdfPreview } from './chunk-BUJKR34D.js';
11
11
  import './chunk-KUIPWCTJ.js';
12
12
  import { toast_default } from './chunk-WIJ45SYD.js';
13
13
  export { toast_default as toast } from './chunk-WIJ45SYD.js';
14
- import { useWindowManager, glassStyle, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, startMenuCategories, useIsMobile, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons, ModalActions, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-RGAFGLUW.js';
15
- export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, glassStyle, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellNavIcons, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-RGAFGLUW.js';
14
+ import './chunk-MY5PL6MK.js';
15
+ export { EditableGrid } from './chunk-GP4Y3VCB.js';
16
+ import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, useIsMobile, ModalActions, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-4CFEJ4CC.js';
17
+ export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-4CFEJ4CC.js';
16
18
  import { confirm } from './chunk-PLGHQ7QW.js';
17
19
  export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-PLGHQ7QW.js';
20
+ import { useAuth } from './chunk-ADJ3CERD.js';
21
+ export { ShellAuthProvider, setShellAuthBridge, useShellAuth } from './chunk-ADJ3CERD.js';
22
+ import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons } from './chunk-SSA762W5.js';
23
+ export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle, setShellNavIcons } from './chunk-SSA762W5.js';
18
24
  import { createContext, lazy, useState, useRef, useEffect, useCallback, useLayoutEffect, useContext, Suspense, isValidElement, cloneElement, useSyncExternalStore, useMemo } from 'react';
19
25
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
20
26
  import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react';
@@ -909,7 +915,7 @@ function StatusBadge({ status }) {
909
915
  }
910
916
 
911
917
  // src/version.ts
912
- var VERSION = "0.2.61" ;
918
+ var VERSION = "0.2.64" ;
913
919
  var APP_VERSION = VERSION;
914
920
 
915
921
  // src/changelog.ts
@@ -1006,6 +1012,22 @@ var ENTITY_ICONS = {
1006
1012
  proposal: "PR",
1007
1013
  folder: "FLD"
1008
1014
  };
1015
+ var PREVIEW_FILE_CODES = {
1016
+ pdf: "PDF",
1017
+ dxf: "DXF",
1018
+ "3d": "STP",
1019
+ image: "IMG",
1020
+ csv: "CSV"
1021
+ };
1022
+ var PREVIEW_FILE_COLORS = {
1023
+ pdf: "text-red-600",
1024
+ dxf: "text-blue-600",
1025
+ "3d": "text-purple-600",
1026
+ image: "text-emerald-600",
1027
+ csv: "text-green-600"
1028
+ };
1029
+ var DOCUMENTS_FOLDER_ID = "documents";
1030
+ var DOCUMENTS_FOLDER_NAME = "Documents";
1009
1031
  var GRID = 90;
1010
1032
  function snapToGrid(x, y) {
1011
1033
  return { x: Math.round(x / GRID) * GRID, y: Math.round(y / GRID) * GRID };
@@ -1171,7 +1193,7 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
1171
1193
  children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3" }) })
1172
1194
  }
1173
1195
  ),
1174
- /* @__PURE__ */ jsx("div", { className: `w-12 h-12 rounded-lg bg-white shadow flex items-center justify-center text-xs font-bold ${ENTITY_ICON_COLORS[item.entityType] || "text-gray-600"}`, children: ENTITY_ICONS[item.entityType] || item.entityType.slice(0, 3).toUpperCase() }),
1196
+ /* @__PURE__ */ jsx("div", { className: `w-12 h-12 rounded-lg bg-white shadow flex items-center justify-center text-xs font-bold ${item.entityType === "preview-file" && item.fileKind ? PREVIEW_FILE_COLORS[item.fileKind] : ENTITY_ICON_COLORS[item.entityType] || "text-gray-600"}`, children: item.entityType === "preview-file" && item.fileKind ? PREVIEW_FILE_CODES[item.fileKind] : ENTITY_ICONS[item.entityType] || item.entityType.slice(0, 3).toUpperCase() }),
1175
1197
  /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight truncate w-full ${isSelected ? "text-blue-900" : "text-gray-700"}`, children: item.label })
1176
1198
  ]
1177
1199
  },
@@ -1317,6 +1339,32 @@ function Desktop({ profile }) {
1317
1339
  if (host.saveSnap) host.saveSnap(v);
1318
1340
  else saveShellPrefs({ desktop_snap: v });
1319
1341
  }, [host, saveShellPrefs]);
1342
+ const previewStateRef = useRef({ folders, favDocs, saveFolders, saveDocs });
1343
+ previewStateRef.current = { folders, favDocs, saveFolders, saveDocs };
1344
+ useEffect(() => {
1345
+ const handler = (e) => {
1346
+ const detail = e.detail;
1347
+ if (!detail?.filePath) return;
1348
+ const { folders: fs, favDocs: docs, saveFolders: sf, saveDocs: sd } = previewStateRef.current;
1349
+ if (!fs.some((f) => f.id === DOCUMENTS_FOLDER_ID)) {
1350
+ sf([...fs, { id: DOCUMENTS_FOLDER_ID, name: DOCUMENTS_FOLDER_NAME }]);
1351
+ }
1352
+ const deduped = docs.filter(
1353
+ (d) => !(d.entityType === "preview-file" && d.filePath === detail.filePath)
1354
+ );
1355
+ const next = {
1356
+ entityType: "preview-file",
1357
+ entityId: detail.filePath,
1358
+ label: detail.filename,
1359
+ filePath: detail.filePath,
1360
+ fileKind: detail.kind,
1361
+ folderId: DOCUMENTS_FOLDER_ID
1362
+ };
1363
+ sd([next, ...deduped]);
1364
+ };
1365
+ window.addEventListener(PREVIEW_OPENED_EVENT, handler);
1366
+ return () => window.removeEventListener(PREVIEW_OPENED_EVENT, handler);
1367
+ }, []);
1320
1368
  const getDefaultPos = (idx) => {
1321
1369
  const col = Math.floor(idx / 8);
1322
1370
  const row = idx % 8;
@@ -1500,6 +1548,25 @@ function Desktop({ profile }) {
1500
1548
  };
1501
1549
  useEffect(() => {
1502
1550
  if (!rubberBand) return;
1551
+ const computeSelection = (minX, maxX, minY, maxY) => {
1552
+ const sel = /* @__PURE__ */ new Set();
1553
+ const cw = containerRef.current?.clientWidth || 800;
1554
+ desktopItems.forEach((item, i) => {
1555
+ const pos = getItemPos(item, i);
1556
+ const leftX = cw - pos.right - 80;
1557
+ if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
1558
+ sel.add(`item-${i}`);
1559
+ }
1560
+ });
1561
+ folders.forEach((f, i) => {
1562
+ const pos = getFolderPos(f, i);
1563
+ const leftX = cw - pos.right - 80;
1564
+ if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
1565
+ sel.add(`folder-${i}`);
1566
+ }
1567
+ });
1568
+ return sel;
1569
+ };
1503
1570
  const move = (e) => {
1504
1571
  const rect = containerRef.current?.getBoundingClientRect();
1505
1572
  if (!rect) return;
@@ -1509,31 +1576,15 @@ function Desktop({ profile }) {
1509
1576
  const dy = y - rubberBand.startY;
1510
1577
  if (dx * dx + dy * dy > 16) didRubberBandDragRef.current = true;
1511
1578
  setRubberBand((prev) => prev ? { ...prev, endX: x, endY: y } : null);
1579
+ if (didRubberBandDragRef.current) {
1580
+ const minX = Math.min(rubberBand.startX, x);
1581
+ const maxX = Math.max(rubberBand.startX, x);
1582
+ const minY = Math.min(rubberBand.startY, y);
1583
+ const maxY = Math.max(rubberBand.startY, y);
1584
+ setSelected(computeSelection(minX, maxX, minY, maxY));
1585
+ }
1512
1586
  };
1513
1587
  const up = () => {
1514
- if (rubberBand) {
1515
- const minX = Math.min(rubberBand.startX, rubberBand.endX);
1516
- const maxX = Math.max(rubberBand.startX, rubberBand.endX);
1517
- const minY = Math.min(rubberBand.startY, rubberBand.endY);
1518
- const maxY = Math.max(rubberBand.startY, rubberBand.endY);
1519
- const sel = /* @__PURE__ */ new Set();
1520
- const cw = containerRef.current?.clientWidth || 800;
1521
- desktopItems.forEach((item, i) => {
1522
- const pos = getItemPos(item, i);
1523
- const leftX = cw - pos.right - 80;
1524
- if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
1525
- sel.add(`item-${i}`);
1526
- }
1527
- });
1528
- folders.forEach((f, i) => {
1529
- const pos = getFolderPos(f, i);
1530
- const leftX = cw - pos.right - 80;
1531
- if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
1532
- sel.add(`folder-${i}`);
1533
- }
1534
- });
1535
- setSelected(sel);
1536
- }
1537
1588
  setRubberBand(null);
1538
1589
  };
1539
1590
  window.addEventListener("pointermove", move);
@@ -1720,26 +1771,31 @@ function Desktop({ profile }) {
1720
1771
  purple: "bg-purple-100 border-purple-300",
1721
1772
  orange: "bg-orange-100 border-orange-300"
1722
1773
  };
1723
- const renderIcon = (entityType, label, isSelected, entityId) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
1724
- entityType === "folder" ? /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: /* @__PURE__ */ jsxs("svg", { className: "h-12 w-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]", viewBox: "0 0 48 48", children: [
1725
- /* @__PURE__ */ jsx("path", { d: "M6 12a4 4 0 014-4h10l4 4h14a4 4 0 014 4v20a4 4 0 01-4 4H10a4 4 0 01-4-4V12z", fill: "white", stroke: "#eab308", strokeWidth: "2", strokeLinejoin: "round" }),
1726
- /* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
1727
- ] }) }) : entityType === "page" ? /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: (() => {
1728
- const icon = navIcons[label] || (entityId ? navIcons[entityId] : void 0);
1729
- if (icon && isValidElement(icon)) {
1730
- return cloneElement(icon, { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]" });
1731
- }
1732
- return /* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("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" }) });
1733
- })() }) : /* @__PURE__ */ jsxs("div", { className: `w-12 h-12 relative flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: [
1734
- /* @__PURE__ */ jsxs("svg", { className: `w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${ENTITY_ICON_COLORS[entityType] || "text-gray-500"}`, viewBox: "0 0 40 48", fill: "none", children: [
1735
- /* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", fill: "white", fillOpacity: "0.92" }),
1736
- /* @__PURE__ */ jsx("path", { d: "M26 0l10 10H30a4 4 0 01-4-4V0z", fill: "currentColor", fillOpacity: "0.2" }),
1737
- /* @__PURE__ */ jsx("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" })
1774
+ const renderIcon = (entityType, label, isSelected, entityId, fileKind) => {
1775
+ const isPreviewFile = entityType === "preview-file" && fileKind;
1776
+ const previewColor2 = isPreviewFile ? PREVIEW_FILE_COLORS[fileKind] : null;
1777
+ const previewCode = isPreviewFile ? PREVIEW_FILE_CODES[fileKind] : null;
1778
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
1779
+ entityType === "folder" ? /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: /* @__PURE__ */ jsxs("svg", { className: "h-12 w-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]", viewBox: "0 0 48 48", children: [
1780
+ /* @__PURE__ */ jsx("path", { d: "M6 12a4 4 0 014-4h10l4 4h14a4 4 0 014 4v20a4 4 0 01-4 4H10a4 4 0 01-4-4V12z", fill: "white", stroke: "#eab308", strokeWidth: "2", strokeLinejoin: "round" }),
1781
+ /* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
1782
+ ] }) }) : entityType === "page" ? /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: (() => {
1783
+ const icon = navIcons[label] || (entityId ? navIcons[entityId] : void 0);
1784
+ if (icon && isValidElement(icon)) {
1785
+ return cloneElement(icon, { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]" });
1786
+ }
1787
+ return /* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("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" }) });
1788
+ })() }) : /* @__PURE__ */ jsxs("div", { className: `w-12 h-12 relative flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: [
1789
+ /* @__PURE__ */ jsxs("svg", { className: `w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${previewColor2 ?? ENTITY_ICON_COLORS[entityType] ?? "text-gray-500"}`, viewBox: "0 0 40 48", fill: "none", children: [
1790
+ /* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", fill: "white", fillOpacity: "0.92" }),
1791
+ /* @__PURE__ */ jsx("path", { d: "M26 0l10 10H30a4 4 0 01-4-4V0z", fill: "currentColor", fillOpacity: "0.2" }),
1792
+ /* @__PURE__ */ jsx("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" })
1793
+ ] }),
1794
+ /* @__PURE__ */ jsx("span", { className: `absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${previewColor2 ?? ENTITY_ICON_COLORS[entityType] ?? "text-gray-600"}`, children: previewCode ?? ENTITY_ICONS[entityType] ?? entityType.slice(0, 3).toUpperCase() })
1738
1795
  ] }),
1739
- /* @__PURE__ */ jsx("span", { className: `absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${ENTITY_ICON_COLORS[entityType] || "text-gray-600"}`, children: ENTITY_ICONS[entityType] || entityType.slice(0, 3).toUpperCase() })
1740
- ] }),
1741
- /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight w-full drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)] ${isSelected ? "text-blue-200 bg-blue-600/60 rounded px-1" : "text-white"}`, children: label })
1742
- ] });
1796
+ /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight w-full drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)] ${isSelected ? "text-blue-200 bg-blue-600/60 rounded px-1" : "text-white"}`, children: label })
1797
+ ] });
1798
+ };
1743
1799
  const menuStyle = (x, y) => ({
1744
1800
  ...x + 180 > window.innerWidth ? { right: window.innerWidth - x } : { left: x },
1745
1801
  ...y + 250 > window.innerHeight ? { bottom: window.innerHeight - y } : { top: y }
@@ -1862,10 +1918,21 @@ function Desktop({ profile }) {
1862
1918
  onContextMenu: (e) => handleItemContextMenu(e, i),
1863
1919
  onDoubleClick: (e) => {
1864
1920
  e.stopPropagation();
1865
- doc.entityType === "page" ? openPage(doc.entityId) : openEntity(doc.entityType, doc.entityId, null, doc.label);
1921
+ if (doc.entityType === "preview-file" && doc.filePath && doc.fileKind) {
1922
+ openPreviewFile({
1923
+ filePath: doc.filePath,
1924
+ filename: doc.label,
1925
+ kind: doc.fileKind,
1926
+ onStaged: (route) => openPage(route)
1927
+ });
1928
+ } else if (doc.entityType === "page") {
1929
+ openPage(doc.entityId);
1930
+ } else {
1931
+ openEntity(doc.entityType, doc.entityId, null, doc.label);
1932
+ }
1866
1933
  },
1867
1934
  className: "cursor-default select-none",
1868
- children: renderIcon(doc.entityType, doc.label, isSelected, doc.entityId)
1935
+ children: renderIcon(doc.entityType, doc.label, isSelected, doc.entityId, doc.fileKind)
1869
1936
  },
1870
1937
  `item-${doc.entityType}-${doc.entityId}-${i}`
1871
1938
  );
@@ -2157,7 +2224,18 @@ function Desktop({ profile }) {
2157
2224
  folder,
2158
2225
  items: folderItems(openFolder),
2159
2226
  onClose: () => setOpenFolder(null),
2160
- onOpen: (item) => openEntity(item.entityType, item.entityId, null, item.label),
2227
+ onOpen: (item) => {
2228
+ if (item.entityType === "preview-file" && item.filePath && item.fileKind) {
2229
+ openPreviewFile({
2230
+ filePath: item.filePath,
2231
+ filename: item.label,
2232
+ kind: item.fileKind,
2233
+ onStaged: (route) => openPage(route)
2234
+ });
2235
+ } else {
2236
+ openEntity(item.entityType, item.entityId, null, item.label);
2237
+ }
2238
+ },
2161
2239
  onMoveOut: (toMove) => {
2162
2240
  const ids = new Set(toMove.map((t) => `${t.entityType}|${t.entityId}`));
2163
2241
  const updated = favDocs.map(
@@ -2251,29 +2329,6 @@ function Desktop({ profile }) {
2251
2329
  }
2252
2330
  );
2253
2331
  }
2254
- var DEFAULT = { hasAnyPerm: () => true };
2255
- var ShellAuthContext = createContext(DEFAULT);
2256
- function ShellAuthProvider({ value, children }) {
2257
- return /* @__PURE__ */ jsx(ShellAuthContext.Provider, { value, children });
2258
- }
2259
- function useShellAuth() {
2260
- return useContext(ShellAuthContext);
2261
- }
2262
-
2263
- // src/contexts/AuthContext.tsx
2264
- var _authBridge = {};
2265
- function setShellAuthBridge(bridge) {
2266
- _authBridge = bridge;
2267
- }
2268
- function useAuth() {
2269
- const { hasAnyPerm } = useShellAuth();
2270
- return {
2271
- user: _authBridge.user,
2272
- logout: _authBridge.logout ?? (() => {
2273
- }),
2274
- hasAnyPerm
2275
- };
2276
- }
2277
2332
  function subscribeMediaQuery(cb) {
2278
2333
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
2279
2334
  mq.addEventListener("change", cb);
@@ -2997,231 +3052,6 @@ function StartMenu({
2997
3052
  ` })
2998
3053
  ] });
2999
3054
  }
3000
- function Sidebar({
3001
- width,
3002
- openPage,
3003
- profile,
3004
- user,
3005
- onLogout,
3006
- onNavigate,
3007
- navSections: navSections2 = navSections,
3008
- navIcons: navIcons2 = navIcons,
3009
- sectionIcons: sectionIcons2 = sectionIcons,
3010
- categories = startMenuCategories,
3011
- productName,
3012
- productIcon
3013
- }) {
3014
- const { hasAnyPerm } = useAuth();
3015
- const erpLabels = new Set(categories.erp);
3016
- const systemLabels = new Set(categories.system);
3017
- const virtualSections = categories.virtual ?? [];
3018
- const [search, setSearch] = useState("");
3019
- const [expanded, setExpanded] = useState(/* @__PURE__ */ new Set());
3020
- const searchRef = useRef(null);
3021
- const toggleExpanded = (label) => {
3022
- setExpanded((prev) => {
3023
- const next = new Set(prev);
3024
- if (next.has(label)) next.delete(label);
3025
- else next.add(label);
3026
- return next;
3027
- });
3028
- };
3029
- const topItems = navSections2.filter((item) => !isSection(item));
3030
- const erpSections = navSections2.filter((item) => isSection(item) && erpLabels.has(item.label));
3031
- const systemSections = navSections2.filter((item) => isSection(item) && systemLabels.has(item.label));
3032
- const getVisibleItems = (section) => {
3033
- if (section.perms && !hasAnyPerm(section.perms)) return [];
3034
- return section.items.filter((it) => !it.perms || hasAnyPerm(it.perms));
3035
- };
3036
- const searchResults = useMemo(() => {
3037
- if (search.length < 2) return [];
3038
- const q = search.toLowerCase();
3039
- return navSections2.flatMap((entry) => {
3040
- if (isSection(entry)) {
3041
- return getVisibleItems(entry).filter((it) => it.label.toLowerCase().includes(q));
3042
- }
3043
- return entry.label.toLowerCase().includes(q) ? [entry] : [];
3044
- });
3045
- }, [search, navSections2, hasAnyPerm]);
3046
- useEffect(() => {
3047
- const onKey = (e) => {
3048
- if (e.key === "Escape") {
3049
- setExpanded(/* @__PURE__ */ new Set());
3050
- setSearch("");
3051
- } else if (e.key === "/" && document.activeElement?.tagName !== "INPUT" && document.activeElement?.tagName !== "TEXTAREA") {
3052
- e.preventDefault();
3053
- searchRef.current?.focus();
3054
- }
3055
- };
3056
- window.addEventListener("keydown", onKey);
3057
- return () => window.removeEventListener("keydown", onKey);
3058
- }, []);
3059
- const handleClick = (path) => {
3060
- onNavigate(path);
3061
- onPageOpenedReset();
3062
- };
3063
- const onPageOpenedReset = () => {
3064
- setSearch("");
3065
- };
3066
- const itemCls = "w-full flex items-center gap-2 rounded-lg px-3 py-2 text-sm";
3067
- const menuGlass = glassStyle();
3068
- const iconEl = (to) => {
3069
- const icon = navIcons2[to];
3070
- if (icon && isValidElement(icon)) {
3071
- return cloneElement(icon, {
3072
- className: "h-4 w-4 shrink-0 text-gray-500"
3073
- });
3074
- }
3075
- return /* @__PURE__ */ jsx("span", { className: "h-4 w-4 shrink-0" });
3076
- };
3077
- const secIcon = (label) => {
3078
- const icon = sectionIcons2[label];
3079
- if (icon && isValidElement(icon)) {
3080
- return cloneElement(icon, {
3081
- className: "h-4 w-4 shrink-0 text-gray-500"
3082
- });
3083
- }
3084
- return /* @__PURE__ */ jsx("span", { className: "h-4 w-4 shrink-0" });
3085
- };
3086
- const renderItem = (item) => /* @__PURE__ */ jsxs("div", { children: [
3087
- /* @__PURE__ */ jsxs(
3088
- "button",
3089
- {
3090
- onClick: () => handleClick(item.to),
3091
- className: `${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`,
3092
- children: [
3093
- iconEl(item.to),
3094
- /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
3095
- ]
3096
- }
3097
- ),
3098
- item.dividerAfter && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" })
3099
- ] }, item.to);
3100
- const renderSectionAccordion = (section, isErp) => {
3101
- const items = "perms" in section ? getVisibleItems(section) : section.items;
3102
- if (items.length === 0) return null;
3103
- const isOpen = expanded.has(section.label);
3104
- return /* @__PURE__ */ jsxs("div", { children: [
3105
- /* @__PURE__ */ jsxs(
3106
- "button",
3107
- {
3108
- onClick: () => toggleExpanded(section.label),
3109
- "aria-expanded": isOpen,
3110
- className: `${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`,
3111
- children: [
3112
- "icon" in section && section.icon ? section.icon : secIcon(section.label),
3113
- /* @__PURE__ */ jsx("span", { className: `truncate ${isErp ? "font-medium" : ""}`, children: section.label }),
3114
- /* @__PURE__ */ jsx(
3115
- "svg",
3116
- {
3117
- className: `h-3.5 w-3.5 ml-auto text-gray-500 transition-transform ${isOpen ? "rotate-90" : ""}`,
3118
- fill: "none",
3119
- viewBox: "0 0 24 24",
3120
- stroke: "currentColor",
3121
- strokeWidth: 2,
3122
- children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" })
3123
- }
3124
- )
3125
- ]
3126
- }
3127
- ),
3128
- isOpen && /* @__PURE__ */ jsx("div", { className: "pl-4 mt-0.5 mb-1 space-y-0.5", children: items.map((it) => /* @__PURE__ */ jsxs(
3129
- "button",
3130
- {
3131
- onClick: () => handleClick(it.to),
3132
- className: `${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`,
3133
- children: [
3134
- iconEl(it.to),
3135
- /* @__PURE__ */ jsx("span", { className: "truncate", children: it.label })
3136
- ]
3137
- },
3138
- it.to
3139
- )) })
3140
- ] }, section.label);
3141
- };
3142
- return /* @__PURE__ */ jsxs(
3143
- "div",
3144
- {
3145
- className: "fixed top-0 left-0 bottom-0 z-[260] flex flex-col rounded-r-2xl overflow-hidden",
3146
- style: { width, ...menuGlass },
3147
- children: [
3148
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-white/15 shrink-0", children: [
3149
- productIcon && /* @__PURE__ */ jsx("img", { src: productIcon, alt: "", className: "h-5 w-5 shrink-0 opacity-80" }),
3150
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-800 truncate", children: productName ?? "Apps" })
3151
- ] }),
3152
- /* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-2 ${GLASS_INPUT_BG} rounded-lg px-2.5 py-1.5`, children: [
3153
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" }) }),
3154
- /* @__PURE__ */ jsx(
3155
- "input",
3156
- {
3157
- ref: searchRef,
3158
- value: search,
3159
- onChange: (e) => setSearch(e.target.value),
3160
- placeholder: "Search...",
3161
- className: "flex-1 bg-transparent text-xs outline-none placeholder-gray-400"
3162
- }
3163
- ),
3164
- search && /* @__PURE__ */ jsx("button", { onClick: () => setSearch(""), className: "text-gray-400 hover:text-gray-600 text-xs", children: "\xD7" })
3165
- ] }) }),
3166
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-1 pb-1", children: search.length >= 2 ? (
3167
- // Search results take over the body.
3168
- /* @__PURE__ */ jsx("div", { children: searchResults.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center text-xs text-gray-400", children: "No matches" }) : searchResults.map((r) => /* @__PURE__ */ jsxs(
3169
- "button",
3170
- {
3171
- onClick: () => handleClick(r.to),
3172
- className: `${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`,
3173
- children: [
3174
- iconEl(r.to),
3175
- /* @__PURE__ */ jsx("span", { className: "truncate", children: r.label })
3176
- ]
3177
- },
3178
- r.to
3179
- )) })
3180
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
3181
- topItems.map(renderItem),
3182
- /* @__PURE__ */ jsxs(
3183
- "button",
3184
- {
3185
- onClick: () => handleClick("/notifications"),
3186
- className: `${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`,
3187
- children: [
3188
- /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 shrink-0 text-gray-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }),
3189
- /* @__PURE__ */ jsx("span", { children: "Notifications" })
3190
- ]
3191
- }
3192
- ),
3193
- /* @__PURE__ */ jsx("div", { className: "border-t border-white/15 my-1.5 mx-2" }),
3194
- erpSections.map((s) => renderSectionAccordion(s, true)),
3195
- systemSections.map((s) => renderSectionAccordion(s, false)),
3196
- virtualSections.map((v) => renderSectionAccordion(v, false))
3197
- ] }) }),
3198
- /* @__PURE__ */ jsx("div", { className: "border-t border-white/15 p-1 shrink-0", children: /* @__PURE__ */ jsxs(
3199
- "div",
3200
- {
3201
- onClick: () => handleClick("/profile"),
3202
- className: "rounded-lg px-2 py-1.5 flex items-center gap-2.5 hover:bg-blue-50 hover:text-blue-700 transition-colors cursor-pointer",
3203
- children: [
3204
- profile?.avatar_url ? /* @__PURE__ */ jsx("img", { src: profile.avatar_url, alt: "", className: "h-8 w-8 rounded-full object-cover border border-white/20 shrink-0" }) : /* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-blue-100 flex items-center justify-center text-sm font-bold text-blue-700 shrink-0", children: (profile?.first_name?.charAt(0) || user?.email?.charAt(0) || "?").toUpperCase() }),
3205
- /* @__PURE__ */ jsx("p", { className: "flex-1 min-w-0 text-sm font-medium text-gray-900 truncate", children: profile?.first_name ? `${profile.first_name} ${profile.last_name || ""}`.trim() : user?.email }),
3206
- /* @__PURE__ */ jsx(
3207
- "button",
3208
- {
3209
- onClick: (e) => {
3210
- e.stopPropagation();
3211
- onLogout();
3212
- },
3213
- title: "Sign Out",
3214
- className: "shrink-0 p-1.5 rounded-md text-gray-500 hover:text-red-600 hover:bg-red-50 transition-colors",
3215
- children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" }) })
3216
- }
3217
- )
3218
- ]
3219
- }
3220
- ) })
3221
- ]
3222
- }
3223
- );
3224
- }
3225
3055
 
3226
3056
  // src/shell/mobileShellStore.ts
3227
3057
  var _mode = "home";
@@ -3985,6 +3815,7 @@ function MobileBottomNav({
3985
3815
  }
3986
3816
  );
3987
3817
  }
3818
+ var Sidebar = lazy(() => import('./Sidebar-4V6NQROQ.js'));
3988
3819
  function useFavorites(wallpapers) {
3989
3820
  const { prefs, save } = useShellPrefs();
3990
3821
  const favorites = prefs.favorite_pages || [];
@@ -4184,7 +4015,7 @@ function Layout({
4184
4015
  taskbarTrayLeft
4185
4016
  } = {}) {
4186
4017
  const bugReport = useBugReport();
4187
- const { user, logout} = useAuth();
4018
+ const { user, logout, hasAnyPerm } = useAuth();
4188
4019
  const { openPage, openEntity, openWindows } = useWindowManager();
4189
4020
  const [menuOpen, setMenuOpen] = useState(false);
4190
4021
  useEmailUnreadCount();
@@ -4373,7 +4204,7 @@ function Layout({
4373
4204
  categories
4374
4205
  }
4375
4206
  ),
4376
- sidebarMode && /* @__PURE__ */ jsx(
4207
+ sidebarMode && /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
4377
4208
  Sidebar,
4378
4209
  {
4379
4210
  width: sidebarWidth,
@@ -4389,7 +4220,7 @@ function Layout({
4389
4220
  productName,
4390
4221
  productIcon
4391
4222
  }
4392
- ),
4223
+ ) }),
4393
4224
  (() => {
4394
4225
  const wallpaperStyle = {
4395
4226
  backgroundColor: desktopBg?.startsWith("#") ? desktopBg : desktopBg === "none" ? (() => {
@@ -5127,6 +4958,6 @@ function useEditHotkey(callback) {
5127
4958
  }, [callback, isActive]);
5128
4959
  }
5129
4960
 
5130
- export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, BugReportConfigProvider, BugReportDetail, BugReportProvider, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Customization, Desktop, DesktopHostProvider, ENTER, GlobalSearch, Layout, MOD, NotificationBell, SHIFT, ShellAuthProvider, ShellEntityFetcherProvider, ShortcutHelp, StartMenu, StatusBadge, StatusBadgeProvider, VERSION, createWindowRegistry, isMac, openBugReportDialog, reportBug, setShellAuthBridge, useBugReport, useClickOutside, useDesktopHost, useEditHotkey, useNewHotkey, useShellAuth, useShellEntityFetcher };
4961
+ export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, BugReportConfigProvider, BugReportDetail, BugReportProvider, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Customization, Desktop, DesktopHostProvider, ENTER, GlobalSearch, Layout, MOD, NotificationBell, SHIFT, ShellEntityFetcherProvider, ShortcutHelp, StartMenu, StatusBadge, StatusBadgeProvider, VERSION, createWindowRegistry, isMac, openBugReportDialog, reportBug, useBugReport, useClickOutside, useDesktopHost, useEditHotkey, useNewHotkey, useShellEntityFetcher };
5131
4962
  //# sourceMappingURL=index.js.map
5132
4963
  //# sourceMappingURL=index.js.map