Files
Excalidraw/excalidraw/excalidraw-app/data/storageAdapters/IndexedDBStorageAdapter.ts
T
Yuzhong Zhang 602f4629ff init frontend
2025-07-05 23:22:48 +08:00

95 lines
3.0 KiB
TypeScript

import { createStore, set, get, del, entries } from "idb-keyval";
import { CanvasData, CanvasMetadata, IStorageAdapter } from "../storage";
import { generateThumbnail } from "../thumbnail";
const metadataStore = createStore("excalidraw-canvases-metadata", "metadata");
const dataStore = createStore("excalidraw-canvases-data", "data");
export class IndexedDBStorageAdapter implements IStorageAdapter {
async listCanvases(): Promise<CanvasMetadata[]> {
const allEntries = await entries<string, CanvasMetadata>(metadataStore);
return allEntries.map(([, metadata]) => metadata);
}
async loadCanvas(id: string): Promise<CanvasData | null> {
const data = await get<CanvasData>(id, dataStore);
return data === undefined ? null : data;
}
async saveCanvas(id: string, data: CanvasData): Promise<void> {
const existingMetadata = await get<CanvasMetadata>(id, metadataStore);
if (!existingMetadata) {
throw new Error("Canvas metadata not found. Cannot save.");
}
const thumbnail = await generateThumbnail(
data.elements,
data.appState,
data.files,
);
const updatedMetadata: CanvasMetadata = {
...existingMetadata,
name: data.appState.name || existingMetadata.name,
updatedAt: new Date().toISOString(),
thumbnail: data.elements.length > 0 ? thumbnail : undefined,
};
await set(id, updatedMetadata, metadataStore);
await set(id, data, dataStore);
}
async createCanvas(data: CanvasData): Promise<CanvasMetadata> {
const newId = window.crypto.randomUUID();
const now = new Date().toISOString();
const thumbnail = await generateThumbnail(
data.elements,
data.appState,
data.files,
);
const newMetadata: CanvasMetadata = {
id: newId,
name: data.appState.name || "Untitled Canvas",
createdAt: now,
updatedAt: now,
// UserID is 0 for local, non-synced canvases
userId: 0,
thumbnail: data.elements.length > 0 ? thumbnail : undefined,
};
await set(newId, newMetadata, metadataStore);
await set(newId, data, dataStore);
return newMetadata;
}
async deleteCanvas(id: string): Promise<void> {
await del(id, metadataStore);
await del(id, dataStore);
}
async renameCanvas(id: string, newName: string): Promise<void> {
// Update metadata
const existingMetadata = await get<CanvasMetadata>(id, metadataStore);
if (!existingMetadata) {
throw new Error("Canvas metadata not found. Cannot rename.");
}
await set(id, { ...existingMetadata, name: newName }, metadataStore);
// Update canvas data
const existingData = await get<CanvasData>(id, dataStore);
if (!existingData) {
// This should not happen if metadata exists, but as a safeguard:
throw new Error("Canvas data not found. Cannot rename.");
}
await set(
id,
{
...existingData,
appState: { ...existingData.appState, name: newName },
},
dataStore,
);
}
}