react-os-shell 1.3.0 → 1.5.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 (33) hide show
  1. package/dist/{Browser-VTTA3X6R.js → Browser-MYVYM7YM.js} +4 -4
  2. package/dist/{Browser-VTTA3X6R.js.map → Browser-MYVYM7YM.js.map} +1 -1
  3. package/dist/{Documents-RRKY4LNJ.js → Documents-SLODLCU4.js} +3 -3
  4. package/dist/{Documents-RRKY4LNJ.js.map → Documents-SLODLCU4.js.map} +1 -1
  5. package/dist/{Files-QM7OERST.js → Files-NE4YZTRX.js} +7 -7
  6. package/dist/{Files-QM7OERST.js.map → Files-NE4YZTRX.js.map} +1 -1
  7. package/dist/{Notepad-7HBOCTJX.js → Notepad-F3TLHMWJ.js} +3 -3
  8. package/dist/{Notepad-7HBOCTJX.js.map → Notepad-F3TLHMWJ.js.map} +1 -1
  9. package/dist/Preview-HFGTMXE7.js +9 -0
  10. package/dist/{Preview-S54JZBKK.js.map → Preview-HFGTMXE7.js.map} +1 -1
  11. package/dist/{Spreadsheet-PRO6WI45.js → Spreadsheet-WF34DA44.js} +4 -4
  12. package/dist/{Spreadsheet-PRO6WI45.js.map → Spreadsheet-WF34DA44.js.map} +1 -1
  13. package/dist/apps/index.js +12 -12
  14. package/dist/chunk-F6NIGZTF.js +262 -0
  15. package/dist/chunk-F6NIGZTF.js.map +1 -0
  16. package/dist/{chunk-HQWHWS7V.js → chunk-IJ5Y4EGQ.js} +3 -3
  17. package/dist/{chunk-HQWHWS7V.js.map → chunk-IJ5Y4EGQ.js.map} +1 -1
  18. package/dist/{chunk-BDGH2GKX.js → chunk-PTRHYPXO.js} +3 -3
  19. package/dist/{chunk-BDGH2GKX.js.map → chunk-PTRHYPXO.js.map} +1 -1
  20. package/dist/{chunk-V2BMSY64.js → chunk-RE2FEWBE.js} +138 -25
  21. package/dist/chunk-RE2FEWBE.js.map +1 -0
  22. package/dist/{chunk-DLOIO7UD.js → chunk-W5ARJ7PU.js} +5 -5
  23. package/dist/{chunk-DLOIO7UD.js.map → chunk-W5ARJ7PU.js.map} +1 -1
  24. package/dist/{chunk-T4USMWTS.js → chunk-XHBHCL5I.js} +3 -3
  25. package/dist/{chunk-T4USMWTS.js.map → chunk-XHBHCL5I.js.map} +1 -1
  26. package/dist/index.d.ts +22 -2
  27. package/dist/index.js +128 -446
  28. package/dist/index.js.map +1 -1
  29. package/package.json +1 -1
  30. package/dist/Preview-S54JZBKK.js +0 -9
  31. package/dist/chunk-V2BMSY64.js.map +0 -1
  32. package/dist/chunk-WMOF4TAP.js +0 -98
  33. package/dist/chunk-WMOF4TAP.js.map +0 -1
package/dist/index.js CHANGED
@@ -4,18 +4,18 @@ import { subscribePomo, getPomoSnapshot } from './chunk-5X5LQNOX.js';
4
4
  export { setShellTodoProvider } from './chunk-5X5LQNOX.js';
5
5
  import { useShellPrefs } from './chunk-36VM54SC.js';
6
6
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
7
- import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-WMOF4TAP.js';
8
- export { Breadcrumbs } from './chunk-WMOF4TAP.js';
7
+ import { PREVIEW_OPENED_EVENT, publishDesktopFolders, requestFilesTrashView, FolderGlyph, openPreviewFile, requestFilesDesktopFolderView, FileIconTile, hashGradient } from './chunk-F6NIGZTF.js';
8
+ export { Breadcrumbs } from './chunk-F6NIGZTF.js';
9
9
  import { SidebarLayout } from './chunk-VGTEM5RZ.js';
10
10
  export { SidebarLayout } from './chunk-VGTEM5RZ.js';
11
11
  import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, setSoundForType, previewSound, setAllSounds, playLogout } from './chunk-D7PYW2QS.js';
12
- import { setPdfPreview } from './chunk-BDGH2GKX.js';
12
+ import { setPdfPreview } from './chunk-PTRHYPXO.js';
13
13
  import './chunk-KUIPWCTJ.js';
14
14
  import { toast_default } from './chunk-WIJ45SYD.js';
15
15
  export { toast_default as toast } from './chunk-WIJ45SYD.js';
16
- export { EditableGrid } from './chunk-HQWHWS7V.js';
17
- import { APP_VERSION } from './chunk-DLOIO7UD.js';
18
- export { VERSION } from './chunk-DLOIO7UD.js';
16
+ export { EditableGrid } from './chunk-IJ5Y4EGQ.js';
17
+ import { APP_VERSION } from './chunk-W5ARJ7PU.js';
18
+ export { VERSION } from './chunk-W5ARJ7PU.js';
19
19
  import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, WINDOW_REGISTRY, isPageEntry, useIsMobile, ModalActions, useModalActive, client_default, LoadingSpinner, setWindowPosition, ThumbCard, activateModal } from './chunk-GWVVILYQ.js';
20
20
  export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-GWVVILYQ.js';
21
21
  import { confirm } from './chunk-UBN4IUDE.js';
@@ -1488,87 +1488,8 @@ async function reportBug(submit) {
1488
1488
  toast_default.error(err?.response?.data?.detail || "Failed to send.");
1489
1489
  }
1490
1490
  }
