mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-31 22:29:48 +08:00
feat(baoyu-markdown-to-html): inline rendering pipeline and enhance modern theme
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,17 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { writeFile } from 'node:fs/promises';
|
|
||||||
import os from 'node:os';
|
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
import { spawnSync } from 'node:child_process';
|
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
import type { StyleConfig, HtmlDocumentMeta } from './md/types.js';
|
||||||
|
import { DEFAULT_STYLE, THEME_STYLE_DEFAULTS } from './md/constants.js';
|
||||||
|
import { loadThemeCss, normalizeThemeCss } from './md/themes.js';
|
||||||
|
import { initRenderer, renderMarkdown, postProcessHtml } from './md/renderer.js';
|
||||||
|
import {
|
||||||
|
buildCss, loadCodeThemeCss, buildHtmlDocument,
|
||||||
|
inlineCss, normalizeInlineCss, modifyHtmlStructure, removeFirstHeading,
|
||||||
|
} from './md/html-builder.js';
|
||||||
|
|
||||||
interface ImageInfo {
|
interface ImageInfo {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
@@ -187,33 +191,23 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
|||||||
|
|
||||||
const modifiedMarkdown = `---\n${Object.entries(frontmatter).map(([k, v]) => `${k}: ${v}`).join('\n')}\n---\n${modifiedBody}`;
|
const modifiedMarkdown = `---\n${Object.entries(frontmatter).map(([k, v]) => `${k}: ${v}`).join('\n')}\n---\n${modifiedBody}`;
|
||||||
|
|
||||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'markdown-to-html-'));
|
|
||||||
const tempMdPath = path.join(tempDir, 'temp-article.md');
|
|
||||||
await writeFile(tempMdPath, modifiedMarkdown, 'utf-8');
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
const renderScript = path.join(__dirname, 'md', 'render.ts');
|
|
||||||
|
|
||||||
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}`);
|
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}`);
|
||||||
|
|
||||||
const args = ['-y', 'bun', renderScript, tempMdPath, '--theme', theme];
|
const themeDefaults = THEME_STYLE_DEFAULTS[theme] ?? {};
|
||||||
if (keepTitle) args.push('--keep-title');
|
const style: StyleConfig = { ...DEFAULT_STYLE, ...themeDefaults };
|
||||||
|
const { baseCss, themeCss } = loadThemeCss(theme);
|
||||||
|
const css = normalizeThemeCss(buildCss(baseCss, themeCss, style));
|
||||||
|
const codeThemeCss = loadCodeThemeCss('github');
|
||||||
|
|
||||||
const result = spawnSync('npx', args, {
|
const renderer = initRenderer({});
|
||||||
stdio: ['inherit', 'pipe', 'pipe'],
|
const { html: baseHtml, readingTime } = renderMarkdown(modifiedMarkdown, renderer);
|
||||||
cwd: baseDir,
|
let htmlContent = postProcessHtml(baseHtml, readingTime, renderer);
|
||||||
});
|
if (!keepTitle) htmlContent = removeFirstHeading(htmlContent);
|
||||||
|
|
||||||
if (result.status !== 0) {
|
const meta: HtmlDocumentMeta = { title, author, description: summary };
|
||||||
const stderr = result.stderr?.toString() || '';
|
const fullHtml = buildHtmlDocument(meta, css, htmlContent, codeThemeCss);
|
||||||
throw new Error(`Render failed: ${stderr}`);
|
const inlinedHtml = normalizeInlineCss(await inlineCss(fullHtml), style);
|
||||||
}
|
const renderedHtml = modifyHtmlStructure(inlinedHtml);
|
||||||
|
|
||||||
const tempHtmlPath = tempMdPath.replace(/\.md$/i, '.html');
|
|
||||||
if (!fs.existsSync(tempHtmlPath)) {
|
|
||||||
throw new Error(`HTML file not generated: ${tempHtmlPath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalHtmlPath = markdownPath.replace(/\.md$/i, '.html');
|
const finalHtmlPath = markdownPath.replace(/\.md$/i, '.html');
|
||||||
let backupPath: string | undefined;
|
let backupPath: string | undefined;
|
||||||
@@ -224,11 +218,16 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
|||||||
fs.renameSync(finalHtmlPath, backupPath);
|
fs.renameSync(finalHtmlPath, backupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.copyFileSync(tempHtmlPath, finalHtmlPath);
|
fs.writeFileSync(finalHtmlPath, renderedHtml, 'utf-8');
|
||||||
|
|
||||||
const contentImages: ImageInfo[] = [];
|
const contentImages: ImageInfo[] = [];
|
||||||
|
let tempDir: string | undefined;
|
||||||
for (const img of images) {
|
for (const img of images) {
|
||||||
const localPath = await resolveImagePath(img.src, baseDir, tempDir);
|
if (!tempDir && (img.src.startsWith('http://') || img.src.startsWith('https://'))) {
|
||||||
|
const os = await import('node:os');
|
||||||
|
tempDir = fs.mkdtempSync(path.join(os.default.tmpdir(), 'markdown-to-html-'));
|
||||||
|
}
|
||||||
|
const localPath = await resolveImagePath(img.src, baseDir, tempDir ?? baseDir);
|
||||||
contentImages.push({
|
contentImages.push({
|
||||||
placeholder: img.placeholder,
|
placeholder: img.placeholder,
|
||||||
localPath,
|
localPath,
|
||||||
@@ -236,12 +235,12 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let htmlContent = fs.readFileSync(finalHtmlPath, 'utf-8');
|
let finalContent = fs.readFileSync(finalHtmlPath, 'utf-8');
|
||||||
for (const img of contentImages) {
|
for (const img of contentImages) {
|
||||||
const imgTag = `<img src="${img.placeholder}" data-local-path="${img.localPath}" style="display: block; width: 100%; margin: 1.5em auto;">`;
|
const imgTag = `<img src="${img.originalPath}" data-local-path="${img.localPath}" style="display: block; width: 100%; margin: 1.5em auto;">`;
|
||||||
htmlContent = htmlContent.replace(img.placeholder, imgTag);
|
finalContent = finalContent.replace(img.placeholder, imgTag);
|
||||||
}
|
}
|
||||||
fs.writeFileSync(finalHtmlPath, htmlContent, 'utf-8');
|
fs.writeFileSync(finalHtmlPath, finalContent, 'utf-8');
|
||||||
|
|
||||||
console.error(`[markdown-to-html] HTML saved to: ${finalHtmlPath}`);
|
console.error(`[markdown-to-html] HTML saved to: ${finalHtmlPath}`);
|
||||||
|
|
||||||
|
|||||||
@@ -400,10 +400,10 @@ export function renderMarkdown(raw: string, renderer: RendererAPI): {
|
|||||||
html: string;
|
html: string;
|
||||||
readingTime: ReadTimeResults;
|
readingTime: ReadTimeResults;
|
||||||
} {
|
} {
|
||||||
const preprocessed = preprocessCjkEmphasis(raw);
|
|
||||||
const { markdownContent, readingTime: readingTimeResult } =
|
const { markdownContent, readingTime: readingTimeResult } =
|
||||||
renderer.parseFrontMatterAndContent(preprocessed);
|
renderer.parseFrontMatterAndContent(raw);
|
||||||
const html = marked.parse(markdownContent) as string;
|
const preprocessed = preprocessCjkEmphasis(markdownContent);
|
||||||
|
const html = marked.parse(preprocessed) as string;
|
||||||
return { html, readingTime: readingTimeResult };
|
return { html, readingTime: readingTimeResult };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* MD 现代主题 (modern)
|
* MD 现代主题 (modern)
|
||||||
* 大圆角、药丸形标题、宽松行距、现代感
|
* 大圆角、药丸形标题、宽松行距、现代感
|
||||||
|
* 如需使用主题色,请使用 var(--md-primary-color) 代替颜色值
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ==================== 容器样式覆盖 ==================== */
|
/* ==================== 容器样式覆盖 ==================== */
|
||||||
@@ -9,6 +10,8 @@ container {
|
|||||||
font-family: var(--md-font-family);
|
font-family: var(--md-font-family);
|
||||||
font-size: var(--md-font-size);
|
font-size: var(--md-font-size);
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
|
letter-spacing: 0px;
|
||||||
|
font-weight: 400;
|
||||||
background-color: var(--md-container-bg);
|
background-color: var(--md-container-bg);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.01);
|
border: 1px solid rgba(255, 255, 255, 0.01);
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
@@ -44,15 +47,22 @@ h2 {
|
|||||||
color: var(--md-primary-color);
|
color: var(--md-primary-color);
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
letter-spacing: 0.578px;
|
||||||
|
line-height: 1.7;
|
||||||
border-bottom: 2px solid var(--md-accent-color);
|
border-bottom: 2px solid var(--md-accent-color);
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 三级标题 ==================== */
|
/* ==================== 三级标题 ==================== */
|
||||||
h3 {
|
h3 {
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 4px solid var(--md-primary-color);
|
||||||
|
border-radius: 2px;
|
||||||
margin: 0 8px 10px;
|
margin: 0 8px 10px;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
font-size: 18px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 四级标题 ==================== */
|
/* ==================== 四级标题 ==================== */
|
||||||
@@ -67,7 +77,7 @@ h4 {
|
|||||||
h5 {
|
h5 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 8px 10px;
|
margin: 0 8px 10px;
|
||||||
padding: 4px 10px;
|
padding: 4px 12px;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
background: rgba(255, 255, 255, 0.7);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
border: 1px solid rgb(189, 224, 254);
|
border: 1px solid rgb(189, 224, 254);
|
||||||
@@ -87,86 +97,300 @@ h6 {
|
|||||||
/* ==================== 段落 ==================== */
|
/* ==================== 段落 ==================== */
|
||||||
p {
|
p {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
letter-spacing: 0px;
|
letter-spacing: 0px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 引用块 ==================== */
|
/* ==================== 引用块 ==================== */
|
||||||
blockquote {
|
blockquote {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
padding: 15px 12px;
|
padding: 15px 0;
|
||||||
|
margin: 12px 0;
|
||||||
border-left: 7px solid var(--md-accent-color);
|
border-left: 7px solid var(--md-accent-color);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
background-color: var(--blockquote-background);
|
background-color: var(--blockquote-background);
|
||||||
margin: 12px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote > p {
|
blockquote > p {
|
||||||
|
display: block;
|
||||||
|
font-size: 1em;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
font-size: 14px;
|
|
||||||
margin: 0;
|
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,
|
pre.code__pre,
|
||||||
.hljs.code__pre {
|
.hljs.code__pre {
|
||||||
|
font-size: 90%;
|
||||||
|
overflow-x: auto;
|
||||||
border-radius: 10px;
|
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);
|
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 图片 ==================== */
|
/* ==================== 图片 ==================== */
|
||||||
img {
|
img {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0.1em auto 0.5em;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin: 5px auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 列表 ==================== */
|
/* ==================== 列表 ==================== */
|
||||||
ol {
|
ol {
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
margin: 15px 0;
|
margin-left: 0;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: circle;
|
||||||
padding-left: 0;
|
padding-left: 1em;
|
||||||
margin: 15px 0;
|
margin-left: 0;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0.2em 0;
|
display: block;
|
||||||
|
margin: 0.2em 8px;
|
||||||
color: hsl(var(--foreground));
|
color: hsl(var(--foreground));
|
||||||
font-size: 15px;
|
}
|
||||||
|
|
||||||
|
/* ==================== 脚注 ==================== */
|
||||||
|
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 {
|
hr {
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px 0 0;
|
border-width: 1px 0 0;
|
||||||
border-color: var(--md-primary-color);
|
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;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 强调 ==================== */
|
/* ==================== 强调 ==================== */
|
||||||
strong {
|
em {
|
||||||
color: hsl(var(--foreground));
|
font-style: italic;
|
||||||
font-weight: bold;
|
font-size: inherit;
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================== 标记高亮 ==================== */
|
|
||||||
.markup-highlight {
|
|
||||||
background-color: hsl(var(--foreground));
|
|
||||||
padding: 10px;
|
|
||||||
color: var(--md-container-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.markup-underline {
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: var(--md-accent-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 链接 ==================== */
|
/* ==================== 链接 ==================== */
|
||||||
@@ -175,7 +399,67 @@ a {
|
|||||||
text-decoration: none;
|
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 {
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user