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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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(<MagicNotesWorkspace onNotify={onNotify} />)
|
||||
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(<MagicNotesWorkspace onNotify={onNotify} />)
|
||||
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')
|
||||
|
||||
@@ -1946,11 +1946,28 @@ export function MagicNotesWorkspace({
|
||||
</button>
|
||||
)}
|
||||
{detailView && (
|
||||
<button
|
||||
id="magic-notes-index-toggle"
|
||||
type="button"
|
||||
className="secondary-button"
|
||||
aria-controls="magic-notes-index"
|
||||
aria-expanded={indexExpanded}
|
||||
aria-label={t(indexExpanded ? 'records.hide' : 'records.show')}
|
||||
title={t(indexExpanded ? 'records.hide' : 'records.show')}
|
||||
onClick={() => isNarrowLayout
|
||||
? setNarrowIndexOpen((current) => !current)
|
||||
: setIndexPaneOpen((current) => !current)}
|
||||
>
|
||||
{indexExpanded ? <PanelLeftClose aria-hidden="true" size={15} /> : <PanelLeftOpen aria-hidden="true" size={15} />}
|
||||
{t(indexExpanded ? 'records.hide' : 'records.show')}
|
||||
</button>
|
||||
)}
|
||||
{detailView && (
|
||||
<button
|
||||
aria-controls="magic-notes-ai-pane"
|
||||
aria-expanded={aiPaneOpen}
|
||||
aria-label={t(aiPaneOpen ? 'actions.hideAiComments' : 'actions.showAiComments')}
|
||||
className={`icon-button${aiPaneOpen ? ' icon-button--active' : ''}`}
|
||||
className="secondary-button"
|
||||
onClick={() => setAiPaneOpen((current) => !current)}
|
||||
title={t(aiPaneOpen ? 'actions.hideAiComments' : 'actions.showAiComments')}
|
||||
type="button"
|
||||
@@ -1960,6 +1977,7 @@ export function MagicNotesWorkspace({
|
||||
) : (
|
||||
<PanelRightOpen aria-hidden="true" size={15} />
|
||||
)}
|
||||
{t(aiPaneOpen ? 'actions.hideAiComments' : 'actions.showAiComments')}
|
||||
</button>
|
||||
)}
|
||||
{!detailView && (
|
||||
@@ -2496,20 +2514,6 @@ export function MagicNotesWorkspace({
|
||||
</div>
|
||||
)}
|
||||
<header className="magic-note-detail-header">
|
||||
<button
|
||||
id="magic-notes-index-toggle"
|
||||
type="button"
|
||||
className="icon-button"
|
||||
aria-controls="magic-notes-index"
|
||||
aria-expanded={indexExpanded}
|
||||
aria-label={t(indexExpanded ? 'records.hide' : 'records.show')}
|
||||
title={t(indexExpanded ? 'records.hide' : 'records.show')}
|
||||
onClick={() => isNarrowLayout
|
||||
? setNarrowIndexOpen((current) => !current)
|
||||
: setIndexPaneOpen((current) => !current)}
|
||||
>
|
||||
{indexExpanded ? <PanelLeftClose aria-hidden="true" size={16} /> : <PanelLeftOpen aria-hidden="true" size={16} />}
|
||||
</button>
|
||||
<input
|
||||
aria-describedby={
|
||||
validation?.target === 'note-title'
|
||||
|
||||
Reference in New Issue
Block a user