1491
- var ENTITY_ICON_COLORS = {
1492
- order: "text-blue-600",
1493
- purchase_order: "text-purple-600",
1494
- invoice: "text-green-600",
1495
- client: "text-indigo-600",
1496
- manufacturer: "text-orange-600",
1497
- shipment: "text-teal-600",
1498
- part_number: "text-gray-600",
1499
- project: "text-pink-600",
1500
- mould: "text-red-600",
1501
- design: "text-cyan-600",
1502
- brand: "text-amber-600",
1503
- price_sheet: "text-emerald-600",
1504
- folder: "text-yellow-600",
1505
- page: "text-blue-500"
1506
- };
1507
- var ENTITY_ICONS = {
1508
- order: "SO",
1509
- purchase_order: "PO",
1510
- invoice: "INV",
1511
- client: "CLI",
1512
- manufacturer: "MFR",
1513
- shipment: "DN",
1514
- part_number: "PN",
1515
- project: "PRJ",
1516
- mould: "MLD",
1517
- design: "DSN",
1518
- brand: "BRD",
1519
- price_sheet: "PS",
1520
- vendor_invoice: "VI",
1521
- vendor_payment: "VP",
1522
- warranty_claim: "WC",
1523
- qc_report: "QC",
1524
- vendor_shipment: "GRN",
1525
- bank_account: "BA",
1526
- wheel_finish: "WF",
1527
- weight_log: "WL",
1528
- production_progress: "PP",
1529
- vendor_price_sheet: "VPS",
1530
- proposal: "PR",
1531
- folder: "FLD"
1532
- };
1533
- var PREVIEW_FILE_CODES = {
1534
- pdf: "PDF",
1535
- dxf: "DXF",
1536
- "3d": "STP",
1537
- image: "IMG",
1538
- csv: "CSV"
1539
- };
1540
- var PREVIEW_FILE_COLORS = {
1541
- pdf: "text-red-600",
1542
- dxf: "text-blue-600",
1543
- "3d": "text-purple-600",
1544
- image: "text-emerald-600",
1545
- csv: "text-green-600"
1546
- };
1547
1491
  var DOCUMENTS_FOLDER_ID = "documents";
1548
1492
  var DOCUMENTS_FOLDER_NAME = "Documents";
