react-os-shell 0.2.1 → 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.
- package/dist/index.js +133 -110
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PAC
|
|
|
8
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, useIsMobile, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons, ModalActions, useModalActive, subscribeMobileMode, getMobileMode,
|
|
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
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
14
|
import { createContext, useState, useRef, useEffect, useCallback, useLayoutEffect, useContext, isValidElement, cloneElement, useSyncExternalStore, useMemo, Suspense } from 'react';
|
|
@@ -2794,6 +2794,28 @@ function StartMenu({
|
|
|
2794
2794
|
var MOBILE_WIDGET_ORDER_KEY = "erp_mobile_widget_order";
|
|
2795
2795
|
var MOBILE_HOME_ORDER_KEY = "erp_mobile_home_order";
|
|
2796
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
|
+
}
|
|
2797
2819
|
function loadOrder(key) {
|
|
2798
2820
|
try {
|
|
2799
2821
|
const raw = localStorage.getItem(key);
|
|
@@ -2811,7 +2833,6 @@ function saveOrder(key, order) {
|
|
|
2811
2833
|
} catch {
|
|
2812
2834
|
}
|
|
2813
2835
|
}
|
|
2814
|
-
var FALLBACK_FOLDER_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 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776" }) });
|
|
2815
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" }) });
|
|
2816
2837
|
function sizeIcon(node, fallback, sizeClass = "h-10 w-10") {
|
|
2817
2838
|
if (!node) return fallback;
|
|
@@ -2822,6 +2843,27 @@ function sizeIcon(node, fallback, sizeClass = "h-10 w-10") {
|
|
|
2822
2843
|
}
|
|
2823
2844
|
return node;
|
|
2824
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
|
+
}
|
|
2825
2867
|
function MobileHome({
|
|
2826
2868
|
navSections: navSections2,
|
|
2827
2869
|
navIcons: navIcons2,
|
|
@@ -2943,7 +2985,7 @@ function MobileHome({
|
|
|
2943
2985
|
if (icon.kind === "app") onOpenApp(icon.route);
|
|
2944
2986
|
else setSelectedFolder(icon.section);
|
|
2945
2987
|
};
|
|
2946
|
-
const [widgetOrder,
|
|
2988
|
+
const [widgetOrder, _setWidgetOrder] = useState(() => loadOrder(MOBILE_WIDGET_ORDER_KEY));
|
|
2947
2989
|
const widgetWindows = useMemo(() => {
|
|
2948
2990
|
const widgets = openWindows.filter((w) => {
|
|
2949
2991
|
if (!w.route) return false;
|
|
@@ -2963,22 +3005,10 @@ function MobileHome({
|
|
|
2963
3005
|
...visibleRoutes.filter((r) => !widgetOrder.includes(r))
|
|
2964
3006
|
];
|
|
2965
3007
|
if (next.length !== widgetOrder.length || next.some((r, i) => r !== widgetOrder[i])) {
|
|
2966
|
-
|
|
3008
|
+
_setWidgetOrder(next);
|
|
2967
3009
|
saveOrder(MOBILE_WIDGET_ORDER_KEY, next);
|
|
2968
3010
|
}
|
|
2969
3011
|
}, [widgetWindows, widgetOrder]);
|
|
2970
|
-
const moveWidget = (route, dir) => {
|
|
2971
|
-
setWidgetOrder((prev) => {
|
|
2972
|
-
const i = prev.indexOf(route);
|
|
2973
|
-
if (i === -1) return prev;
|
|
2974
|
-
const j = i + dir;
|
|
2975
|
-
if (j < 0 || j >= prev.length) return prev;
|
|
2976
|
-
const next = prev.slice();
|
|
2977
|
-
[next[i], next[j]] = [next[j], next[i]];
|
|
2978
|
-
saveOrder(MOBILE_WIDGET_ORDER_KEY, next);
|
|
2979
|
-
return next;
|
|
2980
|
-
});
|
|
2981
|
-
};
|
|
2982
3012
|
const openCountByRoute = useMemo(() => {
|
|
2983
3013
|
const map = /* @__PURE__ */ new Map();
|
|
2984
3014
|
for (const w of openWindows) {
|
|
@@ -2993,79 +3023,56 @@ function MobileHome({
|
|
|
2993
3023
|
};
|
|
2994
3024
|
const draggedIcon = dragId ? homeIcons.find((i) => i.id === dragId) : null;
|
|
2995
3025
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2996
|
-
/* @__PURE__ */ jsxs(
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
onPointerCancel: cancelLongPress,
|
|
3047
|
-
onPointerLeave: cancelLongPress,
|
|
3048
|
-
onClick: () => handleIconClick(icon),
|
|
3049
|
-
style: { touchAction: "none", visibility: isBeingDragged ? "hidden" : "visible" },
|
|
3050
|
-
className: `flex flex-col items-center gap-1 py-1 rounded-lg active:bg-white/40 ${dragId && !isBeingDragged ? "transition-transform" : ""}`,
|
|
3051
|
-
children: [
|
|
3052
|
-
/* @__PURE__ */ jsxs(
|
|
3053
|
-
"span",
|
|
3054
|
-
{
|
|
3055
|
-
className: `relative h-[72px] w-[72px] rounded-2xl flex items-center justify-center shadow-sm border ${isFolder ? "bg-white/70 backdrop-blur border-white/40 text-blue-700" : "bg-white/85 backdrop-blur border-white/40 text-gray-800"}`,
|
|
3056
|
-
children: [
|
|
3057
|
-
isFolder ? sizeIcon(sectionIcons2[icon.label], FALLBACK_FOLDER_ICON) : sizeIcon(navIcons2[icon.route], FALLBACK_APP_ICON),
|
|
3058
|
-
openCount > 0 && (isFolder ? /* @__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: openCount }) : /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-blue-500 border-2 border-white" }))
|
|
3059
|
-
]
|
|
3060
|
-
}
|
|
3061
|
-
),
|
|
3062
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-sm truncate w-full text-center", children: icon.label })
|
|
3063
|
-
]
|
|
3064
|
-
},
|
|
3065
|
-
icon.id
|
|
3066
|
-
);
|
|
3067
|
-
}) }) })
|
|
3068
|
-
] }),
|
|
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
|
+
),
|
|
3069
3076
|
draggedIcon && dragPos && /* @__PURE__ */ jsx(
|
|
3070
3077
|
"div",
|
|
3071
3078
|
{
|
|
@@ -3075,15 +3082,9 @@ function MobileHome({
|
|
|
3075
3082
|
top: dragPos.y - dragOffsetRef.current.y,
|
|
3076
3083
|
transform: "scale(1.12)"
|
|
3077
3084
|
},
|
|
3078
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-1", children: [
|
|
3079
|
-
/* @__PURE__ */ jsx(
|
|
3080
|
-
|
|
3081
|
-
{
|
|
3082
|
-
className: `relative h-[72px] w-[72px] rounded-2xl flex items-center justify-center shadow-2xl border ${draggedIcon.kind === "folder" ? "bg-white backdrop-blur border-white/40 text-blue-700" : "bg-white backdrop-blur border-white/40 text-gray-800"}`,
|
|
3083
|
-
children: draggedIcon.kind === "folder" ? sizeIcon(sectionIcons2[draggedIcon.label], FALLBACK_FOLDER_ICON) : sizeIcon(navIcons2[draggedIcon.route], FALLBACK_APP_ICON)
|
|
3084
|
-
}
|
|
3085
|
-
),
|
|
3086
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-md truncate max-w-[80px] text-center", children: draggedIcon.label })
|
|
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 })
|
|
3087
3088
|
] })
|
|
3088
3089
|
}
|
|
3089
3090
|
),
|
|
@@ -3119,15 +3120,25 @@ function FolderPopup({
|
|
|
3119
3120
|
return /* @__PURE__ */ jsxs(
|
|
3120
3121
|
"div",
|
|
3121
3122
|
{
|
|
3122
|
-
className: "fixed inset-0 z-[210] flex flex-col items-center justify-center px-6 bg-black/45 backdrop-blur-xl",
|
|
3123
|
-
style: {
|
|
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
|
+
},
|
|
3124
3130
|
onClick: onClose,
|
|
3125
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
|
+
` }),
|
|
3126
3136
|
/* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-white drop-shadow-md mb-4 self-start", children: folder.label }),
|
|
3127
3137
|
/* @__PURE__ */ jsx(
|
|
3128
3138
|
"div",
|
|
3129
3139
|
{
|
|
3130
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)" },
|
|
3131
3142
|
onClick: (e) => e.stopPropagation(),
|
|
3132
3143
|
children: /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-5", children: [
|
|
3133
3144
|
openInFolder.length > 0 && /* @__PURE__ */ jsxs("section", { className: "mb-4", children: [
|
|
@@ -3138,7 +3149,7 @@ function FolderPopup({
|
|
|
3138
3149
|
onClick: () => onActivateWindow(w.id),
|
|
3139
3150
|
className: "flex items-center gap-2 p-2 rounded-lg bg-white/15 active:bg-white/25 text-left",
|
|
3140
3151
|
children: [
|
|
3141
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
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") }),
|
|
3142
3153
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-white truncate flex-1", children: w.label })
|
|
3143
3154
|
]
|
|
3144
3155
|
},
|
|
@@ -3153,10 +3164,7 @@ function FolderPopup({
|
|
|
3153
3164
|
onClick: () => onOpenApp(item.to),
|
|
3154
3165
|
className: "flex flex-col items-center gap-1.5 p-1 rounded-lg active:bg-white/15",
|
|
3155
3166
|
children: [
|
|
3156
|
-
/* @__PURE__ */
|
|
3157
|
-
sizeIcon(navIcons2[item.to], FALLBACK_APP_ICON),
|
|
3158
|
-
openCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-blue-500 border-2 border-white" })
|
|
3159
|
-
] }),
|
|
3167
|
+
/* @__PURE__ */ jsx(AppTile, { route: item.to, icon: navIcons2[item.to], badge: openCount > 0 }),
|
|
3160
3168
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-white drop-shadow-sm truncate w-full text-center", children: item.label })
|
|
3161
3169
|
]
|
|
3162
3170
|
},
|
|
@@ -3383,6 +3391,14 @@ function MobileShell({
|
|
|
3383
3391
|
const mode = useSyncExternalStore(subscribeMobileMode, getMobileMode);
|
|
3384
3392
|
const [sheet, setSheet] = useState(null);
|
|
3385
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]);
|
|
3386
3402
|
const prevOpenCountRef = useRef(openWindows.length);
|
|
3387
3403
|
useEffect(() => {
|
|
3388
3404
|
if (openWindows.length < prevOpenCountRef.current && mode === "app") {
|
|
@@ -3429,7 +3445,7 @@ function MobileShell({
|
|
|
3429
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(
|
|
3430
3446
|
MobileSwitcher,
|
|
3431
3447
|
{
|
|
3432
|
-
windows:
|
|
3448
|
+
windows: switcherWindows,
|
|
3433
3449
|
onActivate: handleActivateWindow,
|
|
3434
3450
|
onClose: (id) => closeEntity(id)
|
|
3435
3451
|
}
|
|
@@ -3451,7 +3467,7 @@ function MobileShell({
|
|
|
3451
3467
|
MobileBottomNav,
|
|
3452
3468
|
{
|
|
3453
3469
|
mode,
|
|
3454
|
-
openCount:
|
|
3470
|
+
openCount: switcherWindows.length,
|
|
3455
3471
|
unreadCount,
|
|
3456
3472
|
showNotifications: !!notifications,
|
|
3457
3473
|
profileAvatar: profile?.avatar_url,
|
|
@@ -3482,12 +3498,19 @@ function MobileBottomNav({
|
|
|
3482
3498
|
onNotifications,
|
|
3483
3499
|
onProfile
|
|
3484
3500
|
}) {
|
|
3485
|
-
const btnClass = (active) => `flex-1 flex flex-col items-center justify-center gap-0.5 py-2 transition-colors ${active ? "text-blue-600" : "text-gray-
|
|
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"}`;
|
|
3486
3502
|
return /* @__PURE__ */ jsxs(
|
|
3487
3503
|
"nav",
|
|
3488
3504
|
{
|
|
3489
|
-
className: "fixed bottom-0 inset-x-0 z-[300] flex items-stretch
|
|
3490
|
-
style: {
|
|
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
|
+
},
|
|
3491
3514
|
children: [
|
|
3492
3515
|
/* @__PURE__ */ jsxs("button", { onClick: onHome, className: btnClass(mode === "home"), "aria-label": "Home", children: [
|
|
3493
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" }) }),
|