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({
)}