diff --git a/01_content/lib/client.js b/01_content/lib/client.js index 80a0a7f..b715d10 100644 --- a/01_content/lib/client.js +++ b/01_content/lib/client.js @@ -8219,6 +8219,9 @@ var css = xterm_default + "\n" + [ ".dsh-wt_dropGear:hover{background:var(--wt-chip);color:var(--wt-text)}", ".dsh-wt_dropWide{width:264px}", ".dsh-wt_dropTrash{flex:none;width:22px;height:22px;margin-right:2px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--wt-text3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background .15s ease,color .15s ease}", + ".dsh-wt_dragHandle{flex:none;width:18px;height:22px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--wt-text3);cursor:grab;display:inline-flex;align-items:center;justify-content:center;transition:background .15s ease,color .15s ease;touch-action:none}", + ".dsh-wt_dragHandle:hover{background:var(--wt-chip);color:var(--wt-text2)}", + ".dsh-wt_dragHandleOn{background:var(--wt-chip);color:var(--wt-text);cursor:grabbing}", ".dsh-wt_dropTrash:hover{background:rgba(244,63,94,.16);color:#f87171}", ".dsh-wt_gridLabel{flex:none;white-space:nowrap;font-size:12px;line-height:17px;color:var(--wt-text2);padding:2px 2px 2px 4px}", ".dsh-wt_gridHalf .dsh-wt_switch{margin-right:2px}", @@ -8515,6 +8518,7 @@ var zh = { "console.bgPhotoUse": "\u4F7F\u7528\u6B64\u7167\u7247", "console.bgPhotoCurrent": "\u5F53\u524D\u4F7F\u7528", "console.bgPhotoNone": "\u8FD8\u6CA1\u6709\u4E0A\u4F20\u8FC7\u7167\u7247", + "console.bgMediaDrag": "\u62D6\u52A8\u8C03\u6574\u987A\u5E8F", "console.bgPhotoDelete": "\u5220\u9664\u8FD9\u6761\u5A92\u4F53", "console.bgGridLabel": "\u7F51\u683C\u80CC\u666F", "console.bgTipB": "\u8D34\u7247\u6A21\u7CCA\u7A0B\u5EA6", @@ -8729,6 +8733,7 @@ var en = { "console.bgPhotoUse": "Use this photo", "console.bgPhotoCurrent": "In use", "console.bgPhotoNone": "No photos yet", + "console.bgMediaDrag": "Drag to reorder", "console.bgPhotoDelete": "Delete this media", "console.bgGridLabel": "Background grid", "console.bgTipB": "Card blur", @@ -18080,6 +18085,42 @@ function ConsolePane() { setAutoCheck(next); if (next) void runUpdateCheck(false); }; + const dragRowRef = (0, import_react.useRef)(null); + const [dragRowId, setDragRowId] = (0, import_react.useState)(null); + const onHandleDown = (id, e) => { + if (e.button !== 0) return; + e.preventDefault(); + e.stopPropagation(); + dragRowRef.current = id; + setDragRowId(id); + const onMove = (ev) => { + if (dragRowRef.current !== id) return; + const rows = Array.from(document.querySelectorAll(".dsh-wt_photoRow")); + let target = 0; + for (let i = 0; i < rows.length; i++) { + const r = rows[i].getBoundingClientRect(); + if (ev.clientY > r.top + r.height / 2) target = i + 1; + } + const from = photoList.findIndex((x) => x.id === id); + if (from < 0) return; + const next = [...photoList]; + const moved = next.splice(from, 1)[0]; + const to = Math.max(0, Math.min(target > from ? target - 1 : target, next.length)); + next.splice(to, 0, moved); + setPhotoList(next); + }; + const onUp = () => { + dragRowRef.current = null; + setDragRowId(null); + window.removeEventListener("pointermove", onMove); + window.removeEventListener("pointerup", onUp); + const ids = photoList.map((x) => x.id); + void splitEnv?.console?.reorderPhotos?.(ids).catch(() => { + }); + }; + window.addEventListener("pointermove", onMove); + window.addEventListener("pointerup", onUp); + }; const selectPhoto = (p) => { setPhotoIdLocal(p.id); splitEnv?.console?.setPhotoId?.(p.id); @@ -18484,6 +18525,14 @@ function ConsolePane() { ] }) }) ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-wt_photoName", children: photoId === p.id ? T("console.bgPhotoCurrent") : T("console.bgPhotoUse") }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dsh-wt_dragHandle" + (dragRowId === p.id ? " dsh-wt_dragHandleOn" : ""), title: T("console.bgMediaDrag"), "aria-label": T("console.bgMediaDrag"), onPointerDown: (e) => onHandleDown(p.id, e), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "10", height: "12", viewBox: "0 0 10 12", "aria-hidden": true, children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "2.5", cy: "2", r: "1.1", fill: "currentColor" }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "7.5", cy: "2", r: "1.1", fill: "currentColor" }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "2.5", cy: "6", r: "1.1", fill: "currentColor" }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "7.5", cy: "6", r: "1.1", fill: "currentColor" }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "2.5", cy: "10", r: "1.1", fill: "currentColor" }), + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "7.5", cy: "10", r: "1.1", fill: "currentColor" }) + ] }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dsh-wt_dropTrash", title: T("console.bgPhotoDelete"), "aria-label": T("console.bgPhotoDelete"), onClick: (e) => { e.stopPropagation(); removePhotoById(p); @@ -19594,7 +19643,9 @@ function getAll(db) { arr.push({ id: r.id, createdAt: r.createdAt, kind: kindOf(r.blob), blob: r.blob }); } } - arr.sort((a, b) => b.createdAt - a.createdAt); + const allOrdered = arr.every((r) => typeof r.order === "number"); + if (allOrdered) arr.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); + else arr.sort((a, b) => b.createdAt - a.createdAt); db.close(); resolve(arr); }; @@ -19657,6 +19708,40 @@ var photoStore = { }; }); }, + /** 排序:ids 按给定顺序写入 order(0..n),其余保持原顺序追加在后 */ + async reorder(ids) { + const db = await openDb(); + const cur = await getAll(db); + const idx = /* @__PURE__ */ new Map(); + ids.forEach((id, i) => idx.set(id, i)); + const ordered = []; + const restSorted = [...cur].sort((a, b) => b.createdAt - a.createdAt); + for (const r of cur) { + const n = idx.get(r.id); + if (typeof n === "number") ordered.push({ ...r, order: n }); + } + let tail = ordered.length; + for (const r of restSorted) { + if (!idx.has(r.id)) ordered.push({ ...r, order: tail++ }); + } + return new Promise((resolve, reject) => { + const tx = db.transaction(STORE, "readwrite"); + const store = tx.objectStore(STORE); + for (const r of ordered) store.put(r, r.id); + tx.oncomplete = () => { + db.close(); + resolve(); + }; + tx.onerror = () => { + db.close(); + reject(tx.error); + }; + tx.onabort = () => { + db.close(); + reject(tx.error); + }; + }); + }, /** 删除一张记录 */ async remove(id) { const db = await openDb(); @@ -20958,6 +21043,9 @@ function WorktableSection(props) { removePhoto: async (id) => { await photoStore.remove(id); }, + reorderPhotos: async (ids) => { + await photoStore.reorder(ids); + }, getPhotoGrid: () => viewRef.current.consoleBgPhotoGrid !== false, setPhotoGrid: (v) => persistView({ consoleBgPhotoGrid: v }), getGridOpacity: () => viewRef.current.consoleBgGridOpacity ?? 8, diff --git a/01_content/src/client/index.tsx b/01_content/src/client/index.tsx index 6ce2922..b74efa3 100644 --- a/01_content/src/client/index.tsx +++ b/01_content/src/client/index.tsx @@ -1425,6 +1425,7 @@ function WorktableSection(props: any) { }, setPhotoId: (id: string) => persistView({ consoleBgPhotoId: id }), removePhoto: async (id: string) => { await photoStore.remove(id) }, + reorderPhotos: async (ids: string[]) => { await photoStore.reorder(ids) }, getPhotoGrid: () => viewRef.current.consoleBgPhotoGrid !== false, setPhotoGrid: (v: boolean) => persistView({ consoleBgPhotoGrid: v }), getGridOpacity: () => viewRef.current.consoleBgGridOpacity ?? 8, diff --git a/01_content/src/client/locales.ts b/01_content/src/client/locales.ts index 4ece08c..67492be 100644 --- a/01_content/src/client/locales.ts +++ b/01_content/src/client/locales.ts @@ -134,6 +134,7 @@ export const zh = { 'console.bgPhotoUse': '使用此照片', 'console.bgPhotoCurrent': '当前使用', 'console.bgPhotoNone': '还没有上传过照片', + 'console.bgMediaDrag': '拖动调整顺序', 'console.bgPhotoDelete': '删除这条媒体', 'console.bgGridLabel': '网格背景', 'console.bgTipB': '贴片模糊程度', @@ -353,6 +354,7 @@ export const en = { 'console.bgPhotoUse': 'Use this photo', 'console.bgPhotoCurrent': 'In use', 'console.bgPhotoNone': 'No photos yet', + 'console.bgMediaDrag': 'Drag to reorder', 'console.bgPhotoDelete': 'Delete this media', 'console.bgGridLabel': 'Background grid', 'console.bgTipB': 'Card blur', diff --git a/01_content/src/client/photoStore.ts b/01_content/src/client/photoStore.ts index 7c6e573..a047816 100644 --- a/01_content/src/client/photoStore.ts +++ b/01_content/src/client/photoStore.ts @@ -7,7 +7,7 @@ const LEGACY_STORE = 'consoleBgPhoto' const LEGACY_KEY = 'original' export type MediaKind = 'photo' | 'video' -export type PhotoRecord = { id: string; createdAt: number; kind: MediaKind; blob: Blob } +export type PhotoRecord = { id: string; createdAt: number; kind: MediaKind; blob: Blob; order?: number } export const kindOf = (blob: Blob): MediaKind => (blob.type && blob.type.indexOf('video/') === 0 ? 'video' : 'photo') @@ -35,7 +35,9 @@ function getAll(db: IDBDatabase): Promise { arr.push({ id: r.id, createdAt: r.createdAt, kind: kindOf(r.blob), blob: r.blob }) } } - arr.sort((a, b) => b.createdAt - a.createdAt) + const allOrdered = arr.every((r) => typeof r.order === 'number') + if (allOrdered) arr.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) + else arr.sort((a, b) => b.createdAt - a.createdAt) db.close() resolve(arr) } @@ -87,6 +89,31 @@ export const photoStore = { tx.onabort = () => { db.close(); reject(tx.error) } }) }, + /** 排序:ids 按给定顺序写入 order(0..n),其余保持原顺序追加在后 */ + async reorder(ids: string[]): Promise { + const db = await openDb() + const cur = await getAll(db) + const idx = new Map() + ids.forEach((id, i) => idx.set(id, i)) + const ordered: PhotoRecord[] = [] + const restSorted = [...cur].sort((a, b) => b.createdAt - a.createdAt) + for (const r of cur) { + const n = idx.get(r.id) + if (typeof n === 'number') ordered.push({ ...r, order: n }) + } + let tail = ordered.length + for (const r of restSorted) { + if (!idx.has(r.id)) ordered.push({ ...r, order: tail++ }) + } + return new Promise((resolve, reject) => { + const tx = db.transaction(STORE, 'readwrite') + const store = tx.objectStore(STORE) + for (const r of ordered) store.put(r, r.id) + tx.oncomplete = () => { db.close(); resolve() } + tx.onerror = () => { db.close(); reject(tx.error) } + tx.onabort = () => { db.close(); reject(tx.error) } + }) + }, /** 删除一张记录 */ async remove(id: string): Promise { const db = await openDb() diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index 475c682..100d82a 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -255,6 +255,7 @@ type SplitEnv = { getPhotoHsl: (id: string) => { h: number; s: number; l: number } setPhotoHsl: (id: string, v: { h: number; s: number; l: number }) => void removePhoto: (id: string) => Promise + reorderPhotos: (ids: string[]) => Promise getPhotoGrid: () => boolean setPhotoGrid: (v: boolean) => void getGridOpacity: () => number @@ -1571,6 +1572,42 @@ function ConsolePane() { storeAutoCheck(next) if (next) void runUpdateCheck(false) } + /** 抓手拖拽排序:按住抓手上下移动 → 行实时重排,松手持久化 */ + const dragRowRef = useRef(null) + const [dragRowId, setDragRowId] = useState(null) + const onHandleDown = (id: string, e: { button: number; preventDefault: () => void; stopPropagation: () => void }) => { + if (e.button !== 0) return + e.preventDefault() + e.stopPropagation() + dragRowRef.current = id + setDragRowId(id) + const onMove = (ev: PointerEvent) => { + if (dragRowRef.current !== id) return + const rows = Array.from(document.querySelectorAll('.dsh-wt_photoRow')) + let target = 0 + for (let i = 0; i < rows.length; i++) { + const r = rows[i].getBoundingClientRect() + if (ev.clientY > r.top + r.height / 2) target = i + 1 + } + const from = photoList.findIndex((x) => x.id === id) + if (from < 0) return + const next = [...photoList] + const moved = next.splice(from, 1)[0] + const to = Math.max(0, Math.min(target > from ? target - 1 : target, next.length)) + next.splice(to, 0, moved) + setPhotoList(next) + } + const onUp = () => { + dragRowRef.current = null + setDragRowId(null) + window.removeEventListener('pointermove', onMove) + window.removeEventListener('pointerup', onUp) + const ids = photoList.map((x) => x.id) + void splitEnv?.console?.reorderPhotos?.(ids).catch(() => {}) + } + window.addEventListener('pointermove', onMove) + window.addEventListener('pointerup', onUp) + } /** 在媒体库中选中某条 */ const selectPhoto = (p: { id: string; kind: 'photo' | 'video'; url: string }) => { setPhotoIdLocal(p.id) @@ -1889,6 +1926,7 @@ function ConsolePane() { : } {photoId === p.id ? T('console.bgPhotoCurrent') : T('console.bgPhotoUse')} + )) diff --git a/01_content/src/client/styles.ts b/01_content/src/client/styles.ts index 60a6249..735fca0 100644 --- a/01_content/src/client/styles.ts +++ b/01_content/src/client/styles.ts @@ -467,6 +467,9 @@ export const css = xtermCss + '\n' + [ '.dsh-wt_dropGear:hover{background:var(--wt-chip);color:var(--wt-text)}', '.dsh-wt_dropWide{width:264px}', '.dsh-wt_dropTrash{flex:none;width:22px;height:22px;margin-right:2px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--wt-text3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background .15s ease,color .15s ease}', + '.dsh-wt_dragHandle{flex:none;width:18px;height:22px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--wt-text3);cursor:grab;display:inline-flex;align-items:center;justify-content:center;transition:background .15s ease,color .15s ease;touch-action:none}', + '.dsh-wt_dragHandle:hover{background:var(--wt-chip);color:var(--wt-text2)}', + '.dsh-wt_dragHandleOn{background:var(--wt-chip);color:var(--wt-text);cursor:grabbing}', '.dsh-wt_dropTrash:hover{background:rgba(244,63,94,.16);color:#f87171}', '.dsh-wt_gridLabel{flex:none;white-space:nowrap;font-size:12px;line-height:17px;color:var(--wt-text2);padding:2px 2px 2px 4px}', '.dsh-wt_gridHalf .dsh-wt_switch{margin-right:2px}', diff --git a/02_process/tmp-async.ps1 b/02_process/tmp-async.ps1 new file mode 100644 index 0000000..a43d58a --- /dev/null +++ b/02_process/tmp-async.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { window.__t = 1; setTimeout(() => { window.__t = 2; }, 400); return 's'; })()" +Start-Sleep -Milliseconds 900 +opencli --profile 74u3g3us browser wt eval "window.__t" diff --git a/02_process/tmp-idb.ps1 b/02_process/tmp-idb.ps1 new file mode 100644 index 0000000..2d9d43c --- /dev/null +++ b/02_process/tmp-idb.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { window.__idb = 'pending'; const o = indexedDB.open('dsh-worktable', 2); o.onsuccess = () => { try { const db = o.result; const names = Array.from(db.objectStoreNames).join(','); const r = db.transaction('photoRecords', 'readonly').objectStore('photoRecords').get('default1'); r.onsuccess = () => { window.__idb = 'names=' + names + ';get-default1=' + (r.target.result ? 'found ' + r.target.result.blob.type + ' ' + r.target.result.blob.size : 'null'); }; r.onerror = () => { window.__idb = 'get-err'; }; } catch (e) { window.__idb = 'tx-err:' + e.message; } }; o.onerror = () => { window.__idb = 'open-err'; }; return 's'; })()" +Start-Sleep -Milliseconds 1500 +opencli --profile 74u3g3us browser wt eval "window.__idb" diff --git a/02_process/tmp-list.ps1 b/02_process/tmp-list.ps1 new file mode 100644 index 0000000..4463fda --- /dev/null +++ b/02_process/tmp-list.ps1 @@ -0,0 +1,2 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { const o = indexedDB.open('dsh-worktable', 2); o.onsuccess = () => { const r = o.result.transaction('photoRecords', 'readonly').objectStore('photoRecords').getAll(); r.onsuccess = () => { const out = r.target.result.map(x => ({ id: x.id, createdAt: x.createdAt, type: x.blob && x.blob.type, size: x.blob && x.blob.size })); console.log('DATA:' + JSON.stringify(out)); }; }; return 'go'; })()" diff --git a/02_process/tmp-list2.ps1 b/02_process/tmp-list2.ps1 new file mode 100644 index 0000000..2638d6b --- /dev/null +++ b/02_process/tmp-list2.ps1 @@ -0,0 +1,2 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(async () => { const o = indexedDB.open('dsh-worktable', 2); const db = await new Promise((res, rej) => { o.onsuccess = () => res(o.result); o.onerror = () => rej(o.error); }); const r = db.transaction('photoRecords', 'readonly').objectStore('photoRecords').getAll(); const list = await new Promise((res, rej) => { r.onsuccess = () => res(r.target.result); r.onerror = () => rej(r.error); }); return JSON.stringify(list.map(x => ({ id: x.id, type: x.blob && x.blob.type, size: x.blob && x.blob.size }))); })()" diff --git a/02_process/tmp-list3.ps1 b/02_process/tmp-list3.ps1 new file mode 100644 index 0000000..65eba1b --- /dev/null +++ b/02_process/tmp-list3.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { const o = indexedDB.open('dsh-worktable', 2); o.onsuccess = () => { const r = o.result.transaction('photoRecords', 'readonly').objectStore('photoRecords').getAll(); r.onsuccess = () => { window.__mediaList = JSON.stringify(r.target.result.map(x => ({ id: x.id, type: x.blob && x.blob.type, size: x.blob && x.blob.size }))); }; }; return 'scheduled'; })()" +Start-Sleep -Milliseconds 1200 +opencli --profile 74u3g3us browser wt eval "window.__mediaList || 'none'" diff --git a/02_process/tmp-list4.ps1 b/02_process/tmp-list4.ps1 new file mode 100644 index 0000000..4b2cdeb --- /dev/null +++ b/02_process/tmp-list4.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { try { const o = indexedDB.open('dsh-worktable', 2); o.onerror = () => { window.__mediaList = 'open-err'; }; o.onsuccess = () => { const db = o.result; try { const tx = db.transaction('photoRecords', 'readonly'); const r = tx.objectStore('photoRecords').getAll(); r.onsuccess = () => { window.__mediaList = JSON.stringify(r.target.result.map(x => ({ id: x.id, type: x.blob && x.blob.type, size: x.blob && x.blob.size }))); }; r.onerror = () => { window.__mediaList = 'get-err'; }; } catch (e) { window.__mediaList = 'tx-err:' + e.message; } }; return 'go2'; })()" +Start-Sleep -Milliseconds 3000 +opencli --profile 74u3g3us browser wt eval "window.__mediaList || 'none2'" diff --git a/02_process/tmp-list5.ps1 b/02_process/tmp-list5.ps1 new file mode 100644 index 0000000..696f831 --- /dev/null +++ b/02_process/tmp-list5.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { window.__mediaList = 'pending'; const o = indexedDB.open('dsh-worktable', 2); o.onerror = () => { window.__mediaList = 'open-err'; }; o.onsuccess = () => { const db = o.result; const r = db.transaction('photoRecords', 'readonly').objectStore('photoRecords').getAll(); r.onsuccess = () => { window.__mediaList = JSON.stringify(r.target.result.map(x => ({ id: x.id, type: x.blob && x.blob.type, size: x.blob && x.blob.size }))); }; r.onerror = () => { window.__mediaList = 'get-err'; }; }; return 'go3'; })()" +Start-Sleep -Milliseconds 2500 +opencli --profile 74u3g3us browser wt eval "window.__mediaList || 'none3'" diff --git a/02_process/tmp-seed.ps1 b/02_process/tmp-seed.ps1 new file mode 100644 index 0000000..170b797 --- /dev/null +++ b/02_process/tmp-seed.ps1 @@ -0,0 +1,3 @@ +$ErrorActionPreference = 'Stop' +opencli --profile 74u3g3us browser wt eval "(() => { try { const id = 'default1'; const svg = atob('PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgwIiBoZWlnaHQ9IjcyMCIgdmlld0JveD0iMCAwIDEyODAgNzIwIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImciIHgxPSIwIiB5MT0iMCIgeDI9IjAiIHkyPSIxIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMwYTBkMTMiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMxMDFhMmUiLz48L2xpbmVhckdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iYjEiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzRmOGVmNyIgc3RvcC1vcGFjaXR5PSIwLjU1Ii8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNGY4ZWY3IiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iYjIiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzdhNWNmZiIgc3RvcC1vcGFjaXR5PSIwLjQ1Ii8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN2E1Y2ZmIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iYjMiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzAwYzJmZiIgc3RvcC1vcGFjaXR5PSIwLjQiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMGMyZmYiIHN0b3Atb3BhY2l0eT0iMCIvPjwvcmFkaWFsR3JhZGllbnQ+PHJhZGlhbEdyYWRpZW50IGlkPSJiNCI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmY5YTNkIiBzdG9wLW9wYWNpdHk9IjAuMjgiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNmZjlhM2QiIHN0b3Atb3BhY2l0eT0iMCIvPjwvcmFkaWFsR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMjgwIiBoZWlnaHQ9IjcyMCIgZmlsbD0idXJsKCNnKSIvPjxlbGxpcHNlIGN4PSIzMDAiIGN5PSIxODAiIHJ4PSI0MjAiIHJ5PSIyNjAiIGZpbGw9InVybCgjYjEpIi8+PGVsbGlwc2UgY3g9Ijk4MCIgY3k9IjIyMCIgcng9IjM4MCIgcnk9IjI0MCIgZmlsbD0idXJsKCNiMikiLz48ZWxsaXBzZSBjeD0iNzYwIiBjeT0iNTYwIiByeD0iNDIwIiByeT0iMjUwIiBmaWxsPSJ1cmwoI2IzKSIvPjxlbGxpcHNlIGN4PSIxODAiIGN5PSI2MDAiIHJ4PSIzMDAiIHJ5PSIyMDAiIGZpbGw9InVybCgjYjQpIi8+PC9zdmc+'); const o = indexedDB.open('dsh-worktable', 2); o.onsuccess = () => { const db = o.result; const tx = db.transaction('photoRecords', 'readwrite'); tx.objectStore('photoRecords').put({ id: id, createdAt: Date.now(), blob: new Blob([svg], { type: 'image/svg+xml' }) }, id); tx.oncomplete = () => { db.close(); }; tx.onerror = () => {}; }; return 'seeded-ok'; } catch (e) { return 'err:' + e.message; } })()" +opencli --profile 74u3g3us browser wt eval "(() => { const o = indexedDB.open('dsh-worktable', 2); let n = -1; o.onsuccess = () => { o.result.transaction('photoRecords', 'readonly').objectStore('photoRecords').getAll().onsuccess = (r) => { n = r.target.result.length; }; }; return 'count-scheduled'; })()"