mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-08-02 15:19:48 +08:00
feat(baoyu-markdown-to-html): add --cite option for bottom citations
Add optional --cite flag to convert ordinary external links to numbered bottom citations. WeChat links stay inline. Also translate theme and color descriptions from Chinese to English for consistency.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: baoyu-markdown-to-html
|
name: baoyu-markdown-to-html
|
||||||
description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, and infographics. Use when user asks for "markdown to html", "convert md to html", "md转html", or needs styled HTML output from markdown.
|
description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, infographics, and optional bottom citations for external links. Use when user asks for "markdown to html", "convert md to html", "md转html", "微信外链转底部引用", or needs styled HTML output from markdown.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Markdown to HTML Converter
|
# Markdown to HTML Converter
|
||||||
@@ -98,15 +98,26 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { Select-Str
|
|||||||
|
|
||||||
| Theme | Description |
|
| Theme | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `default` (Recommended) | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 |
|
| `default` (Recommended) | Classic - traditional layout, centered title with bottom border, H2 with white text on colored background |
|
||||||
| `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 |
|
| `grace` | Elegant - text shadow, rounded cards, refined blockquotes |
|
||||||
| `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 |
|
| `simple` | Minimal - modern minimalist, asymmetric rounded corners, clean whitespace |
|
||||||
| `modern` | 现代主题 - 大圆角、药丸形标题、宽松行距(搭配 `--color red` 还原传统红金风格) |
|
| `modern` | Modern - large radius, pill-shaped titles, relaxed line height (pair with `--color red` for traditional red-gold style) |
|
||||||
|
|
||||||
|
### Step 1.5: Determine Citation Mode
|
||||||
|
|
||||||
|
**Default**: Off. Do not ask by default.
|
||||||
|
|
||||||
|
**Enable only if the user explicitly asks** for "微信外链转底部引用", "底部引用", "文末引用", or passes `--cite`.
|
||||||
|
|
||||||
|
**Behavior when enabled**:
|
||||||
|
- Ordinary external links are rendered with numbered superscripts and collected under a final `引用链接` section.
|
||||||
|
- `https://mp.weixin.qq.com/...` links stay as direct links and are not moved to the bottom.
|
||||||
|
- Bare links where link text equals URL stay inline.
|
||||||
|
|
||||||
### Step 2: Convert
|
### Step 2: Convert
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme>
|
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme> [--cite]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Report Result
|
### Step 3: Report Result
|
||||||
@@ -128,6 +139,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
|||||||
| `--font-family <name>` | Font: sans, serif, serif-cjk, mono, or CSS value | theme default |
|
| `--font-family <name>` | Font: sans, serif, serif-cjk, mono, or CSS value | theme default |
|
||||||
| `--font-size <N>` | Font size: 14px, 15px, 16px, 17px, 18px | 16px |
|
| `--font-size <N>` | Font size: 14px, 15px, 16px, 17px, 18px | 16px |
|
||||||
| `--title <title>` | Override title from frontmatter | |
|
| `--title <title>` | Override title from frontmatter | |
|
||||||
|
| `--cite` | Convert external links to bottom citations, append `引用链接` section | false (off) |
|
||||||
| `--keep-title` | Keep the first heading in content | false (removed) |
|
| `--keep-title` | Keep the first heading in content | false (removed) |
|
||||||
| `--help` | Show help | |
|
| `--help` | Show help | |
|
||||||
|
|
||||||
@@ -135,19 +147,19 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
|||||||
|
|
||||||
| Name | Hex | Label |
|
| Name | Hex | Label |
|
||||||
|------|-----|-------|
|
|------|-----|-------|
|
||||||
| blue | #0F4C81 | 经典蓝 |
|
| blue | #0F4C81 | Classic Blue |
|
||||||
| green | #009874 | 翡翠绿 |
|
| green | #009874 | Emerald Green |
|
||||||
| vermilion | #FA5151 | 活力橘 |
|
| vermilion | #FA5151 | Vibrant Vermilion |
|
||||||
| yellow | #FECE00 | 柠檬黄 |
|
| yellow | #FECE00 | Lemon Yellow |
|
||||||
| purple | #92617E | 薰衣紫 |
|
| purple | #92617E | Lavender Purple |
|
||||||
| sky | #55C9EA | 天空蓝 |
|
| sky | #55C9EA | Sky Blue |
|
||||||
| rose | #B76E79 | 玫瑰金 |
|
| rose | #B76E79 | Rose Gold |
|
||||||
| olive | #556B2F | 橄榄绿 |
|
| olive | #556B2F | Olive Green |
|
||||||
| black | #333333 | 石墨黑 |
|
| black | #333333 | Graphite Black |
|
||||||
| gray | #A9A9A9 | 雾烟灰 |
|
| gray | #A9A9A9 | Smoke Gray |
|
||||||
| pink | #FFB7C5 | 樱花粉 |
|
| pink | #FFB7C5 | Sakura Pink |
|
||||||
| red | #A93226 | 中国红 |
|
| red | #A93226 | China Red |
|
||||||
| orange | #D97757 | 暖橘 (modern default) |
|
| orange | #D97757 | Warm Orange (modern default) |
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
@@ -161,6 +173,9 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme grace
|
|||||||
# Theme with custom color
|
# Theme with custom color
|
||||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red
|
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red
|
||||||
|
|
||||||
|
# Enable bottom citations for ordinary external links
|
||||||
|
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --cite
|
||||||
|
|
||||||
# Keep the first heading in content
|
# Keep the first heading in content
|
||||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --keep-title
|
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --keep-title
|
||||||
|
|
||||||
@@ -200,10 +215,10 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
|||||||
|
|
||||||
| Theme | Description |
|
| Theme | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `default` | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 |
|
| `default` | Classic - traditional layout, centered title with bottom border, H2 with white text on colored background |
|
||||||
| `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 (by @brzhang) |
|
| `grace` | Elegant - text shadow, rounded cards, refined blockquotes (by @brzhang) |
|
||||||
| `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 (by @okooo5km) |
|
| `simple` | Minimal - modern minimalist, asymmetric rounded corners, clean whitespace (by @okooo5km) |
|
||||||
| `modern` | 现代主题 - 大圆角、药丸形标题、宽松行距(搭配 `--color red` 还原传统红金风格) |
|
| `modern` | Modern - large radius, pill-shaped titles, relaxed line height (pair with `--color red` for traditional red-gold style) |
|
||||||
|
|
||||||
## Supported Markdown Features
|
## Supported Markdown Features
|
||||||
|
|
||||||
@@ -215,7 +230,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
|||||||
| Inline code | `` `code` `` |
|
| Inline code | `` `code` `` |
|
||||||
| Tables | GitHub-flavored markdown tables |
|
| Tables | GitHub-flavored markdown tables |
|
||||||
| Images | `` |
|
| Images | `` |
|
||||||
| Links | `[text](url)` with footnote references |
|
| Links | `[text](url)`; add `--cite` to move ordinary external links into bottom references |
|
||||||
| Blockquotes | `> quote` |
|
| Blockquotes | `> quote` |
|
||||||
| Lists | `-` unordered, `1.` ordered |
|
| Lists | `-` unordered, `1.` ordered |
|
||||||
| Alerts | `> [!NOTE]`, `> [!WARNING]`, etc. |
|
| Alerts | `> [!NOTE]`, `> [!WARNING]`, etc. |
|
||||||
|
|||||||
@@ -122,11 +122,15 @@ function parseFrontmatter(content: string): { frontmatter: Record<string, string
|
|||||||
return { frontmatter, body: match[2]! };
|
return { frontmatter, body: match[2]! };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function convertMarkdown(markdownPath: string, options?: { title?: string; theme?: string; keepTitle?: boolean }): Promise<ParsedResult> {
|
export async function convertMarkdown(
|
||||||
|
markdownPath: string,
|
||||||
|
options?: { title?: string; theme?: string; keepTitle?: boolean; citeStatus?: boolean }
|
||||||
|
): Promise<ParsedResult> {
|
||||||
const baseDir = path.dirname(markdownPath);
|
const baseDir = path.dirname(markdownPath);
|
||||||
const content = fs.readFileSync(markdownPath, 'utf-8');
|
const content = fs.readFileSync(markdownPath, 'utf-8');
|
||||||
const theme = options?.theme ?? 'default';
|
const theme = options?.theme ?? 'default';
|
||||||
const keepTitle = options?.keepTitle ?? false;
|
const keepTitle = options?.keepTitle ?? false;
|
||||||
|
const citeStatus = options?.citeStatus ?? false;
|
||||||
|
|
||||||
const { frontmatter, body } = parseFrontmatter(content);
|
const { frontmatter, body } = parseFrontmatter(content);
|
||||||
|
|
||||||
@@ -191,7 +195,7 @@ 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}`;
|
||||||
|
|
||||||
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}`);
|
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}, citeStatus: ${citeStatus}`);
|
||||||
|
|
||||||
const themeDefaults = THEME_STYLE_DEFAULTS[theme] ?? {};
|
const themeDefaults = THEME_STYLE_DEFAULTS[theme] ?? {};
|
||||||
const style: StyleConfig = { ...DEFAULT_STYLE, ...themeDefaults };
|
const style: StyleConfig = { ...DEFAULT_STYLE, ...themeDefaults };
|
||||||
@@ -199,7 +203,7 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
|||||||
const css = normalizeThemeCss(buildCss(baseCss, themeCss, style));
|
const css = normalizeThemeCss(buildCss(baseCss, themeCss, style));
|
||||||
const codeThemeCss = loadCodeThemeCss('github');
|
const codeThemeCss = loadCodeThemeCss('github');
|
||||||
|
|
||||||
const renderer = initRenderer({});
|
const renderer = initRenderer({ citeStatus });
|
||||||
const { html: baseHtml, readingTime } = renderMarkdown(modifiedMarkdown, renderer);
|
const { html: baseHtml, readingTime } = renderMarkdown(modifiedMarkdown, renderer);
|
||||||
let htmlContent = postProcessHtml(baseHtml, readingTime, renderer);
|
let htmlContent = postProcessHtml(baseHtml, readingTime, renderer);
|
||||||
if (!keepTitle) htmlContent = removeFirstHeading(htmlContent);
|
if (!keepTitle) htmlContent = removeFirstHeading(htmlContent);
|
||||||
@@ -263,6 +267,7 @@ Usage:
|
|||||||
Options:
|
Options:
|
||||||
--title <title> Override title
|
--title <title> Override title
|
||||||
--theme <name> Theme name (default, grace, simple). Default: default
|
--theme <name> Theme name (default, grace, simple). Default: default
|
||||||
|
--cite Convert ordinary external links to bottom citations. Default: off
|
||||||
--keep-title Keep the first heading in content. Default: false (removed)
|
--keep-title Keep the first heading in content. Default: false (removed)
|
||||||
--help Show this help
|
--help Show this help
|
||||||
|
|
||||||
@@ -284,6 +289,7 @@ Output JSON format:
|
|||||||
Example:
|
Example:
|
||||||
npx -y bun main.ts article.md
|
npx -y bun main.ts article.md
|
||||||
npx -y bun main.ts article.md --theme grace
|
npx -y bun main.ts article.md --theme grace
|
||||||
|
npx -y bun main.ts article.md --cite
|
||||||
`);
|
`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
@@ -297,6 +303,7 @@ async function main(): Promise<void> {
|
|||||||
let markdownPath: string | undefined;
|
let markdownPath: string | undefined;
|
||||||
let title: string | undefined;
|
let title: string | undefined;
|
||||||
let theme: string | undefined;
|
let theme: string | undefined;
|
||||||
|
let citeStatus = false;
|
||||||
let keepTitle = false;
|
let keepTitle = false;
|
||||||
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
@@ -305,6 +312,8 @@ async function main(): Promise<void> {
|
|||||||
title = args[++i];
|
title = args[++i];
|
||||||
} else if (arg === '--theme' && args[i + 1]) {
|
} else if (arg === '--theme' && args[i + 1]) {
|
||||||
theme = args[++i];
|
theme = args[++i];
|
||||||
|
} else if (arg === '--cite') {
|
||||||
|
citeStatus = true;
|
||||||
} else if (arg === '--keep-title') {
|
} else if (arg === '--keep-title') {
|
||||||
keepTitle = true;
|
keepTitle = true;
|
||||||
} else if (!arg.startsWith('-')) {
|
} else if (!arg.startsWith('-')) {
|
||||||
@@ -322,7 +331,7 @@ async function main(): Promise<void> {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await convertMarkdown(markdownPath, { title, theme, keepTitle });
|
const result = await convertMarkdown(markdownPath, { title, theme, keepTitle, citeStatus });
|
||||||
console.log(JSON.stringify(result, null, 2));
|
console.log(JSON.stringify(result, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user