react-os-shell 0.1.63 → 0.2.2

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 (41) hide show
  1. package/dist/{Browser-DJL2TT56.js → Browser-IAQ5N3LL.js} +3 -3
  2. package/dist/{Browser-DJL2TT56.js.map → Browser-IAQ5N3LL.js.map} +1 -1
  3. package/dist/{Calculator-CIAX4UDE.js → Calculator-7MIONNJK.js} +4 -4
  4. package/dist/{Calculator-CIAX4UDE.js.map → Calculator-7MIONNJK.js.map} +1 -1
  5. package/dist/{Calendar-LMKNYJ7J.js → Calendar-2R2DWXTG.js} +3 -3
  6. package/dist/{Calendar-LMKNYJ7J.js.map → Calendar-2R2DWXTG.js.map} +1 -1
  7. package/dist/{CurrencyConverter-QSMM26HX.js → CurrencyConverter-BMTB7FLA.js} +4 -4
  8. package/dist/{CurrencyConverter-QSMM26HX.js.map → CurrencyConverter-BMTB7FLA.js.map} +1 -1
  9. package/dist/{Documents-OCP3FEKB.js → Documents-CBNJAM3Q.js} +3 -3
  10. package/dist/{Documents-OCP3FEKB.js.map → Documents-CBNJAM3Q.js.map} +1 -1
  11. package/dist/{Email-E7FTMUDO.js → Email-BS6MESSZ.js} +3 -3
  12. package/dist/{Email-E7FTMUDO.js.map → Email-BS6MESSZ.js.map} +1 -1
  13. package/dist/Files-U3BSTCC3.js +7 -0
  14. package/dist/{Files-BYZQMLJJ.js.map → Files-U3BSTCC3.js.map} +1 -1
  15. package/dist/{Minesweeper-YUQVBS2S.js → Minesweeper-XOSH6BW2.js} +3 -3
  16. package/dist/{Minesweeper-YUQVBS2S.js.map → Minesweeper-XOSH6BW2.js.map} +1 -1
  17. package/dist/{Notepad-MJRVAKGR.js → Notepad-DMSBGGMS.js} +3 -3
  18. package/dist/{Notepad-MJRVAKGR.js.map → Notepad-DMSBGGMS.js.map} +1 -1
  19. package/dist/{PomodoroTimer-P5PLQAO7.js → PomodoroTimer-3XLLIDV3.js} +4 -4
  20. package/dist/{PomodoroTimer-P5PLQAO7.js.map → PomodoroTimer-3XLLIDV3.js.map} +1 -1
  21. package/dist/Preview-Y2LMO2DL.js +6 -0
  22. package/dist/{Preview-R2V2HL6V.js.map → Preview-Y2LMO2DL.js.map} +1 -1
  23. package/dist/{Spreadsheet-KL2TS6GG.js → Spreadsheet-IRPGCABR.js} +3 -3
  24. package/dist/{Spreadsheet-KL2TS6GG.js.map → Spreadsheet-IRPGCABR.js.map} +1 -1
  25. package/dist/{Weather-WPMGZ2QY.js → Weather-5IW43PAQ.js} +4 -4
  26. package/dist/{Weather-WPMGZ2QY.js.map → Weather-5IW43PAQ.js.map} +1 -1
  27. package/dist/apps/index.js +16 -16
  28. package/dist/{chunk-GBQOM343.js → chunk-7P6DO3NC.js} +126 -10
  29. package/dist/chunk-7P6DO3NC.js.map +1 -0
  30. package/dist/{chunk-AVP2E5H5.js → chunk-DIJ46HNS.js} +3 -3
  31. package/dist/{chunk-AVP2E5H5.js.map → chunk-DIJ46HNS.js.map} +1 -1
  32. package/dist/{chunk-7S2XQTV7.js → chunk-IQV6QQBQ.js} +3 -3
  33. package/dist/{chunk-7S2XQTV7.js.map → chunk-IQV6QQBQ.js.map} +1 -1
  34. package/dist/{chunk-RZUFEZWB.js → chunk-JEJHECSO.js} +4 -4
  35. package/dist/{chunk-RZUFEZWB.js.map → chunk-JEJHECSO.js.map} +1 -1
  36. package/dist/index.js +1052 -155
  37. package/dist/index.js.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/Files-BYZQMLJJ.js +0 -7
  40. package/dist/Preview-R2V2HL6V.js +0 -6
  41. package/dist/chunk-GBQOM343.js.map +0 -1
package/dist/index.js CHANGED
@@ -4,14 +4,14 @@ export { formatDate } from './chunk-NSU7OHPC.js';
4
4
  import { useGoogleAuth } from './chunk-46LICZUM.js';
5
5
  import { useShellPrefs } from './chunk-36VM54SC.js';
6
6
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
7
- import { playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
8
- import { setPdfPreview } from './chunk-7S2XQTV7.js';
7
+ import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
8
+ import { setPdfPreview } from './chunk-IQV6QQBQ.js';
9
9
  import { toast_default } from './chunk-WIJ45SYD.js';
10
10
  export { toast_default as toast } from './chunk-WIJ45SYD.js';
11
- import { useWindowManager, glassStyle, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons, ModalActions, useModalActive } from './chunk-GBQOM343.js';
12
- export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, glassStyle, isEntityEntry, isPageEntry, setShellApiClient, setShellNavIcons, setShellWindowRegistry, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-GBQOM343.js';
11
+ import { useWindowManager, glassStyle, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, startMenuCategories, useIsMobile, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons, ModalActions, useModalActive, subscribeMobileMode, getMobileMode, WINDOW_REGISTRY, isPageEntry, setMobileMode, LoadingSpinner, ThumbCard, activateModal } from './chunk-7P6DO3NC.js';
12
+ export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, glassStyle, isEntityEntry, isPageEntry, setShellApiClient, setShellNavIcons, setShellWindowRegistry, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-7P6DO3NC.js';
13
13
  export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-PLGHQ7QW.js';
14
- import { createContext, useState, useRef, useEffect, useCallback, useLayoutEffect, useContext, isValidElement, cloneElement, useSyncExternalStore } from 'react';
14
+ import { createContext, useState, useRef, useEffect, useCallback, useLayoutEffect, useContext, isValidElement, cloneElement, useSyncExternalStore, useMemo, Suspense } from 'react';
15
15
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
16
16
  import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react';
17
17
  import { createPortal } from 'react-dom';
@@ -274,6 +274,39 @@ function NotificationBell({
274
274
  useEffect(() => {
275
275
  if ("Notification" in window && Notification.permission === "default") Notification.requestPermission();
276
276
  }, []);
277
+ const handleClick = useCallback((notif) => {
278
+ if (!notif.is_read) {
279
+ queryClient.setQueryData(["notification-unread-count"], (old) => old ? { ...old, count: Math.max(0, (old.count || 0) - 1) } : old);
280
+ queryClient.setQueryData(["notifications-dropdown"], (old) => {
281
+ if (!old?.results) return old;
282
+ return { ...old, results: old.results.map((n) => n.id === notif.id ? { ...n, is_read: true } : n) };
283
+ });
284
+ markRead(notif.id).catch(() => {
285
+ queryClient.invalidateQueries({ queryKey: ["notification-unread-count"] });
286
+ queryClient.invalidateQueries({ queryKey: ["notifications-dropdown"] });
287
+ });
288
+ }
289
+ setOpen(false);
290
+ onItemClick(notif);
291
+ }, [queryClient, markRead, onItemClick]);
292
+ const [inlineNotif, setInlineNotif] = useState(null);
293
+ const inlineTimerRef = useRef(null);
294
+ const dismissInline = useCallback(() => {
295
+ if (inlineTimerRef.current) {
296
+ clearTimeout(inlineTimerRef.current);
297
+ inlineTimerRef.current = null;
298
+ }
299
+ setInlineNotif(null);
300
+ }, []);
301
+ const showInlineNotif = useCallback((notif, durationMs = 5e3) => {
302
+ setInlineNotif(notif);
303
+ playNotification();
304
+ if (inlineTimerRef.current) clearTimeout(inlineTimerRef.current);
305
+ inlineTimerRef.current = setTimeout(() => setInlineNotif(null), durationMs);
306
+ }, []);
307
+ useEffect(() => () => {
308
+ if (inlineTimerRef.current) clearTimeout(inlineTimerRef.current);
309
+ }, []);
277
310
  const prevCountRef = useRef(null);
278
311
  useEffect(() => {
279
312
  if (prevCountRef.current === null) {
@@ -291,18 +324,18 @@ function NotificationBell({
291
324
  const n = new Notification(title, { body, icon: "/favicon.svg", tag: `notif-${latest.id}` });
292
325
  n.onclick = () => {
293
326
  window.focus();
294
- onItemClick(latest);
327
+ handleClick(latest);
295
328
  n.close();
296
329
  };
297
330
  }
298
331
  } else {
299
- toast_default.info(title, { duration: 5e3 });
332
+ showInlineNotif(latest);
300
333
  }
301
334
  }).catch(() => {
302
335
  });
303
336
  }
304
337
  prevCountRef.current = unreadCount;
305
- }, [unreadCount, list, onItemClick]);
338
+ }, [unreadCount, list, showInlineNotif]);
306
339
  const { data: notifData } = useQuery({
307
340
  queryKey: ["notifications-dropdown"],
308
341
  queryFn: () => list({ page_size: 30 }),
@@ -310,21 +343,6 @@ function NotificationBell({
310
343
  refetchInterval: 3e4
311
344
  });
312
345
  const notifications = notifData?.results ?? [];
313
- const handleClick = (notif) => {
314
- if (!notif.is_read) {
315
- queryClient.setQueryData(["notification-unread-count"], (old) => old ? { ...old, count: Math.max(0, (old.count || 0) - 1) } : old);
316
- queryClient.setQueryData(["notifications-dropdown"], (old) => {
317
- if (!old?.results) return old;
318
- return { ...old, results: old.results.map((n) => n.id === notif.id ? { ...n, is_read: true } : n) };
319
- });
320
- markRead(notif.id).catch(() => {
321
- queryClient.invalidateQueries({ queryKey: ["notification-unread-count"] });
322
- queryClient.invalidateQueries({ queryKey: ["notifications-dropdown"] });
323
- });
324
- }
325
- setOpen(false);
326
- onItemClick(notif);
327
- };
328
346
  const handleMarkAllRead = () => {
329
347
  queryClient.setQueryData(["notification-unread-count"], (old) => old ? { ...old, count: 0 } : old);
330
348
  queryClient.setQueryData(["notifications-dropdown"], (old) => {
@@ -407,6 +425,43 @@ function NotificationBell({
407
425
  ] })
408
426
  ] }),
409
427
  document.body
428
+ ),
429
+ inlineNotif && createPortal(
430
+ /* @__PURE__ */ jsxs(Fragment, { children: [
431
+ /* @__PURE__ */ jsx("style", { children: `@keyframes notif-in { from { opacity: 0; transform: translateX(30px) scale(0.95); } to { opacity: 1; transform: translateX(0) scale(1); } }` }),
432
+ /* @__PURE__ */ jsxs(
433
+ "div",
434
+ {
435
+ onClick: () => {
436
+ handleClick(inlineNotif);
437
+ dismissInline();
438
+ },
439
+ className: "fixed top-4 right-4 z-[9999] w-[320px] max-w-[calc(100vw-2rem)] cursor-pointer rounded-2xl bg-white/85 backdrop-blur-md border border-white/40 shadow-2xl flex items-start gap-3 px-4 py-3",
440
+ style: { animation: "notif-in 300ms cubic-bezier(0.4,0,0.2,1)" },
441
+ children: [
442
+ /* @__PURE__ */ jsx("div", { className: "h-9 w-9 shrink-0 rounded-lg bg-blue-500/15 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5 text-blue-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, 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" }) }) }),
443
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
444
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] font-semibold uppercase tracking-wide text-blue-600 mb-0.5", children: "Notification" }),
445
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-800 leading-snug truncate", children: inlineNotif.title }),
446
+ inlineNotif.message && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 leading-snug truncate mt-0.5", children: inlineNotif.message })
447
+ ] }),
448
+ /* @__PURE__ */ jsx(
449
+ "button",
450
+ {
451
+ onClick: (e) => {
452
+ e.stopPropagation();
453
+ dismissInline();
454
+ },
455
+ className: "shrink-0 p-1 -mr-1 -mt-1 text-gray-400 hover:text-gray-600 transition-colors",
456
+ "aria-label": "Dismiss notification",
457
+ children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) })
458
+ }
459
+ )
460
+ ]
461
+ }
462
+ )
463
+ ] }),
464
+ document.body
410
465
  )
