fix(frontend): 提升 Markdown 表格与列表对比度

This commit is contained in:
2026-08-30 20:23:22 +08:00
parent 7fa2e9c404
commit 668139706b
7 changed files with 39 additions and 12 deletions
+2 -2
View File
@@ -184,13 +184,13 @@ pnpm build
```text ```text
pnpm build passed pnpm build passed
pnpm test 17 passed pnpm test 18 passed
uv run pytest 71 passed uv run pytest 71 passed
preview smoke HTTP 200 preview smoke HTTP 200
git diff --check passed git diff --check passed
``` ```
当前前端使用 Vitest 执行 Store、Workspace、文件树、编辑器组件、智能体标签轻量动效约束测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 71 项测试结果,也不涉及产品代码。 当前前端使用 Vitest 执行 Store、Workspace、文件树、编辑器组件、智能体标签轻量动效约束和 Markdown 对比度 Token 测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 71 项测试结果,也不涉及产品代码。
Vite 当前会提示 Chat 与 Workspace 的部分异步 Chunk 超过 500 kB,这是 Milkdown、CodeMirror、KaTeX 和 Shiki 等编辑/渲染依赖带来的性能优化项,不影响构建成功或功能正确性;进入桌面打包前应通过手动分包或更细粒度动态加载继续优化。 Vite 当前会提示 Chat 与 Workspace 的部分异步 Chunk 超过 500 kB,这是 Milkdown、CodeMirror、KaTeX 和 Shiki 等编辑/渲染依赖带来的性能优化项,不影响构建成功或功能正确性;进入桌面打包前应通过手动分包或更细粒度动态加载继续优化。
@@ -97,12 +97,12 @@ backdrop-filter / filter 模糊
## 6. 验证 ## 6. 验证
新增 `styles/motion.spec.ts`,防止全局样式重新引入 `transition: all`、高成本模糊滤镜或布局型页面入场动画。 新增 `styles/motion.spec.ts`,防止全局样式重新引入 `transition: all`、高成本模糊滤镜或布局型页面入场动画,并约束 Markdown 表格与列表使用独立的高对比度主题变量
当前验证结果: 当前验证结果:
```text ```text
pnpm test 7 files / 17 tests passed pnpm test 7 files / 18 tests passed
pnpm build passed pnpm build passed
git diff --check passed git diff --check passed
``` ```
+2 -2
View File
@@ -84,10 +84,10 @@ pnpm test
```text ```text
7 test files passed 7 test files passed
17 tests passed 18 tests passed
``` ```
通过标准:退出码为 0、失败数为 0。测试覆盖 Provider Store、Workspace、文件树、文件切换、可视化编辑器、智能体中文标签轻量动效性能约束。 通过标准:退出码为 0、失败数为 0。测试覆盖 Provider Store、Workspace、文件树、文件切换、可视化编辑器、智能体中文标签轻量动效性能约束和 Markdown 对比度 Token
### 3.3 类型检查与生产构建 ### 3.3 类型检查与生产构建
@@ -23,12 +23,14 @@ watch(() => props.source, async (source) => {
.markdown-content :deep(h1), .markdown-content :deep(h2), .markdown-content :deep(h3) { margin: 1em 0 .5em; line-height: var(--line-height-tight); } .markdown-content :deep(h1), .markdown-content :deep(h2), .markdown-content :deep(h3) { margin: 1em 0 .5em; line-height: var(--line-height-tight); }
.markdown-content :deep(ul) { padding-left: 1.5em; list-style: disc; } .markdown-content :deep(ul) { padding-left: 1.5em; list-style: disc; }
.markdown-content :deep(ol) { padding-left: 1.5em; list-style: decimal; } .markdown-content :deep(ol) { padding-left: 1.5em; list-style: decimal; }
.markdown-content :deep(li::marker) { color: var(--color-markdown-marker); font-weight: 700; }
.markdown-content :deep(.shiki) { overflow: auto; padding: var(--space-md); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); } .markdown-content :deep(.shiki) { overflow: auto; padding: var(--space-md); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); }
.markdown-content :deep(code) { padding: .1em .3em; border-radius: var(--radius-sm); background: var(--color-background-tertiary); font-family: var(--font-ui-mono); } .markdown-content :deep(code) { padding: .1em .3em; border-radius: var(--radius-sm); background: var(--color-background-tertiary); font-family: var(--font-ui-mono); }
.markdown-content :deep(pre code) { padding: 0; background: transparent; } .markdown-content :deep(pre code) { padding: 0; background: transparent; }
.markdown-content :deep(blockquote) { padding-left: 1em; border-left: 3px solid var(--color-accent-primary); color: var(--color-text-secondary); } .markdown-content :deep(blockquote) { padding-left: 1em; border-left: 3px solid var(--color-accent-primary); color: var(--color-text-secondary); }
.markdown-content :deep(table) { width: 100%; margin: .65em 0; border-collapse: collapse; } .markdown-content :deep(table) { width: 100%; margin: .65em 0; border-collapse: collapse; }
.markdown-content :deep(th), .markdown-content :deep(td) { padding: .45em .65em; border: 1px solid var(--color-border-default); text-align: left; } .markdown-content :deep(th), .markdown-content :deep(td) { padding: .45em .65em; border: 1px solid var(--color-markdown-grid); text-align: left; }
.markdown-content :deep(th) { background: var(--color-markdown-table-header); font-weight: 700; }
.markdown-content :deep(img) { max-width: 100%; } .markdown-content :deep(img) { max-width: 100%; }
.markdown-content :deep(hr) { margin: 1em 0; border: 0; border-top: 1px solid var(--color-border-default); } .markdown-content :deep(hr) { margin: 1em 0; border: 0; border-top: 1px solid var(--color-border-default); }
:global([data-theme='dark']) .markdown-content :deep(.shiki), :global([data-theme='dark']) .markdown-content :deep(.shiki),
@@ -250,7 +250,7 @@ defineExpose({ getEditor: () => crepe?.editor })
--crepe-color-surface-low: var(--color-background-secondary); --crepe-color-surface-low: var(--color-background-secondary);
--crepe-color-on-surface: var(--color-text-primary); --crepe-color-on-surface: var(--color-text-primary);
--crepe-color-on-surface-variant: var(--color-text-secondary); --crepe-color-on-surface-variant: var(--color-text-secondary);
--crepe-color-outline: var(--color-border-default); --crepe-color-outline: var(--color-markdown-grid);
--crepe-color-primary: var(--color-accent-primary); --crepe-color-primary: var(--color-accent-primary);
--crepe-color-secondary: var(--color-accent-soft); --crepe-color-secondary: var(--color-accent-soft);
--crepe-color-on-secondary: var(--color-text-primary); --crepe-color-on-secondary: var(--color-text-primary);
@@ -272,10 +272,11 @@ defineExpose({ getEditor: () => crepe?.editor })
:global(.milkdown-toolbar) { border: 1px solid var(--color-border-default) !important; background: var(--color-surface-elevated) !important; box-shadow: var(--shadow-md) !important; } :global(.milkdown-toolbar) { border: 1px solid var(--color-border-default) !important; background: var(--color-surface-elevated) !important; box-shadow: var(--shadow-md) !important; }
:global(.milkdown-toolbar .toolbar-item svg), :global(.milkdown-toolbar .toolbar-item.active svg) { color: var(--color-text-primary) !important; fill: var(--color-text-primary) !important; opacity: 1 !important; } :global(.milkdown-toolbar .toolbar-item svg), :global(.milkdown-toolbar .toolbar-item.active svg) { color: var(--color-text-primary) !important; fill: var(--color-text-primary) !important; opacity: 1 !important; }
:global(.milkdown-toolbar .toolbar-item:hover svg), :global(.milkdown-toolbar .toolbar-item.active svg) { color: var(--color-accent-primary) !important; fill: var(--color-accent-primary) !important; } :global(.milkdown-toolbar .toolbar-item:hover svg), :global(.milkdown-toolbar .toolbar-item.active svg) { color: var(--color-accent-primary) !important; fill: var(--color-accent-primary) !important; }
:global([data-theme='light']) .milkdown-host :deep(.milkdown-table-block th), .milkdown-host :deep(.milkdown-table-block th),
:global([data-theme='light']) .milkdown-host :deep(.milkdown-table-block td) { border-color: var(--color-text-tertiary); } .milkdown-host :deep(.milkdown-table-block td) { border-color: var(--color-markdown-grid); }
:global([data-theme='light']) .milkdown-host :deep(.milkdown-list-item-block li .label-wrapper) { color: var(--color-text-secondary); font-weight: 600; } .milkdown-host :deep(.milkdown-table-block th) { background: var(--color-markdown-table-header); font-weight: 700; }
:global([data-theme='light']) .milkdown-host :deep(.milkdown-list-item-block li .label-wrapper svg) { fill: var(--color-text-secondary); } .milkdown-host :deep(.milkdown-list-item-block li .label-wrapper) { color: var(--color-markdown-marker); font-weight: 700; }
.milkdown-host :deep(.milkdown-list-item-block li .label-wrapper svg) { fill: var(--color-markdown-marker); }
.milkdown-host :deep(code) { font-family: var(--font-editor-mono); } .milkdown-host :deep(code) { font-family: var(--font-editor-mono); }
:global([data-theme='dark']) .milkdown-host :deep(.milkdown) { color-scheme: dark; } :global([data-theme='dark']) .milkdown-host :deep(.milkdown) { color-scheme: dark; }
@media (max-width: 680px) { .toolbar-select select { min-width: 46px; width: 46px; } } @media (max-width: 680px) { .toolbar-select select { min-width: 46px; width: 46px; } }
+12
View File
@@ -8,6 +8,11 @@ const globalStyles = [
new URL('./features.css', import.meta.url), new URL('./features.css', import.meta.url),
].map((path) => readFileSync(path, 'utf8')).join('\n') ].map((path) => readFileSync(path, 'utf8')).join('\n')
const markdownStyles = [
new URL('../features/editor/VisualMarkdownEditor.vue', import.meta.url),
new URL('../components/common/MarkdownContent.vue', import.meta.url),
].map((path) => readFileSync(path, 'utf8')).join('\n')
describe('轻量动效基线', () => { describe('轻量动效基线', () => {
it('为减少动态效果偏好提供全局回退', () => { it('为减少动态效果偏好提供全局回退', () => {
expect(globalStyles).toContain('@media (prefers-reduced-motion: reduce)') expect(globalStyles).toContain('@media (prefers-reduced-motion: reduce)')
@@ -24,4 +29,11 @@ describe('轻量动效基线', () => {
expect(pageAnimation).toContain('transform') expect(pageAnimation).toContain('transform')
expect(pageAnimation).not.toMatch(/(?:width|height|margin|padding|top|left)\s*:/) expect(pageAnimation).not.toMatch(/(?:width|height|margin|padding|top|left)\s*:/)
}) })
it('Markdown 序号和表格使用独立的高对比度主题变量', () => {
expect(globalStyles).toContain('--color-markdown-grid:')
expect(globalStyles).toContain('--color-markdown-marker:')
expect(markdownStyles).toContain('var(--color-markdown-grid)')
expect(markdownStyles).toContain('var(--color-markdown-marker)')
})
}) })
+12
View File
@@ -44,6 +44,11 @@
--color-border-focus: #5b67f1; --color-border-focus: #5b67f1;
--color-border-disabled: #eef0f3; --color-border-disabled: #eef0f3;
/* Markdown */
--color-markdown-grid: #8b949e;
--color-markdown-marker: #343b44;
--color-markdown-table-header: #eef0f3;
/* Shadow */ /* Shadow */
--shadow-sm: 0 1px 2px rgba(31, 35, 40, 0.05), 0 1px 5px rgba(31, 35, 40, 0.03); --shadow-sm: 0 1px 2px rgba(31, 35, 40, 0.05), 0 1px 5px rgba(31, 35, 40, 0.03);
--shadow-md: 0 8px 22px rgba(31, 35, 40, 0.08), 0 2px 6px rgba(31, 35, 40, 0.04); --shadow-md: 0 8px 22px rgba(31, 35, 40, 0.08), 0 2px 6px rgba(31, 35, 40, 0.04);
@@ -152,6 +157,10 @@
--color-border-focus: #7d8bff; --color-border-focus: #7d8bff;
--color-border-disabled: #21262d; --color-border-disabled: #21262d;
--color-markdown-grid: #6e7681;
--color-markdown-marker: #c9d1d9;
--color-markdown-table-header: #21262d;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5); --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
@@ -172,6 +181,9 @@
--color-text-tertiary: #9a8a72; --color-text-tertiary: #9a8a72;
--color-border-default: #ddcfad; --color-border-default: #ddcfad;
--color-border-subtle: #eadfc4; --color-border-subtle: #eadfc4;
--color-markdown-grid: #9c8353;
--color-markdown-marker: #554735;
--color-markdown-table-header: #eadbb8;
--color-accent-primary: #8a5b32; --color-accent-primary: #8a5b32;
--color-accent-primary-hover: #704724; --color-accent-primary-hover: #704724;
--color-accent-soft: #edddbd; --color-accent-soft: #edddbd;