diff --git a/UI-DESIGN.md b/UI-DESIGN.md index 87a3417e..30d5741a 100644 --- a/UI-DESIGN.md +++ b/UI-DESIGN.md @@ -709,6 +709,7 @@ GoodBuddy 是可调整窗口大小的桌面应用。响应式设计优先保证 - 全页设置使用固定标题区、左侧分类导航和独立滚动的内容区。右上角关闭按钮是离开设置中心的稳定入口。 - 新建项目与项目设置弹窗固定标题、关闭按钮和底部操作区,仅表单内容滚动;滚动条不进入标题区,关闭按钮保留至少 40 × 40px 的点击区域。 +- 项目弹窗通过 Portal 挂载到 `document.body`,避免侧栏内的弹窗与主窗口标题栏拖动区域重叠时,Electron 截获关闭按钮的鼠标输入。 - 左侧分类导航在宽屏使用 `220px`,中等窗口使用 `196px`,窄窗口转为横向滚动;纵向滚动条仅在内容溢出时占用右侧空间,不在左侧创建镜像预留,选项与左侧可见边界保持默认内距。分类标题使用正文级字号,分类说明使用辅助字号;右侧内容区在可用空间内流式伸缩,最大宽度使用 `standard` 壳层的 `960px`,不得以页面专属较窄宽度压缩表单。 - 全页设置标题区与双栏内容使用共享 `--page-gutter`,标题、分类导航和内容区在同一页面边距基线上;标题继续使用标准 `PageHeader` 的底部分隔线与下内距。固定标题和双独立滚动区域不改变这些一级页面壳层规则;模态设置保留自身外框与标题边界。 - 设置中心不显示全局操作页脚,避免重复关闭入口和没有功能意义的整宽分隔线。 diff --git a/src/renderer/src/ProjectSwitcher.test.tsx b/src/renderer/src/ProjectSwitcher.test.tsx index c54761d4..64994f47 100644 --- a/src/renderer/src/ProjectSwitcher.test.tsx +++ b/src/renderer/src/ProjectSwitcher.test.tsx @@ -354,6 +354,23 @@ describe('ProjectSwitcher project activity integration', () => { }) describe('ProjectSwitcher runtime fields', () => { + it.each(['新建项目', '项目设置'])('keeps %s outside the sidebar and restores focus after closing', (name) => { + renderSwitcher() + const trigger = screen.getByLabelText(name) + fireEvent.click(trigger) + const dialog = screen.getByRole('dialog', { name }) + expect(dialog.parentElement?.parentElement).toBe(document.body) + const body = dialog.querySelector('.project-create-card__body')! + const close = within(dialog).getByRole('button', { name: `关闭${name}` }) + expect(body).toContainElement(within(dialog).getByLabelText('名称')) + expect(body).not.toContainElement(close) + expect(body).not.toContainElement(within(dialog).getByRole('button', { name: '取消' })) + fireEvent.scroll(body, { target: { scrollTop: 500 } }) + fireEvent.click(close) + expect(screen.queryByRole('dialog', { name })).not.toBeInTheDocument() + expect(trigger).toHaveFocus() + }) + it('creates an ordinary project with DeepSeek Harness', async () => { const { onCreate } = renderSwitcher() diff --git a/src/renderer/src/ProjectSwitcher.tsx b/src/renderer/src/ProjectSwitcher.tsx index c053190b..9cdd5755 100644 --- a/src/renderer/src/ProjectSwitcher.tsx +++ b/src/renderer/src/ProjectSwitcher.tsx @@ -17,6 +17,7 @@ import { } from 'lucide-react' import type { LucideIcon } from 'lucide-react' import { useCallback, useEffect, useRef, useState } from 'react' +import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' import type { AssistantProject, @@ -1413,7 +1414,7 @@ export function ProjectSwitcher({ - {dialogMode && ( + {dialogMode && createPortal(
{ @@ -2139,7 +2140,8 @@ export function ProjectSwitcher({ )}
- + , + document.body )} )