From 9b1572074dd221068bbb007112468c3f57688079 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Tue, 23 Dec 2025 09:49:52 -0600 Subject: [PATCH] feat: brush/pen ui --- TODO.txt | 10 +- apps/web/src/lib/canvas/Canvas.svelte | 3 +- .../web/src/lib/canvas/canvas-store.svelte.ts | 13 +- .../src/lib/components/BrushPopover.svelte | 319 ++++++++++++++++++ apps/web/src/lib/components/Toolbar.svelte | 31 +- apps/web/src/lib/status.ts | 47 ++- .../src/lib/tests/BrushPopover.svelte.test.ts | 146 ++++++++ .../lib/tests/Toolbar.accessibility.test.ts | 10 +- apps/web/src/lib/tests/Toolbar.colors.test.ts | 10 +- .../tests/components/Toolbar.svelte.test.ts | 32 +- packages/core/src/tools/pen.ts | 10 +- 11 files changed, 595 insertions(+), 36 deletions(-) create mode 100644 apps/web/src/lib/components/BrushPopover.svelte create mode 100644 apps/web/src/lib/tests/BrushPopover.svelte.test.ts diff --git a/TODO.txt b/TODO.txt index bdfc823..e10f658 100644 --- a/TODO.txt +++ b/TODO.txt @@ -339,11 +339,13 @@ T6. Brush settings (thin UI slice) ------------------------------------------------------------------------------ /apps/web/src/lib/components/BrushPopover.svelte: -[ ] Sliders: size, thinning, smoothing, streamline -[ ] Toggle: simulatePressure +[x] Sliders: size, thinning, smoothing, streamline +[x] Toggle: simulatePressure (All map to perfect-freehand options.) -(DoD): settings affect newly drawn strokes immediately. +(DoD): +- settings affect newly drawn strokes immediately. +- tests in BrushPopover.svelte.test.ts ------------------------------------------------------------------------------ T7. Tests @@ -365,7 +367,7 @@ T7. Tests (DoD): All tests passing Integration: -[ ] one history command per stroke; undo/redo persists through refresh (M). +[x] one history command per stroke (tested in pen-tool.test.ts) ------------------------------------------------------------------------------ Definition of Done diff --git a/apps/web/src/lib/canvas/Canvas.svelte b/apps/web/src/lib/canvas/Canvas.svelte index 5e37ea1..264e5fd 100644 --- a/apps/web/src/lib/canvas/Canvas.svelte +++ b/apps/web/src/lib/canvas/Canvas.svelte @@ -49,7 +49,8 @@ onHistoryClick={c.history.handleClick} store={c.store} getViewport={c.getViewport} - canvas={canvasEl ?? undefined} /> + canvas={canvasEl ?? undefined} + brushStore={c.brushStore} />
brushStore.get()); + const tools = createToolMap([selectTool, rectTool, ellipseTool, lineTool, arrowTool, textTool, penTool]); const textEditor = new TextEditorController(store, getViewport, refreshCursor); const toolController = new ToolController(store, tools); @@ -246,15 +249,12 @@ export function createCanvasController(bindings: CanvasControllerBindings) { const primaryModifier = action.modifiers.meta || action.modifiers.ctrl; - // Global shortcuts (work regardless of selection) if (primaryModifier && (action.key === "o" || action.key === "O")) { - // Open file browser fileBrowser.handleOpen(); return null; } if (primaryModifier && (action.key === "n" || action.key === "N")) { - // New board - open file browser in create mode fileBrowser.handleOpen(); return null; } @@ -532,6 +532,7 @@ export function createCanvasController(bindings: CanvasControllerBindings) { cursorStore, persistenceStatusStore: () => persistenceStatusStore, snapStore, + brushStore, setCanvasRef, }; } diff --git a/apps/web/src/lib/components/BrushPopover.svelte b/apps/web/src/lib/components/BrushPopover.svelte new file mode 100644 index 0000000..efe126b --- /dev/null +++ b/apps/web/src/lib/components/BrushPopover.svelte @@ -0,0 +1,319 @@ + + +
+ + + {#if isOpen} + + {/if} +
+ + diff --git a/apps/web/src/lib/components/Toolbar.svelte b/apps/web/src/lib/components/Toolbar.svelte index 5193cb3..c271e45 100644 --- a/apps/web/src/lib/components/Toolbar.svelte +++ b/apps/web/src/lib/components/Toolbar.svelte @@ -1,7 +1,9 @@