diff --git a/UI-DESIGN.md b/UI-DESIGN.md index 79fa1716..b0312684 100644 --- a/UI-DESIGN.md +++ b/UI-DESIGN.md @@ -766,7 +766,7 @@ GoodBuddy 是可调整窗口大小的桌面应用。响应式设计优先保证 - 左侧记录索引默认 `168px`,可拖动右边界在 `140–320px` 内调整栏宽,缩略图随列宽等比适配。开关独立位于详情标题左侧,提供 `aria-controls`、展开状态和动作提示;收起后完全移除索引列、分隔条、间隙、边框及轨道,不占宽度,隐藏内容不可聚焦。右侧 AI 评论独立显示、滚动和收起,不与索引共享页签。每条记录一个导航项:画布显示真实首页缩略图及总页数,文字显示摘要,两者均显示类型和时间。两侧分别记住桌面展开状态和宽度,共用原有布局偏好;宽布局分隔条共用样式及 `separator` 语义,方向键每次调整 `16px`,Home、End 跳到当前上下限。两侧宽度按可用空间协调限制,为主区保留至少 `300px`,窗口缩小时不覆盖保存的偏好。内容容器不超过 `800px` 时索引默认隐藏,由同一标题栏按钮开闭标题栏下方固定 `168px` 的抽屉,不显示调宽分隔条;标题栏自身保留控件高度,不保留轨道。选择记录或按 Escape 后关闭,Escape 将焦点返回开关。AI 移至底部,高度不超过可用布局的 40% 且最多 `280px`,不显示分隔条。 AI 评论的唯一显隐入口位于页面右上角,使用紧凑面板图标按钮;展开时应用共享选中样式,图标随显示或隐藏动作切换,并提供对应的工具提示、可访问名称、`aria-expanded` 和 `aria-controls`。评论面板内部不再显示重复的“AI 评论”标题或隐藏按钮行,保留区域的可访问名称、评论方向选择及各记录的分析操作。 - 笔记详情的内部记录索引使用透明底色,与主内容表面连续,仅保留细调宽分隔线。每条索引记录保留 `1px` 的 `--border-subtle` 淡边框,不加卡片底色或阴影,悬停使用轻微次级底色;选中记录使用淡蓝背景和左侧 `3px` 蓝色内侧标记,悬停时保留选中态。缩略图保留纸张边界,键盘焦点环与强制颜色模式选中边框保持可见。窄屏抽屉使用不透明的主内容表面,避免下层正文透出;深色主题沿用语义令牌。 -- 笔记详情的标题、正文和记录流不再包裹额外的大外框,记录流容器不加内边距;每条已保存记录使用一层 `1px` 的 `--border-subtle` 淡边框和 `--radius-control` 圆角,保留透明底色与记录间留白,不加阴影或头部下划线。记录编辑时保留输入区边框、页面安全边距及 AI 区域分隔。此规则仅作用于笔记详情,不改变卡片总览与待办独立布局。 +- 笔记详情的标题、正文和记录流不再包裹额外的大外框,记录流容器不加内边距;缩略图列表顶部与正文区顶部对齐,左边界与索引栏左边界对齐,仅在右侧和底部保留 `8px` 留白,键盘焦点环向内绘制以避免滚动容器裁切。每条已保存记录使用一层 `1px` 的 `--border-subtle` 淡边框和 `--radius-control` 圆角,保留透明底色与记录间留白,不加阴影或头部下划线。记录编辑时保留输入区边框、页面安全边距及 AI 区域分隔。此规则仅作用于笔记详情,不改变卡片总览与待办独立布局。 - 画布新建、编辑和只读态统一保留 `12px` 内容间距;详情中已保存画布去掉预览外框和工具栏底色、下划线,保留灰色画布衬底与白色纸张,编辑态保留编辑器边框。记录头部操作按内容宽度排列,空间不足时自然换行。文字新建的保存区与编辑器属于同一卡片,空白编辑区使用最小高度,不随容器百分比高度拉长。文字工具栏图标、菜单和原生滚动条须跟随主题。 - 整篇笔记的置顶、取消置顶和删除放在卡片的“更多”菜单,标题编辑区不重复提供入口。按钮在悬停、键盘聚焦或菜单展开时显示,触屏设备常显;菜单沿用会话列表样式,通过 Portal 避免滚动区域裁切,支持方向键、Home、End 和 Escape。删除在菜单内二次确认并说明笔记标题及全部记录;打开菜单不进入详情。 - 左侧“魔法笔记”入口可显示未完成待办数量。数量为 0 时隐藏徽标,超过 99 时显示 `99+`,可访问名称仍说明精确数量;勾选、取消勾选以及 Agent / MCP 对笔记清单的写入都必须刷新数量。 diff --git a/src/renderer/src/styles.css b/src/renderer/src/styles.css index eeccf53c..4973b23e 100644 --- a/src/renderer/src/styles.css +++ b/src/renderer/src/styles.css @@ -1382,7 +1382,7 @@ } } -.magic-note-records { display: grid; gap: var(--space-3); padding: var(--space-2); } +.magic-note-records { display: grid; gap: var(--space-3); padding: 0 var(--space-2) var(--space-2) 0; } .magic-note-records[hidden] { display: none; } .magic-note-record { display: grid; @@ -1405,7 +1405,7 @@ @media (forced-colors: active) { .magic-note-record[aria-current="true"] { border-color: Highlight; } } -.magic-note-record:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } +.magic-note-record:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } .magic-note-record time { color: var(--text-secondary); font-size: var(--font-caption); } .magic-note-record__summary { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; } .magic-note-record__image { display: block; min-width: 0; text-align: center; } diff --git a/tests/magic-notes-layout.electron.test.ts b/tests/magic-notes-layout.electron.test.ts index 15f01746..45a1ba50 100644 --- a/tests/magic-notes-layout.electron.test.ts +++ b/tests/magic-notes-layout.electron.test.ts @@ -78,6 +78,9 @@ it('resizes record columns with native Electron input and preserves desktop widt await js('document.documentElement.dataset.theme = "light"'); await settle(); const index = '.magic-notes-index-pane', handle = '.magic-notes-index-resize-handle', stream = '.magic-notes-stream-pane'; assert.equal((await rect(index)).width, 168); + const firstRecord = await rect('.magic-note-record'); + assert.equal(firstRecord.x, (await rect(index)).x, 'Thumbnails align with the left pane edge'); + assert.equal(firstRecord.y, (await rect(stream)).y, 'Thumbnails align with the top of the note content'); await drag(handle, 80); const dragged = (await rect(index)).width; assert(dragged > 240 && dragged < 260, 'Dragged index width: ' + dragged); await key(handle, 'Home'); assert.equal((await rect(index)).width, 140); await key(handle, 'Right'); assert.equal((await rect(index)).width, 156); @@ -107,6 +110,10 @@ it('resizes record columns with native Electron input and preserves desktop widt await screenshot('magic-notes-narrow'); win.setContentSize(1280, 800); await settle(); await settle(); assert.equal((await rect(index)).width, withoutAi); + await key('.magic-note-record', 'Tab'); + await js('document.querySelector(".magic-note-record").focus()'); + assert(await js('document.querySelector(".magic-note-record").matches(":focus-visible")')); + assert.equal(await js('getComputedStyle(document.querySelector(".magic-note-record")).outlineOffset'), '-2px', 'Focus outline stays inside the scroll viewport'); await js('document.querySelector(' + JSON.stringify(editor) + ').focus()'); await win.webContents.insertText('Composer growth check\\n'.repeat(30)); await settle(); const grownHeight = (await rect(editor)).height;