polish: smaller monochrome bind icon with hover tooltip showing bound conversation name

This commit is contained in:
Aisland
2026-08-19 02:07:46 +08:00
parent 696f8070b9
commit 6ac51d9986
5 changed files with 120 additions and 10 deletions
+15 -2
View File
@@ -754,6 +754,16 @@ function WorktableSection(props: any) {
}
}, [])
/** 绑定会话显示名(同步读会话快照;找不到回退 id)——供按钮 hover 气泡使用 */
function boundSessionTitle(sid: string): string {
try {
const snap = sessionBridge?.list?.getSnapshot?.()
const e = snap?.byId?.[sid]
if (e) return e.displayTitle ?? e.title ?? sid
} catch {}
return sid
}
/** 绑定会话信息:文件夹(工作区)+ 会话标题(供绑定弹窗状态行展示) */
function bindInfoOf(groups: { title: string; sessions: { id: string; title: string; isCurrent: boolean }[] }[], sid: string): { folder: string; title: string } {
for (const g of groups) {
@@ -1134,7 +1144,9 @@ function buildCustomLayoutPrompt(req: string): string {
bindBtn.setAttribute('data-wt-bind', id)
const bound = projects.bindings[id]
bindBtn.setAttribute('data-bound', bound ? 'true' : 'false')
bindBtn.title = bound ? t('bind.titleBound') : t('bind.titleUnbound')
const tip = bound ? t('bind.tipBound', { name: boundSessionTitle(bound) }) : t('bind.tipUnbound')
bindBtn.setAttribute('data-tip', tip)
bindBtn.setAttribute('aria-label', tip)
const icon = el.children[0] as HTMLElement | null
if (icon) {
const ovr = projects.iconOverrides[id]
@@ -1682,7 +1694,8 @@ function buildCustomLayoutPrompt(req: string): string {
role="button"
tabIndex={0}
data-bound={projects.bindings[l.id] ? 'true' : 'false'}
title={projects.bindings[l.id] ? t('bind.titleBound') : t('bind.titleUnbound')}
data-tip={projects.bindings[l.id] ? t('bind.tipBound', { name: boundSessionTitle(projects.bindings[l.id]) }) : t('bind.tipUnbound')}
aria-label={projects.bindings[l.id] ? t('bind.tipBound', { name: boundSessionTitle(projects.bindings[l.id]) }) : t('bind.tipUnbound')}
onClick={(e) => { e.stopPropagation(); openBindPick(l.id, e.currentTarget as HTMLElement) }}
><span className="dsh-wt_bindCircles" aria-hidden /></span>
<span className="dsh-wt_layoutArrow" aria-hidden>›</span>
+4
View File
@@ -88,6 +88,8 @@ export const zh = {
'bind.unbound': '未绑定对话',
'bind.titleUnbound': '绑定对话(未绑定 ○○):点击选择要跟随的对话',
'bind.titleBound': '已绑定对话(●●):点击更换或解绑',
'bind.tipUnbound': '未绑定对话:点击选择要跟随的对话',
'bind.tipBound': '已绑定对话:{name}',
'bind.hint': '一个项目只能绑定一个对话。选择后,打开该项目时右侧对话窗会自动切换过去;已绑定的项目不会因新建/发送对话而自动改绑。',
'customLayout.add': '自定义',
'customLayout.addTitle': '自定义一个布局(生成提示词)',
@@ -209,6 +211,8 @@ export const en = {
'bind.unbound': 'No conversation bound',
'bind.titleUnbound': 'Bind conversation (unbound ○○): pick the conversation to follow',
'bind.titleBound': 'Conversation bound (●●): click to change or unbind',
'bind.tipUnbound': 'No conversation bound — click to pick one',
'bind.tipBound': 'Bound to: {name}',
'bind.hint': 'A project can bind exactly one conversation. When bound, opening the project switches the right chat pane to it; an existing binding is never auto-changed by creating/sending conversations.',
'customLayout.add': 'Custom',
'customLayout.addTitle': 'Customize a layout (generate a prompt)',
+10 -8
View File
@@ -153,15 +153,17 @@ export const css = [
'.dsh-wt_presetAdd{border-style:dashed;color:var(--dsw-alias-state-accent-primary,#4f8ef7)}',
'.dsh-wt_presetAddIcon{font-size:18px;line-height:20px}',
'.dsh-wt_presetAddText{font-size:10px;line-height:13px}',
// 项目卡片上的对话绑定按钮(○○ 空心 = 未绑定 / ●● 实心 = 已绑定;CSS 双圆单色绘制;
// 布局卡与入驻卡统一绝对定位于卡片中间偏右、垂直居中,保证所有卡片竖向对齐)
'.dsh-wt_bindBtn{position:absolute;right:26px;top:50%;transform:translateY(-50%);width:18px;height:14px;margin:0;display:block;color:var(--dsw-alias-label-tertiary,#6b7280);cursor:pointer;user-select:none}',
'.dsh-wt_bindBtn:hover{color:var(--dsw-alias-label-primary,#e6e8eb)}',
'.dsh-wt_bindBtn[data-bound=true]{color:var(--dsw-alias-state-accent-primary,#4f8ef7)}',
'.dsh-wt_bindCircles{position:absolute;left:0;top:50%;width:18px;height:9px;transform:translateY(-50%)}',
'.dsh-wt_bindCircles::before,.dsh-wt_bindCircles::after{content:\'\';position:absolute;top:50%;width:8px;height:8px;margin-top:-4px;border-radius:50%;box-sizing:border-box;border:1.4px solid currentColor;background:transparent}',
// 项目卡片上的对话绑定按钮(○○ 空心 = 未绑定 / ●● 实心 = 已绑定;CSS 双圆绘制,黑白单色克制:
// 未绑定次级灰空心、已绑定主色实心,不用强调色;hover 时自身出现按钮底色 + 气泡显示绑定对象)
'.dsh-wt_bindBtn{position:absolute;right:26px;top:50%;transform:translateY(-50%);width:16px;height:12px;margin:0;display:block;border-radius:4px;color:var(--dsw-alias-label-secondary,#9aa4b2);cursor:pointer;user-select:none}',
'.dsh-wt_bindBtn:hover{background:var(--dsw-alias-fill-l2,rgba(255,255,255,.09));color:var(--dsw-alias-label-primary,#e6e8eb)}',
'.dsh-wt_bindBtn[data-bound=true]{color:var(--dsw-alias-label-primary,#e6e8eb)}',
'.dsh-wt_bindBtn::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%) translateY(2px);padding:4px 8px;border:1px solid var(--dsw-alias-border-l2,#3a4150);border-radius:6px;background:var(--dsw-alias-fill-l2,#171b22);color:var(--dsw-alias-label-primary,#e6e8eb);font-size:11px;line-height:15px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .12s ease, transform .12s ease;z-index:90;box-shadow:0 4px 12px rgba(0,0,0,.35)}',
'.dsh-wt_bindBtn:hover::after{opacity:1;transform:translateX(-50%) translateY(0)}',
'.dsh-wt_bindCircles{position:absolute;left:0;top:50%;width:14px;height:7px;transform:translateY(-50%)}',
'.dsh-wt_bindCircles::before,.dsh-wt_bindCircles::after{content:\'\';position:absolute;top:50%;width:6px;height:6px;margin-top:-3px;border-radius:50%;box-sizing:border-box;border:1.2px solid currentColor;background:transparent}',
'.dsh-wt_bindCircles::before{left:0}',
'.dsh-wt_bindCircles::after{left:9px}',
'.dsh-wt_bindCircles::after{left:7px}',
'.dsh-wt_bindBtn[data-bound=true] .dsh-wt_bindCircles::before,.dsh-wt_bindBtn[data-bound=true] .dsh-wt_bindCircles::after{background:currentColor}',
// 布局条目卡片