Files
BoosAPI/desktop/libs/markstream-vue/design/themes.md
T
boos e0a5f57793 feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
2026-06-22 11:32:57 +08:00

204 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Theming System
> markstream-vue 的主题机制文档:Light/Dark 模式实现、CSS 变量架构、主题切换方式。
---
## 1. 主题架构概览
markstream-vue 采用 **混合主题方案**:
```
Props (isDark) → CSS Class (.is-dark / .dark) → CSS Variables Override → 组件渲染
```
三层机制互为补充:
| 层级 | 机制 | 说明 |
|---|---|---|
| 1. Props | `isDark: boolean` | 由宿主应用传入,最高优先级 |
| 2. CSS Class | `.dark` / `.is-dark` | 添加到根容器或组件上 |
| 3. Media Query | `prefers-color-scheme: dark` | 系统偏好兜底 |
---
## 2. 全局主题变量
### 2.1 挂载方式
```css
/* Light(默认) */
.markstream-vue {
--border: 214.3 31.8% 91.4%;
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--secondary: 210 40% 96%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
}
/* Dark — 两种触发方式 */
.dark .markstream-vue, /* 父级添加 .dark 类 */
.markstream-vue.dark { /* 自身添加 .dark 类 */
--border: 217.2 32.6% 17.5%;
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--secondary: 217.2 32.6% 17.5%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
}
```
### 2.2 使用方式
在组件中通过 `hsl()` 引用:
```css
color: hsl(var(--foreground));
background-color: hsl(var(--secondary));
border: 1px solid hsl(var(--border) / 0.9);
```
Tailwind 配置中也引用这些变量(带回退值):
```js
const fallback = {
foreground: 'hsl(var(--foreground), 217.2 22.08% 19.5%)',
}
```
---
## 3. 组件级暗色模式
### 3.1 Props 传递链
```
NodeRenderer (isDark prop)
└─ 所有子组件 (isDark prop)
└─ :class="{ 'is-dark': props.isDark }"
```
### 3.2 CSS 类切换模式
各组件使用 `.is-dark` 类覆盖 CSS 变量:
```vue
<div class="code-block-container" :class="{ 'is-dark': props.isDark }">
<style scoped>
.code-block-container {
--markstream-code-fallback-bg: #ffffff;
}
.code-block-container.is-dark {
--markstream-code-fallback-bg: #111827;
}
</style>
```
### 3.3 各组件暗色实现方式
| 组件 | 暗色触发 | 方式 |
|---|---|---|
| 全局变量 | `.dark .markstream-vue` | CSS 变量覆盖 |
| CodeBlockNode | `.is-dark` class | ~30+ CSS 变量覆盖 |
| AdmonitionNode | `.is-dark` class | CSS 变量覆盖 + 透明度调整 |
| MermaidBlockNode | `:class` 条件 | Tailwind dark 类名切换 |
| Tooltip | `.is-dark` class | `bg-gray-900 text-white` |
| MathBlockNode | `.is-dark` class | spinner 颜色反转 |
| ImageNode | - | 无暗色适配 |
| HighlightNode | - | **无暗色适配**(固定 `#ffff00`) |
| BlockquoteNode | - | 仅通过全局 `--blockquote-border-color` |
| TableNode | - | 仅通过 `--table-border` |
| ListItemNode | - | 仅通过 `--list-item-marker` 等 |
| FootnoteNode | - | 固定 `#eaecef` 边框色,**无暗色适配** |
---
## 4. Monaco Editor 主题
代码块支持独立的编辑器主题系统:
```ts
interface Props {
darkTheme?: CodeBlockMonacoTheme // 暗色编辑器主题
lightTheme?: CodeBlockMonacoTheme // 亮色编辑器主题
}
// 运行时根据 isDark 切换
const activeTheme = props.isDark ? props.darkTheme : props.lightTheme
```
支持:
- 字符串形式:内置主题名
- 对象形式:`CodeBlockMonacoThemeObject` 自定义主题
VSCode 变量自动映射:
- `--vscode-editor-background`
- `--vscode-editor-foreground`
- `--vscode-editor-selectionBackground`
---
## 5. 媒体查询兜底
部分组件使用系统偏好作为兜底:
```css
@media (prefers-color-scheme: dark) {
.math-loading-spinner {
border-color: rgba(255, 255, 255, 0.1);
border-top-color: rgba(255, 255, 255, 0.6);
}
}
```
JavaScript 检测:
```js
window.matchMedia('(prefers-color-scheme: dark)').matches
```
---
## 6. Tailwind 作用域隔离
所有 Tailwind 工具类限定在 `.markstream-vue` 内生效,避免全局污染:
```js
// tailwind.config.js
important: '.markstream-vue'
```
按钮重置使用 `:where()` 保持低特异性:
```css
:where(.markstream-vue) button {
appearance: none;
background: transparent;
border: 0;
}
```
---
## 7. 双构建输出
| 构建 | 输出文件 | 说明 |
|---|---|---|
| 标准构建 | `dist/index.css` | 包含完整 Tailwind 工具类 |
| Tailwind 构建 | `dist/index.tailwind.css` | 不含 Tailwind,供宿主项目自行引入 |
---
## 8. 当前主题体系的问题
| 问题 | 详情 |
|---|---|
| 暗色覆盖不完整 | HighlightNode、FootnoteNode、ImageNode 等无暗色适配 |
| 变量命名不统一 | 全局用 HSL 裸值,组件用 HEX/RGB/rgba,缺乏统一规范 |
| 暗色触发方式不一致 | 全局用 `.dark`,组件用 `.is-dark`,Mermaid 用条件 class |
| 硬编码颜色散落 | `#e2e8f0`、`#eaecef`、`#cbd5e1` 等直接写在组件中 |
| 语义色彩未统一 | Admonition 语义色与全局体系分离 |
| CSS 变量缺乏 Dark 值 | `--blockquote-border-color`、`--table-border` 等无暗色默认值 |