diff --git a/TODO.txt b/TODO.txt
index 057702e..a9831f0 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -192,25 +192,25 @@ R2. Web: Boards list + Dexie "Inspector" drawer
--------------------------------------------------------------------------------
/apps/web/src/lib/filebrowser/FileBrowser.svelte:
-[ ] Boards panel:
+[x] Boards panel:
- listBoards() -> render
- search filter
- open / create / rename / delete
Inspector drawer (selected board):
-[ ] Show "Storage"
-[ ] Show schema info:
+[x] Show "Storage"
+[x] Show schema info:
- declared schema version
- installed schema version
-[ ] Show board-level stats (computed live):
+[x] Show board-level stats (computed live):
- row counts: pages/shapes/bindings for this board & doc size bytes for docs row
- last updatedAt
-[ ] Show migration info:
+[x] Show migration info:
- list applied migrations from migrations table (id + appliedAt)
- show "pending" migrations if any (based on known list vs applied)
Safe deletes:
-[ ] deleteBoard must be a single atomic transaction (boards + related tables)
+[x] deleteBoard must be a single atomic transaction (boards + related tables)
(DoD):
- Web: you can browse boards, open one, and verify migrations + row counts.
@@ -227,8 +227,8 @@ R3. Desktop: real directory + files (Tauri)
- tree view with folders
[ ] Implement file actions:
- [x] New: create new file
- - [ ] Rename: rename file
- - [ ] Delete: delete file
+ - [ ] Rename: rename file (Tauri command needed)
+ - [ ] Delete: delete file (Tauri command needed)
- [x] Open: load file into editor
- [x] Export: save JSON
diff --git a/apps/web/src/lib/canvas/canvas-store.svelte.ts b/apps/web/src/lib/canvas/canvas-store.svelte.ts
index a210d60..145088f 100644
--- a/apps/web/src/lib/canvas/canvas-store.svelte.ts
+++ b/apps/web/src/lib/canvas/canvas-store.svelte.ts
@@ -430,7 +430,6 @@ export function createCanvasController(bindings: CanvasControllerBindings) {
let inputAdapter: InputAdapter | null = null;
let canvasInitialized = false;
- // Initialize canvas-dependent systems when canvas becomes available
$effect(() => {
if (!canvas || canvasInitialized) return;
diff --git a/apps/web/src/lib/tests/Canvas.history.test.ts b/apps/web/src/lib/tests/Canvas.history.test.ts
index 672f189..d8a1b9d 100644
--- a/apps/web/src/lib/tests/Canvas.history.test.ts
+++ b/apps/web/src/lib/tests/Canvas.history.test.ts
@@ -332,7 +332,7 @@ describe("Canvas history integration", () => {
it("wraps pointer actions in SnapshotCommands and enqueues persistence", async () => {
render(Canvas);
- // Wait for onMount to complete and input adapter to be created
+
await vi.waitFor(() => {
expect(actionHandlers.length).toBeGreaterThan(0);
});
diff --git a/packages/core/src/export.ts b/packages/core/src/export.ts
index 106b823..1ab1501 100644
--- a/packages/core/src/export.ts
+++ b/packages/core/src/export.ts
@@ -59,18 +59,15 @@ export async function exportSelectionToPNG(
return null;
}
- // Calculate combined bounds
const bounds = combineBounds(shapes.map((s) => shapeBounds(s)));
if (!bounds) {
return null;
}
- // Add padding
const padding = 20;
const width = Box2Ops.width(bounds) + padding * 2;
const height = Box2Ops.height(bounds) + padding * 2;
- // Create temporary canvas
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
@@ -80,20 +77,16 @@ export async function exportSelectionToPNG(
throw new Error("Failed to get 2D context");
}
- // Clear background (white)
context.fillStyle = "white";
context.fillRect(0, 0, width, height);
- // Translate to handle bounds offset + padding
context.save();
context.translate(-bounds.min.x + padding, -bounds.min.y + padding);
- // Let caller render the shapes
renderFunction(context, shapes, bounds);
context.restore();
- // Export to PNG
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) {
@@ -122,7 +115,6 @@ export function exportToSVG(state: EditorState, options: ExportOptions = {}): st
return "";
}
- // Calculate bounds
const bounds = combineBounds(shapes.map((s) => shapeBounds(s)));
if (!bounds) {
return "";
@@ -136,9 +128,6 @@ export function exportToSVG(state: EditorState, options: ExportOptions = {}): st
const elements: string[] = [``];
- // Add white background
-
- // Render each shape
for (const shape of shapes) {
const svg = shapeToSVG(shape, state);
if (svg) {
@@ -217,7 +206,6 @@ function lineToSVG(shape: LineShape, transform: string): string {
function arrowToSVG(shape: ArrowShape, transform: string, _state: EditorState): string {
const { a, b, stroke, width } = shape.props;
- // Calculate arrow head
const angle = Math.atan2(b.y - a.y, b.x - a.x);
const arrowLength = 15;
const arrowAngle = Math.PI / 6;
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index adffb78..485bc63 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -6,9 +6,9 @@ export * from "./geom";
export * from "./history";
export * from "./math";
export * from "./model";
-export * from "./persist/DocRepo";
export * from "./persistence/db";
export * from "./persistence/desktop";
+export * from "./persistence/repo";
export * from "./persistence/stats";
export * from "./persistence/web";
export * from "./reactivity";
diff --git a/packages/core/src/persistence/db.ts b/packages/core/src/persistence/db.ts
index 7814886..271b9ab 100644
--- a/packages/core/src/persistence/db.ts
+++ b/packages/core/src/persistence/db.ts
@@ -1,6 +1,6 @@
import Dexie, { type Transaction } from "dexie";
import { PageRecord as PageOps } from "../model";
-import type { BoardMeta, Timestamp } from "../persist/DocRepo";
+import type { BoardMeta, Timestamp } from "./repo";
import type { BindingRow, MetaRow, MigrationRow, PageRow, ShapeRow } from "./web";
export const DB_NAME = "inkfinite";
diff --git a/packages/core/src/persistence/desktop.ts b/packages/core/src/persistence/desktop.ts
index e1acc18..f5ca10a 100644
--- a/packages/core/src/persistence/desktop.ts
+++ b/packages/core/src/persistence/desktop.ts
@@ -1,5 +1,5 @@
import type { BindingRecord, Document, PageRecord, ShapeRecord } from "../model";
-import type { BoardMeta } from "../persist/DocRepo";
+import type { BoardMeta } from "./repo";
import type { DocOrder, LoadedDoc } from "./web";
/**
diff --git a/packages/core/src/persist/DocRepo.ts b/packages/core/src/persistence/repo.ts
similarity index 91%
rename from packages/core/src/persist/DocRepo.ts
rename to packages/core/src/persistence/repo.ts
index b01bdb7..f312306 100644
--- a/packages/core/src/persist/DocRepo.ts
+++ b/packages/core/src/persistence/repo.ts
@@ -4,7 +4,6 @@ export type BoardMeta = { id: string; name: string; createdAt: Timestamp; update
/**
* Shared document repository contract used by both web and desktop persistence layers.
- * Provides the minimal operations required for listing and managing boards.
*/
export interface DocRepo {
/**
diff --git a/packages/core/src/persistence/stats.ts b/packages/core/src/persistence/stats.ts
index 5718149..ff66446 100644
--- a/packages/core/src/persistence/stats.ts
+++ b/packages/core/src/persistence/stats.ts
@@ -1,4 +1,4 @@
-import type { Timestamp } from "../persist/DocRepo";
+import type { Timestamp } from "./repo";
export type BoardStats = {
pageCount: number;
diff --git a/packages/core/src/persistence/web.ts b/packages/core/src/persistence/web.ts
index caa58db..3ba9908 100644
--- a/packages/core/src/persistence/web.ts
+++ b/packages/core/src/persistence/web.ts
@@ -9,7 +9,7 @@ import {
type ShapeRecord,
ShapeRecord as ShapeOps,
} from "../model";
-import type { BoardMeta, DocRepo, Timestamp } from "../persist/DocRepo";
+import type { BoardMeta, DocRepo, Timestamp } from "./repo";
import type { BoardInspectorData, BoardStats, MigrationInfo, SchemaInfo } from "./stats";
import { BoardStatsOps, getPendingMigrations } from "./stats";
diff --git a/packages/core/src/ui/filebrowser.ts b/packages/core/src/ui/filebrowser.ts
index 75b3062..9fa210c 100644
--- a/packages/core/src/ui/filebrowser.ts
+++ b/packages/core/src/ui/filebrowser.ts
@@ -1,4 +1,4 @@
-import type { BoardMeta, DocRepo } from "../persist/DocRepo";
+import type { BoardMeta, DocRepo } from "../persistence/repo";
export type FileBrowserActions = {
open(boardId: string): Promise;
diff --git a/packages/core/tests/filebrowser.test.ts b/packages/core/tests/filebrowser.test.ts
index e8f3b15..33cc10f 100644
--- a/packages/core/tests/filebrowser.test.ts
+++ b/packages/core/tests/filebrowser.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from "vitest";
-import type { DocRepo } from "../src/persist/DocRepo";
+import type { DocRepo } from "../src/persistence/repo";
import { FileBrowserVM } from "../src/ui/filebrowser";
function createRepoMock(): DocRepo {