411
466
  ] });
412
467
  }
@@ -651,7 +706,7 @@ function StatusBadge({ status }) {
651
706
  }
652
707
 
653
708
  // src/version.ts
654
- var VERSION = "0.1.63" ;
709
+ var VERSION = "0.2.1" ;
655
710
  var APP_VERSION = VERSION;
656
711
 
657
712
  // src/changelog.ts
@@ -2395,6 +2450,7 @@ function StartMenu({
2395
2450
  virtualSections.map((v) => [v.label, v])
2396
2451
  );
2397
2452
  const { hasAnyPerm } = useAuth();
2453
+ const isMobile = useIsMobile();
2398
2454
  const [hoveredSection, setHoveredSection] = useState(null);
2399
2455
  const [hoveredY, setHoveredY] = useState(0);
2400
2456
  const [search, setSearch] = useState("");
@@ -2429,6 +2485,68 @@ function StartMenu({
2429
2485
  openPage(path);
2430
2486
  onClose();
2431
2487
  };
2488
+ if (isMobile) {
2489
+ const allItems = [];
2490
+ for (const entry of navSections2) {
2491
+ if (isSection(entry)) {
2492
+ const sec = entry;
2493
+ if (sec.perms && !hasAnyPerm(sec.perms)) continue;
2494
+ for (const it of sec.items) {
2495
+ if (it.perms && !hasAnyPerm(it.perms)) continue;
2496
+ allItems.push({ item: it, sectionLabel: sec.label });
2497
+ }
2498
+ } else {
2499
+ const it = entry;
2500
+ if (it.perms && !hasAnyPerm(it.perms)) continue;
2501
+ allItems.push({ item: it });
2502
+ }
2503
+ }
2504
+ const filtered = search.length >= 1 ? allItems.filter(({ item }) => item.label.toLowerCase().includes(search.toLowerCase())) : allItems;
2505
+ return /* @__PURE__ */ jsxs(
2506
+ "div",
2507
+ {
2508
+ ref: menuRef,
2509
+ className: "fixed inset-0 z-[260] flex flex-col bg-white",
2510
+ style: { paddingBottom: "var(--mobile-bottom-nav, 56px)" },
2511
+ children: [
2512
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-gray-200", children: [
2513
+ /* @__PURE__ */ jsx("button", { onClick: onClose, className: "p-2 -ml-1 rounded-full active:bg-gray-200 text-gray-700", "aria-label": "Close menu", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }),
2514
+ /* @__PURE__ */ jsxs("div", { className: `flex-1 flex items-center gap-2 ${GLASS_INPUT_BG} rounded-lg px-3 py-2`, children: [
2515
+ /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 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" }) }),
2516
+ /* @__PURE__ */ jsx(
2517
+ "input",
2518
+ {
2519
+ value: search,
2520
+ onChange: (e) => setSearch(e.target.value),
2521
+ placeholder: "Search apps...",
2522
+ className: "flex-1 bg-transparent text-sm outline-none placeholder-gray-400",
2523
+ autoFocus: true
2524
+ }
2525
+ )
2526
+ ] })
2527
+ ] }),
2528
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-400 text-center py-12", children: "No matching apps" }) : filtered.map(({ item, sectionLabel }, i) => {
2529
+ const icon = navIcons2[item.to];
2530
+ return /* @__PURE__ */ jsxs(
2531
+ "button",
2532
+ {
2533
+ onClick: () => handleClick(item.to),
2534
+ className: "w-full flex items-center gap-3 px-4 py-3 active:bg-gray-100 border-b border-gray-100 text-left",
2535
+ children: [
2536
+ /* @__PURE__ */ jsx("span", { className: "h-8 w-8 rounded-lg bg-gray-100 flex items-center justify-center text-gray-600 shrink-0", children: icon && isValidElement(icon) ? cloneElement(icon, { className: "h-5 w-5" }) : null }),
2537
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2538
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: item.label }),
2539
+ sectionLabel && /* @__PURE__ */ jsx("div", { className: "text-[11px] text-gray-500 truncate", children: sectionLabel })
2540
+ ] })
2541
+ ]
2542
+ },
2543
+ `${item.to}-${i}`
2544
+ );
2545
+ }) })
2546
+ ]
2547
+ }
2548
+ );
2549
+ }
2432
2550
  const isVertical = taskbarPosition !== "bottom";
2433
2551
  const topItems = navSections2.filter((item) => !isSection(item));
2434
2552
  const erpSections = navSections2.filter((item) => isSection(item) && erpLabels.has(item.label));
