rita-workspace 0.4.0 → 0.4.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.d.mts CHANGED
@@ -74,6 +74,8 @@ interface Translations {
74
74
  clickNewToStart: string;
75
75
  modified: string;
76
76
  confirmDelete: string;
77
+ exportWorkspace: string;
78
+ importWorkspace: string;
77
79
  shortcutNewDrawing: string;
78
80
  }
79
81
  /**
@@ -100,6 +102,9 @@ interface WorkspaceContextValue {
100
102
  removeDrawing: (id: string) => Promise<void>;
101
103
  duplicateCurrentDrawing: () => Promise<Drawing | null>;
102
104
  saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
105
+ saveDrawingById: (id: string, elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
106
+ exportWorkspace: () => Promise<void>;
107
+ importWorkspace: () => Promise<void>;
103
108
  }
104
109
  declare function useWorkspace(): WorkspaceContextValue;
105
110
  /**
package/dist/index.d.ts CHANGED
@@ -74,6 +74,8 @@ interface Translations {
74
74
  clickNewToStart: string;
75
75
  modified: string;
76
76
  confirmDelete: string;
77
+ exportWorkspace: string;
78
+ importWorkspace: string;
77
79
  shortcutNewDrawing: string;
78
80
  }
79
81
  /**
@@ -100,6 +102,9 @@ interface WorkspaceContextValue {
100
102
  removeDrawing: (id: string) => Promise<void>;
101
103
  duplicateCurrentDrawing: () => Promise<Drawing | null>;
102
104
  saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
105
+ saveDrawingById: (id: string, elements: unknown[], appState: Record<string, unknown>, files?: Record<string, unknown>) => Promise<void>;
106
+ exportWorkspace: () => Promise<void>;
107
+ importWorkspace: () => Promise<void>;
103
108
  }
104
109
  declare function useWorkspace(): WorkspaceContextValue;
105
110
  /**
package/dist/index.js CHANGED
@@ -216,7 +216,7 @@ var sv = {
216
216
  newDrawing: "Ny ritning",
217
217
  manageDrawings: "Hantera arbetsyta...",
218
218
  // Dialog
219
- dialogTitle: "Arbetsyta",
219
+ dialogTitle: "Min Arbetsyta",
220
220
  close: "St\xE4ng",
221
221
  open: "\xD6ppna",
222
222
  rename: "Byt namn",
@@ -229,6 +229,9 @@ var sv = {
229
229
  clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
230
230
  modified: "\xC4ndrad",
231
231
  confirmDelete: "Vill du ta bort denna ritning?",
232
+ // Export/Import
233
+ exportWorkspace: "Exportera",
234
+ importWorkspace: "Importera",
232
235
  // Shortcuts
233
236
  shortcutNewDrawing: "Ctrl+Alt+N"
234
237
  };
@@ -251,6 +254,9 @@ var en = {
251
254
  clickNewToStart: 'Click "New drawing" to start.',
252
255
  modified: "Modified",
253
256
  confirmDelete: "Do you want to delete this drawing?",
257
+ // Export/Import
258
+ exportWorkspace: "Export",
259
+ importWorkspace: "Import",
254
260
  // Shortcuts
255
261
  shortcutNewDrawing: "Ctrl+Alt+N"
256
262
  };
@@ -409,15 +415,87 @@ function WorkspaceProvider({ children, lang = "en" }) {
409
415
  if (files) {
410
416
  updateData.files = files;
411
417
  }
412
- const updated = await updateDrawing(activeDrawing.id, updateData);
413
- if (updated) {
414
- setActiveDrawing2(updated);
415
- setDrawings((prev) => prev.map((d) => d.id === updated.id ? updated : d));
416
- }
418
+ await updateDrawing(activeDrawing.id, updateData);
417
419
  } catch (err) {
418
420
  setError(err instanceof Error ? err.message : "Failed to save drawing");
419
421
  }
420
422
  }, [activeDrawing]);
423
+ const saveDrawingById = (0, import_react.useCallback)(async (id, elements, appState, files) => {
424
+ try {
425
+ const updateData = {
426
+ elements,
427
+ appState
428
+ };
429
+ if (files) {
430
+ updateData.files = files;
431
+ }
432
+ await updateDrawing(id, updateData);
433
+ } catch (err) {
434
+ setError(err instanceof Error ? err.message : "Failed to save drawing");
435
+ }
436
+ }, []);
437
+ const exportWorkspace = (0, import_react.useCallback)(async () => {
438
+ try {
439
+ const exportData = {
440
+ version: 1,
441
+ name: workspace?.name || "Min Arbetsyta",
442
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
443
+ drawings: drawings.map((d) => ({
444
+ name: d.name,
445
+ elements: d.elements,
446
+ appState: d.appState,
447
+ files: d.files,
448
+ createdAt: d.createdAt,
449
+ updatedAt: d.updatedAt
450
+ }))
451
+ };
452
+ const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: "application/json" });
453
+ const url = URL.createObjectURL(blob);
454
+ const a = document.createElement("a");
455
+ a.href = url;
456
+ a.download = `arbetsyta-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
457
+ document.body.appendChild(a);
458
+ a.click();
459
+ document.body.removeChild(a);
460
+ URL.revokeObjectURL(url);
461
+ } catch (err) {
462
+ setError(err instanceof Error ? err.message : "Failed to export workspace");
463
+ }
464
+ }, [workspace, drawings]);
465
+ const importWorkspace = (0, import_react.useCallback)(async () => {
466
+ if (!workspace) return;
467
+ try {
468
+ const input = document.createElement("input");
469
+ input.type = "file";
470
+ input.accept = ".json";
471
+ const file = await new Promise((resolve) => {
472
+ input.onchange = () => resolve(input.files?.[0] || null);
473
+ input.click();
474
+ });
475
+ if (!file) return;
476
+ const text = await file.text();
477
+ const data = JSON.parse(text);
478
+ if (!data.version || !Array.isArray(data.drawings)) {
479
+ throw new Error("Invalid workspace file");
480
+ }
481
+ for (const d of data.drawings) {
482
+ const drawing = await createDrawing(d.name || t.newDrawing);
483
+ await updateDrawing(drawing.id, {
484
+ elements: d.elements || [],
485
+ appState: d.appState || {},
486
+ files: d.files || {}
487
+ });
488
+ await addDrawingToWorkspace(workspace.id, drawing.id);
489
+ }
490
+ const allDrawings = await getAllDrawings();
491
+ const ws = await getOrCreateDefaultWorkspace();
492
+ const wsDrawings = allDrawings.filter((dr) => ws.drawingIds.includes(dr.id));
493
+ setWorkspace(ws);
494
+ setDrawings(wsDrawings);
495
+ } catch (err) {
496
+ setError(err instanceof Error ? err.message : "Failed to import workspace");
497
+ }
498
+ }, [workspace, t]);
421
499
  const value = {
422
500
  workspace,
423
501
  drawings,
@@ -431,7 +509,10 @@ function WorkspaceProvider({ children, lang = "en" }) {
431
509
  renameDrawing,
432
510
  removeDrawing,
433
511
  duplicateCurrentDrawing,
434
- saveCurrentDrawing
512
+ saveCurrentDrawing,
513
+ saveDrawingById,
514
+ exportWorkspace,
515
+ importWorkspace
435
516
  };
436
517
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceContext.Provider, { value, children });
437
518
  }
@@ -755,6 +836,8 @@ var DrawingsDialog = ({
755
836
  createNewDrawing,
756
837
  renameDrawing,
757
838
  removeDrawing,
839
+ exportWorkspace,
840
+ importWorkspace,
758
841
  t: contextT,
759
842
  lang: contextLang
760
843
  } = useWorkspace();
@@ -766,15 +849,13 @@ var DrawingsDialog = ({
766
849
  const handleSelect = (0, import_react5.useCallback)(async (drawing) => {
767
850
  await switchDrawing(drawing.id);
768
851
  onDrawingSelect?.(drawing);
769
- onClose();
770
- }, [switchDrawing, onDrawingSelect, onClose]);
852
+ }, [switchDrawing, onDrawingSelect]);
771
853
  const handleCreate = (0, import_react5.useCallback)(async () => {
772
854
  const newDrawing = await createNewDrawing();
773
855
  if (newDrawing) {
774
856
  onDrawingSelect?.(newDrawing);
775
- onClose();
776
857
  }
777
- }, [createNewDrawing, onDrawingSelect, onClose]);
858
+ }, [createNewDrawing, onDrawingSelect]);
778
859
  const handleStartEdit = (0, import_react5.useCallback)((drawing) => {
779
860
  setEditingId(drawing.id);
780
861
  setEditName(drawing.name);
@@ -1106,26 +1187,67 @@ var DrawingsDialog = ({
1106
1187
  alignItems: "center"
1107
1188
  },
1108
1189
  children: [
1109
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1110
- "button",
1111
- {
1112
- onClick: handleCreate,
1113
- style: {
1114
- padding: "10px 20px",
1115
- fontSize: "14px",
1116
- backgroundColor: "var(--color-primary, #6c63ff)",
1117
- color: "#fff",
1118
- border: "none",
1119
- borderRadius: "6px",
1120
- cursor: "pointer",
1121
- fontWeight: 500
1122
- },
1123
- children: [
1124
- "+ ",
1125
- t.newDrawing
1126
- ]
1127
- }
1128
- ),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1192
+ "button",
1193
+ {
1194
+ onClick: handleCreate,
1195
+ style: {
1196
+ padding: "10px 20px",
1197
+ fontSize: "14px",
1198
+ backgroundColor: "var(--color-primary, #6c63ff)",
1199
+ color: "#fff",
1200
+ border: "none",
1201
+ borderRadius: "6px",
1202
+ cursor: "pointer",
1203
+ fontWeight: 500
1204
+ },
1205
+ children: [
1206
+ "+ ",
1207
+ t.newDrawing
1208
+ ]
1209
+ }
1210
+ ),
1211
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1212
+ "button",
1213
+ {
1214
+ onClick: importWorkspace,
1215
+ style: {
1216
+ padding: "10px 20px",
1217
+ fontSize: "14px",
1218
+ backgroundColor: "transparent",
1219
+ border: "1px solid var(--default-border-color, #ccc)",
1220
+ borderRadius: "6px",
1221
+ cursor: "pointer",
1222
+ color: "inherit"
1223
+ },
1224
+ children: [
1225
+ "\u{1F4E5} ",
1226
+ t.importWorkspace
1227
+ ]
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1231
+ "button",
1232
+ {
1233
+ onClick: exportWorkspace,
1234
+ style: {
1235
+ padding: "10px 20px",
1236
+ fontSize: "14px",
1237
+ backgroundColor: "transparent",
1238
+ border: "1px solid var(--default-border-color, #ccc)",
1239
+ borderRadius: "6px",
1240
+ cursor: "pointer",
1241
+ color: "inherit"
1242
+ },
1243
+ disabled: drawings.length === 0,
1244
+ children: [
1245
+ "\u{1F4E4} ",
1246
+ t.exportWorkspace
1247
+ ]
1248
+ }
1249
+ )
1250
+ ] }),
1129
1251
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1130
1252
  "button",
1131
1253
  {
package/dist/index.mjs CHANGED
@@ -154,7 +154,7 @@ var sv = {
154
154
  newDrawing: "Ny ritning",
155
155
  manageDrawings: "Hantera arbetsyta...",
156
156
  // Dialog
157
- dialogTitle: "Arbetsyta",
157
+ dialogTitle: "Min Arbetsyta",
158
158
  close: "St\xE4ng",
159
159
  open: "\xD6ppna",
160
160
  rename: "Byt namn",
@@ -167,6 +167,9 @@ var sv = {
167
167
  clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
168
168
  modified: "\xC4ndrad",
169
169
  confirmDelete: "Vill du ta bort denna ritning?",
170
+ // Export/Import
171
+ exportWorkspace: "Exportera",
172
+ importWorkspace: "Importera",
170
173
  // Shortcuts
171
174
  shortcutNewDrawing: "Ctrl+Alt+N"
172
175
  };
@@ -189,6 +192,9 @@ var en = {
189
192
  clickNewToStart: 'Click "New drawing" to start.',
190
193
  modified: "Modified",
191
194
  confirmDelete: "Do you want to delete this drawing?",
195
+ // Export/Import
196
+ exportWorkspace: "Export",
197
+ importWorkspace: "Import",
192
198
  // Shortcuts
193
199
  shortcutNewDrawing: "Ctrl+Alt+N"
194
200
  };
@@ -347,15 +353,87 @@ function WorkspaceProvider({ children, lang = "en" }) {
347
353
  if (files) {
348
354
  updateData.files = files;
349
355
  }
350
- const updated = await updateDrawing(activeDrawing.id, updateData);
351
- if (updated) {
352
- setActiveDrawing2(updated);
353
- setDrawings((prev) => prev.map((d) => d.id === updated.id ? updated : d));
354
- }
356
+ await updateDrawing(activeDrawing.id, updateData);
355
357
  } catch (err) {
356
358
  setError(err instanceof Error ? err.message : "Failed to save drawing");
357
359
  }
358
360
  }, [activeDrawing]);
361
+ const saveDrawingById = useCallback(async (id, elements, appState, files) => {
362
+ try {
363
+ const updateData = {
364
+ elements,
365
+ appState
366
+ };
367
+ if (files) {
368
+ updateData.files = files;
369
+ }
370
+ await updateDrawing(id, updateData);
371
+ } catch (err) {
372
+ setError(err instanceof Error ? err.message : "Failed to save drawing");
373
+ }
374
+ }, []);
375
+ const exportWorkspace = useCallback(async () => {
376
+ try {
377
+ const exportData = {
378
+ version: 1,
379
+ name: workspace?.name || "Min Arbetsyta",
380
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
381
+ drawings: drawings.map((d) => ({
382
+ name: d.name,
383
+ elements: d.elements,
384
+ appState: d.appState,
385
+ files: d.files,
386
+ createdAt: d.createdAt,
387
+ updatedAt: d.updatedAt
388
+ }))
389
+ };
390
+ const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: "application/json" });
391
+ const url = URL.createObjectURL(blob);
392
+ const a = document.createElement("a");
393
+ a.href = url;
394
+ a.download = `arbetsyta-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
395
+ document.body.appendChild(a);
396
+ a.click();
397
+ document.body.removeChild(a);
398
+ URL.revokeObjectURL(url);
399
+ } catch (err) {
400
+ setError(err instanceof Error ? err.message : "Failed to export workspace");
401
+ }
402
+ }, [workspace, drawings]);
403
+ const importWorkspace = useCallback(async () => {
404
+ if (!workspace) return;
405
+ try {
406
+ const input = document.createElement("input");
407
+ input.type = "file";
408
+ input.accept = ".json";
409
+ const file = await new Promise((resolve) => {
410
+ input.onchange = () => resolve(input.files?.[0] || null);
411
+ input.click();
412
+ });
413
+ if (!file) return;
414
+ const text = await file.text();
415
+ const data = JSON.parse(text);
416
+ if (!data.version || !Array.isArray(data.drawings)) {
417
+ throw new Error("Invalid workspace file");
418
+ }
419
+ for (const d of data.drawings) {
420
+ const drawing = await createDrawing(d.name || t.newDrawing);
421
+ await updateDrawing(drawing.id, {
422
+ elements: d.elements || [],
423
+ appState: d.appState || {},
424
+ files: d.files || {}
425
+ });
426
+ await addDrawingToWorkspace(workspace.id, drawing.id);
427
+ }
428
+ const allDrawings = await getAllDrawings();
429
+ const ws = await getOrCreateDefaultWorkspace();
430
+ const wsDrawings = allDrawings.filter((dr) => ws.drawingIds.includes(dr.id));
431
+ setWorkspace(ws);
432
+ setDrawings(wsDrawings);
433
+ } catch (err) {
434
+ setError(err instanceof Error ? err.message : "Failed to import workspace");
435
+ }
436
+ }, [workspace, t]);
359
437
  const value = {
360
438
  workspace,
361
439
  drawings,
@@ -369,7 +447,10 @@ function WorkspaceProvider({ children, lang = "en" }) {
369
447
  renameDrawing,
370
448
  removeDrawing,
371
449
  duplicateCurrentDrawing,
372
- saveCurrentDrawing
450
+ saveCurrentDrawing,
451
+ saveDrawingById,
452
+ exportWorkspace,
453
+ importWorkspace
373
454
  };
374
455
  return /* @__PURE__ */ jsx(WorkspaceContext.Provider, { value, children });
