fix(code-highlighter): 修复暗色主题下未高亮代码为黑色文字,并将硬编码色 token 化 - #172
Merged
Conversation
When a language misses the highlighter, `codeToHtml` returns a bare `<pre><code>` without inline colors, and the `-dark` style block never set a `color` on `-code`. The text then inherited the ambient `colorText` (near-black in a light context) on top of the `#1e1e1e` content background, making it unreadable. This hits more than plain text: the built-in language whitelist only covers typescript / javascript / python / json / html / css, so any other language without a custom `setupCodeHighlighter` loader takes the same fallback path. Add `codeColor` / `codeColorDark` component tokens, defaulting to the vitesse-light / vitesse-dark foreground colors so the fallback matches highlighted output. Shiki writes its colors inline, so these rules only apply when highlighting is absent. They are component tokens rather than global ones because `-light` / `-dark` are self-contained color schemes with hardcoded backgrounds — using `colorText` would break the mirrored case (dark algorithm + `theme="light"`).
The `-light` / `-dark` variants are self-contained color schemes picked by the user-controlled `theme` prop, so their colors cannot come from global tokens — those follow the app algorithm and would break whenever `theme` is set opposite to it. Move every remaining literal out of the style function into component tokens with unchanged defaults, so users can override them via `theme.components.CodeHighlighter`: codeBg / codeBgDark, codeHeaderBgDark, codeBorderColorDark, codeLangColorDark, codeLineNumberColorDark, codeBtnColorDark, codeBtnHoverBgDark. No visual change — the defaults are the previous literals.
1 task
cc-hearts
added a commit
that referenced
this pull request
Aug 7, 2026
…174) * fix(code-highlighter): make light-theme line number color self-contained The previous dark-theme fix (#172) added a self-contained `codeLineNumberColorDark` token, but the light-theme line number color still used the global `token.colorTextQuaternary`. The `-light` / `-dark` variants are self-contained color schemes driven by the `theme` prop, so their colors must not follow the app color algorithm. In the mirrored case (app on the dark algorithm + `theme="light"`), `colorTextQuaternary` resolves to `rgba(255, 255, 255, 0.25)` (from `colorTextBase=#fff`), rendered on top of the `#fafafa` light background, making the line numbers nearly invisible. Add a `codeLineNumberColor` component token (light counterpart to `codeLineNumberColorDark`), defaulting to `rgba(0, 0, 0, 0.25)` - the effective color of `colorTextQuaternary` under the light algorithm (`colorTextBase=#000` @ 0.25) - so the common-case appearance is unchanged while the value no longer drifts with the app algorithm. * fix(code-highlighter): make light-theme chrome fully self-contained The previous commit only tokenized the line-number color. The rest of the light-theme chrome still used algorithm-driven global tokens, so in the mirrored case (app on the dark algorithm + `theme="light"`) the language label and action buttons became invisible, the header lost separation from the content, and the borders were wrong. Add the missing light counterparts to the existing dark tokens and wire them in, so `-light` / `-dark` are now fully self-contained and symmetric: - `codeHeaderBg` (was `colorFillSecondary`) - `codeBorderColor` (was `colorBorderSecondary`, used on root / header-bottom / gutter-right) - `codeLangColor` (was `colorTextSecondary`) - `codeBtnColor` (was `colorTextSecondary`) - `codeBtnHoverBg` (light had no hover override; antd Button's algorithm-driven default was used) Also fix the dark-theme root border, which used the global `colorBorder` instead of the existing `codeBorderColorDark` - in the mirrored case (light algorithm + `theme="dark"`) it drew a light `#d9d9d9` outline around the dark card. The light-theme action buttons now mirror the dark side: `!important` plus an explicit hover background, so the override reliably beats antd Button's `.ant-btn-variant-text` color (which is why the dark side already needed `!important`). Defaults preserve the previous common-case appearance: opaque hexes are the equivalent of the prior translucent global tokens composited over white (e.g. `#f0f0f0` == `colorBorderSecondary` / `colorFillSecondary` over white), and the rgba text colors match the prior `colorTextSecondary` under the light algorithm.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
最小复现:
<ax-code-highlighter theme="dark" language="text" content="123" />暗色主题下文字仍是黑色,压在
#1e1e1e的背景上,基本看不见。原因
shiki.ts:147里,语言没命中高亮时会直接返回裸的<pre><code>…</code></pre>,不带任何 inline 颜色:而
style/index.ts的&-dark样式块只设置了 header 背景、-lang、按钮、-content背景、行号颜色,唯独没有给-code设color。于是文字继承外层的token.colorText(浅色上下文里是近黑色),黑字压深底。影响面比纯文本更大:内置语言白名单只有
typescript/javascript/python/json/html/css(shiki.ts:22-29),因此bash、go、java、sql等在未调用setupCodeHighlighter注入 loader 时都会走同一条降级路径,暗色下同样是黑字。修复(commit 1)
新增
codeColor/codeColorDark两个 Component Token,分别作用于亮色态和&-dark态的-code,默认值取 shikivitesse-light/vitesse-dark的前景色,保证降级文本与正常高亮的色调一致。Shiki 高亮成功时颜色写在 inline style 上,优先级更高,因此这两条规则只在「未高亮」时生效,不影响已高亮的代码。
顺带清理(commit 2)
把样式函数里剩余的 8 处硬编码色也全部移到 Component Token,默认值保持原样,无视觉变化:
codeBg/codeBgDark#fafafa/#1e1e1ecodeHeaderBgDark#252526codeBorderColorDark#3e3e42codeLangColorDark#cccccccodeLineNumberColorDark#858585codeBtnColorDark#ffffffcodeBtnHoverBgDark#3e3e42改完后样式函数里已无颜色字面量,字面量只存在于
prepareComponentToken,使用方可通过theme.components.CodeHighlighter覆盖。为什么用 Component Token 而不是全局 Token
themeprop 完全由使用方控制,-light/-dark是两套各自自包含的配色,与全局 algorithm 无关。如果这些颜色改用colorText/colorFillQuaternary之类的全局 token,那么「theme与全局 algorithm 相反」时(例如整站 darkAlgorithm 但组件用默认theme="light"),背景与文字会同时朝一个方向漂移,重新造出这次修的那类「深底深字 / 白底白字」问题。固定默认值 + 可覆盖的 Component Token 在两个方向上都稳。说明
组件的
theme保持完全由使用方控制,本 PR 不引入任何自动跟随全局 algorithm 的行为。验证
vp run --filter @antdv-next/x type-check通过vp check --fix(commit hook)通过