style: 重做界面视觉与信息层级

先截图审视现状,再针对性修改。主要问题与改动如下。

工具栏
- 标签筛选从「平铺全部标签」改为下拉面板,标签多时不再换行挤爆工具栏
- 备份与快捷键帮助移到导航栏 —— 它们是应用级操作,不该挤在看板工具栏里,
  顺带修好了「? 帮助只在看板可用」的问题
- 到期统计(今日到期 / 逾期)合并为可点击的筛选入口,去掉两个独立控件
- 移动端工具栏从占半屏降到三行紧凑布局

卡片
- 优先级从彩色胶囊改为左侧色条,扫视一列时比读文字更快分辨轻重
- 元信息改为「优先级 · 日期 · 标签」的轻量文本行,不再三种胶囊叠在一起
- 完成态用勾选图标 + 降低不透明度

布局
- 今日视图限宽居中(max-w-3xl):此前 1440px 下卡片被拉满整屏,
  标题与元信息之间出现大片空白
- 修复移动端卡片被压成细条:TaskCard 的 overflow-hidden(用于裁切左侧色条)
  会让 flex 项的最小尺寸解析为 0,补 shrink-0 修正;
  同时改为移动端按内容高度堆叠、桌面端列内滚动

其他
- 导航栏品牌改用看板图标,消除「看板」重复出现两次
- 统一卡片阴影、圆角与键盘焦点样式
- 新增 scripts/screenshot.mjs,便于后续对照审视视觉改动

验证:单元测试 452 个、端到端测试 23 个全部通过,lint 与构建无错误。
This commit is contained in:
chenshoulin
2026-10-18 14:05:06 +08:00
parent 4e064e82ea
commit 442cbbd734
23 changed files with 981 additions and 333 deletions
+9 -32
View File
@@ -9,6 +9,7 @@ import { createMemoryTaskRepository } from '@/data/taskRepository'
import { useFilterStore } from '@/stores/filters'
import { useTaskStore } from '@/stores/tasks'
import { useToastStore } from '@/stores/toast'
import { useUiStore } from '@/stores/ui'
import BoardView from './BoardView.vue'
@@ -53,7 +54,7 @@ describe('BoardView 结构', () => {
store.createTask({ title: '进行中事项', status: 'doing' })
const counters = mountBoard(pinia)
.findAll('section header span')
.findAll('[data-role="column-count"]')
.map((node) => node.text())
expect(counters).toEqual(['1', '1', '0'])
})
@@ -245,7 +246,7 @@ describe('BoardView 筛选', () => {
expect(wrapper.findAll('article')).toHaveLength(1)
expect(wrapper.text()).toContain('高优先级')
expect(wrapper.text()).not.toContain('低优先级')
expect(wrapper.findAll('section header span')[0]?.text()).toBe('1')
expect(wrapper.findAll('[data-role="column-count"]')[0]?.text()).toBe('1')
})
it('显示命中数量提示', async () => {
@@ -257,7 +258,7 @@ describe('BoardView 筛选', () => {
useFilterStore().togglePriority(3)
await nextTick()
expect(wrapper.text()).toContain('显示 1 / 2 个任务')
expect(wrapper.text()).toContain('已隐藏 1 个')
})
it('清空筛选后恢复全部卡片', async () => {
@@ -273,7 +274,7 @@ describe('BoardView 筛选', () => {
await nextTick()
expect(wrapper.findAll('article')).toHaveLength(2)
expect(wrapper.text()).not.toContain('显示 1 / 2')
expect(wrapper.text()).not.toContain('已隐藏')
})
it('点击「逾期」只显示逾期任务', async () => {
@@ -327,7 +328,7 @@ describe('BoardView 归档', () => {
const wrapper = mountBoard(pinia)
expect(wrapper.findAll('article')).toHaveLength(0)
expect(wrapper.text()).toContain('显示 0 / 1 个任务')
expect(wrapper.text()).toContain('已隐藏 1 个')
})
it('开启「显示归档」后归档任务重新出现', async () => {
@@ -400,17 +401,6 @@ describe('BoardView 快捷键', () => {
expect(document.activeElement).toBe(wrapper.find('input[aria-label="搜索任务"]').element)
})
it('按 ? 打开快捷键帮助', async () => {
const { pinia } = setup()
const wrapper = mountBoard(pinia)
await nextTick()
pressKey('?')
await nextTick()
expect(wrapper.text()).toContain('聚焦「待办」列的快速新增输入框')
})
it('在输入框内按 N 不触发快捷键', async () => {
const { pinia } = setup()
const wrapper = mountBoard(pinia)
@@ -422,29 +412,16 @@ describe('BoardView 快捷键', () => {
expect(document.activeElement).not.toBe(wrapper.find('input[aria-label="添加任务"]').element)
})
it('面板打开时不响应快捷键', async () => {
it('应用级面板打开时不响应快捷键', async () => {
const { pinia } = setup()
const wrapper = mountBoard(pinia)
await nextTick()
await wrapper.find('button[aria-label="快捷键帮助"]').trigger('click')
// 帮助面板由 App 渲染,这里只验证看板会让出快捷键
useUiStore().openHelp()
await nextTick()
pressKey('n')
expect(document.activeElement).not.toBe(wrapper.find('input[aria-label="添加任务"]').element)
})
it('按 Esc 关闭已打开的面板', async () => {
const { pinia } = setup()
const wrapper = mountBoard(pinia)
await nextTick()
await wrapper.find('button[aria-label="快捷键帮助"]').trigger('click')
await nextTick()
expect(wrapper.text()).toContain('聚焦「待办」列的快速新增输入框')
pressKey('Escape')
await nextTick()
expect(wrapper.text()).not.toContain('聚焦「待办」列的快速新增输入框')
})
})