rita-workspace 0.5.33 → 0.5.34
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.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +98 -5
- package/dist/index.mjs +97 -5
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,8 @@ interface Drawing {
|
|
|
6
6
|
id: string;
|
|
7
7
|
name: string;
|
|
8
8
|
folderId?: string | null;
|
|
9
|
+
/** Manual sort position. Lower = earlier in list. Falls back to createdAt when unset. */
|
|
10
|
+
position?: number;
|
|
9
11
|
elements: unknown[];
|
|
10
12
|
appState: Record<string, unknown>;
|
|
11
13
|
files: Record<string, unknown>;
|
|
@@ -64,6 +66,12 @@ declare function updateDrawing(id: string, updates: Partial<Omit<Drawing, 'id' |
|
|
|
64
66
|
declare function deleteDrawing(id: string): Promise<boolean>;
|
|
65
67
|
declare function duplicateDrawing(id: string, newName?: string): Promise<Drawing | undefined>;
|
|
66
68
|
declare function moveDrawingToFolder(drawingId: string, folderId: string | null): Promise<Drawing | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Re-number `position` for the given drawing IDs in the order provided (0..N-1).
|
|
71
|
+
* Drawings not in `orderedIds` are left untouched (caller should pass the full
|
|
72
|
+
* sorted slice that the user reordered, e.g. all root drawings or all in a folder).
|
|
73
|
+
*/
|
|
74
|
+
declare function reorderDrawings(orderedIds: string[]): Promise<void>;
|
|
67
75
|
|
|
68
76
|
declare function createFolder(name: string): Promise<Folder>;
|
|
69
77
|
declare function getFolder(id: string): Promise<Folder | undefined>;
|
|
@@ -147,6 +155,9 @@ interface WorkspaceContextValue {
|
|
|
147
155
|
renameFolder: (id: string, name: string) => Promise<void>;
|
|
148
156
|
deleteFolder: (id: string) => Promise<void>;
|
|
149
157
|
moveDrawingToFolder: (drawingId: string, folderId: string | null) => Promise<void>;
|
|
158
|
+
/** Re-numbers `position` for the given drawing IDs in order. Use the full ordered slice
|
|
159
|
+
* the user reordered (e.g. all root drawings, or all drawings in a folder). */
|
|
160
|
+
reorderDrawings: (orderedIds: string[]) => Promise<void>;
|
|
150
161
|
saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
|
|
151
162
|
saveDrawingById: (id: string, elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
|
|
152
163
|
refreshDrawings: () => Promise<void>;
|
|
@@ -388,4 +399,4 @@ interface WorkspacePluginProps {
|
|
|
388
399
|
*/
|
|
389
400
|
declare function WorkspacePlugin(props: WorkspacePluginProps): react_jsx_runtime.JSX.Element;
|
|
390
401
|
|
|
391
|
-
export { type Drawing, DrawingList, DrawingListItem, type DrawingMeta, DrawingsDialog, type DrawingsDialogProps, type ExcalidrawImperativeAPI, type Folder, Sidebar, type SupportedLanguage, type Translations, type Workspace, WorkspaceBridge, type WorkspaceBridgeProps, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, createFolder, deleteDrawing, deleteFolder, duplicateDrawing, getAllDrawings, getAllDrawingsMeta, getAllFolders, getDB, getDrawing, getFolder, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isDrawingOpenedEarlierInOtherTab, isLanguageSupported, moveDrawingToFolder, removeDrawingFromWorkspace, renameFolder, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang, warmDB };
|
|
402
|
+
export { type Drawing, DrawingList, DrawingListItem, type DrawingMeta, DrawingsDialog, type DrawingsDialogProps, type ExcalidrawImperativeAPI, type Folder, Sidebar, type SupportedLanguage, type Translations, type Workspace, WorkspaceBridge, type WorkspaceBridgeProps, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, createFolder, deleteDrawing, deleteFolder, duplicateDrawing, getAllDrawings, getAllDrawingsMeta, getAllFolders, getDB, getDrawing, getFolder, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isDrawingOpenedEarlierInOtherTab, isLanguageSupported, moveDrawingToFolder, removeDrawingFromWorkspace, renameFolder, reorderDrawings, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang, warmDB };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ interface Drawing {
|
|
|
6
6
|
id: string;
|
|
7
7
|
name: string;
|
|
8
8
|
folderId?: string | null;
|
|
9
|
+
/** Manual sort position. Lower = earlier in list. Falls back to createdAt when unset. */
|
|
10
|
+
position?: number;
|
|
9
11
|
elements: unknown[];
|
|
10
12
|
appState: Record<string, unknown>;
|
|
11
13
|
files: Record<string, unknown>;
|
|
@@ -64,6 +66,12 @@ declare function updateDrawing(id: string, updates: Partial<Omit<Drawing, 'id' |
|
|
|
64
66
|
declare function deleteDrawing(id: string): Promise<boolean>;
|
|
65
67
|
declare function duplicateDrawing(id: string, newName?: string): Promise<Drawing | undefined>;
|
|
66
68
|
declare function moveDrawingToFolder(drawingId: string, folderId: string | null): Promise<Drawing | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Re-number `position` for the given drawing IDs in the order provided (0..N-1).
|
|
71
|
+
* Drawings not in `orderedIds` are left untouched (caller should pass the full
|
|
72
|
+
* sorted slice that the user reordered, e.g. all root drawings or all in a folder).
|
|
73
|
+
*/
|
|
74
|
+
declare function reorderDrawings(orderedIds: string[]): Promise<void>;
|
|
67
75
|
|
|
68
76
|
declare function createFolder(name: string): Promise<Folder>;
|
|
69
77
|
declare function getFolder(id: string): Promise<Folder | undefined>;
|
|
@@ -147,6 +155,9 @@ interface WorkspaceContextValue {
|
|
|
147
155
|
renameFolder: (id: string, name: string) => Promise<void>;
|
|
148
156
|
deleteFolder: (id: string) => Promise<void>;
|
|
149
157
|
moveDrawingToFolder: (drawingId: string, folderId: string | null) => Promise<void>;
|
|
158
|
+
/** Re-numbers `position` for the given drawing IDs in order. Use the full ordered slice
|
|
159
|
+
* the user reordered (e.g. all root drawings, or all drawings in a folder). */
|
|
160
|
+
reorderDrawings: (orderedIds: string[]) => Promise<void>;
|
|
150
161
|
saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
|
|
151
162
|
saveDrawingById: (id: string, elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
|
|
152
163
|
refreshDrawings: () => Promise<void>;
|
|
@@ -388,4 +399,4 @@ interface WorkspacePluginProps {
|
|
|
388
399
|
*/
|
|
389
400
|
declare function WorkspacePlugin(props: WorkspacePluginProps): react_jsx_runtime.JSX.Element;
|
|
390
401
|
|
|
391
|
-
export { type Drawing, DrawingList, DrawingListItem, type DrawingMeta, DrawingsDialog, type DrawingsDialogProps, type ExcalidrawImperativeAPI, type Folder, Sidebar, type SupportedLanguage, type Translations, type Workspace, WorkspaceBridge, type WorkspaceBridgeProps, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, createFolder, deleteDrawing, deleteFolder, duplicateDrawing, getAllDrawings, getAllDrawingsMeta, getAllFolders, getDB, getDrawing, getFolder, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isDrawingOpenedEarlierInOtherTab, isLanguageSupported, moveDrawingToFolder, removeDrawingFromWorkspace, renameFolder, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang, warmDB };
|
|
402
|
+
export { type Drawing, DrawingList, DrawingListItem, type DrawingMeta, DrawingsDialog, type DrawingsDialogProps, type ExcalidrawImperativeAPI, type Folder, Sidebar, type SupportedLanguage, type Translations, type Workspace, WorkspaceBridge, type WorkspaceBridgeProps, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, createFolder, deleteDrawing, deleteFolder, duplicateDrawing, getAllDrawings, getAllDrawingsMeta, getAllFolders, getDB, getDrawing, getFolder, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isDrawingOpenedEarlierInOtherTab, isLanguageSupported, moveDrawingToFolder, removeDrawingFromWorkspace, renameFolder, reorderDrawings, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang, warmDB };
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ __export(index_exports, {
|
|
|
59
59
|
moveDrawingToFolder: () => moveDrawingToFolder,
|
|
60
60
|
removeDrawingFromWorkspace: () => removeDrawingFromWorkspace,
|
|
61
61
|
renameFolder: () => renameFolder,
|
|
62
|
+
reorderDrawings: () => reorderDrawings,
|
|
62
63
|
setActiveDrawing: () => setActiveDrawing,
|
|
63
64
|
updateDrawing: () => updateDrawing,
|
|
64
65
|
updateWorkspace: () => updateWorkspace,
|
|
@@ -177,6 +178,17 @@ async function duplicateDrawing(id, newName) {
|
|
|
177
178
|
async function moveDrawingToFolder(drawingId, folderId) {
|
|
178
179
|
return updateDrawing(drawingId, { folderId });
|
|
179
180
|
}
|
|
181
|
+
async function reorderDrawings(orderedIds) {
|
|
182
|
+
const db = await getDB();
|
|
183
|
+
const tx = db.transaction("drawings", "readwrite");
|
|
184
|
+
const store = tx.objectStore("drawings");
|
|
185
|
+
for (let i = 0; i < orderedIds.length; i++) {
|
|
186
|
+
const existing = await store.get(orderedIds[i]);
|
|
187
|
+
if (!existing) continue;
|
|
188
|
+
await store.put({ ...existing, position: i });
|
|
189
|
+
}
|
|
190
|
+
await tx.done;
|
|
191
|
+
}
|
|
180
192
|
|
|
181
193
|
// src/storage/folderStore.ts
|
|
182
194
|
var import_nanoid2 = require("nanoid");
|
|
@@ -315,8 +327,8 @@ var sv = {
|
|
|
315
327
|
// Actions with descriptions
|
|
316
328
|
createNewDrawing: "Skapa ny ritning",
|
|
317
329
|
createNewDrawingDesc: "Skapar en tom ritning i din arbetsyta",
|
|
318
|
-
openFromFile: "
|
|
319
|
-
openFromFileDesc: "
|
|
330
|
+
openFromFile: "Importera ritning fr\xE5n fil",
|
|
331
|
+
openFromFileDesc: "Importerar en sparad ritning fr\xE5n din dator",
|
|
320
332
|
saveAllBackup: "Spara alla ritningar (backup)",
|
|
321
333
|
saveAllBackupDesc: "Ladda ner hela din arbetsyta som backup",
|
|
322
334
|
loadBackup: "L\xE4s in sparad arbetsyta",
|
|
@@ -365,8 +377,8 @@ var en = {
|
|
|
365
377
|
// Actions with descriptions
|
|
366
378
|
createNewDrawing: "Create new drawing",
|
|
367
379
|
createNewDrawingDesc: "Creates an empty drawing in your workspace",
|
|
368
|
-
openFromFile: "
|
|
369
|
-
openFromFileDesc: "
|
|
380
|
+
openFromFile: "Import drawing from file",
|
|
381
|
+
openFromFileDesc: "Imports a saved drawing from your computer",
|
|
370
382
|
saveAllBackup: "Save all drawings (backup)",
|
|
371
383
|
saveAllBackupDesc: "Download your entire workspace as a backup",
|
|
372
384
|
loadBackup: "Load saved workspace",
|
|
@@ -1251,6 +1263,19 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
1251
1263
|
setError(err instanceof Error ? err.message : "Failed to move drawing");
|
|
1252
1264
|
}
|
|
1253
1265
|
}, []);
|
|
1266
|
+
const reorderDrawings2 = (0, import_react.useCallback)(async (orderedIds) => {
|
|
1267
|
+
const positionMap = new Map(orderedIds.map((id, idx) => [id, idx]));
|
|
1268
|
+
setDrawings((prev) => prev.map(
|
|
1269
|
+
(d) => positionMap.has(d.id) ? { ...d, position: positionMap.get(d.id) } : d
|
|
1270
|
+
));
|
|
1271
|
+
try {
|
|
1272
|
+
await reorderDrawings(orderedIds);
|
|
1273
|
+
broadcastWorkspaceChange();
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
setError(err instanceof Error ? err.message : "Failed to reorder drawings");
|
|
1276
|
+
refreshDrawingsRef.current();
|
|
1277
|
+
}
|
|
1278
|
+
}, []);
|
|
1254
1279
|
const value = {
|
|
1255
1280
|
workspace,
|
|
1256
1281
|
drawings,
|
|
@@ -1270,6 +1295,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
1270
1295
|
renameFolder: renameFolder2,
|
|
1271
1296
|
deleteFolder: deleteFolder2,
|
|
1272
1297
|
moveDrawingToFolder: moveDrawingToFolder2,
|
|
1298
|
+
reorderDrawings: reorderDrawings2,
|
|
1273
1299
|
saveCurrentDrawing,
|
|
1274
1300
|
saveDrawingById,
|
|
1275
1301
|
refreshDrawings,
|
|
@@ -1638,6 +1664,7 @@ var DrawingsDialog = ({
|
|
|
1638
1664
|
renameFolder: renameFolder2,
|
|
1639
1665
|
deleteFolder: deleteFolder2,
|
|
1640
1666
|
moveDrawingToFolder: moveDrawingToFolder2,
|
|
1667
|
+
reorderDrawings: reorderDrawings2,
|
|
1641
1668
|
exportWorkspace,
|
|
1642
1669
|
importWorkspace,
|
|
1643
1670
|
exportDrawingAsExcalidraw,
|
|
@@ -1666,6 +1693,8 @@ var DrawingsDialog = ({
|
|
|
1666
1693
|
const [isRefreshing, setIsRefreshing] = (0, import_react5.useState)(false);
|
|
1667
1694
|
const [draggingDrawingId, setDraggingDrawingId] = (0, import_react5.useState)(null);
|
|
1668
1695
|
const [dropTargetFolderId, setDropTargetFolderId] = (0, import_react5.useState)(null);
|
|
1696
|
+
const [dropTargetDrawingId, setDropTargetDrawingId] = (0, import_react5.useState)(null);
|
|
1697
|
+
const [dropTargetPosition, setDropTargetPosition] = (0, import_react5.useState)(null);
|
|
1669
1698
|
const [position, setPosition] = (0, import_react5.useState)(null);
|
|
1670
1699
|
const dragRef = (0, import_react5.useRef)(null);
|
|
1671
1700
|
const dialogRef = (0, import_react5.useRef)(null);
|
|
@@ -1773,6 +1802,28 @@ var DrawingsDialog = ({
|
|
|
1773
1802
|
setSelectedId(null);
|
|
1774
1803
|
moveDrawingToFolder2(drawingId, folderId);
|
|
1775
1804
|
}, [moveDrawingToFolder2]);
|
|
1805
|
+
const handleReorderDrop = (0, import_react5.useCallback)((draggedId, targetId, pos) => {
|
|
1806
|
+
if (draggedId === targetId) return;
|
|
1807
|
+
const target = drawings.find((d) => d.id === targetId);
|
|
1808
|
+
if (!target) return;
|
|
1809
|
+
const scopeFolderId = target.folderId ?? null;
|
|
1810
|
+
const scope = drawings.filter((d) => (d.folderId ?? null) === scopeFolderId).sort((a, b) => (a.position ?? a.createdAt) - (b.position ?? b.createdAt));
|
|
1811
|
+
const withoutDragged = scope.filter((d) => d.id !== draggedId);
|
|
1812
|
+
const targetIdx = withoutDragged.findIndex((d) => d.id === targetId);
|
|
1813
|
+
if (targetIdx === -1) return;
|
|
1814
|
+
const insertIdx = pos === "before" ? targetIdx : targetIdx + 1;
|
|
1815
|
+
const dragged = drawings.find((d) => d.id === draggedId);
|
|
1816
|
+
if (!dragged) return;
|
|
1817
|
+
if ((dragged.folderId ?? null) !== scopeFolderId) {
|
|
1818
|
+
moveDrawingToFolder2(draggedId, scopeFolderId);
|
|
1819
|
+
}
|
|
1820
|
+
const ordered = [
|
|
1821
|
+
...withoutDragged.slice(0, insertIdx),
|
|
1822
|
+
dragged,
|
|
1823
|
+
...withoutDragged.slice(insertIdx)
|
|
1824
|
+
].map((d) => d.id);
|
|
1825
|
+
reorderDrawings2(ordered);
|
|
1826
|
+
}, [drawings, reorderDrawings2, moveDrawingToFolder2]);
|
|
1776
1827
|
const toggleFolder = (0, import_react5.useCallback)((folderId) => {
|
|
1777
1828
|
setExpandedFolders((prev) => {
|
|
1778
1829
|
const next = new Set(prev);
|
|
@@ -1805,7 +1856,9 @@ var DrawingsDialog = ({
|
|
|
1805
1856
|
const { rootDrawings, drawingsByFolder, filteredFolders } = (0, import_react5.useMemo)(() => {
|
|
1806
1857
|
const query = searchQuery.toLowerCase().trim();
|
|
1807
1858
|
const filtered = query ? drawings.filter((d) => d.name.toLowerCase().includes(query)) : drawings;
|
|
1808
|
-
const sorted = [...filtered].sort(
|
|
1859
|
+
const sorted = [...filtered].sort(
|
|
1860
|
+
(a, b) => (a.position ?? a.createdAt) - (b.position ?? b.createdAt)
|
|
1861
|
+
);
|
|
1809
1862
|
const root = sorted.filter((d) => !d.folderId);
|
|
1810
1863
|
const byFolder = {};
|
|
1811
1864
|
for (const folder of folders) {
|
|
@@ -1860,6 +1913,34 @@ var DrawingsDialog = ({
|
|
|
1860
1913
|
onDragEnd: () => {
|
|
1861
1914
|
setDraggingDrawingId(null);
|
|
1862
1915
|
setDropTargetFolderId(null);
|
|
1916
|
+
setDropTargetDrawingId(null);
|
|
1917
|
+
setDropTargetPosition(null);
|
|
1918
|
+
},
|
|
1919
|
+
onDragOver: (e) => {
|
|
1920
|
+
if (!draggingDrawingId || draggingDrawingId === drawing.id) return;
|
|
1921
|
+
e.preventDefault();
|
|
1922
|
+
e.dataTransfer.dropEffect = "move";
|
|
1923
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
1924
|
+
const isBefore = e.clientY < rect.top + rect.height / 2;
|
|
1925
|
+
setDropTargetDrawingId(drawing.id);
|
|
1926
|
+
setDropTargetPosition(isBefore ? "before" : "after");
|
|
1927
|
+
},
|
|
1928
|
+
onDragLeave: (e) => {
|
|
1929
|
+
if (e.currentTarget.contains(e.relatedTarget)) return;
|
|
1930
|
+
if (dropTargetDrawingId === drawing.id) {
|
|
1931
|
+
setDropTargetDrawingId(null);
|
|
1932
|
+
setDropTargetPosition(null);
|
|
1933
|
+
}
|
|
1934
|
+
},
|
|
1935
|
+
onDrop: (e) => {
|
|
1936
|
+
if (!draggingDrawingId || !dropTargetPosition || draggingDrawingId === drawing.id) return;
|
|
1937
|
+
e.preventDefault();
|
|
1938
|
+
e.stopPropagation();
|
|
1939
|
+
handleReorderDrop(draggingDrawingId, drawing.id, dropTargetPosition);
|
|
1940
|
+
setDraggingDrawingId(null);
|
|
1941
|
+
setDropTargetDrawingId(null);
|
|
1942
|
+
setDropTargetPosition(null);
|
|
1943
|
+
setDropTargetFolderId(null);
|
|
1863
1944
|
},
|
|
1864
1945
|
onMouseEnter: () => setHoveredId(drawing.id),
|
|
1865
1946
|
onMouseLeave: () => setHoveredId(null),
|
|
@@ -1875,6 +1956,7 @@ var DrawingsDialog = ({
|
|
|
1875
1956
|
handleSelect(drawing);
|
|
1876
1957
|
},
|
|
1877
1958
|
style: {
|
|
1959
|
+
position: "relative",
|
|
1878
1960
|
padding: "10px 12px",
|
|
1879
1961
|
display: "flex",
|
|
1880
1962
|
alignItems: "center",
|
|
@@ -1889,6 +1971,16 @@ var DrawingsDialog = ({
|
|
|
1889
1971
|
opacity: draggingDrawingId === drawing.id ? 0.4 : switchingId && switchingId !== drawing.id ? 0.5 : 1
|
|
1890
1972
|
},
|
|
1891
1973
|
children: [
|
|
1974
|
+
dropTargetDrawingId === drawing.id && dropTargetPosition && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1975
|
+
position: "absolute",
|
|
1976
|
+
left: 4,
|
|
1977
|
+
right: 4,
|
|
1978
|
+
[dropTargetPosition === "before" ? "top" : "bottom"]: -2,
|
|
1979
|
+
height: "3px",
|
|
1980
|
+
backgroundColor: "var(--color-primary, #6c63ff)",
|
|
1981
|
+
borderRadius: "2px",
|
|
1982
|
+
pointerEvents: "none"
|
|
1983
|
+
} }),
|
|
1892
1984
|
renderThumbnail && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1893
1985
|
width: "64px",
|
|
1894
1986
|
height: "48px",
|
|
@@ -2815,6 +2907,7 @@ function WorkspacePlugin(props) {
|
|
|
2815
2907
|
moveDrawingToFolder,
|
|
2816
2908
|
removeDrawingFromWorkspace,
|
|
2817
2909
|
renameFolder,
|
|
2910
|
+
reorderDrawings,
|
|
2818
2911
|
setActiveDrawing,
|
|
2819
2912
|
updateDrawing,
|
|
2820
2913
|
updateWorkspace,
|
package/dist/index.mjs
CHANGED
|
@@ -106,6 +106,17 @@ async function duplicateDrawing(id, newName) {
|
|
|
106
106
|
async function moveDrawingToFolder(drawingId, folderId) {
|
|
107
107
|
return updateDrawing(drawingId, { folderId });
|
|
108
108
|
}
|
|
109
|
+
async function reorderDrawings(orderedIds) {
|
|
110
|
+
const db = await getDB();
|
|
111
|
+
const tx = db.transaction("drawings", "readwrite");
|
|
112
|
+
const store = tx.objectStore("drawings");
|
|
113
|
+
for (let i = 0; i < orderedIds.length; i++) {
|
|
114
|
+
const existing = await store.get(orderedIds[i]);
|
|
115
|
+
if (!existing) continue;
|
|
116
|
+
await store.put({ ...existing, position: i });
|
|
117
|
+
}
|
|
118
|
+
await tx.done;
|
|
119
|
+
}
|
|
109
120
|
|
|
110
121
|
// src/storage/folderStore.ts
|
|
111
122
|
import { nanoid as nanoid2 } from "nanoid";
|
|
@@ -244,8 +255,8 @@ var sv = {
|
|
|
244
255
|
// Actions with descriptions
|
|
245
256
|
createNewDrawing: "Skapa ny ritning",
|
|
246
257
|
createNewDrawingDesc: "Skapar en tom ritning i din arbetsyta",
|
|
247
|
-
openFromFile: "
|
|
248
|
-
openFromFileDesc: "
|
|
258
|
+
openFromFile: "Importera ritning fr\xE5n fil",
|
|
259
|
+
openFromFileDesc: "Importerar en sparad ritning fr\xE5n din dator",
|
|
249
260
|
saveAllBackup: "Spara alla ritningar (backup)",
|
|
250
261
|
saveAllBackupDesc: "Ladda ner hela din arbetsyta som backup",
|
|
251
262
|
loadBackup: "L\xE4s in sparad arbetsyta",
|
|
@@ -294,8 +305,8 @@ var en = {
|
|
|
294
305
|
// Actions with descriptions
|
|
295
306
|
createNewDrawing: "Create new drawing",
|
|
296
307
|
createNewDrawingDesc: "Creates an empty drawing in your workspace",
|
|
297
|
-
openFromFile: "
|
|
298
|
-
openFromFileDesc: "
|
|
308
|
+
openFromFile: "Import drawing from file",
|
|
309
|
+
openFromFileDesc: "Imports a saved drawing from your computer",
|
|
299
310
|
saveAllBackup: "Save all drawings (backup)",
|
|
300
311
|
saveAllBackupDesc: "Download your entire workspace as a backup",
|
|
301
312
|
loadBackup: "Load saved workspace",
|
|
@@ -1180,6 +1191,19 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
1180
1191
|
setError(err instanceof Error ? err.message : "Failed to move drawing");
|
|
1181
1192
|
}
|
|
1182
1193
|
}, []);
|
|
1194
|
+
const reorderDrawings2 = useCallback(async (orderedIds) => {
|
|
1195
|
+
const positionMap = new Map(orderedIds.map((id, idx) => [id, idx]));
|
|
1196
|
+
setDrawings((prev) => prev.map(
|
|
1197
|
+
(d) => positionMap.has(d.id) ? { ...d, position: positionMap.get(d.id) } : d
|
|
1198
|
+
));
|
|
1199
|
+
try {
|
|
1200
|
+
await reorderDrawings(orderedIds);
|
|
1201
|
+
broadcastWorkspaceChange();
|
|
1202
|
+
} catch (err) {
|
|
1203
|
+
setError(err instanceof Error ? err.message : "Failed to reorder drawings");
|
|
1204
|
+
refreshDrawingsRef.current();
|
|
1205
|
+
}
|
|
1206
|
+
}, []);
|
|
1183
1207
|
const value = {
|
|
1184
1208
|
workspace,
|
|
1185
1209
|
drawings,
|
|
@@ -1199,6 +1223,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
1199
1223
|
renameFolder: renameFolder2,
|
|
1200
1224
|
deleteFolder: deleteFolder2,
|
|
1201
1225
|
moveDrawingToFolder: moveDrawingToFolder2,
|
|
1226
|
+
reorderDrawings: reorderDrawings2,
|
|
1202
1227
|
saveCurrentDrawing,
|
|
1203
1228
|
saveDrawingById,
|
|
1204
1229
|
refreshDrawings,
|
|
@@ -1567,6 +1592,7 @@ var DrawingsDialog = ({
|
|
|
1567
1592
|
renameFolder: renameFolder2,
|
|
1568
1593
|
deleteFolder: deleteFolder2,
|
|
1569
1594
|
moveDrawingToFolder: moveDrawingToFolder2,
|
|
1595
|
+
reorderDrawings: reorderDrawings2,
|
|
1570
1596
|
exportWorkspace,
|
|
1571
1597
|
importWorkspace,
|
|
1572
1598
|
exportDrawingAsExcalidraw,
|
|
@@ -1595,6 +1621,8 @@ var DrawingsDialog = ({
|
|
|
1595
1621
|
const [isRefreshing, setIsRefreshing] = useState4(false);
|
|
1596
1622
|
const [draggingDrawingId, setDraggingDrawingId] = useState4(null);
|
|
1597
1623
|
const [dropTargetFolderId, setDropTargetFolderId] = useState4(null);
|
|
1624
|
+
const [dropTargetDrawingId, setDropTargetDrawingId] = useState4(null);
|
|
1625
|
+
const [dropTargetPosition, setDropTargetPosition] = useState4(null);
|
|
1598
1626
|
const [position, setPosition] = useState4(null);
|
|
1599
1627
|
const dragRef = useRef3(null);
|
|
1600
1628
|
const dialogRef = useRef3(null);
|
|
@@ -1702,6 +1730,28 @@ var DrawingsDialog = ({
|
|
|
1702
1730
|
setSelectedId(null);
|
|
1703
1731
|
moveDrawingToFolder2(drawingId, folderId);
|
|
1704
1732
|
}, [moveDrawingToFolder2]);
|
|
1733
|
+
const handleReorderDrop = useCallback2((draggedId, targetId, pos) => {
|
|
1734
|
+
if (draggedId === targetId) return;
|
|
1735
|
+
const target = drawings.find((d) => d.id === targetId);
|
|
1736
|
+
if (!target) return;
|
|
1737
|
+
const scopeFolderId = target.folderId ?? null;
|
|
1738
|
+
const scope = drawings.filter((d) => (d.folderId ?? null) === scopeFolderId).sort((a, b) => (a.position ?? a.createdAt) - (b.position ?? b.createdAt));
|
|
1739
|
+
const withoutDragged = scope.filter((d) => d.id !== draggedId);
|
|
1740
|
+
const targetIdx = withoutDragged.findIndex((d) => d.id === targetId);
|
|
1741
|
+
if (targetIdx === -1) return;
|
|
1742
|
+
const insertIdx = pos === "before" ? targetIdx : targetIdx + 1;
|
|
1743
|
+
const dragged = drawings.find((d) => d.id === draggedId);
|
|
1744
|
+
if (!dragged) return;
|
|
1745
|
+
if ((dragged.folderId ?? null) !== scopeFolderId) {
|
|
1746
|
+
moveDrawingToFolder2(draggedId, scopeFolderId);
|
|
1747
|
+
}
|
|
1748
|
+
const ordered = [
|
|
1749
|
+
...withoutDragged.slice(0, insertIdx),
|
|
1750
|
+
dragged,
|
|
1751
|
+
...withoutDragged.slice(insertIdx)
|
|
1752
|
+
].map((d) => d.id);
|
|
1753
|
+
reorderDrawings2(ordered);
|
|
1754
|
+
}, [drawings, reorderDrawings2, moveDrawingToFolder2]);
|
|
1705
1755
|
const toggleFolder = useCallback2((folderId) => {
|
|
1706
1756
|
setExpandedFolders((prev) => {
|
|
1707
1757
|
const next = new Set(prev);
|
|
@@ -1734,7 +1784,9 @@ var DrawingsDialog = ({
|
|
|
1734
1784
|
const { rootDrawings, drawingsByFolder, filteredFolders } = useMemo(() => {
|
|
1735
1785
|
const query = searchQuery.toLowerCase().trim();
|
|
1736
1786
|
const filtered = query ? drawings.filter((d) => d.name.toLowerCase().includes(query)) : drawings;
|
|
1737
|
-
const sorted = [...filtered].sort(
|
|
1787
|
+
const sorted = [...filtered].sort(
|
|
1788
|
+
(a, b) => (a.position ?? a.createdAt) - (b.position ?? b.createdAt)
|
|
1789
|
+
);
|
|
1738
1790
|
const root = sorted.filter((d) => !d.folderId);
|
|
1739
1791
|
const byFolder = {};
|
|
1740
1792
|
for (const folder of folders) {
|
|
@@ -1789,6 +1841,34 @@ var DrawingsDialog = ({
|
|
|
1789
1841
|
onDragEnd: () => {
|
|
1790
1842
|
setDraggingDrawingId(null);
|
|
1791
1843
|
setDropTargetFolderId(null);
|
|
1844
|
+
setDropTargetDrawingId(null);
|
|
1845
|
+
setDropTargetPosition(null);
|
|
1846
|
+
},
|
|
1847
|
+
onDragOver: (e) => {
|
|
1848
|
+
if (!draggingDrawingId || draggingDrawingId === drawing.id) return;
|
|
1849
|
+
e.preventDefault();
|
|
1850
|
+
e.dataTransfer.dropEffect = "move";
|
|
1851
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
1852
|
+
const isBefore = e.clientY < rect.top + rect.height / 2;
|
|
1853
|
+
setDropTargetDrawingId(drawing.id);
|
|
1854
|
+
setDropTargetPosition(isBefore ? "before" : "after");
|
|
1855
|
+
},
|
|
1856
|
+
onDragLeave: (e) => {
|
|
1857
|
+
if (e.currentTarget.contains(e.relatedTarget)) return;
|
|
1858
|
+
if (dropTargetDrawingId === drawing.id) {
|
|
1859
|
+
setDropTargetDrawingId(null);
|
|
1860
|
+
setDropTargetPosition(null);
|
|
1861
|
+
}
|
|
1862
|
+
},
|
|
1863
|
+
onDrop: (e) => {
|
|
1864
|
+
if (!draggingDrawingId || !dropTargetPosition || draggingDrawingId === drawing.id) return;
|
|
1865
|
+
e.preventDefault();
|
|
1866
|
+
e.stopPropagation();
|
|
1867
|
+
handleReorderDrop(draggingDrawingId, drawing.id, dropTargetPosition);
|
|
1868
|
+
setDraggingDrawingId(null);
|
|
1869
|
+
setDropTargetDrawingId(null);
|
|
1870
|
+
setDropTargetPosition(null);
|
|
1871
|
+
setDropTargetFolderId(null);
|
|
1792
1872
|
},
|
|
1793
1873
|
onMouseEnter: () => setHoveredId(drawing.id),
|
|
1794
1874
|
onMouseLeave: () => setHoveredId(null),
|
|
@@ -1804,6 +1884,7 @@ var DrawingsDialog = ({
|
|
|
1804
1884
|
handleSelect(drawing);
|
|
1805
1885
|
},
|
|
1806
1886
|
style: {
|
|
1887
|
+
position: "relative",
|
|
1807
1888
|
padding: "10px 12px",
|
|
1808
1889
|
display: "flex",
|
|
1809
1890
|
alignItems: "center",
|
|
@@ -1818,6 +1899,16 @@ var DrawingsDialog = ({
|
|
|
1818
1899
|
opacity: draggingDrawingId === drawing.id ? 0.4 : switchingId && switchingId !== drawing.id ? 0.5 : 1
|
|
1819
1900
|
},
|
|
1820
1901
|
children: [
|
|
1902
|
+
dropTargetDrawingId === drawing.id && dropTargetPosition && /* @__PURE__ */ jsx6("div", { style: {
|
|
1903
|
+
position: "absolute",
|
|
1904
|
+
left: 4,
|
|
1905
|
+
right: 4,
|
|
1906
|
+
[dropTargetPosition === "before" ? "top" : "bottom"]: -2,
|
|
1907
|
+
height: "3px",
|
|
1908
|
+
backgroundColor: "var(--color-primary, #6c63ff)",
|
|
1909
|
+
borderRadius: "2px",
|
|
1910
|
+
pointerEvents: "none"
|
|
1911
|
+
} }),
|
|
1821
1912
|
renderThumbnail && /* @__PURE__ */ jsx6("div", { style: {
|
|
1822
1913
|
width: "64px",
|
|
1823
1914
|
height: "48px",
|
|
@@ -2743,6 +2834,7 @@ export {
|
|
|
2743
2834
|
moveDrawingToFolder,
|
|
2744
2835
|
removeDrawingFromWorkspace,
|
|
2745
2836
|
renameFolder,
|
|
2837
|
+
reorderDrawings,
|
|
2746
2838
|
setActiveDrawing,
|
|
2747
2839
|
updateDrawing,
|
|
2748
2840
|
updateWorkspace,
|