diff --git a/UI-DESIGN.md b/UI-DESIGN.md index 4a6b5661..808a1f94 100644 --- a/UI-DESIGN.md +++ b/UI-DESIGN.md @@ -371,7 +371,7 @@ - 已打开实例保留 `tablist`、`tab`、`tabpanel`、方向键、Home、End 和焦点恢复语义。 实例过多时 Tab 区单行横向滚动,“+”保持可见,不换行或改成下拉框。不可关闭实例不渲染 关闭按钮,也不响应关闭快捷命令。 - “+”位于滚动容器外并占用固定宽度;滚动箭头限定在剩余的页签区域内,不能覆盖添加入口。 + “+”位于滚动容器外并占用固定宽度;溢出时左右滚动箭头在滚动视口两侧各占独立宽度,不能覆盖页签、关闭按钮或添加入口。箭头隐藏或禁用时保留占位,避免悬停或滚动引起布局跳动。 - 当前工作栏 Tab 必须同时使用连续内容表面、可见边框、顶部指示、图标或较高字重中的至少 两种信号;悬停反馈不得强于当前选中态。Tab 关闭按钮保留固定布局空间,默认仅在对应 Tab 悬停或 `focus-within` 时显示;无悬停或粗指针设备始终显示,键盘与辅助技术始终可访问。 diff --git a/docs/features/assistant-workbar/terminal-tabs-prd.md b/docs/features/assistant-workbar/terminal-tabs-prd.md index 7f183b78..c09b0bbf 100644 --- a/docs/features/assistant-workbar/terminal-tabs-prd.md +++ b/docs/features/assistant-workbar/terminal-tabs-prd.md @@ -182,7 +182,7 @@ stdio fallback。首期远程终端随 SSH Channel 结束,不提供跨 SSH 或 - 每个实例使用独立 `tab` 和 `tabpanel`。 - “+”固定在 Tab 行末尾,位于 `tablist` 和页签滚动容器之外,占用独立宽度。 - Tab 过多时实例区域单行横向滚动,不换行、不自动隐藏实例。“+”在 `300px` 工作栏内也保持可见和可点击。 -- 标签全部可见时隐藏左右滚动按钮;溢出时左右箭头透明浮动于页签区域两端,不占标签布局宽度,也不进入“+”的点击区域。鼠标移入标签栏时显示可滚动方向的箭头,移出后隐藏;键盘聚焦箭头时显示,无悬停能力的设备保持可滚动方向的箭头可见。悬停箭头时显示轻微底色。点击滚动约一屏,边界方向禁用并隐藏,且不拦截下方标签的指针操作。切换或新增激活标签时将其滚入可见区域。未激活标签使用低对比度灰蓝底色和细边框,激活标签保留亮底与强调色顶线。 +- 标签全部可见时移除左右滚动按钮及其占位;溢出时左右箭头在滚动视口两侧各占独立的 28px 宽度,不覆盖标签、关闭按钮或“+”。鼠标移入标签栏时显示可滚动方向的箭头,移出后隐藏;键盘聚焦箭头时显示,无悬停能力的设备保持可滚动方向的箭头可见。悬停箭头时显示轻微底色。点击滚动约一屏,边界方向禁用并隐藏;溢出期间隐藏和禁用均保留占位,避免布局跳动。切换或新增激活标签时将整个标签(含关闭按钮)滚入可见区域。未激活标签使用低对比度灰蓝底色和细边框,激活标签保留亮底与强调色顶线。 - 终端 Tab 默认使用递增标题,例如“终端 1”“终端 2”;状态栏持续显示项目、Host、 工作目录和 Shell。用户可以重命名终端。 - 任务中心、工作区、成果及新建终端的默认标题随界面语言切换,恢复布局时也使用当前语言。 diff --git a/src/renderer/src/styles.css b/src/renderer/src/styles.css index 45ed1cd3..464d8d19 100644 --- a/src/renderer/src/styles.css +++ b/src/renderer/src/styles.css @@ -5055,9 +5055,9 @@ button > svg { } .workbar-shell__scroll-button { - position: absolute; - z-index: 2; - bottom: 5px; + flex: 0 0 28px; + align-self: flex-end; + margin-bottom: 5px; background: transparent; opacity: 0; pointer-events: none; @@ -5070,14 +5070,6 @@ button > svg { pointer-events: auto; } -.workbar-shell__scroll-button:first-child { - left: 0; -} - -.workbar-shell__scroll-button:last-child { - right: 0; -} - .workbar-shell__scroll-button:hover:not(:disabled) { background: var(--surface-muted); color: var(--text-primary); diff --git a/tests/support/workbar-settings-layout-driver.mjs b/tests/support/workbar-settings-layout-driver.mjs index c2a0fe69..049d1067 100644 --- a/tests/support/workbar-settings-layout-driver.mjs +++ b/tests/support/workbar-settings-layout-driver.mjs @@ -130,6 +130,10 @@ app.whenReady().then(async () => { for (const many of [false, true]) { if (many) { await click('#many-tabs'); await wait('document.querySelectorAll("[role=tab]").length===16') } await addVisible() + assert(await js(`(() => { + const s=${scroll}.getBoundingClientRect(),buttons=[...document.querySelectorAll('.workbar-shell__scroll-button')]; + return buttons.length===2 && buttons[0].getBoundingClientRect().right<=s.left && buttons[1].getBoundingClientRect().left>=s.right; + })()`), 'Scroll arrows must reserve space outside the tab viewport') await click('.workbar-shell__add') await wait('!!document.querySelector(".workbar-shell__catalog") && document.activeElement.matches("[data-workbar-app-choice]")') await key('Escape') @@ -160,7 +164,19 @@ app.whenReady().then(async () => { await click('.workbar-shell__catalog-choice:has(.workbar-shell__app-icon--browser)') await wait('document.querySelectorAll("[role=tab]").length===17 && !document.querySelector(".workbar-shell__catalog")') await addVisible() - observations.push({ locale, theme, workbar: 'default and 16 long tabs; native add/catalog/create, arrows, Home/End' }) + await key('Left') + await wait('document.querySelector(".workbar-shell__tab-item:nth-last-child(2) [role=tab]").getAttribute("aria-selected")==="true"') + await js(`${scroll}.scrollLeft=0`) + await settle() + await js(`(() => { + const tab=document.querySelector('.workbar-shell__tab-item--active'),s=${scroll}; + s.scrollLeft+=tab.getBoundingClientRect().right-s.getBoundingClientRect().right; + })()`) + await wait('!document.querySelector(".workbar-shell__scroll-button:last-child").disabled') + const closingId = await js('document.querySelector(".workbar-shell__tab-item--active [role=tab]").id') + await click('.workbar-shell__tab-item--active .workbar-shell__tab-close') + await wait(`document.querySelectorAll('[role=tab]').length===16 && !document.getElementById(${JSON.stringify(closingId)})`) + observations.push({ locale, theme, workbar: 'default and 16 long tabs; native add/catalog/create, arrows, Home/End, close at right viewport edge with right arrow enabled' }) await win.loadURL(`${process.env.GB_LAYOUT_URL}?surface=settings&locale=${locale}&theme=${theme}`) await wait('!!document.querySelector(".model-connection-detail select")')