From 0265cfb76245bdf3f193ff39f4c61dd994a9ea9f Mon Sep 17 00:00:00 2001 From: mesalogo Date: Wed, 23 Sep 2026 15:47:54 +0800 Subject: [PATCH] fix: group and label note page controls Move the record index toggle beside the back button and show text labels for both index and AI comment controls. Preserve pane visibility, keyboard focus, and narrow-window behavior; update tests and documentation. Validation: 112 workspace tests and Electron layout regression passed; typecheck and lint passed. Full suite hit unrelated test failures and timed out. --- docs/features/magic-notes/technical-design.md | 6 ++-- src/renderer/src/MagicNotesWorkspace.test.tsx | 25 +++++++++----- src/renderer/src/MagicNotesWorkspace.tsx | 34 +++++++++++-------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/docs/features/magic-notes/technical-design.md b/docs/features/magic-notes/technical-design.md index 1f0d26ea..e0c9cbfe 100644 --- a/docs/features/magic-notes/technical-design.md +++ b/docs/features/magic-notes/technical-design.md @@ -54,8 +54,10 @@ and 320px. It shares the AI pane's pointer-capture handlers, separator styling and keyboard semantics (16px arrow steps, Home/End limits). Both widths are stored in `goodbuddy.magic-notes-layout.v1`; missing index width defaults to 168px. Displayed widths clamp together to reserve at least 300px for the stream, -without overwriting saved widths when the window shrinks. The index toggle stays in the detail header immediately -before the title; collapsing hides the entire index and removes its grid column, +without overwriting saved widths when the window shrinks. The page header places +the index toggle immediately after the back button, followed by the AI toggle. +All three use icons and visible localized text; pane toggle labels reflect their +current show/hide action. Collapsing hides the entire index and removes its grid column, border, resize separator and occupied width. AI has a separate right pane with its existing resize separator and header toggle. Both panes scroll independently and persist independent desktop visibility. At container widths of diff --git a/src/renderer/src/MagicNotesWorkspace.test.tsx b/src/renderer/src/MagicNotesWorkspace.test.tsx index fab33df9..ea3eb256 100644 --- a/src/renderer/src/MagicNotesWorkspace.test.tsx +++ b/src/renderer/src/MagicNotesWorkspace.test.tsx @@ -824,10 +824,10 @@ describe('MagicNotesWorkspace detail behavior', () => { await openNote() showAi() const toggle = screen.getByRole('button', { name: '隐藏 AI 评论', expanded: true }) - expect(toggle).toHaveClass('icon-button', 'icon-button--active') + expect(toggle).toHaveClass('secondary-button') expect(toggle).toHaveAttribute('title', '隐藏 AI 评论') expect(toggle).toHaveAttribute('aria-controls', 'magic-notes-ai-pane') - expect(toggle.textContent).toBe('') + expect(toggle).toHaveTextContent('隐藏 AI 评论') const pane = screen.getByRole('complementary', { name: 'AI 评论' }) expect(pane).toHaveAttribute('id', toggle.getAttribute('aria-controls')) expect(within(pane).queryByText('AI 评论', { exact: true })).not.toBeInTheDocument() @@ -841,7 +841,7 @@ describe('MagicNotesWorkspace detail behavior', () => { expect(toggle).toHaveFocus() expect(screen.getByRole('button', { name: '显示 AI 评论', expanded: false })).toBe(toggle) expect(toggle).toHaveAttribute('title', '显示 AI 评论') - expect(toggle).not.toHaveClass('icon-button--active') + expect(toggle).toHaveTextContent('显示 AI 评论') expect(screen.queryByRole('complementary', { name: 'AI 评论' })).not.toBeInTheDocument() back() await openNote() @@ -956,7 +956,7 @@ describe('MagicNotesWorkspace detail behavior', () => { it('keeps entry editing contained and supports deletion confirmation', async () => { const { container } = render() await openNote() - expect(container.querySelector('.magic-note-detail-header button + input')).toBe(screen.getByLabelText('笔记标题')) + expect(container.querySelector('.magic-note-detail-header > :first-child')).toBe(screen.getByLabelText('笔记标题')) expect(screen.getByRole('button', { name: '删除记录' })).toHaveClass('danger-button--quiet') fireEvent.click(screen.getByRole('button', { name: '编辑' })) expect(container.querySelector('.magic-note-entry__editor')).toBeVisible() @@ -1187,8 +1187,14 @@ describe('MagicNotesWorkspace canvas integration', () => { fireEvent.click(screen.getByRole('button', { name: '编辑' })) const editor = screen.getByTestId('magic-note-editor') const toggle = screen.getByRole('button', { name: '收起记录索引' }) - expect(toggle.parentElement).toHaveClass('magic-note-detail-header') - expect(toggle.nextElementSibling).toBe(screen.getByLabelText('笔记标题')) + expect(toggle.parentElement).toHaveClass('page-header__actions') + const back = screen.getByRole('button', { name: '返回总览' }) + expect(back).toHaveTextContent('返回总览') + expect(back.nextElementSibling).toBe(toggle) + expect(toggle).toHaveTextContent('收起记录索引') + const aiToggle = screen.getByRole('button', { name: '隐藏 AI 评论' }) + expect(toggle.nextElementSibling).toBe(aiToggle) + expect(aiToggle).toHaveTextContent('隐藏 AI 评论') expect(toggle).toHaveAttribute('aria-controls', 'magic-notes-index') expect(toggle).toHaveAttribute('aria-expanded', 'true') toggle.focus() @@ -1196,23 +1202,26 @@ describe('MagicNotesWorkspace canvas integration', () => { expect(toggle).toHaveFocus() expect(toggle).toHaveAttribute('aria-expanded', 'false') expect(toggle).toHaveAttribute('title', '展开记录索引') + expect(toggle).toHaveTextContent('展开记录索引') expect(document.querySelector('.magic-notes-index-pane')).toHaveAttribute('hidden') expect(document.querySelector('.magic-notes-layout')).toHaveClass('magic-notes-layout--index-hidden') expect(screen.queryByRole('navigation', { name: '记录' })).not.toBeInTheDocument() expect(screen.getByRole('complementary', { name: 'AI 评论' })).toBeVisible() fireEvent.click(screen.getByRole('button', { name: '隐藏 AI 评论' })) + expect(aiToggle).toHaveTextContent('显示 AI 评论') fireEvent.click(screen.getByRole('button', { name: '展开记录索引' })) expect(screen.getByRole('navigation', { name: '记录' })).toBeVisible() expect(screen.queryByRole('complementary', { name: 'AI 评论' })).not.toBeInTheDocument() expect(screen.getByTestId('magic-note-editor')).toBe(editor) }) - it('opens and closes the narrow index from the detail header and returns Escape focus', async () => { + it('opens and closes the narrow index beside the back button and returns Escape focus', async () => { vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(700) render() await openNote() const toggle = screen.getByRole('button', { name: '展开记录索引' }) - expect(toggle.nextElementSibling).toBe(screen.getByLabelText('笔记标题')) + expect(screen.getByRole('button', { name: '返回总览' }).nextElementSibling).toBe(toggle) + expect(toggle).toHaveTextContent('展开记录索引') expect(document.querySelector('.magic-notes-index-pane')).toHaveAttribute('hidden') fireEvent.click(toggle) expect(toggle).toHaveAttribute('aria-expanded', 'true') diff --git a/src/renderer/src/MagicNotesWorkspace.tsx b/src/renderer/src/MagicNotesWorkspace.tsx index 5a18b94a..7ae9c3df 100644 --- a/src/renderer/src/MagicNotesWorkspace.tsx +++ b/src/renderer/src/MagicNotesWorkspace.tsx @@ -1946,11 +1946,28 @@ export function MagicNotesWorkspace({ )} {detailView && ( + + )} + {detailView && ( )} {!detailView && ( @@ -2496,20 +2514,6 @@ export function MagicNotesWorkspace({ )}
-