1549
- function FileIconTile({ entityType, isSelected, entityId, label, fileKind }) {
1550
- const isPreviewFile = entityType === "preview-file" && fileKind;
1551
- const previewColor2 = isPreviewFile ? PREVIEW_FILE_COLORS[fileKind] : null;
1552
- const previewCode = isPreviewFile ? PREVIEW_FILE_CODES[fileKind] : null;
1553
- if (entityType === "folder") {
1554
- return /* @__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: [
1555
- /* @__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" }),
1556
- /* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
1557
- ] }) });
1558
- }
1559
- if (entityType === "page") {
1560
- const icon = label && navIcons[label] || (entityId ? navIcons[entityId] : void 0);
1561
- return /* @__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: icon && isValidElement(icon) ? cloneElement(icon, { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]" }) : /* @__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" }) }) });
1562
- }
1563
- return /* @__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: [
1564
- /* @__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: [
1565
- /* @__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" }),
1566
- /* @__PURE__ */ jsx("path", { d: "M26 0l10 10H30a4 4 0 01-4-4V0z", fill: "currentColor", fillOpacity: "0.2" }),
1567
- /* @__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" })
1568
- ] }),
1569
- /* @__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() })
1570
- ] });
1571
- }
1572
1493
  var GRID = 90;
1573
1494
  function snapToGrid(x, y) {
1574
1495
  return { x: Math.round(x / GRID) * GRID, y: Math.round(y / GRID) * GRID };
@@ -1580,242 +1501,6 @@ function DesktopHostProvider({ value, children }) {
1580
1501
  function useDesktopHost() {
1581
1502
  return useContext(DesktopHostContext);
1582
1503
  }
1583
- var FOLDER_GRID = 90;
1584
- var FOLDER_ITEM_H = 80;
1585
- var FOLDER_PAD = 12;
1586
- function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onSetFolderPosition, onDragOutToDesktop }) {
1587
- const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
1588
- const [rubber, setRubber] = useState(null);
1589
- const didDragRubber = useRef(false);
1590
- const bodyRef = useRef(null);
1591
- const [bodyWidth, setBodyWidth] = useState(800);
1592
- const setDragOutsideClass = (on) => {
1593
- const el = bodyRef.current;
1594
- if (!el) return;
1595
- el.style.outline = on ? "2px dashed rgb(96 165 250 / 0.6)" : "";
1596
- el.style.outlineOffset = on ? "-2px" : "";
1597
- };
1598
- useEffect(() => {
1599
- const el = bodyRef.current;
1600
- if (!el) return;
1601
- const update = () => setBodyWidth(el.clientWidth);
1602
- update();
1603
- const ro = new ResizeObserver(update);
1604
- ro.observe(el);
1605
- return () => ro.disconnect();
1606
- }, []);
1607
- const cols = Math.max(1, Math.floor((bodyWidth - FOLDER_PAD) / FOLDER_GRID));
1608
- const getItemFolderPos = (item, idx) => {
1609
- if (item.folderX != null && item.folderY != null) return { x: item.folderX, y: item.folderY };
1610
- return { x: FOLDER_PAD + idx % cols * FOLDER_GRID, y: FOLDER_PAD + Math.floor(idx / cols) * FOLDER_GRID };
1611
- };
1612
- const toggleSelect = (i, e) => {
1613
- e.stopPropagation();
1614
- if (e.shiftKey || e.metaKey || e.ctrlKey) {
1615
- setSelected((prev) => {
1616
- const next = new Set(prev);
1617
- next.has(i) ? next.delete(i) : next.add(i);
1618
- return next;
1619
- });
1620
- } else if (!selected.has(i)) {
1621
- setSelected(/* @__PURE__ */ new Set([i]));
1622
- }
1623
- };
1624
- const startRubber = (e) => {
1625
- if (e.button !== 0 || e.target !== bodyRef.current) return;
1626
- const el = bodyRef.current;
1627
- const r = el.getBoundingClientRect();
1628
- const x = e.clientX - r.left + el.scrollLeft;
1629
- const y = e.clientY - r.top + el.scrollTop;
1630
- setRubber({ x1: x, y1: y, x2: x, y2: y });
1631
- didDragRubber.current = false;
1632
- setSelected(/* @__PURE__ */ new Set());
1633
- };
1634
- useEffect(() => {
1635
- if (!rubber) return;
1636
- const computeSelection = (minX, maxX, minY, maxY) => {
1637
- const next = /* @__PURE__ */ new Set();
1638
- const r = bodyRef.current;
1639
- if (!r) return next;
1640
- const tiles = r.querySelectorAll("[data-folder-item]");
1641
- const containerRect = r.getBoundingClientRect();
1642
- tiles.forEach((t) => {
1643
- const tr = t.getBoundingClientRect();
1644
- const tx = tr.left - containerRect.left + r.scrollLeft;
1645
- const ty = tr.top - containerRect.top + r.scrollTop;
1646
- if (tx + tr.width > minX && tx < maxX && ty + tr.height > minY && ty < maxY) {
1647
- const i = parseInt(t.getAttribute("data-folder-item") || "-1", 10);
1648
- if (i >= 0) next.add(i);
1649
- }
1650
- });
1651
- return next;
1652
- };
1653
- const move = (e) => {
1654
- const el = bodyRef.current;
1655
- if (!el) return;
1656
- const r = el.getBoundingClientRect();
1657
- const x = e.clientX - r.left + el.scrollLeft;
1658
- const y = e.clientY - r.top + el.scrollTop;
1659
- const dx = x - rubber.x1, dy = y - rubber.y1;
1660
- if (dx * dx + dy * dy > 16) didDragRubber.current = true;
1661
- setRubber((prev) => prev ? { ...prev, x2: x, y2: y } : null);
1662
- if (didDragRubber.current) {
1663
- const minX = Math.min(rubber.x1, x);
1664
- const maxX = Math.max(rubber.x1, x);
1665
- const minY = Math.min(rubber.y1, y);
1666
- const maxY = Math.max(rubber.y1, y);
1667
- setSelected(computeSelection(minX, maxX, minY, maxY));
1668
- }
1669
- };
1670
- const up = () => setRubber(null);
1671
- window.addEventListener("pointermove", move);
1672
- window.addEventListener("pointerup", up);
1673
- return () => {
1674
- window.removeEventListener("pointermove", move);
1675
- window.removeEventListener("pointerup", up);
1676
- };
1677
- }, [rubber]);
1678
- const dragEntriesRef = useRef([]);
1679
- const dragStartRef = useRef(null);
1680
- const startItemDrag = (i, e) => {
1681
- if (e.button !== 0) return;
1682
- e.stopPropagation();
1683
- e.preventDefault();
1684
- const useMulti = selected.has(i) && selected.size > 1;
1685
- const idxs = useMulti ? Array.from(selected) : [i];
1686
- if (!useMulti) setSelected(/* @__PURE__ */ new Set([i]));
1687
- const entries = idxs.map((idx) => {
1688
- const item = items[idx];
1689
- const pos = getItemFolderPos(item, idx);
1690
- const el = bodyRef.current?.querySelector(`[data-folder-item="${idx}"]`) ?? null;
1691
- return { idx, item, origX: pos.x, origY: pos.y, el };
1692
- }).filter((e2) => e2.item);
1693
- dragEntriesRef.current = entries;
1694
- dragStartRef.current = { clientX: e.clientX, clientY: e.clientY };
1695
- setDragOutsideClass(false);
1696
- let moved = false;
1697
- const move = (ev) => {
1698
- const start = dragStartRef.current;
1699
- if (!start) return;
1700
- const dx = ev.clientX - start.clientX;
1701
- const dy = ev.clientY - start.clientY;
1702
- if (!moved && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) moved = true;
1703
- if (!moved) return;
1704
- for (const entry of dragEntriesRef.current) {
1705
- if (!entry.el) continue;
1706
- entry.el.style.left = `${entry.origX + dx}px`;
1707
- entry.el.style.top = `${entry.origY + dy}px`;
1708
- entry.el.style.zIndex = "100";
1709
- entry.el.style.opacity = "0.85";
1710
- }
1711
- const r = bodyRef.current?.getBoundingClientRect();
1712
- const inside = !!r && ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top && ev.clientY <= r.bottom;
1713
- setDragOutsideClass(!inside);
1714
- };
1715
- const up = (ev) => {
1716
- window.removeEventListener("pointermove", move);
1717
- window.removeEventListener("pointerup", up);
1718
- const entries2 = dragEntriesRef.current;
1719
- dragEntriesRef.current = [];
1720
- dragStartRef.current = null;
1721
- for (const entry of entries2) {
1722
- if (!entry.el) continue;
1723
- entry.el.style.zIndex = "";
1724
- entry.el.style.opacity = "";
1725
- }
1726
- setDragOutsideClass(false);
1727
- if (!moved) return;
1728
- const r = bodyRef.current?.getBoundingClientRect();
1729
- const inside = !!r && ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top && ev.clientY <= r.bottom;
1730
- if (!inside) {
1731
- const drops = entries2.map((e2) => ({ item: e2.item, clientX: ev.clientX, clientY: ev.clientY }));
1732
- setSelected(/* @__PURE__ */ new Set());
1733
- onDragOutToDesktop(drops);
1734
- } else {
1735
- const updates = entries2.map((e2) => {
1736
- const leftStr = e2.el?.style.left || `${e2.origX}px`;
1737
- const topStr = e2.el?.style.top || `${e2.origY}px`;
1738
- const x = Math.max(0, parseFloat(leftStr));
1739
- const y = Math.max(0, parseFloat(topStr));
1740
- return { item: e2.item, x, y };
1741
- });
1742
- onSetFolderPosition(updates);
1743
- }
1744
- };
1745
- window.addEventListener("pointermove", move);
1746
- window.addEventListener("pointerup", up);
1747
- };
1748
- const moveSelectedOut = () => {
1749
- if (selected.size === 0) return;
1750
- onMoveOut(Array.from(selected).map((i) => items[i]).filter(Boolean));
1751
- setSelected(/* @__PURE__ */ new Set());
1752
- };
1753
- const folderIcon = /* @__PURE__ */ jsx("svg", { className: "h-5 w-5 text-amber-500", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M2 6a2 2 0 012-2h5l2 2h9a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" }) });
1754
- const contentHeight = items.reduce((max, item, i) => {
1755
- const pos = getItemFolderPos(item, i);
1756
- return Math.max(max, pos.y + FOLDER_ITEM_H + FOLDER_PAD);
1757
- }, 300);
1758
- return /* @__PURE__ */ jsx(Modal, { open: true, onClose, title: folder.name, icon: folderIcon, size: "lg", children: /* @__PURE__ */ jsxs(
1759
- "div",
1760
- {
1761
- ref: bodyRef,
1762
- onPointerDown: startRubber,
1763
- onClick: () => {
1764
- if (didDragRubber.current) {
1765
- didDragRubber.current = false;
1766
- return;
1767
- }
1768
- setSelected(/* @__PURE__ */ new Set());
1769
- },
1770
- className: "relative h-full min-h-[300px] p-3 overflow-auto",
1771
- style: {
1772
- background: "linear-gradient(135deg, rgba(254, 243, 199, 0.55) 0%, rgba(253, 230, 138, 0.4) 50%, rgba(252, 211, 77, 0.3) 100%)"
1773
- },
1774
- children: [
1775
- selected.size > 0 && /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-20 mb-2 flex items-center gap-2 px-2 py-1 rounded-md bg-white/80 backdrop-blur-sm shadow border border-gray-200 text-xs text-gray-700 w-fit", children: [
1776
- /* @__PURE__ */ jsxs("span", { children: [
1777
- selected.size,
1778
- " selected"
1779
- ] }),
1780
- /* @__PURE__ */ jsx("button", { onClick: moveSelectedOut, className: "px-2 py-0.5 rounded text-blue-600 hover:bg-blue-50", children: "Move to desktop" }),
1781
- /* @__PURE__ */ jsx("button", { onClick: () => setSelected(/* @__PURE__ */ new Set()), className: "px-2 py-0.5 rounded text-gray-500 hover:bg-gray-100", children: "Clear" })
1782
- ] }),
1783
- items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 text-center py-8 italic", children: "Folder is empty. Drag documents here." }) : /* @__PURE__ */ jsx("div", { className: "relative", style: { height: contentHeight }, children: items.map((item, i) => {
1784
- const isSelected = selected.has(i);
1785
- const pos = getItemFolderPos(item, i);
1786
- return /* @__PURE__ */ jsx(
1787
- "div",
1788
- {
1789
- "data-folder-item": i,
1790
- onPointerDown: (e) => startItemDrag(i, e),
1791
- onClick: (e) => toggleSelect(i, e),
1792
- onDoubleClick: () => onOpen(item),
1793
- style: { position: "absolute", left: pos.x, top: pos.y },
1794
- className: "cursor-default select-none",
1795
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
1796
- /* @__PURE__ */ jsx(FileIconTile, { entityType: item.entityType, isSelected, entityId: item.entityId, label: item.label, fileKind: item.fileKind }),
1797
- /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight truncate w-full ${isSelected ? "text-blue-900 bg-blue-200/60 rounded px-1" : "text-gray-700"}`, children: item.label })
1798
- ] })
1799
- },
1800
- `${item.entityType}-${item.entityId}-${i}`
1801
- );
1802
- }) }),
1803
- rubber && /* @__PURE__ */ jsx(
1804
- "div",
1805
- {
1806
- className: "absolute border border-blue-500 bg-blue-500/10 pointer-events-none",
1807
- style: {
1808
- left: Math.min(rubber.x1, rubber.x2),
1809
- top: Math.min(rubber.y1, rubber.y2),
1810
- width: Math.abs(rubber.x2 - rubber.x1),
1811
- height: Math.abs(rubber.y2 - rubber.y1)
1812
- }
1813
- }
1814
- )
1815
- ]
1816
- }
1817
- ) });
1818
- }
1819
1504
  function Desktop({ profile }) {
1820
1505
  useQueryClient();
1821
1506
  const { openEntity, openPage } = useWindowManager();
@@ -1918,7 +1603,6 @@ function Desktop({ profile }) {
1918
1603
  const [contextMenu, setContextMenu] = useState(null);
1919
1604
  const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
1920
1605
  const [rubberBand, setRubberBand] = useState(null);
1921
- const [openFolder, setOpenFolder] = useState(null);
1922
1606
  const [aboutOpen, setAboutOpen] = useState(false);
1923
1607
  const [whatsNewOpen, setWhatsNewOpen] = useState(false);
1924
1608
  const [widgetsOpen, setWidgetsOpen] = useState(false);
@@ -1941,13 +1625,13 @@ function Desktop({ profile }) {
1941
1625
  if (host.saveSnap) host.saveSnap(v);
1942
1626
  else saveShellPrefs({ desktop_snap: v });
1943
1627
  }, [host, saveShellPrefs]);
1944
- const previewStateRef = useRef({ folders, favDocs, saveFolders, saveDocs });
1945
- previewStateRef.current = { folders, favDocs, saveFolders, saveDocs };
1628
+ const liveStateRef = useRef({ folders, favDocs, saveFolders, saveDocs });
1629
+ liveStateRef.current = { folders, favDocs, saveFolders, saveDocs };
1946
1630
  useEffect(() => {
1947
1631
  const handler = (e) => {
1948
1632
  const detail = e.detail;
1949
1633
  if (!detail?.filePath) return;
1950
- const { folders: fs, favDocs: docs, saveFolders: sf, saveDocs: sd } = previewStateRef.current;
1634
+ const { folders: fs, favDocs: docs, saveFolders: sf, saveDocs: sd } = liveStateRef.current;
1951
1635
  if (!fs.some((f) => f.id === DOCUMENTS_FOLDER_ID)) {
1952
1636
  sf([...fs, { id: DOCUMENTS_FOLDER_ID, name: DOCUMENTS_FOLDER_NAME }]);
1953
1637
  }
@@ -1982,6 +1666,36 @@ function Desktop({ profile }) {
1982
1666
  };
1983
1667
  const desktopItems = favDocs.filter((d) => !d.folderId);
1984
1668
  const folderItems = (folderId) => favDocs.filter((d) => d.folderId === folderId);
1669
+ const openItem = (item) => {
1670
+ if (item.entityType === "preview-file" && item.filePath && item.fileKind) {
1671
+ openPreviewFile({
1672
+ filePath: item.filePath,
1673
+ filename: item.label,
1674
+ kind: item.fileKind,
1675
+ onStaged: (route) => openPage(route)
1676
+ });
1677
+ } else if (item.entityType === "page") {
1678
+ openPage(item.entityId);
1679
+ } else {
1680
+ openEntity(item.entityType, item.entityId, null, item.label);
1681
+ }
1682
+ };
1683
+ const openDesktopFolder = (folderId) => {
1684
+ requestFilesDesktopFolderView(folderId);
1685
+ openPage("/files");
1686
+ };
1687
+ const bridgeMoveToDesktop = useCallback((toMove) => {
1688
+ const { favDocs: docs, saveDocs: sd } = liveStateRef.current;
1689
+ const ids = new Set(toMove.map((t) => `${t.entityType}|${t.entityId}`));
1690
+ sd(docs.map(
1691
+ (d) => d.folderId && ids.has(`${d.entityType}|${d.entityId}`) ? { ...d, folderId: void 0, folderX: void 0, folderY: void 0 } : d
1692
+ ));
1693
+ }, []);
1694
+ const bridgeRemoveShortcuts = useCallback((toRemove) => {
1695
+ const { favDocs: docs, saveDocs: sd } = liveStateRef.current;
1696
+ const ids = new Set(toRemove.map((t) => `${t.entityType}|${t.entityId}`));
1697
+ sd(docs.filter((d) => !(d.folderId && ids.has(`${d.entityType}|${d.entityId}`))));
1698
+ }, []);
1985
1699
  const [localPositions, setLocalPositions] = useState({});
1986
1700
  const dragEntriesRef = useRef([]);
1987
1701
  const startDrag = (type, idx, e) => {
@@ -2138,6 +1852,21 @@ function Desktop({ profile }) {
2138
1852
  useEffect(() => {
2139
1853
  setLocalPositions({});
2140
1854
  }, [favDocsKey, foldersKey]);
1855
+ useEffect(() => {
1856
+ const { folders: fs, favDocs: docs } = liveStateRef.current;
1857
+ const itemsByFolder = {};
1858
+ for (const f of fs) itemsByFolder[f.id] = [];
1859
+ for (const d of docs) {
1860
+ if (d.folderId && itemsByFolder[d.folderId]) itemsByFolder[d.folderId].push(d);
1861
+ }
1862
+ publishDesktopFolders({
1863
+ folders: fs.map((f) => ({ id: f.id, name: f.name, itemCount: itemsByFolder[f.id]?.length ?? 0 })),
1864
+ itemsByFolder,
1865
+ moveToDesktop: bridgeMoveToDesktop,
1866
+ removeShortcuts: bridgeRemoveShortcuts
1867
+ });
1868
+ }, [favDocsKey, foldersKey, bridgeMoveToDesktop, bridgeRemoveShortcuts]);
1869
+ useEffect(() => () => publishDesktopFolders(null), []);
2141
1870
  const didRubberBandDragRef = useRef(false);
2142
1871
  const startRubberBand = (e) => {
2143
1872
  if (e.button !== 0 || e.target !== containerRef.current) return;
@@ -2167,6 +1896,16 @@ function Desktop({ profile }) {
2167
1896
  sel.add(`folder-${i}`);
2168
1897
  }
2169
1898
  });
1899
+ const trashEl = containerRef.current?.querySelector('[data-desktop-icon="trash"]');
1900
+ const containerRect = containerRef.current?.getBoundingClientRect();
1901
+ if (trashEl && containerRect) {
1902
+ const tr = trashEl.getBoundingClientRect();
1903
+ const tx = tr.left - containerRect.left;
1904
+ const ty = tr.top - containerRect.top;
1905
+ if (tx + tr.width > minX && tx < maxX && ty + tr.height > minY && ty < maxY) {
1906
+ sel.add("trash");
1907
+ }
1908
+ }
2170
1909
  return sel;
2171
1910
  };
2172
1911
  const move = (e) => {
@@ -2407,6 +2146,7 @@ function Desktop({ profile }) {
2407
2146
  const trashPos = prefs.desktop_trash_position;
2408
2147
  const right = trashPos?.right ?? defaultRight;
2409
2148
  const bottom = trashPos?.bottom ?? defaultBottom;
2149
+ const isTrashSelected = selected.has("trash");
2410
2150
  const startTrashDrag = (e) => {
2411
2151
  if (e.button !== 0) return;
2412
2152
  e.preventDefault();
@@ -2443,18 +2183,28 @@ function Desktop({ profile }) {
2443
2183
  "data-desktop-icon": "trash",
2444
2184
  style: { position: "absolute", right, bottom, zIndex: 1 },
2445
2185
  onPointerDown: startTrashDrag,
2446
- onClick: (e) => e.stopPropagation(),
2186
+ onClick: (e) => {
2187
+ e.stopPropagation();
2188
+ if (e.shiftKey || e.metaKey || e.ctrlKey) {
2189
+ setSelected((prev) => {
2190
+ const next = new Set(prev);
2191
+ next.has("trash") ? next.delete("trash") : next.add("trash");
2192
+ return next;
2193
+ });
2194
+ } else if (!selected.has("trash")) {
2195
+ setSelected(/* @__PURE__ */ new Set(["trash"]));
2196
+ }
2197
+ },
2447
2198
  onContextMenu: (e) => e.preventDefault(),
2448
2199
  onDoubleClick: (e) => {
2449
2200
  e.stopPropagation();
2450
- window.__REACT_OS_SHELL_FILES_VIEW__ = "trash";
2451
- window.dispatchEvent(new CustomEvent("react-os-shell:files-show-trash"));
2201
+ requestFilesTrashView();
2452
2202
  openPage("/files");
2453
2203
  },
2454
2204
  className: "cursor-default select-none",
2455
2205
  title: "Trash \u2014 double-click to open, drag to move",
2456
2206
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
2457
- /* @__PURE__ */ jsx("div", { className: "w-12 h-12 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-12 w-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx(
2207
+ /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isTrashSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: /* @__PURE__ */ jsx("svg", { className: "h-12 w-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx(
2458
2208
  "path",
2459
2209
  {
2460
2210
  fill: "#c0c4cc",
@@ -2466,7 +2216,7 @@ function Desktop({ profile }) {
2466
2216
  d: "M16.5 4.478v.227a48.816 48.816 0 013.878.512.75.75 0 11-.256 1.478l-.209-.035-1.005 13.07a3 3 0 01-2.991 2.77H8.084a3 3 0 01-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 01-.256-1.478A48.567 48.567 0 017.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 014.368 0c1.603.051 2.816 1.387 2.816 2.951zm-6.136-1.452a51.196 51.196 0 013.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 00-6 0v-.113c0-.794.609-1.428 1.364-1.452zm-.355 5.945a.75.75 0 10-1.5.058l.347 9a.75.75 0 101.499-.058l-.346-9zm5.48.058a.75.75 0 10-1.498-.058l-.347 9a.75.75 0 001.5.058l.346-9z"
2467
2217
  }
2468
2218
  ) }) }),
2469
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-center leading-tight text-white drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]", children: "Trash" })
2219
+ /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)] ${isTrashSelected ? "text-blue-200 bg-blue-600/60 rounded px-1" : "text-white"}`, children: "Trash" })
2470
2220
  ] })
2471
2221
  }