@@ -2673,6 +2791,758 @@ function StartMenu({
2673
2791
  ` })
2674
2792
  ] });
2675
2793
  }
2794
+ var MOBILE_WIDGET_ORDER_KEY = "erp_mobile_widget_order";
2795
+ var MOBILE_HOME_ORDER_KEY = "erp_mobile_home_order";
2796
+ var LONG_PRESS_MS = 400;
2797
+ var ICON_GRADIENTS = [
2798
+ "from-blue-500 to-blue-700",
2799
+ "from-indigo-500 to-purple-600",
2800
+ "from-purple-500 to-pink-600",
2801
+ "from-pink-500 to-rose-600",
2802
+ "from-red-500 to-rose-600",
2803
+ "from-orange-500 to-red-600",
2804
+ "from-amber-500 to-orange-600",
2805
+ "from-yellow-500 to-amber-500",
2806
+ "from-lime-500 to-green-600",
2807
+ "from-green-500 to-emerald-600",
2808
+ "from-emerald-500 to-teal-600",
2809
+ "from-teal-500 to-cyan-600",
2810
+ "from-cyan-500 to-sky-600",
2811
+ "from-sky-500 to-blue-600",
2812
+ "from-violet-500 to-fuchsia-600"
2813
+ ];
2814
+ function hashGradient(seed) {
2815
+ let h = 0;
2816
+ for (let i = 0; i < seed.length; i++) h = (h << 5) - h + seed.charCodeAt(i);
2817
+ return ICON_GRADIENTS[Math.abs(h) % ICON_GRADIENTS.length];
2818
+ }
2819
+ function loadOrder(key) {
2820
+ try {
2821
+ const raw = localStorage.getItem(key);
2822
+ if (raw) {
2823
+ const parsed = JSON.parse(raw);
2824
+ if (Array.isArray(parsed)) return parsed.filter((s) => typeof s === "string");
2825
+ }
2826
+ } catch {
2827
+ }
2828
+ return [];
2829
+ }
2830
+ function saveOrder(key, order) {
2831
+ try {
2832
+ localStorage.setItem(key, JSON.stringify(order));
2833
+ } catch {
2834
+ }
2835
+ }
2836
+ var FALLBACK_APP_ICON = /* @__PURE__ */ jsx("svg", { className: "h-10 w-10", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("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" }) });
2837
+ function sizeIcon(node, fallback, sizeClass = "h-10 w-10") {
2838
+ if (!node) return fallback;
2839
+ if (isValidElement(node)) {
2840
+ return cloneElement(node, {
2841
+ className: `${sizeClass} ${node.props?.className ?? ""}`.trim()
2842
+ });
2843
+ }
2844
+ return node;
2845
+ }
2846
+ function AppTile({ route, icon, badge }) {
2847
+ return /* @__PURE__ */ jsxs("span", { className: `relative aspect-square w-full max-w-[80px] mx-auto rounded-2xl bg-gradient-to-br ${hashGradient(route)} flex items-center justify-center text-white shadow-sm border border-white/30`, children: [
2848
+ sizeIcon(icon, FALLBACK_APP_ICON, "h-11 w-11"),
2849
+ badge && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 h-2.5 w-2.5 rounded-full bg-blue-400 border-2 border-white" })
2850
+ ] });
2851
+ }
2852
+ function FolderTile({ section, navIcons: navIcons2, badge }) {
2853
+ const previewItems = section.items.slice(0, 4);
2854
+ return /* @__PURE__ */ jsxs("span", { className: "relative aspect-square w-full max-w-[80px] mx-auto rounded-2xl bg-white/30 backdrop-blur-sm border border-white/40 p-1.5 grid grid-cols-2 gap-1 shadow-sm", children: [
2855
+ previewItems.map((item) => /* @__PURE__ */ jsx(
2856
+ "span",
2857
+ {
2858
+ className: `rounded-md bg-gradient-to-br ${hashGradient(item.to)} flex items-center justify-center text-white`,
2859
+ children: sizeIcon(navIcons2[item.to], FALLBACK_APP_ICON, "h-3.5 w-3.5")
2860
+ },
2861
+ item.to
2862
+ )),
2863
+ Array.from({ length: Math.max(0, 4 - previewItems.length) }).map((_, i) => /* @__PURE__ */ jsx("span", { className: "rounded-md bg-white/20" }, `empty-${i}`)),
2864
+ badge !== void 0 && badge > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 min-w-[18px] h-[18px] px-1 rounded-full bg-blue-500 text-white text-[10px] font-bold leading-[18px] text-center border-2 border-white", children: badge })
2865
+ ] });
2866
+ }
2867
+ function MobileHome({
2868
+ navSections: navSections2,
2869
+ navIcons: navIcons2,
2870
+ sectionIcons: sectionIcons2,
2871
+ openWindows,
2872
+ onOpenApp,
2873
+ onActivateWindow
2874
+ }) {
2875
+ const [selectedFolder, setSelectedFolder] = useState(null);
2876
+ const homeIconsRaw = useMemo(() => {
2877
+ const list = [];
2878
+ for (const entry of navSections2) {
2879
+ if (isSection(entry)) {
2880
+ const sec = entry;
2881
+ list.push({ kind: "folder", id: `folder:${sec.label}`, label: sec.label, section: sec });
2882
+ } else {
2883
+ const it = entry;
2884
+ list.push({ kind: "app", id: `app:${it.to}`, label: it.label, route: it.to });
2885
+ }
2886
+ }
2887
+ return list;
2888
+ }, [navSections2]);
2889
+ const [homeOrder, setHomeOrder] = useState(() => loadOrder(MOBILE_HOME_ORDER_KEY));
2890
+ const homeIcons = useMemo(() => {
2891
+ const indexFor = (id) => {
2892
+ const i = homeOrder.indexOf(id);
2893
+ return i === -1 ? Number.MAX_SAFE_INTEGER : i;
2894
+ };
2895
+ return homeIconsRaw.slice().sort((a, b) => {
2896
+ const ia = indexFor(a.id);
2897
+ const ib = indexFor(b.id);
2898
+ if (ia !== ib) return ia - ib;
2899
+ return homeIconsRaw.indexOf(a) - homeIconsRaw.indexOf(b);
2900
+ });
2901
+ }, [homeIconsRaw, homeOrder]);
2902
+ useEffect(() => {
2903
+ const visibleIds = homeIconsRaw.map((i) => i.id);
2904
+ const next = [
2905
+ ...homeOrder.filter((id) => visibleIds.includes(id)),
2906
+ ...visibleIds.filter((id) => !homeOrder.includes(id))
2907
+ ];
2908
+ if (next.length !== homeOrder.length || next.some((id, i) => id !== homeOrder[i])) {
2909
+ setHomeOrder(next);
2910
+ saveOrder(MOBILE_HOME_ORDER_KEY, next);
2911
+ }
2912
+ }, [homeIconsRaw, homeOrder]);
2913
+ const [dragId, setDragId] = useState(null);
2914
+ const [dragPos, setDragPos] = useState(null);
2915
+ const dragOffsetRef = useRef({ x: 0, y: 0 });
2916
+ const longPressTimerRef = useRef(null);
2917
+ const longPressFiredRef = useRef(false);
2918
+ const cancelLongPress = () => {
2919
+ if (longPressTimerRef.current) {
2920
+ clearTimeout(longPressTimerRef.current);
2921
+ longPressTimerRef.current = null;
2922
+ }
2923
+ };
2924
+ const beginLongPress = (id, e) => {
2925
+ if (dragId) return;
2926
+ const x = e.clientX;
2927
+ const y = e.clientY;
2928
+ const target = e.currentTarget;
2929
+ longPressFiredRef.current = false;
2930
+ cancelLongPress();
2931
+ longPressTimerRef.current = setTimeout(() => {
2932
+ if (!target.isConnected) return;
2933
+ const rect = target.getBoundingClientRect();
2934
+ dragOffsetRef.current = { x: x - rect.left, y: y - rect.top };
2935
+ longPressFiredRef.current = true;
2936
+ setDragId(id);
2937
+ setDragPos({ x, y });
2938
+ try {
2939
+ navigator.vibrate?.(15);
2940
+ } catch {
2941
+ }
2942
+ }, LONG_PRESS_MS);
2943
+ };
2944
+ useEffect(() => {
2945
+ if (!dragId) return;
2946
+ const onMove = (e) => {
2947
+ setDragPos({ x: e.clientX, y: e.clientY });
2948
+ const el = document.elementFromPoint(e.clientX, e.clientY);
2949
+ const targetEl = el?.closest("[data-home-icon-id]");
2950
+ if (!targetEl) return;
2951
+ const targetId = targetEl.dataset.homeIconId;
2952
+ if (targetId === dragId) return;
2953
+ setHomeOrder((prev) => {
2954
+ const fromIdx = prev.indexOf(dragId);
2955
+ const toIdx = prev.indexOf(targetId);
2956
+ if (fromIdx === -1 || toIdx === -1) return prev;
2957
+ const next = prev.slice();
2958
+ next.splice(fromIdx, 1);
2959
+ next.splice(toIdx, 0, dragId);
2960
+ return next;
2961
+ });
2962
+ };
2963
+ const onUp = () => {
2964
+ setDragId(null);
2965
+ setDragPos(null);
2966
+ setHomeOrder((prev) => {
2967
+ saveOrder(MOBILE_HOME_ORDER_KEY, prev);
2968
+ return prev;
2969
+ });
2970
+ };
2971
+ window.addEventListener("pointermove", onMove);
2972
+ window.addEventListener("pointerup", onUp);
2973
+ window.addEventListener("pointercancel", onUp);
2974
+ return () => {
2975
+ window.removeEventListener("pointermove", onMove);
2976
+ window.removeEventListener("pointerup", onUp);
2977
+ window.removeEventListener("pointercancel", onUp);
2978
+ };
2979
+ }, [dragId]);
2980
+ const handleIconClick = (icon) => {
2981
+ if (longPressFiredRef.current) {
2982
+ longPressFiredRef.current = false;
2983
+ return;
2984
+ }
2985
+ if (icon.kind === "app") onOpenApp(icon.route);
2986
+ else setSelectedFolder(icon.section);
2987
+ };
2988
+ const [widgetOrder, _setWidgetOrder] = useState(() => loadOrder(MOBILE_WIDGET_ORDER_KEY));
2989
+ const widgetWindows = useMemo(() => {
2990
+ const widgets = openWindows.filter((w) => {
2991
+ if (!w.route) return false;
2992
+ const entry = WINDOW_REGISTRY[w.route];
2993
+ return entry && isPageEntry(entry) && entry.widget;
2994
+ });
2995
+ const indexFor = (route) => {
2996
+ const i = widgetOrder.indexOf(route);
2997
+ return i === -1 ? Number.MAX_SAFE_INTEGER : i;
2998
+ };
2999
+ return widgets.slice().sort((a, b) => indexFor(a.route) - indexFor(b.route));
3000
+ }, [openWindows, widgetOrder]);
3001
+ useEffect(() => {
3002
+ const visibleRoutes = widgetWindows.map((w) => w.route).filter(Boolean);
3003
+ const next = [
3004
+ ...widgetOrder.filter((r) => visibleRoutes.includes(r)),
3005
+ ...visibleRoutes.filter((r) => !widgetOrder.includes(r))
3006
+ ];
3007
+ if (next.length !== widgetOrder.length || next.some((r, i) => r !== widgetOrder[i])) {
3008
+ _setWidgetOrder(next);
3009
+ saveOrder(MOBILE_WIDGET_ORDER_KEY, next);
3010
+ }
3011
+ }, [widgetWindows, widgetOrder]);
3012
+ const openCountByRoute = useMemo(() => {
3013
+ const map = /* @__PURE__ */ new Map();
3014
+ for (const w of openWindows) {
3015
+ if (!w.route) continue;
3016
+ map.set(w.route, (map.get(w.route) ?? 0) + 1);
3017
+ }
3018
+ return map;
3019
+ }, [openWindows]);
3020
+ const openInFolder = (folder) => {
3021
+ const routes = new Set(folder.items.map((i) => i.to));
3022
+ return openWindows.filter((w) => w.route && routes.has(w.route));
3023
+ };
3024
+ const draggedIcon = dragId ? homeIcons.find((i) => i.id === dragId) : null;
3025
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3026
+ /* @__PURE__ */ jsxs(
3027
+ "div",
3028
+ {
3029
+ className: "h-full overflow-y-auto px-3 pt-4 pb-4 select-none",
3030
+ style: {
3031
+ // Disable iOS long-press text-selection / "Copy" callout on icon labels.
3032
+ WebkitUserSelect: "none",
3033
+ WebkitTouchCallout: "none"
3034
+ },
3035
+ children: [
3036
+ widgetWindows.length > 0 && /* @__PURE__ */ jsx("section", { className: "mb-4", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-6", children: widgetWindows.map((w) => {
3037
+ const entry = WINDOW_REGISTRY[w.route];
3038
+ if (!entry) return null;
3039
+ const Component = entry.component;
3040
+ return /* @__PURE__ */ jsx(
3041
+ "div",
3042
+ {
3043
+ className: "relative rounded-2xl bg-white/85 backdrop-blur border border-white/40 shadow-md overflow-hidden aspect-square",
3044
+ children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }), children: /* @__PURE__ */ jsx(Component, {}) })
3045
+ },
3046
+ w.id
3047
+ );
3048
+ }) }) }),
3049
+ homeIcons.length > 0 && /* @__PURE__ */ jsx("section", { children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-3", children: homeIcons.map((icon) => {
3050
+ const isFolder = icon.kind === "folder";
3051
+ const folderOpen = isFolder ? openInFolder(icon.section).length : 0;
3052
+ const appOpen = !isFolder ? openCountByRoute.get(icon.route) ?? 0 : 0;
3053
+ const isBeingDragged = dragId === icon.id;
3054
+ return /* @__PURE__ */ jsxs(
3055
+ "button",
3056
+ {
3057
+ "data-home-icon-id": icon.id,
3058
+ onPointerDown: (e) => beginLongPress(icon.id, e),
3059
+ onPointerUp: cancelLongPress,
3060
+ onPointerCancel: cancelLongPress,
3061
+ onPointerLeave: cancelLongPress,
3062
+ onClick: () => handleIconClick(icon),
3063
+ style: { touchAction: "none", visibility: isBeingDragged ? "hidden" : "visible" },
3064
+ className: `flex flex-col items-center gap-1 py-1 rounded-lg active:bg-white/20 ${dragId && !isBeingDragged ? "transition-transform" : ""}`,
3065
+ children: [
3066
+ isFolder ? /* @__PURE__ */ jsx(FolderTile, { section: icon.section, navIcons: navIcons2, badge: folderOpen }) : /* @__PURE__ */ jsx(AppTile, { route: icon.route, icon: navIcons2[icon.route], badge: appOpen > 0 }),
3067
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-sm truncate w-full text-center", children: icon.label })
3068
+ ]
3069
+ },
3070
+ icon.id
3071
+ );
3072
+ }) }) })
3073
+ ]
3074
+ }
3075
+ ),
3076
+ draggedIcon && dragPos && /* @__PURE__ */ jsx(
3077
+ "div",
3078
+ {
3079
+ className: "fixed pointer-events-none z-[400] transition-none",
3080
+ style: {
3081
+ left: dragPos.x - dragOffsetRef.current.x,
3082
+ top: dragPos.y - dragOffsetRef.current.y,
3083
+ transform: "scale(1.12)"
3084
+ },
3085
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-1 w-20", children: [
3086
+ draggedIcon.kind === "folder" ? /* @__PURE__ */ jsx(FolderTile, { section: draggedIcon.section, navIcons: navIcons2 }) : /* @__PURE__ */ jsx(AppTile, { route: draggedIcon.route, icon: navIcons2[draggedIcon.route] }),
3087
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-md truncate w-full text-center", children: draggedIcon.label })
3088
+ ] })
3089
+ }
3090
+ ),
3091
+ selectedFolder && /* @__PURE__ */ jsx(
3092
+ FolderPopup,
3093
+ {
3094
+ folder: selectedFolder,
3095
+ navIcons: navIcons2,
3096
+ openInFolder: openInFolder(selectedFolder),
3097
+ openCountByRoute,
3098
+ onClose: () => setSelectedFolder(null),
3099
+ onOpenApp: (path) => {
3100
+ setSelectedFolder(null);
3101
+ onOpenApp(path);
3102
+ },
3103
+ onActivateWindow: (id) => {
3104
+ setSelectedFolder(null);
3105
+ onActivateWindow(id);
3106
+ }
3107
+ }
3108
+ )
3109
+ ] });
3110
+ }
3111
+ function FolderPopup({
3112
+ folder,
3113
+ navIcons: navIcons2,
3114
+ openInFolder,
3115
+ openCountByRoute,
3116
+ onClose,
3117
+ onOpenApp,
3118
+ onActivateWindow
3119
+ }) {
3120
+ return /* @__PURE__ */ jsxs(
3121
+ "div",
3122
+ {
3123
+ className: "fixed inset-0 z-[210] flex flex-col items-center justify-center px-6 bg-black/45 backdrop-blur-xl select-none",
3124
+ style: {
3125
+ paddingBottom: "calc(var(--mobile-bottom-nav, 70px) + 16px)",
3126
+ animation: "folder-fade-in 220ms ease-out",
3127
+ WebkitUserSelect: "none",
3128
+ WebkitTouchCallout: "none"
3129
+ },
3130
+ onClick: onClose,
3131
+ children: [
3132
+ /* @__PURE__ */ jsx("style", { children: `
3133
+ @keyframes folder-fade-in { from { opacity: 0; } to { opacity: 1; } }
3134
+ @keyframes folder-pop-in { from { opacity: 0; transform: scale(0.86) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }
3135
+ ` }),
3136
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-white drop-shadow-md mb-4 self-start", children: folder.label }),
3137
+ /* @__PURE__ */ jsx(
3138
+ "div",
3139
+ {
3140
+ className: "w-full max-w-md max-h-[70vh] flex flex-col rounded-3xl bg-white/15 backdrop-blur-xl border border-white/25 shadow-2xl overflow-hidden",
3141
+ style: { animation: "folder-pop-in 240ms cubic-bezier(0.34, 1.56, 0.64, 1)" },
3142
+ onClick: (e) => e.stopPropagation(),
3143
+ children: /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-5", children: [
3144
+ openInFolder.length > 0 && /* @__PURE__ */ jsxs("section", { className: "mb-4", children: [
3145
+ /* @__PURE__ */ jsx("h3", { className: "text-[11px] font-semibold uppercase tracking-wide text-white/70 mb-2", children: "Open" }),
3146
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: openInFolder.map((w) => /* @__PURE__ */ jsxs(
3147
+ "button",
3148
+ {
3149
+ onClick: () => onActivateWindow(w.id),
3150
+ className: "flex items-center gap-2 p-2 rounded-lg bg-white/15 active:bg-white/25 text-left",
3151
+ children: [
3152
+ /* @__PURE__ */ jsx("span", { className: `h-7 w-7 rounded bg-gradient-to-br ${hashGradient(w.route ?? "")} flex items-center justify-center text-white shrink-0`, children: sizeIcon(w.route ? navIcons2[w.route] : null, FALLBACK_APP_ICON, "h-4 w-4") }),
3153
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-white truncate flex-1", children: w.label })
3154
+ ]
3155
+ },
3156
+ w.id
3157
+ )) })
3158
+ ] }),
3159
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-3", children: folder.items.map((item) => {
3160
+ const openCount = openCountByRoute.get(item.to) ?? 0;
3161
+ return /* @__PURE__ */ jsxs(
3162
+ "button",
3163
+ {
3164
+ onClick: () => onOpenApp(item.to),
3165
+ className: "flex flex-col items-center gap-1.5 p-1 rounded-lg active:bg-white/15",
3166
+ children: [
3167
+ /* @__PURE__ */ jsx(AppTile, { route: item.to, icon: navIcons2[item.to], badge: openCount > 0 }),
3168
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-sm truncate w-full text-center", children: item.label })
3169
+ ]
3170
+ },
3171
+ item.to
3172
+ );
3173
+ }) })
3174
+ ] })
3175
+ }
3176
+ )
3177
+ ]
3178
+ }
3179
+ );
3180
+ }
3181
+ function MobileSwitcher({ windows, onActivate, onClose }) {
3182
+ const [cardSize, setCardSize] = useState(() => computeCardSize());
3183
+ useEffect(() => {
3184
+ const onResize = () => setCardSize(computeCardSize());
3185
+ window.addEventListener("resize", onResize);
3186
+ return () => window.removeEventListener("resize", onResize);
3187
+ }, []);
3188
+ if (windows.length === 0) {
3189
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 text-white/80 px-6 text-center", children: [
3190
+ /* @__PURE__ */ jsxs("svg", { className: "h-12 w-12 text-white/40", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.4, children: [
3191
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "3.5", width: "7", height: "7", rx: "1.25" }),
3192
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "3.5", width: "7", height: "7", rx: "1.25" }),
3193
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "13.5", width: "7", height: "7", rx: "1.25" }),
3194
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "13.5", width: "7", height: "7", rx: "1.25" })
3195
+ ] }),
3196
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No open apps." }),
3197
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-white/50", children: "Tap Home to launch one." })
3198
+ ] });
3199
+ }
3200
+ return /* @__PURE__ */ jsxs("div", { className: "h-full overflow-y-auto px-3 pt-4 pb-4", children: [
3201
+ /* @__PURE__ */ jsxs("h1", { className: "text-white text-base font-semibold mb-3 px-1", children: [
3202
+ "Open apps \xB7 ",
3203
+ windows.length
3204
+ ] }),
3205
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: windows.map((w) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-stretch gap-1", children: [
3206
+ /* @__PURE__ */ jsx(
3207
+ ThumbCard,
3208
+ {
3209
+ id: w.id,
3210
+ label: w.label,
3211
+ maxW: cardSize.w,
3212
+ maxH: cardSize.h,
3213
+ titleAbove: true,
3214
+ onClick: () => onActivate(w.id),
3215
+ onClose: () => onClose(w.id)
3216
+ }
3217
+ ),
3218
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-white/80 truncate px-1", children: w.label })
3219
+ ] }, w.id)) })
3220
+ ] });
3221
+ }
3222
+ function computeCardSize() {
3223
+ const w = typeof window !== "undefined" ? window.innerWidth : 360;
3224
+ const h = typeof window !== "undefined" ? window.innerHeight : 640;
3225
+ const cardW = Math.max(120, Math.floor((w - 36) / 2));
3226
+ const cardH = Math.min(cardW * 1.4, Math.floor(h * 0.4));
3227
+ return { w: cardW, h: cardH };
3228
+ }
3229
+ function timeAgo2(dateStr) {
3230
+ const diff = Date.now() - new Date(dateStr).getTime();
3231
+ const mins = Math.floor(diff / 6e4);
3232
+ if (mins < 1) return "just now";
3233
+ if (mins < 60) return `${mins}m ago`;
3234
+ const hrs = Math.floor(mins / 60);
3235
+ if (hrs < 24) return `${hrs}h ago`;
3236
+ const days = Math.floor(hrs / 24);
3237
+ if (days < 7) return `${days}d ago`;
3238
+ return formatDate(dateStr);
3239
+ }
3240
+ function MobileNotificationSheet({ config, onClose }) {
3241
+ const { list, markRead, markAllRead, onItemClick } = config;
3242
+ const queryClient = useQueryClient();
3243
+ const unreadCount = config.useUnreadCount();
3244
+ const { data: notifData } = useQuery({
3245
+ queryKey: ["notifications-dropdown"],
3246
+ queryFn: () => list({ page_size: 30 }),
3247
+ staleTime: 3e4
3248
+ });
3249
+ const notifications = notifData?.results ?? [];
3250
+ const handleClick = useCallback((notif) => {
3251
+ if (!notif.is_read) {
3252
+ queryClient.setQueryData(["notification-unread-count"], (old) => old ? { ...old, count: Math.max(0, (old.count || 0) - 1) } : old);
3253
+ queryClient.setQueryData(["notifications-dropdown"], (old) => {
3254
+ if (!old?.results) return old;
3255
+ return { ...old, results: old.results.map((n) => n.id === notif.id ? { ...n, is_read: true } : n) };
3256
+ });
3257
+ markRead(notif.id).catch(() => {
3258
+ queryClient.invalidateQueries({ queryKey: ["notification-unread-count"] });
3259
+ queryClient.invalidateQueries({ queryKey: ["notifications-dropdown"] });
3260
+ });
3261
+ }
3262
+ onClose();
3263
+ onItemClick(notif);
3264
+ }, [queryClient, markRead, onItemClick, onClose]);
3265
+ const handleMarkAllRead = () => {
3266
+ queryClient.setQueryData(["notification-unread-count"], (old) => old ? { ...old, count: 0 } : old);
3267
+ queryClient.setQueryData(["notifications-dropdown"], (old) => {
3268
+ if (!old?.results) return old;
3269
+ return { ...old, results: old.results.map((n) => ({ ...n, is_read: true })) };
3270
+ });
3271
+ markAllRead().then(() => {
3272
+ queryClient.invalidateQueries({ queryKey: ["notification-unread-count"] });
3273
+ queryClient.invalidateQueries({ queryKey: ["notifications-dropdown"] });
3274
+ });
3275
+ };
3276
+ return /* @__PURE__ */ jsxs(
3277
+ "div",
3278
+ {
3279
+ className: "fixed inset-0 z-[210] flex flex-col bg-white",
3280
+ style: { paddingBottom: "var(--mobile-bottom-nav, 70px)" },
3281
+ children: [
3282
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between px-3 py-3 border-b border-gray-200 shrink-0", children: [
3283
+ /* @__PURE__ */ jsx("button", { onClick: onClose, className: "p-2 -ml-1 rounded-full active:bg-gray-200 text-gray-700", "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }),
3284
+ /* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-gray-900", children: "Notifications" }),
3285
+ unreadCount > 0 ? /* @__PURE__ */ jsx("button", { onClick: handleMarkAllRead, className: "text-xs text-blue-600 font-medium px-2 py-1 active:bg-blue-50 rounded", children: "Mark all read" }) : /* @__PURE__ */ jsx("span", { className: "w-[88px]" })
3286
+ ] }),
3287
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: notifications.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [
3288
+ /* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-gray-300 mb-3", 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" }) }),
3289
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-700 font-medium", children: "All caught up" }),
3290
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 mt-1", children: "No notifications yet" })
3291
+ ] }) : notifications.map((notif) => /* @__PURE__ */ jsxs(
3292
+ "button",
3293
+ {
3294
+ onClick: () => handleClick(notif),
3295
+ className: "w-full flex items-start gap-3 px-4 py-3 active:bg-gray-100 border-b border-gray-100 text-left",
3296
+ children: [
3297
+ /* @__PURE__ */ jsx("div", { className: "pt-1 shrink-0", children: !notif.is_read ? /* @__PURE__ */ jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-blue-500" }) : /* @__PURE__ */ jsx("div", { className: "h-2.5 w-2.5" }) }),
3298
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3299
+ /* @__PURE__ */ jsx("p", { className: `text-sm leading-snug ${!notif.is_read ? "font-medium text-gray-900" : "text-gray-700"}`, children: notif.title }),
3300
+ notif.message && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1 line-clamp-2", children: notif.message }),
3301
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1.5", children: [
3302
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-gray-400", children: timeAgo2(notif.created_at) }),
3303
+ notif.actor_name && /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-gray-400", children: [
3304
+ "by ",
3305
+ notif.actor_name
3306
+ ] })
3307
+ ] })
3308
+ ] })
3309
+ ]
3310
+ },
3311
+ notif.id
3312
+ )) })
3313
+ ]
3314
+ }
3315
+ );
3316
+ }
3317
+ function MobileProfileSheet({ profile, user, onClose, onNavigate, onLogout }) {
3318
+ const initial = (profile?.first_name?.charAt(0) || user?.email?.charAt(0) || "?").toUpperCase();
3319
+ const displayName = profile?.first_name ? `${profile.first_name} ${profile.last_name || ""}`.trim() : user?.email ?? "Account";
3320
+ const groups = profile?.group_names ?? [];
3321
+ const handleNav = (path) => {
3322
+ onNavigate(path);
3323
+ onClose();
3324
+ };
3325
+ return /* @__PURE__ */ jsxs(
3326
+ "div",
3327
+ {
3328
+ className: "fixed inset-0 z-[210] flex flex-col bg-white",
3329
+ style: { paddingBottom: "var(--mobile-bottom-nav, 70px)" },
3330
+ children: [
3331
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between px-3 py-3 border-b border-gray-200 shrink-0", children: [
3332
+ /* @__PURE__ */ jsx("button", { onClick: onClose, className: "p-2 -ml-1 rounded-full active:bg-gray-200 text-gray-700", "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }),
3333
+ /* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-gray-900", children: "Profile" }),
3334
+ /* @__PURE__ */ jsx("span", { className: "w-10" })
3335
+ ] }),
3336
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
3337
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center px-6 py-8 border-b border-gray-100", children: [
3338
+ profile?.avatar_url ? /* @__PURE__ */ jsx("img", { src: profile.avatar_url, alt: "", className: "h-20 w-20 rounded-full object-cover border border-gray-200 shadow-sm" }) : /* @__PURE__ */ jsx("div", { className: "h-20 w-20 rounded-full bg-blue-100 flex items-center justify-center text-2xl font-bold text-blue-700 shadow-sm", children: initial }),
3339
+ /* @__PURE__ */ jsx("div", { className: "mt-3 text-base font-semibold text-gray-900 truncate max-w-full", children: displayName }),
3340
+ user?.email && profile?.first_name && /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 truncate max-w-full", children: user.email }),
3341
+ groups.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap justify-center gap-1.5", children: groups.map((g) => /* @__PURE__ */ jsx("span", { className: "text-[11px] px-2 py-0.5 rounded-full bg-gray-100 text-gray-700", children: g }, g)) })
3342
+ ] }),
3343
+ /* @__PURE__ */ jsxs("div", { className: "py-2", children: [
3344
+ /* @__PURE__ */ jsxs(
3345
+ "button",
3346
+ {
3347
+ onClick: () => handleNav("/customization"),
3348
+ className: "w-full flex items-center gap-3 px-4 py-4 active:bg-gray-100 border-b border-gray-100 text-left",
3349
+ children: [
3350
+ /* @__PURE__ */ jsx("span", { className: "h-9 w-9 rounded-lg bg-gray-100 flex items-center justify-center text-gray-700 shrink-0", children: /* @__PURE__ */ jsxs("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [
3351
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" }),
3352
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
3353
+ ] }) }),
3354
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-medium text-gray-800", children: "Customization" }),
3355
+ /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 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: "M8.25 4.5l7.5 7.5-7.5 7.5" }) })
3356
+ ]
3357
+ }
3358
+ ),
3359
+ /* @__PURE__ */ jsxs(
3360
+ "button",
3361
+ {
3362
+ onClick: () => {
3363
+ onLogout();
3364
+ onClose();
3365
+ },
3366
+ className: "w-full flex items-center gap-3 px-4 py-4 active:bg-red-50 text-left",
3367
+ children: [
3368
+ /* @__PURE__ */ jsx("span", { className: "h-9 w-9 rounded-lg bg-red-50 flex items-center justify-center text-red-600 shrink-0", 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.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" }) }) }),
3369
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-medium text-red-600", children: "Sign out" })
3370
+ ]
3371
+ }
3372
+ )
3373
+ ] })
3374
+ ] })
3375
+ ]
3376
+ }
3377
+ );
3378
+ }
3379
+ function MobileShell({
3380
+ navSections: navSections2,
3381
+ navIcons: navIcons2,
3382
+ sectionIcons: sectionIcons2,
3383
+ wallpaperStyle,
3384
+ notifications,
3385
+ profile,
3386
+ user,
3387
+ onNavigate,
3388
+ onLogout
3389
+ }) {
3390
+ const { openWindows, openPage, closeEntity } = useWindowManager();
3391
+ const mode = useSyncExternalStore(subscribeMobileMode, getMobileMode);
3392
+ const [sheet, setSheet] = useState(null);
3393
+ const unreadCount = notifications?.useUnreadCount() ?? 0;
3394
+ const switcherWindows = useMemo(() => {
3395
+ return openWindows.filter((w) => {
3396
+ if (!w.route) return true;
3397
+ const entry = WINDOW_REGISTRY[w.route];
3398
+ if (!entry || !isPageEntry(entry)) return true;
3399
+ return !entry.widget;
3400
+ });
3401
+ }, [openWindows]);
3402
+ const prevOpenCountRef = useRef(openWindows.length);
3403
+ useEffect(() => {
3404
+ if (openWindows.length < prevOpenCountRef.current && mode === "app") {
3405
+ setMobileMode("home");
3406
+ }
3407
+ prevOpenCountRef.current = openWindows.length;
3408
+ }, [openWindows.length, mode]);
3409
+ const activateWindowById = (windowId) => {
3410
+ const panel = document.querySelector(`[data-modal-panel][data-window-key="${windowId}"]`);
3411
+ const mid = panel?.getAttribute("data-modal-id");
3412
+ if (mid) activateModal(mid);
3413
+ };
3414
+ const handleOpenApp = (path) => {
3415
+ openPage(path);
3416
+ setMobileMode("app");
3417
+ };
3418
+ const handleActivateWindow = (id) => {
3419
+ activateWindowById(id);
3420
+ setMobileMode("app");
3421
+ };
3422
+ const closeSheet = () => setSheet(null);
3423
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3424
+ mode === "home" && /* @__PURE__ */ jsx(
3425
+ "div",
3426
+ {
3427
+ className: "fixed inset-0 z-[200]",
3428
+ style: {
3429
+ ...wallpaperStyle,
3430
+ paddingBottom: "var(--mobile-bottom-nav, 70px)"
3431
+ },
3432
+ children: /* @__PURE__ */ jsx(
3433
+ MobileHome,
3434
+ {
3435
+ navSections: navSections2,
3436
+ navIcons: navIcons2,
3437
+ sectionIcons: sectionIcons2,
3438
+ openWindows,
3439
+ onOpenApp: handleOpenApp,
3440
+ onActivateWindow: handleActivateWindow
3441
+ }
3442
+ )
3443
+ }
3444
+ ),
3445
+ mode === "switcher" && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[200] bg-gray-900/95 backdrop-blur-sm", style: { paddingBottom: "var(--mobile-bottom-nav, 70px)" }, children: /* @__PURE__ */ jsx(
3446
+ MobileSwitcher,
3447
+ {
3448
+ windows: switcherWindows,
3449
+ onActivate: handleActivateWindow,
3450
+ onClose: (id) => closeEntity(id)
3451
+ }
3452
+ ) }),
3453
+ sheet === "notifications" && notifications && /* @__PURE__ */ jsx(MobileNotificationSheet, { config: notifications, onClose: closeSheet }),
3454
+ sheet === "profile" && /* @__PURE__ */ jsx(
3455
+ MobileProfileSheet,
3456
+ {
3457
+ profile,
3458
+ user,
3459
+ onClose: closeSheet,
3460
+ onNavigate: (path) => {
3461
+ onNavigate?.(path);
3462
+ },
3463
+ onLogout: () => onLogout?.()
3464
+ }
3465
+ ),
3466
+ /* @__PURE__ */ jsx(
3467
+ MobileBottomNav,
3468
+ {
3469
+ mode,
3470
+ openCount: switcherWindows.length,
3471
+ unreadCount,
3472
+ showNotifications: !!notifications,
3473
+ profileAvatar: profile?.avatar_url,
3474
+ profileInitial: (profile?.first_name?.charAt(0) || user?.email?.charAt(0) || "?").toUpperCase(),
3475
+ onHome: () => {
3476
+ closeSheet();
3477
+ setMobileMode("home");
3478
+ },
3479
+ onSwitcher: () => {
3480
+ closeSheet();
3481
+ setMobileMode("switcher");
3482
+ },
3483
+ onNotifications: () => setSheet(sheet === "notifications" ? null : "notifications"),
3484
+ onProfile: () => setSheet(sheet === "profile" ? null : "profile")
3485
+ }
3486
+ )
3487
+ ] });
3488
+ }
3489
+ function MobileBottomNav({
3490
+ mode,
3491
+ openCount,
3492
+ unreadCount,
3493
+ showNotifications,
3494
+ profileAvatar,
3495
+ profileInitial,
3496
+ onHome,
3497
+ onSwitcher,
3498
+ onNotifications,
3499
+ onProfile
3500
+ }) {
3501
+ const btnClass = (active) => `flex-1 flex flex-col items-center justify-center gap-0.5 py-2 transition-colors select-none ${active ? "text-blue-600" : "text-gray-700 active:text-gray-900"}`;
3502
+ return /* @__PURE__ */ jsxs(
3503
+ "nav",
3504
+ {
3505
+ className: "fixed bottom-0 inset-x-0 z-[300] flex items-stretch border-t border-white/40",
3506
+ style: {
3507
+ height: "var(--mobile-bottom-nav, 70px)",
3508
+ paddingBottom: "env(safe-area-inset-bottom)",
3509
+ WebkitBackdropFilter: "blur(28px) saturate(1.8)",
3510
+ backdropFilter: "blur(28px) saturate(1.8)",
3511
+ background: "linear-gradient(135deg, rgba(255,255,255,0.65) 0%, rgba(255,255,255,0.45) 50%, rgba(255,255,255,0.55) 100%)",
3512
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.6), 0 -2px 12px rgba(0,0,0,0.08)"
3513
+ },
3514
+ children: [
3515
+ /* @__PURE__ */ jsxs("button", { onClick: onHome, className: btnClass(mode === "home"), "aria-label": "Home", children: [
3516
+ /* @__PURE__ */ jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.7, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" }) }),
3517
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium", children: "Home" })
3518
+ ] }),
3519
+ /* @__PURE__ */ jsxs("button", { onClick: onSwitcher, className: btnClass(mode === "switcher"), "aria-label": "App switcher", children: [
3520
+ /* @__PURE__ */ jsxs("span", { className: "relative", children: [
3521
+ /* @__PURE__ */ jsxs("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.7, children: [
3522
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "3.5", width: "7", height: "7", rx: "1.25" }),
3523
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "3.5", width: "7", height: "7", rx: "1.25" }),
3524
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "13.5", width: "7", height: "7", rx: "1.25" }),
3525
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "13.5", width: "7", height: "7", rx: "1.25" })
3526
+ ] }),
3527
+ openCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-2 min-w-[16px] h-4 px-1 rounded-full bg-blue-500 text-white text-[10px] font-bold leading-4 text-center", children: openCount })
3528
+ ] }),
3529
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium", children: "Apps" })
3530
+ ] }),
3531
+ showNotifications && /* @__PURE__ */ jsxs("button", { onClick: onNotifications, className: btnClass(false), "aria-label": "Notifications", children: [
3532
+ /* @__PURE__ */ jsxs("span", { className: "relative", children: [
3533
+ /* @__PURE__ */ jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.7, 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" }) }),
3534
+ unreadCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-2 min-w-[16px] h-4 px-1 rounded-full bg-red-500 text-white text-[10px] font-bold leading-4 text-center", children: unreadCount > 99 ? "99+" : unreadCount })
3535
+ ] }),
3536
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium", children: "Alerts" })
3537
+ ] }),
3538
+ /* @__PURE__ */ jsxs("button", { onClick: onProfile, className: btnClass(false), "aria-label": "Profile", children: [
3539
+ profileAvatar ? /* @__PURE__ */ jsx("img", { src: profileAvatar, alt: "", className: "h-6 w-6 rounded-full object-cover border border-gray-200" }) : /* @__PURE__ */ jsx("div", { className: "h-6 w-6 rounded-full bg-blue-100 flex items-center justify-center text-[10px] font-bold text-blue-700", children: profileInitial }),
3540
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium", children: "Profile" })
3541
+ ] })
3542
+ ]
3543
+ }
3544
+ );
3545
+ }
2676
3546
  function useFavorites(wallpapers) {
2677
3547
  const { prefs, save } = useShellPrefs();
2678
3548
  const favorites = prefs.favorite_pages || [];
@@ -2962,6 +3832,7 @@ function Layout({
2962
3832
  const { openPage, openEntity, openWindows } = useWindowManager();
2963
3833
  const [menuOpen, setMenuOpen] = useState(false);
2964
3834
  useEmailUnreadCount();
3835
+ const isMobile = useIsMobile();
2965
3836
  const profile = user || {};
2966
3837
  useTheme();
2967
3838
  const { desktopBg} = useFavorites(wallpapers);
@@ -3006,6 +3877,9 @@ function Layout({
3006
3877
  root.style.setProperty("--window-tab-width", sv.tabW);
3007
3878
  root.style.setProperty("--window-tab-font-size", sv.tabFont);
3008
3879
  }, [inactiveHeaderOpacity, inactiveContentOpacity, activeHeaderOpacity, activeContentOpacity, taskbarH, taskbarPosition, prefs.default_window_size, prefs.window_position, prefs.menu_density, prefs.start_menu_size]);
3880
+ useEffect(() => {
3881
+ document.documentElement.style.setProperty("--mobile-bottom-nav", isMobile ? "70px" : "0px");
3882
+ }, [isMobile]);
3009
3883
  const [balloonDismissed, setBalloonDismissed] = useState(false);
3010
3884
  const [isFullscreen, setIsFullscreen] = useState(!!document.fullscreenElement);
3011
3885
  const [taskbarMenu, setTaskbarMenu] = useState(null);
@@ -3136,146 +4010,169 @@ function Layout({
3136
4010
  categories
3137
4011
  }
3138
4012
  ),
3139
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 min-h-0", children: /* @__PURE__ */ jsx(
3140
- "main",
3141
- {
3142
- className: "flex-1 flex flex-col overflow-hidden cursor-default",
3143
- onDoubleClick: () => {
3144
- if (desktopDblClick === "deactivate") {
3145
- setMenuOpen(false);
3146
- window.dispatchEvent(new CustomEvent("deactivate-all-modals"));
4013
+ (() => {
4014
+ const wallpaperStyle = {
4015
+ backgroundColor: desktopBg?.startsWith("#") ? desktopBg : desktopBg === "none" ? (() => {
4016
+ const customBg = getComputedStyle(document.documentElement).getPropertyValue("--custom-bg-color")?.trim();
4017
+ if (customBg) return customBg;
4018
+ const t = document.documentElement.getAttribute("data-theme") || "light";
4019
+ const map = { light: "#f3f4f6", dark: "#1e1e2e", pink: "#fdf2f8", green: "#f0fdf4", grey: "#d1d5db", blue: "#eff6ff" };
4020
+ return map[t] || "#f3f4f6";
4021
+ })() : "#1a1a2e",
4022
+ backgroundImage: desktopBg && desktopBg !== "none" && !desktopBg.startsWith("#") ? `url(${desktopBg})` : "none",
4023
+ backgroundSize: "cover",
4024
+ backgroundPosition: "center",
4025
+ backgroundRepeat: "no-repeat"
4026
+ };
4027
+ if (isMobile) {
4028
+ return /* @__PURE__ */ jsx(
4029
+ MobileShell,
4030
+ {
4031
+ productName,
4032
+ productIcon,
4033
+ navSections: navSections2,
4034
+ navIcons: navIcons2,
4035
+ sectionIcons: sectionIcons2,
4036
+ wallpaperStyle,
4037
+ notifications,
4038
+ profile,
4039
+ user,
4040
+ onNavigate: (path) => openPage(path),
4041
+ onLogout: () => setShowLogout(true)
3147
4042
  }
3148
- },
3149
- style: {
3150
- backgroundColor: desktopBg?.startsWith("#") ? desktopBg : desktopBg === "none" ? (() => {
3151
- const customBg = getComputedStyle(document.documentElement).getPropertyValue("--custom-bg-color")?.trim();
3152
- if (customBg) return customBg;
3153
- const t = document.documentElement.getAttribute("data-theme") || "light";
3154
- const map = { light: "#f3f4f6", dark: "#1e1e2e", pink: "#fdf2f8", green: "#f0fdf4", grey: "#d1d5db", blue: "#eff6ff" };
3155
- return map[t] || "#f3f4f6";
3156
- })() : "#1a1a2e",
3157
- backgroundImage: desktopBg && desktopBg !== "none" && !desktopBg.startsWith("#") ? `url(${desktopBg})` : "none",
3158
- backgroundSize: "cover",
3159
- backgroundPosition: "center",
3160
- backgroundRepeat: "no-repeat"
3161
- },
3162
- children: /* @__PURE__ */ jsx(Desktop, { profile })
4043
+ );
3163
4044
  }
3164
- ) }),
3165
- /* @__PURE__ */ jsxs(
3166
- "div",
3167
- {
3168
- className: `flex backdrop-blur-sm border-gray-200 z-[250] fixed ${isVerticalTaskbar ? `flex-col items-center ${taskbarWClass} py-3 gap-2 top-0 bottom-0 ${taskbarPosition === "left" ? "left-0 border-r" : "right-0 border-l"}` : `items-center ${taskbarHClass} px-3 gap-2 left-0 right-0 ${taskbarPosition === "top" ? "top-0 border-b" : "bottom-0 border-t"}`}`,
3169
- style: { backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${taskbarOpacity})` },
3170
- onContextMenu: (e) => {
3171
- e.preventDefault();
3172
- setTaskbarMenu({ x: e.clientX, y: e.clientY });
3173
- },
3174
- children: [
3175
- /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
3176
- openWindows.length === 0 && !menuOpen && !balloonDismissed && /* @__PURE__ */ jsxs(
3177
- "div",
3178
- {
3179
- className: `absolute left-1/2 -translate-x-1/2 whitespace-nowrap text-white text-[10px] font-medium pl-3 pr-2 py-1 rounded-full shadow-lg animate-bounce flex items-center gap-1 ${taskbarPosition === "top" ? "top-full mt-2" : "-top-8"}`,
3180
- style: { backgroundColor: "var(--accent-600, #7c3aed)" },
3181
- children: [
3182
- "Click here to start",
3183
- /* @__PURE__ */ jsx("button", { onClick: (e) => {
3184
- e.stopPropagation();
3185
- setBalloonDismissed(true);
3186
- }, className: "text-white/60 hover:text-white ml-1.5", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }),
4045
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4046
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 min-h-0", children: /* @__PURE__ */ jsx(
4047
+ "main",
4048
+ {
4049
+ className: "flex-1 flex flex-col overflow-hidden cursor-default",
4050
+ onDoubleClick: () => {
4051
+ if (desktopDblClick === "deactivate") {
4052
+ setMenuOpen(false);
4053
+ window.dispatchEvent(new CustomEvent("deactivate-all-modals"));
4054
+ }
4055
+ },
4056
+ style: wallpaperStyle,
4057
+ children: /* @__PURE__ */ jsx(Desktop, { profile })
4058
+ }
4059
+ ) }),
4060
+ /* @__PURE__ */ jsxs(
4061
+ "div",
4062
+ {
4063
+ className: `flex backdrop-blur-sm border-gray-200 z-[250] fixed ${isVerticalTaskbar ? `flex-col items-center ${taskbarWClass} py-3 gap-2 top-0 bottom-0 ${taskbarPosition === "left" ? "left-0 border-r" : "right-0 border-l"}` : `items-center ${taskbarHClass} px-3 gap-2 left-0 right-0 ${taskbarPosition === "top" ? "top-0 border-b" : "bottom-0 border-t"}`}`,
4064
+ style: { backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${taskbarOpacity})` },
4065
+ onContextMenu: (e) => {
4066
+ e.preventDefault();
4067
+ setTaskbarMenu({ x: e.clientX, y: e.clientY });
4068
+ },
4069
+ children: [
4070
+ /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
4071
+ openWindows.length === 0 && !menuOpen && !balloonDismissed && /* @__PURE__ */ jsxs(
4072
+ "div",
4073
+ {
4074
+ className: `absolute left-1/2 -translate-x-1/2 whitespace-nowrap text-white text-[10px] font-medium pl-3 pr-2 py-1 rounded-full shadow-lg animate-bounce flex items-center gap-1 ${taskbarPosition === "top" ? "top-full mt-2" : "-top-8"}`,
4075
+ style: { backgroundColor: "var(--accent-600, #7c3aed)" },
4076
+ children: [
4077
+ "Click here to start",
4078
+ /* @__PURE__ */ jsx("button", { onClick: (e) => {
4079
+ e.stopPropagation();
4080
+ setBalloonDismissed(true);
4081
+ }, className: "text-white/60 hover:text-white ml-1.5", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }),
4082
+ /* @__PURE__ */ jsx(
4083
+ "div",
4084
+ {
4085
+ className: `absolute left-1/2 -translate-x-1/2 border-[6px] border-transparent ${taskbarPosition === "top" ? "bottom-full border-b-[var(--accent-color,#7c3aed)]" : "top-full border-t-[var(--accent-color,#7c3aed)]"}`,
4086
+ style: taskbarPosition === "top" ? { borderBottomColor: "var(--accent-600, #7c3aed)" } : { borderTopColor: "var(--accent-600, #7c3aed)" }
4087
+ }
4088
+ )
4089
+ ]
4090
+ }
4091
+ ),
4092
+ /* @__PURE__ */ jsxs(
4093
+ "button",
4094
+ {
4095
+ "data-menu-toggle": true,
4096
+ onClick: () => setMenuOpen((prev) => !prev),
4097
+ title: menuOpen ? "Close menu" : "Open menu",
4098
+ className: `group/erp relative flex items-center gap-1.5 rounded-lg px-4 py-2 text-xs font-medium border overflow-hidden transition-all ${isVerticalTaskbar ? "w-full" : "min-w-[140px]"} ${menuOpen ? "bg-gray-200/40 border-gray-300/40 text-gray-800" : "bg-gray-50/40 border-gray-200/40 text-gray-600 hover:text-gray-800"}`,
4099
+ style: { transition: "box-shadow 0.3s, border-color 0.3s" },
4100
+ onMouseMove: (e) => {
4101
+ const r = e.currentTarget.getBoundingClientRect();
4102
+ e.currentTarget.style.setProperty("--mx", `${e.clientX - r.left}px`);
4103
+ e.currentTarget.style.setProperty("--my", `${e.clientY - r.top}px`);
4104
+ },
4105
+ onMouseEnter: (e) => {
4106
+ e.currentTarget.style.boxShadow = "0 0 15px rgba(255,255,255,0.2), 0 0 30px rgba(255,255,255,0.1)";
4107
+ e.currentTarget.style.borderColor = "rgba(255,255,255,0.4)";
4108
+ },
4109
+ onMouseLeave: (e) => {
4110
+ e.currentTarget.style.boxShadow = "";
4111
+ e.currentTarget.style.borderColor = "";
4112
+ },
4113
+ children: [
4114
+ /* @__PURE__ */ jsx(
4115
+ "span",
4116
+ {
4117
+ className: "absolute inset-0 opacity-0 group-hover/erp:opacity-100 transition-opacity duration-200 pointer-events-none",
4118
+ style: { background: "radial-gradient(circle 60px at var(--mx, 50%) var(--my, 50%), rgba(255,255,255,0.25) 0%, transparent 100%)" }
4119
+ }
4120
+ ),
4121
+ productIcon && /* @__PURE__ */ jsx("img", { src: productIcon, alt: "", className: "relative z-10 h-3.5 w-3.5 shrink-0 opacity-60" }),
4122
+ /* @__PURE__ */ jsx("span", { className: "relative z-10 truncate", children: productName })
4123
+ ]
4124
+ }
4125
+ )
4126
+ ] }),
4127
+ /* @__PURE__ */ jsx("div", { className: isVerticalTaskbar ? "h-px w-6 bg-gray-300 my-1" : "w-px h-6 bg-gray-300 mx-1" }),
4128
+ /* @__PURE__ */ jsx("div", { id: "taskbar-windows", className: `flex-1 flex ${isVerticalTaskbar ? "flex-col items-center gap-1 min-h-0 overflow-y-auto w-full" : "items-center gap-1.5 min-w-0 overflow-x-auto"}` }),
4129
+ /* @__PURE__ */ jsx("div", { className: isVerticalTaskbar ? "h-px w-6 bg-gray-300 my-1" : "w-px h-6 bg-gray-300 mx-1" }),
4130
+ isVerticalTaskbar ? (
4131
+ /* Vertical: clock + bell + google evenly spaced in a row */
4132
+ /* @__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: [
4133
+ /* @__PURE__ */ jsx(TaskbarClock, {}),
3187
4134
  /* @__PURE__ */ jsx(
3188
- "div",
4135
+ "button",
3189
4136
  {
3190
- className: `absolute left-1/2 -translate-x-1/2 border-[6px] border-transparent ${taskbarPosition === "top" ? "bottom-full border-b-[var(--accent-color,#7c3aed)]" : "top-full border-t-[var(--accent-color,#7c3aed)]"}`,
3191
- style: taskbarPosition === "top" ? { borderBottomColor: "var(--accent-600, #7c3aed)" } : { borderTopColor: "var(--accent-600, #7c3aed)" }
4137
+ onClick: () => setGoogleConnectOpen(true),
4138
+ title: googleConnected ? "Google Connected" : "Connect Google",
4139
+ className: `shrink-0 rounded-md p-1.5 transition-colors ${googleConnected ? "hover:bg-green-50" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200"}`,
4140
+ children: /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", children: [
4141
+ /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4142
+ /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4143
+ /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4144
+ /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: googleConnected ? "#16a34a" : "#9ca3af" })
4145
+ ] })
3192
4146
  }
