refactor: share markdown renderer via baoyu-md

This commit is contained in:
Jim Liu 宝玉
2026-03-13 10:20:28 -05:00
parent c62cda4424
commit 056fa06c3b
427 changed files with 10831 additions and 3816 deletions
+21
View File
@@ -0,0 +1,21 @@
{
"name": "baoyu-md",
"private": true,
"version": "0.1.0",
"type": "module",
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"fflate": "^0.8.2",
"front-matter": "^4.0.2",
"highlight.js": "^11.11.1",
"juice": "^11.0.1",
"marked": "^15.0.6",
"reading-time": "^1.5.0",
"remark-cjk-friendly": "^1.1.0",
"remark-parse": "^11.0.0",
"remark-stringify": "^11.0.0",
"unified": "^11.0.5"
}
}
+18
View File
@@ -0,0 +1,18 @@
This directory contains code adapted from the doocs/md project.
Original project: https://github.com/doocs/md
License: WTFPL (Do What The Fuck You Want To Public License)
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2025 Doocs <admin@doocs.org>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+163
View File
@@ -0,0 +1,163 @@
import type { CliOptions, ThemeName } from "./types.js";
import {
FONT_FAMILY_MAP,
FONT_SIZE_OPTIONS,
COLOR_PRESETS,
CODE_BLOCK_THEMES,
} from "./constants.js";
import { THEME_NAMES } from "./themes.js";
import { loadExtendConfig } from "./extend-config.js";
export function printUsage(): void {
console.error(
[
"Usage:",
" npx tsx render.ts <markdown_file> [options]",
"",
"Options:",
` --theme <name> Theme (${THEME_NAMES.join(", ")})`,
` --color <name|hex> Primary color: ${Object.keys(COLOR_PRESETS).join(", ")}, or hex`,
` --font-family <name> Font: ${Object.keys(FONT_FAMILY_MAP).join(", ")}, or CSS value`,
` --font-size <N> Font size: ${FONT_SIZE_OPTIONS.join(", ")} (default: 16px)`,
` --code-theme <name> Code highlight theme (default: github)`,
` --mac-code-block Show Mac-style code block header`,
` --line-number Show line numbers in code blocks`,
` --cite Enable footnote citations`,
` --count Show reading time / word count`,
` --legend <value> Image caption: title-alt, alt-title, title, alt, none`,
` --keep-title Keep the first heading in output`,
].join("\n")
);
}
function parseArgValue(argv: string[], i: number, flag: string): string | null {
const arg = argv[i]!;
if (arg.includes("=")) {
return arg.slice(flag.length + 1);
}
const next = argv[i + 1];
return next ?? null;
}
function resolveFontFamily(value: string): string {
return FONT_FAMILY_MAP[value] ?? value;
}
function resolveColor(value: string): string {
return COLOR_PRESETS[value] ?? value;
}
export function parseArgs(argv: string[]): CliOptions | null {
const ext = loadExtendConfig();
let inputPath = "";
let theme: ThemeName = ext.default_theme ?? "default";
let keepTitle = ext.keep_title ?? false;
let primaryColor: string | undefined = ext.default_color ? resolveColor(ext.default_color) : undefined;
let fontFamily: string | undefined = ext.default_font_family ? resolveFontFamily(ext.default_font_family) : undefined;
let fontSize: string | undefined = ext.default_font_size ?? undefined;
let codeTheme = ext.default_code_theme ?? "github";
let isMacCodeBlock = ext.mac_code_block ?? true;
let isShowLineNumber = ext.show_line_number ?? false;
let citeStatus = ext.cite ?? false;
let countStatus = ext.count ?? false;
let legend = ext.legend ?? "alt";
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i]!;
if (!arg.startsWith("--") && !inputPath) {
inputPath = arg;
continue;
}
if (arg === "--help" || arg === "-h") {
return null;
}
if (arg === "--keep-title") { keepTitle = true; continue; }
if (arg === "--mac-code-block") { isMacCodeBlock = true; continue; }
if (arg === "--no-mac-code-block") { isMacCodeBlock = false; continue; }
if (arg === "--line-number") { isShowLineNumber = true; continue; }
if (arg === "--cite") { citeStatus = true; continue; }
if (arg === "--count") { countStatus = true; continue; }
if (arg === "--theme" || arg.startsWith("--theme=")) {
const val = parseArgValue(argv, i, "--theme");
if (!val) { console.error("Missing value for --theme"); return null; }
theme = val as ThemeName;
if (!arg.includes("=")) i += 1;
continue;
}
if (arg === "--color" || arg.startsWith("--color=")) {
const val = parseArgValue(argv, i, "--color");
if (!val) { console.error("Missing value for --color"); return null; }
primaryColor = resolveColor(val);
if (!arg.includes("=")) i += 1;
continue;
}
if (arg === "--font-family" || arg.startsWith("--font-family=")) {
const val = parseArgValue(argv, i, "--font-family");
if (!val) { console.error("Missing value for --font-family"); return null; }
fontFamily = resolveFontFamily(val);
if (!arg.includes("=")) i += 1;
continue;
}
if (arg === "--font-size" || arg.startsWith("--font-size=")) {
const val = parseArgValue(argv, i, "--font-size");
if (!val) { console.error("Missing value for --font-size"); return null; }
fontSize = val.endsWith("px") ? val : `${val}px`;
if (!FONT_SIZE_OPTIONS.includes(fontSize)) {
console.error(`Invalid font size: ${fontSize}. Valid: ${FONT_SIZE_OPTIONS.join(", ")}`);
return null;
}
if (!arg.includes("=")) i += 1;
continue;
}
if (arg === "--code-theme" || arg.startsWith("--code-theme=")) {
const val = parseArgValue(argv, i, "--code-theme");
if (!val) { console.error("Missing value for --code-theme"); return null; }
codeTheme = val;
if (!CODE_BLOCK_THEMES.includes(codeTheme)) {
console.error(`Unknown code theme: ${codeTheme}`);
return null;
}
if (!arg.includes("=")) i += 1;
continue;
}
if (arg === "--legend" || arg.startsWith("--legend=")) {
const val = parseArgValue(argv, i, "--legend");
if (!val) { console.error("Missing value for --legend"); return null; }
const valid = ["title-alt", "alt-title", "title", "alt", "none"];
if (!valid.includes(val)) {
console.error(`Invalid legend: ${val}. Valid: ${valid.join(", ")}`);
return null;
}
legend = val;
if (!arg.includes("=")) i += 1;
continue;
}
console.error(`Unknown argument: ${arg}`);
return null;
}
if (!inputPath) {
return null;
}
if (!THEME_NAMES.includes(theme)) {
console.error(`Unknown theme: ${theme}`);
return null;
}
return {
inputPath, theme, keepTitle, primaryColor, fontFamily, fontSize,
codeTheme, isMacCodeBlock, isShowLineNumber, citeStatus, countStatus, legend,
};
}
+9
View File
@@ -0,0 +1,9 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: 1c-light
Description: Style IDE 1C:Enterprise 8
Author: (c) Barilko Vitaliy <barilkovetal@gmail.com>
Maintainer: @Diversus23
Website: https://softonit.ru/
License: see project LICENSE
Touched: 2023
*/.hljs{color:#00f;background:#fff}.hljs-comment{color:green}.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-function,.hljs-keyword,.hljs-name,.hljs-punctuation,.hljs-selector-tag{color:red}.hljs-params,.hljs-type{color:#00f}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-symbol,.hljs-template-tag{color:#000}.hljs-section,.hljs-title{color:#00f}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:red}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#00f}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#963200}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+7
View File
@@ -0,0 +1,7 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: a11y-dark
Author: @ericwbailey
Maintainer: @ericwbailey
Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css
*/.hljs{background:#2b2b2b;color:#f8f8f2}.hljs-comment,.hljs-quote{color:#d4d0ab}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ffa07a}.hljs-built_in,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#f5ab35}.hljs-attribute{color:gold}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#abe338}.hljs-section,.hljs-title{color:#00e0e0}.hljs-keyword,.hljs-selector-tag{color:#dcc6e0}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-comment,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-quote,.hljs-string,.hljs-symbol,.hljs-type{color:highlight}.hljs-keyword,.hljs-selector-tag{font-weight:700}}
+7
View File
@@ -0,0 +1,7 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: a11y-light
Author: @ericwbailey
Maintainer: @ericwbailey
Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css
*/.hljs{background:#fefefe;color:#545454}.hljs-comment,.hljs-quote{color:#696969}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#d91e18}.hljs-attribute,.hljs-built_in,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#aa5d00}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:green}.hljs-section,.hljs-title{color:#007faa}.hljs-keyword,.hljs-selector-tag{color:#7928a1}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-comment,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-quote,.hljs-string,.hljs-symbol,.hljs-type{color:highlight}.hljs-keyword,.hljs-selector-tag{font-weight:700}}
+20
View File
@@ -0,0 +1,20 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: Agate
Author: (c) Taufik Nurrohman <hi@taufik-nurrohman.com>
Maintainer: @taufik-nurrohman
Updated: 2021-04-24
#333
#62c8f3
#7bd694
#888
#a2fca2
#ade5fc
#b8d8a2
#c6b4f0
#d36363
#fc9b9b
#fcc28c
#ffa
#fff
*/.hljs{background:#333;color:#fff}.hljs-doctag,.hljs-meta-keyword,.hljs-name,.hljs-strong{font-weight:700}.hljs-code,.hljs-emphasis{font-style:italic}.hljs-section,.hljs-tag{color:#62c8f3}.hljs-selector-class,.hljs-selector-id,.hljs-template-variable,.hljs-variable{color:#ade5fc}.hljs-meta-string,.hljs-string{color:#a2fca2}.hljs-attr,.hljs-quote,.hljs-selector-attr{color:#7bd694}.hljs-tag .hljs-attr{color:inherit}.hljs-attribute,.hljs-title,.hljs-type{color:#ffa}.hljs-number,.hljs-symbol{color:#d36363}.hljs-bullet,.hljs-template-tag{color:#b8d8a2}.hljs-built_in,.hljs-keyword,.hljs-literal,.hljs-selector-tag{color:#fcc28c}.hljs-code,.hljs-comment,.hljs-formula{color:#888}.hljs-link,.hljs-regexp,.hljs-selector-pseudo{color:#c6b4f0}.hljs-meta{color:#fc9b9b}.hljs-deletion{background:#fc9b9b;color:#333}.hljs-addition{background:#a2fca2;color:#333}.hljs-subst{color:#fff}.hljs a{color:inherit}.hljs a:focus,.hljs a:hover{color:inherit;text-decoration:underline}.hljs mark{background:#555;color:inherit}
+9
View File
@@ -0,0 +1,9 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: An Old Hope Star Wars Syntax
Author: (c) Gustavo Costa <gusbemacbe@gmail.com>
Maintainer: @gusbemacbe
Original theme - Ocean Dark Theme by https://github.com/gavsiu
Based on Jesse Leite's Atom syntax theme 'An Old Hope'
https://github.com/JesseLeite/an-old-hope-syntax-atom
*/.hljs{background:#1c1d21;color:#c0c5ce}.hljs-comment,.hljs-quote{color:#b6b18b}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#eb3c54}.hljs-built_in,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#e7ce56}.hljs-attribute{color:#ee7c2b}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#4fb4d7}.hljs-section,.hljs-title{color:#78bb65}.hljs-keyword,.hljs-selector-tag{color:#b45ea4}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#a9b7c6;background:#282b2e}.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#6897bb}.hljs-deletion,.hljs-keyword,.hljs-selector-tag{color:#cc7832}.hljs-link,.hljs-template-variable,.hljs-variable{color:#629755}.hljs-comment,.hljs-quote{color:grey}.hljs-meta{color:#bbb529}.hljs-addition,.hljs-attribute,.hljs-string{color:#6a8759}.hljs-section,.hljs-title,.hljs-type{color:#ffc66d}.hljs-name,.hljs-selector-class,.hljs-selector-id{color:#e8bf6a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#434f54}.hljs-subst{color:#434f54}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#00979d}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-literal{color:#d35400}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#00979d}.hljs-deletion,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#005c5f}.hljs-comment{color:rgba(149,165,166,.8)}.hljs-meta .hljs-keyword{color:#728e00}.hljs-meta{color:#434f54}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-function{color:#728e00}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-number{color:#8a7b52}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#222;color:#aaa}.hljs-subst{color:#aaa}.hljs-section{color:#fff}.hljs-comment,.hljs-meta,.hljs-quote{color:#444}.hljs-bullet,.hljs-regexp,.hljs-string,.hljs-symbol{color:#fc3}.hljs-addition,.hljs-number{color:#0c6}.hljs-attribute,.hljs-built_in,.hljs-link,.hljs-literal,.hljs-template-variable,.hljs-type{color:#32aaee}.hljs-keyword,.hljs-name,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag{color:#64a}.hljs-deletion,.hljs-template-tag,.hljs-title,.hljs-variable{color:#b16}.hljs-doctag,.hljs-section,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#000}.hljs-addition,.hljs-attribute,.hljs-bullet,.hljs-link,.hljs-section,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#888}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#ccc}.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-type{font-weight:700}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-keyword,.hljs-operator,.hljs-pattern-match{color:#f92672}.hljs-function,.hljs-pattern-match .hljs-constructor{color:#61aeee}.hljs-function .hljs-params{color:#a6e22e}.hljs-function .hljs-params .hljs-typing{color:#fd971f}.hljs-module-access .hljs-module{color:#7e57c2}.hljs-constructor{color:#e2b93d}.hljs-constructor .hljs-string{color:#9ccc65}.hljs-comment,.hljs-quote{color:#b18eb1;font-style:italic}.hljs-doctag,.hljs-formula{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#383a42;background:#fafafa}.hljs-comment,.hljs-quote{color:#a0a1a7;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e45649}.hljs-literal{color:#0184bb}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#50a14f}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#4078f2}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#c18401}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#363c69;background:url(./brown-papersq.png) #b7a68e}.hljs-keyword,.hljs-literal,.hljs-selector-tag{color:#059}.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-link,.hljs-name,.hljs-section,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#2c009f}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#802022}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#222;color:#fff}.hljs-comment,.hljs-quote{color:#777}.hljs-built_in,.hljs-bullet,.hljs-deletion,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-regexp,.hljs-symbol,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ab875d}.hljs-attribute,.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-title,.hljs-type{color:#9b869b}.hljs-addition,.hljs-keyword,.hljs-selector-tag,.hljs-string{color:#8f9c6c}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#000;background:#fff}.hljs-addition,.hljs-meta,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable{color:#756bb1}.hljs-comment,.hljs-quote{color:#636363}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-regexp{color:#31a354}.hljs-deletion,.hljs-variable{color:#88f}.hljs-built_in,.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-strong,.hljs-tag,.hljs-title,.hljs-type{color:#3182bd}.hljs-emphasis{font-style:italic}.hljs-attribute{color:#e6550d}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#ddd;background:#303030}.hljs-keyword,.hljs-link,.hljs-literal,.hljs-section,.hljs-selector-tag{color:#fff}.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-name,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#d88}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#979797}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.hljs-emphasis{font-style:italic}
+9
View File
@@ -0,0 +1,9 @@
/*!
Theme: Default
Description: Original highlight.js style
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
Maintainer: @highlightjs/core-team
Website: https://highlightjs.org/
License: see project LICENSE
Touched: 2021
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+7
View File
@@ -0,0 +1,7 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: devibeans (dark)
Author: @terminaldweller
Maintainer: @terminaldweller
Inspired by vim's jellybeans theme (https://github.com/nanotech/jellybeans.vim)
*/.hljs{background:#000;color:#a39e9b}.hljs-attr,.hljs-template-tag{color:#8787d7}.hljs-comment,.hljs-doctag,.hljs-quote{color:#396}.hljs-params{color:#a39e9b}.hljs-regexp{color:#d700ff}.hljs-literal,.hljs-number,.hljs-selector-id,.hljs-tag{color:#ef5350}.hljs-meta,.hljs-meta .hljs-keyword{color:#0087ff}.hljs-code,.hljs-formula,.hljs-keyword,.hljs-link,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-variable{color:#64b5f6}.hljs-built_in,.hljs-deletion,.hljs-title{color:#ff8700}.hljs-attribute,.hljs-function,.hljs-name,.hljs-property,.hljs-section,.hljs-type{color:#ffd75f}.hljs-addition,.hljs-bullet,.hljs-meta .hljs-string,.hljs-string,.hljs-subst,.hljs-symbol{color:#558b2f}.hljs-selector-tag{color:#96f}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#000;background:#f8f8ff}.hljs-comment,.hljs-quote{color:#408080;font-style:italic}.hljs-keyword,.hljs-literal,.hljs-selector-tag,.hljs-subst{color:#954121}.hljs-number{color:#40a070}.hljs-doctag,.hljs-string{color:#219161}.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-type{color:#19469d}.hljs-params{color:#00f}.hljs-title{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-template-variable,.hljs-variable{color:teal}.hljs-link,.hljs-regexp{color:#b68}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#0ff;background:navy}.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable{color:#ff0}.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-type,.hljs-variable{color:#fff}.hljs-comment,.hljs-deletion,.hljs-doctag,.hljs-quote{color:#888}.hljs-link,.hljs-literal,.hljs-number,.hljs-regexp{color:#0f0}.hljs-meta{color:teal}.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title{font-weight:700}.hljs-emphasis{font-style:italic}
+7
View File
@@ -0,0 +1,7 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
* Theme: FelipeC
* Author: (c) 2021 Felipe Contreras <felipe.contreras@gmail.com>
* Website: https://github.com/felipec/vim-felipec
*
* Autogenerated with vim-felipec's generator.
*/.hljs{color:#dedde4;background-color:#1d1c21}.hljs ::selection,.hljs::selection{color:#1d1c21;background-color:#ba9cef}.hljs-code,.hljs-comment,.hljs-quote{color:#9e9da4}.hljs-deletion,.hljs-literal,.hljs-number{color:#f09080}.hljs-doctag,.hljs-meta,.hljs-operator,.hljs-punctuation,.hljs-selector-attr,.hljs-subst,.hljs-template-variable{color:#ffbb7b}.hljs-type{color:#fddb7c}.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-title{color:#c4da7d}.hljs-addition,.hljs-regexp,.hljs-string{color:#93e4a4}.hljs-class,.hljs-property{color:#65e7d1}.hljs-name,.hljs-selector-tag{color:#30c2d8}.hljs-built_in,.hljs-keyword{color:#5fb8f2}.hljs-bullet,.hljs-section{color:#90aafa}.hljs-selector-pseudo{color:#ba9cef}.hljs-attr,.hljs-attribute,.hljs-params,.hljs-variable{color:#d991d2}.hljs-link,.hljs-symbol{color:#ec8dab}.hljs-literal,.hljs-strong,.hljs-title{font-weight:700}.hljs-emphasis{font-style:italic}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#eee;color:#000}.hljs-addition,.hljs-attribute,.hljs-emphasis,.hljs-link{color:#070}.hljs-emphasis{font-style:italic}.hljs-deletion,.hljs-string,.hljs-strong{color:#d14}.hljs-strong{font-weight:700}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-section,.hljs-title{color:#900}.hljs-class .hljs-title,.hljs-title.class_,.hljs-type{color:#458}.hljs-template-variable,.hljs-variable{color:#369}.hljs-bullet{color:#970}.hljs-meta{color:#34b}.hljs-code,.hljs-keyword,.hljs-literal,.hljs-number,.hljs-selector-tag{color:#099}.hljs-regexp{background-color:#fff0ff;color:#808}.hljs-symbol{color:#990073}.hljs-name,.hljs-selector-class,.hljs-selector-id,.hljs-tag{color:#070}
@@ -0,0 +1,9 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub Dark Dimmed
Description: Dark dimmed theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Colors taken from GitHub's CSS
*/.hljs{color:#adbac7;background:#22272e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#f47067}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#dcbdfb}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#6cb6ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#96d0ff}.hljs-built_in,.hljs-symbol{color:#f69d50}.hljs-code,.hljs-comment,.hljs-formula{color:#768390}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#8ddb8c}.hljs-subst{color:#adbac7}.hljs-section{color:#316dca;font-weight:700}.hljs-bullet{color:#eac55f}.hljs-emphasis{color:#adbac7;font-style:italic}.hljs-strong{color:#adbac7;font-weight:700}.hljs-addition{color:#b4f1b4;background-color:#1b4721}.hljs-deletion{color:#ffd8d3;background-color:#78191b}
+10
View File
@@ -0,0 +1,10 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}
+10
View File
@@ -0,0 +1,10 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#222;color:silver}.hljs-keyword{color:#ffb871;font-weight:700}.hljs-built_in{color:#ffb871}.hljs-literal{color:#ff8080}.hljs-symbol{color:#58e55a}.hljs-comment{color:#5b995b}.hljs-string{color:#ff0}.hljs-number{color:#ff8080}.hljs-addition,.hljs-attribute,.hljs-bullet,.hljs-code,.hljs-deletion,.hljs-doctag,.hljs-function,.hljs-link,.hljs-meta,.hljs-meta .hljs-keyword,.hljs-name,.hljs-quote,.hljs-regexp,.hljs-section,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-selector-tag,.hljs-subst,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:silver}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#000}.hljs-comment,.hljs-quote{color:#800}.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-title{color:#008}.hljs-template-variable,.hljs-variable{color:#660}.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string{color:#080}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-symbol{color:#066}.hljs-attr,.hljs-built_in,.hljs-doctag,.hljs-params,.hljs-title,.hljs-type{color:#606}.hljs-attribute,.hljs-subst{color:#000}.hljs-formula{background-color:#eee;font-style:italic}.hljs-selector-class,.hljs-selector-id{color:#9b703f}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-doctag,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background-color:#652487;background-image:linear-gradient(160deg,#652487 0,#443ac3 35%,#0174b7 68%,#04988e 100%);color:#e7e4eb}.hljs-subtr{color:#e7e4eb}.hljs-comment,.hljs-doctag,.hljs-meta,.hljs-quote{color:#af8dd9}.hljs-attr,.hljs-regexp,.hljs-selector-id,.hljs-selector-tag,.hljs-tag,.hljs-template-tag{color:#aefbff}.hljs-bullet,.hljs-params,.hljs-selector-class{color:#f19fff}.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-symbol,.hljs-type{color:#17fc95}.hljs-addition,.hljs-link,.hljs-number{color:#c5fe00}.hljs-string{color:#38c0ff}.hljs-addition,.hljs-attribute{color:#e7ff9f}.hljs-template-variable,.hljs-variable{color:#e447ff}.hljs-built_in,.hljs-class,.hljs-formula,.hljs-function,.hljs-name,.hljs-title{color:#ffc800}.hljs-deletion,.hljs-literal,.hljs-selector-pseudo{color:#ff9e44}.hljs-emphasis,.hljs-quote{font-style:italic}.hljs-keyword,.hljs-params,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-strong,.hljs-template-tag{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background-color:#f9ccff;background-image:linear-gradient(295deg,#f9ccff 0,#e6bbf9 11%,#9ec6f9 32%,#55e6ee 60%,#91f5d1 74%,#f9ffbf 98%);color:#250482}.hljs-subtr{color:#01958b}.hljs-comment,.hljs-doctag,.hljs-meta,.hljs-quote{color:#cb7200}.hljs-attr,.hljs-regexp,.hljs-selector-id,.hljs-selector-tag,.hljs-tag,.hljs-template-tag{color:#07bd5f}.hljs-bullet,.hljs-params,.hljs-selector-class{color:#43449f}.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-symbol,.hljs-type{color:#7d2801}.hljs-addition,.hljs-link,.hljs-number{color:#7f0096}.hljs-string{color:#2681ab}.hljs-addition,.hljs-attribute{color:#296562}.hljs-template-variable,.hljs-variable{color:#025c8f}.hljs-built_in,.hljs-class,.hljs-formula,.hljs-function,.hljs-name,.hljs-title{color:#529117}.hljs-deletion,.hljs-literal,.hljs-selector-pseudo{color:#ad13ff}.hljs-emphasis,.hljs-quote{font-style:italic}.hljs-keyword,.hljs-params,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-strong,.hljs-template-tag{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#333;background:#fff}.hljs-comment,.hljs-quote{color:#777;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number{color:#777}.hljs-doctag,.hljs-formula,.hljs-string{color:#333;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAJ0lEQVQIW2O8e/fufwYGBgZBQUEQxcCIIfDu3Tuwivfv30NUoAsAALHpFMMLqZlPAAAAAElFTkSuQmCC)}.hljs-section,.hljs-selector-id,.hljs-title{color:#000;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-name,.hljs-title.class_,.hljs-type{color:#333;font-weight:700}.hljs-tag{color:#333}.hljs-regexp{color:#333;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==)}.hljs-bullet,.hljs-link,.hljs-symbol{color:#000;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAKElEQVQIW2NkQAO7d+/+z4gsBhJwdXVlhAvCBECKwIIwAbhKZBUwBQA6hBpm5efZsgAAAABJRU5ErkJggg==)}.hljs-built_in{color:#000;text-decoration:underline}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{color:#fff;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==)}.hljs-addition{color:#000;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAALUlEQVQYV2N89+7dfwYk8P79ewZBQUFkIQZGOiu6e/cuiptQHAPl0NtNxAQBAM97Oejj3Dg7AAAAAElFTkSuQmCC)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#1d1f21;color:#c5c8c6}.hljs span::selection,.hljs::selection{background:#373b41}.hljs span::-moz-selection,.hljs::-moz-selection{background:#373b41}.hljs-name,.hljs-title{color:#f0c674}.hljs-comment,.hljs-meta,.hljs-meta .hljs-keyword{color:#707880}.hljs-deletion,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol{color:#c66}.hljs-addition,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string{color:#b5bd68}.hljs-attribute,.hljs-code,.hljs-selector-id{color:#b294bb}.hljs-bullet,.hljs-keyword,.hljs-selector-tag,.hljs-tag{color:#81a2be}.hljs-subst,.hljs-template-tag,.hljs-template-variable,.hljs-variable{color:#8abeb7}.hljs-built_in,.hljs-quote,.hljs-section,.hljs-selector-class,.hljs-type{color:#de935f}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#000;background:#fff}.hljs-subst,.hljs-title{font-weight:400;color:#000}.hljs-comment,.hljs-quote{color:grey;font-style:italic}.hljs-meta{color:olive}.hljs-tag{background:#efefef}.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-type{font-weight:700;color:navy}.hljs-attribute,.hljs-link,.hljs-number,.hljs-regexp{font-weight:700;color:#00f}.hljs-link,.hljs-number,.hljs-regexp{font-weight:400}.hljs-string{color:green;font-weight:700}.hljs-bullet,.hljs-formula,.hljs-symbol{color:#000;background:#d0eded;font-style:italic}.hljs-doctag{text-decoration:underline}.hljs-template-variable,.hljs-variable{color:#660e7a}.hljs-addition{background:#baeeba}.hljs-deletion{background:#ffc8bd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#000;background:#fff}.hljs-subst,.hljs-title{font-weight:400;color:#000}.hljs-title.function_{color:#7a7a43}.hljs-code,.hljs-comment,.hljs-quote{color:#8c8c8c;font-style:italic}.hljs-meta{color:#9e880d}.hljs-section{color:#871094}.hljs-built_in,.hljs-keyword,.hljs-literal,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-selector-tag,.hljs-symbol,.hljs-template-tag,.hljs-type,.hljs-variable.language_{color:#0033b3}.hljs-attr,.hljs-property{color:#871094}.hljs-attribute{color:#174ad4}.hljs-number{color:#1750eb}.hljs-regexp{color:#264eff}.hljs-link{text-decoration:underline;color:#006dcc}.hljs-meta .hljs-string,.hljs-string{color:#067d17}.hljs-char.escape_{color:#0037a6}.hljs-doctag{text-decoration:underline}.hljs-template-variable{color:#248f8f}.hljs-addition{background:#bee6be}.hljs-deletion{background:#d6d6d6}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#000;color:#f8f8f8}.hljs-comment,.hljs-meta,.hljs-quote{color:#7c7c7c}.hljs-keyword,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#96cbfe}.hljs-attribute,.hljs-selector-id{color:#ffffb6}.hljs-addition,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string{color:#a8ff60}.hljs-subst{color:#daefa3}.hljs-link,.hljs-regexp{color:#e9c062}.hljs-doctag,.hljs-section,.hljs-title,.hljs-type{color:#ffffb6}.hljs-bullet,.hljs-literal,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#c6c5fe}.hljs-deletion,.hljs-number{color:#ff73fd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#404040}.hljs,.hljs-subst{color:#f0f0f0}.hljs-comment{color:#b5b5b5;font-style:italic}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f0f0f0;font-weight:700}.hljs-string{color:#97bf0d}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#f0f0f0}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#e2c696}.hljs-built_in,.hljs-literal{color:#97bf0d;font-weight:700}.hljs-addition,.hljs-bullet,.hljs-code{color:#397300}.hljs-class{color:#ce9d4d;font-weight:700}.hljs-section,.hljs-title{color:#df471e}.hljs-title>.hljs-built_in{color:#81bce9;font-weight:400}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#000}.hljs-subst{color:#000}.hljs-comment{color:#555;font-style:italic}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{color:#000;font-weight:700}.hljs-string{color:navy}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#000}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#5e1700}.hljs-built_in,.hljs-literal{color:navy;font-weight:700}.hljs-addition,.hljs-bullet,.hljs-code{color:#397300}.hljs-class{color:#6f1c00;font-weight:700}.hljs-section,.hljs-title{color:#fb2c00}.hljs-title>.hljs-built_in{color:teal;font-weight:400}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#221a0f;color:#d3af86}.hljs-comment,.hljs-quote{color:#d6baad}.hljs-meta,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#dc3958}.hljs-built_in,.hljs-deletion,.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-type{color:#f79a32}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#889b4a}.hljs-function,.hljs-keyword,.hljs-selector-tag{color:#98676a}.hljs-attribute,.hljs-section,.hljs-title{color:#f06431}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fbebd4;color:#84613d}.hljs-comment,.hljs-quote{color:#a57a4c}.hljs-meta,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#dc3958}.hljs-built_in,.hljs-deletion,.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-type{color:#f79a32}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#889b4a}.hljs-function,.hljs-keyword,.hljs-selector-tag{color:#98676a}.hljs-attribute,.hljs-section,.hljs-title{color:#f06431}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#444;background:#fff}.hljs-name{color:#01a3a3}.hljs-meta,.hljs-tag{color:#789}.hljs-comment{color:#888}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#4286f4}.hljs-section,.hljs-title{color:#4286f4;font-weight:700}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#bc6060}.hljs-literal{color:#62bcbc}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#25c6c6}.hljs-meta .hljs-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#303030;color:#c5c8c6}.hljs-comment{color:#8d8d8d}.hljs-quote{color:#b3c7d8}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#c66}.hljs-built_in,.hljs-literal,.hljs-number,.hljs-subst .hljs-link,.hljs-type{color:#de935f}.hljs-attribute{color:#f0c674}.hljs-addition,.hljs-bullet,.hljs-params,.hljs-string{color:#b5bd68}.hljs-class,.hljs-function,.hljs-keyword,.hljs-selector-tag{color:#be94bb}.hljs-meta,.hljs-section,.hljs-title{color:#81a2be}.hljs-symbol{color:#dbc4d9}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background-color:#f4f4f4;color:#000}.hljs-subst{color:#000}.hljs-addition,.hljs-attribute,.hljs-bullet,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-variable{color:#050}.hljs-comment,.hljs-quote{color:#777}.hljs-link,.hljs-literal,.hljs-number,.hljs-regexp,.hljs-type{color:#800}.hljs-deletion,.hljs-meta{color:#00e}.hljs-built_in,.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-tag,.hljs-title{font-weight:700;color:navy}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#eaeef3;color:#00193a}.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title{font-weight:700}.hljs-comment{color:#738191}.hljs-addition,.hljs-built_in,.hljs-literal,.hljs-name,.hljs-quote,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-tag,.hljs-title,.hljs-type{color:#0048ab}.hljs-attribute,.hljs-bullet,.hljs-deletion,.hljs-link,.hljs-meta,.hljs-regexp,.hljs-subst,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#4c81c9}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#23241f;color:#f8f8f2}.hljs-subst,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#ae81ff}.hljs-code,.hljs-section,.hljs-selector-class,.hljs-title{color:#a6e22e}.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}.hljs-attr,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f92672}.hljs-attribute,.hljs-symbol{color:#66d9ef}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_{color:#f8f8f2}.hljs-addition,.hljs-built_in,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-variable,.hljs-type,.hljs-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#272822;color:#ddd}.hljs-keyword,.hljs-literal,.hljs-name,.hljs-number,.hljs-selector-tag,.hljs-strong,.hljs-tag{color:#f92672}.hljs-code{color:#66d9ef}.hljs-attr,.hljs-attribute,.hljs-link,.hljs-regexp,.hljs-symbol{color:#bf79db}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-emphasis,.hljs-section,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string,.hljs-subst,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#a6e22e}.hljs-class .hljs-title,.hljs-title.class_{color:#fff}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#75715e}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-section,.hljs-selector-id,.hljs-selector-tag,.hljs-title,.hljs-type{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#011627;color:#d6deeb}.hljs-keyword{color:#c792ea;font-style:italic}.hljs-built_in{color:#addb67;font-style:italic}.hljs-type{color:#82aaff}.hljs-literal{color:#ff5874}.hljs-number{color:#f78c6c}.hljs-regexp{color:#5ca7e4}.hljs-string{color:#ecc48d}.hljs-subst{color:#d3423e}.hljs-symbol{color:#82aaff}.hljs-class{color:#ffcb8b}.hljs-function{color:#82aaff}.hljs-title{color:#dcdcaa;font-style:italic}.hljs-params{color:#7fdbca}.hljs-comment{color:#637777;font-style:italic}.hljs-doctag{color:#7fdbca}.hljs-meta,.hljs-meta .hljs-keyword{color:#82aaff}.hljs-meta .hljs-string{color:#ecc48d}.hljs-section{color:#82b1ff}.hljs-attr,.hljs-name,.hljs-tag{color:#7fdbca}.hljs-attribute{color:#80cbc4}.hljs-variable{color:#addb67}.hljs-bullet{color:#d9f5dd}.hljs-code{color:#80cbc4}.hljs-emphasis{color:#c792ea;font-style:italic}.hljs-strong{color:#addb67;font-weight:700}.hljs-formula{color:#c792ea}.hljs-link{color:#ff869a}.hljs-quote{color:#697098;font-style:italic}.hljs-selector-tag{color:#ff6363}.hljs-selector-id{color:#fad430}.hljs-selector-class{color:#addb67;font-style:italic}.hljs-selector-attr,.hljs-selector-pseudo{color:#c792ea;font-style:italic}.hljs-template-tag{color:#c792ea}.hljs-template-variable{color:#addb67}.hljs-addition{color:#addb67ff;font-style:italic}.hljs-deletion{color:#ef535090;font-style:italic}
+10
View File
@@ -0,0 +1,10 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: nnfx dark
Description: a theme inspired by Netscape Navigator/Firefox
Author: (c) 2020-2021 Jim Mason <jmason@ibinx.com>
Maintainer: @RocketMan
License: https://creativecommons.org/licenses/by-sa/4.0 CC BY-SA 4.0
Updated: 2021-05-17
@version 1.1.0
*/.hljs{background:#333;color:#fff}.language-xml .hljs-meta,.language-xml .hljs-meta-string{font-weight:700;font-style:italic;color:#69f}.hljs-comment,.hljs-quote{font-style:italic;color:#9c6}.hljs-built_in,.hljs-keyword,.hljs-name{color:#a7a}.hljs-attr,.hljs-name{font-weight:700}.hljs-string{font-weight:400}.hljs-code,.hljs-link,.hljs-meta .hljs-string,.hljs-number,.hljs-regexp,.hljs-string{color:#bce}.hljs-bullet,.hljs-symbol,.hljs-template-variable,.hljs-title,.hljs-variable{color:#d40}.hljs-class .hljs-title,.hljs-title.class_,.hljs-type{font-weight:700;color:#96c}.hljs-attr,.hljs-function .hljs-title,.hljs-subst,.hljs-tag,.hljs-title.function_{color:#fff}.hljs-formula{background-color:#eee;font-style:italic}.hljs-addition{background-color:#797}.hljs-deletion{background-color:#c99}.hljs-meta{color:#69f}.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-selector-tag{font-weight:700;color:#69f}.hljs-selector-pseudo{font-style:italic}.hljs-doctag,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
+10
View File
@@ -0,0 +1,10 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: nnfx light
Description: a theme inspired by Netscape Navigator/Firefox
Author: (c) 2020-2021 Jim Mason <jmason@ibinx.com>
Maintainer: @RocketMan
License: https://creativecommons.org/licenses/by-sa/4.0 CC BY-SA 4.0
Updated: 2021-05-17
@version 1.1.0
*/.hljs{background:#fff;color:#000}.language-xml .hljs-meta,.language-xml .hljs-meta-string{font-weight:700;font-style:italic;color:#48b}.hljs-comment,.hljs-quote{font-style:italic;color:#070}.hljs-built_in,.hljs-keyword,.hljs-name{color:#808}.hljs-attr,.hljs-name{font-weight:700}.hljs-string{font-weight:400}.hljs-code,.hljs-link,.hljs-meta .hljs-string,.hljs-number,.hljs-regexp,.hljs-string{color:#00f}.hljs-bullet,.hljs-symbol,.hljs-template-variable,.hljs-title,.hljs-variable{color:#f40}.hljs-class .hljs-title,.hljs-title.class_,.hljs-type{font-weight:700;color:#639}.hljs-attr,.hljs-function .hljs-title,.hljs-subst,.hljs-tag,.hljs-title.function_{color:#000}.hljs-formula{background-color:#eee;font-style:italic}.hljs-addition{background-color:#beb}.hljs-deletion{background-color:#fbb}.hljs-meta{color:#269}.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-selector-tag{font-weight:700;color:#48b}.hljs-selector-pseudo{font-style:italic}.hljs-doctag,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2e3440}.hljs,.hljs-subst{color:#d8dee9}.hljs-selector-tag{color:#81a1c1}.hljs-selector-id{color:#8fbcbb;font-weight:700}.hljs-selector-attr,.hljs-selector-class{color:#8fbcbb}.hljs-property,.hljs-selector-pseudo{color:#88c0d0}.hljs-addition{background-color:rgba(163,190,140,.5)}.hljs-deletion{background-color:rgba(191,97,106,.5)}.hljs-built_in,.hljs-class,.hljs-type{color:#8fbcbb}.hljs-function,.hljs-function>.hljs-title,.hljs-title.hljs-function{color:#88c0d0}.hljs-keyword,.hljs-literal,.hljs-symbol{color:#81a1c1}.hljs-number{color:#b48ead}.hljs-regexp{color:#ebcb8b}.hljs-string{color:#a3be8c}.hljs-title{color:#8fbcbb}.hljs-params{color:#d8dee9}.hljs-bullet{color:#81a1c1}.hljs-code{color:#8fbcbb}.hljs-emphasis{font-style:italic}.hljs-formula{color:#8fbcbb}.hljs-strong{font-weight:700}.hljs-link:hover{text-decoration:underline}.hljs-comment,.hljs-quote{color:#4c566a}.hljs-doctag{color:#8fbcbb}.hljs-meta,.hljs-meta .hljs-keyword{color:#5e81ac}.hljs-meta .hljs-string{color:#a3be8c}.hljs-attr{color:#8fbcbb}.hljs-attribute{color:#d8dee9}.hljs-name{color:#81a1c1}.hljs-section{color:#88c0d0}.hljs-tag{color:#81a1c1}.hljs-template-variable,.hljs-variable{color:#d8dee9}.hljs-template-tag{color:#5e81ac}.language-abnf .hljs-attribute{color:#88c0d0}.language-abnf .hljs-symbol{color:#ebcb8b}.language-apache .hljs-attribute{color:#88c0d0}.language-apache .hljs-section{color:#81a1c1}.language-arduino .hljs-built_in{color:#88c0d0}.language-aspectj .hljs-meta{color:#d08770}.language-aspectj>.hljs-title{color:#88c0d0}.language-bnf .hljs-attribute{color:#8fbcbb}.language-clojure .hljs-name{color:#88c0d0}.language-clojure .hljs-symbol{color:#ebcb8b}.language-coq .hljs-built_in{color:#88c0d0}.language-cpp .hljs-meta .hljs-string{color:#8fbcbb}.language-css .hljs-built_in{color:#88c0d0}.language-css .hljs-keyword{color:#d08770}.language-diff .hljs-meta,.language-ebnf .hljs-attribute{color:#8fbcbb}.language-glsl .hljs-built_in{color:#88c0d0}.language-groovy .hljs-meta:not(:first-child),.language-haxe .hljs-meta,.language-java .hljs-meta{color:#d08770}.language-ldif .hljs-attribute{color:#8fbcbb}.language-lisp .hljs-name,.language-lua .hljs-built_in,.language-moonscript .hljs-built_in,.language-nginx .hljs-attribute{color:#88c0d0}.language-nginx .hljs-section{color:#5e81ac}.language-pf .hljs-built_in,.language-processing .hljs-built_in{color:#88c0d0}.language-scss .hljs-keyword,.language-stylus .hljs-keyword{color:#81a1c1}.language-swift .hljs-meta{color:#d08770}.language-vim .hljs-built_in{color:#88c0d0;font-style:italic}.language-yaml .hljs-meta{color:#d08770}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#e0e2e4;background:#282b2e}.hljs-keyword,.hljs-literal,.hljs-selector-id,.hljs-selector-tag{color:#93c763}.hljs-number{color:#ffcd22}.hljs-attribute{color:#668bb0}.hljs-link,.hljs-regexp{color:#d39745}.hljs-meta{color:#557182}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-emphasis,.hljs-name,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-subst,.hljs-tag,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable{color:#8cbbad}.hljs-string,.hljs-symbol{color:#ec7600}.hljs-comment,.hljs-deletion,.hljs-quote{color:#818e96}.hljs-selector-class{color:#a082bd}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.hljs-class .hljs-title,.hljs-code,.hljs-section,.hljs-title.class_{color:#fff}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#e6e6e6;background:#2a2c2d}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}.hljs-comment,.hljs-quote{color:#bbb;font-style:italic}.hljs-params{color:#bbb}.hljs-attr,.hljs-punctuation{color:#e6e6e6}.hljs-meta,.hljs-name,.hljs-selector-tag{color:#ff4b82}.hljs-char.escape_,.hljs-operator{color:#b084eb}.hljs-deletion,.hljs-keyword{color:#ff75b5}.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-variable.language_{color:#ff9ac1}.hljs-code,.hljs-formula,.hljs-property,.hljs-section,.hljs-subst,.hljs-title.function_{color:#45a9f9}.hljs-addition,.hljs-bullet,.hljs-meta .hljs-string,.hljs-selector-class,.hljs-string,.hljs-symbol,.hljs-title.class_,.hljs-title.class_.inherited__{color:#19f9d8}.hljs-attribute,.hljs-built_in,.hljs-doctag,.hljs-link,.hljs-literal,.hljs-meta .hljs-keyword,.hljs-number,.hljs-punctuation,.hljs-selector-id,.hljs-tag,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#ffb86c}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#2a2c2d;background:#e6e6e6}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}.hljs-comment,.hljs-quote{color:#676b79;font-style:italic}.hljs-params{color:#676b79}.hljs-attr,.hljs-punctuation{color:#2a2c2d}.hljs-char.escape_,.hljs-meta,.hljs-name,.hljs-operator,.hljs-selector-tag{color:#c56200}.hljs-deletion,.hljs-keyword{color:#d92792}.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-variable.language_{color:#cc5e91}.hljs-code,.hljs-formula,.hljs-property,.hljs-section,.hljs-subst,.hljs-title.function_{color:#3787c7}.hljs-addition,.hljs-bullet,.hljs-meta .hljs-string,.hljs-selector-class,.hljs-string,.hljs-symbol,.hljs-title.class_,.hljs-title.class_.inherited__{color:#0d7d6c}.hljs-attribute,.hljs-built_in,.hljs-doctag,.hljs-link,.hljs-literal,.hljs-meta .hljs-keyword,.hljs-number,.hljs-selector-id,.hljs-tag,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#7641bb}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2f1e2e;color:#a39e9b}.hljs-comment,.hljs-quote{color:#8d8687}.hljs-link,.hljs-meta,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ef6155}.hljs-built_in,.hljs-deletion,.hljs-literal,.hljs-number,.hljs-params,.hljs-type{color:#f99b15}.hljs-attribute,.hljs-section,.hljs-title{color:#fec418}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#48b685}.hljs-keyword,.hljs-selector-tag{color:#815ba4}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#e7e9db;color:#4f424c}.hljs-comment,.hljs-quote{color:#776e71}.hljs-link,.hljs-meta,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ef6155}.hljs-built_in,.hljs-deletion,.hljs-literal,.hljs-number,.hljs-params,.hljs-type{color:#f99b15}.hljs-attribute,.hljs-section,.hljs-title{color:#fec418}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#48b685}.hljs-keyword,.hljs-selector-tag{color:#815ba4}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#dccf8f;background:url(./pojoaque.jpg) left top #181914}.hljs-comment,.hljs-quote{color:#586e75;font-style:italic}.hljs-addition,.hljs-keyword,.hljs-literal,.hljs-selector-tag{color:#b64926}.hljs-doctag,.hljs-number,.hljs-regexp,.hljs-string{color:#468966}.hljs-built_in,.hljs-name,.hljs-section,.hljs-title{color:#ffb03b}.hljs-class .hljs-title,.hljs-tag,.hljs-template-variable,.hljs-title.class_,.hljs-type,.hljs-variable{color:#b58900}.hljs-attribute{color:#b89859}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-subst,.hljs-symbol{color:#cb4b16}.hljs-deletion{color:#dc322f}.hljs-selector-class,.hljs-selector-id{color:#d3a60c}.hljs-formula{background:#073642}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#ffffdf}.hljs,.hljs-attr,.hljs-function,.hljs-name,.hljs-number,.hljs-params,.hljs-subst,.hljs-type{color:#000}.hljs-addition,.hljs-comment,.hljs-regexp,.hljs-section,.hljs-selector-pseudo{color:#0aa}.hljs-built_in,.hljs-class,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-selector-class{color:#066;font-weight:700}.hljs-code,.hljs-tag,.hljs-title,.hljs-variable{color:#066}.hljs-selector-attr,.hljs-string{color:#0080ff}.hljs-attribute,.hljs-deletion,.hljs-link,.hljs-symbol{color:#924b72}.hljs-literal,.hljs-meta,.hljs-selector-id{color:#924b72;font-weight:700}.hljs-name,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#aaa;background:#000}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#f5f}.hljs-code .hljs-selector-class{color:#aaf}.hljs-emphasis,.hljs-stronge,.hljs-type{font-style:italic}.hljs-function,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-symbol{color:#ff5}.hljs-subst,.hljs-tag,.hljs-title{color:#aaa}.hljs-attribute{color:#f55}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_,.hljs-variable{color:#88f}.hljs-addition,.hljs-built_in,.hljs-link,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:#f5f}.hljs-comment,.hljs-deletion,.hljs-meta{color:#5ff}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#000;background:#fff}.hljs-emphasis,.hljs-strong{color:#000}.hljs-bullet,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:navy}.hljs-code .hljs-selector-class{color:purple}.hljs-emphasis,.hljs-stronge,.hljs-type{font-style:italic}.hljs-function,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-symbol{color:olive}.hljs-subst,.hljs-tag,.hljs-title{color:#000}.hljs-attribute{color:maroon}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_,.hljs-variable{color:#0055af}.hljs-addition,.hljs-built_in,.hljs-comment,.hljs-deletion,.hljs-link,.hljs-meta,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-type{color:green}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#474949;color:#d1d9e1}.hljs-comment,.hljs-quote{color:#969896;font-style:italic}.hljs-addition,.hljs-keyword,.hljs-literal,.hljs-selector-tag,.hljs-type{color:#c9c}.hljs-number,.hljs-selector-attr,.hljs-selector-pseudo{color:#f99157}.hljs-doctag,.hljs-regexp,.hljs-string{color:#8abeb7}.hljs-built_in,.hljs-name,.hljs-section,.hljs-title{color:#b5bd68}.hljs-class .hljs-title,.hljs-selector-id,.hljs-template-variable,.hljs-title.class_,.hljs-variable{color:#fc6}.hljs-name,.hljs-section,.hljs-strong{font-weight:700}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-subst,.hljs-symbol{color:#f99157}.hljs-deletion{color:#dc322f}.hljs-formula{background:#eee8d5}.hljs-attr,.hljs-attribute{color:#81a2be}.hljs-emphasis{font-style:italic}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#444;background:#f0f0f0}.hljs-subst{color:#444}.hljs-comment{color:#888}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-attribute{color:#0e9a00}.hljs-function{color:#99069a}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#bc6060}.hljs-literal{color:#78a960}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#0c9a9a}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#3e5915;background:#f6f5b2}.hljs-keyword,.hljs-literal,.hljs-selector-tag{color:#059}.hljs-subst{color:#3e5915}.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-link,.hljs-section,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#2c009f}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#e60415}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-id,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.hljs-emphasis{font-style:italic}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2d2b57;color:#e3dfff;font-weight:400}.hljs-subst{color:#e3dfff}.hljs-title{color:#fad000;font-weight:400}.hljs-name{color:#a1feff}.hljs-tag{color:#fff}.hljs-attr{color:#f8d000;font-style:italic}.hljs-built_in,.hljs-keyword,.hljs-section,.hljs-selector-tag{color:#fb9e00}.hljs-addition,.hljs-attribute,.hljs-bullet,.hljs-code,.hljs-deletion,.hljs-quote,.hljs-regexp,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-string,.hljs-symbol,.hljs-template-tag{color:#4cd213}.hljs-meta,.hljs-meta .hljs-string{color:#fb9e00}.hljs-comment{color:#ac65ff}.hljs-keyword,.hljs-literal,.hljs-name,.hljs-selector-tag,.hljs-strong{font-weight:400}.hljs-literal,.hljs-number{color:#fa658d}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#1c1b19;color:#fce8c3}.hljs-literal,.hljs-quote,.hljs-subst{color:#fce8c3}.hljs-symbol,.hljs-type{color:#68a8e4}.hljs-deletion,.hljs-keyword{color:#ef2f27}.hljs-attribute,.hljs-function,.hljs-name,.hljs-section,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#fbb829}.hljs-class,.hljs-code,.hljs-property,.hljs-template-variable,.hljs-variable{color:#0aaeb3}.hljs-addition,.hljs-bullet,.hljs-regexp,.hljs-string{color:#98bc37}.hljs-built_in,.hljs-params{color:#ff5c8f}.hljs-selector-tag,.hljs-template-tag{color:#2c78bf}.hljs-comment,.hljs-link,.hljs-meta,.hljs-number{color:#918175}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1,13 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: StackOverflow Dark
Description: Dark theme as used on stackoverflow.com
Author: stackoverflow.com
Maintainer: @Hirse
Website: https://github.com/StackExchange/Stacks
License: MIT
Updated: 2021-05-15
Updated for @stackoverflow/stacks v0.64.0
Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
*/.hljs{color:#fff;background:#1c1b1b}.hljs-subst{color:#fff}.hljs-comment{color:#999}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#88aece}.hljs-attribute{color:#c59bc1}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#f08d49}.hljs-selector-class{color:#88aece}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#b5bd68}.hljs-meta,.hljs-selector-pseudo{color:#88aece}.hljs-built_in,.hljs-literal,.hljs-title{color:#f08d49}.hljs-bullet,.hljs-code{color:#ccc}.hljs-meta .hljs-string{color:#b5bd68}.hljs-deletion{color:#de7176}.hljs-addition{color:#76c490}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1,13 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: StackOverflow Light
Description: Light theme as used on stackoverflow.com
Author: stackoverflow.com
Maintainer: @Hirse
Website: https://github.com/StackExchange/Stacks
License: MIT
Updated: 2021-05-15
Updated for @stackoverflow/stacks v0.64.0
Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
*/.hljs{color:#2f3337;background:#f6f6f6}.hljs-subst{color:#2f3337}.hljs-comment{color:#656e77}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#015692}.hljs-attribute{color:#803378}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#b75501}.hljs-selector-class{color:#015692}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#54790d}.hljs-meta,.hljs-selector-pseudo{color:#015692}.hljs-built_in,.hljs-literal,.hljs-title{color:#b75501}.hljs-bullet,.hljs-code{color:#535a60}.hljs-meta .hljs-string{color:#54790d}.hljs-deletion{color:#c02d2e}.hljs-addition{color:#2f6f44}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#000;color:#f8f8f8}.hljs-comment,.hljs-quote{color:#aeaeae;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#e28964}.hljs-string{color:#65b042}.hljs-subst{color:#daefa3}.hljs-link,.hljs-regexp{color:#e9c062}.hljs-name,.hljs-section,.hljs-tag,.hljs-title{color:#89bdff}.hljs-class .hljs-title,.hljs-doctag,.hljs-title.class_{text-decoration:underline}.hljs-bullet,.hljs-number,.hljs-symbol{color:#3387cc}.hljs-params,.hljs-template-variable,.hljs-variable{color:#3e87e3}.hljs-attribute{color:#cda869}.hljs-meta{color:#8996a8}.hljs-formula{background-color:#0e2231;color:#f8f8f8;font-style:italic}.hljs-addition{background-color:#253b22;color:#f8f8f8}.hljs-deletion{background-color:#420e09;color:#f8f8f8}.hljs-selector-class{color:#9b703f}.hljs-selector-id{color:#8b98ab}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1,8 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: Tokyo-night-Dark
origin: https://github.com/enkia/tokyo-night-vscode-theme
Description: Original highlight.js style
Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
License: see project LICENSE
Touched: 2022
*/.hljs-comment,.hljs-meta{color:#565f89}.hljs-deletion,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-tag,.hljs-template-tag,.hljs-variable.language_{color:#f7768e}.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-template-variable,.hljs-type,.hljs-variable{color:#ff9e64}.hljs-attribute,.hljs-built_in{color:#e0af68}.hljs-keyword,.hljs-property,.hljs-subst,.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#7dcfff}.hljs-selector-tag{color:#73daca}.hljs-addition,.hljs-bullet,.hljs-quote,.hljs-string,.hljs-symbol{color:#9ece6a}.hljs-code,.hljs-formula,.hljs-section{color:#7aa2f7}.hljs-attr,.hljs-char.escape_,.hljs-keyword,.hljs-name,.hljs-operator{color:#bb9af7}.hljs-punctuation{color:#c0caf5}.hljs{background:#1a1b26;color:#9aa5ce}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1,8 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: Tokyo-night-light
origin: https://github.com/enkia/tokyo-night-vscode-theme
Description: Original highlight.js style
Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
License: see project LICENSE
Touched: 2022
*/.hljs-comment,.hljs-meta{color:#9699a3}.hljs-deletion,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-tag,.hljs-template-tag,.hljs-variable.language_{color:#8c4351}.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-template-variable,.hljs-type,.hljs-variable{color:#965027}.hljs-attribute,.hljs-built_in{color:#8f5e15}.hljs-keyword,.hljs-property,.hljs-subst,.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#0f4b6e}.hljs-selector-tag{color:#33635c}.hljs-addition,.hljs-bullet,.hljs-quote,.hljs-string,.hljs-symbol{color:#485e30}.hljs-code,.hljs-formula,.hljs-section{color:#34548a}.hljs-attr,.hljs-char.escape_,.hljs-keyword,.hljs-name,.hljs-operator{color:#5a4a78}.hljs-punctuation{color:#343b58}.hljs{background:#d5d6db;color:#565a6e}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs-comment,.hljs-quote{color:#7285b7}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ff9da4}.hljs-built_in,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#ffc58f}.hljs-attribute{color:#ffeead}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#d1f1a9}.hljs-section,.hljs-title{color:#bbdaff}.hljs-keyword,.hljs-selector-tag{color:#ebbbff}.hljs{background:#002451;color:#fff}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs-comment,.hljs-quote{color:#969896}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#d54e53}.hljs-built_in,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#e78c45}.hljs-attribute{color:#e7c547}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#b9ca4a}.hljs-section,.hljs-title{color:#7aa6da}.hljs-keyword,.hljs-selector-tag{color:#c397d8}.hljs{background:#000;color:#eaeaea}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#000}.hljs-comment,.hljs-quote,.hljs-variable{color:green}.hljs-built_in,.hljs-keyword,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#00f}.hljs-addition,.hljs-attribute,.hljs-literal,.hljs-section,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type{color:#a31515}.hljs-deletion,.hljs-meta,.hljs-selector-attr,.hljs-selector-pseudo{color:#2b91af}.hljs-doctag{color:grey}.hljs-attr{color:red}.hljs-bullet,.hljs-link,.hljs-symbol{color:#00b0e8}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#1e1e1e;color:#dcdcdc}.hljs-keyword,.hljs-literal,.hljs-name,.hljs-symbol{color:#569cd6}.hljs-link{color:#569cd6;text-decoration:underline}.hljs-built_in,.hljs-type{color:#4ec9b0}.hljs-class,.hljs-number{color:#b8d7a3}.hljs-meta .hljs-string,.hljs-string{color:#d69d85}.hljs-regexp,.hljs-template-tag{color:#9a5334}.hljs-formula,.hljs-function,.hljs-params,.hljs-subst,.hljs-title{color:#dcdcdc}.hljs-comment,.hljs-quote{color:#57a64a;font-style:italic}.hljs-doctag{color:#608b4e}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-tag{color:#9b9b9b}.hljs-template-variable,.hljs-variable{color:#bd63c5}.hljs-attr,.hljs-attribute{color:#9cdcfe}.hljs-section{color:gold}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-bullet,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-selector-tag{color:#d7ba7d}.hljs-addition{background-color:#144212;display:inline-block;width:100%}.hljs-deletion{background-color:#600;display:inline-block;width:100%}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#fff;color:#000}.xml .hljs-meta{color:silver}.hljs-comment,.hljs-quote{color:#007400}.hljs-attribute,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#aa0d91}.hljs-template-variable,.hljs-variable{color:#3f6e74}.hljs-code,.hljs-meta .hljs-string,.hljs-string{color:#c41a16}.hljs-link,.hljs-regexp{color:#0e0eff}.hljs-bullet,.hljs-number,.hljs-symbol,.hljs-title{color:#1c00cf}.hljs-meta,.hljs-section{color:#643820}.hljs-built_in,.hljs-class .hljs-title,.hljs-params,.hljs-title.class_,.hljs-type{color:#5c2699}.hljs-attr{color:#836c28}.hljs-subst{color:#000}.hljs-formula{background-color:#eee;font-style:italic}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-selector-class,.hljs-selector-id{color:#9b703f}.hljs-doctag,.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}
+1
View File
@@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#eaeaea;background:#000}.hljs-subst{color:#eaeaea}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-type{color:#eaeaea}.hljs-params{color:#da0000}.hljs-literal,.hljs-name,.hljs-number{color:red;font-weight:bolder}.hljs-comment{color:#969896}.hljs-quote,.hljs-selector-id{color:#0ff}.hljs-template-variable,.hljs-title,.hljs-variable{color:#0ff;font-weight:700}.hljs-keyword,.hljs-selector-class,.hljs-symbol{color:#fff000}.hljs-bullet,.hljs-string{color:#0f0}.hljs-section,.hljs-tag{color:#000fff}.hljs-selector-tag{color:#000fff;font-weight:700}.hljs-attribute,.hljs-built_in,.hljs-link,.hljs-regexp{color:#f0f}.hljs-meta{color:#fff;font-weight:bolder}
+84
View File
@@ -0,0 +1,84 @@
import type { StyleConfig } from "./types.js";
export const FONT_FAMILY_MAP: Record<string, string> = {
sans: `-apple-system-font,BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB , Microsoft YaHei UI , Microsoft YaHei ,Arial,sans-serif`,
serif: `Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif`,
"serif-cjk": `"Source Han Serif SC", "Noto Serif CJK SC", "Source Han Serif CN", STSong, SimSun, serif`,
mono: `Menlo, Monaco, 'Courier New', monospace`,
};
export const FONT_SIZE_OPTIONS = ["14px", "15px", "16px", "17px", "18px"];
export const COLOR_PRESETS: Record<string, string> = {
blue: "#0F4C81",
green: "#009874",
vermilion: "#FA5151",
yellow: "#FECE00",
purple: "#92617E",
sky: "#55C9EA",
rose: "#B76E79",
olive: "#556B2F",
black: "#333333",
gray: "#A9A9A9",
pink: "#FFB7C5",
red: "#A93226",
orange: "#D97757",
};
export const CODE_BLOCK_THEMES = [
"1c-light", "a11y-dark", "a11y-light", "agate", "an-old-hope",
"androidstudio", "arduino-light", "arta", "ascetic",
"atom-one-dark-reasonable", "atom-one-dark", "atom-one-light",
"brown-paper", "codepen-embed", "color-brewer", "dark", "default",
"devibeans", "docco", "far", "felipec", "foundation",
"github-dark-dimmed", "github-dark", "github", "gml", "googlecode",
"gradient-dark", "gradient-light", "grayscale", "hybrid", "idea",
"intellij-light", "ir-black", "isbl-editor-dark", "isbl-editor-light",
"kimbie-dark", "kimbie-light", "lightfair", "lioshi", "magula",
"mono-blue", "monokai-sublime", "monokai", "night-owl", "nnfx-dark",
"nnfx-light", "nord", "obsidian", "panda-syntax-dark",
"panda-syntax-light", "paraiso-dark", "paraiso-light", "pojoaque",
"purebasic", "qtcreator-dark", "qtcreator-light", "rainbow", "routeros",
"school-book", "shades-of-purple", "srcery", "stackoverflow-dark",
"stackoverflow-light", "sunburst", "tokyo-night-dark", "tokyo-night-light",
"tomorrow-night-blue", "tomorrow-night-bright", "vs", "vs2015", "xcode",
"xt256",
];
export const DEFAULT_STYLE: StyleConfig = {
primaryColor: "#0F4C81",
fontFamily: FONT_FAMILY_MAP.sans!,
fontSize: "16px",
foreground: "0 0% 3.9%",
blockquoteBackground: "#f7f7f7",
accentColor: "#6B7280",
containerBg: "transparent",
};
export const THEME_STYLE_DEFAULTS: Record<string, Partial<StyleConfig>> = {
default: {
primaryColor: COLOR_PRESETS.blue,
},
grace: {
primaryColor: COLOR_PRESETS.purple,
},
simple: {
primaryColor: COLOR_PRESETS.green,
},
modern: {
primaryColor: COLOR_PRESETS.orange,
accentColor: "#E4B1A0",
containerBg: "rgba(250, 249, 245, 1)",
fontFamily: FONT_FAMILY_MAP.sans,
fontSize: "15px",
blockquoteBackground: "rgba(255, 255, 255, 0.6)",
},
};
export const macCodeSvg = `
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" width="45px" height="13px" viewBox="0 0 450 130">
<ellipse cx="50" cy="65" rx="50" ry="52" stroke="rgb(220,60,54)" stroke-width="2" fill="rgb(237,108,96)" />
<ellipse cx="225" cy="65" rx="50" ry="52" stroke="rgb(218,151,33)" stroke-width="2" fill="rgb(247,193,81)" />
<ellipse cx="400" cy="65" rx="50" ry="52" stroke="rgb(27,161,37)" stroke-width="2" fill="rgb(100,200,86)" />
</svg>
`.trim();
+105
View File
@@ -0,0 +1,105 @@
import { Lexer } from "marked";
export type FrontmatterFields = Record<string, string>;
export function parseFrontmatter(content: string): {
frontmatter: FrontmatterFields;
body: string;
} {
const match = content.match(/^\s*---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
if (!match) {
return { frontmatter: {}, body: content };
}
const frontmatter: FrontmatterFields = {};
const lines = match[1]!.split("\n");
for (const line of lines) {
const colonIdx = line.indexOf(":");
if (colonIdx <= 0) continue;
const key = line.slice(0, colonIdx).trim();
const value = line.slice(colonIdx + 1).trim();
frontmatter[key] = stripWrappingQuotes(value);
}
return { frontmatter, body: match[2]! };
}
export function serializeFrontmatter(frontmatter: FrontmatterFields): string {
const entries = Object.entries(frontmatter);
if (entries.length === 0) return "";
return `---\n${entries.map(([key, value]) => `${key}: ${value}`).join("\n")}\n---\n`;
}
export function stripWrappingQuotes(value: string): string {
if (!value) return value;
const doubleQuoted = value.startsWith('"') && value.endsWith('"');
const singleQuoted = value.startsWith("'") && value.endsWith("'");
const cjkDoubleQuoted = value.startsWith("\u201c") && value.endsWith("\u201d");
const cjkSingleQuoted = value.startsWith("\u2018") && value.endsWith("\u2019");
if (doubleQuoted || singleQuoted || cjkDoubleQuoted || cjkSingleQuoted) {
return value.slice(1, -1).trim();
}
return value.trim();
}
export function toFrontmatterString(value: unknown): string | undefined {
if (typeof value === "string") {
return stripWrappingQuotes(value);
}
if (typeof value === "number" || typeof value === "boolean") {
return String(value);
}
return undefined;
}
export function pickFirstString(
frontmatter: Record<string, unknown>,
keys: string[],
): string | undefined {
for (const key of keys) {
const value = toFrontmatterString(frontmatter[key]);
if (value) return value;
}
return undefined;
}
export function extractTitleFromMarkdown(markdown: string): string {
const tokens = Lexer.lex(markdown, { gfm: true, breaks: true });
for (const token of tokens) {
if (token.type !== "heading" || (token.depth !== 1 && token.depth !== 2)) continue;
return stripWrappingQuotes(token.text);
}
return "";
}
export function extractSummaryFromBody(body: string, maxLen: number): string {
const lines = body.split("\n");
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed.startsWith("#")) continue;
if (trimmed.startsWith("![")) continue;
if (trimmed.startsWith(">")) continue;
if (trimmed.startsWith("-") || trimmed.startsWith("*")) continue;
if (/^\d+\./.test(trimmed)) continue;
if (trimmed.startsWith("```")) continue;
const cleanText = trimmed
.replace(/\*\*(.+?)\*\*/g, "$1")
.replace(/\*(.+?)\*/g, "$1")
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
.replace(/`([^`]+)`/g, "$1");
if (cleanText.length > 20) {
if (cleanText.length <= maxLen) return cleanText;
return `${cleanText.slice(0, maxLen - 3)}...`;
}
}
return "";
}
+206
View File
@@ -0,0 +1,206 @@
import fs from "node:fs";
import path from "node:path";
import type { ReadTimeResults } from "reading-time";
import {
COLOR_PRESETS,
DEFAULT_STYLE,
FONT_FAMILY_MAP,
THEME_STYLE_DEFAULTS,
} from "./constants.js";
import {
extractSummaryFromBody,
extractTitleFromMarkdown,
pickFirstString,
stripWrappingQuotes,
} from "./content.js";
import { loadExtendConfig } from "./extend-config.js";
import {
buildCss,
buildHtmlDocument,
inlineCss,
loadCodeThemeCss,
modifyHtmlStructure,
normalizeInlineCss,
removeFirstHeading,
} from "./html-builder.js";
import { initRenderer, postProcessHtml, renderMarkdown } from "./renderer.js";
import { loadThemeCss, normalizeThemeCss } from "./themes.js";
import type { HtmlDocumentMeta, IOpts, StyleConfig, ThemeName } from "./types.js";
export interface RenderMarkdownDocumentOptions {
codeTheme?: string;
countStatus?: boolean;
citeStatus?: boolean;
defaultTitle?: string;
fontFamily?: string;
fontSize?: string;
isMacCodeBlock?: boolean;
isShowLineNumber?: boolean;
keepTitle?: boolean;
legend?: string;
primaryColor?: string;
theme?: ThemeName;
themeMode?: IOpts["themeMode"];
}
export interface RenderMarkdownDocumentResult {
contentHtml: string;
html: string;
meta: HtmlDocumentMeta;
readingTime: ReadTimeResults;
style: StyleConfig;
yamlData: Record<string, unknown>;
}
export function resolveColorToken(value?: string): string | undefined {
if (!value) return undefined;
return COLOR_PRESETS[value] ?? value;
}
export function resolveFontFamilyToken(value?: string): string | undefined {
if (!value) return undefined;
return FONT_FAMILY_MAP[value] ?? value;
}
export function formatTimestamp(date = new Date()): string {
const pad = (value: number) => String(value).padStart(2, "0");
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(
date.getDate(),
)}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
}
export function buildMarkdownDocumentMeta(
markdown: string,
yamlData: Record<string, unknown>,
defaultTitle = "document",
): HtmlDocumentMeta {
const title = pickFirstString(yamlData, ["title"])
|| extractTitleFromMarkdown(markdown)
|| defaultTitle;
const author = pickFirstString(yamlData, ["author"]);
const description = pickFirstString(yamlData, ["description", "summary"])
|| extractSummaryFromBody(markdown, 120);
return {
title: stripWrappingQuotes(title),
author: author ? stripWrappingQuotes(author) : undefined,
description: description ? stripWrappingQuotes(description) : undefined,
};
}
export function resolveMarkdownStyle(options: RenderMarkdownDocumentOptions = {}): StyleConfig {
const theme = options.theme ?? "default";
const themeDefaults = THEME_STYLE_DEFAULTS[theme] ?? {};
return {
...DEFAULT_STYLE,
...themeDefaults,
...(options.primaryColor !== undefined ? { primaryColor: options.primaryColor } : {}),
...(options.fontFamily !== undefined ? { fontFamily: options.fontFamily } : {}),
...(options.fontSize !== undefined ? { fontSize: options.fontSize } : {}),
};
}
export function resolveRenderOptions(
options: RenderMarkdownDocumentOptions = {},
): RenderMarkdownDocumentOptions {
const extendConfig = loadExtendConfig();
return {
codeTheme: options.codeTheme ?? extendConfig.default_code_theme ?? "github",
countStatus: options.countStatus ?? extendConfig.count ?? false,
citeStatus: options.citeStatus ?? extendConfig.cite ?? false,
defaultTitle: options.defaultTitle,
fontFamily: options.fontFamily ?? resolveFontFamilyToken(extendConfig.default_font_family ?? undefined),
fontSize: options.fontSize ?? extendConfig.default_font_size ?? undefined,
isMacCodeBlock: options.isMacCodeBlock ?? extendConfig.mac_code_block ?? true,
isShowLineNumber: options.isShowLineNumber ?? extendConfig.show_line_number ?? false,
keepTitle: options.keepTitle ?? extendConfig.keep_title ?? false,
legend: options.legend ?? extendConfig.legend ?? "alt",
primaryColor: options.primaryColor ?? resolveColorToken(extendConfig.default_color ?? undefined),
theme: options.theme ?? extendConfig.default_theme ?? "default",
themeMode: options.themeMode,
};
}
export async function renderMarkdownDocument(
markdown: string,
options: RenderMarkdownDocumentOptions = {},
): Promise<RenderMarkdownDocumentResult> {
const resolvedOptions = resolveRenderOptions(options);
const theme = resolvedOptions.theme ?? "default";
const codeTheme = resolvedOptions.codeTheme ?? "github";
const style = resolveMarkdownStyle(resolvedOptions);
const { baseCss, themeCss } = loadThemeCss(theme);
const css = normalizeThemeCss(buildCss(baseCss, themeCss, style));
const codeThemeCss = loadCodeThemeCss(codeTheme);
const renderer = initRenderer({
citeStatus: resolvedOptions.citeStatus ?? false,
countStatus: resolvedOptions.countStatus ?? false,
isMacCodeBlock: resolvedOptions.isMacCodeBlock ?? true,
isShowLineNumber: resolvedOptions.isShowLineNumber ?? false,
legend: resolvedOptions.legend ?? "alt",
themeMode: resolvedOptions.themeMode,
});
const { yamlData, markdownContent, readingTime } = renderer.parseFrontMatterAndContent(markdown);
const { html: baseHtml, readingTime: readingTimeResult } = renderMarkdown(markdown, renderer);
let contentHtml = postProcessHtml(baseHtml, readingTimeResult, renderer);
if (!(resolvedOptions.keepTitle ?? false)) {
contentHtml = removeFirstHeading(contentHtml);
}
const meta = buildMarkdownDocumentMeta(
markdownContent,
yamlData as Record<string, unknown>,
resolvedOptions.defaultTitle,
);
const html = buildHtmlDocument(meta, css, contentHtml, codeThemeCss);
const inlinedHtml = normalizeInlineCss(await inlineCss(html), style);
return {
contentHtml,
html: modifyHtmlStructure(inlinedHtml),
meta,
readingTime,
style,
yamlData: yamlData as Record<string, unknown>,
};
}
export async function renderMarkdownFileToHtml(
inputPath: string,
options: RenderMarkdownDocumentOptions = {},
): Promise<RenderMarkdownDocumentResult & {
backupPath?: string;
outputPath: string;
}> {
const markdown = fs.readFileSync(inputPath, "utf-8");
const outputPath = path.resolve(
path.dirname(inputPath),
`${path.basename(inputPath, path.extname(inputPath))}.html`,
);
const result = await renderMarkdownDocument(markdown, {
...options,
defaultTitle: options.defaultTitle ?? path.basename(outputPath, ".html"),
});
let backupPath: string | undefined;
if (fs.existsSync(outputPath)) {
backupPath = `${outputPath}.bak-${formatTimestamp()}`;
fs.renameSync(outputPath, backupPath);
}
fs.writeFileSync(outputPath, result.html, "utf-8");
return {
...result,
backupPath,
outputPath,
};
}
+57
View File
@@ -0,0 +1,57 @@
import fs from "node:fs";
import { homedir } from "node:os";
import path from "node:path";
import type { ExtendConfig } from "./types.js";
function extractYamlFrontMatter(content: string): string | null {
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*$/m);
return match ? match[1]! : null;
}
function parseExtendYaml(yaml: string): Partial<ExtendConfig> {
const config: Partial<ExtendConfig> = {};
for (const line of yaml.split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const colonIdx = trimmed.indexOf(":");
if (colonIdx < 0) continue;
const key = trimmed.slice(0, colonIdx).trim();
let value = trimmed.slice(colonIdx + 1).trim().replace(/^['"]|['"]$/g, "");
if (value === "null" || value === "") continue;
if (key === "default_theme") config.default_theme = value;
else if (key === "default_color") config.default_color = value;
else if (key === "default_font_family") config.default_font_family = value;
else if (key === "default_font_size") config.default_font_size = value.endsWith("px") ? value : `${value}px`;
else if (key === "default_code_theme") config.default_code_theme = value;
else if (key === "mac_code_block") config.mac_code_block = value === "true";
else if (key === "show_line_number") config.show_line_number = value === "true";
else if (key === "cite") config.cite = value === "true";
else if (key === "count") config.count = value === "true";
else if (key === "legend") config.legend = value;
else if (key === "keep_title") config.keep_title = value === "true";
}
return config;
}
export function loadExtendConfig(): Partial<ExtendConfig> {
const paths = [
path.join(process.cwd(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
path.join(
process.env.XDG_CONFIG_HOME || path.join(homedir(), ".config"),
"baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"
),
path.join(homedir(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
];
for (const p of paths) {
try {
const content = fs.readFileSync(p, "utf-8");
const yaml = extractYamlFrontMatter(content);
if (!yaml) continue;
return parseExtendYaml(yaml);
} catch {
continue;
}
}
return {};
}
+284
View File
@@ -0,0 +1,284 @@
import type { MarkedExtension, Tokens } from 'marked'
export interface AlertOptions {
className?: string
variants?: AlertVariantItem[]
withoutStyle?: boolean
}
export interface AlertVariantItem {
type: string
icon: string
title?: string
titleClassName?: string
}
function ucfirst(str: string) {
return str.slice(0, 1).toUpperCase() + str.slice(1).toLowerCase()
}
/**
* https://github.com/bent10/marked-extensions/tree/main/packages/alert
* To support theme, we need to modify the source code.
* A [marked](https://marked.js.org/) extension to support [GFM alerts](https://github.com/orgs/community/discussions/16925).
*/
export function markedAlert(options: AlertOptions = {}): MarkedExtension {
const { className = `markdown-alert`, variants = [], withoutStyle = false } = options
const resolvedVariants = resolveVariants(variants)
// 提取公共的元数据构建逻辑
function buildMeta(variantType: string, matchedVariant: AlertVariantItem, fromContainer = false) {
return {
className,
variant: variantType,
icon: matchedVariant.icon,
title: matchedVariant.title ?? ucfirst(variantType),
titleClassName: `${className}-title`,
fromContainer,
}
}
// 提取公共的渲染逻辑
function renderAlert(token: any) {
const { meta, tokens = [] } = token
// @ts-expect-error marked renderer context has parser property
const text = this.parser.parse(tokens)
// 新主题系统:使用 CSS 选择器而非内联样式
let tmpl = `<blockquote class="${meta.className} ${meta.className}-${meta.variant}">\n`
tmpl += `<p class="${meta.titleClassName} alert-title-${meta.variant}">`
if (!withoutStyle) {
// 给 SVG 添加 class,通过 CSS 控制颜色
tmpl += meta.icon.replace(
`<svg`,
`<svg class="alert-icon-${meta.variant}"`,
)
}
tmpl += meta.title
tmpl += `</p>\n`
tmpl += text
tmpl += `</blockquote>\n`
return tmpl
}
return {
walkTokens(token) {
if (token.type !== `blockquote`)
return
const matchedVariant = resolvedVariants.find(({ type }) =>
new RegExp(createSyntaxPattern(type), `i`).test(token.text),
)
if (matchedVariant) {
const { type: variantType } = matchedVariant
const typeRegexp = new RegExp(createSyntaxPattern(variantType), `i`)
Object.assign(token, {
type: `alert`,
meta: buildMeta(variantType, matchedVariant),
})
const firstLine = token.tokens?.[0] as Tokens.Paragraph
const firstLineText = firstLine.raw?.replace(typeRegexp, ``).trim()
if (firstLineText) {
const patternToken = firstLine.tokens[0] as Tokens.Text
Object.assign(patternToken, {
raw: patternToken.raw.replace(typeRegexp, ``),
text: patternToken.text.replace(typeRegexp, ``),
})
if (firstLine.tokens[1]?.type === `br`) {
firstLine.tokens.splice(1, 1)
}
}
else {
token.tokens?.shift()
}
}
},
extensions: [
{
name: `alert`,
level: `block`,
renderer: renderAlert,
},
{
name: `alertContainer`,
level: `block`,
start(src) {
return src.match(/^:::/)?.index
},
tokenizer(src, _tokens) {
// eslint-disable-next-line regexp/no-super-linear-backtracking
const match = /^:::\s*(\w+)\s*\n([\s\S]*?)\n:::/.exec(src)
if (match) {
const [raw, variant, content] = match
const matchedVariant = resolvedVariants.find(v => v.type === variant)
if (!matchedVariant)
return
return {
type: `alert`,
raw,
text: content.trim(),
tokens: this.lexer.blockTokens(content.trim()),
meta: buildMeta(variant, matchedVariant, true),
}
}
},
renderer: renderAlert,
},
],
}
}
/**
* The default configuration for alert variants.
*/
const defaultAlertVariant: AlertVariantItem[] = [
{
type: `note`,
icon: `<svg class="octicon octicon-info" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
},
{
type: `info`,
icon: `<svg class="octicon octicon-info" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
},
{
type: `tip`,
icon: `<svg class="octicon octicon-light-bulb" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>`,
},
{
type: `important`,
icon: `<svg class="octicon octicon-report" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
},
{
type: `warning`,
icon: `<svg class="octicon octicon-alert" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
},
{
type: `caution`,
icon: `<svg class="octicon octicon-stop" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
},
// Obsidian-style callouts
{
type: `abstract`,
title: `Abstract`,
icon: `<svg class="octicon octicon-clipboard" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M5.75 1a.75.75 0 0 0-.75.75v.5c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.5a.75.75 0 0 0-.75-.75Zm4.5-1.5a2.25 2.25 0 0 1 2.122 1.5H13a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h.628A2.25 2.25 0 0 1 5.75-.5ZM3.5 3v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5Z"></path></svg>`,
},
{
type: `summary`,
title: `Summary`,
icon: `<svg class="octicon octicon-clipboard" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M5.75 1a.75.75 0 0 0-.75.75v.5c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.5a.75.75 0 0 0-.75-.75Zm4.5-1.5a2.25 2.25 0 0 1 2.122 1.5H13a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h.628A2.25 2.25 0 0 1 5.75-.5ZM3.5 3v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5Z"></path></svg>`,
},
{
type: `tldr`,
title: `TL;DR`,
icon: `<svg class="octicon octicon-clipboard" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M5.75 1a.75.75 0 0 0-.75.75v.5c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.5a.75.75 0 0 0-.75-.75Zm4.5-1.5a2.25 2.25 0 0 1 2.122 1.5H13a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h.628A2.25 2.25 0 0 1 5.75-.5ZM3.5 3v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5Z"></path></svg>`,
},
{
type: `todo`,
title: `Todo`,
icon: `<svg class="octicon octicon-checklist" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M2.5 1.75v11.5c0 .138.112.25.25.25h3.17a.75.75 0 0 1 0 1.5H2.75A1.75 1.75 0 0 1 1 13.25V1.75C1 .784 1.784 0 2.75 0h8.5C12.216 0 13 .784 13 1.75v7.736a.75.75 0 0 1-1.5 0V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm10.97 8.72a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1-1.06 1.06l-1.22-1.22v4.94a.75.75 0 0 1-1.5 0v-4.94l-1.22 1.22a.75.75 0 0 1-1.06-1.06Z"></path></svg>`,
},
{
type: `success`,
title: `Success`,
icon: `<svg class="octicon octicon-check-circle" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm3.78-9.72a.751.751 0 0 0-.018-1.042.751.751 0 0 0-1.042-.018L6.75 9.19 5.28 7.72a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042l2 2a.75.75 0 0 0 1.06 0Z"></path></svg>`,
},
{
type: `done`,
title: `Done`,
icon: `<svg class="octicon octicon-check-circle" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm3.78-9.72a.751.751 0 0 0-.018-1.042.751.751 0 0 0-1.042-.018L6.75 9.19 5.28 7.72a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042l2 2a.75.75 0 0 0 1.06 0Z"></path></svg>`,
},
{
type: `question`,
title: `Question`,
icon: `<svg class="octicon octicon-question" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
},
{
type: `help`,
title: `Help`,
icon: `<svg class="octicon octicon-question" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
},
{
type: `faq`,
title: `FAQ`,
icon: `<svg class="octicon octicon-question" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
},
{
type: `failure`,
title: `Failure`,
icon: `<svg class="octicon octicon-x-circle" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path></svg>`,
},
{
type: `fail`,
title: `Fail`,
icon: `<svg class="octicon octicon-x-circle" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path></svg>`,
},
{
type: `missing`,
title: `Missing`,
icon: `<svg class="octicon octicon-x-circle" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path></svg>`,
},
{
type: `danger`,
title: `Danger`,
icon: `<svg class="octicon octicon-zap" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M9.504.43a1.516 1.516 0 0 1 2.437 1.713L10.415 5.5h2.123c1.57 0 2.346 1.909 1.22 3.004l-7.34 7.142a1.249 1.249 0 0 1-.871.354h-.302a1.25 1.25 0 0 1-1.157-1.723L5.633 10.5H3.462c-1.57 0-2.346-1.909-1.22-3.004ZM9.98 1.873a.016.016 0 0 0-.016.006L2.252 9.021a.75.75 0 0 0 .488 1.212h3.838a.75.75 0 0 1 .694 1.034L5.545 15.02a.016.016 0 0 0 .003.017.017.017 0 0 0 .018.004h.302a.016.016 0 0 0 .012-.005l7.34-7.142a.75.75 0 0 0-.488-1.212h-3.838a.75.75 0 0 1-.694-1.034l1.527-3.628a.016.016 0 0 0-.003-.017.017.017 0 0 0-.018-.004h-.302Z"></path></svg>`,
},
{
type: `error`,
title: `Error`,
icon: `<svg class="octicon octicon-zap" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M9.504.43a1.516 1.516 0 0 1 2.437 1.713L10.415 5.5h2.123c1.57 0 2.346 1.909 1.22 3.004l-7.34 7.142a1.249 1.249 0 0 1-.871.354h-.302a1.25 1.25 0 0 1-1.157-1.723L5.633 10.5H3.462c-1.57 0-2.346-1.909-1.22-3.004ZM9.98 1.873a.016.016 0 0 0-.016.006L2.252 9.021a.75.75 0 0 0 .488 1.212h3.838a.75.75 0 0 1 .694 1.034L5.545 15.02a.016.016 0 0 0 .003.017.017.017 0 0 0 .018.004h.302a.016.016 0 0 0 .012-.005l7.34-7.142a.75.75 0 0 0-.488-1.212h-3.838a.75.75 0 0 1-.694-1.034l1.527-3.628a.016.016 0 0 0-.003-.017.017.017 0 0 0-.018-.004h-.302Z"></path></svg>`,
},
{
type: `bug`,
title: `Bug`,
icon: `<svg class="octicon octicon-bug" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M4.72.22a.75.75 0 0 1 1.06 0l1 .999a3.488 3.488 0 0 1 2.441 0l.999-1a.748.748 0 0 1 1.265.332.75.75 0 0 1-.205.729l-.775.776c.616.63.995 1.493.995 2.444v.327c0 .1-.009.197-.025.292l.727.726a.75.75 0 1 1-1.06 1.06l-.727-.727a2.17 2.17 0 0 1-.292.026H9.25V7.5a.75.75 0 0 1-1.5 0V6.125H6.875a2.17 2.17 0 0 1-.292-.026l-.727.727a.75.75 0 1 1-1.06-1.06l.727-.726a2.17 2.17 0 0 1-.025-.292V4.5c0-.951.379-1.814.995-2.444l-.775-.776a.75.75 0 0 1 0-1.06Zm6.437 6.003A.608.608 0 0 0 11 6.072v-.026a3.999 3.999 0 0 0-.11-.936 2.488 2.488 0 0 0-5.78 0 3.992 3.992 0 0 0-.11.936v.026c0 .05.008.098.02.147h4.937a.612.612 0 0 0 .2-.02ZM2.25 7.5a.75.75 0 0 0 0 1.5h.5v1.25a4.75 4.75 0 0 0 2.478 4.166l.247.137a.75.75 0 1 0 .722-1.313l-.246-.137A3.25 3.25 0 0 1 4.25 10.25V9h7.5v1.25a3.25 3.25 0 0 1-1.701 2.853l-.246.137a.75.75 0 1 0 .722 1.313l.247-.137A4.75 4.75 0 0 0 13.25 10.25V9h.5a.75.75 0 0 0 0-1.5Z"></path></svg>`,
},
{
type: `example`,
title: `Example`,
icon: `<svg class="octicon octicon-list-unordered" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
},
{
type: `quote`,
title: `Quote`,
icon: `<svg class="octicon octicon-quote" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25v-8.5C0 2.784.784 2 1.75 2ZM1.5 12.25c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM4 5.25a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5A.75.75 0 0 1 4 5.25Zm0 4a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Z"></path></svg>`,
},
{
type: `cite`,
title: `Cite`,
icon: `<svg class="octicon octicon-quote" style="margin-right: 0.25em;" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25v-8.5C0 2.784.784 2 1.75 2ZM1.5 12.25c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM4 5.25a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5A.75.75 0 0 1 4 5.25Zm0 4a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Z"></path></svg>`,
},
]
/**
* Resolves the variants configuration, combining the provided variants with
* the default variants.
*/
export function resolveVariants(variants: AlertVariantItem[]) {
if (!variants.length)
return defaultAlertVariant
return Object.values(
[...defaultAlertVariant, ...variants].reduce(
(map, item) => {
map[item.type] = item
return map
},
{} as { [key: string]: AlertVariantItem },
),
)
}
/**
* Returns regex pattern to match alert syntax.
*/
export function createSyntaxPattern(type: string) {
return `^(?:\\[!${type}])\\s*?\n*`
}
@@ -0,0 +1,89 @@
import type { MarkedExtension, Tokens } from 'marked'
/**
* A marked extension to support footnotes syntax.
* Syntax:
* This is a footnote reference[^1][^2].
*
* [^1]: .....
* [^2]: .....
*/
interface MapContent {
index: number
text: string
}
const fnMap = new Map<string, MapContent>()
export function markedFootnotes(): MarkedExtension {
return {
extensions: [
{
name: `footnoteDef`,
level: `block`,
start(src: string) {
fnMap.clear()
return src.match(/^\[\^/)?.index
},
tokenizer(src: string) {
const match = src.match(/^\[\^(.*)\]:(.*)/)
if (match) {
const [raw, fnId, text] = match
const index = fnMap.size + 1
fnMap.set(fnId, { index, text })
return {
type: `footnoteDef`,
raw,
fnId,
index,
text,
}
}
return undefined
},
renderer(token: Tokens.Generic) {
const { index, text, fnId } = token
const fnInner = `
<code>${index}.</code>
<span>${text}</span>
<a id="fnDef-${fnId}" href="#fnRef-${fnId}" style="color: var(--md-primary-color);">\u21A9\uFE0E</a>
<br>`
if (index === 1) {
return `
<p style="font-size: 80%;margin: 0.5em 8px;word-break:break-all;">${fnInner}`
}
if (index === fnMap.size) {
return `${fnInner}</p>`
}
return fnInner
},
},
{
name: `footnoteRef`,
level: `inline`,
start(src: string) {
return src.match(/\[\^/)?.index
},
tokenizer(src: string) {
const match = src.match(/^\[\^(.*?)\]/)
if (match) {
const [raw, fnId] = match
if (fnMap.has(fnId)) {
return {
type: `footnoteRef`,
raw,
fnId,
}
}
}
},
renderer(token: Tokens.Generic) {
const { fnId } = token
const { index } = fnMap.get(fnId) as MapContent
return `<sup style="color: var(--md-primary-color);">
<a href="#fnDef-${fnId}" id="fnRef-${fnId}">\[${index}\]</a>
</sup>`
},
},
],
}
}
+10
View File
@@ -0,0 +1,10 @@
// Markdown 扩展导出
export * from './alert.js'
export * from './footnotes.js'
export * from './infographic.js'
export * from './katex.js'
export * from './markup.js'
export * from './plantuml.js'
export * from './ruby.js'
export * from './slider.js'
export * from './toc.js'
@@ -0,0 +1,119 @@
import type { MarkedExtension } from 'marked'
interface InfographicOptions {
themeMode?: 'dark' | 'light'
}
async function renderInfographic(containerId: string, code: string, options?: InfographicOptions) {
if (typeof window === 'undefined')
return
try {
const { Infographic, setDefaultFont, setFontExtendFactor, exportToSVG } = await import('@antv/infographic')
setFontExtendFactor(1.1)
setDefaultFont('-apple-system-font, "system-ui", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif')
const findContainer = (retries = 5, delay = 100) => {
const container = document.getElementById(containerId)
if (container) {
const isDark = options?.themeMode === 'dark'
// 从 CSS 变量中读取主题颜色
const root = document.documentElement
const computedStyle = getComputedStyle(root)
const primaryColor = computedStyle.getPropertyValue('--md-primary-color').trim()
const backgroundColor = computedStyle.getPropertyValue('--background').trim()
// 转换 HSL 格式
const toHSLString = (variant: string) => {
const vars = variant.split(' ')
if (vars.length === 3)
return `hsl(${vars.join(', ')})`
if (vars.length === 4)
return `hsla(${vars.join(', ')})`
return ''
}
const instance = new Infographic({
container,
svg: {
style: {
width: '100%',
height: '100%',
background: isDark ? '#000' : 'transparent',
},
background: false,
},
theme: isDark ? 'dark' : 'default',
themeConfig: {
colorPrimary: primaryColor || undefined,
colorBg: toHSLString(backgroundColor) || undefined,
},
})
instance.on('loaded', ({ node }) => {
exportToSVG(node, { removeIds: true }).then((svg) => {
container.replaceChildren(svg)
})
})
instance.render(code)
return
}
if (retries > 0) {
setTimeout(() => findContainer(retries - 1, delay), delay)
}
}
findContainer()
}
catch (error) {
console.error('Failed to render Infographic:', error)
const container = document.getElementById(containerId)
if (container) {
container.innerHTML = `<div style="color: red; padding: 10px; border: 1px solid red;">Infographic 渲染失败: ${error instanceof Error ? error.message : String(error)}</div>`
}
}
}
export function markedInfographic(options?: InfographicOptions): MarkedExtension {
const className = 'infographic-diagram'
return {
extensions: [
{
name: 'infographic',
level: 'block',
start(src: string) {
return src.match(/^```infographic/m)?.index
},
tokenizer(src: string) {
const match = /^```infographic\r?\n([\s\S]*?)\r?\n```/.exec(src)
if (match) {
return {
type: 'infographic',
raw: match[0],
text: match[1].trim(),
}
}
},
renderer(token: any) {
const id = `infographic-${Math.random().toString(36).slice(2, 11)}`
const code = token.text
renderInfographic(id, code, options)
return `<div id="${id}" class="${className}" style="width: 100%;">正在加载 Infographic...</div>`
},
},
],
walkTokens(token: any) {
if (token.type === 'code' && token.lang === 'infographic') {
token.type = 'infographic'
}
},
}
}
+162
View File
@@ -0,0 +1,162 @@
import type { MarkedExtension } from 'marked'
export interface MarkedKatexOptions {
nonStandard?: boolean
}
const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\1(?=[\s?!.,:?!。,:]|$)/
const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\1/ // Non-standard, even if there are no spaces before and after $ or $$, try to parse
const blockRule = /^\s{0,3}(\${1,2})[ \t]*\n([\s\S]+?)\n\s{0,3}\1[ \t]*(?:\n|$)/
// LaTeX style rules for \( ... \) and \[ ... \]
const inlineLatexRule = /^\\\(([^\\]*(?:\\.[^\\]*)*?)\\\)/
const blockLatexRule = /^\\\[([^\\]*(?:\\.[^\\]*)*?)\\\]/
function createRenderer(display: boolean, withStyle: boolean = true) {
return (token: any) => {
// @ts-expect-error MathJax is a global variable
window.MathJax.texReset()
// @ts-expect-error MathJax is a global variable
const mjxContainer = window.MathJax.tex2svg(token.text, { display })
const svg = mjxContainer.firstChild
const width = svg.style[`min-width`] || svg.getAttribute(`width`)
svg.removeAttribute(`width`)
// 行内公式对齐 https://groups.google.com/g/mathjax-users/c/zThKffrrCvE?pli=1
// 直接覆盖 style 会覆盖 MathJax 的样式,需要手动设置
// svg.style = `max-width: 300vw !important; display: initial; flex-shrink: 0;`
if (withStyle) {
svg.style.display = `initial`
svg.style.setProperty(`max-width`, `300vw`, `important`)
svg.style.flexShrink = `0`
svg.style.width = width
}
if (!display) {
// 新主题系统:使用 class 而非内联样式
return `<span class="katex-inline">${svg.outerHTML}</span>`
}
return `<section class="katex-block">${svg.outerHTML}</section>`
}
}
function inlineKatex(options: MarkedKatexOptions | undefined, renderer: any) {
const nonStandard = options && options.nonStandard
const ruleReg = nonStandard ? inlineRuleNonStandard : inlineRule
return {
name: `inlineKatex`,
level: `inline`,
start(src: string) {
let index
let indexSrc = src
while (indexSrc) {
index = indexSrc.indexOf(`$`)
if (index === -1) {
return
}
const f = nonStandard ? index > -1 : index === 0 || indexSrc.charAt(index - 1) === ` `
if (f) {
const possibleKatex = indexSrc.substring(index)
if (possibleKatex.match(ruleReg)) {
return index
}
}
indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, ``)
}
},
tokenizer(src: string) {
const match = src.match(ruleReg)
if (match) {
return {
type: `inlineKatex`,
raw: match[0],
text: match[2].trim(),
displayMode: match[1].length === 2,
}
}
},
renderer,
}
}
function blockKatex(_options: MarkedKatexOptions | undefined, renderer: any) {
return {
name: `blockKatex`,
level: `block`,
tokenizer(src: string) {
const match = src.match(blockRule)
if (match) {
return {
type: `blockKatex`,
raw: match[0],
text: match[2].trim(),
displayMode: match[1].length === 2,
}
}
},
renderer,
}
}
function inlineLatexKatex(_options: MarkedKatexOptions | undefined, renderer: any) {
return {
name: `inlineLatexKatex`,
level: `inline`,
start(src: string) {
const index = src.indexOf(`\\(`)
return index !== -1 ? index : undefined
},
tokenizer(src: string) {
const match = src.match(inlineLatexRule)
if (match) {
return {
type: `inlineLatexKatex`,
raw: match[0],
text: match[1].trim(),
displayMode: false,
}
}
},
renderer,
}
}
function blockLatexKatex(_options: MarkedKatexOptions | undefined, renderer: any) {
return {
name: `blockLatexKatex`,
level: `block`,
start(src: string) {
const index = src.indexOf(`\\[`)
return index !== -1 ? index : undefined
},
tokenizer(src: string) {
const match = src.match(blockLatexRule)
if (match) {
return {
type: `blockLatexKatex`,
raw: match[0],
text: match[1].trim(),
displayMode: true,
}
}
},
renderer,
}
}
export function MDKatex(options: MarkedKatexOptions | undefined, withStyle: boolean = true): MarkedExtension {
return {
extensions: [
inlineKatex(options, createRenderer(false, withStyle)),
blockKatex(options, createRenderer(true, withStyle)),
inlineLatexKatex(options, createRenderer(false, withStyle)),
blockLatexKatex(options, createRenderer(true, withStyle)),
],
}
}
@@ -0,0 +1,87 @@
import type { MarkedExtension } from 'marked'
/**
* 扩展标记语法:
* - 高亮: ==文本==
* - 下划线: ++文本++
* - 波浪线: ~文本~
*/
export function markedMarkup(): MarkedExtension {
return {
extensions: [
// 高亮语法 ==文本==
{
name: `markup_highlight`,
level: `inline`,
start(src: string) {
return src.match(/==(?!=)/)?.index
},
tokenizer(src: string) {
const rule = /^==((?:[^=]|=(?!=))+)==/
const match = rule.exec(src)
if (match) {
return {
type: `markup_highlight`,
raw: match[0],
text: match[1],
}
}
},
renderer(token: any) {
// 新主题系统:使用 class 而非内联样式
return `<span class="markup-highlight">${token.text}</span>`
},
},
// 下划线语法 ++文本++
{
name: `markup_underline`,
level: `inline`,
start(src: string) {
return src.match(/\+\+(?!\+)/)?.index
},
tokenizer(src: string) {
const rule = /^\+\+((?:[^+]|\+(?!\+))+)\+\+/
const match = rule.exec(src)
if (match) {
return {
type: `markup_underline`,
raw: match[0],
text: match[1],
}
}
},
renderer(token: any) {
// 新主题系统:使用 class 而非内联样式
return `<span class="markup-underline">${token.text}</span>`
},
},
// 波浪线语法 ~文本~
{
name: `markup_wavyline`,
level: `inline`,
start(src: string) {
// 查找单个 ~ 但不是连续的 ~~
return src.match(/~(?!~)/)?.index
},
tokenizer(src: string) {
// 匹配 ~文本~ 但确保不是 ~~文本~~
const rule = /^~([^~\n]+)~(?!~)/
const match = rule.exec(src)
if (match) {
return {
type: `markup_wavyline`,
raw: match[0],
text: match[1],
}
}
},
renderer(token: any) {
// 新主题系统:使用 class 而非内联样式
return `<span class="markup-wavyline">${token.text}</span>`
},
},
],
}
}
@@ -0,0 +1,289 @@
import type { MarkedExtension, Tokens } from 'marked'
import { deflateSync } from 'fflate'
export interface PlantUMLOptions {
/**
* PlantUML 服务器地址
* @default 'https://www.plantuml.com/plantuml'
*/
serverUrl?: string
/**
* 渲染格式
* @default 'svg'
*/
format?: `svg` | `png`
/**
* CSS 类名
* @default 'plantuml-diagram'
*/
className?: string
/**
* 是否内嵌SVG内容(用于微信公众号等不支持外链图片的环境)
* @default false
*/
inlineSvg?: boolean
/**
* 自定义样式
*/
styles?: {
container?: Record<string, string | number>
}
}
/**
* PlantUML 专用的 6-bit 编码函数
* 基于官方文档 https://plantuml.com/text-encoding
*/
function encode6bit(b: number): string {
if (b < 10) {
return String.fromCharCode(48 + b)
}
b -= 10
if (b < 26) {
return String.fromCharCode(65 + b)
}
b -= 26
if (b < 26) {
return String.fromCharCode(97 + b)
}
b -= 26
if (b === 0) {
return `-`
}
if (b === 1) {
return `_`
}
return `?`
}
/**
* 将 3 个字节附加到编码字符串中
* 基于官方文档 https://plantuml.com/text-encoding
*/
function append3bytes(b1: number, b2: number, b3: number): string {
const c1 = b1 >> 2
const c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
const c3 = ((b2 & 0xF) << 2) | (b3 >> 6)
const c4 = b3 & 0x3F
let r = ``
r += encode6bit(c1 & 0x3F)
r += encode6bit(c2 & 0x3F)
r += encode6bit(c3 & 0x3F)
r += encode6bit(c4 & 0x3F)
return r
}
/**
* PlantUML 专用的 base64 编码函数
* 基于官方文档 https://plantuml.com/text-encoding
*/
function encode64(data: string): string {
let r = ``
for (let i = 0; i < data.length; i += 3) {
if (i + 2 === data.length) {
r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0)
}
else if (i + 1 === data.length) {
r += append3bytes(data.charCodeAt(i), 0, 0)
}
else {
r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), data.charCodeAt(i + 2))
}
}
return r
}
/**
* 使用 fflate 库进行 Deflate 压缩
* 按照官方规范进行压缩
*/
function performDeflate(input: string): string {
try {
// 将字符串转换为字节数组
const inputBytes = new TextEncoder().encode(input)
// 使用 fflate 进行 deflate 压缩(最高压缩级别 9)
const compressed = deflateSync(inputBytes, { level: 9 })
// 将压缩后的字节数组转换为二进制字符串
return String.fromCharCode(...compressed)
}
catch (error) {
console.warn(`Deflate compression failed:`, error)
// 如果压缩失败,返回原始输入
return input
}
}
/**
* 编码 PlantUML 代码为服务器可识别的格式
* 按照官方规范:UTF-8 编码 -> Deflate 压缩 -> PlantUML Base64 编码
*/
function encodePlantUML(plantumlCode: string): string {
try {
// 步骤 1 & 2: UTF-8 编码 + Deflate 压缩
const deflated = performDeflate(plantumlCode)
// 步骤 3: PlantUML 专用的 base64 编码
return encode64(deflated)
}
catch (error) {
// 如果编码失败,回退到简单方案
console.warn(`PlantUML encoding failed, using fallback:`, error)
const utf8Bytes = new TextEncoder().encode(plantumlCode)
const base64 = btoa(String.fromCharCode(...utf8Bytes))
return `~1${base64.replace(/\+/g, `-`).replace(/\//g, `_`).replace(/=/g, ``)}`
}
}
/**
* 生成 PlantUML 图片 URL
*/
function generatePlantUMLUrl(code: string, options: Required<PlantUMLOptions>): string {
const encoded = encodePlantUML(code)
const formatPath = options.format === `svg` ? `svg` : `png`
return `${options.serverUrl}/${formatPath}/${encoded}`
}
/**
* 渲染 PlantUML 图表
*/
function renderPlantUMLDiagram(token: Tokens.Code, options: Required<PlantUMLOptions>): string {
const { text: code } = token
// 检查代码是否包含 PlantUML 标记
const finalCode = (!code.trim().includes(`@start`) || !code.trim().includes(`@end`))
? `@startuml\n${code.trim()}\n@enduml`
: code
const imageUrl = generatePlantUMLUrl(finalCode, options)
// 如果启用了内嵌SVG且格式是SVG
if (options.inlineSvg && options.format === `svg`) {
// 由于marked是同步的,我们需要返回一个占位符,然后异步替换
const placeholder = `plantuml-placeholder-${Math.random().toString(36).slice(2, 11)}`
// 异步获取SVG内容并替换
fetchSvgContent(imageUrl).then((svgContent) => {
const placeholderElement = document.querySelector(`[data-placeholder="${placeholder}"]`)
if (placeholderElement) {
placeholderElement.outerHTML = createPlantUMLHTML(imageUrl, options, svgContent)
}
})
const containerStyles = options.styles.container
? Object.entries(options.styles.container)
.map(([key, value]) => `${key.replace(/([A-Z])/g, `-$1`).toLowerCase()}: ${value}`)
.join(`; `)
: ``
return `<div class="${options.className}" style="${containerStyles}" data-placeholder="${placeholder}">
<div style="color: #666; font-style: italic;">正在加载PlantUML图表...</div>
</div>`
}
return createPlantUMLHTML(imageUrl, options)
}
/**
* 获取SVG内容
*/
async function fetchSvgContent(svgUrl: string): Promise<string> {
try {
const response = await fetch(svgUrl)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
const svgContent = await response.text()
// 移除SVG根元素的固定尺寸,使其响应式
return svgContent
// 移除width和height属性
.replace(/(<svg[^>]*)\swidth="[^"]*"/g, `$1`)
.replace(/(<svg[^>]*)\sheight="[^"]*"/g, `$1`)
// 移除style中的width和height
.replace(/(<svg[^>]*style="[^"]*?)width:[^;]*;?/g, `$1`)
.replace(/(<svg[^>]*style="[^"]*?)height:[^;]*;?/g, `$1`)
}
catch (error) {
console.warn(`Failed to fetch SVG content from ${svgUrl}:`, error)
return `<div style="color: #666; font-style: italic;">PlantUML图表加载失败</div>`
}
}
/**
* 创建 PlantUML HTML 元素
*/
function createPlantUMLHTML(imageUrl: string, options: Required<PlantUMLOptions>, svgContent?: string): string {
const containerStyles = options.styles.container
? Object.entries(options.styles.container)
.map(([key, value]) => `${key.replace(/([A-Z])/g, `-$1`).toLowerCase()}: ${value}`)
.join(`; `)
: ``
// 如果有SVG内容,直接嵌入
if (svgContent) {
return `<div class="${options.className}" style="${containerStyles}">
${svgContent}
</div>`
}
// 否则使用图片链接
return `<div class="${options.className}" style="${containerStyles}">
<img src="${imageUrl}" alt="PlantUML Diagram" style="max-width: 100%; height: auto;" />
</div>`
}
/**
* PlantUML marked 扩展
*/
export function markedPlantUML(options: PlantUMLOptions = {}): MarkedExtension {
const resolvedOptions: Required<PlantUMLOptions> = {
serverUrl: options.serverUrl || `https://www.plantuml.com/plantuml`,
format: options.format || `svg`,
className: options.className || `plantuml-diagram`,
inlineSvg: options.inlineSvg || false,
styles: {
container: {
textAlign: `center`,
margin: `16px 8px`,
overflowX: `auto`,
...options.styles?.container,
},
},
}
return {
extensions: [
{
name: `plantuml`,
level: `block`,
start(src: string) {
// 匹配 ```plantuml 代码块
return src.match(/^```plantuml/m)?.index
},
tokenizer(src: string) {
// 匹配完整的 plantuml 代码块
const match = /^```plantuml\r?\n([\s\S]*?)\r?\n```/.exec(src)
if (match) {
const [raw, code] = match
return {
type: `plantuml`,
raw,
text: code.trim(),
}
}
},
renderer(token: any) {
return renderPlantUMLDiagram(token, resolvedOptions)
},
},
],
walkTokens(token: any) {
// 处理现有的代码块,如果语言是 plantuml 就转换类型
if (token.type === `code` && token.lang === `plantuml`) {
token.type = `plantuml`
}
},
}
}
+125
View File
@@ -0,0 +1,125 @@
import type { MarkedExtension } from 'marked'
/**
* 注音/拼音标注扩展
* https://talk.commonmark.org/t/proper-ruby-text-rb-syntax-support-in-markdown/2279
* https://www.w3.org/TR/ruby/
*
* 支持的格式:
* 1. [文字]{注音}
* 2. [文字]^(注音)
*
* 分隔符:
* - `・` (中点)
* - `` (全角句点)
* - `。` (中文句号)
* - `-` (英文减号)
*/
export function markedRuby(): MarkedExtension {
return {
extensions: [
{
name: `ruby`,
level: `inline`,
start(src: string) {
// 匹配以 [ 开头的格式
return src.match(/\[/)?.index
},
tokenizer(src: string) {
// 1. [文字]{注音}
const rule1 = /^\[([^\]]+)\]\{([^}]+)\}/
let match = rule1.exec(src)
if (match) {
return {
type: `ruby`,
raw: match[0],
text: match[1].trim(),
ruby: match[2].trim(),
format: `basic`,
}
}
// 2. [文字]^(注音)
const rule2 = /^\[([^\]]+)\]\^\(([^)]+)\)/
match = rule2.exec(src)
if (match) {
return {
type: `ruby`,
raw: match[0],
text: match[1].trim(),
ruby: match[2].trim(),
format: `basic-hat`,
}
}
return undefined
},
renderer(token: any) {
const { text, ruby, format } = token
// 检查是否有分隔符
const separatorRegex = /[・.。-]/g
const hasSeparators = separatorRegex.test(ruby)
if (hasSeparators) {
// 分割注音部分
const rubyParts = ruby.split(separatorRegex).filter((part: string) => part.trim() !== ``)
const textChars = text.split(``)
const result = []
if (textChars.length >= rubyParts.length) {
// 文字字符数量 >= 注音部分数量
// 按注音部分数量分割文字
let currentIndex = 0
for (let i = 0; i < rubyParts.length; i++) {
const rubyPart = rubyParts[i]
const remainingChars = textChars.length - currentIndex
const remainingParts = rubyParts.length - i
// 计算当前部分应该包含多少个字符,默认为 1
let charCount = 1
if (remainingParts === 1) {
// 最后一个部分,包含所有剩余字符
charCount = remainingChars
}
// 提取当前部分的文字
const currentText = textChars.slice(currentIndex, currentIndex + charCount).join(``)
result.push(`<ruby data-text="${currentText}" data-ruby="${rubyPart}" data-format="${format}">${currentText}<rp>(</rp><rt>${rubyPart}</rt><rp>)</rp></ruby>`)
currentIndex += charCount
}
// 处理剩余的字符
if (currentIndex < textChars.length) {
result.push(textChars.slice(currentIndex).join(``))
}
}
else {
// 文字字符数量 < 注音部分数量
// 每个字符对应一个注音部分,多余的注音被忽略
for (let i = 0; i < textChars.length; i++) {
const char = textChars[i]
const rubyPart = rubyParts[i] || ``
if (rubyPart) {
result.push(`<ruby data-text="${char}" data-ruby="${rubyPart}" data-format="${format}">${char}<rp>(</rp><rt>${rubyPart}</rt><rp>)</rp></ruby>`)
}
else {
result.push(char)
}
}
}
return result.join(``)
}
return `<ruby data-text="${text}" data-ruby="${ruby}" data-format="${format}">${text}<rp>(</rp><rt>${ruby}</rt><rp>)</rp></ruby>`
},
},
],
}
}
@@ -0,0 +1,73 @@
import type { MarkedExtension, Tokens } from 'marked'
/**
* A marked extension to support horizontal sliding images.
* Syntax: <![alt1](url1),![alt2](url2),![alt3](url3)>
*/
export function markedSlider(): MarkedExtension {
return {
extensions: [
{
name: `horizontalSlider`,
level: `block`,
start(src: string) {
return src.match(/^<!\[/)?.index
},
tokenizer(src: string) {
const rule = /^<(!\[.*?\]\(.*?\)(?:,!\[.*?\]\(.*?\))*)>/
const match = src.match(rule)
if (match) {
return {
type: `horizontalSlider`,
raw: match[0],
text: match[1],
}
}
return undefined
},
renderer(token: Tokens.Generic) {
const { text } = token
const imageMatches = text.match(/!\[(.*?)\]\((.*?)\)/g) || []
if (imageMatches.length === 0) {
return ``
}
const images = imageMatches.map((img: string) => {
const altMatch = img.match(/!\[(.*?)\]/) || []
const srcMatch = img.match(/\]\((.*?)\)/) || []
const alt = altMatch[1] || ``
const src = srcMatch[1] || ``
// 新主题系统:不再需要内联样式
return { src, alt }
})
// 使用微信公众号兼容的滑动容器布局
// 使用微信支持的section标签和特殊样式组合
return `
<section style="box-sizing: border-box; font-size: 16px;">
<section data-role="outer" style="font-family: 微软雅黑; font-size: 16px;">
<section data-role="paragraph" style="margin: 0px auto; box-sizing: border-box; width: 100%;">
<section style="margin: 0px auto; text-align: center;">
<section style="display: inline-block; width: 100%;">
<!-- 微信公众号支持的滑动图片容器 -->
<section style="overflow-x: scroll; -webkit-overflow-scrolling: touch; white-space: nowrap; width: 100%; text-align: center;">
${images.map((img: { src: string, alt: string }, _index: number) => `<section style="display: inline-block; width: 100%; margin-right: 0; vertical-align: top;">
<img src="${img.src}" alt="${img.alt}" title="${img.alt}" style="width: 100%; height: auto; border-radius: 4px; vertical-align: top;"/>
<p style="margin-top: 5px; font-size: 14px; color: #666; text-align: center; white-space: normal;">${img.alt}</p>
</section>`).join(``)}
</section>
</section>
</section>
</section>
</section>
<p style="font-size: 14px; color: #999; text-align: center; margin-top: 5px;"><<< 左右滑动看更多 >>></p>
</section>
`
},
},
],
}
}
+74
View File
@@ -0,0 +1,74 @@
import type { MarkedExtension } from 'marked'
/**
* marked 插件:支持 [TOC] 语法,自动生成嵌套目录
*/
export function markedToc(): MarkedExtension {
let headings: { text: string, depth: number, index: number }[] = []
let firstToken = true
return {
walkTokens(token) {
if (firstToken) {
headings = []
firstToken = false
}
if (token.type === `heading`) {
const text = token.text || ``
const depth = token.depth || 1
const index = headings.length
headings.push({ text, depth, index })
}
},
extensions: [
{
name: `toc`,
level: `block`,
start(src) {
// 只匹配独立一行的 [TOC],避免误伤
const match = src.match(/^\s*\[TOC\]\s*$/m)
return match ? match.index : undefined
},
tokenizer(src) {
const match = /^\[TOC\]/.exec(src)
if (match) {
return {
type: `toc`,
raw: match[0],
}
}
},
renderer() {
if (!headings.length)
return ``
let html = `<nav class="markdown-toc"><ul class="toc-ul toc-level-1 pl-4 border-l ml-2">`
let lastDepth = 1
headings.forEach(({ text, depth, index }) => {
if (depth > lastDepth) {
for (let i = lastDepth + 1; i <= depth; i++) {
html += `<ul class="toc-ul toc-level-${i} pl-4 border-l ml-2">`
}
}
else if (depth < lastDepth) {
for (let i = lastDepth; i > depth; i--) {
html += `</ul>`
}
}
html += `<li class="toc-li toc-level-${depth} mb-1"><a class="text-gray-700 hover:text-blue-600 underline transition-colors" href="#${index}">${text}</a></li>`
lastDepth = depth
})
for (let i = lastDepth; i > 1; i--) {
html += `</ul>`
}
html += `</ul></nav>`
firstToken = true
return html
},
},
],
}
}
+142
View File
@@ -0,0 +1,142 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { StyleConfig, HtmlDocumentMeta } from "./types.js";
import { DEFAULT_STYLE } from "./constants.js";
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const CODE_THEMES_DIR = path.resolve(SCRIPT_DIR, "code-themes");
export function buildCss(baseCss: string, themeCss: string, style: StyleConfig = DEFAULT_STYLE): string {
const variables = `
:root {
--md-primary-color: ${style.primaryColor};
--md-font-family: ${style.fontFamily};
--md-font-size: ${style.fontSize};
--foreground: ${style.foreground};
--blockquote-background: ${style.blockquoteBackground};
--md-accent-color: ${style.accentColor};
--md-container-bg: ${style.containerBg};
}
body {
margin: 0;
padding: 24px;
background: #ffffff;
}
#output {
max-width: 860px;
margin: 0 auto;
}
`.trim();
return [variables, baseCss, themeCss].join("\n\n");
}
export function loadCodeThemeCss(themeName: string): string {
const filePath = path.join(CODE_THEMES_DIR, `${themeName}.min.css`);
try {
return fs.readFileSync(filePath, "utf-8");
} catch {
console.error(`Code theme CSS not found: ${filePath}`);
return "";
}
}
export function buildHtmlDocument(meta: HtmlDocumentMeta, css: string, html: string, codeThemeCss?: string): string {
const lines = [
"<!doctype html>",
"<html>",
"<head>",
' <meta charset="utf-8" />',
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
` <title>${meta.title}</title>`,
];
if (meta.author) {
lines.push(` <meta name="author" content="${meta.author}" />`);
}
if (meta.description) {
lines.push(` <meta name="description" content="${meta.description}" />`);
}
lines.push(` <style>${css}</style>`);
if (codeThemeCss) {
lines.push(` <style>${codeThemeCss}</style>`);
}
lines.push(
"</head>",
"<body>",
' <div id="output">',
html,
" </div>",
"</body>",
"</html>"
);
return lines.join("\n");
}
export async function inlineCss(html: string): Promise<string> {
try {
const { default: juice } = await import("juice");
return juice(html, {
inlinePseudoElements: true,
preserveImportant: true,
resolveCSSVariables: false,
});
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
throw new Error(
`Missing dependency "juice" for CSS inlining. Install it first (e.g. "bun add juice" or "npm add juice"). Original error: ${detail}`
);
}
}
export function normalizeCssText(cssText: string, style: StyleConfig = DEFAULT_STYLE): string {
return cssText
.replace(/var\(--md-primary-color\)/g, style.primaryColor)
.replace(/var\(--md-font-family\)/g, style.fontFamily)
.replace(/var\(--md-font-size\)/g, style.fontSize)
.replace(/var\(--blockquote-background\)/g, style.blockquoteBackground)
.replace(/var\(--md-accent-color\)/g, style.accentColor)
.replace(/var\(--md-container-bg\)/g, style.containerBg)
.replace(/hsl\(var\(--foreground\)\)/g, "#3f3f3f")
.replace(/--md-primary-color:\s*[^;"']+;?/g, "")
.replace(/--md-font-family:\s*[^;"']+;?/g, "")
.replace(/--md-font-size:\s*[^;"']+;?/g, "")
.replace(/--blockquote-background:\s*[^;"']+;?/g, "")
.replace(/--md-accent-color:\s*[^;"']+;?/g, "")
.replace(/--md-container-bg:\s*[^;"']+;?/g, "")
.replace(/--foreground:\s*[^;"']+;?/g, "");
}
export function normalizeInlineCss(html: string, style: StyleConfig = DEFAULT_STYLE): string {
let output = html;
output = output.replace(
/<style([^>]*)>([\s\S]*?)<\/style>/gi,
(_match, attrs: string, cssText: string) =>
`<style${attrs}>${normalizeCssText(cssText, style)}</style>`
);
output = output.replace(
/style="([^"]*)"/gi,
(_match, cssText: string) => `style="${normalizeCssText(cssText, style)}"`
);
output = output.replace(
/style='([^']*)'/gi,
(_match, cssText: string) => `style='${normalizeCssText(cssText, style)}'`
);
return output;
}
export function modifyHtmlStructure(htmlString: string): string {
let output = htmlString;
const pattern =
/<li([^>]*)>([\s\S]*?)(<ul[\s\S]*?<\/ul>|<ol[\s\S]*?<\/ol>)<\/li>/i;
while (pattern.test(output)) {
output = output.replace(pattern, "<li$1>$2</li>$3");
}
return output;
}
export function removeFirstHeading(html: string): string {
return html.replace(/<h[12][^>]*>[\s\S]*?<\/h[12]>/, "");
}
+127
View File
@@ -0,0 +1,127 @@
import { createHash } from "node:crypto";
import fs from "node:fs";
import http from "node:http";
import https from "node:https";
import path from "node:path";
export interface ImagePlaceholder {
originalPath: string;
placeholder: string;
}
export interface ResolvedImageInfo extends ImagePlaceholder {
localPath: string;
}
export function replaceMarkdownImagesWithPlaceholders(
markdown: string,
placeholderPrefix: string,
): {
images: ImagePlaceholder[];
markdown: string;
} {
const images: ImagePlaceholder[] = [];
let imageCounter = 0;
const rewritten = markdown.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_match, _alt, src) => {
const placeholder = `${placeholderPrefix}${++imageCounter}`;
images.push({
originalPath: src,
placeholder,
});
return placeholder;
});
return { images, markdown: rewritten };
}
export function getImageExtension(urlOrPath: string): string {
const match = urlOrPath.match(/\.(jpg|jpeg|png|gif|webp)(\?|$)/i);
return match ? match[1]!.toLowerCase() : "png";
}
export async function downloadFile(url: string, destPath: string): Promise<void> {
return await new Promise((resolve, reject) => {
const protocol = url.startsWith("https://") ? https : http;
const file = fs.createWriteStream(destPath);
const request = protocol.get(url, { headers: { "User-Agent": "Mozilla/5.0" } }, (response) => {
if (response.statusCode === 301 || response.statusCode === 302) {
const redirectUrl = response.headers.location;
if (redirectUrl) {
file.close();
fs.unlinkSync(destPath);
void downloadFile(redirectUrl, destPath).then(resolve).catch(reject);
return;
}
}
if (response.statusCode !== 200) {
file.close();
fs.unlinkSync(destPath);
reject(new Error(`Failed to download: ${response.statusCode}`));
return;
}
response.pipe(file);
file.on("finish", () => {
file.close();
resolve();
});
});
request.on("error", (error) => {
file.close();
fs.unlink(destPath, () => {});
reject(error);
});
request.setTimeout(30_000, () => {
request.destroy();
reject(new Error("Download timeout"));
});
});
}
export async function resolveImagePath(
imagePath: string,
baseDir: string,
tempDir: string,
logLabel = "baoyu-md",
): Promise<string> {
if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
const hash = createHash("md5").update(imagePath).digest("hex").slice(0, 8);
const ext = getImageExtension(imagePath);
const localPath = path.join(tempDir, `remote_${hash}.${ext}`);
if (!fs.existsSync(localPath)) {
console.error(`[${logLabel}] Downloading: ${imagePath}`);
await downloadFile(imagePath, localPath);
}
return localPath;
}
if (path.isAbsolute(imagePath)) {
return imagePath;
}
return path.resolve(baseDir, imagePath);
}
export async function resolveContentImages(
images: ImagePlaceholder[],
baseDir: string,
tempDir: string,
logLabel = "baoyu-md",
): Promise<ResolvedImageInfo[]> {
const resolved: ResolvedImageInfo[] = [];
for (const image of images) {
resolved.push({
...image,
localPath: await resolveImagePath(image.originalPath, baseDir, tempDir, logLabel),
});
}
return resolved;
}
+10
View File
@@ -0,0 +1,10 @@
export * from "./cli.js";
export * from "./constants.js";
export * from "./content.js";
export * from "./document.js";
export * from "./extend-config.js";
export * from "./html-builder.js";
export * from "./images.js";
export * from "./renderer.js";
export * from "./themes.js";
export * from "./types.js";
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env npx tsx
import path from "node:path";
import { parseArgs, printUsage } from "./cli.js";
import { renderMarkdownFileToHtml } from "./document.js";
async function main(): Promise<void> {
const options = parseArgs(process.argv.slice(2));
if (!options) {
printUsage();
process.exit(1);
}
const inputPath = path.resolve(process.cwd(), options.inputPath);
if (!inputPath.toLowerCase().endsWith(".md")) {
console.error("Input file must end with .md");
process.exit(1);
}
const result = await renderMarkdownFileToHtml(inputPath, {
codeTheme: options.codeTheme,
countStatus: options.countStatus,
citeStatus: options.citeStatus,
fontFamily: options.fontFamily,
fontSize: options.fontSize,
isMacCodeBlock: options.isMacCodeBlock,
isShowLineNumber: options.isShowLineNumber,
keepTitle: options.keepTitle,
legend: options.legend,
primaryColor: options.primaryColor,
theme: options.theme,
});
if (result.backupPath) {
console.log(`Backup created: ${result.backupPath}`);
}
console.log(`HTML written: ${result.outputPath}`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
+434
View File
@@ -0,0 +1,434 @@
import frontMatter from "front-matter";
import hljs from "highlight.js/lib/core";
import { marked, type RendererObject, type Tokens } from "marked";
import readingTime, { type ReadTimeResults } from "reading-time";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkCjkFriendly from "remark-cjk-friendly";
import remarkStringify from "remark-stringify";
import {
markedAlert,
markedFootnotes,
markedInfographic,
markedMarkup,
markedPlantUML,
markedRuby,
markedSlider,
markedToc,
MDKatex,
} from "./extensions/index.js";
import {
COMMON_LANGUAGES,
highlightAndFormatCode,
} from "./utils/languages.js";
import { macCodeSvg } from "./constants.js";
import type { IOpts, ParseResult, RendererAPI } from "./types.js";
Object.entries(COMMON_LANGUAGES).forEach(([name, lang]) => {
hljs.registerLanguage(name, lang);
});
export { hljs };
marked.setOptions({
breaks: true,
});
marked.use(markedSlider());
function escapeHtml(text: string): string {
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;")
.replace(/`/g, "&#96;");
}
function buildAddition(): string {
return `
<style>
.preview-wrapper pre::before {
position: absolute;
top: 0;
right: 0;
color: #ccc;
text-align: center;
font-size: 0.8em;
padding: 5px 10px 0;
line-height: 15px;
height: 15px;
font-weight: 600;
}
</style>
`;
}
function buildFootnoteArray(footnotes: [number, string, string][]): string {
return footnotes
.map(([index, title, link]) =>
link === title
? `<code style="font-size: 90%; opacity: 0.6;">[${index}]</code>: <i style="word-break: break-all">${title}</i><br/>`
: `<code style="font-size: 90%; opacity: 0.6;">[${index}]</code> ${title}: <i style="word-break: break-all">${link}</i><br/>`
)
.join("\n");
}
function transform(legend: string, text: string | null, title: string | null): string {
const options = legend.split("-");
for (const option of options) {
if (option === "alt" && text) {
return text;
}
if (option === "title" && title) {
return title;
}
}
return "";
}
function parseFrontMatterAndContent(markdownText: string): ParseResult {
try {
const parsed = frontMatter(markdownText);
const yamlData = parsed.attributes;
const markdownContent = parsed.body;
const readingTimeResult = readingTime(markdownContent);
return {
yamlData: yamlData as Record<string, any>,
markdownContent,
readingTime: readingTimeResult,
};
} catch (error) {
console.error("Error parsing front-matter:", error);
return {
yamlData: {},
markdownContent: markdownText,
readingTime: readingTime(markdownText),
};
}
}
export function initRenderer(opts: IOpts = {}): RendererAPI {
const footnotes: [number, string, string][] = [];
let footnoteIndex = 0;
let codeIndex = 0;
const listOrderedStack: boolean[] = [];
const listCounters: number[] = [];
const isBrowser = typeof window !== "undefined";
function getOpts(): IOpts {
return opts;
}
function styledContent(styleLabel: string, content: string, tagName?: string): string {
const tag = tagName ?? styleLabel;
const className = `${styleLabel.replace(/_/g, "-")}`;
const headingAttr = /^h\d$/.test(tag) ? " data-heading=\"true\"" : "";
return `<${tag} class="${className}"${headingAttr}>${content}</${tag}>`;
}
function addFootnote(title: string, link: string): number {
const existingFootnote = footnotes.find(([, , existingLink]) => existingLink === link);
if (existingFootnote) {
return existingFootnote[0];
}
footnotes.push([++footnoteIndex, title, link]);
return footnoteIndex;
}
function reset(newOpts: Partial<IOpts>): void {
footnotes.length = 0;
footnoteIndex = 0;
setOptions(newOpts);
}
function setOptions(newOpts: Partial<IOpts>): void {
opts = { ...opts, ...newOpts };
marked.use(markedAlert());
if (isBrowser) {
marked.use(MDKatex({ nonStandard: true }, true));
}
marked.use(markedMarkup());
marked.use(markedInfographic({ themeMode: opts.themeMode }));
}
function buildReadingTime(readingTimeResult: ReadTimeResults): string {
if (!opts.countStatus) {
return "";
}
if (!readingTimeResult.words) {
return "";
}
return `
<blockquote class="md-blockquote">
<p class="md-blockquote-p">字数 ${readingTimeResult?.words},阅读大约需 ${Math.ceil(readingTimeResult?.minutes)} 分钟</p>
</blockquote>
`;
}
const buildFootnotes = () => {
if (!footnotes.length) {
return "";
}
return (
styledContent("h4", "引用链接")
+ styledContent("footnotes", buildFootnoteArray(footnotes), "p")
);
};
const renderer: RendererObject = {
heading({ tokens, depth }: Tokens.Heading) {
const text = this.parser.parseInline(tokens);
const tag = `h${depth}`;
return styledContent(tag, text);
},
paragraph({ tokens }: Tokens.Paragraph): string {
const text = this.parser.parseInline(tokens);
const isFigureImage = text.includes("<figure") && text.includes("<img");
const isEmpty = text.trim() === "";
if (isFigureImage || isEmpty) {
return text;
}
return styledContent("p", text);
},
blockquote({ tokens }: Tokens.Blockquote): string {
const text = this.parser.parse(tokens);
return styledContent("blockquote", text);
},
code({ text, lang = "" }: Tokens.Code): string {
if (lang.startsWith("mermaid")) {
if (isBrowser) {
clearTimeout(codeIndex as any);
codeIndex = setTimeout(async () => {
const windowRef = typeof window !== "undefined" ? (window as any) : undefined;
if (windowRef && windowRef.mermaid) {
const mermaid = windowRef.mermaid;
await mermaid.run();
} else {
const mermaid = await import("mermaid");
await mermaid.default.run();
}
}, 0) as any as number;
}
return `<pre class="mermaid">${text}</pre>`;
}
const langText = lang.split(" ")[0];
const isLanguageRegistered = hljs.getLanguage(langText);
const language = isLanguageRegistered ? langText : "plaintext";
const highlighted = highlightAndFormatCode(
text,
language,
hljs,
!!opts.isShowLineNumber
);
const span = `<span class="mac-sign" style="padding: 10px 14px 0;">${macCodeSvg}</span>`;
let pendingAttr = "";
if (!isLanguageRegistered && langText !== "plaintext") {
const escapedText = text.replace(/"/g, "&quot;");
pendingAttr = ` data-language-pending="${langText}" data-raw-code="${escapedText}" data-show-line-number="${opts.isShowLineNumber}"`;
}
const code = `<code class="language-${lang}"${pendingAttr}>${highlighted}</code>`;
return `<pre class="hljs code__pre">${span}${code}</pre>`;
},
codespan({ text }: Tokens.Codespan): string {
const escapedText = escapeHtml(text);
return styledContent("codespan", escapedText, "code");
},
list({ ordered, items, start = 1 }: Tokens.List) {
listOrderedStack.push(ordered);
listCounters.push(Number(start));
const html = items.map((item) => this.listitem(item)).join("");
listOrderedStack.pop();
listCounters.pop();
return styledContent(ordered ? "ol" : "ul", html);
},
listitem(token: Tokens.ListItem) {
const ordered = listOrderedStack[listOrderedStack.length - 1];
const idx = listCounters[listCounters.length - 1]!;
listCounters[listCounters.length - 1] = idx + 1;
const prefix = ordered ? `${idx}. ` : "• ";
let content: string;
try {
content = this.parser.parseInline(token.tokens);
} catch {
content = this.parser
.parse(token.tokens)
.replace(/^<p(?:\s[^>]*)?>([\s\S]*?)<\/p>/, "$1");
}
return styledContent("listitem", `${prefix}${content}`, "li");
},
image({ href, title, text }: Tokens.Image): string {
const newText = opts.legend ? transform(opts.legend, text, title) : "";
const subText = newText ? styledContent("figcaption", newText) : "";
const titleAttr = title ? ` title="${title}"` : "";
return `<figure><img src="${href}"${titleAttr} alt="${text}"/>${subText}</figure>`;
},
link({ href, title, text, tokens }: Tokens.Link): string {
const parsedText = this.parser.parseInline(tokens);
if (/^https?:\/\/mp\.weixin\.qq\.com/.test(href)) {
return `<a href="${href}" title="${title || text}">${parsedText}</a>`;
}
if (href === text) {
return parsedText;
}
if (opts.citeStatus) {
const ref = addFootnote(title || text, href);
return `<a href="${href}" title="${title || text}">${parsedText}<sup>[${ref}]</sup></a>`;
}
return `<a href="${href}" title="${title || text}">${parsedText}</a>`;
},
strong({ tokens }: Tokens.Strong): string {
return styledContent("strong", this.parser.parseInline(tokens));
},
em({ tokens }: Tokens.Em): string {
return styledContent("em", this.parser.parseInline(tokens));
},
table({ header, rows }: Tokens.Table): string {
const headerRow = header
.map((cell) => {
const text = this.parser.parseInline(cell.tokens);
return styledContent("th", text);
})
.join("");
const body = rows
.map((row) => {
const rowContent = row.map((cell) => this.tablecell(cell)).join("");
return styledContent("tr", rowContent);
})
.join("");
return `
<section style="max-width: 100%; overflow: auto">
<table class="preview-table">
<thead>${headerRow}</thead>
<tbody>${body}</tbody>
</table>
</section>
`;
},
tablecell(token: Tokens.TableCell): string {
const text = this.parser.parseInline(token.tokens);
return styledContent("td", text);
},
hr(_: Tokens.Hr): string {
return styledContent("hr", "");
},
};
marked.use({ renderer });
marked.use(markedMarkup());
marked.use(markedToc());
marked.use(markedSlider());
marked.use(markedAlert({}));
if (isBrowser) {
marked.use(MDKatex({ nonStandard: true }, true));
}
marked.use(markedFootnotes());
marked.use(
markedPlantUML({
inlineSvg: isBrowser,
})
);
marked.use(markedInfographic());
marked.use(markedRuby());
return {
buildAddition,
buildFootnotes,
setOptions,
reset,
parseFrontMatterAndContent,
buildReadingTime,
createContainer(content: string) {
return styledContent("container", content, "section");
},
getOpts,
};
}
function preprocessCjkEmphasis(markdown: string): string {
const processor = unified()
.use(remarkParse)
.use(remarkCjkFriendly);
const tree = processor.parse(markdown);
const extractText = (node: any): string => {
if (node.type === "text") return node.value;
if (node.children) return node.children.map(extractText).join("");
return "";
};
const visit = (node: any, parent?: any, index?: number) => {
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
visit(node.children[i], node, i);
}
}
if (node.type === "strong" && parent && typeof index === "number") {
const text = extractText(node);
parent.children[index] = { type: "html", value: `<strong>${text}</strong>` };
}
if (node.type === "emphasis" && parent && typeof index === "number") {
const text = extractText(node);
parent.children[index] = { type: "html", value: `<em>${text}</em>` };
}
};
visit(tree);
const stringify = unified().use(remarkStringify);
let result = stringify.stringify(tree);
result = result.replace(/&#x([0-9A-Fa-f]+);/g, (_, hex) =>
String.fromCodePoint(parseInt(hex, 16))
);
return result;
}
export function renderMarkdown(raw: string, renderer: RendererAPI): {
html: string;
readingTime: ReadTimeResults;
} {
const { markdownContent, readingTime: readingTimeResult } =
renderer.parseFrontMatterAndContent(raw);
const preprocessed = preprocessCjkEmphasis(markdownContent);
const html = marked.parse(preprocessed) as string;
return { html, readingTime: readingTimeResult };
}
export function postProcessHtml(
baseHtml: string,
reading: ReadTimeResults,
renderer: RendererAPI
): string {
let html = baseHtml;
html = renderer.buildReadingTime(reading) + html;
html += renderer.buildFootnotes();
html += renderer.buildAddition();
html += `
<style>
.hljs.code__pre > .mac-sign {
display: ${renderer.getOpts().isMacCodeBlock ? "flex" : "none"};
}
</style>
`;
html += `
<style>
h2 strong {
color: inherit !important;
}
</style>
`;
return renderer.createContainer(html);
}
+62
View File
@@ -0,0 +1,62 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { ThemeName } from "./types.js";
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
export const THEME_DIR = path.resolve(SCRIPT_DIR, "themes");
const FALLBACK_THEMES: ThemeName[] = ["default", "grace", "simple"];
function stripOutputScope(cssContent: string): string {
let css = cssContent;
css = css.replace(/#output\s*\{/g, "body {");
css = css.replace(/#output\s+/g, "");
css = css.replace(/^#output\s*/gm, "");
return css;
}
function discoverThemesFromDir(dir: string): string[] {
if (!fs.existsSync(dir)) {
return [];
}
return fs
.readdirSync(dir)
.filter((name) => name.endsWith(".css"))
.map((name) => name.replace(/\.css$/i, ""))
.filter((name) => name.toLowerCase() !== "base");
}
function resolveThemeNames(): ThemeName[] {
const localThemes = discoverThemesFromDir(THEME_DIR);
const resolved = localThemes.filter((name) =>
fs.existsSync(path.join(THEME_DIR, `${name}.css`))
);
return resolved.length ? resolved : FALLBACK_THEMES;
}
export const THEME_NAMES: ThemeName[] = resolveThemeNames();
export function loadThemeCss(theme: ThemeName): {
baseCss: string;
themeCss: string;
} {
const basePath = path.join(THEME_DIR, "base.css");
const themePath = path.join(THEME_DIR, `${theme}.css`);
if (!fs.existsSync(basePath)) {
throw new Error(`Missing base CSS: ${basePath}`);
}
if (!fs.existsSync(themePath)) {
throw new Error(`Missing theme CSS for "${theme}": ${themePath}`);
}
return {
baseCss: fs.readFileSync(basePath, "utf-8"),
themeCss: fs.readFileSync(themePath, "utf-8"),
};
}
export function normalizeThemeCss(css: string): string {
return stripOutputScope(css);
}
+39
View File
@@ -0,0 +1,39 @@
/**
* MD 基础主题样式
* 包含所有元素的基础样式和 CSS 变量定义
*/
/* ==================== 容器样式 ==================== */
section,
container {
font-family: var(--md-font-family);
font-size: var(--md-font-size);
line-height: 1.75;
text-align: left;
}
/* 确保 #output 容器应用基础样式 */
#output {
font-family: var(--md-font-family);
font-size: var(--md-font-size);
line-height: 1.75;
text-align: left;
}
/* ==================== Global resets ==================== */
blockquote {
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
/* 去除第一个元素的 margin-top */
#output section > :first-child {
margin-top: 0 !important;
}
.mermaid-diagram .nodeLabel p {
color: unset !important;
letter-spacing: unset !important;
}
+434
View File
@@ -0,0 +1,434 @@
/**
* MD 默认主题(经典主题)
* 按 Alt/Option + Shift + F 可格式化
* 如需使用主题色,请使用 var(--md-primary-color) 代替颜色值
*/
/* ==================== 一级标题 ==================== */
h1 {
display: table;
padding: 0 1em;
border-bottom: 2px solid var(--md-primary-color);
margin: 2em auto 1em;
color: hsl(var(--foreground));
font-size: calc(var(--md-font-size) * 1.2);
font-weight: bold;
text-align: center;
}
/* ==================== 二级标题 ==================== */
h2 {
display: table;
padding: 0 0.2em;
margin: 4em auto 2em;
color: #fff;
background: var(--md-primary-color);
font-size: calc(var(--md-font-size) * 1.2);
font-weight: bold;
text-align: center;
}
/* ==================== 三级标题 ==================== */
h3 {
padding-left: 8px;
border-left: 3px solid var(--md-primary-color);
margin: 2em 8px 0.75em 0;
color: hsl(var(--foreground));
font-size: calc(var(--md-font-size) * 1.1);
font-weight: bold;
line-height: 1.2;
}
/* ==================== 四级标题 ==================== */
h4 {
margin: 2em 8px 0.5em;
color: var(--md-primary-color);
font-size: calc(var(--md-font-size) * 1);
font-weight: bold;
}
/* ==================== 五级标题 ==================== */
h5 {
margin: 1.5em 8px 0.5em;
color: var(--md-primary-color);
font-size: calc(var(--md-font-size) * 1);
font-weight: bold;
}
/* ==================== 六级标题 ==================== */
h6 {
margin: 1.5em 8px 0.5em;
font-size: calc(var(--md-font-size) * 1);
color: var(--md-primary-color);
}
/* ==================== 段落 ==================== */
p {
margin: 1.5em 8px;
letter-spacing: 0.1em;
color: hsl(var(--foreground));
}
/* ==================== 引用块 ==================== */
blockquote {
font-style: normal;
padding: 1em;
border-left: 4px solid var(--md-primary-color);
border-radius: 6px;
color: hsl(var(--foreground));
background: var(--blockquote-background);
margin-bottom: 1em;
}
blockquote > p {
display: block;
font-size: 1em;
letter-spacing: 0.1em;
color: hsl(var(--foreground));
margin: 0;
}
/* ==================== GFM 警告块 ==================== */
.alert-title-note,
.alert-title-tip,
.alert-title-info,
.alert-title-important,
.alert-title-warning,
.alert-title-caution,
.alert-title-abstract,
.alert-title-summary,
.alert-title-tldr,
.alert-title-todo,
.alert-title-success,
.alert-title-done,
.alert-title-question,
.alert-title-help,
.alert-title-faq,
.alert-title-failure,
.alert-title-fail,
.alert-title-missing,
.alert-title-danger,
.alert-title-error,
.alert-title-bug,
.alert-title-example,
.alert-title-quote,
.alert-title-cite {
display: flex;
align-items: center;
gap: 0.5em;
margin-bottom: 0.5em;
}
.alert-title-note {
color: #478be6;
}
.alert-title-tip {
color: #57ab5a;
}
.alert-title-info {
color: #93c5fd;
}
.alert-title-important {
color: #986ee2;
}
.alert-title-warning {
color: #c69026;
}
.alert-title-caution {
color: #e5534b;
}
/* Obsidian-style callout colors */
.alert-title-abstract,
.alert-title-summary,
.alert-title-tldr {
color: #00bfff;
}
.alert-title-todo {
color: #478be6;
}
.alert-title-success,
.alert-title-done {
color: #57ab5a;
}
.alert-title-question,
.alert-title-help,
.alert-title-faq {
color: #c69026;
}
.alert-title-failure,
.alert-title-fail,
.alert-title-missing {
color: #e5534b;
}
.alert-title-danger,
.alert-title-error {
color: #e5534b;
}
.alert-title-bug {
color: #e5534b;
}
.alert-title-example {
color: #986ee2;
}
.alert-title-quote,
.alert-title-cite {
color: #9ca3af;
}
/* GFM Alert SVG 图标颜色 */
.alert-icon-note {
fill: #478be6;
}
.alert-icon-tip {
fill: #57ab5a;
}
.alert-icon-info {
fill: #93c5fd;
}
.alert-icon-important {
fill: #986ee2;
}
.alert-icon-warning {
fill: #c69026;
}
.alert-icon-caution {
fill: #e5534b;
}
/* Obsidian-style callout icon colors */
.alert-icon-abstract,
.alert-icon-summary,
.alert-icon-tldr {
fill: #00bfff;
}
.alert-icon-todo {
fill: #478be6;
}
.alert-icon-success,
.alert-icon-done {
fill: #57ab5a;
}
.alert-icon-question,
.alert-icon-help,
.alert-icon-faq {
fill: #c69026;
}
.alert-icon-failure,
.alert-icon-fail,
.alert-icon-missing {
fill: #e5534b;
}
.alert-icon-danger,
.alert-icon-error {
fill: #e5534b;
}
.alert-icon-bug {
fill: #e5534b;
}
.alert-icon-example {
fill: #986ee2;
}
.alert-icon-quote,
.alert-icon-cite {
fill: #9ca3af;
}
/* ==================== 代码块 ==================== */
pre.code__pre,
.hljs.code__pre {
font-size: 90%;
overflow-x: auto;
border-radius: 8px;
padding: 0 !important;
line-height: 1.5;
margin: 10px 8px;
box-shadow: inset 0 0 10px rgba(0,0,0,0.05);
}
/* ==================== 图片 ==================== */
img {
display: block;
max-width: 100%;
margin: 0.1em auto 0.5em;
border-radius: 4px;
}
/* ==================== 列表 ==================== */
ol {
padding-left: 1em;
margin-left: 0;
color: hsl(var(--foreground));
}
ul {
list-style: circle;
padding-left: 1em;
margin-left: 0;
color: hsl(var(--foreground));
}
li {
display: block;
margin: 0.2em 8px;
color: hsl(var(--foreground));
}
/* ==================== 脚注 ==================== */
/* footnotes 在 buildFootnotes() 中渲染为 <p> 标签 */
p.footnotes {
margin: 0.5em 8px;
font-size: 80%;
color: hsl(var(--foreground));
}
/* ==================== 图表 ==================== */
figure {
margin: 1.5em 8px;
color: hsl(var(--foreground));
}
figcaption,
.md-figcaption {
text-align: center;
color: #888;
font-size: 0.8em;
}
/* ==================== 分隔线 ==================== */
hr {
border-style: solid;
border-width: 2px 0 0;
border-color: rgba(0, 0, 0, 0.1);
-webkit-transform-origin: 0 0;
-webkit-transform: scale(1, 0.5);
transform-origin: 0 0;
transform: scale(1, 0.5);
height: 0.4em;
margin: 1.5em 0;
}
/* ==================== 行内代码 ==================== */
code {
font-size: 90%;
color: #d14;
background: rgba(27, 31, 35, 0.05);
padding: 3px 5px;
border-radius: 4px;
}
/* 代码块内的 code 标签需要特殊处理(覆盖行内 code 样式) */
pre.code__pre > code,
.hljs.code__pre > code {
display: -webkit-box;
padding: 0.5em 1em 1em;
overflow-x: auto;
text-indent: 0;
color: inherit;
background: none;
white-space: nowrap;
margin: 0;
}
/* ==================== 强调 ==================== */
em {
font-style: italic;
font-size: inherit;
}
/* ==================== 链接 ==================== */
a {
color: #576b95;
text-decoration: none;
}
/* ==================== 粗体 ==================== */
strong {
color: var(--md-primary-color);
font-weight: bold;
font-size: inherit;
}
/* ==================== 表格 ==================== */
table {
color: hsl(var(--foreground));
}
thead {
font-weight: bold;
color: hsl(var(--foreground));
}
th {
border: 1px solid #dfdfdf;
padding: 0.25em 0.5em;
color: hsl(var(--foreground));
word-break: keep-all;
background: rgba(0, 0, 0, 0.05);
}
td {
border: 1px solid #dfdfdf;
padding: 0.25em 0.5em;
color: hsl(var(--foreground));
word-break: keep-all;
}
/* ==================== KaTeX 公式 ==================== */
.katex-inline {
max-width: 100%;
overflow-x: auto;
}
.katex-block {
max-width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding: 0.5em 0;
text-align: center;
}
/* ==================== 标记高亮 ==================== */
.markup-highlight {
background-color: var(--md-primary-color);
padding: 2px 4px;
border-radius: 2px;
color: #fff;
}
.markup-underline {
text-decoration: underline;
text-decoration-color: var(--md-primary-color);
}
.markup-wavyline {
text-decoration: underline wavy;
text-decoration-color: var(--md-primary-color);
text-decoration-thickness: 2px;
}
+136
View File
@@ -0,0 +1,136 @@
/**
* MD 优雅主题 (@brzhang)
* 在默认主题基础上添加优雅的视觉效果
*/
/* ==================== 标题样式 ==================== */
h1 {
padding: 0.5em 1em;
border-bottom: 2px solid var(--md-primary-color);
font-size: calc(var(--md-font-size) * 1.4);
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
h2 {
padding: 0.3em 1em;
border-radius: 8px;
font-size: calc(var(--md-font-size) * 1.3);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h3 {
padding-left: 12px;
font-size: calc(var(--md-font-size) * 1.2);
border-left: 4px solid var(--md-primary-color);
border-bottom: 1px dashed var(--md-primary-color);
}
h4 {
font-size: calc(var(--md-font-size) * 1.1);
}
h5 {
font-size: var(--md-font-size);
}
h6 {
font-size: var(--md-font-size);
}
/* ==================== 引用块 ==================== */
blockquote {
font-style: italic;
padding: 1em 1em 1em 2em;
border-left: 4px solid var(--md-primary-color);
border-radius: 6px;
color: rgba(0, 0, 0, 0.6);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
margin-bottom: 1em;
}
.markdown-alert {
font-style: italic;
}
/* ==================== 代码块 ==================== */
pre.code__pre,
.hljs.code__pre {
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05);
}
pre.code__pre > code,
.hljs.code__pre > code {
font-family:
'Fira Code',
Menlo,
Operator Mono,
Consolas,
Monaco,
monospace;
}
/* ==================== 图片 ==================== */
img {
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
figcaption,
.md-figcaption {
text-align: center;
color: #888;
font-size: 0.8em;
}
/* ==================== 列表 ==================== */
ol {
padding-left: 1.5em;
}
ul {
list-style: none;
padding-left: 1.5em;
}
li {
margin: 0.5em 8px;
}
/* ==================== 分隔线 ==================== */
hr {
height: 1px;
border: none;
margin: 2em 0;
background: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0));
}
/* ==================== 表格 ==================== */
table {
border-collapse: separate;
border-spacing: 0;
border-radius: 8px;
margin: 1em 8px;
color: hsl(var(--foreground));
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
thead {
color: #fff;
}
td {
padding: 0.5em 1em;
}
/* ==================== 强调 ==================== */
em {
font-style: italic;
font-size: inherit;
}
/* ==================== 链接 ==================== */
a {
color: #576b95;
text-decoration: none;
}
+465
View File
@@ -0,0 +1,465 @@
/**
* MD 现代主题 (modern)
* 大圆角、药丸形标题、宽松行距、现代感
* 如需使用主题色,请使用 var(--md-primary-color) 代替颜色值
*/
/* ==================== 容器样式覆盖 ==================== */
section,
container {
font-family: var(--md-font-family);
font-size: var(--md-font-size);
line-height: 2;
letter-spacing: 0px;
font-weight: 400;
background-color: var(--md-container-bg);
border: 1px solid rgba(255, 255, 255, 0.01);
border-radius: 25px;
padding: 12px 12px;
}
#output {
font-family: var(--md-font-family);
font-size: var(--md-font-size);
line-height: 2;
}
/* ==================== 一级标题 ==================== */
h1 {
display: table;
padding: 0.3em 1em;
margin: 20px auto;
color: hsl(var(--foreground));
background: var(--md-primary-color);
border-radius: 15px;
font-size: 28px;
font-weight: bold;
text-align: center;
}
/* ==================== 二级标题 ==================== */
h2 {
display: block;
padding: 0.2em 0;
padding-bottom: 0;
margin: 0 auto 20px;
width: 100%;
color: var(--md-primary-color);
font-size: 20px;
font-weight: bold;
letter-spacing: 0.578px;
line-height: 1.7;
border-bottom: 2px solid var(--md-accent-color);
text-align: left;
}
/* ==================== 三级标题 ==================== */
h3 {
padding-left: 10px;
border-left: 4px solid var(--md-primary-color);
border-radius: 2px;
margin: 0 8px 10px;
color: hsl(var(--foreground));
font-size: 20px;
font-weight: bold;
line-height: 1.2;
}
/* ==================== 四级标题 ==================== */
h4 {
margin: 0 8px 10px;
color: var(--md-primary-color);
font-size: 16px;
font-weight: bold;
}
/* ==================== 五级标题 ==================== */
h5 {
display: inline-block;
margin: 0 8px 10px;
padding: 4px 12px;
color: hsl(var(--foreground));
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgb(189, 224, 254);
border-radius: 20px;
font-size: 16px;
font-weight: 500;
}
/* ==================== 六级标题 ==================== */
h6 {
margin: 0 8px 10px;
color: var(--md-primary-color);
font-size: 16px;
font-weight: bold;
}
/* ==================== 段落 ==================== */
p {
margin: 20px 0;
letter-spacing: 0.1em;
color: hsl(var(--foreground));
line-height: 2;
letter-spacing: 0px;
font-size: 15px;
font-weight: 400;
word-break: break-all;
}
/* ==================== 引用块 ==================== */
blockquote {
font-style: normal;
padding: 15px 0;
margin: 12px 0;
border-left: 7px solid var(--md-accent-color);
border-radius: 10px;
color: hsl(var(--foreground));
background-color: var(--blockquote-background);
}
blockquote > p {
display: block;
font-size: 1em;
letter-spacing: 0.1em;
color: hsl(var(--foreground));
margin: 0;
}
/* ==================== GFM 警告块 ==================== */
.alert-title-note,
.alert-title-tip,
.alert-title-info,
.alert-title-important,
.alert-title-warning,
.alert-title-caution,
.alert-title-abstract,
.alert-title-summary,
.alert-title-tldr,
.alert-title-todo,
.alert-title-success,
.alert-title-done,
.alert-title-question,
.alert-title-help,
.alert-title-faq,
.alert-title-failure,
.alert-title-fail,
.alert-title-missing,
.alert-title-danger,
.alert-title-error,
.alert-title-bug,
.alert-title-example,
.alert-title-quote,
.alert-title-cite {
display: flex;
align-items: center;
gap: 0.5em;
margin-bottom: 0.5em;
}
.alert-title-note {
color: #478be6;
}
.alert-title-tip {
color: #57ab5a;
}
.alert-title-info {
color: #93c5fd;
}
.alert-title-important {
color: #986ee2;
}
.alert-title-warning {
color: #c69026;
}
.alert-title-caution {
color: #e5534b;
}
.alert-title-abstract,
.alert-title-summary,
.alert-title-tldr {
color: #00bfff;
}
.alert-title-todo {
color: #478be6;
}
.alert-title-success,
.alert-title-done {
color: #57ab5a;
}
.alert-title-question,
.alert-title-help,
.alert-title-faq {
color: #c69026;
}
.alert-title-failure,
.alert-title-fail,
.alert-title-missing {
color: #e5534b;
}
.alert-title-danger,
.alert-title-error {
color: #e5534b;
}
.alert-title-bug {
color: #e5534b;
}
.alert-title-example {
color: #986ee2;
}
.alert-title-quote,
.alert-title-cite {
color: #9ca3af;
}
/* GFM Alert SVG 图标颜色 */
.alert-icon-note {
fill: #478be6;
}
.alert-icon-tip {
fill: #57ab5a;
}
.alert-icon-info {
fill: #93c5fd;
}
.alert-icon-important {
fill: #986ee2;
}
.alert-icon-warning {
fill: #c69026;
}
.alert-icon-caution {
fill: #e5534b;
}
.alert-icon-abstract,
.alert-icon-summary,
.alert-icon-tldr {
fill: #00bfff;
}
.alert-icon-todo {
fill: #478be6;
}
.alert-icon-success,
.alert-icon-done {
fill: #57ab5a;
}
.alert-icon-question,
.alert-icon-help,
.alert-icon-faq {
fill: #c69026;
}
.alert-icon-failure,
.alert-icon-fail,
.alert-icon-missing {
fill: #e5534b;
}
.alert-icon-danger,
.alert-icon-error {
fill: #e5534b;
}
.alert-icon-bug {
fill: #e5534b;
}
.alert-icon-example {
fill: #986ee2;
}
.alert-icon-quote,
.alert-icon-cite {
fill: #9ca3af;
}
/* ==================== 代码块 ==================== */
pre.code__pre,
.hljs.code__pre {
font-size: 90%;
overflow-x: auto;
border-radius: 10px;
padding: 0 !important;
line-height: 1.5;
margin: 10px 8px;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05);
}
/* ==================== 图片 ==================== */
img {
display: block;
max-width: 100%;
margin: 0.1em auto 0.5em;
border-radius: 10px;
}
/* ==================== 列表 ==================== */
ol {
padding-left: 1em;
margin-left: 0;
color: hsl(var(--foreground));
line-height: 2;
}
ul {
list-style: circle;
padding-left: 1em;
margin-left: 0;
color: hsl(var(--foreground));
line-height: 2;
}
li {
display: block;
margin: 0.2em 8px;
color: hsl(var(--foreground));
}
/* ==================== 脚注 ==================== */
p.footnotes {
margin: 0.5em 8px;
font-size: 80%;
color: hsl(var(--foreground));
}
/* ==================== 图表 ==================== */
figure {
margin: 1.5em 8px;
color: hsl(var(--foreground));
}
figcaption,
.md-figcaption {
text-align: center;
color: #888;
font-size: 0.8em;
}
/* ==================== 分隔线 ==================== */
hr {
border-style: solid;
border-width: 1px 0 0;
border-color: var(--md-accent-color);
margin: 1.5em 0;
}
/* ==================== 行内代码 ==================== */
code {
font-size: 90%;
color: #d14;
background: rgba(27, 31, 35, 0.05);
padding: 3px 5px;
border-radius: 4px;
}
/* 代码块内的 code 标签需要特殊处理(覆盖行内 code 样式) */
pre.code__pre > code,
.hljs.code__pre > code {
display: -webkit-box;
padding: 0.5em 1em 1em;
overflow-x: auto;
text-indent: 0;
color: inherit;
background: none;
white-space: nowrap;
margin: 0;
}
/* ==================== 强调 ==================== */
em {
font-style: italic;
font-size: inherit;
}
/* ==================== 链接 ==================== */
a {
color: var(--md-primary-color);
text-decoration: none;
}
/* ==================== 粗体 ==================== */
strong {
color: var(--md-primary-color);
font-weight: bold;
font-size: inherit;
}
/* ==================== 表格 ==================== */
table {
color: hsl(var(--foreground));
}
thead {
font-weight: bold;
color: hsl(var(--foreground));
}
th {
border: 1px solid #dfdfdf;
padding: 0.25em 0.5em;
color: hsl(var(--foreground));
word-break: keep-all;
background: color-mix(in srgb, var(--md-primary-color) 10%, transparent);
}
td {
border: 1px solid #dfdfdf;
padding: 0.25em 0.5em;
color: hsl(var(--foreground));
word-break: keep-all;
}
/* ==================== KaTeX 公式 ==================== */
.katex-inline {
max-width: 100%;
overflow-x: auto;
}
.katex-block {
max-width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding: 0.5em 0;
text-align: center;
}
/* ==================== 标记高亮 ==================== */
.markup-highlight {
background-color: var(--md-primary-color);
padding: 2px 4px;
border-radius: 4px;
color: #fff;
}
.markup-underline {
text-decoration: underline;
text-decoration-color: var(--md-primary-color);
}
.markup-wavyline {
text-decoration: underline wavy;
text-decoration-color: var(--md-primary-color);
text-decoration-thickness: 2px;
}

Some files were not shown because too many files have changed in this diff Show More