feat: explorer copy-path & @-reference actions; icons on tabs and + menu

- Tabs, the + menu, and empty-pane cards carry per-type icons (folder /
  branch / terminal / code file); a terminal glyph joins the icon set
- Hovering an explorer row reveals an @文件 button at the far right that
  appends @<relative path> to the composer draft (session-scoped input
  service, space-separated append)
- Right-clicking a row opens a context menu: copy relative / absolute
  path (writeClipboard + transient in-row "copied" label)
- Rows become div role=button (Enter/Space) to host the inner button;
  relativeTo helper unit-tested
This commit is contained in:
Menghuan1918
2026-08-08 23:46:14 +08:00
parent 88b08de957
commit 6e36a99c88
11 changed files with 306 additions and 26 deletions
+5
View File
@@ -11,6 +11,7 @@ import {
IconCloseFill14, IconPlusOutline16, Menu,
} from '@deepseek-ai/dsh-client-ui-primitives'
import type { SidebarTab } from './state.ts'
import { tabTypeIcon } from './icons.tsx'
import { t } from './locales.ts'
import css from './sidebar.module.css'
@@ -19,6 +20,8 @@ export interface NewTabOption {
id: string
label: string
disabled?: boolean
/** Leading icon (Menu row). */
icon?: ReactNode
}
/** Drag payload for tab moves (HTML5 DnD dataTransfer). */
@@ -109,6 +112,7 @@ export function TabBar(props: {
}
}}
>
{tabTypeIcon(tab.type, 14)}
<span className={css.tabTitle}>{tab.title}</span>
<button
type="button"
@@ -135,6 +139,7 @@ export function TabBar(props: {
id: option.id,
label: option.label,
...(option.disabled === true ? { disabled: true } : {}),
...(option.icon !== undefined ? { icon: option.icon } : {}),
}))}
onSelect={(id) => {
onNewTab(id)