2472
2222
  );
@@ -2499,18 +2249,7 @@ function Desktop({ profile }) {
2499
2249
  onContextMenu: (e) => handleItemContextMenu(e, i),
2500
2250
  onDoubleClick: (e) => {
2501
2251
  e.stopPropagation();
2502
- if (doc.entityType === "preview-file" && doc.filePath && doc.fileKind) {
2503
- openPreviewFile({
2504
- filePath: doc.filePath,
2505
- filename: doc.label,
2506
- kind: doc.fileKind,
2507
- onStaged: (route) => openPage(route)
2508
- });
2509
- } else if (doc.entityType === "page") {
2510
- openPage(doc.entityId);
2511
- } else {
2512
- openEntity(doc.entityType, doc.entityId, null, doc.label);
2513
- }
2252
+ openItem(doc);
2514
2253
  },
2515
2254
  className: "cursor-default select-none",
2516
2255
  children: renderIcon(doc.entityType, doc.label, isSelected, doc.entityId, doc.fileKind)
@@ -2554,14 +2293,11 @@ function Desktop({ profile }) {
2554
2293
  onContextMenu: (e) => handleFolderContextMenu(e, i),
2555
2294
  onDoubleClick: (e) => {
2556
2295
  e.stopPropagation();
2557
- setOpenFolder(folder.id);
2296
+ openDesktopFolder(folder.id);
2558
2297
  },
2559
2298
  className: "cursor-default select-none",
2560
2299
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
2561
- /* @__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" : ""} ${isHovered ? "rounded-lg ring-4 ring-amber-400 shadow-[0_0_20px_rgba(245,158,11,0.6)]" : ""}`, 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: [
2562
- /* @__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" }),
2563
- /* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
2564
- ] }) }),
2300
+ /* @__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" : ""} ${isHovered ? "rounded-lg ring-4 ring-amber-400 shadow-[0_0_20px_rgba(245,158,11,0.6)]" : ""}`, children: /* @__PURE__ */ jsx(FolderGlyph, { className: "h-12 w-12 text-amber-500 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]" }) }),
2565
2301
  renamingFolder === folder.id ? /* @__PURE__ */ jsx(
2566
2302
  "input",
2567
2303
  {
@@ -2788,8 +2524,7 @@ function Desktop({ profile }) {
2788
2524
  ] }),
