react-os-shell 0.2.63 → 0.2.66
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/{Browser-F7TJRHMK.js → Browser-QPQX2OXO.js} +3 -3
- package/dist/{Browser-F7TJRHMK.js.map → Browser-QPQX2OXO.js.map} +1 -1
- package/dist/{Calculator-FO3NUVCK.js → Calculator-ZFY3ZB5X.js} +4 -4
- package/dist/{Calculator-FO3NUVCK.js.map → Calculator-ZFY3ZB5X.js.map} +1 -1
- package/dist/{Calendar-ZGKMZ5TU.js → Calendar-LL5DUDDN.js} +3 -3
- package/dist/{Calendar-ZGKMZ5TU.js.map → Calendar-LL5DUDDN.js.map} +1 -1
- package/dist/{CurrencyConverter-IMHQD6XV.js → CurrencyConverter-JGAC32DB.js} +4 -4
- package/dist/{CurrencyConverter-IMHQD6XV.js.map → CurrencyConverter-JGAC32DB.js.map} +1 -1
- package/dist/{Documents-PHVXWN4S.js → Documents-XW7O22QF.js} +3 -3
- package/dist/{Documents-PHVXWN4S.js.map → Documents-XW7O22QF.js.map} +1 -1
- package/dist/{Email-VXTFMSS5.js → Email-PCBQUXE4.js} +3 -3
- package/dist/{Email-VXTFMSS5.js.map → Email-PCBQUXE4.js.map} +1 -1
- package/dist/Files-UATWOZM3.js +12 -0
- package/dist/{Files-YO5YOKD7.js.map → Files-UATWOZM3.js.map} +1 -1
- package/dist/{Minesweeper-PX4DUPOE.js → Minesweeper-KBZXSRJF.js} +3 -3
- package/dist/{Minesweeper-PX4DUPOE.js.map → Minesweeper-KBZXSRJF.js.map} +1 -1
- package/dist/{Notepad-LFCZD2Y3.js → Notepad-XPSVB6GJ.js} +3 -3
- package/dist/{Notepad-LFCZD2Y3.js.map → Notepad-XPSVB6GJ.js.map} +1 -1
- package/dist/{PomodoroTimer-7Y36AEWF.js → PomodoroTimer-7R2GTFUR.js} +4 -4
- package/dist/{PomodoroTimer-7Y36AEWF.js.map → PomodoroTimer-7R2GTFUR.js.map} +1 -1
- package/dist/Preview-OAGLCTU6.js +8 -0
- package/dist/{Preview-UMGXEYCV.js.map → Preview-OAGLCTU6.js.map} +1 -1
- package/dist/{Spreadsheet-L2DOK2JK.js → Spreadsheet-OTOBE6YI.js} +4 -4
- package/dist/{Spreadsheet-L2DOK2JK.js.map → Spreadsheet-OTOBE6YI.js.map} +1 -1
- package/dist/{Weather-FDL7CFDL.js → Weather-DLZUHBXU.js} +4 -4
- package/dist/{Weather-FDL7CFDL.js.map → Weather-DLZUHBXU.js.map} +1 -1
- package/dist/{WorldClock-4PCYEMLF.js → WorldClock-WVHQD5K7.js} +4 -4
- package/dist/{WorldClock-4PCYEMLF.js.map → WorldClock-WVHQD5K7.js.map} +1 -1
- package/dist/apps/index.js +19 -18
- package/dist/apps/index.js.map +1 -1
- package/dist/{chunk-6JAAM5TA.js → chunk-4EMPRKHL.js} +11 -19
- package/dist/chunk-4EMPRKHL.js.map +1 -0
- package/dist/{chunk-ONQJGZCL.js → chunk-DVS3TOYB.js} +15 -15
- package/dist/chunk-DVS3TOYB.js.map +1 -0
- package/dist/{chunk-FJ6NSPYF.js → chunk-JRUZT46J.js} +3 -3
- package/dist/{chunk-FJ6NSPYF.js.map → chunk-JRUZT46J.js.map} +1 -1
- package/dist/{chunk-E7ZO44KU.js → chunk-XE4FDK4O.js} +3 -3
- package/dist/{chunk-E7ZO44KU.js.map → chunk-XE4FDK4O.js.map} +1 -1
- package/dist/chunk-XWSXCBP2.js +46 -0
- package/dist/chunk-XWSXCBP2.js.map +1 -0
- package/dist/{chunk-TRYZ75AV.js → chunk-ZAOJ5JY5.js} +3 -3
- package/dist/{chunk-TRYZ75AV.js.map → chunk-ZAOJ5JY5.js.map} +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +300 -138
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/Files-YO5YOKD7.js +0 -9
- package/dist/Preview-UMGXEYCV.js +0 -8
- package/dist/chunk-6JAAM5TA.js.map +0 -1
- package/dist/chunk-ONQJGZCL.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -606,6 +606,8 @@ interface ChangelogEntry {
|
|
|
606
606
|
changes: string[];
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
type PreviewFileKind = 'pdf' | 'dxf' | '3d' | 'image' | 'csv';
|
|
610
|
+
|
|
609
611
|
interface DesktopItem {
|
|
610
612
|
entityType: string;
|
|
611
613
|
entityId: string;
|
|
@@ -613,6 +615,10 @@ interface DesktopItem {
|
|
|
613
615
|
x?: number;
|
|
614
616
|
y?: number;
|
|
615
617
|
folderId?: string;
|
|
618
|
+
folderX?: number;
|
|
619
|
+
folderY?: number;
|
|
620
|
+
filePath?: string;
|
|
621
|
+
fileKind?: PreviewFileKind;
|
|
616
622
|
}
|
|
617
623
|
interface DesktopFolder {
|
|
618
624
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -5,18 +5,20 @@ import { subscribePomo, getPomoSnapshot } from './chunk-MK3HLUO4.js';
|
|
|
5
5
|
import { useGoogleAuth } from './chunk-MVWEL34Y.js';
|
|
6
6
|
import { useShellPrefs } from './chunk-36VM54SC.js';
|
|
7
7
|
export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
|
|
8
|
+
import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-XWSXCBP2.js';
|
|
8
9
|
import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
|
|
9
|
-
import { setPdfPreview } from './chunk-
|
|
10
|
+
import { setPdfPreview } from './chunk-ZAOJ5JY5.js';
|
|
10
11
|
import './chunk-KUIPWCTJ.js';
|
|
11
12
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
12
13
|
export { toast_default as toast } from './chunk-WIJ45SYD.js';
|
|
13
|
-
import
|
|
14
|
-
export { ShellAuthProvider, setShellAuthBridge, useShellAuth } from './chunk-ADJ3CERD.js';
|
|
14
|
+
import './chunk-JRUZT46J.js';
|
|
15
15
|
export { EditableGrid } from './chunk-GP4Y3VCB.js';
|
|
16
|
-
import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, useIsMobile, ModalActions, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-
|
|
17
|
-
export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-
|
|
16
|
+
import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, useIsMobile, ModalActions, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-DVS3TOYB.js';
|
|
17
|
+
export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-DVS3TOYB.js';
|
|
18
18
|
import { confirm } from './chunk-PLGHQ7QW.js';
|
|
19
19
|
export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-PLGHQ7QW.js';
|
|
20
|
+
import { useAuth } from './chunk-ADJ3CERD.js';
|
|
21
|
+
export { ShellAuthProvider, setShellAuthBridge, useShellAuth } from './chunk-ADJ3CERD.js';
|
|
20
22
|
import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons } from './chunk-SSA762W5.js';
|
|
21
23
|
export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle, setShellNavIcons } from './chunk-SSA762W5.js';
|
|
22
24
|
import { createContext, lazy, useState, useRef, useEffect, useCallback, useLayoutEffect, useContext, Suspense, isValidElement, cloneElement, useSyncExternalStore, useMemo } from 'react';
|
|
@@ -913,7 +915,7 @@ function StatusBadge({ status }) {
|
|
|
913
915
|
}
|
|
914
916
|
|
|
915
917
|
// src/version.ts
|
|
916
|
-
var VERSION = "0.2.
|
|
918
|
+
var VERSION = "0.2.66" ;
|
|
917
919
|
var APP_VERSION = VERSION;
|
|
918
920
|
|
|
919
921
|
// src/changelog.ts
|
|
@@ -1010,6 +1012,45 @@ var ENTITY_ICONS = {
|
|
|
1010
1012
|
proposal: "PR",
|
|
1011
1013
|
folder: "FLD"
|
|
1012
1014
|
};
|
|
1015
|
+
var PREVIEW_FILE_CODES = {
|
|
1016
|
+
pdf: "PDF",
|
|
1017
|
+
dxf: "DXF",
|
|
1018
|
+
"3d": "STP",
|
|
1019
|
+
image: "IMG",
|
|
1020
|
+
csv: "CSV"
|
|
1021
|
+
};
|
|
1022
|
+
var PREVIEW_FILE_COLORS = {
|
|
1023
|
+
pdf: "text-red-600",
|
|
1024
|
+
dxf: "text-blue-600",
|
|
1025
|
+
"3d": "text-purple-600",
|
|
1026
|
+
image: "text-emerald-600",
|
|
1027
|
+
csv: "text-green-600"
|
|
1028
|
+
};
|
|
1029
|
+
var DOCUMENTS_FOLDER_ID = "documents";
|
|
1030
|
+
var DOCUMENTS_FOLDER_NAME = "Documents";
|
|
1031
|
+
function FileIconTile({ entityType, isSelected, entityId, label, fileKind }) {
|
|
1032
|
+
const isPreviewFile = entityType === "preview-file" && fileKind;
|
|
1033
|
+
const previewColor2 = isPreviewFile ? PREVIEW_FILE_COLORS[fileKind] : null;
|
|
1034
|
+
const previewCode = isPreviewFile ? PREVIEW_FILE_CODES[fileKind] : null;
|
|
1035
|
+
if (entityType === "folder") {
|
|
1036
|
+
return /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: /* @__PURE__ */ jsxs("svg", { className: "h-12 w-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]", viewBox: "0 0 48 48", children: [
|
|
1037
|
+
/* @__PURE__ */ jsx("path", { d: "M6 12a4 4 0 014-4h10l4 4h14a4 4 0 014 4v20a4 4 0 01-4 4H10a4 4 0 01-4-4V12z", fill: "white", stroke: "#eab308", strokeWidth: "2", strokeLinejoin: "round" }),
|
|
1038
|
+
/* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
|
|
1039
|
+
] }) });
|
|
1040
|
+
}
|
|
1041
|
+
if (entityType === "page") {
|
|
1042
|
+
const icon = label && navIcons[label] || (entityId ? navIcons[entityId] : void 0);
|
|
1043
|
+
return /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: icon && isValidElement(icon) ? cloneElement(icon, { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]" }) : /* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6z" }) }) });
|
|
1044
|
+
}
|
|
1045
|
+
return /* @__PURE__ */ jsxs("div", { className: `w-12 h-12 relative flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: [
|
|
1046
|
+
/* @__PURE__ */ jsxs("svg", { className: `w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${previewColor2 ?? ENTITY_ICON_COLORS[entityType] ?? "text-gray-500"}`, viewBox: "0 0 40 48", fill: "none", children: [
|
|
1047
|
+
/* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", fill: "white", fillOpacity: "0.92" }),
|
|
1048
|
+
/* @__PURE__ */ jsx("path", { d: "M26 0l10 10H30a4 4 0 01-4-4V0z", fill: "currentColor", fillOpacity: "0.2" }),
|
|
1049
|
+
/* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.5" })
|
|
1050
|
+
] }),
|
|
1051
|
+
/* @__PURE__ */ jsx("span", { className: `absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${previewColor2 ?? ENTITY_ICON_COLORS[entityType] ?? "text-gray-600"}`, children: previewCode ?? ENTITY_ICONS[entityType] ?? entityType.slice(0, 3).toUpperCase() })
|
|
1052
|
+
] });
|
|
1053
|
+
}
|
|
1013
1054
|
var GRID = 90;
|
|
1014
1055
|
function snapToGrid(x, y) {
|
|
1015
1056
|
return { x: Math.round(x / GRID) * GRID, y: Math.round(y / GRID) * GRID };
|
|
@@ -1021,13 +1062,35 @@ function DesktopHostProvider({ value, children }) {
|
|
|
1021
1062
|
function useDesktopHost() {
|
|
1022
1063
|
return useContext(DesktopHostContext);
|
|
1023
1064
|
}
|
|
1024
|
-
|
|
1065
|
+
var FOLDER_GRID = 90;
|
|
1066
|
+
var FOLDER_ITEM_H = 80;
|
|
1067
|
+
var FOLDER_PAD = 12;
|
|
1068
|
+
function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onSetFolderPosition, onDragOutToDesktop }) {
|
|
1025
1069
|
const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
|
|
1026
1070
|
const [rubber, setRubber] = useState(null);
|
|
1027
1071
|
const didDragRubber = useRef(false);
|
|
1028
1072
|
const bodyRef = useRef(null);
|
|
1029
|
-
const [
|
|
1030
|
-
const
|
|
1073
|
+
const [bodyWidth, setBodyWidth] = useState(800);
|
|
1074
|
+
const setDragOutsideClass = (on) => {
|
|
1075
|
+
const el = bodyRef.current;
|
|
1076
|
+
if (!el) return;
|
|
1077
|
+
el.style.outline = on ? "2px dashed rgb(96 165 250 / 0.6)" : "";
|
|
1078
|
+
el.style.outlineOffset = on ? "-2px" : "";
|
|
1079
|
+
};
|
|
1080
|
+
useEffect(() => {
|
|
1081
|
+
const el = bodyRef.current;
|
|
1082
|
+
if (!el) return;
|
|
1083
|
+
const update = () => setBodyWidth(el.clientWidth);
|
|
1084
|
+
update();
|
|
1085
|
+
const ro = new ResizeObserver(update);
|
|
1086
|
+
ro.observe(el);
|
|
1087
|
+
return () => ro.disconnect();
|
|
1088
|
+
}, []);
|
|
1089
|
+
const cols = Math.max(1, Math.floor((bodyWidth - FOLDER_PAD) / FOLDER_GRID));
|
|
1090
|
+
const getItemFolderPos = (item, idx) => {
|
|
1091
|
+
if (item.folderX != null && item.folderY != null) return { x: item.folderX, y: item.folderY };
|
|
1092
|
+
return { x: FOLDER_PAD + idx % cols * FOLDER_GRID, y: FOLDER_PAD + Math.floor(idx / cols) * FOLDER_GRID };
|
|
1093
|
+
};
|
|
1031
1094
|
const toggleSelect = (i, e) => {
|
|
1032
1095
|
e.stopPropagation();
|
|
1033
1096
|
if (e.shiftKey || e.metaKey || e.ctrlKey) {
|
|
@@ -1036,53 +1099,57 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
|
|
|
1036
1099
|
next.has(i) ? next.delete(i) : next.add(i);
|
|
1037
1100
|
return next;
|
|
1038
1101
|
});
|
|
1039
|
-
} else {
|
|
1102
|
+
} else if (!selected.has(i)) {
|
|
1040
1103
|
setSelected(/* @__PURE__ */ new Set([i]));
|
|
1041
1104
|
}
|
|
1042
1105
|
};
|
|
1043
1106
|
const startRubber = (e) => {
|
|
1044
1107
|
if (e.button !== 0 || e.target !== bodyRef.current) return;
|
|
1045
|
-
const
|
|
1046
|
-
const
|
|
1047
|
-
const
|
|
1108
|
+
const el = bodyRef.current;
|
|
1109
|
+
const r = el.getBoundingClientRect();
|
|
1110
|
+
const x = e.clientX - r.left + el.scrollLeft;
|
|
1111
|
+
const y = e.clientY - r.top + el.scrollTop;
|
|
1048
1112
|
setRubber({ x1: x, y1: y, x2: x, y2: y });
|
|
1049
1113
|
didDragRubber.current = false;
|
|
1050
1114
|
setSelected(/* @__PURE__ */ new Set());
|
|
1051
1115
|
};
|
|
1052
1116
|
useEffect(() => {
|
|
1053
1117
|
if (!rubber) return;
|
|
1118
|
+
const computeSelection = (minX, maxX, minY, maxY) => {
|
|
1119
|
+
const next = /* @__PURE__ */ new Set();
|
|
1120
|
+
const r = bodyRef.current;
|
|
1121
|
+
if (!r) return next;
|
|
1122
|
+
const tiles = r.querySelectorAll("[data-folder-item]");
|
|
1123
|
+
const containerRect = r.getBoundingClientRect();
|
|
1124
|
+
tiles.forEach((t) => {
|
|
1125
|
+
const tr = t.getBoundingClientRect();
|
|
1126
|
+
const tx = tr.left - containerRect.left + r.scrollLeft;
|
|
1127
|
+
const ty = tr.top - containerRect.top + r.scrollTop;
|
|
1128
|
+
if (tx + tr.width > minX && tx < maxX && ty + tr.height > minY && ty < maxY) {
|
|
1129
|
+
const i = parseInt(t.getAttribute("data-folder-item") || "-1", 10);
|
|
1130
|
+
if (i >= 0) next.add(i);
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
return next;
|
|
1134
|
+
};
|
|
1054
1135
|
const move = (e) => {
|
|
1055
|
-
const
|
|
1056
|
-
if (!
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1136
|
+
const el = bodyRef.current;
|
|
1137
|
+
if (!el) return;
|
|
1138
|
+
const r = el.getBoundingClientRect();
|
|
1139
|
+
const x = e.clientX - r.left + el.scrollLeft;
|
|
1140
|
+
const y = e.clientY - r.top + el.scrollTop;
|
|
1059
1141
|
const dx = x - rubber.x1, dy = y - rubber.y1;
|
|
1060
1142
|
if (dx * dx + dy * dy > 16) didDragRubber.current = true;
|
|
1061
1143
|
setRubber((prev) => prev ? { ...prev, x2: x, y2: y } : null);
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
const maxX = Math.max(rubber.x1, rubber.x2);
|
|
1069
|
-
const minY = Math.min(rubber.y1, rubber.y2);
|
|
1070
|
-
const maxY = Math.max(rubber.y1, rubber.y2);
|
|
1071
|
-
const tiles = r.querySelectorAll("[data-folder-item]");
|
|
1072
|
-
const containerRect = r.getBoundingClientRect();
|
|
1073
|
-
tiles.forEach((t) => {
|
|
1074
|
-
const tr = t.getBoundingClientRect();
|
|
1075
|
-
const tx = tr.left - containerRect.left;
|
|
1076
|
-
const ty = tr.top - containerRect.top;
|
|
1077
|
-
if (tx + tr.width > minX && tx < maxX && ty + tr.height > minY && ty < maxY) {
|
|
1078
|
-
const i = parseInt(t.getAttribute("data-folder-item") || "-1", 10);
|
|
1079
|
-
if (i >= 0) next.add(i);
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1144
|
+
if (didDragRubber.current) {
|
|
1145
|
+
const minX = Math.min(rubber.x1, x);
|
|
1146
|
+
const maxX = Math.max(rubber.x1, x);
|
|
1147
|
+
const minY = Math.min(rubber.y1, y);
|
|
1148
|
+
const maxY = Math.max(rubber.y1, y);
|
|
1149
|
+
setSelected(computeSelection(minX, maxX, minY, maxY));
|
|
1082
1150
|
}
|
|
1083
|
-
if (didDragRubber.current) setSelected(next);
|
|
1084
|
-
setRubber(null);
|
|
1085
1151
|
};
|
|
1152
|
+
const up = () => setRubber(null);
|
|
1086
1153
|
window.addEventListener("pointermove", move);
|
|
1087
1154
|
window.addEventListener("pointerup", up);
|
|
1088
1155
|
return () => {
|
|
@@ -1090,28 +1157,75 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
|
|
|
1090
1157
|
window.removeEventListener("pointerup", up);
|
|
1091
1158
|
};
|
|
1092
1159
|
}, [rubber]);
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
const onItemDragOver = (i) => (e) => {
|
|
1099
|
-
e.preventDefault();
|
|
1100
|
-
if (dragIdx !== null && dragIdx !== i) setDropIdx(i);
|
|
1101
|
-
};
|
|
1102
|
-
const onItemDrop = (i) => (e) => {
|
|
1160
|
+
const dragEntriesRef = useRef([]);
|
|
1161
|
+
const dragStartRef = useRef(null);
|
|
1162
|
+
const startItemDrag = (i, e) => {
|
|
1163
|
+
if (e.button !== 0) return;
|
|
1164
|
+
e.stopPropagation();
|
|
1103
1165
|
e.preventDefault();
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1166
|
+
const useMulti = selected.has(i) && selected.size > 1;
|
|
1167
|
+
const idxs = useMulti ? Array.from(selected) : [i];
|
|
1168
|
+
if (!useMulti) setSelected(/* @__PURE__ */ new Set([i]));
|
|
1169
|
+
const entries = idxs.map((idx) => {
|
|
1170
|
+
const item = items[idx];
|
|
1171
|
+
const pos = getItemFolderPos(item, idx);
|
|
1172
|
+
const el = bodyRef.current?.querySelector(`[data-folder-item="${idx}"]`) ?? null;
|
|
1173
|
+
return { idx, item, origX: pos.x, origY: pos.y, el };
|
|
1174
|
+
}).filter((e2) => e2.item);
|
|
1175
|
+
dragEntriesRef.current = entries;
|
|
1176
|
+
dragStartRef.current = { clientX: e.clientX, clientY: e.clientY };
|
|
1177
|
+
setDragOutsideClass(false);
|
|
1178
|
+
let moved = false;
|
|
1179
|
+
const move = (ev) => {
|
|
1180
|
+
const start = dragStartRef.current;
|
|
1181
|
+
if (!start) return;
|
|
1182
|
+
const dx = ev.clientX - start.clientX;
|
|
1183
|
+
const dy = ev.clientY - start.clientY;
|
|
1184
|
+
if (!moved && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) moved = true;
|
|
1185
|
+
if (!moved) return;
|
|
1186
|
+
for (const entry of dragEntriesRef.current) {
|
|
1187
|
+
if (!entry.el) continue;
|
|
1188
|
+
entry.el.style.left = `${entry.origX + dx}px`;
|
|
1189
|
+
entry.el.style.top = `${entry.origY + dy}px`;
|
|
1190
|
+
entry.el.style.zIndex = "100";
|
|
1191
|
+
entry.el.style.opacity = "0.85";
|
|
1192
|
+
}
|
|
1193
|
+
const r = bodyRef.current?.getBoundingClientRect();
|
|
1194
|
+
const inside = !!r && ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top && ev.clientY <= r.bottom;
|
|
1195
|
+
setDragOutsideClass(!inside);
|
|
1196
|
+
};
|
|
1197
|
+
const up = (ev) => {
|
|
1198
|
+
window.removeEventListener("pointermove", move);
|
|
1199
|
+
window.removeEventListener("pointerup", up);
|
|
1200
|
+
const entries2 = dragEntriesRef.current;
|
|
1201
|
+
dragEntriesRef.current = [];
|
|
1202
|
+
dragStartRef.current = null;
|
|
1203
|
+
for (const entry of entries2) {
|
|
1204
|
+
if (!entry.el) continue;
|
|
1205
|
+
entry.el.style.zIndex = "";
|
|
1206
|
+
entry.el.style.opacity = "";
|
|
1207
|
+
}
|
|
1208
|
+
setDragOutsideClass(false);
|
|
1209
|
+
if (!moved) return;
|
|
1210
|
+
const r = bodyRef.current?.getBoundingClientRect();
|
|
1211
|
+
const inside = !!r && ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top && ev.clientY <= r.bottom;
|
|
1212
|
+
if (!inside) {
|
|
1213
|
+
const drops = entries2.map((e2) => ({ item: e2.item, clientX: ev.clientX, clientY: ev.clientY }));
|
|
1214
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
1215
|
+
onDragOutToDesktop(drops);
|
|
1216
|
+
} else {
|
|
1217
|
+
const updates = entries2.map((e2) => {
|
|
1218
|
+
const leftStr = e2.el?.style.left || `${e2.origX}px`;
|
|
1219
|
+
const topStr = e2.el?.style.top || `${e2.origY}px`;
|
|
1220
|
+
const x = Math.max(0, parseFloat(leftStr));
|
|
1221
|
+
const y = Math.max(0, parseFloat(topStr));
|
|
1222
|
+
return { item: e2.item, x, y };
|
|
1223
|
+
});
|
|
1224
|
+
onSetFolderPosition(updates);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
window.addEventListener("pointermove", move);
|
|
1228
|
+
window.addEventListener("pointerup", up);
|
|
1115
1229
|
};
|
|
1116
1230
|
const moveSelectedOut = () => {
|
|
1117
1231
|
if (selected.size === 0) return;
|
|
@@ -1119,6 +1233,10 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
|
|
|
1119
1233
|
setSelected(/* @__PURE__ */ new Set());
|
|
1120
1234
|
};
|
|
1121
1235
|
const folderIcon = /* @__PURE__ */ jsx("svg", { className: "h-5 w-5 text-amber-500", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M2 6a2 2 0 012-2h5l2 2h9a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" }) });
|
|
1236
|
+
const contentHeight = items.reduce((max, item, i) => {
|
|
1237
|
+
const pos = getItemFolderPos(item, i);
|
|
1238
|
+
return Math.max(max, pos.y + FOLDER_ITEM_H + FOLDER_PAD);
|
|
1239
|
+
}, 300);
|
|
1122
1240
|
return /* @__PURE__ */ jsx(Modal, { open: true, onClose, title: folder.name, icon: folderIcon, size: "lg", children: /* @__PURE__ */ jsxs(
|
|
1123
1241
|
"div",
|
|
1124
1242
|
{
|
|
@@ -1136,7 +1254,7 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
|
|
|
1136
1254
|
background: "linear-gradient(135deg, rgba(254, 243, 199, 0.55) 0%, rgba(253, 230, 138, 0.4) 50%, rgba(252, 211, 77, 0.3) 100%)"
|
|
1137
1255
|
},
|
|
1138
1256
|
children: [
|
|
1139
|
-
selected.size > 0 && /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-
|
|
1257
|
+
selected.size > 0 && /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-20 mb-2 flex items-center gap-2 px-2 py-1 rounded-md bg-white/80 backdrop-blur-sm shadow border border-gray-200 text-xs text-gray-700 w-fit", children: [
|
|
1140
1258
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
1141
1259
|
selected.size,
|
|
1142
1260
|
" selected"
|
|
@@ -1144,40 +1262,22 @@ function FolderWindow({ folder, items, onClose, onOpen, onMoveOut, onReorder })
|
|
|
1144
1262
|
/* @__PURE__ */ jsx("button", { onClick: moveSelectedOut, className: "px-2 py-0.5 rounded text-blue-600 hover:bg-blue-50", children: "Move to desktop" }),
|
|
1145
1263
|
/* @__PURE__ */ jsx("button", { onClick: () => setSelected(/* @__PURE__ */ new Set()), className: "px-2 py-0.5 rounded text-gray-500 hover:bg-gray-100", children: "Clear" })
|
|
1146
1264
|
] }),
|
|
1147
|
-
items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 text-center py-8 italic", children: "Folder is empty. Drag documents here." }) : /* @__PURE__ */ jsx("div", { className: "
|
|
1265
|
+
items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 text-center py-8 italic", children: "Folder is empty. Drag documents here." }) : /* @__PURE__ */ jsx("div", { className: "relative", style: { height: contentHeight }, children: items.map((item, i) => {
|
|
1148
1266
|
const isSelected = selected.has(i);
|
|
1149
|
-
const
|
|
1150
|
-
return /* @__PURE__ */
|
|
1267
|
+
const pos = getItemFolderPos(item, i);
|
|
1268
|
+
return /* @__PURE__ */ jsx(
|
|
1151
1269
|
"div",
|
|
1152
1270
|
{
|
|
1153
1271
|
"data-folder-item": i,
|
|
1154
|
-
|
|
1155
|
-
onDragStart: onItemDragStart(i),
|
|
1156
|
-
onDragOver: onItemDragOver(i),
|
|
1157
|
-
onDrop: onItemDrop(i),
|
|
1158
|
-
onDragEnd: () => {
|
|
1159
|
-
setDragIdx(null);
|
|
1160
|
-
setDropIdx(null);
|
|
1161
|
-
},
|
|
1272
|
+
onPointerDown: (e) => startItemDrag(i, e),
|
|
1162
1273
|
onClick: (e) => toggleSelect(i, e),
|
|
1163
1274
|
onDoubleClick: () => onOpen(item),
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
e.stopPropagation();
|
|
1171
|
-
onMoveOut([item]);
|
|
1172
|
-
},
|
|
1173
|
-
title: "Move to desktop",
|
|
1174
|
-
className: "absolute -top-1 -right-1 h-5 w-5 rounded-full bg-gray-200 text-gray-500 flex items-center justify-center text-[10px] opacity-0 group-hover:opacity-100 transition-opacity hover:bg-red-100 hover:text-red-600 shadow-sm z-10",
|
|
1175
|
-
children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3" }) })
|
|
1176
|
-
}
|
|
1177
|
-
),
|
|
1178
|
-
/* @__PURE__ */ jsx("div", { className: `w-12 h-12 rounded-lg bg-white shadow flex items-center justify-center text-xs font-bold ${ENTITY_ICON_COLORS[item.entityType] || "text-gray-600"}`, children: ENTITY_ICONS[item.entityType] || item.entityType.slice(0, 3).toUpperCase() }),
|
|
1179
|
-
/* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight truncate w-full ${isSelected ? "text-blue-900" : "text-gray-700"}`, children: item.label })
|
|
1180
|
-
]
|
|
1275
|
+
style: { position: "absolute", left: pos.x, top: pos.y },
|
|
1276
|
+
className: "cursor-default select-none",
|
|
1277
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
|
|
1278
|
+
/* @__PURE__ */ jsx(FileIconTile, { entityType: item.entityType, isSelected, entityId: item.entityId, label: item.label, fileKind: item.fileKind }),
|
|
1279
|
+
/* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight truncate w-full ${isSelected ? "text-blue-900 bg-blue-200/60 rounded px-1" : "text-gray-700"}`, children: item.label })
|
|
1280
|
+
] })
|
|
1181
1281
|
},
|
|
1182
1282
|
`${item.entityType}-${item.entityId}-${i}`
|
|
1183
1283
|
);
|
|
@@ -1321,6 +1421,32 @@ function Desktop({ profile }) {
|
|
|
1321
1421
|
if (host.saveSnap) host.saveSnap(v);
|
|
1322
1422
|
else saveShellPrefs({ desktop_snap: v });
|
|
1323
1423
|
}, [host, saveShellPrefs]);
|
|
1424
|
+
const previewStateRef = useRef({ folders, favDocs, saveFolders, saveDocs });
|
|
1425
|
+
previewStateRef.current = { folders, favDocs, saveFolders, saveDocs };
|
|
1426
|
+
useEffect(() => {
|
|
1427
|
+
const handler = (e) => {
|
|
1428
|
+
const detail = e.detail;
|
|
1429
|
+
if (!detail?.filePath) return;
|
|
1430
|
+
const { folders: fs, favDocs: docs, saveFolders: sf, saveDocs: sd } = previewStateRef.current;
|
|
1431
|
+
if (!fs.some((f) => f.id === DOCUMENTS_FOLDER_ID)) {
|
|
1432
|
+
sf([...fs, { id: DOCUMENTS_FOLDER_ID, name: DOCUMENTS_FOLDER_NAME }]);
|
|
1433
|
+
}
|
|
1434
|
+
const deduped = docs.filter(
|
|
1435
|
+
(d) => !(d.entityType === "preview-file" && d.filePath === detail.filePath)
|
|
1436
|
+
);
|
|
1437
|
+
const next = {
|
|
1438
|
+
entityType: "preview-file",
|
|
1439
|
+
entityId: detail.filePath,
|
|
1440
|
+
label: detail.filename,
|
|
1441
|
+
filePath: detail.filePath,
|
|
1442
|
+
fileKind: detail.kind,
|
|
1443
|
+
folderId: DOCUMENTS_FOLDER_ID
|
|
1444
|
+
};
|
|
1445
|
+
sd([next, ...deduped]);
|
|
1446
|
+
};
|
|
1447
|
+
window.addEventListener(PREVIEW_OPENED_EVENT, handler);
|
|
1448
|
+
return () => window.removeEventListener(PREVIEW_OPENED_EVENT, handler);
|
|
1449
|
+
}, []);
|
|
1324
1450
|
const getDefaultPos = (idx) => {
|
|
1325
1451
|
const col = Math.floor(idx / 8);
|
|
1326
1452
|
const row = idx % 8;
|
|
@@ -1451,7 +1577,7 @@ function Desktop({ profile }) {
|
|
|
1451
1577
|
const desktopIdx = favDocs.indexOf(desktopItems[move2.entry.idx]);
|
|
1452
1578
|
if (desktopIdx === -1) continue;
|
|
1453
1579
|
if (droppedOnFolder) {
|
|
1454
|
-
updated[desktopIdx] = { ...updated[desktopIdx], folderId: droppedOnFolder.id, x: void 0, y: void 0 };
|
|
1580
|
+
updated[desktopIdx] = { ...updated[desktopIdx], folderId: droppedOnFolder.id, x: void 0, y: void 0, folderX: void 0, folderY: void 0 };
|
|
1455
1581
|
} else {
|
|
1456
1582
|
updated[desktopIdx] = { ...updated[desktopIdx], x: move2.finalRight, y: move2.finalTop, folderId: void 0 };
|
|
1457
1583
|
positionsPatch[`item-${desktopIdx}`] = { right: move2.finalRight, top: move2.finalTop };
|
|
@@ -1504,6 +1630,25 @@ function Desktop({ profile }) {
|
|
|
1504
1630
|
};
|
|
1505
1631
|
useEffect(() => {
|
|
1506
1632
|
if (!rubberBand) return;
|
|
1633
|
+
const computeSelection = (minX, maxX, minY, maxY) => {
|
|
1634
|
+
const sel = /* @__PURE__ */ new Set();
|
|
1635
|
+
const cw = containerRef.current?.clientWidth || 800;
|
|
1636
|
+
desktopItems.forEach((item, i) => {
|
|
1637
|
+
const pos = getItemPos(item, i);
|
|
1638
|
+
const leftX = cw - pos.right - 80;
|
|
1639
|
+
if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
|
|
1640
|
+
sel.add(`item-${i}`);
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
folders.forEach((f, i) => {
|
|
1644
|
+
const pos = getFolderPos(f, i);
|
|
1645
|
+
const leftX = cw - pos.right - 80;
|
|
1646
|
+
if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
|
|
1647
|
+
sel.add(`folder-${i}`);
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
return sel;
|
|
1651
|
+
};
|
|
1507
1652
|
const move = (e) => {
|
|
1508
1653
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
1509
1654
|
if (!rect) return;
|
|
@@ -1513,31 +1658,15 @@ function Desktop({ profile }) {
|
|
|
1513
1658
|
const dy = y - rubberBand.startY;
|
|
1514
1659
|
if (dx * dx + dy * dy > 16) didRubberBandDragRef.current = true;
|
|
1515
1660
|
setRubberBand((prev) => prev ? { ...prev, endX: x, endY: y } : null);
|
|
1661
|
+
if (didRubberBandDragRef.current) {
|
|
1662
|
+
const minX = Math.min(rubberBand.startX, x);
|
|
1663
|
+
const maxX = Math.max(rubberBand.startX, x);
|
|
1664
|
+
const minY = Math.min(rubberBand.startY, y);
|
|
1665
|
+
const maxY = Math.max(rubberBand.startY, y);
|
|
1666
|
+
setSelected(computeSelection(minX, maxX, minY, maxY));
|
|
1667
|
+
}
|
|
1516
1668
|
};
|
|
1517
1669
|
const up = () => {
|
|
1518
|
-
if (rubberBand) {
|
|
1519
|
-
const minX = Math.min(rubberBand.startX, rubberBand.endX);
|
|
1520
|
-
const maxX = Math.max(rubberBand.startX, rubberBand.endX);
|
|
1521
|
-
const minY = Math.min(rubberBand.startY, rubberBand.endY);
|
|
1522
|
-
const maxY = Math.max(rubberBand.startY, rubberBand.endY);
|
|
1523
|
-
const sel = /* @__PURE__ */ new Set();
|
|
1524
|
-
const cw = containerRef.current?.clientWidth || 800;
|
|
1525
|
-
desktopItems.forEach((item, i) => {
|
|
1526
|
-
const pos = getItemPos(item, i);
|
|
1527
|
-
const leftX = cw - pos.right - 80;
|
|
1528
|
-
if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
|
|
1529
|
-
sel.add(`item-${i}`);
|
|
1530
|
-
}
|
|
1531
|
-
});
|
|
1532
|
-
folders.forEach((f, i) => {
|
|
1533
|
-
const pos = getFolderPos(f, i);
|
|
1534
|
-
const leftX = cw - pos.right - 80;
|
|
1535
|
-
if (leftX + 40 > minX && leftX < maxX && pos.top + 40 > minY && pos.top < maxY) {
|
|
1536
|
-
sel.add(`folder-${i}`);
|
|
1537
|
-
}
|
|
1538
|
-
});
|
|
1539
|
-
setSelected(sel);
|
|
1540
|
-
}
|
|
1541
1670
|
setRubberBand(null);
|
|
1542
1671
|
};
|
|
1543
1672
|
window.addEventListener("pointermove", move);
|
|
@@ -1724,24 +1853,8 @@ function Desktop({ profile }) {
|
|
|
1724
1853
|
purple: "bg-purple-100 border-purple-300",
|
|
1725
1854
|
orange: "bg-orange-100 border-orange-300"
|
|
1726
1855
|
};
|
|
1727
|
-
const renderIcon = (entityType, label, isSelected, entityId) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
|
|
1728
|
-
|
|
1729
|
-
/* @__PURE__ */ jsx("path", { d: "M6 12a4 4 0 014-4h10l4 4h14a4 4 0 014 4v20a4 4 0 01-4 4H10a4 4 0 01-4-4V12z", fill: "white", stroke: "#eab308", strokeWidth: "2", strokeLinejoin: "round" }),
|
|
1730
|
-
/* @__PURE__ */ jsx("path", { d: "M6 18h36", stroke: "#eab308", strokeWidth: "1.5" })
|
|
1731
|
-
] }) }) : entityType === "page" ? /* @__PURE__ */ jsx("div", { className: `w-12 h-12 flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: (() => {
|
|
1732
|
-
const icon = navIcons[label] || (entityId ? navIcons[entityId] : void 0);
|
|
1733
|
-
if (icon && isValidElement(icon)) {
|
|
1734
|
-
return cloneElement(icon, { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]" });
|
|
1735
|
-
}
|
|
1736
|
-
return /* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.4)]", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6z" }) });
|
|
1737
|
-
})() }) : /* @__PURE__ */ jsxs("div", { className: `w-12 h-12 relative flex items-center justify-center ${isSelected ? "rounded-lg bg-blue-400/30 ring-2 ring-blue-500" : ""}`, children: [
|
|
1738
|
-
/* @__PURE__ */ jsxs("svg", { className: `w-10 h-12 drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)] ${ENTITY_ICON_COLORS[entityType] || "text-gray-500"}`, viewBox: "0 0 40 48", fill: "none", children: [
|
|
1739
|
-
/* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", fill: "white", fillOpacity: "0.92" }),
|
|
1740
|
-
/* @__PURE__ */ jsx("path", { d: "M26 0l10 10H30a4 4 0 01-4-4V0z", fill: "currentColor", fillOpacity: "0.2" }),
|
|
1741
|
-
/* @__PURE__ */ jsx("path", { d: "M4 0h22l10 10v34a4 4 0 01-4 4H4a4 4 0 01-4-4V4a4 4 0 014-4z", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.5" })
|
|
1742
|
-
] }),
|
|
1743
|
-
/* @__PURE__ */ jsx("span", { className: `absolute inset-0 flex items-center justify-center text-[9px] font-bold pt-2 ${ENTITY_ICON_COLORS[entityType] || "text-gray-600"}`, children: ENTITY_ICONS[entityType] || entityType.slice(0, 3).toUpperCase() })
|
|
1744
|
-
] }),
|
|
1856
|
+
const renderIcon = (entityType, label, isSelected, entityId, fileKind) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 w-20 p-2", children: [
|
|
1857
|
+
/* @__PURE__ */ jsx(FileIconTile, { entityType, isSelected, entityId, label, fileKind }),
|
|
1745
1858
|
/* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium text-center leading-tight w-full drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)] ${isSelected ? "text-blue-200 bg-blue-600/60 rounded px-1" : "text-white"}`, children: label })
|
|
1746
1859
|
] });
|
|
1747
1860
|
const menuStyle = (x, y) => ({
|
|
@@ -1866,10 +1979,21 @@ function Desktop({ profile }) {
|
|
|
1866
1979
|
onContextMenu: (e) => handleItemContextMenu(e, i),
|
|
1867
1980
|
onDoubleClick: (e) => {
|
|
1868
1981
|
e.stopPropagation();
|
|
1869
|
-
doc.entityType === "
|
|
1982
|
+
if (doc.entityType === "preview-file" && doc.filePath && doc.fileKind) {
|
|
1983
|
+
openPreviewFile({
|
|
1984
|
+
filePath: doc.filePath,
|
|
1985
|
+
filename: doc.label,
|
|
1986
|
+
kind: doc.fileKind,
|
|
1987
|
+
onStaged: (route) => openPage(route)
|
|
1988
|
+
});
|
|
1989
|
+
} else if (doc.entityType === "page") {
|
|
1990
|
+
openPage(doc.entityId);
|
|
1991
|
+
} else {
|
|
1992
|
+
openEntity(doc.entityType, doc.entityId, null, doc.label);
|
|
1993
|
+
}
|
|
1870
1994
|
},
|
|
1871
1995
|
className: "cursor-default select-none",
|
|
1872
|
-
children: renderIcon(doc.entityType, doc.label, isSelected, doc.entityId)
|
|
1996
|
+
children: renderIcon(doc.entityType, doc.label, isSelected, doc.entityId, doc.fileKind)
|
|
1873
1997
|
},
|
|
1874
1998
|
`item-${doc.entityType}-${doc.entityId}-${i}`
|
|
1875
1999
|
);
|
|
@@ -2161,17 +2285,55 @@ function Desktop({ profile }) {
|
|
|
2161
2285
|
folder,
|
|
2162
2286
|
items: folderItems(openFolder),
|
|
2163
2287
|
onClose: () => setOpenFolder(null),
|
|
2164
|
-
onOpen: (item) =>
|
|
2288
|
+
onOpen: (item) => {
|
|
2289
|
+
if (item.entityType === "preview-file" && item.filePath && item.fileKind) {
|
|
2290
|
+
openPreviewFile({
|
|
2291
|
+
filePath: item.filePath,
|
|
2292
|
+
filename: item.label,
|
|
2293
|
+
kind: item.fileKind,
|
|
2294
|
+
onStaged: (route) => openPage(route)
|
|
2295
|
+
});
|
|
2296
|
+
} else {
|
|
2297
|
+
openEntity(item.entityType, item.entityId, null, item.label);
|
|
2298
|
+
}
|
|
2299
|
+
},
|
|
2165
2300
|
onMoveOut: (toMove) => {
|
|
2166
2301
|
const ids = new Set(toMove.map((t) => `${t.entityType}|${t.entityId}`));
|
|
2167
2302
|
const updated = favDocs.map(
|
|
2168
|
-
(d) => d.folderId === openFolder && ids.has(`${d.entityType}|${d.entityId}`) ? { ...d, folderId: void 0 } : d
|
|
2303
|
+
(d) => d.folderId === openFolder && ids.has(`${d.entityType}|${d.entityId}`) ? { ...d, folderId: void 0, folderX: void 0, folderY: void 0 } : d
|
|
2169
2304
|
);
|
|
2170
2305
|
saveDocs(updated);
|
|
2171
2306
|
},
|
|
2172
|
-
|
|
2173
|
-
const
|
|
2174
|
-
|
|
2307
|
+
onSetFolderPosition: (updates) => {
|
|
2308
|
+
const patch = new Map(updates.map((u) => [`${u.item.entityType}|${u.item.entityId}`, u]));
|
|
2309
|
+
const updated = favDocs.map((d) => {
|
|
2310
|
+
const u = patch.get(`${d.entityType}|${d.entityId}`);
|
|
2311
|
+
return u ? { ...d, folderX: u.x, folderY: u.y } : d;
|
|
2312
|
+
});
|
|
2313
|
+
saveDocs(updated);
|
|
2314
|
+
},
|
|
2315
|
+
onDragOutToDesktop: (drops) => {
|
|
2316
|
+
const containerRect = containerRef.current?.getBoundingClientRect();
|
|
2317
|
+
const cw = containerRef.current?.clientWidth ?? window.innerWidth;
|
|
2318
|
+
const patch = /* @__PURE__ */ new Map();
|
|
2319
|
+
for (const d of drops) {
|
|
2320
|
+
const offX = containerRect ? d.clientX - containerRect.left : d.clientX;
|
|
2321
|
+
const offY = containerRect ? d.clientY - containerRect.top : d.clientY;
|
|
2322
|
+
let right = cw - offX - 40;
|
|
2323
|
+
let top = Math.max(0, offY - 40);
|
|
2324
|
+
if (snapEnabled) {
|
|
2325
|
+
const s = snapToGrid(right, top);
|
|
2326
|
+
right = s.x;
|
|
2327
|
+
top = s.y;
|
|
2328
|
+
}
|
|
2329
|
+
right = Math.max(0, right);
|
|
2330
|
+
patch.set(`${d.item.entityType}|${d.item.entityId}`, { right, top });
|
|
2331
|
+
}
|
|
2332
|
+
const updated = favDocs.map((d) => {
|
|
2333
|
+
const p = patch.get(`${d.entityType}|${d.entityId}`);
|
|
2334
|
+
return p ? { ...d, folderId: void 0, folderX: void 0, folderY: void 0, x: p.right, y: p.top } : d;
|
|
2335
|
+
});
|
|
2336
|
+
saveDocs(updated);
|
|
2175
2337
|
}
|
|
2176
2338
|
}
|
|
2177
2339
|
);
|