refactor(shared): 下沉 mermaid Catppuccin 主题变量到 shared 包

前台 yggdrasil-core 的 LATTE_VARS/MOCHA_VARS 是 mermaid 配色唯一真相源。
后台 tiptap 编辑器要实现 mermaid 预览且与前台视觉一致,需复用同一套变量;
若复制一份会立即产生漂移风险,而「主题一致性」正是编辑器预览的核心目标。

按 shared 包「单一真相源」的设计意图,把两套主题变量(~100 行)+ MermaidThemeVariables
类型 + mermaidThemeVarsFor(theme) 工具函数搬到 shared。yggdrasil-core 改 import
自 shared,删除本地定义——行为零变化(同一份变量,只换引用源)。

前台 37 个测试全绿回归,含 10 个 mermaid 测试验证亮/暗主题传入正确调色板。
This commit is contained in:
xfy 2026-07-23 15:12:48 +08:00
parent 86781d8bbc
commit 800129e245
2 changed files with 133 additions and 119 deletions

View File

@ -25,3 +25,131 @@ export const THEME_CHANGE_EVENT = 'yggdrasil:theme-change';
export function prefersReducedMotion(): boolean {
return !!window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}
// ---------------------------------------------------------------------------
// Mermaid Catppuccin 主题变量
// ---------------------------------------------------------------------------
//
// 这是 mermaid 渲染配色的单一真相源。前台 yggdrasil-core 与后台 tiptap-editor
// 都从这里取,保证「编辑器预览 = 线上文章页」视觉一致(各 IIFE 不能 import 彼此,
// 但都能 inline 本包)。
//
// mermaid 把颜色烤进 SVG 内联 style,无法靠 CSS 原地改主题,故须在 initialize 时注入。
// 用 `theme: 'base'`(非 'default'/'dark'):base 主题不硬编码颜色,themeVariables 能完全
// 控制调色板;'default' 主题硬编码 mainBkg=#ECECFF 等会阻断覆盖。
//
// 设计哲学:极简卡片化——节点用 surface 色阶(卡片感)、边框/连线用 subtext 色阶(克制)、
// 文字用 primary text。不滥用强调色,绿/紫等 accent 留给作者用 classDef 手动强调。
// hex 值取自 themes/Catppuccin Latte.tmTheme 与 Catppuccin Mocha.tmTheme。
//
// 覆盖的字段涵盖 flowchart / sequence / class 三类图(测试文章用到的全部类型)。
/** mermaid themeVariables 的字段集合(mermaid 实际接受更多字段,这里只列项目用到的)。 */
export type MermaidThemeVariables = Record<string, unknown>;
/** Latte(亮)主题:节点 surface 色阶、文字 #4c4f69、连线 subtext1 #5c5f77。 */
export const MERMAID_LATTE_VARS: MermaidThemeVariables = {
background: '#dce0e8', // = --color-paper-code-block,图背景与 pre 无缝衔接
// 节点填充:surface 色阶递进(主/次/三级),卡片质感
primaryColor: '#e6e9ef',
secondaryColor: '#ccd0da',
tertiaryColor: '#bcc0cc',
mainBkg: '#e6e9ef',
nodeBkg: '#e6e9ef',
secondBkg: '#ccd0da',
// 节点边框:surface1 偏冷灰
primaryBorderColor: '#bcc0cc',
secondaryBorderColor: '#acb0be',
tertiaryBorderColor: '#9ca0b0',
nodeBorder: '#bcc0cc',
clusterBorder: '#bcc0cc',
labelBoxBorderColor: '#bcc0cc',
// 文字:primary text #4c4f69
primaryTextColor: '#4c4f69',
secondaryTextColor: '#5c5f77',
tertiaryTextColor: '#6c6f85',
textColor: '#4c4f69',
nodeTextColor: '#4c4f69',
titleColor: '#4c4f69',
classText: '#4c4f69',
labelTextColor: '#4c4f69',
// 连线/箭头:subtext1 #5c5f77
lineColor: '#5c5f77',
defaultLinkColor: '#5c5f77',
arrowheadColor: '#5c5f77',
// 时序图
actorBkg: '#e6e9ef',
actorBorder: '#bcc0cc',
actorTextColor: '#4c4f69',
actorLineColor: '#5c5f77',
signalColor: '#5c5f77',
signalTextColor: '#4c4f69',
loopTextColor: '#4c4f69',
sequenceNumberColor: '#eff1f5',
activationBkgColor: '#ccd0da',
activationBorderColor: '#bcc0cc',
// 边标签 / 子图背景
edgeLabelBackground: '#eff1f5',
labelBoxBkgColor: '#eff1f5',
clusterBkg: 'rgba(239, 241, 245, 0.5)',
// 注释:低饱和黄(Latte yellow #df8e1d)
noteBkgColor: 'rgba(223, 142, 29, 0.15)',
noteBorderColor: '#df8e1d',
noteTextColor: '#4c4f69',
// 字体:与正文 sans 对齐,中文友好
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif",
fontSize: '16px',
};
/** Mocha(暗)主题:节点 surface 色阶、文字 #cdd6f4、连线 subtext0 #a6adc8。 */
export const MERMAID_MOCHA_VARS: MermaidThemeVariables = {
background: '#313244', // = --color-paper-code-block(暗)
primaryColor: '#45475a',
secondaryColor: '#585b70',
tertiaryColor: '#1e1e2e',
mainBkg: '#45475a',
nodeBkg: '#45475a',
secondBkg: '#585b70',
primaryBorderColor: '#585b70',
secondaryBorderColor: '#45475a',
tertiaryBorderColor: '#313244',
nodeBorder: '#585b70',
clusterBorder: '#585b70',
labelBoxBorderColor: '#585b70',
primaryTextColor: '#cdd6f4',
secondaryTextColor: '#bac2de',
tertiaryTextColor: '#a6adc8',
textColor: '#cdd6f4',
nodeTextColor: '#cdd6f4',
titleColor: '#cdd6f4',
classText: '#cdd6f4',
labelTextColor: '#cdd6f4',
lineColor: '#a6adc8',
defaultLinkColor: '#a6adc8',
arrowheadColor: '#a6adc8',
actorBkg: '#45475a',
actorBorder: '#585b70',
actorTextColor: '#cdd6f4',
actorLineColor: '#a6adc8',
signalColor: '#a6adc8',
signalTextColor: '#cdd6f4',
loopTextColor: '#cdd6f4',
sequenceNumberColor: '#1e1e2e',
activationBkgColor: '#585b70',
activationBorderColor: '#6c7086',
edgeLabelBackground: '#1e1e2e',
labelBoxBkgColor: '#1e1e2e',
clusterBkg: 'rgba(30, 30, 46, 0.5)',
noteBkgColor: 'rgba(249, 226, 175, 0.12)',
noteBorderColor: '#f9e2af',
noteTextColor: '#cdd6f4',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif",
fontSize: '16px',
};
/** 按主题返回对应 Catppuccin themeVariables 的副本(调用方可安全 mutate)。 */
export function mermaidThemeVarsFor(theme: ThemeName): MermaidThemeVariables {
return theme === 'dark' ? { ...MERMAID_MOCHA_VARS } : { ...MERMAID_LATTE_VARS };
}