2789
2525
  contextMenu && contextMenu.itemIdx != null && /* @__PURE__ */ jsxs(PopupMenu, { style: menuStyle(contextMenu.x, contextMenu.y), minWidth: 160, children: [
2790
2526
  /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
2791
- const d = desktopItems[contextMenu.itemIdx];
2792
- d.entityType === "page" ? openPage(d.entityId) : openEntity(d.entityType, d.entityId, null, d.label);
2527
+ openItem(desktopItems[contextMenu.itemIdx]);
2793
2528
  setContextMenu(null);
2794
2529
  }, children: "Open" }),
2795
2530
  /* @__PURE__ */ jsx(PopupMenuDivider, {}),
@@ -2797,7 +2532,7 @@ function Desktop({ profile }) {
2797
2532
  ] }),
2798
2533
  contextMenu && contextMenu.folderIdx != null && /* @__PURE__ */ jsxs(PopupMenu, { style: menuStyle(contextMenu.x, contextMenu.y), minWidth: 160, children: [
2799
2534
  /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
2800
- setOpenFolder(folders[contextMenu.folderIdx].id);
2535
+ openDesktopFolder(folders[contextMenu.folderIdx].id);
2801
2536
  setContextMenu(null);
2802
2537
  }, children: "Open" }),
2803
2538
  /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