3193
- )
3194
- ]
3195
- }
3196
- ),
3197
- /* @__PURE__ */ jsxs(
3198
- "button",
3199
- {
3200
- "data-menu-toggle": true,
3201
- onClick: () => setMenuOpen((prev) => !prev),
3202
- title: menuOpen ? "Close menu" : "Open menu",
3203
- className: `group/erp relative flex items-center gap-1.5 rounded-lg px-4 py-2 text-xs font-medium border overflow-hidden transition-all ${isVerticalTaskbar ? "w-full" : "min-w-[140px]"} ${menuOpen ? "bg-gray-200/40 border-gray-300/40 text-gray-800" : "bg-gray-50/40 border-gray-200/40 text-gray-600 hover:text-gray-800"}`,
3204
- style: { transition: "box-shadow 0.3s, border-color 0.3s" },
3205
- onMouseMove: (e) => {
3206
- const r = e.currentTarget.getBoundingClientRect();
3207
- e.currentTarget.style.setProperty("--mx", `${e.clientX - r.left}px`);
3208
- e.currentTarget.style.setProperty("--my", `${e.clientY - r.top}px`);
3209
- },
3210
- onMouseEnter: (e) => {
3211
- e.currentTarget.style.boxShadow = "0 0 15px rgba(255,255,255,0.2), 0 0 30px rgba(255,255,255,0.1)";
3212
- e.currentTarget.style.borderColor = "rgba(255,255,255,0.4)";
3213
- },
3214
- onMouseLeave: (e) => {
3215
- e.currentTarget.style.boxShadow = "";
3216
- e.currentTarget.style.borderColor = "";
3217
- },
3218
- children: [
4147
+ ),
4148
+ notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications, popDirection: taskbarPosition === "right" ? "left" : "right" })
4149
+ ] }) })
4150
+ ) : (
4151
+ /* Horizontal: icons then clock */
4152
+ /* @__PURE__ */ jsxs(Fragment, { children: [
4153
+ notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications }),
3219
4154
  /* @__PURE__ */ jsx(
3220
- "span",
4155
+ "button",
3221
4156
  {
3222
- className: "absolute inset-0 opacity-0 group-hover/erp:opacity-100 transition-opacity duration-200 pointer-events-none",
3223
- style: { background: "radial-gradient(circle 60px at var(--mx, 50%) var(--my, 50%), rgba(255,255,255,0.25) 0%, transparent 100%)" }
4157
+ onClick: () => setGoogleConnectOpen(true),
4158
+ title: googleConnected ? "Google Connected" : "Connect Google",
4159
+ className: `shrink-0 rounded-md p-2 transition-colors ${googleConnected ? "hover:bg-green-50" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200"}`,
4160
+ children: /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", children: [
4161
+ /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4162
+ /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4163
+ /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
4164
+ /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: googleConnected ? "#16a34a" : "#9ca3af" })
4165
+ ] })
3224
4166
  }