View File

@ -20,6 +20,7 @@
*/
import type { ThemeName } from '@yggdrasil/shared';
import { mermaidThemeVarsFor } from '@yggdrasil/shared';
import { onThemeChange } from './theme-transition';
/** 文章正文容器选择器(与 post_content.rs 的 __initMermaid 调用一致)。 */
@ -31,126 +32,11 @@ type MermaidApi = {
};
/**
* Catppuccin themeVariables --color-paper-* / .tmTheme
*
* mermaid SVG style CSS initialize
* `theme: 'base'` 'default'/'dark'base themeVariables
* 'default' mainBkg=#ECECFF
*
* surface /线 subtext
* primary text绿/ accent classDef
* hex themes/Catppuccin Latte.tmTheme Catppuccin Mocha.tmTheme
*
* flowchart / sequence / class
* Catppuccin themeVariables @yggdrasil/shared tiptap
* `theme: 'base'` themeVariables
* shared/src/index.ts MERMAID_LATTE_VARS / MERMAID_MOCHA_VARS
*/
/** Latte主题节点 surface 色阶、文字 #4c4f69、连线 subtext1 #5c5f77。 */
const LATTE_VARS = {
background: '#dce0e8', // = --color-paper-code-block图背景与 pre 无缝衔接
// 节点填充surface 色阶递进(主/次/三级),卡片质感
primaryColor: '#e6e9ef',
secondaryColor: '#ccd0da',
tertiaryColor: '#bcc0cc',
mainBkg: '#e6e9ef',
nodeBkg: '#e6e9ef',
secondBkg: '#ccd0da',
// 节点边框surface1 偏冷灰
primaryBorderColor: '#bcc0cc',
secondaryBorderColor: '#acb0be',
tertiaryBorderColor: '#9ca0b0',
nodeBorder: '#bcc0cc',
clusterBorder: '#bcc0cc',
labelBoxBorderColor: '#bcc0cc',
// 文字primary text #4c4f69
primaryTextColor: '#4c4f69',
secondaryTextColor: '#5c5f77',
tertiaryTextColor: '#6c6f85',
textColor: '#4c4f69',
nodeTextColor: '#4c4f69',
titleColor: '#4c4f69',
classText: '#4c4f69',
labelTextColor: '#4c4f69',
// 连线/箭头subtext1 #5c5f77
lineColor: '#5c5f77',
defaultLinkColor: '#5c5f77',
arrowheadColor: '#5c5f77',
// 时序图
actorBkg: '#e6e9ef',
actorBorder: '#bcc0cc',
actorTextColor: '#4c4f69',
actorLineColor: '#5c5f77',
signalColor: '#5c5f77',
signalTextColor: '#4c4f69',
loopTextColor: '#4c4f69',
sequenceNumberColor: '#eff1f5',
activationBkgColor: '#ccd0da',
activationBorderColor: '#bcc0cc',
// 边标签 / 子图背景
edgeLabelBackground: '#eff1f5',
labelBoxBkgColor: '#eff1f5',
clusterBkg: 'rgba(239, 241, 245, 0.5)',
// 注释低饱和黄Latte yellow #df8e1d
noteBkgColor: 'rgba(223, 142, 29, 0.15)',
noteBorderColor: '#df8e1d',
noteTextColor: '#4c4f69',
// 字体:与正文 sans 对齐,中文友好
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif",
fontSize: '16px',
} as const;
/** Mocha主题节点 surface 色阶、文字 #cdd6f4、连线 subtext0 #a6adc8。 */
const MOCHA_VARS = {
background: '#313244', // = --color-paper-code-block
primaryColor: '#45475a',
secondaryColor: '#585b70',
tertiaryColor: '#1e1e2e',
mainBkg: '#45475a',
nodeBkg: '#45475a',
secondBkg: '#585b70',
primaryBorderColor: '#585b70',
secondaryBorderColor: '#45475a',
tertiaryBorderColor: '#313244',
nodeBorder: '#585b70',
clusterBorder: '#585b70',
labelBoxBorderColor: '#585b70',
primaryTextColor: '#cdd6f4',
secondaryTextColor: '#bac2de',
tertiaryTextColor: '#a6adc8',
textColor: '#cdd6f4',
nodeTextColor: '#cdd6f4',
titleColor: '#cdd6f4',
classText: '#cdd6f4',
labelTextColor: '#cdd6f4',
lineColor: '#a6adc8',
defaultLinkColor: '#a6adc8',
arrowheadColor: '#a6adc8',
actorBkg: '#45475a',
actorBorder: '#585b70',
actorTextColor: '#cdd6f4',
actorLineColor: '#a6adc8',
signalColor: '#a6adc8',
signalTextColor: '#cdd6f4',
loopTextColor: '#cdd6f4',
sequenceNumberColor: '#1e1e2e',
activationBkgColor: '#585b70',
activationBorderColor: '#6c7086',
edgeLabelBackground: '#1e1e2e',
labelBoxBkgColor: '#1e1e2e',
clusterBkg: 'rgba(30, 30, 46, 0.5)',
noteBkgColor: 'rgba(249, 226, 175, 0.12)',
noteBorderColor: '#f9e2af',
noteTextColor: '#cdd6f4',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif",
fontSize: '16px',
} as const;
/** 按主题返回对应 Catppuccin themeVariables。 */
function themeVarsFor(theme: ThemeName): Record<string, unknown> {
return theme === 'dark' ? { ...MOCHA_VARS } : { ...LATTE_VARS };
}
declare global {
interface Window {
MermaidRenderer?: MermaidApi;
@ -234,7 +120,7 @@ async function renderBlock(pre: HTMLPreElement, source: string, theme: ThemeName
useMaxWidth: true,
htmlLabels: true,
},
themeVariables: themeVarsFor(theme),
themeVariables: mermaidThemeVarsFor(theme),
});
const id = `mermaid-svg-${++renderCounter}`;
const { svg } = await mermaid.render(id, source);