@@ -2808,68 +2543,6 @@ function Desktop({ profile }) {
2808
2543
  /* @__PURE__ */ jsx(PopupMenuDivider, {}),
2809
2544
  /* @__PURE__ */ jsx(PopupMenuItem, { danger: true, onClick: () => removeFolder(contextMenu.folderIdx), children: "Delete Folder" })
2810
2545
  ] }),
2811
- openFolder && (() => {
2812
- const folder = folders.find((f) => f.id === openFolder);
2813
- if (!folder) return null;
2814
- return /* @__PURE__ */ jsx(
2815
- FolderWindow,
2816
- {
2817
- folder,
2818
- items: folderItems(openFolder),
2819
- onClose: () => setOpenFolder(null),
2820
- onOpen: (item) => {
2821
- if (item.entityType === "preview-file" && item.filePath && item.fileKind) {
2822
- openPreviewFile({
2823
- filePath: item.filePath,
2824
- filename: item.label,
2825
- kind: item.fileKind,
2826
- onStaged: (route) => openPage(route)
2827
- });
2828
- } else {
2829
- openEntity(item.entityType, item.entityId, null, item.label);
2830
- }
2831
- },
2832
- onMoveOut: (toMove) => {
2833
- const ids = new Set(toMove.map((t) => `${t.entityType}|${t.entityId}`));
2834
- const updated = favDocs.map(
2835
- (d) => d.folderId === openFolder && ids.has(`${d.entityType}|${d.entityId}`) ? { ...d, folderId: void 0, folderX: void 0, folderY: void 0 } : d
2836
- );
2837
- saveDocs(updated);
2838
- },
2839
- onSetFolderPosition: (updates) => {
2840
- const patch = new Map(updates.map((u) => [`${u.item.entityType}|${u.item.entityId}`, u]));
2841
- const updated = favDocs.map((d) => {
2842
- const u = patch.get(`${d.entityType}|${d.entityId}`);
2843
- return u ? { ...d, folderX: u.x, folderY: u.y } : d;
2844
- });
2845
- saveDocs(updated);
2846
- },
2847
- onDragOutToDesktop: (drops) => {
2848
- const containerRect = containerRef.current?.getBoundingClientRect();
2849
- const cw = containerRef.current?.clientWidth ?? window.innerWidth;
2850
- const patch = /* @__PURE__ */ new Map();
2851
- for (const d of drops) {
2852
- const offX = containerRect ? d.clientX - containerRect.left : d.clientX;
2853
- const offY = containerRect ? d.clientY - containerRect.top : d.clientY;
2854
- let right = cw - offX - 40;
2855
- let top = Math.max(0, offY - 40);
2856
- if (snapEnabled) {
2857
- const s = snapToGrid(right, top);
2858
- right = s.x;
2859
- top = s.y;
2860
- }
2861
- right = Math.max(0, right);
2862
- patch.set(`${d.item.entityType}|${d.item.entityId}`, { right, top });
2863
- }
2864
- const updated = favDocs.map((d) => {
2865
- const p = patch.get(`${d.entityType}|${d.entityId}`);
2866
- return p ? { ...d, folderId: void 0, folderX: void 0, folderY: void 0, x: p.right, y: p.top } : d;
2867
- });
2868
- saveDocs(updated);
2869
- }
2870
- }
2871
- );
2872
- })(),
2873
2546
  /* @__PURE__ */ jsx(WidgetManager, { open: widgetsOpen, onClose: () => setWidgetsOpen(false) }),