375
456
  }
@@ -693,6 +774,8 @@ var DrawingsDialog = ({
693
774
  createNewDrawing,
694
775
  renameDrawing,
695
776
  removeDrawing,
777
+ exportWorkspace,
778
+ importWorkspace,
696
779
  t: contextT,
697
780
  lang: contextLang
698
781
  } = useWorkspace();
@@ -704,15 +787,13 @@ var DrawingsDialog = ({
704
787
  const handleSelect = useCallback2(async (drawing) => {
705
788
  await switchDrawing(drawing.id);
706
789
  onDrawingSelect?.(drawing);
707
- onClose();
708
- }, [switchDrawing, onDrawingSelect, onClose]);
790
+ }, [switchDrawing, onDrawingSelect]);
709
791
  const handleCreate = useCallback2(async () => {
710
792
  const newDrawing = await createNewDrawing();
711
793
  if (newDrawing) {
712
794
  onDrawingSelect?.(newDrawing);
713
- onClose();
714
795
  }
715
- }, [createNewDrawing, onDrawingSelect, onClose]);
796
+ }, [createNewDrawing, onDrawingSelect]);
716
797
  const handleStartEdit = useCallback2((drawing) => {
717
798
  setEditingId(drawing.id);
718
799
  setEditName(drawing.name);
@@ -1044,26 +1125,67 @@ var DrawingsDialog = ({
1044
1125
  alignItems: "center"
1045
1126
  },
1046
1127
  children: [
1047
- /* @__PURE__ */ jsxs4(
1048
- "button",
1049
- {
1050
- onClick: handleCreate,
1051
- style: {
1052
- padding: "10px 20px",
1053
- fontSize: "14px",
1054
- backgroundColor: "var(--color-primary, #6c63ff)",
1055
- color: "#fff",
1056
- border: "none",
1057
- borderRadius: "6px",
1058
- cursor: "pointer",
1059
- fontWeight: 500
1060
- },
1061
- children: [
1062
- "+ ",
1063
- t.newDrawing
1064
- ]
1065
- }
1066
- ),
1128
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: "8px" }, children: [
1129
+ /* @__PURE__ */ jsxs4(
1130
+ "button",
1131
+ {
1132
+ onClick: handleCreate,
1133
+ style: {
1134
+ padding: "10px 20px",
1135
+ fontSize: "14px",
1136
+ backgroundColor: "var(--color-primary, #6c63ff)",
1137
+ color: "#fff",
1138
+ border: "none",
1139
+ borderRadius: "6px",
1140
+ cursor: "pointer",
1141
+ fontWeight: 500
1142
+ },
1143
+ children: [
1144
+ "+ ",
1145
+ t.newDrawing
1146
+ ]
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ jsxs4(
1150
+ "button",
1151
+ {
1152
+ onClick: importWorkspace,
1153
+ style: {
1154
+ padding: "10px 20px",
1155
+ fontSize: "14px",
1156
+ backgroundColor: "transparent",
1157
+ border: "1px solid var(--default-border-color, #ccc)",
1158
+ borderRadius: "6px",
1159
+ cursor: "pointer",
1160
+ color: "inherit"
1161
+ },
1162
+ children: [
1163
+ "\u{1F4E5} ",
1164
+ t.importWorkspace
1165
+ ]
1166
+ }
1167
+ ),
1168
+ /* @__PURE__ */ jsxs4(
1169
+ "button",
1170
+ {
1171
+ onClick: exportWorkspace,
1172
+ style: {
1173
+ padding: "10px 20px",
1174
+ fontSize: "14px",
1175
+ backgroundColor: "transparent",
1176
+ border: "1px solid var(--default-border-color, #ccc)",
1177
+ borderRadius: "6px",
1178
+ cursor: "pointer",
1179
+ color: "inherit"
1180
+ },
1181
+ disabled: drawings.length === 0,
1182
+ children: [
1183
+ "\u{1F4E4} ",
1184
+ t.exportWorkspace
1185
+ ]
1186
+ }
1187
+ )
1188
+ ] }),
1067
1189
  /* @__PURE__ */ jsx6(
1068
1190
  "button",
1069
1191
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rita-workspace",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Multi-drawing workspace feature for Rita (Excalidraw fork)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",