rita-workspace 0.5.2 → 0.5.4
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 +76 -6
- package/dist/index.mjs +76 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -453,6 +453,54 @@ function isDrawingOpenedEarlierInOtherTab(drawingId) {
|
|
|
453
453
|
([tabId, entry]) => tabId !== TAB_ID && entry.drawingId === drawingId && entry.openedAt <= myOpenedAt
|
|
454
454
|
);
|
|
455
455
|
}
|
|
456
|
+
function cleanupStaleTabs() {
|
|
457
|
+
const tabs = getTabsMap();
|
|
458
|
+
const otherTabIds = Object.keys(tabs).filter((id) => id !== TAB_ID);
|
|
459
|
+
if (otherTabIds.length === 0) return;
|
|
460
|
+
const alive = /* @__PURE__ */ new Set();
|
|
461
|
+
try {
|
|
462
|
+
const channel = new BroadcastChannel(TAB_CHANNEL);
|
|
463
|
+
channel.onmessage = (event) => {
|
|
464
|
+
if (event.data?.type === "pong" && event.data?.tabId) {
|
|
465
|
+
alive.add(event.data.tabId);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
channel.postMessage({ type: "ping", tabId: TAB_ID });
|
|
469
|
+
setTimeout(() => {
|
|
470
|
+
const currentTabs = getTabsMap();
|
|
471
|
+
let changed = false;
|
|
472
|
+
for (const tabId of otherTabIds) {
|
|
473
|
+
if (!alive.has(tabId) && tabId in currentTabs) {
|
|
474
|
+
delete currentTabs[tabId];
|
|
475
|
+
changed = true;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (changed) {
|
|
479
|
+
const json = JSON.stringify(currentTabs);
|
|
480
|
+
localStorage.setItem(TABS_KEY, json);
|
|
481
|
+
tabsMapCache = currentTabs;
|
|
482
|
+
tabsMapRaw = json;
|
|
483
|
+
}
|
|
484
|
+
channel.close();
|
|
485
|
+
}, 500);
|
|
486
|
+
} catch {
|
|
487
|
+
const now = Date.now();
|
|
488
|
+
const maxAge = 24 * 60 * 60 * 1e3;
|
|
489
|
+
let changed = false;
|
|
490
|
+
for (const [tabId, entry] of Object.entries(tabs)) {
|
|
491
|
+
if (tabId !== TAB_ID && entry.openedAt < now - maxAge) {
|
|
492
|
+
delete tabs[tabId];
|
|
493
|
+
changed = true;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (changed) {
|
|
497
|
+
const json = JSON.stringify(tabs);
|
|
498
|
+
localStorage.setItem(TABS_KEY, json);
|
|
499
|
+
tabsMapCache = tabs;
|
|
500
|
+
tabsMapRaw = json;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
456
504
|
function WorkspaceProvider({ children, lang = "en" }) {
|
|
457
505
|
const [workspace, setWorkspace] = (0, import_react.useState)(null);
|
|
458
506
|
const [drawings, setDrawings] = (0, import_react.useState)([]);
|
|
@@ -472,6 +520,16 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
472
520
|
}
|
|
473
521
|
prevConflictRef.current = isDrawingConflict;
|
|
474
522
|
}, [isDrawingConflict, activeDrawing?.id]);
|
|
523
|
+
(0, import_react.useEffect)(() => {
|
|
524
|
+
cleanupStaleTabs();
|
|
525
|
+
const timer = setTimeout(() => {
|
|
526
|
+
const drawingId = activeDrawing?.id;
|
|
527
|
+
if (drawingId) {
|
|
528
|
+
setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
|
|
529
|
+
}
|
|
530
|
+
}, 600);
|
|
531
|
+
return () => clearTimeout(timer);
|
|
532
|
+
}, []);
|
|
475
533
|
(0, import_react.useEffect)(() => {
|
|
476
534
|
const drawingId = activeDrawing?.id || null;
|
|
477
535
|
setTabDrawing(drawingId);
|
|
@@ -491,6 +549,9 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
491
549
|
channel.postMessage({ type: "drawing-changed", tabId: TAB_ID, drawingId });
|
|
492
550
|
channel.onmessage = (event) => {
|
|
493
551
|
if (event.data?.tabId !== TAB_ID) {
|
|
552
|
+
if (event.data?.type === "ping") {
|
|
553
|
+
channel?.postMessage({ type: "pong", tabId: TAB_ID });
|
|
554
|
+
}
|
|
494
555
|
recheckConflict();
|
|
495
556
|
}
|
|
496
557
|
};
|
|
@@ -1390,7 +1451,6 @@ var DrawingsDialog = ({
|
|
|
1390
1451
|
minute: "2-digit"
|
|
1391
1452
|
});
|
|
1392
1453
|
};
|
|
1393
|
-
if (!open) return null;
|
|
1394
1454
|
const { rootDrawings, drawingsByFolder, filteredFolders } = (0, import_react5.useMemo)(() => {
|
|
1395
1455
|
const query = searchQuery.toLowerCase().trim();
|
|
1396
1456
|
const filtered = query ? drawings.filter((d) => d.name.toLowerCase().includes(query)) : drawings;
|
|
@@ -1402,6 +1462,7 @@ var DrawingsDialog = ({
|
|
|
1402
1462
|
const foldersFiltered = query ? folders.filter((f) => f.name.toLowerCase().includes(query) || (byFolder[f.id] || []).length > 0) : folders;
|
|
1403
1463
|
return { rootDrawings: root, drawingsByFolder: byFolder, filteredFolders: foldersFiltered };
|
|
1404
1464
|
}, [drawings, folders, searchQuery]);
|
|
1465
|
+
if (!open) return null;
|
|
1405
1466
|
const dialogStyle = position ? {
|
|
1406
1467
|
position: "fixed",
|
|
1407
1468
|
left: position.x,
|
|
@@ -1449,10 +1510,6 @@ var DrawingsDialog = ({
|
|
|
1449
1510
|
setDropTargetFolderId("__none__");
|
|
1450
1511
|
setTimeout(() => setDropTargetFolderId(null), 0);
|
|
1451
1512
|
},
|
|
1452
|
-
onClick: () => {
|
|
1453
|
-
if (editingId || confirmDeleteId || switchingId || movingDrawingId) return;
|
|
1454
|
-
if (activeDrawing?.id !== drawing.id) handleSelect(drawing);
|
|
1455
|
-
},
|
|
1456
1513
|
style: {
|
|
1457
1514
|
padding: "10px 12px",
|
|
1458
1515
|
display: "flex",
|
|
@@ -1460,7 +1517,7 @@ var DrawingsDialog = ({
|
|
|
1460
1517
|
gap: "12px",
|
|
1461
1518
|
borderRadius: "8px",
|
|
1462
1519
|
marginBottom: "4px",
|
|
1463
|
-
cursor: draggingDrawingId ? "grabbing" :
|
|
1520
|
+
cursor: draggingDrawingId ? "grabbing" : "default",
|
|
1464
1521
|
backgroundColor: activeDrawing?.id === drawing.id ? "var(--color-primary-light, rgba(108, 99, 255, 0.1))" : "transparent",
|
|
1465
1522
|
transition: "background-color 0.15s",
|
|
1466
1523
|
opacity: draggingDrawingId === drawing.id ? 0.4 : switchingId && switchingId !== drawing.id ? 0.5 : 1
|
|
@@ -1619,6 +1676,19 @@ var DrawingsDialog = ({
|
|
|
1619
1676
|
}
|
|
1620
1677
|
)
|
|
1621
1678
|
] }) : editingId !== drawing.id && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1679
|
+
activeDrawing?.id !== drawing.id && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1680
|
+
"button",
|
|
1681
|
+
{
|
|
1682
|
+
onClick: (e) => {
|
|
1683
|
+
e.stopPropagation();
|
|
1684
|
+
handleSelect(drawing);
|
|
1685
|
+
},
|
|
1686
|
+
disabled: !!switchingId,
|
|
1687
|
+
style: { padding: "3px 8px", fontSize: "12px", backgroundColor: "var(--color-primary, #6c63ff)", color: "#fff", border: "none", borderRadius: "4px", cursor: "pointer", opacity: switchingId ? 0.6 : 1 },
|
|
1688
|
+
title: t.open,
|
|
1689
|
+
children: switchingId === drawing.id ? "\u23F3" : t.open
|
|
1690
|
+
}
|
|
1691
|
+
),
|
|
1622
1692
|
folders.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1623
1693
|
"button",
|
|
1624
1694
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -385,6 +385,54 @@ function isDrawingOpenedEarlierInOtherTab(drawingId) {
|
|
|
385
385
|
([tabId, entry]) => tabId !== TAB_ID && entry.drawingId === drawingId && entry.openedAt <= myOpenedAt
|
|
386
386
|
);
|
|
387
387
|
}
|
|
388
|
+
function cleanupStaleTabs() {
|
|
389
|
+
const tabs = getTabsMap();
|
|
390
|
+
const otherTabIds = Object.keys(tabs).filter((id) => id !== TAB_ID);
|
|
391
|
+
if (otherTabIds.length === 0) return;
|
|
392
|
+
const alive = /* @__PURE__ */ new Set();
|
|
393
|
+
try {
|
|
394
|
+
const channel = new BroadcastChannel(TAB_CHANNEL);
|
|
395
|
+
channel.onmessage = (event) => {
|
|
396
|
+
if (event.data?.type === "pong" && event.data?.tabId) {
|
|
397
|
+
alive.add(event.data.tabId);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
channel.postMessage({ type: "ping", tabId: TAB_ID });
|
|
401
|
+
setTimeout(() => {
|
|
402
|
+
const currentTabs = getTabsMap();
|
|
403
|
+
let changed = false;
|
|
404
|
+
for (const tabId of otherTabIds) {
|
|
405
|
+
if (!alive.has(tabId) && tabId in currentTabs) {
|
|
406
|
+
delete currentTabs[tabId];
|
|
407
|
+
changed = true;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (changed) {
|
|
411
|
+
const json = JSON.stringify(currentTabs);
|
|
412
|
+
localStorage.setItem(TABS_KEY, json);
|
|
413
|
+
tabsMapCache = currentTabs;
|
|
414
|
+
tabsMapRaw = json;
|
|
415
|
+
}
|
|
416
|
+
channel.close();
|
|
417
|
+
}, 500);
|
|
418
|
+
} catch {
|
|
419
|
+
const now = Date.now();
|
|
420
|
+
const maxAge = 24 * 60 * 60 * 1e3;
|
|
421
|
+
let changed = false;
|
|
422
|
+
for (const [tabId, entry] of Object.entries(tabs)) {
|
|
423
|
+
if (tabId !== TAB_ID && entry.openedAt < now - maxAge) {
|
|
424
|
+
delete tabs[tabId];
|
|
425
|
+
changed = true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (changed) {
|
|
429
|
+
const json = JSON.stringify(tabs);
|
|
430
|
+
localStorage.setItem(TABS_KEY, json);
|
|
431
|
+
tabsMapCache = tabs;
|
|
432
|
+
tabsMapRaw = json;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
388
436
|
function WorkspaceProvider({ children, lang = "en" }) {
|
|
389
437
|
const [workspace, setWorkspace] = useState(null);
|
|
390
438
|
const [drawings, setDrawings] = useState([]);
|
|
@@ -404,6 +452,16 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
404
452
|
}
|
|
405
453
|
prevConflictRef.current = isDrawingConflict;
|
|
406
454
|
}, [isDrawingConflict, activeDrawing?.id]);
|
|
455
|
+
useEffect(() => {
|
|
456
|
+
cleanupStaleTabs();
|
|
457
|
+
const timer = setTimeout(() => {
|
|
458
|
+
const drawingId = activeDrawing?.id;
|
|
459
|
+
if (drawingId) {
|
|
460
|
+
setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
|
|
461
|
+
}
|
|
462
|
+
}, 600);
|
|
463
|
+
return () => clearTimeout(timer);
|
|
464
|
+
}, []);
|
|
407
465
|
useEffect(() => {
|
|
408
466
|
const drawingId = activeDrawing?.id || null;
|
|
409
467
|
setTabDrawing(drawingId);
|
|
@@ -423,6 +481,9 @@ function WorkspaceProvider({ children, lang = "en" }) {
|
|
|
423
481
|
channel.postMessage({ type: "drawing-changed", tabId: TAB_ID, drawingId });
|
|
424
482
|
channel.onmessage = (event) => {
|
|
425
483
|
if (event.data?.tabId !== TAB_ID) {
|
|
484
|
+
if (event.data?.type === "ping") {
|
|
485
|
+
channel?.postMessage({ type: "pong", tabId: TAB_ID });
|
|
486
|
+
}
|
|
426
487
|
recheckConflict();
|
|
427
488
|
}
|
|
428
489
|
};
|
|
@@ -1322,7 +1383,6 @@ var DrawingsDialog = ({
|
|
|
1322
1383
|
minute: "2-digit"
|
|
1323
1384
|
});
|
|
1324
1385
|
};
|
|
1325
|
-
if (!open) return null;
|
|
1326
1386
|
const { rootDrawings, drawingsByFolder, filteredFolders } = useMemo(() => {
|
|
1327
1387
|
const query = searchQuery.toLowerCase().trim();
|
|
1328
1388
|
const filtered = query ? drawings.filter((d) => d.name.toLowerCase().includes(query)) : drawings;
|
|
@@ -1334,6 +1394,7 @@ var DrawingsDialog = ({
|
|
|
1334
1394
|
const foldersFiltered = query ? folders.filter((f) => f.name.toLowerCase().includes(query) || (byFolder[f.id] || []).length > 0) : folders;
|
|
1335
1395
|
return { rootDrawings: root, drawingsByFolder: byFolder, filteredFolders: foldersFiltered };
|
|
1336
1396
|
}, [drawings, folders, searchQuery]);
|
|
1397
|
+
if (!open) return null;
|
|
1337
1398
|
const dialogStyle = position ? {
|
|
1338
1399
|
position: "fixed",
|
|
1339
1400
|
left: position.x,
|
|
@@ -1381,10 +1442,6 @@ var DrawingsDialog = ({
|
|
|
1381
1442
|
setDropTargetFolderId("__none__");
|
|
1382
1443
|
setTimeout(() => setDropTargetFolderId(null), 0);
|
|
1383
1444
|
},
|
|
1384
|
-
onClick: () => {
|
|
1385
|
-
if (editingId || confirmDeleteId || switchingId || movingDrawingId) return;
|
|
1386
|
-
if (activeDrawing?.id !== drawing.id) handleSelect(drawing);
|
|
1387
|
-
},
|
|
1388
1445
|
style: {
|
|
1389
1446
|
padding: "10px 12px",
|
|
1390
1447
|
display: "flex",
|
|
@@ -1392,7 +1449,7 @@ var DrawingsDialog = ({
|
|
|
1392
1449
|
gap: "12px",
|
|
1393
1450
|
borderRadius: "8px",
|
|
1394
1451
|
marginBottom: "4px",
|
|
1395
|
-
cursor: draggingDrawingId ? "grabbing" :
|
|
1452
|
+
cursor: draggingDrawingId ? "grabbing" : "default",
|
|
1396
1453
|
backgroundColor: activeDrawing?.id === drawing.id ? "var(--color-primary-light, rgba(108, 99, 255, 0.1))" : "transparent",
|
|
1397
1454
|
transition: "background-color 0.15s",
|
|
1398
1455
|
opacity: draggingDrawingId === drawing.id ? 0.4 : switchingId && switchingId !== drawing.id ? 0.5 : 1
|
|
@@ -1551,6 +1608,19 @@ var DrawingsDialog = ({
|
|
|
1551
1608
|
}
|
|
1552
1609
|
)
|
|
1553
1610
|
] }) : editingId !== drawing.id && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1611
|
+
activeDrawing?.id !== drawing.id && /* @__PURE__ */ jsx6(
|
|
1612
|
+
"button",
|
|
1613
|
+
{
|
|
1614
|
+
onClick: (e) => {
|
|
1615
|
+
e.stopPropagation();
|
|
1616
|
+
handleSelect(drawing);
|
|
1617
|
+
},
|
|
1618
|
+
disabled: !!switchingId,
|
|
1619
|
+
style: { padding: "3px 8px", fontSize: "12px", backgroundColor: "var(--color-primary, #6c63ff)", color: "#fff", border: "none", borderRadius: "4px", cursor: "pointer", opacity: switchingId ? 0.6 : 1 },
|
|
1620
|
+
title: t.open,
|
|
1621
|
+
children: switchingId === drawing.id ? "\u23F3" : t.open
|
|
1622
|
+
}
|
|
1623
|
+
),
|
|
1554
1624
|
folders.length > 0 && /* @__PURE__ */ jsx6(
|
|
1555
1625
|
"button",
|
|
1556
1626
|
{
|