From dbc722abd35ec8dcd69fbd03a980d4b0ede421a1 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Fri, 21 Aug 2026 21:22:25 -0500 Subject: [PATCH] refactor: reorganize editor controls for compact layouts --- TODO.md | 16 +- apps/web/src/lib/tests/Canvas.svelte.test.ts | 16 +- .../web/src/lib/tests/TitleBar.svelte.test.ts | 17 +- .../ui/src/lib/editor/canvas/Canvas.svelte | 31 +- .../editor/components/ProposalReview.svelte | 2 +- .../lib/editor/components/StatusBar.svelte | 39 +- .../src/lib/editor/components/Toolbar.svelte | 1251 ++++++++++------- .../__tests__/StatusBar.svelte.test.ts | 22 + .../__tests__/Toolbar.svelte.test.ts | 24 +- 9 files changed, 829 insertions(+), 589 deletions(-) diff --git a/TODO.md b/TODO.md index 8b6a76c..8eeb006 100644 --- a/TODO.md +++ b/TODO.md @@ -21,18 +21,18 @@ and rendered output where visual fidelity matters. Separate persistent application actions from drawing tools and selection-specific controls. -- [ ] Split the current editor toolbar into tool, application, and contextual +- [x] Split the current editor toolbar into tool, application, and contextual control surfaces -- [ ] Keep the primary tool dock limited to tool selection and active-tool +- [x] Keep the primary tool dock limited to tool selection and active-tool controls -- [ ] Move import and export into file/application chrome -- [ ] Move layout, arrange, group, lock, and related commands into selection +- [x] Move import and export into file/application chrome +- [x] Move layout, arrange, group, lock, and related commands into selection context -- [ ] Move stencils into an insert/library surface -- [ ] Remove the Stormlight Labs tagline and other non-editor content from the +- [x] Move stencils into an insert/library surface +- [x] Remove the Stormlight Labs tagline and other non-editor content from the primary drawing controls -- [ ] Preserve compact layouts for narrower viewports and coarse pointers -- [ ] Verify floating controls do not obscure selection handles, dialogs, or +- [x] Preserve compact layouts for narrower viewports and coarse pointers +- [x] Verify floating controls do not obscure selection handles, dialogs, or proposal review UI ### Contextual selection controls diff --git a/apps/web/src/lib/tests/Canvas.svelte.test.ts b/apps/web/src/lib/tests/Canvas.svelte.test.ts index 625b700..26fcb75 100644 --- a/apps/web/src/lib/tests/Canvas.svelte.test.ts +++ b/apps/web/src/lib/tests/Canvas.svelte.test.ts @@ -114,15 +114,14 @@ describe('Canvas component', () => { expect(statusBar?.querySelector('[aria-label="History"]')).toBeTruthy(); }); - it('should render all tool buttons in toolbar', () => { + it('keeps the tool dock limited to drawing tools', () => { const { container } = renderCanvas(); - const toolButtons = container.querySelectorAll('.tool-button'); + const toolButtons = container.querySelectorAll('.toolbar .tool-button'); - expect(toolButtons.length).toBe(11); + expect(toolButtons.length).toBe(10); const toolIds = Array.from(toolButtons).map((btn) => btn.getAttribute('data-tool-id')); - const coreToolIds = toolIds.filter((id) => id && id !== 'history'); - expect(coreToolIds).toEqual([ + expect(toolIds).toEqual([ 'select', 'direct-select', 'rect', @@ -135,8 +134,11 @@ describe('Canvas component', () => { 'pen' ]); - const historyButton = container.querySelector('.status-bar__action[aria-label="History"]'); - expect(historyButton).toBeTruthy(); + const insertButton = container.querySelector( + '.application-chrome [aria-label="Open stencils library"]' + ); + expect(insertButton).toBeTruthy(); + expect(insertButton?.closest('.toolbar')).toBeNull(); }); it('should have select tool active by default', () => { diff --git a/apps/web/src/lib/tests/TitleBar.svelte.test.ts b/apps/web/src/lib/tests/TitleBar.svelte.test.ts index cbf483c..f17750a 100644 --- a/apps/web/src/lib/tests/TitleBar.svelte.test.ts +++ b/apps/web/src/lib/tests/TitleBar.svelte.test.ts @@ -19,22 +19,29 @@ const renderToolbar = (overrides: Partial> = {}) return { container }; }; -describe('TitleBar (merged into Toolbar)', () => { +describe('Editor application chrome', () => { beforeEach(() => { cleanup(); }); - it('renders the title and monochrome logo', () => { + it('renders the application title and monochrome logo', () => { const { container } = renderToolbar(); - expect(container.querySelector('.toolbar')).toBeTruthy(); + expect(container.querySelector('.application-chrome')).toBeTruthy(); expect(container.querySelector('.toolbar__logo svg path')?.getAttribute('fill')).toBe( 'currentColor' ); + expect(container.querySelector('.toolbar__tagline')).toBeNull(); }); it('keeps file commands out of the drawing toolbar', () => { const { container } = renderToolbar(); - expect(container.querySelector('.toolbar__desktop')).toBeNull(); - expect(container.textContent).not.toContain('Save As…'); + expect(container.querySelector('.toolbar .toolbar__import-button')).toBeNull(); + expect(container.querySelector('.toolbar .toolbar__export-button')).toBeNull(); + expect( + container.querySelector('.application-chrome .toolbar__import-button') + ).toBeTruthy(); + expect( + container.querySelector('.application-chrome .toolbar__export-button') + ).toBeTruthy(); }); }); diff --git a/packages/ui/src/lib/editor/canvas/Canvas.svelte b/packages/ui/src/lib/editor/canvas/Canvas.svelte index 6931b0d..5c29678 100644 --- a/packages/ui/src/lib/editor/canvas/Canvas.svelte +++ b/packages/ui/src/lib/editor/canvas/Canvas.svelte @@ -501,19 +501,24 @@ icon: allLocked ? 'lock-open' : 'lock', disabled: selected.length === 0 }, - { - id: 'agent-editable', - label: SELECTION_COMMAND_LABELS['agent-editable'], - icon: 'terminal', - disabled: selected.length === 0 - }, - { - id: 'agent-readonly', - label: SELECTION_COMMAND_LABELS['agent-readonly'], - icon: 'lock-open', - disabled: selected.length === 0 - }, - { type: 'separator' }, + ...(platformKind === 'desktop' + ? [ + { type: 'separator' as const }, + { + id: 'agent-editable', + label: SELECTION_COMMAND_LABELS['agent-editable'], + icon: 'terminal' as const, + disabled: selected.length === 0 + }, + { + id: 'agent-readonly', + label: SELECTION_COMMAND_LABELS['agent-readonly'], + icon: 'lock-open' as const, + disabled: selected.length === 0 + }, + { type: 'separator' as const } + ] + : []), { id: 'zoom-selection', label: 'Zoom to selection', diff --git a/packages/ui/src/lib/editor/components/ProposalReview.svelte b/packages/ui/src/lib/editor/components/ProposalReview.svelte index e56d238..ad74001 100644 --- a/packages/ui/src/lib/editor/components/ProposalReview.svelte +++ b/packages/ui/src/lib/editor/components/ProposalReview.svelte @@ -144,7 +144,7 @@ position: absolute; top: 1rem; right: 1rem; - z-index: 4; + z-index: 120; width: min(24rem, calc(100% - 2rem)); box-sizing: border-box; border-radius: 0.9rem; diff --git a/packages/ui/src/lib/editor/components/StatusBar.svelte b/packages/ui/src/lib/editor/components/StatusBar.svelte index a07b112..b78b5ac 100644 --- a/packages/ui/src/lib/editor/components/StatusBar.svelte +++ b/packages/ui/src/lib/editor/components/StatusBar.svelte @@ -211,23 +211,25 @@ aria-label="Enable main snapping" /> - + {#if snapSnapshot.gridEnabled} + + {/if} @@ -323,16 +325,20 @@