fix(client): reveal new-session keys on hover and align settings radius
This commit is contained in:
1 parent
eccfda04d6
commit
4d4bb4c907
11 files changed
+32
-21
No files matched your search
@@ -324,7 +324,7 @@ describe('web e2e: shortcut reference', () => {
|
||||
it.each([
|
||||
{ platform: 'Win32', primary: 'Control', keys: 'Ctrl + Alt + N' },
|
||||
{ platform: 'MacIntel', primary: 'Meta', keys: '⌥ ⇧ ⌘ F12' },
|
||||
])('keeps the shortcut on New Session at wide and narrow sidebar widths on $platform', async ({ platform, primary, keys }) => {
|
||||
])('shows the shortcut inside New Session on hover and keyboard focus at wide and narrow widths on $platform', async ({ platform, primary, keys }) => {
|
||||
const context = await browser.newContext({ locale: 'en-US', viewport: { width: 1440, height: 1000 } })
|
||||
try {
|
||||
await context.addInitScript((value) => { Object.defineProperty(navigator, 'platform', { value }) }, platform)
|
||||
@@ -353,19 +353,28 @@ describe('web e2e: shortcut reference', () => {
|
||||
return Math.abs(button.x + button.width / 2 - content.x - content.width / 2)
|
||||
})
|
||||
expect(await centerOffset()).toBeLessThan(1)
|
||||
const hintStyle = () => newSession.locator('[class*="newSessionShortcut"]').evaluate(element => ({
|
||||
opacity: getComputedStyle(element).opacity, mask: getComputedStyle(element.previousElementSibling!).maskImage,
|
||||
}))
|
||||
expect(await hintStyle()).toEqual({ opacity: '0', mask: 'none' })
|
||||
await newSession.hover()
|
||||
expect(await centerOffset()).toBeLessThan(1)
|
||||
const mask = await newSession.locator('[class*="newSessionLabelMask"]').boundingBox()
|
||||
const hint = await newSession.locator('[class*="newSessionShortcut"]').boundingBox()
|
||||
expect(mask!.x + mask!.width).toBeLessThanOrEqual(hint!.x + 1)
|
||||
expect((await hintStyle()).opacity).toBe('1')
|
||||
expect((await hintStyle()).mask).toContain('linear-gradient')
|
||||
await newSession.screenshot({ path: fileURLToPath(new URL(`../../../.artifacts/new-session-${process.pid}-${platform}-${colorScheme}-${width}.png`, import.meta.url)) })
|
||||
await newSession.hover()
|
||||
expect(await centerOffset()).toBeLessThan(1)
|
||||
const hintStyle = await newSession.locator('[class*="newSessionShortcut"]').evaluate(element => ({
|
||||
opacity: getComputedStyle(element).opacity, mask: getComputedStyle(element.previousElementSibling!).maskImage,
|
||||
}))
|
||||
expect(hintStyle.opacity).toBe('1')
|
||||
expect(hintStyle.mask).toContain('linear-gradient')
|
||||
expect(await page.getByRole('tooltip').count()).toBe(0)
|
||||
await page.mouse.move(700, 100)
|
||||
expect(await hintStyle()).toEqual({ opacity: '0', mask: 'none' })
|
||||
await newSession.focus()
|
||||
await page.keyboard.press('Shift+Tab')
|
||||
await page.keyboard.press('Tab')
|
||||
expect(await newSession.evaluate(element => element.matches(':focus-visible'))).toBe(true)
|
||||
expect((await hintStyle()).opacity).toBe('1')
|
||||
expect(await page.getByRole('tooltip').count()).toBe(0)
|
||||
await newSession.evaluate((element) => { element.blur() })
|
||||
}
|
||||
}
|
||||
} finally { await context.close() }
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
en: d152484eb41ac6b4
|
||||
zh: 0cd57b7b8d8c9b59
|
||||
/deepseek-ai-dsh-client-ui-shortcuts/use-this-package:
|
||||
en: 10a28cdcb6bc7c03
|
||||
zh: 62b12ff10b52e8de
|
||||
en: 2d35beb03b54d4ea
|
||||
zh: 12f3c6ec1a79c673
|
||||
/deepseek-ai-dsh-client-ui-shortcuts/understand-the-implementation:
|
||||
en: f56f2610e7258825
|
||||
zh: 249d7cdd55c57166
|
||||
|
||||
@@ -25,7 +25,7 @@ Browse the commands available in the current window and find them by action, Eng
|
||||
<a id="use-this-package"></a>
|
||||
## Use this package
|
||||
|
||||
The Web app bundle mounts this package together with `shortcuts`. The reference shows only registered commands and existing fixed input actions. Desktop shows the effective device keys; commands without a Web default show No shortcut. The Settings entry and Mod+/ open the same single dialog, titled “Keyboard shortcuts” in English and “快捷键” in Chinese. Its 480×600 CSS-pixel card shrinks to fit smaller windows; the header and search remain above an internally scrolling list. The search field receives focus on open without changing its border color. Automatic entry and return focus in the reference, recorder, and reset confirmation omit outlines, including returns after Escape and application close shortcuts. Containers remain outline-free, and Tab and directional navigation retain their visible focus indicators. The Settings entry is labeled “Edit shortcuts”, with an “Open from anywhere” shortcut tooltip, and uses a filled capsule button without a dropdown icon and reads the same effective binding for its tooltip and `aria-keyshortcuts`; both are absent without a binding.
|
||||
The Web app bundle mounts this package together with `shortcuts`. The reference shows only registered commands and existing fixed input actions. Desktop shows the effective device keys; commands without a Web default show No shortcut. The Settings entry and Mod+/ open the same single dialog, titled “Keyboard shortcuts” in English and “快捷键” in Chinese. Its 480×600 CSS-pixel card shrinks to fit smaller windows; the header and search remain above an internally scrolling list. The search field receives focus on open without changing its border color. Automatic entry and return focus in the reference, recorder, and reset confirmation omit outlines, including returns after Escape and application close shortcuts. Containers remain outline-free, and Tab and directional navigation retain their visible focus indicators. The Settings entry is labeled “Edit shortcuts”, with an “Open from anywhere” shortcut tooltip, and uses a filled button with the same standard radius as adjacent settings controls and no dropdown icon and reads the same effective binding for its tooltip and `aria-keyshortcuts`; both are absent without a binding.
|
||||
|
||||
`Mod+/` opens the reference when no modal is open or Settings is in front, and closes it when the reference is in front. While the reference is in front, the Settings command cannot open or close Settings. Held-key repeats are ignored. Recording, pending writes, and a nested confirmation prevent the reference shortcut from closing the dialog.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ kind: "package-reference"
|
||||
<a id="use-this-package"></a>
|
||||
## 使用此包
|
||||
|
||||
Web 应用 bundle 将此包与 `shortcuts` 一同挂载。速查仅展示已注册命令和现有固定输入操作。桌面端展示设备对应的有效键位;没有 Web 默认键位的命令显示“暂无快捷键”。设置入口与 Mod+/打开同一个单实例弹窗,中文标题为“快捷键”,英文标题为“Keyboard shortcuts”。卡片尺寸为 480×600 CSS 像素,小窗口中缩小以保持可见;标题和搜索框位于内部滚动列表上方。打开时聚焦搜索框,边框颜色保持不变。速查窗、录键框及重置确认框内的自动进入和回焦均不绘制外轮廓线,包括通过 Esc 和应用关闭快捷键触发的回焦。容器仍不绘制焦点外框,Tab 和方向键导航保留可见焦点提示。设置入口标为“编辑快捷键”,快捷键提示文案为“全局唤起查看”,使用无下拉图标的填充胶囊按钮,并从同一有效绑定读取提示及 `aria-keyshortcuts`;没有绑定时不显示提示,也不设置该属性。
|
||||
Web 应用 bundle 将此包与 `shortcuts` 一同挂载。速查仅展示已注册命令和现有固定输入操作。桌面端展示设备对应的有效键位;没有 Web 默认键位的命令显示“暂无快捷键”。设置入口与 Mod+/打开同一个单实例弹窗,中文标题为“快捷键”,英文标题为“Keyboard shortcuts”。卡片尺寸为 480×600 CSS 像素,小窗口中缩小以保持可见;标题和搜索框位于内部滚动列表上方。打开时聚焦搜索框,边框颜色保持不变。速查窗、录键框及重置确认框内的自动进入和回焦均不绘制外轮廓线,包括通过 Esc 和应用关闭快捷键触发的回焦。容器仍不绘制焦点外框,Tab 和方向键导航保留可见焦点提示。设置入口标为“编辑快捷键”,快捷键提示文案为“全局唤起查看”,使用与相邻设置控件一致的标准圆角填充按钮,不带下拉图标,并从同一有效绑定读取提示及 `aria-keyshortcuts`;没有绑定时不显示提示,也不设置该属性。
|
||||
|
||||
没有模态弹窗或设置位于最前方时,`Mod+/` 打开速查;速查位于最前方时,该快捷键关闭速查。速查位于前方时,设置命令不能打开或关闭设置。长按产生的重复按键不执行操作。录键期间、写入尚未完成或嵌套确认框打开时,速查快捷键不会关闭弹窗。
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
max-width: 280px;
|
||||
padding: 0 14px;
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
border-radius: var(--dsw-radius-md);
|
||||
background: var(--dsw-alias-bg-module-platform);
|
||||
color: var(--dsw-alias-label-primary);
|
||||
font: inherit;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
en: a970f0547496634f
|
||||
zh: 36ef9a85b26e19f1
|
||||
/deepseek-ai-dsh-client-ui-sidebar/use-this-package/brand-and-new-session:
|
||||
en: 0ee8cab67ce33ec2
|
||||
zh: 5925286aea07a045
|
||||
en: d084cd6732966c41
|
||||
zh: 466e028ca49b4230
|
||||
/deepseek-ai-dsh-client-ui-sidebar/use-this-package/global-panel-entries:
|
||||
en: 5d3300d3506254c5
|
||||
zh: 541ae1ee1e10b921
|
||||
|
||||
@@ -29,7 +29,7 @@ The sidebar is the navigation shell: users see the brand, start new sessions, co
|
||||
|
||||
### Brand and New Session
|
||||
|
||||
The expanded brand row renders `sidebar.brand.mark` and `sidebar.brand.name` as independent single slots; the collapsed rail renders the same mark slot. Without occupants, the shell uses the fish mark and a localized local-build label. A complete build stacks a code badge below the label as `version[-commit][-dirty]`, using `DSH_CLIENT_VERSION`, the optional 7-character `DSH_CLIENT_COMMIT_HASH`, and `DSH_CLIENT_GIT_DIRTY=true`; missing version metadata omits the badge. New Session targets the explicit Workspace used by a scoped action, otherwise the current Session's Workspace, otherwise the most recently active Workspace; when none exists it clears into the blank New Session page. The expanded New Session button always displays the effective binding as trailing grey text. The centered icon and label fade before the shortcut when space is narrow; CSS reserves the shortcut’s width without measuring the button. Icon-only controls retain tooltips with platform-formatted keycaps, including the resident macOS header control when the sidebar is hidden. All controls expose `aria-keyshortcuts`.
|
||||
The expanded brand row renders `sidebar.brand.mark` and `sidebar.brand.name` as independent single slots; the collapsed rail renders the same mark slot. Without occupants, the shell uses the fish mark and a localized local-build label. A complete build stacks a code badge below the label as `version[-commit][-dirty]`, using `DSH_CLIENT_VERSION`, the optional 7-character `DSH_CLIENT_COMMIT_HASH`, and `DSH_CLIENT_GIT_DIRTY=true`; missing version metadata omits the badge. New Session targets the explicit Workspace used by a scoped action, otherwise the current Session's Workspace, otherwise the most recently active Workspace; when none exists it clears into the blank New Session page. The expanded New Session button displays the effective binding as trailing grey text on hover or keyboard focus. While the shortcut is visible, the centered icon and label fade before it when space is narrow; CSS reserves the shortcut’s width without measuring the button. Icon-only controls retain tooltips with platform-formatted keycaps, including the resident macOS header control when the sidebar is hidden. All controls expose `aria-keyshortcuts`.
|
||||
|
||||
### Global panel entries
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ dsh Web 客户端的侧边栏让用户识别当前构建、启动新会话、将
|
||||
|
||||
### 品牌与 New Session
|
||||
|
||||
展开的品牌行把 `sidebar.brand.mark` 与 `sidebar.brand.name` 渲染为两个独立的 single slot;收起轨道则渲染同一个 mark slot。没有占位者时,外壳使用鱼形标记和本地化的本地构建标签。完整构建会在标签下方显示代码徽标;该徽标使用 `DSH_CLIENT_VERSION`、可选的 7 位 `DSH_CLIENT_COMMIT_HASH` 与 `DSH_CLIENT_GIT_DIRTY=true` 组装成 `version[-commit][-dirty]`;缺少版本元数据时不显示徽标。New Session 优先使用作用域操作明确指定的 Workspace,否则使用当前 Session 所属 Workspace,再否则使用最近活跃 Workspace;一个 Workspace 都没有时则清空选择,进入空白 New Session 页面。 展开态的新建会话按钮始终在右侧以灰色文字显示当前有效绑定。空间较窄时,居中的图标与文字在快捷键之前渐隐;CSS 为快捷键保留宽度,无需测量按钮。纯图标控件保留使用平台键位样式的 tooltip,侧栏隐藏时常驻的 macOS 头部控件也保持一致。所有控件均提供 `aria-keyshortcuts`。
|
||||
展开的品牌行把 `sidebar.brand.mark` 与 `sidebar.brand.name` 渲染为两个独立的 single slot;收起轨道则渲染同一个 mark slot。没有占位者时,外壳使用鱼形标记和本地化的本地构建标签。完整构建会在标签下方显示代码徽标;该徽标使用 `DSH_CLIENT_VERSION`、可选的 7 位 `DSH_CLIENT_COMMIT_HASH` 与 `DSH_CLIENT_GIT_DIRTY=true` 组装成 `version[-commit][-dirty]`;缺少版本元数据时不显示徽标。New Session 优先使用作用域操作明确指定的 Workspace,否则使用当前 Session 所属 Workspace,再否则使用最近活跃 Workspace;一个 Workspace 都没有时则清空选择,进入空白 New Session 页面。 展开态的新建会话按钮在悬停或键盘聚焦时于右侧以灰色文字显示当前有效绑定。快捷键可见且空间较窄时,居中的图标与文字在快捷键之前渐隐;CSS 为快捷键保留宽度,无需测量按钮。纯图标控件保留使用平台键位样式的 tooltip,侧栏隐藏时常驻的 macOS 头部控件也保持一致。所有控件均提供 `aria-keyshortcuts`。
|
||||
|
||||
### 全局面板入口
|
||||
|
||||
|
||||
@@ -465,18 +465,21 @@
|
||||
max-width: 0;
|
||||
}
|
||||
|
||||
.newSessionLabelMask { flex: 1; min-width: 0; overflow: hidden; }
|
||||
.newSessionLabelMask:has(+ .newSessionShortcut) { mask-image: linear-gradient(to right, black calc(100% - 16px), transparent); }
|
||||
.newSessionLabelMask { flex: 1; min-width: 0; }
|
||||
.newSession:is(:hover, :focus-visible) .newSessionLabelMask:has(+ .newSessionShortcut) { overflow: hidden; mask-image: linear-gradient(to right, black calc(100% - 16px), transparent); }
|
||||
.newSessionContent { display: flex; width: 100cqw; align-items: center; justify-content: center; gap: 6px; }
|
||||
.newSessionContent > svg { flex: none; }
|
||||
|
||||
.newSessionShortcut {
|
||||
opacity: 0;
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
pointer-events: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.newSession:is(:hover, :focus-visible) .newSessionShortcut { opacity: 1; }
|
||||
|
||||
.panelList {
|
||||
flex: none;
|
||||
display: flex;
|
||||
|
||||
@@ -257,7 +257,7 @@ export function SidebarRoot({
|
||||
{!darwinDesktop && toggle}
|
||||
</div>
|
||||
|
||||
{/* The label fades before the persistent shortcut, including on translucent backgrounds. */}
|
||||
{/* The label fades before the hover/focus shortcut, including on translucent backgrounds. */}
|
||||
<Tooltip label={t('session.new.label')} shortcutKeys={newShortcut?.keys} delayMs={500} side={captionTooltipSide} disabled={wide}>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
".indicator: border-radius: 6px"
|
||||
],
|
||||
"ui-shortcuts/src/client/Reference.module.css": [
|
||||
".button: border-radius: 18px",
|
||||
".dialog: border-radius: 24px",
|
||||
".close: border-radius: 28px",
|
||||
".searchField: border-radius: 12px",
|
||||
|
||||
Reference in new issue
Block a user