发布 1.1.0 Monokai Pro 对标优化

This commit is contained in:
Darkings 2026-06-23 12:47:46 +08:00
parent 4bc66db15a
commit f601cd2c4f
30 changed files with 4676 additions and 195 deletions

View file

@ -1,5 +1,26 @@
# 更新日志 / Changelog
## 1.1.02026-06-23
### 新增
- 默认启用 Monokai Pro 滤镜,并新增 Light、Sun 浅色滤镜。
- 增加代码学习 Calloutconcept、syntax、api、debug、pitfall、exercise、answer、source、output、terminal。
- 增加学习目录图标规则、8 种任务状态、API 参数表语义、Mermaid/Math/Dataview 容器样式。
- 扩展 Style Settings 排版控制:行宽、正文字号、代码字号、代码行高、标题缩放、段落间距和标题色条开关。
### 优化
- 扩展 CodeMirror token、代码块 surface、active line、selection、cursor、gutter 与 bracket match。
- 让 Graph、Canvas、Callout 和代码 token 跟随 8 个滤镜的语义色。
- 优化标题导航感、列表嵌套节奏、表格可读性和阅读/编辑模式一致性。
### 验证
- 增加 8 滤镜调色板检查与多场景对比度审计。
- 扩展视觉 QA 基线生成代码学习、Callout、Mermaid/Math/Dataview、Graph 与 Canvas 样例。
- 完整发布验证覆盖版本一致性、图标、Graph、Active 视觉、样式 polish、对比度、构建、CSS 审计和 Vault QA。
## 1.0.22026-06-22
- 系统优化阅读模式与 Live Preview 的视觉一致性,专项验证扩展到 30 项。

View file

@ -6,31 +6,33 @@ Monokai Syntax 是一个面向 Obsidian 的 Monokai Pro 风格主题,重点优
## 版本
当前版本:`1.0.2`
当前版本:`1.1.0`
最低 Obsidian 版本:`1.0.0`
## 主要特性
- Monokai Pro 风格深色与浅色调色板
- Monokai Pro 默认滤镜,并支持 Classic、Machine、Octagon、Ristretto、Spectrum、Light、Sun
- CodeMirror 6 语法高亮映射到 Monokai 六色光谱。
- 阅读模式与 Live Preview 使用共享语义变量收敛视觉差异。
- 文件树图标覆盖常见文档、配置、代码与项目文件。
- 文件树同层级文件夹与 Markdown 文件对齐,根层折叠图标使用轻量尺寸。
- Callout、块引用、任务列表、表格、代码块、链接、标签、脚注、图片与附件嵌入统一样式层级。
- Callout、块引用、任务列表、API 参数表、代码块、链接、标签、脚注、图片与附件嵌入统一样式层级。
- 代码学习语义 Callout 覆盖 concept、syntax、api、debug、pitfall、exercise、answer、source、output、terminal。
- Mermaid、Math、Dataview 复用主题 surface避免插件内容跳出阅读层级。
- 关系图谱、Canvas、Ribbon、标签页、弹窗和搜索界面适配主题色。
- 支持 Style Settings调色板滤镜、紧凑模式、图标模式、字体、强调色、链接色与代码色。
- 构建产物不加载远程运行时资源,图标字体以内联 woff 形式打包。
## 1.0.2 更新重点
## 1.1.0 更新重点
- 系统收敛阅读模式与 Live Preview 的视觉差异,专项验证覆盖 30 项样式一致性检查
- 优化 H1-H6 标题下边距,按标题层级递减
- 修正文件树同层级文件夹与 Markdown 文件的对齐问题
- 调整根层文件夹折叠图标尺寸与线宽,避免视觉过重
- 更新代码 token 颜色,使深色模式更贴近 Monokai Pro
- 增强代码块、表格源码、块引用、Callout、标签、链接、脚注、附件嵌入和扩展任务状态的阅读/编辑一致性
- 增加发布前验证:版本一致性、生成文件一致性、样式 polish、Vault QA 和 CSS 审计
- 默认滤镜切换为 Monokai Pro并补齐 Light、Sun 两个浅色滤镜
- 扩展 CodeMirror token、代码块 surface、active line、selection、cursor、gutter 和 bracket match
- 增加代码学习 Callout、8 种任务状态、学习目录图标和 API 参数表语义
- 优化标题导航感、列表层级、Mermaid、Math、Dataview、Graph 与 Canvas 的主题一致性
- Style Settings 增加排版滑杆和标题色条开关,支持行宽、字号、代码行高、标题缩放与段落间距
- 对 8 个滤镜运行多场景对比度审计,覆盖链接、代码注释、行号、选区文字、代码块边框和 Callout 标题
- 建立视觉 QA 基线自动生成长文、代码学习、Callout、Mermaid/Math/Dataview、Graph 和 Canvas 检查样例
## 安装
@ -72,7 +74,7 @@ manifest.json
当前支持:
- 调色板滤镜Classic、Machine、Octagon、Ristretto、Spectrum。
- 调色板滤镜:Pro、Classic、Machine、Octagon、Ristretto、Spectrum、Light、Sun
- 紧凑模式。
- 彩色或单色文件树图标。
- 文件树图标开关。
@ -105,6 +107,16 @@ npm run verify
npm run build:vault
```
视觉验收流程:
```powershell
npm run qa:create
npm run build:vault
npm run qa:verify
```
该流程会在默认 vault 中生成综合 QA 笔记,覆盖长文阅读、代码学习、学习 Callout、Mermaid、Math、Dataview、Graph 和 Canvas然后验证 vault 已同步并启用 `Monokai Syntax` 主题。
发布前检查:
```powershell
@ -125,8 +137,8 @@ manifest.json
4. 创建并推送版本标签,例如:
```powershell
git tag v1.0.2
git push origin v1.0.2
git tag v1.1.0
git push origin v1.1.0
```
5. GitHub Actions 会在标签推送后运行发布检查并创建 Release附件包含 `theme.css``manifest.json`