3225
4167
  ),
3226
- productIcon && /* @__PURE__ */ jsx("img", { src: productIcon, alt: "", className: "relative z-10 h-3.5 w-3.5 shrink-0 opacity-60" }),
3227
- /* @__PURE__ */ jsx("span", { className: "relative z-10 truncate", children: productName })
3228
- ]
3229
- }
3230
- )
3231
- ] }),
3232
- /* @__PURE__ */ jsx("div", { className: isVerticalTaskbar ? "h-px w-6 bg-gray-300 my-1" : "w-px h-6 bg-gray-300 mx-1" }),
3233
- /* @__PURE__ */ jsx("div", { id: "taskbar-windows", className: `flex-1 flex ${isVerticalTaskbar ? "flex-col items-center gap-1 min-h-0 overflow-y-auto w-full" : "items-center gap-1.5 min-w-0 overflow-x-auto"}` }),
3234
- /* @__PURE__ */ jsx("div", { className: isVerticalTaskbar ? "h-px w-6 bg-gray-300 my-1" : "w-px h-6 bg-gray-300 mx-1" }),
3235
- isVerticalTaskbar ? (
3236
- /* Vertical: clock + bell + google evenly spaced in a row */
3237
- /* @__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: [
3238
- /* @__PURE__ */ jsx(TaskbarClock, {}),
3239
- /* @__PURE__ */ jsx(
3240
- "button",
3241
- {
3242
- onClick: () => setGoogleConnectOpen(true),
3243
- title: googleConnected ? "Google Connected" : "Connect Google",
3244
- className: `shrink-0 rounded-md p-1.5 transition-colors ${googleConnected ? "hover:bg-green-50" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200"}`,
3245
- children: /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", children: [
3246
- /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3247
- /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3248
- /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3249
- /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: googleConnected ? "#16a34a" : "#9ca3af" })
3250
- ] })
3251
- }
3252
- ),
3253
- notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications, popDirection: taskbarPosition === "right" ? "left" : "right" })
3254
- ] }) })
3255
- ) : (
3256
- /* Horizontal: icons then clock */
3257
- /* @__PURE__ */ jsxs(Fragment, { children: [
3258
- notifications && /* @__PURE__ */ jsx(NotificationBell, { ...notifications }),
3259
- /* @__PURE__ */ jsx(
3260
- "button",
3261
- {
3262
- onClick: () => setGoogleConnectOpen(true),
3263
- title: googleConnected ? "Google Connected" : "Connect Google",
3264
- className: `shrink-0 rounded-md p-2 transition-colors ${googleConnected ? "hover:bg-green-50" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200"}`,
3265
- children: /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", children: [
3266
- /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3267
- /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3268
- /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: googleConnected ? "#16a34a" : "#9ca3af" }),
3269
- /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: googleConnected ? "#16a34a" : "#9ca3af" })
3270
- ] })
3271
- }
3272
- ),
3273
- /* @__PURE__ */ jsx(TaskbarClock, {})
3274
- ] })
3275
- )
3276
- ]
3277
- }
3278
- ),
4168
+ /* @__PURE__ */ jsx(TaskbarClock, {})
4169
+ ] })
4170
+ )
4171
+ ]
4172
+ }
4173
+ )
4174
+ ] });
4175
+ })(),
3279
4176
  taskbarMenu && /* @__PURE__ */ jsx(
3280
4177
  TaskbarContextMenu,
3281
4178
  {