优化: 无障碍第二批(icon-only aria-label + 容器键盘化 20 处)
- TopBar 10 处 icon-only 按钮补 aria-label(复用同 :title 表达式,含三态 title) - ConversationSidebar: 4 icon-only aria-label + 2 分组标题键盘化(role/tabindex/aria-expanded/keydown) - MessageList 2 icon-only; KnowledgeDetail 3 章节折叠键盘化; dashboard 两列表项键盘化 - FileExplorer 面包屑/模块下拉项键盘化; ConflictResolver 冲突文件折叠键盘化 - 约定: 遮罩/点外关闭类(@click.self)非键盘缺口,跳过;零新增 i18n 键 - 验收: bunx vue-tsc --noEmit EXIT 0;看板 P3-2 更新(两批共 23 处)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
动作按钮经 emit 回父(父持有 clear/compress/confirm 逻辑 + 单一 toast 源)。 ═══ -->
|
||||
<div class="ai-header">
|
||||
<div class="ai-header-left">
|
||||
<button class="ai-btn-icon" @click="emit('toggle-sidebar')" :title="$t('aiChat.conversationList')">
|
||||
<button class="ai-btn-icon" @click="emit('toggle-sidebar')" :title="$t('aiChat.conversationList')" :aria-label="$t('aiChat.conversationList')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
||||
</button>
|
||||
<span class="ai-header-icon">
|
||||
@@ -79,6 +79,7 @@
|
||||
class="ai-btn-icon"
|
||||
:class="{ 'ai-btn-icon--active': moreMenuOpen }"
|
||||
:title="$t('aiChat.moreActions')"
|
||||
:aria-label="$t('aiChat.moreActions')"
|
||||
@click="moreMenuOpen = !moreMenuOpen"
|
||||
>
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="19" r="1.5"/></svg>
|
||||
@@ -118,14 +119,14 @@
|
||||
|
||||
<!-- 嵌入模式:最大化/还原 + 分离 + 关闭 -->
|
||||
<template v-if="!detached">
|
||||
<button class="ai-btn-icon" @click="emit('toggle-maximize')" :title="store.state.maximized ? $t('aiChat.restoreSidebar') : $t('aiChat.maximize')">
|
||||
<button class="ai-btn-icon" @click="emit('toggle-maximize')" :title="store.state.maximized ? $t('aiChat.restoreSidebar') : $t('aiChat.maximize')" :aria-label="store.state.maximized ? $t('aiChat.restoreSidebar') : $t('aiChat.maximize')">
|
||||
<svg aria-hidden="true" v-if="store.state.maximized" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="9" y1="3" x2="9" y2="21"/></svg>
|
||||
<svg aria-hidden="true" v-else width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/></svg>
|
||||
</button>
|
||||
<button class="ai-btn-icon" @click="emit('detach')" :title="$t('aiChat.detachWindow')">
|
||||
<button class="ai-btn-icon" @click="emit('detach')" :title="$t('aiChat.detachWindow')" :aria-label="$t('aiChat.detachWindow')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>
|
||||
</button>
|
||||
<button class="ai-btn-icon" @click="emit('close-panel')" :title="$t('aiChat.closePanel')">
|
||||
<button class="ai-btn-icon" @click="emit('close-panel')" :title="$t('aiChat.closePanel')" :aria-label="$t('aiChat.closePanel')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
</template>
|
||||
@@ -133,16 +134,16 @@
|
||||
<template v-else>
|
||||
<!-- V11b(2026-10-05):收回分离窗回主面板(emitReattachToMain → 主窗 reattachPanel),
|
||||
分离窗自关。与「关闭」区别:关闭仅关窗不恢复主面板,收回=分离→主面板合一 -->
|
||||
<button class="ai-btn-icon" @click="emit('reattach')" :title="$t('aiChat.reattachToMain')">
|
||||
<button class="ai-btn-icon" @click="emit('reattach')" :title="$t('aiChat.reattachToMain')" :aria-label="$t('aiChat.reattachToMain')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/><path d="M9 12h6"/><path d="M12 9l0 6"/></svg>
|
||||
</button>
|
||||
<button class="ai-btn-icon" :class="{ 'ai-btn-icon--active': store.state.docked }" @click="emit('dock')" :title="store.state.docked ? $t('aiChat.undock') : $t('aiChat.dockRight')">
|
||||
<button class="ai-btn-icon" :class="{ 'ai-btn-icon--active': store.state.docked }" @click="emit('dock')" :title="store.state.docked ? $t('aiChat.undock') : $t('aiChat.dockRight')" :aria-label="store.state.docked ? $t('aiChat.undock') : $t('aiChat.dockRight')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="8" height="18" rx="1"/><rect x="14" y="3" width="8" height="18" rx="1"/></svg>
|
||||
</button>
|
||||
<button class="ai-btn-icon" :class="{ 'ai-btn-icon--active': alwaysOnTop }" @click="emit('toggle-always-on-top')" :title="alwaysOnTop ? $t('aiChat.unpin') : $t('aiChat.pinOnTop')">
|
||||
<button class="ai-btn-icon" :class="{ 'ai-btn-icon--active': alwaysOnTop }" @click="emit('toggle-always-on-top')" :title="alwaysOnTop ? $t('aiChat.unpin') : $t('aiChat.pinOnTop')" :aria-label="alwaysOnTop ? $t('aiChat.unpin') : $t('aiChat.pinOnTop')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2C8 2 6 5 6 8v3l-2 2v1h16v-1l-2-2V8c0-3-2-6-6-6z"/><line x1="12" y1="14" x2="12" y2="22"/></svg>
|
||||
</button>
|
||||
<button class="ai-btn-icon" @click="emit('close-detached')" :title="$t('aiChat.closeWindow')">
|
||||
<button class="ai-btn-icon" @click="emit('close-detached')" :title="$t('aiChat.closeWindow')" :aria-label="$t('aiChat.closeWindow')">
|
||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
</template>
|
||||
@@ -246,7 +247,7 @@
|
||||
</div>
|
||||
<!-- L3 完整上下文 -->
|
||||
<div v-if="contextInfo.goals.length || contextInfo.summaryCount > 0" class="ai-context-inline">
|
||||
<button type="button" class="ai-context-inline-badge ai-tool-badge" :class="{ 'is-active': contextExpanded }" @click="togglePanel('context')" :title="$t('aiChat.viewContext')">
|
||||
<button type="button" class="ai-context-inline-badge ai-tool-badge" :class="{ 'is-active': contextExpanded }" @click="togglePanel('context')" :title="$t('aiChat.viewContext')" :aria-label="$t('aiChat.viewContext')">
|
||||
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><circle cx="12" cy="8" r="1" fill="currentColor"/></svg>
|
||||
</button>
|
||||
<Transition name="ai-pop">
|
||||
|
||||
Reference in New Issue
Block a user