2874
2547
  aboutOpen && (() => {
2875
2548
  const version = host.productVersion ?? APP_VERSION;
@@ -3704,28 +3377,6 @@ function subscribeMobileMode(cb) {
3704
3377
  var MOBILE_WIDGET_ORDER_KEY = "erp_mobile_widget_order";
3705
3378
  var MOBILE_HOME_ORDER_KEY = "erp_mobile_home_order";
3706
3379
  var LONG_PRESS_MS = 400;
3707
- var ICON_GRADIENTS = [
3708
- "from-blue-500 to-blue-700",
3709
- "from-indigo-500 to-purple-600",
3710
- "from-purple-500 to-pink-600",
3711
- "from-pink-500 to-rose-600",
3712
- "from-red-500 to-rose-600",
3713
- "from-orange-500 to-red-600",
3714
- "from-amber-500 to-orange-600",
3715
- "from-yellow-500 to-amber-500",
3716
- "from-lime-500 to-green-600",
3717
- "from-green-500 to-emerald-600",
3718
- "from-emerald-500 to-teal-600",
3719
- "from-teal-500 to-cyan-600",
3720
- "from-cyan-500 to-sky-600",
3721
- "from-sky-500 to-blue-600",
3722
- "from-violet-500 to-fuchsia-600"
3723
- ];
3724
- function hashGradient(seed) {
3725
- let h = 0;
3726
- for (let i = 0; i < seed.length; i++) h = (h << 5) - h + seed.charCodeAt(i);
3727
- return ICON_GRADIENTS[Math.abs(h) % ICON_GRADIENTS.length];
3728
- }
3729
3380
  function loadOrder(key) {
3730
3381
  try {
3731
3382
  const raw = localStorage.getItem(key);
@@ -4487,7 +4138,7 @@ function TaskbarPomodoro() {
4487
4138
  }
4488
4139
  );
4489
4140
  }
4490
- function TaskbarClock() {
4141
+ function TaskbarClock({ clockCalendar }) {
4491
4142
  const [now, setNow] = useState(/* @__PURE__ */ new Date());
4492
4143
  const [open, setOpen] = useState(false);
4493
4144
  const ref = useRef(null);
@@ -4510,12 +4161,16 @@ function TaskbarClock() {
4510
4161
  const rect = buttonRef.current?.getBoundingClientRect();
4511
4162
  const right = rect ? Math.max(8, window.innerWidth - rect.right) : 8;
4512
4163
  const posStyle = taskbarPos === "top" ? { right, top: (rect?.bottom ?? 0) + 4 } : { right, bottom: window.innerHeight - (rect?.top ?? 0) + 4 };
4513
- return /* @__PURE__ */ jsx("div", { className: "fixed z-[300] rounded-lg border border-gray-200 bg-white shadow-xl", style: posStyle, children: /* @__PURE__ */ jsx(CalendarPopup, { now }) });
4164
+ return /* @__PURE__ */ jsx("div", { className: "fixed z-[300] rounded-lg border border-gray-200 bg-white shadow-xl", style: posStyle, children: /* @__PURE__ */ jsx(CalendarPopup, { now, config: clockCalendar, close: () => setOpen(false) }) });
4514
4165
  })()
4515
4166
  ] });
4516
4167
  }