1520
dist/theme.css vendored

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "Monokai Syntax",
"version": "1.0.2",
"version": "1.1.0",
"minAppVersion": "1.0.0",
"author": "lat3ncy"
}

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "monokai-syntax",
"version": "1.0.2",
"version": "1.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "monokai-syntax",
"version": "1.0.2",
"version": "1.1.0",
"license": "MIT",
"devDependencies": {
"sass": "^1.99.0",

View file

@ -1,6 +1,6 @@
{
"name": "monokai-syntax",
"version": "1.0.2",
"version": "1.1.0",
"description": "面向 Obsidian 的 Monokai Syntax 主题。",
"author": "lat3ncy",
"license": "MIT",
@ -16,8 +16,9 @@
"lint:css": "stylelint \"src/scss/**/*.scss\"",
"check:contrast": "node scripts/check-contrast.js",
"audit:css": "node scripts/audit-css.js",
"verify": "npm run verify:versions && npm run verify:pip-editor && npm run verify:icons && npm run verify:graph && npm run verify:active-visual && npm run verify:style-polish && npm test && npm run lint:css && npm run check:contrast && npm run build && npm run verify:generated && npm run audit:css",
"verify": "npm run verify:versions && npm run verify:palette && npm run verify:pip-editor && npm run verify:icons && npm run verify:graph && npm run verify:active-visual && npm run verify:style-polish && npm test && npm run lint:css && npm run check:contrast && npm run build && npm run verify:generated && npm run audit:css",
"verify:versions": "node scripts/verify-versions.js",
"verify:palette": "node scripts/verify-palette-filters.js",
"verify:generated": "node scripts/verify-generated.js",
"verify:pip-editor": "node scripts/verify-pip-editor.js",
"verify:icons": "node scripts/verify-icons.js",

View file

@ -1,14 +1,78 @@
import { pathToFileURL } from "node:url";
export const pairs = [
["深色正文", "#f8f8f2", "#272822", 4.5],
["深色链接", "#66d9ef", "#272822", 4.5],
["深色图标", "#c1c1bd", "#1e1f1c", 3],
["深色高亮文本", "#f8f8f2", "#5b542f", 4.5],
["浅色正文", "#3d3d3d", "#fdf9f3", 4.5],
["浅色链接", "#14748a", "#fdf9f3", 4.5],
["浅色图标", "#666666", "#f5f0e6", 3],
["浅色高亮文本", "#3d3d3d", "#f7e7b3", 4.5],
{ filter: "pro", label: "正文", foreground: "#fcfcfa", background: "#2d2a2e", minimum: 4.5 },
{ filter: "pro", label: "链接", foreground: "#78dce8", background: "#2d2a2e", minimum: 4.5 },
{ filter: "pro", label: "图标", foreground: "#c1c0c0", background: "#221f22", minimum: 3 },
{ filter: "pro", label: "高亮文本", foreground: "#fcfcfa", background: "#5f5230", minimum: 4.5 },
{ filter: "pro", label: "代码注释", foreground: "#727072", background: "#221f22", minimum: 3 },
{ filter: "pro", label: "行号", foreground: "#939293", background: "#221f22", minimum: 3 },
{ filter: "pro", label: "选区文字", foreground: "#fcfcfa", background: "#344349", minimum: 4.5 },
{ filter: "pro", label: "代码块边框", foreground: "#403e41", background: "#221f22", minimum: 1.3 },
{ filter: "pro", label: "Callout 标题", foreground: "#78dce8", background: "#2e3e42", minimum: 4.5 },
{ filter: "classic", label: "正文", foreground: "#f8f8f2", background: "#272822", minimum: 4.5 },
{ filter: "classic", label: "链接", foreground: "#66d9ef", background: "#272822", minimum: 4.5 },
{ filter: "classic", label: "图标", foreground: "#c1c1bd", background: "#1e1f1c", minimum: 3 },
{ filter: "classic", label: "高亮文本", foreground: "#f8f8f2", background: "#5b542f", minimum: 4.5 },
{ filter: "classic", label: "代码注释", foreground: "#72736f", background: "#1e1f1c", minimum: 3 },
{ filter: "classic", label: "行号", foreground: "#8f908a", background: "#1e1f1c", minimum: 3 },
{ filter: "classic", label: "选区文字", foreground: "#f8f8f2", background: "#33464a", minimum: 4.5 },
{ filter: "classic", label: "代码块边框", foreground: "#3e3d32", background: "#1e1f1c", minimum: 1.3 },
{ filter: "classic", label: "Callout 标题", foreground: "#66d9ef", background: "#283d40", minimum: 4.5 },
{ filter: "machine", label: "正文", foreground: "#f2ffef", background: "#222421", minimum: 4.5 },
{ filter: "machine", label: "链接", foreground: "#6bf5ff", background: "#222421", minimum: 4.5 },
{ filter: "machine", label: "图标", foreground: "#c2c9bd", background: "#191b19", minimum: 3 },
{ filter: "machine", label: "高亮文本", foreground: "#f2ffef", background: "#5d5228", minimum: 4.5 },
{ filter: "machine", label: "代码注释", foreground: "#747d70", background: "#191b19", minimum: 3 },
{ filter: "machine", label: "行号", foreground: "#8b9387", background: "#191b19", minimum: 3 },
{ filter: "machine", label: "选区文字", foreground: "#f2ffef", background: "#2b4648", minimum: 4.5 },
{ filter: "machine", label: "代码块边框", foreground: "#394037", background: "#191b19", minimum: 1.3 },
{ filter: "machine", label: "Callout 标题", foreground: "#6bf5ff", background: "#244045", minimum: 4.5 },
{ filter: "octagon", label: "正文", foreground: "#fff9fb", background: "#28252f", minimum: 4.5 },
{ filter: "octagon", label: "链接", foreground: "#78dce8", background: "#28252f", minimum: 4.5 },
{ filter: "octagon", label: "图标", foreground: "#cbc3d4", background: "#1f1d26", minimum: 3 },
{ filter: "octagon", label: "高亮文本", foreground: "#fff9fb", background: "#5e5133", minimum: 4.5 },
{ filter: "octagon", label: "代码注释", foreground: "#77707f", background: "#1f1d26", minimum: 3 },
{ filter: "octagon", label: "行号", foreground: "#978da3", background: "#1f1d26", minimum: 3 },
{ filter: "octagon", label: "选区文字", foreground: "#fff9fb", background: "#34434e", minimum: 4.5 },
{ filter: "octagon", label: "代码块边框", foreground: "#443d50", background: "#1f1d26", minimum: 1.3 },
{ filter: "octagon", label: "Callout 标题", foreground: "#78dce8", background: "#2a3d48", minimum: 4.5 },
{ filter: "ristretto", label: "正文", foreground: "#fff8ef", background: "#2b241f", minimum: 4.5 },
{ filter: "ristretto", label: "链接", foreground: "#78dce8", background: "#2b241f", minimum: 4.5 },
{ filter: "ristretto", label: "图标", foreground: "#cfc1b2", background: "#211b18", minimum: 3 },
{ filter: "ristretto", label: "高亮文本", foreground: "#fff8ef", background: "#5f4f2e", minimum: 4.5 },
{ filter: "ristretto", label: "代码注释", foreground: "#7b7066", background: "#211b18", minimum: 3 },
{ filter: "ristretto", label: "行号", foreground: "#998b7d", background: "#211b18", minimum: 3 },
{ filter: "ristretto", label: "选区文字", foreground: "#fff8ef", background: "#344145", minimum: 4.5 },
{ filter: "ristretto", label: "代码块边框", foreground: "#463b32", background: "#211b18", minimum: 1.3 },
{ filter: "ristretto", label: "Callout 标题", foreground: "#78dce8", background: "#2d3b3d", minimum: 4.5 },
{ filter: "spectrum", label: "正文", foreground: "#f7f8ff", background: "#262933", minimum: 4.5 },
{ filter: "spectrum", label: "链接", foreground: "#78dce8", background: "#262933", minimum: 4.5 },
{ filter: "spectrum", label: "图标", foreground: "#c3c8d8", background: "#1c1f28", minimum: 3 },
{ filter: "spectrum", label: "高亮文本", foreground: "#f7f8ff", background: "#5d5233", minimum: 4.5 },
{ filter: "spectrum", label: "代码注释", foreground: "#71788c", background: "#1c1f28", minimum: 3 },
{ filter: "spectrum", label: "行号", foreground: "#8d94a8", background: "#1c1f28", minimum: 3 },
{ filter: "spectrum", label: "选区文字", foreground: "#f7f8ff", background: "#33434f", minimum: 4.5 },
{ filter: "spectrum", label: "代码块边框", foreground: "#3e4454", background: "#1c1f28", minimum: 1.3 },
{ filter: "spectrum", label: "Callout 标题", foreground: "#78dce8", background: "#283d48", minimum: 4.5 },
{ filter: "light", label: "正文", foreground: "#3d3d3d", background: "#fdf9f3", minimum: 4.5 },
{ filter: "light", label: "链接", foreground: "#14748a", background: "#fdf9f3", minimum: 4.5 },
{ filter: "light", label: "图标", foreground: "#666666", background: "#f5f0e6", minimum: 3 },
{ filter: "light", label: "高亮文本", foreground: "#3d3d3d", background: "#f7e7b3", minimum: 4.5 },
{ filter: "light", label: "代码注释", foreground: "#7a7369", background: "#f5f0e6", minimum: 3 },
{ filter: "light", label: "行号", foreground: "#7a7369", background: "#f5f0e6", minimum: 3 },
{ filter: "light", label: "选区文字", foreground: "#3d3d3d", background: "#d8edf0", minimum: 4.5 },
{ filter: "light", label: "代码块边框", foreground: "#d8d0c2", background: "#f5f0e6", minimum: 1.3 },
{ filter: "light", label: "Callout 标题", foreground: "#14748a", background: "#eef6f5", minimum: 4.5 },
{ filter: "sun", label: "正文", foreground: "#3a3426", background: "#fbf3db", minimum: 4.5 },
{ filter: "sun", label: "链接", foreground: "#1f7184", background: "#fbf3db", minimum: 4.5 },
{ filter: "sun", label: "图标", foreground: "#675f4a", background: "#f4e8c4", minimum: 3 },
{ filter: "sun", label: "高亮文本", foreground: "#3a3426", background: "#eed99f", minimum: 4.5 },
{ filter: "sun", label: "代码注释", foreground: "#847a60", background: "#f4e8c4", minimum: 3 },
{ filter: "sun", label: "行号", foreground: "#847a60", background: "#f4e8c4", minimum: 3 },
{ filter: "sun", label: "选区文字", foreground: "#3a3426", background: "#d6e6e7", minimum: 4.5 },
{ filter: "sun", label: "代码块边框", foreground: "#d7c89e", background: "#f4e8c4", minimum: 1.3 },
{ filter: "sun", label: "Callout 标题", foreground: "#1f7184", background: "#edf2d5", minimum: 4.5 },
];
export function toRgb(hex) {
@ -41,10 +105,11 @@ export function contrast(foreground, background) {
}
export function checkContrastPairs(contrastPairs = pairs) {
return contrastPairs.map(([label, foreground, background, minimum]) => {
return contrastPairs.map(({ filter, label, foreground, background, minimum }) => {
const ratio = contrast(foreground, background);
return {
filter,
label,
foreground,
background,
@ -61,7 +126,7 @@ function runCli() {
for (const result of results) {
const formattedRatio = result.ratio.toFixed(2);
console.log(`${result.label}: ${formattedRatio}:1要求 >= ${result.minimum}:1`);
console.log(`${result.filter} ${result.label}: ${formattedRatio}:1要求 >= ${result.minimum}:1`);
if (!result.passed) {
hasFailure = true;

View file

@ -27,11 +27,21 @@ priority: high
> 这是一段块引用它应当保留正文可读性同时使用绿色左边框形成清晰边界
- 一级项目
- 二级项目
- 三级项目
- [ ] 未完成任务
- 学习路线
- Day01 图像基础
- API 文档
- 复现示例代码
- Day02 批处理增强
- 记录参数变化
- 总结错误模式
- [ ] 普通任务
- [x] 已完成任务
- [>] 下一步任务
- [-] 取消任务
- [?] 问题任务
- [!] 重点任务
- [/]
- [*] 星标任务
| 项目 | 颜色语义 | 预期 |
| --- | --- | --- |
@ -39,6 +49,34 @@ priority: high
| 引用 | 绿色 | 稳定但不抢眼 |
| 代码 | 深色块 | 像编辑器中的编辑器 |
### API 参数表
| 参数 | 类型 | 默认值 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| \`src\` | \`string\` | \`""\` | **是** | 输入图像路径 |
| \`threshold\` | \`number\` | \`0.5\` | 否 | 边缘检测阈值 |
| \`mode\` | \`"fast" \\| "accurate"\` | \`"fast"\` | 否 | 推理模式 |
### Mermaid / Math / Dataview
\`\`\`mermaid
graph TD
A[读取图像] --> B[预处理]
B --> C{是否需要增强}
C -->|| D[批处理增强]
C -->|| E[输出结果]
\`\`\`
$$
E = mc^2
$$
\`\`\`dataview
TABLE status, priority
FROM #theme-qa
SORT priority DESC
\`\`\`
\`\`\`js
const palette = {
magenta: "#f92672",
@ -79,6 +117,103 @@ Obsidian 的知识管理场景不同于代码编辑器。这里的主要对象
浅色模式尤其需要注意对比度原规划中的浅色蓝色经过对比度检查后调整为更深的青蓝色以保证在暖白背景上达到正文级链接可读性
`;
const codeLearning = `# QA 代码学习样例
这篇笔记用于检查代码学习场景中的任务状态三层嵌套列表API 参数表代码块和 CodeMirror token
## 学习步骤
- OpenCV 学习路径
- Day01 图像读取
- 记录 \`cv2.imread\` 的返回值
- 对比 RGB BGR
- Day02 图像增强
- 调整阈值参数
- 记录失败样例
- [ ] 普通任务
- [x] 已完成任务
- [>] 下一步任务
- [-] 取消任务
- [?] 问题任务
- [!] 重点任务
- [/]
- [*] 星标任务
## API 参数表
| 参数 | 类型 | 默认值 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| \`src\` | \`string\` | \`""\` | **是** | 输入图像路径 |
| \`threshold\` | \`number\` | \`0.5\` | 否 | 边缘检测阈值 |
| \`mode\` | \`"fast" \\| "accurate"\` | \`"fast"\` | 否 | 推理模式 |
\`\`\`python
from pathlib import Path
def load_image(src: str, threshold: float = 0.5) -> dict[str, float]:
path = Path(src)
if not path.exists():
raise FileNotFoundError(src)
return {"threshold": threshold, "area": 42.0}
\`\`\`
`;
const learningCallouts = `# QA Callout 学习语义
> [!concept] 概念
> 用于记录核心概念术语和心智模型
> [!syntax] 语法
> 用于记录语言结构函数签名和调用方式
> [!api] API
> 用于记录参数返回值和错误边界
> [!debug] Debug
> 用于记录调试路径和定位过程
> [!pitfall] 易错点
> 用于记录常见误区和反例
> [!exercise] 练习
> 用于记录待完成的编码训练
> [!answer] 答案
> 用于记录练习解法和解释
> [!source] Source
> 用于记录源码阅读摘记
> [!output] Output
> 用于记录运行结果和日志摘要
> [!terminal] Terminal
> 用于记录命令行输入输出
`;
const mermaidMathDataview = `# QA Mermaid Math Dataview
\`\`\`mermaid
graph TD
A[读取图像] --> B[预处理]
B --> C{是否增强}
C -->|| D[批处理]
C -->|| E[输出]
\`\`\`
$$
E = mc^2
$$
\`\`\`dataview
TABLE status, priority
FROM #theme-qa
SORT priority DESC
\`\`\`
`;
const graphNode = `# QA 关系图谱节点
这篇笔记用于在 Graph View 中产生链接节点
@ -156,6 +291,9 @@ const canvas = {
writeFileSync(resolve(qaDir, "Monokai Syntax QA 总览.md"), overview);
writeFileSync(resolve(qaDir, "QA 长文阅读样例.md"), longReading);
writeFileSync(resolve(qaDir, "QA 代码学习样例.md"), codeLearning);
writeFileSync(resolve(qaDir, "QA Callout 学习语义.md"), learningCallouts);
writeFileSync(resolve(qaDir, "QA Mermaid Math Dataview.md"), mermaidMathDataview);
writeFileSync(resolve(qaDir, "QA 关系图谱节点.md"), graphNode);
writeFileSync(resolve(qaDir, "QA Canvas 检查.md"), canvasNote);
writeFileSync(resolve(qaDir, "Monokai Syntax QA.canvas"), JSON.stringify(canvas, null, 2));

View file

@ -45,6 +45,11 @@ function colorForIcon(fontClass) {
agent: "#ab9df2",
api: "#78dce8",
bug: "#ff6188",
"callout-abstract": "#ab9df2",
"callout-example": "#fc9867",
"callout-info": "#78dce8",
"callout-note": "#78dce8",
"callout-todo": "#ffd866",
changelog: "#fc9867",
cursor: "#66d9ef",
prompts: "#e6db74",
@ -64,10 +69,34 @@ function normalizeFileNameSelector(fileName) {
];
}
function normalizeDirectoryNameSelector(directoryName) {
const escaped = cssAttribute(directoryName);
return [
`.nav-folder-title[data-path="${escaped}"]`,
`.nav-folder-title[data-path$="/${escaped}"]`,
`.nav-folder[data-path="${escaped}"] > .nav-folder-title`,
`.nav-folder[data-path$="/${escaped}"] > .nav-folder-title`,
];
}
function normalizeDirectoryPrefixSelector(directoryPrefix) {
const escaped = cssAttribute(directoryPrefix);
return [
`.nav-folder-title[data-path^="${escaped}"]`,
`.nav-folder-title[data-path*="/${escaped}"]`,
`.nav-folder[data-path^="${escaped}"] > .nav-folder-title`,
`.nav-folder[data-path*="/${escaped}"] > .nav-folder-title`,
];
}
function iconRule(selectors, definition) {
return `${selectors.join(",\n")} {\n --monokai-file-icon-color: ${definition.fontColor};\n content: "${cssContent(definition.fontCharacter)}";\n}\n`;
}
function directoryIconRule(selectors, definition) {
return `${selectors.join(",\n")} {\n --monokai-folder-icon-content: "${cssContent(definition.fontCharacter)}";\n --monokai-folder-icon-color: ${definition.fontColor};\n}\n`;
}
function sortedEntries(record) {
return Object.entries(record ?? {}).sort(([left], [right]) =>
left.localeCompare(right, "en", { sensitivity: "variant" }),
@ -154,6 +183,21 @@ const obsidianFileNames = {
"TODO.md": "todo",
"todo.md": "todo",
};
const obsidianDirectoryNames = {
assets: "image-accent3",
concepts: "callout-abstract",
examples: "callout-example",
exercises: "todo",
labs: "test-accent5",
leetcode: "api",
notes: "readme",
src: "source-accent3",
tests: "test-accent5",
};
const obsidianDirectoryPrefixes = {
Day: "markdown-accent4",
day: "markdown-accent4",
};
const lines = [
"/* stylelint-disable */",
@ -207,6 +251,16 @@ for (const [fileName, iconId] of sortedEntries(obsidianFileNames)) {
lines.push(iconRule(normalizeFileNameSelector(fileName), definition));
}
for (const [directoryName, iconId] of sortedEntries(obsidianDirectoryNames)) {
const definition = iconByClass(theme, iconId);
lines.push(directoryIconRule(normalizeDirectoryNameSelector(directoryName), definition));
}
for (const [directoryPrefix, iconId] of sortedEntries(obsidianDirectoryPrefixes)) {
const definition = iconByClass(theme, iconId);
lines.push(directoryIconRule(normalizeDirectoryPrefixSelector(directoryPrefix), definition));
}
lines.push(iconRule([
'.nav-file-title[data-path^="Bug_"][data-path$=".md"]::before',
'.nav-file-title[data-path*="/Bug_"][data-path$=".md"]::before',

View file

@ -8,8 +8,10 @@ const checks = [
["图谱颜色支持过渡", /\.graph-view[\s\S]*?transition:[\s\S]*?color 140ms ease/],
["图谱背景支持过渡", /\.graph-view[\s\S]*?background-color 180ms ease/],
["图谱使用 Monokai Pro 背景变量", /\.graph-view[\s\S]*?background-color:\s*var\(--monokai-graph-background\)/],
["深色图谱背景对齐导航栏与标题栏", /\.theme-dark \.graph-view[\s\S]*?--monokai-graph-background:\s*#1e1f1c/],
["浅色图谱背景对齐导航栏与标题栏", /\.theme-light \.graph-view[\s\S]*?--monokai-graph-background:\s*#f5f0e6/],
["图谱背景默认继承当前滤镜侧栏背景", /\.graph-view[\s\S]*?--monokai-graph-background:\s*var\(--background-secondary\)/],
["图谱高亮节点跟随滤镜红色光谱", /\.graph-view[\s\S]*?--monokai-graph-focused:\s*var\(--monokai-spectrum-red, var\(--interactive-accent\)\)/],
["图谱标签节点跟随滤镜紫色光谱", /\.graph-view[\s\S]*?--monokai-graph-node-tag:\s*var\(--monokai-spectrum-purple, var\(--h6-color\)\)/],
["图谱附件节点跟随滤镜绿色光谱", /\.graph-view[\s\S]*?--monokai-graph-node-attachment:\s*var\(--monokai-spectrum-green, var\(--h4-color\)\)/],
["图谱控制区使用 Monokai 面板变量", /\.graph-controls[\s\S]*?background-color:\s*var\(--monokai-graph-panel\)/],
["图谱高亮节点无光晕", (scss) => !/drop-shadow\(/.test(scss)],
["图谱容器无呼吸光晕伪元素", (scss) => !/\.workspace-leaf-content\[data-type="graph"\] \.view-content::before/.test(scss)],

View file

@ -43,7 +43,30 @@ const checks = [
["CLAUDE.md/claude.md 文件名规则", /\[data-path\$="\/CLAUDE\.md"\]::before/.test(files.generated) && /\[data-path\$="\/claude\.md"\]::before/.test(files.generated)],
["AGENTS.md/agents.md 文件名规则", /\[data-path\$="\/AGENTS\.md"\]::before/.test(files.generated) && /\[data-path\$="\/agents\.md"\]::before/.test(files.generated)],
["Bug_ 开头文档规则", /\[data-path\*="\/Bug_"\]\[data-path\$="\.md"\]::before/.test(files.generated)],
["第二层文件夹使用 folder-dimmed2 折叠图标", /\.nav-folder-children\s+\.nav-folder-children\s+\.nav-folder-title\s+\.collapse-icon[\s\S]*content:\s*"\\e64d";/.test(files.wrapper)],
["第二层文件夹使用 folder-dimmed2 折叠图标作为默认回退", /\.nav-folder-children\s+\.nav-folder-children\s+\.nav-folder-title\s+\.collapse-icon[\s\S]*content:\s*var\(--monokai-folder-icon-content,\s*"\\e64d"\);/.test(files.wrapper)],
[
"学习目录图标规则由生成器输出为文件夹语义变量",
[
"concepts",
"labs",
"examples",
"exercises",
"leetcode",
"notes",
"assets",
"src",
"tests",
].every((name) => new RegExp(`\\.nav-folder-title\\[data-path="${name}"\\],[\\s\\S]*?\\.nav-folder-title\\[data-path\\$="/${name}"\\][\\s\\S]*?--monokai-folder-icon-content:[\\s\\S]*?--monokai-folder-icon-color:`).test(files.generated))
&& /\.nav-folder-title\[data-path\^="day"\],[\s\S]*?\.nav-folder-title\[data-path\*="\/day"\][\s\S]*?--monokai-folder-icon-content:[\s\S]*?--monokai-folder-icon-color:/.test(files.generated)
&& /\.nav-folder-title\[data-path\^="Day"\],[\s\S]*?\.nav-folder-title\[data-path\*="\/Day"\][\s\S]*?--monokai-folder-icon-content:[\s\S]*?--monokai-folder-icon-color:/.test(files.generated),
],
[
"学习目录图标复用折叠槽变量且不新增文件夹标题伪元素",
/content:\s*var\(--monokai-folder-icon-content,\s*"\\e64d"\);/.test(files.wrapper)
&& /color:\s*var\(--monokai-folder-icon-color,\s*var\(--icon-color\)\);/.test(files.wrapper)
&& !/\.nav-folder-title-content::before/.test(files.wrapper)
&& !/\.nav-folder-title::before/.test(files.wrapper),
],
["兼容 Obsidian 折叠图标类名", /\.nav-folder-collapse-indicator/.test(files.wrapper) && /\.collapse-icon/.test(files.wrapper)],
["第一层文件夹保留 Obsidian 原生折叠图标", !/\.nav-folder\.mod-root\s*>\s*\.nav-folder-children\s*>\s*\.nav-folder\s*>\s*\.nav-folder-title\s+\.nav-folder-collapse-indicator[\s\S]*content:\s*"\\e64d";/.test(files.wrapper)],
["Style Settings 可关闭文档树图标", /monokai-syntax-hide-file-tree-icons/.test(files.styleSettings) && /body\.monokai-syntax-hide-file-tree-icons/.test(files.wrapper)],

View file

@ -0,0 +1,182 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { pathToFileURL } from "node:url";
const rootDir = resolve(import.meta.dirname, "..");
const styleSettingsScssPath = resolve(rootDir, "src/scss/plugins/_style-settings.scss");
const paletteSettingsPath = resolve(rootDir, "src/css/style-settings/10-palette.css.md");
const baseScssPath = resolve(rootDir, "src/scss/_base.scss");
export const paletteFilters = [
"pro",
"classic",
"machine",
"octagon",
"ristretto",
"spectrum",
"light",
"sun",
];
const requiredVariables = [
"--background-primary",
"--background-secondary",
"--background-secondary-alt",
"--text-normal",
"--text-muted",
"--text-faint",
"--background-modifier-border",
"--text-accent",
"--interactive-accent",
"--link-color",
"--link-external-color",
"--h1-color",
"--h2-color",
"--h3-color",
"--h4-color",
"--h5-color",
"--h6-color",
"--code-background",
"--code-comment",
"--code-function",
"--code-important",
"--code-keyword",
"--code-operator",
"--code-property",
"--code-punctuation",
"--code-string",
"--code-tag",
"--code-value",
"--code-type",
"--code-class",
"--code-builtin",
"--code-constant",
"--code-namespace",
"--code-decorator",
"--code-regex",
"--code-meta",
"--code-error",
"--monokai-spectrum-red",
"--monokai-spectrum-orange",
"--monokai-spectrum-yellow",
"--monokai-spectrum-green",
"--monokai-spectrum-cyan",
"--monokai-spectrum-purple",
"--monokai-callout-note-bg",
"--monokai-callout-note-border",
"--monokai-callout-warning-bg",
"--monokai-callout-warning-border",
"--monokai-callout-error-bg",
"--monokai-callout-error-border",
"--monokai-callout-success-bg",
"--monokai-callout-success-border",
"--monokai-graph-background",
"--monokai-graph-panel",
"--monokai-graph-line",
"--monokai-graph-focused",
"--monokai-graph-node-tag",
"--monokai-graph-node-attachment",
"--canvas-color-1",
"--canvas-color-2",
"--canvas-color-3",
"--canvas-color-4",
"--canvas-color-5",
"--canvas-color-6",
"--monokai-filter-name",
];
function readProjectFiles() {
return {
baseScss: readFileSync(baseScssPath, "utf8"),
paletteSettings: readFileSync(paletteSettingsPath, "utf8"),
styleSettingsScss: readFileSync(styleSettingsScssPath, "utf8"),
};
}
function findFilterBlock(scss, filterName) {
const className = `monokai-syntax-filter-${filterName}`;
const pattern = new RegExp(`body\\.${className}\\s*\\{([\\s\\S]*?)\\n\\}`, "m");
return pattern.exec(scss)?.[1] ?? "";
}
function findFilterMixinBlock(scss) {
const pattern = /@mixin monokai-filter\([\s\S]*?\)\s*\{([\s\S]*?)\n\}/m;
return pattern.exec(scss)?.[1] ?? "";
}
export function inspectPaletteFilters(files = readProjectFiles()) {
const failures = [];
const filterMixinBlock = findFilterMixinBlock(files.styleSettingsScss);
if (!filterMixinBlock) {
failures.push("_style-settings.scss 缺少 monokai-filter mixin");
}
for (const filterName of paletteFilters) {
const className = `monokai-syntax-filter-${filterName}`;
const block = findFilterBlock(files.styleSettingsScss, filterName);
if (!files.paletteSettings.includes(`value: ${className}`)) {
failures.push(`Style Settings 缺少滤镜选项:${className}`);
}
if (!block) {
failures.push(`SCSS 缺少滤镜 class${className}`);
continue;
}
for (const variableName of requiredVariables) {
const variablePattern = new RegExp(`${variableName}\\s*:`);
if (!variablePattern.test(block) && !variablePattern.test(filterMixinBlock)) {
failures.push(`${className} 缺少变量:${variableName}`);
}
}
if (!/@include monokai-filter\(/.test(block)) {
failures.push(`${className} 未使用 monokai-filter mixin`);
}
}
if (!/default:\s*monokai-syntax-filter-pro/.test(files.paletteSettings)) {
failures.push("Style Settings 默认滤镜不是 Pro");
}
if (!/\.theme-dark[\s\S]*?--code-keyword:/.test(files.baseScss)) {
failures.push("_base.scss 缺少深色代码 token 基线");
}
if (!/\.theme-light[\s\S]*?--code-keyword:/.test(files.baseScss)) {
failures.push("_base.scss 缺少浅色代码 token 基线");
}
return {
failures,
filters: paletteFilters,
};
}
function runCli() {
const result = inspectPaletteFilters();
for (const filterName of result.filters) {
const className = `monokai-syntax-filter-${filterName}`;
const filterFailures = result.failures.filter((failure) => failure.includes(className));
console.log(`${className}: ${filterFailures.length === 0 ? "通过" : "失败"}`);
}
for (const failure of result.failures) {
console.error(failure);
}
if (result.failures.length > 0) {
process.exitCode = 1;
}
}
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
runCli();
}

View file

@ -33,7 +33,7 @@ const checks = [
["Callout 面板使用语义背景变量", /\.callout[\s\S]*?background-color:\s*var\(--callout-background, transparent\);/],
["表格边框使用增强变量", /(?:\.markdown-rendered[\s\S]*?table|\.markdown-rendered[\s\S]*?th,[\s\S]*?\.markdown-rendered[\s\S]*?td)[\s\S]*?border:\s*1px solid var\(--monokai-table-border\);/],
["已完成任务保持可见", /\.markdown-rendered[\s\S]*?\.task-list-item\.is-checked[\s\S]*?color:\s*var\(--monokai-task-done-color\);/],
["未使用 !important", /^((?!important).)*$/s],
["未使用 !important", !/!important/i.test(`${editorScss}\n${activeVisualScss}`)],
];
let hasFailure = false;

View file

@ -7,6 +7,9 @@ import { resolveQaPaths, resolveVaultRoot } from "./qa-paths.js";
const qaFiles = [
"Monokai Syntax QA 总览.md",
"QA 长文阅读样例.md",
"QA 代码学习样例.md",
"QA Callout 学习语义.md",
"QA Mermaid Math Dataview.md",
"QA 关系图谱节点.md",
"QA Canvas 检查.md",
"Monokai Syntax QA.canvas",
@ -19,15 +22,23 @@ const requiredPatterns = [
["关系图谱样式", /\.graph-view/],
["Canvas 样式", /\.canvas-wrapper/],
["Style Settings 元数据", /@settings/],
["Pro 滤镜", /monokai-syntax-filter-pro/],
["Classic 滤镜", /monokai-syntax-filter-classic/],
["Machine 滤镜", /monokai-syntax-filter-machine/],
["Octagon 滤镜", /monokai-syntax-filter-octagon/],
["Ristretto 滤镜", /monokai-syntax-filter-ristretto/],
["Spectrum 滤镜", /monokai-syntax-filter-spectrum/],
["Light 滤镜", /monokai-syntax-filter-light/],
["Sun 滤镜", /monokai-syntax-filter-sun/],
["紧凑模式", /monokai-syntax-compact/],
["单色图标模式", /monokai-syntax-monochrome-icons/],
["行宽变量", /monokai-readable-line-width/],
["强调色变量", /monokai-accent-color/],
["学习 Calloutconcept", /\.callout\[data-callout=concept\]/],
["学习 Calloutterminal", /\.callout\[data-callout=terminal\]/],
["Mermaid selector", /\.mermaid/],
["Math selector", /\.math/],
["Dataview selector", /\.block-language-dataview|\.dataview/],
];
function readJsonResult(path, label) {
@ -70,6 +81,23 @@ export function verifyQaVault(vaultRoot) {
addCheck(checks, label, pattern.test(themeCss));
}
const overviewPath = resolve(paths.qaDir, "Monokai Syntax QA 总览.md");
const overview = existsSync(overviewPath) ? readFileSync(overviewPath, "utf8") : "";
addCheck(checks, "QA 包含 Mermaid 示例", /```mermaid[\s\S]*?graph TD/.test(overview));
addCheck(checks, "QA 包含 Math 示例", /\$\$[\s\S]*?E = mc\^2[\s\S]*?\$\$/.test(overview));
addCheck(checks, "QA 包含 Dataview 示例", /```dataview[\s\S]*?TABLE/.test(overview));
const codeLearning = existsSync(resolve(paths.qaDir, "QA 代码学习样例.md"))
? readFileSync(resolve(paths.qaDir, "QA 代码学习样例.md"), "utf8")
: "";
addCheck(checks, "QA 代码学习样例包含 API 参数表", /\| 参数 \| 类型 \| 默认值 \| 必填 \| 说明 \|/.test(codeLearning));
addCheck(checks, "QA 代码学习样例包含 8 种任务状态", /\[!\] 重点任务[\s\S]*?\[\/\] 进行中任务[\s\S]*?\[\*\] 星标任务/.test(codeLearning));
const learningCallouts = existsSync(resolve(paths.qaDir, "QA Callout 学习语义.md"))
? readFileSync(resolve(paths.qaDir, "QA Callout 学习语义.md"), "utf8")
: "";
addCheck(checks, "QA Callout 学习语义包含 concept 与 terminal", /\[!concept\][\s\S]*?\[!terminal\]/.test(learningCallouts));
const canvas = readJsonResult(resolve(paths.qaDir, "Monokai Syntax QA.canvas"), "Monokai Syntax QA.canvas");
addCheck(checks, canvas.error ?? "Canvas JSON 可读取", canvas.ok);
addCheck(checks, "Canvas 包含节点", canvas.ok && Array.isArray(canvas.value.nodes) && canvas.value.nodes.length >= 3);

View file

@ -28,6 +28,41 @@ const checks = [
&& /\.HyperMD-header-1[\s\S]*?padding-block-end:\s*var\(--monokai-heading-gap-h1\);/.test(files.editor)
&& /\.HyperMD-header-6[\s\S]*?padding-block-end:\s*var\(--monokai-heading-gap-h6\);/.test(files.editor),
],
[
"标题导航增强具备可选色条、分组间距和锚点颜色",
/--monokai-heading-accent-width:\s*3px;/.test(files.editor)
&& /--monokai-heading-group-spacing:\s*var\(--monokai-heading-group-spacing-value, 1\.4rem\);/.test(files.editor)
&& /--monokai-heading-anchor-color:\s*var\(--text-faint\);/.test(files.editor)
&& /body\.monokai-syntax-heading-accents/.test(files.styleSettings)
&& /monokai-syntax-heading-accents/.test(readFileSync(resolve(rootDir, "src/css/style-settings/40-typography.css.md"), "utf8"))
&& /body\.monokai-syntax-heading-accents[\s\S]*?\.markdown-rendered h1::before,[\s\S]*?\.markdown-rendered h2::before,[\s\S]*?\.markdown-rendered h3::before[\s\S]*?width:\s*var\(--monokai-heading-accent-width\);/.test(files.styleSettings)
&& /\.markdown-rendered[\s\S]*?h2\s*\{[\s\S]*?margin-block:\s*var\(--monokai-heading-group-spacing\) var\(--monokai-heading-gap-h2\);/.test(files.editor)
&& /\.markdown-source-view\.mod-cm6[\s\S]*?\.HyperMD-header-2[\s\S]*?padding-block:\s*calc\(var\(--monokai-heading-group-spacing\) \/ 3\) var\(--monokai-heading-gap-h2\);/.test(files.editor)
&& /\.heading-collapse-indicator,[\s\S]*?\.heading-anchor[\s\S]*?color:\s*var\(--monokai-heading-anchor-color\);/.test(files.editor),
],
[
"Style Settings 排版滑杆完整映射到 Obsidian 与标题变量",
[
"monokai-readable-line-width",
"monokai-body-font-size",
"monokai-code-font-size",
"monokai-code-line-height",
"monokai-heading-scale",
"monokai-paragraph-spacing-value",
].every((settingId) => readFileSync(resolve(rootDir, "src/css/style-settings/40-typography.css.md"), "utf8").includes(settingId))
&& /--file-line-width:\s*var\(--monokai-readable-line-width, 48rem\);/.test(files.styleSettings)
&& /--font-text-size:\s*var\(--monokai-body-font-size, 16px\);/.test(files.styleSettings)
&& /--code-size:\s*var\(--monokai-code-font-size, 0\.9em\);/.test(files.styleSettings)
&& /--monokai-codeblock-line-height:\s*var\(--monokai-code-line-height, 1\.55\);/.test(files.styleSettings)
&& /--monokai-heading-size-scale:\s*var\(--monokai-heading-scale, 1\);/.test(files.styleSettings)
&& /--monokai-paragraph-spacing:\s*var\(--monokai-paragraph-spacing-value, 0\.75rem\);/.test(files.styleSettings)
&& /--h1-size:\s*calc\(1\.802em \* var\(--monokai-heading-size-scale\)\);/.test(files.styleSettings)
&& /--h6-size:\s*calc\(0\.889em \* var\(--monokai-heading-size-scale\)\);/.test(files.styleSettings)
&& /\.markdown-rendered[\s\S]*?h1\s*\{[\s\S]*?font-size:\s*var\(--h1-size\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?h6\s*\{[\s\S]*?font-size:\s*var\(--h6-size\);/.test(files.editor)
&& /\.cm-header-1[\s\S]*?font-size:\s*var\(--h1-size\);/.test(files.editor)
&& /\.cm-header-6[\s\S]*?font-size:\s*var\(--h6-size\);/.test(files.editor),
],
[
"块引用阅读模式与编辑模式共享内容间距变量",
/--monokai-blockquote-content-gap:\s*1\.25rem;/.test(files.activeVisual)
@ -77,6 +112,34 @@ const checks = [
&& /--monokai-table-header-background:\s*rgb\(61 61 61 \/ 6%\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?th\s*\{(?=[\s\S]*?color:\s*var\(--text-normal\);)(?=[\s\S]*?background-color:\s*var\(--monokai-table-header-background\);)[\s\S]*?\}/.test(files.editor),
],
[
"API 参数表具备名称、类型、默认值和必填语义变量",
/--monokai-table-api-name-color:\s*var\(--link-color\);/.test(files.editor)
&& /--monokai-table-api-type-color:\s*var\(--code-type\);/.test(files.editor)
&& /--monokai-table-api-default-color:\s*var\(--code-value\);/.test(files.editor)
&& /--monokai-table-api-required-color:\s*var\(--text-accent\);/.test(files.editor)
&& /--monokai-table-cell-padding:\s*0\.55rem 0\.7rem;/.test(files.editor)
&& /--monokai-table-row-hover-background:\s*var\(--background-modifier-hover\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?table\s*\{[\s\S]*?width:\s*100%;[\s\S]*?border-collapse:\s*separate;/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?th,[\s\S]*?td\s*\{[\s\S]*?padding:\s*var\(--monokai-table-cell-padding\);[\s\S]*?vertical-align:\s*top;/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?tbody tr:hover[\s\S]*?background-color:\s*var\(--monokai-table-row-hover-background\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?td:first-child[\s\S]*?color:\s*var\(--monokai-table-api-name-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?td:nth-child\(2\) code[\s\S]*?color:\s*var\(--monokai-table-api-type-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?td:nth-child\(3\) code[\s\S]*?color:\s*var\(--monokai-table-api-default-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?td:nth-child\(4\) strong[\s\S]*?color:\s*var\(--monokai-table-api-required-color\);/.test(files.editor),
],
[
"Mermaid、Math 与 Dataview 容器复用主题 surface",
/--monokai-plugin-surface-background:\s*var\(--background-secondary\);/.test(files.editor)
&& /--monokai-plugin-surface-border:\s*var\(--background-modifier-border\);/.test(files.editor)
&& /--monokai-plugin-surface-padding:\s*#\{\$spacing-4\};/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.mermaid\s*\{[\s\S]*?background-color:\s*var\(--monokai-plugin-surface-background\);[\s\S]*?border:\s*1px solid var\(--monokai-plugin-surface-border\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.math,[\s\S]*?\.math-block\s*\{[\s\S]*?overflow-x:\s*auto;[\s\S]*?background-color:\s*var\(--monokai-plugin-surface-background\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.math-inline[\s\S]*?color:\s*var\(--monokai-inline-code-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.block-language-dataview,[\s\S]*?\.dataview\s*\{[\s\S]*?background-color:\s*var\(--monokai-plugin-surface-background\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.dataview table[\s\S]*?width:\s*100%;/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.dataview\.task-list-item,[\s\S]*?\.dataview \.task-list-item[\s\S]*?color:\s*var\(--monokai-task-open-color\);/.test(files.editor),
],
[
"深色代码 token 使用 Monokai Pro palette",
/\.theme-dark[\s\S]*?--code-keyword:\s*#\{\$color-dark-red-soft\};/.test(files.base)
@ -86,11 +149,31 @@ const checks = [
&& /\.theme-dark[\s\S]*?--code-property:\s*#\{\$color-dark-cyan-soft\};/.test(files.base)
&& /\.theme-dark[\s\S]*?--code-value:\s*#\{\$color-dark-purple-soft\};/.test(files.base),
],
[
"CodeMirror 扩展语法 token 覆盖类型、类、内建、属性、meta 与错误",
/\.theme-dark[\s\S]*?--code-type:/.test(files.base)
&& /\.theme-light[\s\S]*?--code-type:/.test(files.base)
&& /\.cm-s-obsidian[\s\S]*?span\.cm-type,[\s\S]*?span\.cm-class[\s\S]*?color:\s*var\(--code-type\);/.test(files.editor)
&& /\.cm-s-obsidian[\s\S]*?span\.cm-builtin[\s\S]*?color:\s*var\(--code-builtin\);/.test(files.editor)
&& /\.cm-s-obsidian[\s\S]*?span\.cm-attribute[\s\S]*?color:\s*var\(--code-property\);/.test(files.editor)
&& /\.cm-s-obsidian[\s\S]*?span\.cm-meta[\s\S]*?color:\s*var\(--code-meta\);/.test(files.editor)
&& /\.cm-s-obsidian[\s\S]*?span\.cm-error[\s\S]*?color:\s*var\(--code-error\);/.test(files.editor),
],
[
"列表符号阅读模式与编辑模式共享颜色变量",
/\.markdown-rendered[\s\S]*?ul > li::marker,[\s\S]*?ol > li::marker[\s\S]*?color:\s*var\(--list-marker-color\);/.test(files.editor)
&& /\.cm-formatting-list[\s\S]*?color:\s*var\(--list-marker-color\);/.test(files.editor),
],
[
"嵌套列表具备学习笔记所需的缩进与段落节奏变量",
/--monokai-list-indent:\s*1\.5em;/.test(files.editor)
&& /--monokai-list-item-spacing:\s*0\.35rem;/.test(files.editor)
&& /--monokai-nested-list-spacing:\s*0\.25rem;/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?ul,[\s\S]*?ol\s*\{[\s\S]*?padding-inline-start:\s*var\(--monokai-list-indent\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?li\s*\{[\s\S]*?margin-block:\s*var\(--monokai-list-item-spacing\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?li > ul,[\s\S]*?li > ol\s*\{[\s\S]*?margin-block:\s*var\(--monokai-nested-list-spacing\) 0;/.test(files.editor)
&& /\.cm-formatting-list[\s\S]*?color:\s*var\(--list-marker-color\);/.test(files.editor),
],
[
"已完成任务阅读模式与编辑模式共享弱化文本变量",
/\.markdown-rendered[\s\S]*?\.task-list-item\.is-checked[\s\S]*?color:\s*var\(--monokai-task-done-color\);/.test(files.editor)
@ -166,7 +249,7 @@ const checks = [
[
"段落阅读模式与编辑模式共享行高和段落节奏变量",
/--monokai-paragraph-line-height:\s*var\(--line-height-normal\);/.test(files.editor)
&& /--monokai-paragraph-spacing:\s*#\{\$spacing-3\};/.test(files.editor)
&& /--monokai-paragraph-spacing:\s*var\(--monokai-paragraph-spacing-value, #\{\$spacing-3\}\);/.test(files.editor)
&& /--p-spacing:\s*var\(--monokai-paragraph-spacing\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?p\s*\{[\s\S]*?line-height:\s*var\(--monokai-paragraph-line-height\);[\s\S]*?margin-block:\s*0 var\(--monokai-paragraph-spacing\);/.test(files.editor)
&& /\.markdown-source-view\.mod-cm6[\s\S]*?\.cm-line\s*\{[\s\S]*?line-height:\s*var\(--monokai-paragraph-line-height\);/.test(files.editor)
@ -189,6 +272,26 @@ const checks = [
&& /body \.markdown-source-view\.mod-cm6 \.cm-callout-content[\s\S]*?color:\s*var\(--text-normal\);/.test(files.activeVisual)
&& /body \.markdown-source-view\.mod-cm6 \.cm-formatting-callout,[\s\S]*?body \.markdown-source-view\.mod-cm6 \.cm-callout \.cm-formatting[\s\S]*?color:\s*var\(--monokai-callout-source-marker-color\);/.test(files.activeVisual),
],
[
"代码学习 Callout 语义在阅读模式与编辑模式都有颜色和图标映射",
[
"concept",
"syntax",
"api",
"debug",
"pitfall",
"exercise",
"answer",
"source",
"output",
"terminal",
].every((calloutName) => {
const calloutPattern = new RegExp(`\\.callout\\[data-callout="${calloutName}"\\]`);
const iconPattern = new RegExp(`\\.callout\\[data-callout="${calloutName}"\\] \\.callout-icon::before[\\s\\S]*?content:`);
return calloutPattern.test(files.activeVisual) && iconPattern.test(files.activeVisual);
}),
],
[
"块引用多行和嵌套层级在阅读模式与编辑模式收敛",
/--monokai-blockquote-nested-gap:\s*#\{\$spacing-3\};/.test(files.activeVisual)
@ -206,6 +309,27 @@ const checks = [
&& /\.HyperMD-codeblock[\s\S]*?background-color:\s*var\(--code-background\);[\s\S]*?font-family:\s*var\(--font-monospace-theme\);[\s\S]*?padding-inline:\s*var\(--monokai-codeblock-padding-inline\);/.test(files.editor)
&& /\.cm-formatting-code-block,[\s\S]*?\.cm-hmd-codeblock-begin,[\s\S]*?\.cm-hmd-codeblock-end[\s\S]*?color:\s*var\(--monokai-formatting-marker-color\);/.test(files.editor),
],
[
"代码块具备 Monokai Pro 编辑器 surface 变量与滚动状态",
/--monokai-codeblock-header-height:\s*1\.75rem;/.test(files.editor)
&& /--monokai-codeblock-shadow:/.test(files.editor)
&& /--monokai-codeblock-language-color:\s*var\(--text-faint\);/.test(files.editor)
&& /--monokai-codeblock-line-height:\s*var\(--monokai-code-line-height, 1\.55\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?pre\s*\{[\s\S]*?box-shadow:\s*var\(--monokai-codeblock-shadow\);[\s\S]*?line-height:\s*var\(--monokai-codeblock-line-height\);[\s\S]*?overflow-x:\s*auto;/.test(files.editor)
&& /\.HyperMD-codeblock[\s\S]*?line-height:\s*var\(--monokai-codeblock-line-height\);/.test(files.editor),
],
[
"编辑模式具备 active line、selection、cursor、gutter 与 bracket match 状态",
/--monokai-editor-active-line-background:/.test(files.editor)
&& /--monokai-editor-selection-background:/.test(files.editor)
&& /--monokai-editor-cursor-color:/.test(files.editor)
&& /--monokai-editor-gutter-background:/.test(files.editor)
&& /\.cm-active[\s\S]*?background-color:\s*var\(--monokai-editor-active-line-background\);/.test(files.editor)
&& /\.cm-selectionBackground[\s\S]*?background-color:\s*var\(--monokai-editor-selection-background\);/.test(files.editor)
&& /\.cm-cursor[\s\S]*?border-left-color:\s*var\(--monokai-editor-cursor-color\);/.test(files.editor)
&& /\.cm-gutters[\s\S]*?background-color:\s*var\(--monokai-editor-gutter-background\);/.test(files.editor)
&& /\.cm-matchingBracket[\s\S]*?background-color:\s*var\(--monokai-editor-bracket-match-background\);/.test(files.editor),
],
[
"附件与内部嵌入扩展共享媒体容器变量",
/--monokai-embed-padding:\s*#\{\$spacing-3\};/.test(files.editor)
@ -213,16 +337,30 @@ const checks = [
&& /\.markdown-source-view\.mod-cm6[\s\S]*?\.file-embed,[\s\S]*?\.pdf-embed,[\s\S]*?\.audio-embed,[\s\S]*?\.video-embed,[\s\S]*?\.internal-embed,[\s\S]*?\.cm-embed-block\s*\{[\s\S]*?background-color:\s*var\(--monokai-media-background\);[\s\S]*?border:\s*1px solid var\(--monokai-media-border-color\);[\s\S]*?border-radius:\s*var\(--monokai-media-radius\);[\s\S]*?padding:\s*var\(--monokai-embed-padding\);/.test(files.editor),
],
[
"扩展任务状态阅读模式与编辑模式共享语义颜色",
/--monokai-task-forward-color:\s*var\(--text-accent\);/.test(files.editor)
"8 种任务状态阅读模式与编辑模式共享语义颜色",
/--monokai-task-open-color:\s*var\(--text-normal\);/.test(files.editor)
&& /--monokai-task-forward-color:\s*var\(--text-accent\);/.test(files.editor)
&& /--monokai-task-cancelled-color:\s*var\(--text-faint\);/.test(files.editor)
&& /--monokai-task-question-color:\s*var\(--link-color\);/.test(files.editor)
&& /--monokai-task-important-color:\s*var\(--monokai-spectrum-orange, var\(--text-accent\)\);/.test(files.editor)
&& /--monokai-task-in-progress-color:\s*var\(--monokai-spectrum-cyan, var\(--link-color\)\);/.test(files.editor)
&& /--monokai-task-starred-color:\s*var\(--monokai-spectrum-yellow, var\(--text-accent\)\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task=" "\],[\s\S]*?\.task-list-item\[data-task=""\][\s\S]*?color:\s*var\(--monokai-task-open-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="x"\],[\s\S]*?\.task-list-item\[data-task="X"\],[\s\S]*?\.task-list-item\.is-checked[\s\S]*?color:\s*var\(--monokai-task-done-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task=">"\][\s\S]*?color:\s*var\(--monokai-task-forward-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="-"\][\s\S]*?color:\s*var\(--monokai-task-cancelled-color\);[\s\S]*?text-decoration-line:\s*line-through;/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="\?"\][\s\S]*?color:\s*var\(--monokai-task-question-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="!"\][\s\S]*?color:\s*var\(--monokai-task-important-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="\/"\][\s\S]*?color:\s*var\(--monokai-task-in-progress-color\);/.test(files.editor)
&& /\.markdown-rendered[\s\S]*?\.task-list-item\[data-task="\*"\][\s\S]*?color:\s*var\(--monokai-task-starred-color\);/.test(files.editor)
&& /\.markdown-source-view\.mod-cm6[\s\S]*?\.HyperMD-task-line\[data-task=" "\],[\s\S]*?\.HyperMD-task-line\[data-task=""\][\s\S]*?color:\s*var\(--monokai-task-open-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="x"\],[\s\S]*?\.HyperMD-task-line\[data-task="X"\][\s\S]*?color:\s*var\(--monokai-task-done-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task=">"\][\s\S]*?color:\s*var\(--monokai-task-forward-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="-"\][\s\S]*?color:\s*var\(--monokai-task-cancelled-color\);[\s\S]*?text-decoration-line:\s*line-through;/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="\?"\][\s\S]*?color:\s*var\(--monokai-task-question-color\);/.test(files.editor),
&& /\.HyperMD-task-line\[data-task="\?"\][\s\S]*?color:\s*var\(--monokai-task-question-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="!"\][\s\S]*?color:\s*var\(--monokai-task-important-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="\/"\][\s\S]*?color:\s*var\(--monokai-task-in-progress-color\);/.test(files.editor)
&& /\.HyperMD-task-line\[data-task="\*"\][\s\S]*?color:\s*var\(--monokai-task-starred-color\);/.test(files.editor),
],
];

View file

@ -9,8 +9,11 @@ settings:
title: 调色板滤镜
type: class-select
allowEmpty: false
default: monokai-syntax-filter-classic
default: monokai-syntax-filter-pro
options:
-
label: Pro
value: monokai-syntax-filter-pro
-
label: Classic
value: monokai-syntax-filter-classic
@ -26,4 +29,10 @@ settings:
-
label: Spectrum
value: monokai-syntax-filter-spectrum
-
label: Light
value: monokai-syntax-filter-light
-
label: Sun
value: monokai-syntax-filter-sun
*/

View file

@ -13,4 +13,61 @@ settings:
max: 75
step: 1
format: rem
-
id: monokai-body-font-size
title: 正文字号
type: variable-number-slider
default: 16
min: 13
max: 20
step: 1
format: px
-
id: monokai-code-font-size
title: 代码字号
type: variable-number-slider
default: 0.9
min: 0.75
max: 1.2
step: 0.05
format: em
-
id: monokai-code-line-height
title: 代码行高
type: variable-number-slider
default: 1.55
min: 1.25
max: 1.9
step: 0.05
-
id: monokai-heading-scale
title: 标题缩放
type: variable-number-slider
default: 1
min: 0.9
max: 1.15
step: 0.05
-
id: monokai-heading-group-spacing-value
title: 标题分组间距
type: variable-number-slider
default: 1.4
min: 1
max: 2.2
step: 0.05
format: rem
-
id: monokai-syntax-heading-accents
title: 标题左侧色条
type: class-toggle
default: false
-
id: monokai-paragraph-spacing-value
title: 段落间距
type: variable-number-slider
default: 0.75
min: 0.4
max: 1.2
step: 0.05
format: rem
*/

View file

@ -246,6 +246,68 @@ body .markdown-source-view.mod-cm6 .callout[data-callout="cite"] {
--callout-border: var(--monokai-callout-quote-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="concept"],
body .markdown-rendered .callout[data-callout="concept"],
body .markdown-source-view.mod-cm6 .callout[data-callout="concept"] {
--callout-background: var(--monokai-callout-abstract-bg);
--callout-border: var(--monokai-callout-abstract-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="syntax"],
body .markdown-rendered .callout[data-callout="syntax"],
body .markdown-source-view.mod-cm6 .callout[data-callout="syntax"] {
--callout-background: var(--monokai-callout-info-bg);
--callout-border: var(--monokai-callout-info-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="api"],
body .markdown-rendered .callout[data-callout="api"],
body .markdown-source-view.mod-cm6 .callout[data-callout="api"],
body .markdown-preview-view.markdown-rendered .callout[data-callout="answer"],
body .markdown-rendered .callout[data-callout="answer"],
body .markdown-source-view.mod-cm6 .callout[data-callout="answer"],
body .markdown-preview-view.markdown-rendered .callout[data-callout="terminal"],
body .markdown-rendered .callout[data-callout="terminal"],
body .markdown-source-view.mod-cm6 .callout[data-callout="terminal"] {
--callout-background: var(--monokai-callout-success-bg);
--callout-border: var(--monokai-callout-success-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="debug"],
body .markdown-rendered .callout[data-callout="debug"],
body .markdown-source-view.mod-cm6 .callout[data-callout="debug"] {
--callout-background: var(--monokai-callout-example-bg);
--callout-border: var(--monokai-callout-example-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="pitfall"],
body .markdown-rendered .callout[data-callout="pitfall"],
body .markdown-source-view.mod-cm6 .callout[data-callout="pitfall"] {
--callout-background: var(--monokai-callout-error-bg);
--callout-border: var(--monokai-callout-error-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="exercise"],
body .markdown-rendered .callout[data-callout="exercise"],
body .markdown-source-view.mod-cm6 .callout[data-callout="exercise"] {
--callout-background: var(--monokai-callout-todo-bg);
--callout-border: var(--monokai-callout-todo-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="source"],
body .markdown-rendered .callout[data-callout="source"],
body .markdown-source-view.mod-cm6 .callout[data-callout="source"] {
--callout-background: var(--monokai-callout-note-bg);
--callout-border: var(--monokai-callout-note-border);
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="output"],
body .markdown-rendered .callout[data-callout="output"],
body .markdown-source-view.mod-cm6 .callout[data-callout="output"] {
--callout-background: var(--monokai-callout-quote-bg);
--callout-border: var(--monokai-callout-quote-border);
}
/* ===== Callout 图标 ===== */
body .markdown-preview-view.markdown-rendered .callout-icon,
@ -431,4 +493,68 @@ body .markdown-source-view.mod-cm6 .callout[data-callout="example"] .cm-callout-
content: "\e674";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="concept"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="concept"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="concept"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="concept"] .cm-callout-icon::before {
content: "\e668";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="syntax"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="syntax"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="syntax"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="syntax"] .cm-callout-icon::before,
body .markdown-preview-view.markdown-rendered .callout[data-callout="source"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="source"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="source"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="source"] .cm-callout-icon::before {
content: "\e66f";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="api"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="api"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="api"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="api"] .cm-callout-icon::before,
body .markdown-preview-view.markdown-rendered .callout[data-callout="terminal"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="terminal"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="terminal"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="terminal"] .cm-callout-icon::before {
content: "\e66e";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="debug"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="debug"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="debug"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="debug"] .cm-callout-icon::before {
content: "\e675";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="pitfall"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="pitfall"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="pitfall"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="pitfall"] .cm-callout-icon::before {
content: "\e671";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="exercise"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="exercise"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="exercise"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="exercise"] .cm-callout-icon::before {
content: "\e670";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="answer"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="answer"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="answer"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="answer"] .cm-callout-icon::before {
content: "\e66b";
}
body .markdown-preview-view.markdown-rendered .callout[data-callout="output"] .callout-icon::before,
body .markdown-rendered .callout[data-callout="output"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="output"] .callout-icon::before,
body .markdown-source-view.mod-cm6 .callout[data-callout="output"] .cm-callout-icon::before {
content: "\e672";
}
/* stylelint-enable selector-class-pattern */

View file

@ -65,6 +65,15 @@
--code-string: #{$color-dark-yellow-soft};
--code-tag: #{$color-dark-red-soft};
--code-value: #{$color-dark-purple-soft};
--code-type: #{$color-dark-purple-soft};
--code-class: #{$color-dark-green-soft};
--code-builtin: #{$color-dark-cyan-soft};
--code-constant: #{$color-dark-purple-soft};
--code-namespace: #{$color-dark-text-muted};
--code-decorator: #{$color-dark-orange-soft};
--code-regex: #{$color-dark-yellow-soft};
--code-meta: #{$color-dark-text-faint};
--code-error: #{$color-dark-magenta};
--ribbon-background: #{$color-dark-background-secondary};
--nav-item-background-hover: #{$color-dark-hover};
--nav-item-background-active: #{$color-dark-active};
@ -132,6 +141,15 @@
--code-string: #{$color-light-yellow};
--code-tag: #{$color-light-magenta};
--code-value: #{$color-light-purple};
--code-type: #{$color-light-purple};
--code-class: #{$color-light-green};
--code-builtin: #{$color-light-cyan};
--code-constant: #{$color-light-purple};
--code-namespace: #{$color-light-text-muted};
--code-decorator: #{$color-light-orange};
--code-regex: #{$color-light-yellow};
--code-meta: #{$color-light-text-faint};
--code-error: #{$color-light-magenta};
--ribbon-background: #{$color-light-background-secondary};
--nav-item-background-hover: #{$color-light-hover};
--nav-item-background-active: #{$color-light-active};

View file

@ -18,6 +18,20 @@ $color-dark-cyan: #66d9ef;
$color-dark-cyan-soft: #78dce8;
$color-dark-purple: #ae81ff;
$color-dark-purple-soft: #ab9df2;
$color-pro-background-primary: #2d2a2e;
$color-pro-background-secondary: #221f22;
$color-pro-text-normal: #fcfcfa;
$color-pro-text-muted: #c1c0c0;
$color-pro-text-faint: #939293;
$color-pro-border: #403e41;
$color-pro-hover: #403e41;
$color-pro-active: #4a464d;
$color-pro-magenta: #ff6188;
$color-pro-orange: #fc9867;
$color-pro-yellow: #ffd866;
$color-pro-green: #a9dc76;
$color-pro-cyan: #78dce8;
$color-pro-purple: #ab9df2;
$color-light-background-primary: #fdf9f3;
$color-light-background-secondary: #f5f0e6;
$color-light-text-normal: #3d3d3d;
@ -38,6 +52,20 @@ $color-light-cyan: #14748a;
$color-light-cyan-soft: #1ba5bf;
$color-light-purple: #7058be;
$color-light-purple-soft: #7358cf;
$color-sun-background-primary: #fbf3db;
$color-sun-background-secondary: #f4e8c4;
$color-sun-text-normal: #3a3426;
$color-sun-text-muted: #675f4a;
$color-sun-text-faint: #847a60;
$color-sun-border: #d7c89e;
$color-sun-hover: #ecdfbc;
$color-sun-active: #e2d3ad;
$color-sun-magenta: #c83f67;
$color-sun-orange: #c85f2b;
$color-sun-yellow: #8a6a00;
$color-sun-green: #2f7d57;
$color-sun-cyan: #1f7184;
$color-sun-purple: #6251a8;
$color-dark-blockquote-border: $color-dark-yellow;
$color-light-blockquote-border: $color-light-yellow;
$font-text-theme: "Inter", "Segoe UI", "Helvetica Neue", "Arial", sans-serif;

View file

@ -12,6 +12,9 @@
--monokai-heading-gap-h4: 0.8rem;
--monokai-heading-gap-h5: 0.7rem;
--monokai-heading-gap-h6: 0.6rem;
--monokai-heading-accent-width: 3px;
--monokai-heading-group-spacing: var(--monokai-heading-group-spacing-value, 1.4rem);
--monokai-heading-anchor-color: var(--text-faint);
--monokai-heading-weight: 600;
--monokai-inline-code-color: #a6e22e;
--monokai-inline-code-background: var(--code-background);
@ -30,6 +33,10 @@
--monokai-media-border-color: var(--background-modifier-border);
--monokai-media-background: var(--background-secondary);
--monokai-embed-padding: #{$spacing-3};
--monokai-plugin-surface-background: var(--background-secondary);
--monokai-plugin-surface-border: var(--background-modifier-border);
--monokai-plugin-surface-radius: var(--radius-m);
--monokai-plugin-surface-padding: #{$spacing-4};
--monokai-tag-color: var(--link-color);
--monokai-tag-background: var(--background-secondary);
--monokai-tag-border-color: var(--background-modifier-border);
@ -37,14 +44,38 @@
--monokai-link-decoration-color: var(--link-color);
--monokai-link-decoration-thickness: 1px;
--monokai-paragraph-line-height: var(--line-height-normal);
--monokai-paragraph-spacing: #{$spacing-3};
--monokai-paragraph-spacing: var(--monokai-paragraph-spacing-value, #{$spacing-3});
--monokai-list-indent: 1.5em;
--monokai-list-item-spacing: 0.35rem;
--monokai-nested-list-spacing: 0.25rem;
--monokai-table-source-background: var(--background-secondary);
--monokai-table-source-font-family: var(--font-monospace-theme);
--monokai-table-source-separator-color: var(--text-faint);
--monokai-table-cell-padding: 0.55rem 0.7rem;
--monokai-table-row-hover-background: var(--background-modifier-hover);
--monokai-table-row-alt-background: transparent;
--monokai-table-api-name-color: var(--link-color);
--monokai-table-api-type-color: var(--code-type);
--monokai-table-api-default-color: var(--code-value);
--monokai-table-api-required-color: var(--text-accent);
--monokai-codeblock-border-color: var(--background-modifier-border);
--monokai-codeblock-radius: var(--radius-m);
--monokai-codeblock-header-height: 1.75rem;
--monokai-codeblock-padding: #{$spacing-4};
--monokai-codeblock-padding-inline: #{$spacing-4};
--monokai-codeblock-shadow: 0 10px 24px rgb(0 0 0 / 16%);
--monokai-codeblock-language-color: var(--text-faint);
--monokai-codeblock-line-height: var(--monokai-code-line-height, 1.55);
--monokai-editor-active-line-background: rgb(248 248 242 / 5%);
--monokai-editor-selection-background: rgb(102 217 239 / 22%);
--monokai-editor-cursor-color: var(--interactive-accent);
--monokai-editor-gutter-background: var(--background-secondary);
--monokai-editor-gutter-color: var(--text-faint);
--monokai-editor-bracket-match-background: rgb(166 226 46 / 18%);
--monokai-task-open-color: var(--text-normal);
--monokai-task-important-color: var(--monokai-spectrum-orange, var(--text-accent));
--monokai-task-in-progress-color: var(--monokai-spectrum-cyan, var(--link-color));
--monokai-task-starred-color: var(--monokai-spectrum-yellow, var(--text-accent));
--callout-blend-mode: normal;
--callout-icon-size: 1.25em;
--p-spacing: var(--monokai-paragraph-spacing);
@ -87,12 +118,17 @@ body.theme-dark {
--monokai-inline-code-background: var(--code-background);
--monokai-table-border: rgb(248 248 242 / 18%);
--monokai-table-header-background: rgb(248 248 242 / 6%);
--monokai-table-row-alt-background: rgb(248 248 242 / 3%);
--monokai-task-done-color: rgb(248 248 242 / 68%);
--monokai-task-forward-color: var(--text-accent);
--monokai-task-cancelled-color: var(--text-faint);
--monokai-task-question-color: var(--link-color);
--monokai-modal-shadow: 0 18px 50px rgb(0 0 0 / 35%);
--monokai-selection-ring: rgb(249 38 114 / 28%);
--monokai-codeblock-shadow: 0 10px 28px rgb(0 0 0 / 22%);
--monokai-editor-active-line-background: rgb(248 248 242 / 5%);
--monokai-editor-selection-background: rgb(102 217 239 / 22%);
--monokai-editor-bracket-match-background: rgb(166 226 46 / 18%);
}
body.theme-light {
@ -129,12 +165,17 @@ body.theme-light {
--monokai-inline-code-background: var(--code-background);
--monokai-table-border: rgb(61 61 61 / 18%);
--monokai-table-header-background: rgb(61 61 61 / 6%);
--monokai-table-row-alt-background: rgb(61 61 61 / 3%);
--monokai-task-done-color: rgb(61 61 61 / 66%);
--monokai-task-forward-color: var(--text-accent);
--monokai-task-cancelled-color: var(--text-faint);
--monokai-task-question-color: var(--link-color);
--monokai-modal-shadow: 0 16px 36px rgb(61 61 61 / 16%);
--monokai-selection-ring: rgb(200 63 103 / 22%);
--monokai-codeblock-shadow: 0 8px 20px rgb(61 61 61 / 10%);
--monokai-editor-active-line-background: rgb(61 61 61 / 5%);
--monokai-editor-selection-background: rgb(20 116 138 / 18%);
--monokai-editor-bracket-match-background: rgb(38 157 105 / 16%);
}
.markdown-source-view.mod-cm6 .inline-title {
@ -154,29 +195,35 @@ body.theme-light {
}
h1 {
font-size: var(--h1-size);
margin-block-end: var(--monokai-heading-gap-h1);
}
h2 {
margin-block-end: var(--monokai-heading-gap-h2);
font-size: var(--h2-size);
margin-block: var(--monokai-heading-group-spacing) var(--monokai-heading-gap-h2);
}
h3 {
margin-block-end: var(--monokai-heading-gap-h3);
font-size: var(--h3-size);
margin-block: calc(var(--monokai-heading-group-spacing) * 0.82) var(--monokai-heading-gap-h3);
}
h4 {
color: var(--h4-color);
font-size: var(--h4-size);
margin-block-end: var(--monokai-heading-gap-h4);
}
h5 {
color: var(--h5-color);
font-size: var(--h5-size);
margin-block-end: var(--monokai-heading-gap-h5);
}
h6 {
color: var(--h6-color);
font-size: var(--h6-size);
margin-block-end: var(--monokai-heading-gap-h6);
}
@ -212,10 +259,38 @@ body.theme-light {
color: var(--list-marker-color);
}
ul,
ol {
margin-block: 0 var(--monokai-paragraph-spacing);
padding-inline-start: var(--monokai-list-indent);
}
li {
margin-block: var(--monokai-list-item-spacing);
}
li > p {
margin-block: 0;
}
li > ul,
li > ol {
margin-block: var(--monokai-nested-list-spacing) 0;
}
.task-list-item[data-task=" "],
.task-list-item[data-task=""] {
color: var(--monokai-task-open-color);
}
.task-list-item[data-task="x"],
.task-list-item[data-task="X"],
.task-list-item.is-checked {
color: var(--monokai-task-done-color);
}
.task-list-item[data-task="x"] > p,
.task-list-item[data-task="X"] > p,
.task-list-item.is-checked > p {
color: var(--monokai-task-done-color);
}
@ -233,13 +308,34 @@ body.theme-light {
color: var(--monokai-task-question-color);
}
.task-list-item[data-task="!"] {
color: var(--monokai-task-important-color);
font-weight: 700;
}
.task-list-item[data-task="/"] {
color: var(--monokai-task-in-progress-color);
}
.task-list-item[data-task="*"] {
color: var(--monokai-task-starred-color);
font-weight: 700;
}
table {
width: 100%;
border: 1px solid var(--monokai-table-border);
border-collapse: separate;
border-spacing: 0;
margin-block: var(--monokai-paragraph-spacing);
overflow: hidden;
}
th,
td {
border: 1px solid var(--monokai-table-border);
padding: var(--monokai-table-cell-padding);
vertical-align: top;
}
th {
@ -248,6 +344,32 @@ body.theme-light {
font-weight: 700;
}
tbody tr:nth-child(even) {
background-color: var(--monokai-table-row-alt-background);
}
tbody tr:hover {
background-color: var(--monokai-table-row-hover-background);
}
td:first-child {
color: var(--monokai-table-api-name-color);
font-weight: 600;
}
td:nth-child(2) code {
color: var(--monokai-table-api-type-color);
}
td:nth-child(3) code {
color: var(--monokai-table-api-default-color);
}
td:nth-child(4) strong,
td:nth-child(4) code {
color: var(--monokai-table-api-required-color);
}
code {
color: var(--monokai-inline-code-color);
background-color: var(--monokai-inline-code-background);
@ -261,8 +383,13 @@ body.theme-light {
background-color: var(--code-background);
border: 1px solid var(--monokai-codeblock-border-color);
border-radius: var(--monokai-codeblock-radius);
box-shadow: var(--monokai-codeblock-shadow);
font-family: var(--font-monospace-theme);
line-height: var(--monokai-codeblock-line-height);
overflow-x: auto;
padding: var(--monokai-codeblock-padding);
scrollbar-color: var(--text-faint) transparent;
tab-size: 2;
code {
background-color: transparent;
@ -306,6 +433,61 @@ body.theme-light {
border-radius: var(--monokai-media-radius);
padding: var(--monokai-embed-padding);
}
.mermaid {
color: var(--text-normal);
background-color: var(--monokai-plugin-surface-background);
border: 1px solid var(--monokai-plugin-surface-border);
border-radius: var(--monokai-plugin-surface-radius);
overflow-x: auto;
padding: var(--monokai-plugin-surface-padding);
}
.math,
.math-block {
overflow-x: auto;
color: var(--text-normal);
background-color: var(--monokai-plugin-surface-background);
border: 1px solid var(--monokai-plugin-surface-border);
border-radius: var(--monokai-plugin-surface-radius);
padding: var(--monokai-plugin-surface-padding);
}
.math-inline {
color: var(--monokai-inline-code-color);
background-color: var(--monokai-inline-code-background);
border-radius: var(--radius-s);
padding-inline: var(--monokai-highlight-padding-inline);
}
.block-language-dataview,
.dataview {
color: var(--text-normal);
background-color: var(--monokai-plugin-surface-background);
border: 1px solid var(--monokai-plugin-surface-border);
border-radius: var(--monokai-plugin-surface-radius);
padding: var(--monokai-plugin-surface-padding);
}
.dataview table {
width: 100%;
margin-block: 0;
}
.dataview ul,
.dataview ol {
padding-inline-start: var(--monokai-list-indent);
}
.dataview.task-list-item,
.dataview .task-list-item {
color: var(--monokai-task-open-color);
}
.heading-collapse-indicator,
.heading-anchor {
color: var(--monokai-heading-anchor-color);
}
}
.markdown-source-view.mod-cm6 {
@ -315,11 +497,11 @@ body.theme-light {
}
.HyperMD-header-2 {
padding-block-end: var(--monokai-heading-gap-h2);
padding-block: calc(var(--monokai-heading-group-spacing) / 3) var(--monokai-heading-gap-h2);
}
.HyperMD-header-3 {
padding-block-end: var(--monokai-heading-gap-h3);
padding-block: calc(var(--monokai-heading-group-spacing) / 4) var(--monokai-heading-gap-h3);
}
.HyperMD-header-4 {
@ -334,6 +516,11 @@ body.theme-light {
padding-block-end: var(--monokai-heading-gap-h6);
}
.HyperMD-task-line[data-task=" "],
.HyperMD-task-line[data-task=""] {
color: var(--monokai-task-open-color);
}
.HyperMD-task-line[data-task="x"],
.HyperMD-task-line[data-task="X"] {
color: var(--monokai-task-done-color);
@ -352,9 +539,24 @@ body.theme-light {
color: var(--monokai-task-question-color);
}
.HyperMD-task-line[data-task="!"] {
color: var(--monokai-task-important-color);
font-weight: 700;
}
.HyperMD-task-line[data-task="/"] {
color: var(--monokai-task-in-progress-color);
}
.HyperMD-task-line[data-task="*"] {
color: var(--monokai-task-starred-color);
font-weight: 700;
}
.HyperMD-codeblock {
background-color: var(--code-background);
font-family: var(--font-monospace-theme);
line-height: var(--monokai-codeblock-line-height);
padding-inline: var(--monokai-codeblock-padding-inline);
}
@ -376,31 +578,37 @@ body.theme-light {
.cm-header-1 {
color: var(--h1-color);
font-size: var(--h1-size);
font-weight: var(--monokai-heading-weight);
}
.cm-header-2 {
color: var(--h2-color);
font-size: var(--h2-size);
font-weight: var(--monokai-heading-weight);
}
.cm-header-3 {
color: var(--h3-color);
font-size: var(--h3-size);
font-weight: var(--monokai-heading-weight);
}
.cm-header-4 {
color: var(--h4-color);
font-size: var(--h4-size);
font-weight: var(--monokai-heading-weight);
}
.cm-header-5 {
color: var(--h5-color);
font-size: var(--h5-size);
font-weight: var(--monokai-heading-weight);
}
.cm-header-6 {
color: var(--h6-color);
font-size: var(--h6-size);
font-weight: var(--monokai-heading-weight);
}
@ -515,6 +723,36 @@ body.theme-light {
box-shadow: none;
padding: var(--monokai-inline-code-padding);
}
/* stylelint-disable selector-class-pattern -- CodeMirror 内部类名。 */
.cm-active {
background-color: var(--monokai-editor-active-line-background);
}
.cm-selectionBackground {
background-color: var(--monokai-editor-selection-background);
}
.cm-cursor {
border-left-color: var(--monokai-editor-cursor-color);
}
.cm-gutters {
color: var(--monokai-editor-gutter-color);
background-color: var(--monokai-editor-gutter-background);
border-right: 1px solid var(--background-modifier-border);
}
.cm-lineNumbers .cm-gutterElement {
color: var(--monokai-editor-gutter-color);
}
.cm-matchingBracket {
color: var(--text-normal);
background-color: var(--monokai-editor-bracket-match-background);
border-radius: var(--radius-s);
}
/* stylelint-enable selector-class-pattern */
}
.cm-s-obsidian {
@ -547,6 +785,54 @@ body.theme-light {
span.cm-operator {
color: var(--code-operator);
}
span.cm-type,
span.cm-class {
color: var(--code-type);
}
span.cm-builtin {
color: var(--code-builtin);
}
span.cm-variable,
span.cm-variable-3 {
color: var(--code-normal);
}
span.cm-constant {
color: var(--code-constant);
}
span.cm-attribute {
color: var(--code-property);
}
span.cm-tag {
color: var(--code-tag);
}
span.cm-qualifier,
span.cm-namespace {
color: var(--code-namespace);
}
span.cm-meta {
color: var(--code-meta);
}
span.cm-decorator {
color: var(--code-decorator);
}
span.cm-string-2 {
color: var(--code-regex);
}
span.cm-error {
color: var(--code-error);
text-decoration-color: var(--code-error);
}
}
a,

View file

@ -393,6 +393,94 @@
content: "\e679";
}
.nav-folder-title[data-path="assets"],
.nav-folder-title[data-path$="/assets"],
.nav-folder[data-path="assets"] > .nav-folder-title,
.nav-folder[data-path$="/assets"] > .nav-folder-title {
--monokai-folder-icon-content: "\e638";
--monokai-folder-icon-color: #ffd866;
}
.nav-folder-title[data-path="concepts"],
.nav-folder-title[data-path$="/concepts"],
.nav-folder[data-path="concepts"] > .nav-folder-title,
.nav-folder[data-path$="/concepts"] > .nav-folder-title {
--monokai-folder-icon-content: "\e668";
--monokai-folder-icon-color: #ab9df2;
}
.nav-folder-title[data-path="examples"],
.nav-folder-title[data-path$="/examples"],
.nav-folder[data-path="examples"] > .nav-folder-title,
.nav-folder[data-path$="/examples"] > .nav-folder-title {
--monokai-folder-icon-content: "\e674";
--monokai-folder-icon-color: #fc9867;
}
.nav-folder-title[data-path="exercises"],
.nav-folder-title[data-path$="/exercises"],
.nav-folder[data-path="exercises"] > .nav-folder-title,
.nav-folder[data-path$="/exercises"] > .nav-folder-title {
--monokai-folder-icon-content: "\e679";
--monokai-folder-icon-color: #ffd866;
}
.nav-folder-title[data-path="labs"],
.nav-folder-title[data-path$="/labs"],
.nav-folder[data-path="labs"] > .nav-folder-title,
.nav-folder[data-path$="/labs"] > .nav-folder-title {
--monokai-folder-icon-content: "\e610";
--monokai-folder-icon-color: #78dce8;
}
.nav-folder-title[data-path="leetcode"],
.nav-folder-title[data-path$="/leetcode"],
.nav-folder[data-path="leetcode"] > .nav-folder-title,
.nav-folder[data-path$="/leetcode"] > .nav-folder-title {
--monokai-folder-icon-content: "\eab5";
--monokai-folder-icon-color: #78dce8;
}
.nav-folder-title[data-path="notes"],
.nav-folder-title[data-path$="/notes"],
.nav-folder[data-path="notes"] > .nav-folder-title,
.nav-folder[data-path$="/notes"] > .nav-folder-title {
--monokai-folder-icon-content: "\e695";
--monokai-folder-icon-color: #a9dc76;
}
.nav-folder-title[data-path="src"],
.nav-folder-title[data-path$="/src"],
.nav-folder[data-path="src"] > .nav-folder-title,
.nav-folder[data-path$="/src"] > .nav-folder-title {
--monokai-folder-icon-content: "\e61d";
--monokai-folder-icon-color: #ffd866;
}
.nav-folder-title[data-path="tests"],
.nav-folder-title[data-path$="/tests"],
.nav-folder[data-path="tests"] > .nav-folder-title,
.nav-folder[data-path$="/tests"] > .nav-folder-title {
--monokai-folder-icon-content: "\e610";
--monokai-folder-icon-color: #78dce8;
}
.nav-folder-title[data-path^="day"],
.nav-folder-title[data-path*="/day"],
.nav-folder[data-path^="day"] > .nav-folder-title,
.nav-folder[data-path*="/day"] > .nav-folder-title {
--monokai-folder-icon-content: "\e637";
--monokai-folder-icon-color: #a9dc76;
}
.nav-folder-title[data-path^="Day"],
.nav-folder-title[data-path*="/Day"],
.nav-folder[data-path^="Day"] > .nav-folder-title,
.nav-folder[data-path*="/Day"] > .nav-folder-title {
--monokai-folder-icon-content: "\e637";
--monokai-folder-icon-color: #a9dc76;
}
.nav-file-title[data-path^="Bug_"][data-path$=".md"]::before,
.nav-file-title[data-path*="/Bug_"][data-path$=".md"]::before {
--monokai-file-icon-color: #ff6188;

View file

@ -42,9 +42,9 @@
.nav-folder-children .nav-folder-children .nav-folder-title .nav-folder-collapse-indicator,
.nav-folder-children .nav-folder-children .nav-folder-title .collapse-icon {
&::before {
content: "\e64d";
content: var(--monokai-folder-icon-content, "\e64d");
display: inline-block;
color: var(--icon-color);
color: var(--monokai-folder-icon-color, var(--icon-color));
font-family: monokai-pro-icons, monospace;
font-size: var(--monokai-file-tree-glyph-size);
font-style: normal;
@ -81,6 +81,18 @@ body.monokai-syntax-hide-file-tree-icons {
}
body.monokai-syntax-monochrome-icons {
.nav-folder-title {
--monokai-folder-icon-color: var(--icon-color);
}
.nav-folder-title:hover {
--monokai-folder-icon-color: var(--icon-color-hover);
}
.nav-folder-title.is-active {
--monokai-folder-icon-color: var(--icon-color-active);
}
.nav-file-title::before {
--monokai-file-icon-color: var(--icon-color);
}

View file

@ -1,12 +1,12 @@
.canvas-wrapper {
--canvas-background: var(--background-primary);
--canvas-card-label-color: var(--text-muted);
--canvas-color-1: var(--text-accent);
--canvas-color-2: var(--h2-color);
--canvas-color-3: var(--h3-color);
--canvas-color-4: var(--h4-color);
--canvas-color-5: var(--link-color);
--canvas-color-6: var(--h6-color);
--canvas-color-1: var(--monokai-spectrum-red, var(--text-accent));
--canvas-color-2: var(--monokai-spectrum-orange, var(--h2-color));
--canvas-color-3: var(--monokai-spectrum-yellow, var(--h3-color));
--canvas-color-4: var(--monokai-spectrum-green, var(--h4-color));
--canvas-color-5: var(--monokai-spectrum-cyan, var(--link-color));
--canvas-color-6: var(--monokai-spectrum-purple, var(--h6-color));
background-color: var(--canvas-background);
}

View file

@ -1,4 +1,13 @@
.graph-view {
--monokai-graph-background: var(--background-secondary);
--monokai-graph-panel: var(--background-modifier-active-hover);
--monokai-graph-line: rgb(from var(--monokai-spectrum-cyan, var(--link-color)) r g b / 42%);
--monokai-graph-node: var(--text-muted);
--monokai-graph-focused: var(--monokai-spectrum-red, var(--interactive-accent));
--monokai-graph-node-tag: var(--monokai-spectrum-purple, var(--h6-color));
--monokai-graph-node-attachment: var(--monokai-spectrum-green, var(--h4-color));
--monokai-graph-node-unresolved: var(--text-faint);
--monokai-graph-ring: rgb(from var(--monokai-spectrum-cyan, var(--link-color)) r g b / 28%);
--graph-line: var(--monokai-graph-line);
--graph-node: var(--monokai-graph-node);
--graph-node-focused: var(--monokai-graph-focused);
@ -34,30 +43,6 @@
}
}
.theme-dark .graph-view {
--monokai-graph-background: #1e1f1c;
--monokai-graph-panel: #2b2c26;
--monokai-graph-line: rgb(120 220 232 / 42%);
--monokai-graph-node: #c1c1bd;
--monokai-graph-focused: #ff6188;
--monokai-graph-node-tag: #ab9df2;
--monokai-graph-node-attachment: #a9dc76;
--monokai-graph-node-unresolved: #72736f;
--monokai-graph-ring: rgb(102 217 239 / 28%);
}
.theme-light .graph-view {
--monokai-graph-background: #f5f0e6;
--monokai-graph-panel: #f2ead8;
--monokai-graph-line: rgb(20 116 138 / 42%);
--monokai-graph-node: #4f5a55;
--monokai-graph-focused: #c83f67;
--monokai-graph-node-tag: #7058be;
--monokai-graph-node-attachment: #269d69;
--monokai-graph-node-unresolved: #a39a8d;
--monokai-graph-ring: rgb(20 116 138 / 18%);
}
.graph-controls {
color: var(--text-muted);
background-color: var(--monokai-graph-panel);

View file

@ -1,42 +1,309 @@
@use "../mixins" as *;
@use "../variables" as *;
@mixin monokai-filter(
$name,
$background-primary,
$background-secondary,
$text-normal,
$text-muted,
$text-faint,
$border,
$hover,
$active,
$red,
$orange,
$yellow,
$green,
$cyan,
$purple,
$comment,
$warning-bg
) {
--monokai-filter-name: "#{$name}";
--background-primary: #{$background-primary};
--background-secondary: #{$background-secondary};
--background-secondary-alt: #{$background-secondary};
--background-modifier-hover: #{$hover};
--background-modifier-active-hover: #{$active};
--background-modifier-border: #{$border};
--text-normal: #{$text-normal};
--text-muted: #{$text-muted};
--text-faint: #{$text-faint};
--text-accent: #{$red};
--text-accent-hover: #{$red};
--interactive-accent: #{$red};
--interactive-accent-hover: #{$red};
--link-color: #{$cyan};
--link-color-hover: #{$cyan};
--link-external-color: #{$cyan};
--link-external-color-hover: #{$cyan};
--h1-color: #{$red};
--h2-color: #{$orange};
--h3-color: #{$yellow};
--h4-color: #{$green};
--h5-color: #{$cyan};
--h6-color: #{$purple};
--icon-color: #{$text-muted};
--icon-color-hover: #{$text-normal};
--icon-color-active: #{$cyan};
--metadata-label-text-color: #{$orange};
--metadata-label-text-color-hover: #{$orange};
--monokai-default-accent: #{$red};
--monokai-default-link: #{$cyan};
--monokai-default-success: #{$green};
--monokai-default-warning: #{$warning-bg};
--monokai-default-code-background: #{$background-secondary};
--monokai-spectrum-red: #{$red};
--monokai-spectrum-orange: #{$orange};
--monokai-spectrum-yellow: #{$yellow};
--monokai-spectrum-green: #{$green};
--monokai-spectrum-cyan: #{$cyan};
--monokai-spectrum-purple: #{$purple};
--code-normal: #{$text-normal};
--code-background: #{$background-secondary};
--code-comment: #{$comment};
--code-function: #{$green};
--code-important: #{$red};
--code-keyword: #{$red};
--code-operator: #{$orange};
--code-property: #{$cyan};
--code-punctuation: #{$text-muted};
--code-string: #{$yellow};
--code-tag: #{$red};
--code-value: #{$purple};
--code-type: #{$purple};
--code-class: #{$green};
--code-builtin: #{$cyan};
--code-constant: #{$purple};
--code-namespace: #{$text-muted};
--code-decorator: #{$orange};
--code-regex: #{$yellow};
--code-meta: #{$text-faint};
--code-error: #{$red};
--monokai-callout-note-bg: rgb(from #{$cyan} r g b / 12%);
--monokai-callout-note-border: #{$cyan};
--monokai-callout-info-bg: rgb(from #{$cyan} r g b / 12%);
--monokai-callout-info-border: #{$cyan};
--monokai-callout-abstract-bg: rgb(from #{$purple} r g b / 12%);
--monokai-callout-abstract-border: #{$purple};
--monokai-callout-question-bg: rgb(from #{$purple} r g b / 12%);
--monokai-callout-question-border: #{$purple};
--monokai-callout-todo-bg: rgb(from #{$yellow} r g b / 12%);
--monokai-callout-todo-border: #{$yellow};
--monokai-callout-tip-bg: rgb(from #{$green} r g b / 12%);
--monokai-callout-tip-border: #{$green};
--monokai-callout-warning-bg: rgb(from #{$orange} r g b / 12%);
--monokai-callout-warning-border: #{$orange};
--monokai-callout-error-bg: rgb(from #{$red} r g b / 12%);
--monokai-callout-error-border: #{$red};
--monokai-callout-failure-bg: rgb(from #{$red} r g b / 12%);
--monokai-callout-failure-border: #{$red};
--monokai-callout-bug-bg: rgb(from #{$red} r g b / 12%);
--monokai-callout-bug-border: #{$red};
--monokai-callout-success-bg: rgb(from #{$green} r g b / 12%);
--monokai-callout-success-border: #{$green};
--monokai-callout-example-bg: rgb(from #{$orange} r g b / 12%);
--monokai-callout-example-border: #{$orange};
--monokai-callout-quote-bg: rgb(from #{$text-normal} r g b / 8%);
--monokai-callout-quote-border: #{$text-faint};
--monokai-graph-background: #{$background-secondary};
--monokai-graph-panel: #{$active};
--monokai-graph-line: rgb(from #{$cyan} r g b / 42%);
--monokai-graph-node: #{$text-muted};
--monokai-graph-focused: #{$red};
--monokai-graph-node-tag: #{$purple};
--monokai-graph-node-attachment: #{$green};
--monokai-graph-node-unresolved: #{$text-faint};
--monokai-graph-ring: rgb(from #{$cyan} r g b / 28%);
--canvas-color-1: #{$red};
--canvas-color-2: #{$orange};
--canvas-color-3: #{$yellow};
--canvas-color-4: #{$green};
--canvas-color-5: #{$cyan};
--canvas-color-6: #{$purple};
--ribbon-background: #{$background-secondary};
--nav-item-background-hover: #{$hover};
--nav-item-background-active: #{$active};
--nav-item-color: #{$text-muted};
--nav-item-color-hover: #{$text-normal};
--nav-item-color-active: #{$text-normal};
}
body.monokai-syntax-filter-pro {
@include monokai-filter(
"pro",
$color-pro-background-primary,
$color-pro-background-secondary,
$color-pro-text-normal,
$color-pro-text-muted,
$color-pro-text-faint,
$color-pro-border,
$color-pro-hover,
$color-pro-active,
$color-pro-magenta,
$color-pro-orange,
$color-pro-yellow,
$color-pro-green,
$color-pro-cyan,
$color-pro-purple,
#727072,
rgb(255 216 102 / 24%)
);
}
body.monokai-syntax-filter-classic {
--monokai-filter-name: "classic";
@include monokai-filter(
"classic",
$color-dark-background-primary,
$color-dark-background-secondary,
$color-dark-text-normal,
$color-dark-text-muted,
$color-dark-text-faint,
$color-dark-border,
$color-dark-hover,
$color-dark-active,
$color-dark-magenta,
$color-dark-orange-soft,
$color-dark-yellow-soft,
$color-dark-green-soft,
$color-dark-cyan-soft,
$color-dark-purple-soft,
#72736f,
rgb(230 219 116 / 28%)
);
}
body.monokai-syntax-filter-machine {
--background-primary: #222421;
--background-secondary: #191b19;
--text-accent: #ff4f8b;
--interactive-accent: #ff4f8b;
--monokai-filter-name: "machine";
@include monokai-filter(
"machine",
#222421,
#191b19,
#f2ffef,
#c2c9bd,
#8b9387,
#394037,
#323930,
#3b4438,
#ff4f8b,
#ff9f43,
#ffe66d,
#a5ff6b,
#6bf5ff,
#b68cff,
#747d70,
rgb(255 230 109 / 22%)
);
}
body.monokai-syntax-filter-octagon {
--background-primary: #28252f;
--background-secondary: #1f1d26;
--text-accent: #ff6188;
--interactive-accent: #ff6188;
--link-color: #78dce8;
--monokai-filter-name: "octagon";
@include monokai-filter(
"octagon",
#28252f,
#1f1d26,
#fff9fb,
#cbc3d4,
#978da3,
#443d50,
#3a3444,
#463f52,
#ff6188,
#fc9867,
#ffd866,
#a9dc76,
#78dce8,
#ab9df2,
#77707f,
rgb(255 216 102 / 22%)
);
}
body.monokai-syntax-filter-ristretto {
--background-primary: #2b241f;
--background-secondary: #211b18;
--text-accent: #ff6188;
--interactive-accent: #ff6188;
--link-color: #fc9867;
--monokai-filter-name: "ristretto";
@include monokai-filter(
"ristretto",
#2b241f,
#211b18,
#fff8ef,
#cfc1b2,
#998b7d,
#463b32,
#3c322b,
#483c33,
#ff6188,
#fc9867,
#ffd866,
#a9dc76,
#78dce8,
#ab9df2,
#7b7066,
rgb(255 216 102 / 22%)
);
}
body.monokai-syntax-filter-spectrum {
--background-primary: #262933;
--background-secondary: #1c1f28;
--text-accent: #ab9df2;
--interactive-accent: #ab9df2;
--link-color: #78dce8;
--monokai-filter-name: "spectrum";
@include monokai-filter(
"spectrum",
#262933,
#1c1f28,
#f7f8ff,
#c3c8d8,
#8d94a8,
#3e4454,
#353b49,
#42495a,
#ff6188,
#fc9867,
#ffd866,
#a9dc76,
#78dce8,
#ab9df2,
#71788c,
rgb(255 216 102 / 22%)
);
}
body.monokai-syntax-filter-light {
@include monokai-filter(
"light",
$color-light-background-primary,
$color-light-background-secondary,
$color-light-text-normal,
$color-light-text-muted,
$color-light-text-faint,
$color-light-border,
$color-light-hover,
$color-light-active,
$color-light-magenta,
$color-light-orange,
$color-light-yellow,
$color-light-green,
$color-light-cyan,
$color-light-purple,
$color-light-text-faint,
rgb(232 179 10 / 24%)
);
}
body.monokai-syntax-filter-sun {
@include monokai-filter(
"sun",
$color-sun-background-primary,
$color-sun-background-secondary,
$color-sun-text-normal,
$color-sun-text-muted,
$color-sun-text-faint,
$color-sun-border,
$color-sun-hover,
$color-sun-active,
$color-sun-magenta,
$color-sun-orange,
$color-sun-yellow,
$color-sun-green,
$color-sun-cyan,
$color-sun-purple,
$color-sun-text-faint,
rgb(199 151 0 / 24%)
);
}
body.monokai-syntax-compact {
@ -88,8 +355,50 @@ body.monokai-syntax-monochrome-icons {
--icon-color-active: var(--text-normal);
}
body.monokai-syntax-heading-accents {
.markdown-rendered h1,
.markdown-rendered h2,
.markdown-rendered h3 {
position: relative;
padding-inline-start: calc(var(--monokai-heading-accent-width) + var(--spacing-2));
}
.markdown-rendered h1::before,
.markdown-rendered h2::before,
.markdown-rendered h3::before {
content: "";
position: absolute;
inset-block: 0.18em;
inset-inline-start: 0;
width: var(--monokai-heading-accent-width);
background-color: currentcolor;
border-radius: var(--radius-s);
}
/* stylelint-disable selector-class-pattern -- Obsidian/CodeMirror 内部类名。 */
.markdown-source-view.mod-cm6 .HyperMD-header-1,
.markdown-source-view.mod-cm6 .HyperMD-header-2,
.markdown-source-view.mod-cm6 .HyperMD-header-3 {
border-inline-start: var(--monokai-heading-accent-width) solid currentcolor;
padding-inline-start: calc(var(--monokai-heading-accent-width) + var(--spacing-2));
}
/* stylelint-enable selector-class-pattern */
}
body {
--file-line-width: var(--monokai-readable-line-width, 48rem);
--font-text-size: var(--monokai-body-font-size, 16px);
--code-size: var(--monokai-code-font-size, 0.9em);
--line-height-normal: var(--monokai-body-line-height, 1.6);
--monokai-codeblock-line-height: var(--monokai-code-line-height, 1.55);
--monokai-heading-size-scale: var(--monokai-heading-scale, 1);
--h1-size: calc(1.802em * var(--monokai-heading-size-scale));
--h2-size: calc(1.602em * var(--monokai-heading-size-scale));
--h3-size: calc(1.424em * var(--monokai-heading-size-scale));
--h4-size: calc(1.266em * var(--monokai-heading-size-scale));
--h5-size: calc(1.125em * var(--monokai-heading-size-scale));
--h6-size: calc(0.889em * var(--monokai-heading-size-scale));
--monokai-paragraph-spacing: var(--monokai-paragraph-spacing-value, 0.75rem);
--text-accent: var(--monokai-accent-color, var(--monokai-default-accent));
--interactive-accent: var(--monokai-accent-color, var(--monokai-default-accent));
--link-color: var(--monokai-link-color, var(--monokai-default-link));

View file

@ -1,7 +1,7 @@
import assert from "node:assert/strict";
import test from "node:test";
import { contrast, toRgb } from "../scripts/check-contrast.js";
import { checkContrastPairs, contrast, pairs, toRgb } from "../scripts/check-contrast.js";
test("十六进制颜色转换为 RGB", () => {
assert.deepEqual(toRgb("#66d9ef"), [102, 217, 239]);
@ -10,3 +10,31 @@ test("十六进制颜色转换为 RGB", () => {
test("对比度计算符合 WCAG 公式", () => {
assert.equal(contrast("#000000", "#ffffff").toFixed(2), "21.00");
});
test("对比度样本覆盖全部 Monokai Pro 滤镜", () => {
const filterNames = new Set(pairs.map((pair) => pair.filter));
assert.deepEqual(
[...filterNames].sort(),
["classic", "light", "machine", "octagon", "pro", "ristretto", "spectrum", "sun"].sort(),
);
});
test("全部滤镜对比度样本满足阈值", () => {
const failures = checkContrastPairs().filter((result) => !result.passed);
assert.deepEqual(failures, []);
});
test("全部滤镜覆盖代码学习专项对比度样本", () => {
const requiredLabels = ["代码注释", "行号", "选区文字", "代码块边框", "链接", "Callout 标题"];
for (const filter of ["classic", "light", "machine", "octagon", "pro", "ristretto", "spectrum", "sun"]) {
const labels = new Set(pairs.filter((pair) => pair.filter === filter).map((pair) => pair.label));
assert.deepEqual(
requiredLabels.filter((label) => !labels.has(label)),
[],
`${filter} 缺少代码学习专项样本`,
);
}
});

View file

@ -0,0 +1,10 @@
import assert from "node:assert/strict";
import test from "node:test";
import { inspectPaletteFilters } from "../scripts/verify-palette-filters.js";
test("每个滤镜都覆盖核心语义变量", () => {
const result = inspectPaletteFilters();
assert.deepEqual(result.failures, []);
});

1520
theme.css

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
{
"1.0.0": "1.0.0",
"1.0.1": "1.0.0",
"1.0.2": "1.0.0"
"1.0.2": "1.0.0",
"1.1.0": "1.0.0"
}