优化: 无障碍第二批(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:
lxy
2026-10-10 01:04:09 +08:00
parent 9d83a06300
commit 2a3a6cd25b
9 changed files with 98 additions and 26 deletions
+18 -5
View File
@@ -14,7 +14,7 @@
/>
<div class="ai-conv-sidebar-header">
<span class="ai-conv-sidebar-title">{{ t('aiChat.sidebarTitle') }}</span>
<button class="ai-btn-icon" @click="emit('confirm-new-conversation')" :title="t('aiChat.newConversation')">
<button class="ai-btn-icon" @click="emit('confirm-new-conversation')" :title="t('aiChat.newConversation')" :aria-label="t('aiChat.newConversation')">
<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="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
</button>
</div>
@@ -80,7 +80,7 @@
</div>
<div class="ai-conv-item-actions">
<div class="ai-conv-item-more">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')" :aria-label="t('aiChat.moreActions')">
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
</button>
<div v-if="actionsOpenId === conv.id" class="ai-conv-actions-menu">
@@ -115,7 +115,12 @@
<template v-for="group in groupedActive" :key="'g-' + group.key">
<div
class="ai-conv-group-title ai-conv-group-title--fold"
role="button"
tabindex="0"
:aria-expanded="!store.state.foldedGroups[group.key]"
@click="store.toggleGroupFold(group.key)"
@keydown.enter.prevent="store.toggleGroupFold(group.key)"
@keydown.space.prevent="store.toggleGroupFold(group.key)"
>
<span class="ai-conv-group-arrow" :class="{ 'is-folded': store.state.foldedGroups[group.key] }">▸</span>
{{ group.label }}
@@ -174,7 +179,7 @@
</div>
<div class="ai-conv-item-actions">
<div class="ai-conv-item-more">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')" :aria-label="t('aiChat.moreActions')">
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
</button>
<div v-if="actionsOpenId === conv.id" class="ai-conv-actions-menu">
@@ -228,7 +233,15 @@
<!-- 归档分组(可折叠) -->
<template v-if="archivedConvs.length">
<div class="ai-conv-group-title ai-conv-group-title--fold" @click="store.toggleArchivedFold()">
<div
class="ai-conv-group-title ai-conv-group-title--fold"
role="button"
tabindex="0"
:aria-expanded="!store.state.archivedCollapsed"
@click="store.toggleArchivedFold()"
@keydown.enter.prevent="store.toggleArchivedFold()"
@keydown.space.prevent="store.toggleArchivedFold()"
>
<span class="ai-conv-group-arrow" :class="{ 'is-folded': store.state.archivedCollapsed }">▸</span>
{{ t('aiChat.archivedCount', { n: archivedConvs.length }) }}
</div>
@@ -258,7 +271,7 @@
</div>
<div class="ai-conv-item-actions">
<div class="ai-conv-item-more">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')">
<button class="ai-conv-item-act" @click.stop="toggleActionsMenu(conv.id)" :title="t('aiChat.moreActions')" :aria-label="t('aiChat.moreActions')">
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
</button>
<div v-if="actionsOpenId === conv.id" class="ai-conv-actions-menu">