4517
- function CalendarPopup({ now }) {
4168
+ var toISODate = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
4169
+ function CalendarPopup({ now, config, close }) {
4518
4170
  const [month, setMonth] = useState(() => new Date(now.getFullYear(), now.getMonth(), 1));
4171
+ const [selected, setSelected] = useState(() => toISODate(now));
4172
+ const interactive = !!config?.renderDay;
4173
+ const markedSet = useMemo(() => new Set(config?.markedDates ?? []), [config?.markedDates]);
4519
4174
  const monthLabel = month.toLocaleDateString(void 0, { month: "long", year: "numeric" });
4520
4175
  const fullDate = now.toLocaleDateString(void 0, { weekday: "long", month: "long", day: "numeric" });
4521
4176
  const fullTime = now.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
@@ -4540,7 +4195,7 @@ function CalendarPopup({ now }) {
4540
4195
  const goPrev = () => setMonth((m) => new Date(m.getFullYear(), m.getMonth() - 1, 1));
4541
4196
  const goNext = () => setMonth((m) => new Date(m.getFullYear(), m.getMonth() + 1, 1));
4542
4197
  const goToday = () => setMonth(new Date(today.getFullYear(), today.getMonth(), 1));
4543
- return /* @__PURE__ */ jsxs("div", { className: "w-[260px] p-3", children: [
4198
+ return /* @__PURE__ */ jsxs("div", { className: `${interactive ? "w-[300px]" : "w-[260px]"} p-3`, children: [
4544
4199
  /* @__PURE__ */ jsxs("div", { className: "px-1 pb-2.5 border-b border-gray-100", children: [
4545
4200
  /* @__PURE__ */ jsx("div", { className: "text-[11px] font-semibold text-gray-500 uppercase tracking-wide", children: fullDate }),
4546
4201
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-semibold text-gray-800 tabular-nums leading-tight mt-0.5", children: fullTime })
@@ -4553,15 +4208,41 @@ function CalendarPopup({ now }) {
4553
4208
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 mb-1 text-[10px] font-semibold text-gray-400 text-center uppercase tracking-wide", children: ["S", "M", "T", "W", "T", "F", "S"].map((d, i) => /* @__PURE__ */ jsx("div", { className: "py-1", children: d }, i)) }),
4554
4209
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-px text-center", children: cells.map((cell, i) => {
4555
4210
  const todayCell = cell.thisMonth && isToday(cell.date);
4556
- return /* @__PURE__ */ jsx(
4557
- "div",
4211
+ const iso = toISODate(cell.date);
4212
+ const isSelected = interactive && selected === iso;
4213
+ const look = isSelected ? "bg-blue-500 text-white font-semibold" : todayCell ? interactive ? "text-blue-600 font-bold hover:bg-gray-100" : "bg-blue-500 text-white font-semibold" : cell.thisMonth ? "text-gray-700 hover:bg-gray-100" : interactive ? "text-gray-300 hover:bg-gray-100" : "text-gray-300";
4214
+ const dayClass = `relative text-[12px] py-1.5 rounded-md transition-colors ${look}`;
4215
+ const dot = markedSet.has(iso) && /* @__PURE__ */ jsx(
4216
+ "span",
4558
4217
  {
4559
- className: `text-[12px] py-1.5 rounded-md transition-colors ${todayCell ? "bg-blue-500 text-white font-semibold" : cell.thisMonth ? "text-gray-700 hover:bg-gray-100" : "text-gray-300"}`,
4560
- children: cell.day
4218
+ className: `absolute bottom-[3px] left-1/2 -translate-x-1/2 h-1 w-1 rounded-full ${isSelected ? "bg-white" : cell.thisMonth ? "bg-blue-500" : "bg-gray-300"}`
4219
+ }
4220
+ );
4221
+ if (!interactive) {
4222
+ return /* @__PURE__ */ jsxs("div", { className: dayClass, children: [
4223
+ cell.day,
4224
+ dot
4225
+ ] }, i);
4226
+ }
4227
+ return /* @__PURE__ */ jsxs(
4228
+ "button",
4229
+ {
4230
+ onClick: () => {
4231
+ setSelected(iso);
4232
+ if (!cell.thisMonth) setMonth(new Date(cell.date.getFullYear(), cell.date.getMonth(), 1));
4233
+ },
4234
+ "aria-label": cell.date.toLocaleDateString(void 0, { weekday: "long", year: "numeric", month: "long", day: "numeric" }),
4235
+ "aria-pressed": isSelected,
4236
+ className: `cursor-pointer ${dayClass}`,
4237
+ children: [
4238
+ cell.day,
4239
+ dot
4240
+ ]
4561
4241
  },
4562
4242
  i
4563
4243
  );
4564
- }) })
4244
+ }) }),
4245
+ config?.renderDay && /* @__PURE__ */ jsx("div", { className: "mt-2.5 max-h-[280px] overflow-y-auto border-t border-gray-100 pt-2", children: config.renderDay(selected, { close }) }, selected)
4565
4246
  ] });
4566
4247
  }
4567
4248
  function TaskbarContextMenu({ x, y, position, size, onChangePosition, onChangeSize, onClose, onReportBug }) {
@@ -4629,7 +4310,8 @@ function Layout({
4629
4310
  categories = startMenuCategories,
4630
4311
  notifications,
4631
4312
  search,
4632
- taskbarTrayLeft
4313
+ taskbarTrayLeft,
4314
+ clockCalendar
4633
4315
  } = {}) {
4634
4316
  const bugReport = useBugReport();
4635
4317
  const { user, logout, hasAnyPerm } = useAuth();
@@ -4953,7 +4635,7 @@ function Layout({
4953
4635
  isVerticalTaskbar ? (
4954
4636
  /* Vertical: clock + bell evenly spaced */
4955
4637
  /* @__PURE__ */ jsx("div", { className: "w-full px-2", children: /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-center gap-2 ${taskbarPosition === "right" ? "flex-row-reverse" : ""}`, children: [
4956
- /* @__PURE__ */ jsx(TaskbarClock, {}),
4638
+ /* @__PURE__ */ jsx(TaskbarClock, { clockCalendar }),
4957
4639
  /* @__PURE__ */ jsx(TaskbarPomodoro, {}),
4958
4640
  taskbarTrayLeft,
4959
4641
  notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications, popDirection: taskbarPosition === "right" ? "left" : "right" })
@@ -4964,7 +4646,7 @@ function Layout({
4964
4646
  /* @__PURE__ */ jsx(TaskbarPomodoro, {}),
4965
4647
  taskbarTrayLeft,
4966
4648
  notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications }),
4967
- /* @__PURE__ */ jsx(TaskbarClock, {})
4649
+ /* @__PURE__ */ jsx(TaskbarClock, { clockCalendar })
4968
4650
  ] })
4969
4651
  )
4970
4652
  ]