From 6edc1b782262e30a90eb2746f54663535fa7d33b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20Liu=20=E5=AE=9D=E7=8E=89?= Date: Sat, 28 Feb 2026 11:18:16 -0600 Subject: [PATCH] feat(baoyu-markdown-to-html): rename themes and add color presets with theme defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename red→heritage and orange→warm themes. Add 13 named color presets, serif-cjk font family, and per-theme style defaults with CLI override support. --- skills/baoyu-markdown-to-html/SKILL.md | 34 +++++++-- .../scripts/md/render.ts | 75 ++++++++++++++++--- .../md/themes/{red.css => heritage.css} | 60 +++++++-------- .../md/themes/{orange.css => warm.css} | 56 +++++++------- 4 files changed, 150 insertions(+), 75 deletions(-) rename skills/baoyu-markdown-to-html/scripts/md/themes/{red.css => heritage.css} (66%) rename skills/baoyu-markdown-to-html/scripts/md/themes/{orange.css => warm.css} (71%) diff --git a/skills/baoyu-markdown-to-html/SKILL.md b/skills/baoyu-markdown-to-html/SKILL.md index 8cabe8d..40b2cf0 100644 --- a/skills/baoyu-markdown-to-html/SKILL.md +++ b/skills/baoyu-markdown-to-html/SKILL.md @@ -92,8 +92,8 @@ test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && grep -o 'default | `default` (Recommended) | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 | | `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 | | `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 | -| `red` | 红色主题 - 红金配色,宋体排版,传统书法风格 | -| `orange` | 橙色主题 - 暖色调现代风,宽松行距,圆角装饰 | +| `heritage` | 传统主题 - 宋体排版,传统书法风格,默认红金配色 | +| `warm` | 温暖主题 - 暖色调现代风,宽松行距,圆角装饰 | ### Step 2: Convert @@ -115,11 +115,32 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts [options] | Option | Description | Default | |--------|-------------|---------| -| `--theme ` | Theme name (default, grace, simple, red, orange) | default | +| `--theme ` | Theme name (default, grace, simple, heritage, warm) | default | +| `--color ` | Primary color: preset name or hex value | theme default | +| `--font-family ` | Font: sans, serif, serif-cjk, mono, or CSS value | theme default | +| `--font-size ` | Font size: 14px, 15px, 16px, 17px, 18px | 16px | | `--title ` | Override title from frontmatter | | | `--keep-title` | Keep the first heading in content | false (removed) | | `--help` | Show help | | +**Color Presets:** + +| Name | Hex | Label | +|------|-----|-------| +| blue | #0F4C81 | 经典蓝 | +| green | #009874 | 翡翠绿 | +| vermilion | #FA5151 | 活力橘 | +| yellow | #FECE00 | 柠檬黄 | +| purple | #92617E | 薰衣紫 | +| sky | #55C9EA | 天空蓝 | +| rose | #B76E79 | 玫瑰金 | +| olive | #556B2F | 橄榄绿 | +| black | #333333 | 石墨黑 | +| gray | #A9A9A9 | 雾烟灰 | +| pink | #FFB7C5 | 樱花粉 | +| red | #A93226 | 中国红 (heritage default) | +| orange | #D97757 | 暖橘 (warm default) | + **Examples:** ```bash @@ -129,6 +150,9 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts article.md # With specific theme npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --theme grace +# Theme with custom color +npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --theme heritage --color green + # Keep the first heading in content npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --keep-title @@ -171,8 +195,8 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --title "My Article" | `default` | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 | | `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 (by @brzhang) | | `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 (by @okooo5km) | -| `red` | 红色主题 - 红金配色,宋体排版,传统书法风格 | -| `orange` | 橙色主题 - 暖色调现代风,宽松行距,圆角装饰 | +| `heritage` | 传统主题 - 宋体排版,传统书法风格,默认红金配色 | +| `warm` | 温暖主题 - 暖色调现代风,宽松行距,圆角装饰 | ## Supported Markdown Features diff --git a/skills/baoyu-markdown-to-html/scripts/md/render.ts b/skills/baoyu-markdown-to-html/scripts/md/render.ts index 70755f8..31e6f73 100644 --- a/skills/baoyu-markdown-to-html/scripts/md/render.ts +++ b/skills/baoyu-markdown-to-html/scripts/md/render.ts @@ -44,11 +44,28 @@ const FALLBACK_THEMES: ThemeName[] = ["default", "grace", "simple"]; 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`, }; const FONT_SIZE_OPTIONS = ["14px", "15px", "16px", "17px", "18px"]; +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", +}; + const CODE_BLOCK_THEMES = [ "1c-light", "a11y-dark", "a11y-light", "agate", "an-old-hope", "androidstudio", "arduino-light", "arta", "ascetic", @@ -77,6 +94,8 @@ interface StyleConfig { fontSize: string; foreground: string; blockquoteBackground: string; + accentColor: string; + containerBg: string; } const DEFAULT_STYLE: StyleConfig = { @@ -85,6 +104,26 @@ const DEFAULT_STYLE: StyleConfig = { fontSize: "16px", foreground: "0 0% 3.9%", blockquoteBackground: "#f7f7f7", + accentColor: "#6B7280", + containerBg: "transparent", +}; + +const THEME_STYLE_DEFAULTS: Record<string, Partial<StyleConfig>> = { + heritage: { + primaryColor: COLOR_PRESETS.red, + accentColor: "#D4AC0D", + containerBg: "rgba(255, 251, 240, 1)", + fontFamily: FONT_FAMILY_MAP["serif-cjk"], + blockquoteBackground: "rgba(253, 237, 236, 1)", + }, + warm: { + 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)", + }, }; Object.entries(COMMON_LANGUAGES).forEach(([name, lang]) => { @@ -532,8 +571,8 @@ function printUsage(): void { "", "Options:", ` --theme <name> Theme (${THEME_NAMES.join(", ")})`, - ` --color <hex> Primary color (default: ${DEFAULT_STYLE.primaryColor})`, - ` --font-family <name> Font: sans, serif, mono, or CSS value`, + ` --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`, @@ -559,15 +598,19 @@ function resolveFontFamily(value: string): string { return FONT_FAMILY_MAP[value] ?? value; } +function resolveColor(value: string): string { + return COLOR_PRESETS[value] ?? value; +} + 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 = ext.default_color ?? DEFAULT_STYLE.primaryColor; - let fontFamily = ext.default_font_family ? resolveFontFamily(ext.default_font_family) : DEFAULT_STYLE.fontFamily; - let fontSize = ext.default_font_size ?? DEFAULT_STYLE.fontSize; + 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; @@ -605,7 +648,7 @@ function parseArgs(argv: string[]): CliOptions | null { if (arg === "--color" || arg.startsWith("--color=")) { const val = parseArgValue(argv, i, "--color"); if (!val) { console.error("Missing value for --color"); return null; } - primaryColor = val; + primaryColor = resolveColor(val); if (!arg.includes("=")) i += 1; continue; } @@ -678,9 +721,9 @@ interface CliOptions { inputPath: string; theme: ThemeName; keepTitle: boolean; - primaryColor: string; - fontFamily: string; - fontSize: string; + primaryColor?: string; + fontFamily?: string; + fontSize?: string; codeTheme: string; isMacCodeBlock: boolean; isShowLineNumber: boolean; @@ -883,6 +926,8 @@ function buildCss(baseCss: string, themeCss: string, style: StyleConfig = DEFAUL --md-font-size: ${style.fontSize}; --foreground: ${style.foreground}; --blockquote-background: ${style.blockquoteBackground}; + --md-accent-color: ${style.accentColor}; + --md-container-bg: ${style.containerBg}; } body { @@ -978,11 +1023,15 @@ function normalizeCssText(cssText: string, style: StyleConfig = DEFAULT_STYLE): .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, ""); } @@ -1038,11 +1087,13 @@ async function main(): Promise<void> { options.inputPath.replace(/\.md$/i, ".html") ); + const themeDefaults = THEME_STYLE_DEFAULTS[options.theme] ?? {}; const style: StyleConfig = { ...DEFAULT_STYLE, - primaryColor: options.primaryColor, - fontFamily: options.fontFamily, - fontSize: options.fontSize, + ...themeDefaults, + ...(options.primaryColor !== undefined ? { primaryColor: options.primaryColor } : {}), + ...(options.fontFamily !== undefined ? { fontFamily: options.fontFamily } : {}), + ...(options.fontSize !== undefined ? { fontSize: options.fontSize } : {}), }; const { baseCss, themeCss } = loadThemeCss(options.theme); diff --git a/skills/baoyu-markdown-to-html/scripts/md/themes/red.css b/skills/baoyu-markdown-to-html/scripts/md/themes/heritage.css similarity index 66% rename from skills/baoyu-markdown-to-html/scripts/md/themes/red.css rename to skills/baoyu-markdown-to-html/scripts/md/themes/heritage.css index 2e88e79..e5c88d0 100644 --- a/skills/baoyu-markdown-to-html/scripts/md/themes/red.css +++ b/skills/baoyu-markdown-to-html/scripts/md/themes/heritage.css @@ -1,23 +1,23 @@ /** - * MD 红色主题 - * 传统书法风格,红金配色,宋体排版 + * MD 传统主题 (heritage) + * 传统书法风格,宋体排版,默认红金配色 */ -/* ==================== 容器字体覆盖 ==================== */ +/* ==================== 容器样式覆盖 ==================== */ section, container { - font-family: "Source Han Serif SC", "Noto Serif CJK SC", "Source Han Serif CN", STSong, SimSun, serif; - font-size: 16px; + font-family: var(--md-font-family); + font-size: var(--md-font-size); line-height: 1.8; - background-color: rgba(255, 251, 240, 1); - border: 4px solid rgba(169, 50, 38, 1); + background-color: var(--md-container-bg); + border: 4px solid var(--md-primary-color); border-radius: 12px; padding: 6px 12px; } #output { - font-family: "Source Han Serif SC", "Noto Serif CJK SC", "Source Han Serif CN", STSong, SimSun, serif; - font-size: 16px; + font-family: var(--md-font-family); + font-size: var(--md-font-size); line-height: 1.8; } @@ -25,9 +25,9 @@ container { h1 { display: table; padding: 0 1em; - border-bottom: 2px solid #A93226; + border-bottom: 2px solid var(--md-primary-color); margin: 30px auto 20px; - color: #A93226; + color: var(--md-primary-color); font-size: 24px; font-weight: bold; text-align: center; @@ -40,7 +40,7 @@ h2 { padding: 6px 20px; margin: 30px auto 20px; color: #FFFFFF; - background-color: #A93226; + background-color: var(--md-primary-color); font-size: 18px; font-weight: bold; text-align: center; @@ -52,9 +52,9 @@ h2 { /* ==================== 三级标题 ==================== */ h3 { padding-left: 8px; - border-left: 3px solid #A93226; + border-left: 3px solid var(--md-primary-color); margin: 20px 8px 10px 0; - color: #A93226; + color: var(--md-primary-color); font-size: 17px; font-weight: normal; line-height: 1.2; @@ -63,7 +63,7 @@ h3 { /* ==================== 四级标题 ==================== */ h4 { margin: 10px 8px; - color: #D4AC0D; + color: var(--md-accent-color); font-size: 16px; font-weight: normal; } @@ -88,7 +88,7 @@ h6 { p { margin: 16px 0; letter-spacing: 0.5px; - color: #2C2C2C; + color: hsl(var(--foreground)); line-height: 1.8; } @@ -96,15 +96,15 @@ p { blockquote { font-style: normal; padding: 15px 12px; - border-left: 2px solid rgba(169, 50, 38, 0.8); + border-left: 2px solid color-mix(in srgb, var(--md-primary-color) 80%, transparent); border-radius: 4px; - color: #5D4037; - background-color: rgba(253, 237, 236, 1); + color: hsl(var(--foreground)); + background-color: var(--blockquote-background); margin: 12px 0; } blockquote > p { - color: #5D4037; + color: hsl(var(--foreground)); font-size: 14px; margin: 0; } @@ -113,14 +113,14 @@ blockquote > p { pre.code__pre, .hljs.code__pre { font-size: 13px; - border: 1px solid #D4AC0D; + border: 1px solid var(--md-accent-color); box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05); } /* ==================== 图片 ==================== */ img { border-radius: 4px; - border: 1px solid #D4AC0D; + border: 1px solid var(--md-accent-color); margin: 20px auto; padding: 5px; } @@ -141,7 +141,7 @@ ul { li { margin: 0.2em 0; - color: #2C2C2C; + color: hsl(var(--foreground)); font-size: 16px; } @@ -149,35 +149,35 @@ li { hr { border-style: solid; border-width: 2px 0 0; - border-color: #D4AC0D; + border-color: var(--md-accent-color); margin: 40px 0; } /* ==================== 强调 ==================== */ strong { - color: #A93226; + color: var(--md-primary-color); font-weight: bold; } /* ==================== 标记高亮 ==================== */ .markup-highlight { - background-color: #FADBD8; + background-color: color-mix(in srgb, var(--md-primary-color) 15%, white); padding: 5px; - color: #A93226; + color: var(--md-primary-color); } .markup-underline { text-decoration: underline; - text-decoration-color: #D4AC0D; + text-decoration-color: var(--md-accent-color); } /* ==================== 链接 ==================== */ a { - color: #A93226; + color: var(--md-primary-color); text-decoration: none; } /* ==================== 表格 ==================== */ th { - background: rgba(169, 50, 38, 0.1); + background: color-mix(in srgb, var(--md-primary-color) 10%, transparent); } diff --git a/skills/baoyu-markdown-to-html/scripts/md/themes/orange.css b/skills/baoyu-markdown-to-html/scripts/md/themes/warm.css similarity index 71% rename from skills/baoyu-markdown-to-html/scripts/md/themes/orange.css rename to skills/baoyu-markdown-to-html/scripts/md/themes/warm.css index 6fb764c..89ba61b 100644 --- a/skills/baoyu-markdown-to-html/scripts/md/themes/orange.css +++ b/skills/baoyu-markdown-to-html/scripts/md/themes/warm.css @@ -1,23 +1,23 @@ /** - * MD 橙色主题 - * 暖色调现代风,橙色主色,宽松行距 + * MD 温暖主题 (warm) + * 暖色调现代风,默认橙色主色,宽松行距 */ /* ==================== 容器样式覆盖 ==================== */ section, container { - font-family: PingFang SC, system-ui, -apple-system, BlinkMacSystemFont, Helvetica Neue, Hiragino Sans GB, Microsoft YaHei UI, Microsoft YaHei, Arial, sans-serif; - font-size: 15px; + font-family: var(--md-font-family); + font-size: var(--md-font-size); line-height: 2; - background-color: rgba(250, 249, 245, 1); + background-color: var(--md-container-bg); border: 1px solid rgba(255, 255, 255, 0.01); border-radius: 25px; padding: 12px 12px; } #output { - font-family: PingFang SC, system-ui, -apple-system, BlinkMacSystemFont, Helvetica Neue, Hiragino Sans GB, Microsoft YaHei UI, Microsoft YaHei, Arial, sans-serif; - font-size: 15px; + font-family: var(--md-font-family); + font-size: var(--md-font-size); line-height: 2; } @@ -26,8 +26,8 @@ h1 { display: table; padding: 0.3em 1em; margin: 20px auto; - color: #3B3B38; - background: #D97757; + color: hsl(var(--foreground)); + background: var(--md-primary-color); border-radius: 15px; font-size: 28px; font-weight: bold; @@ -41,16 +41,16 @@ h2 { padding-bottom: 0; margin: 0 auto 20px; width: 100%; - color: #D97757; + color: var(--md-primary-color); font-size: 20px; font-weight: bold; - border-bottom: 2px solid #E4B1A0; + border-bottom: 2px solid var(--md-accent-color); } /* ==================== 三级标题 ==================== */ h3 { margin: 0 8px 10px; - color: #3B3B38; + color: hsl(var(--foreground)); font-size: 18px; font-weight: bold; } @@ -58,7 +58,7 @@ h3 { /* ==================== 四级标题 ==================== */ h4 { margin: 0 8px 10px; - color: #D97757; + color: var(--md-primary-color); font-size: 16px; font-weight: bold; } @@ -68,7 +68,7 @@ h5 { display: inline-block; margin: 0 8px 10px; padding: 4px 10px; - color: #3B3B38; + color: hsl(var(--foreground)); background: rgba(255, 255, 255, 0.7); border: 1px solid rgb(189, 224, 254); border-radius: 20px; @@ -79,7 +79,7 @@ h5 { /* ==================== 六级标题 ==================== */ h6 { margin: 0 8px 10px; - color: #D97757; + color: var(--md-primary-color); font-size: 16px; font-weight: bold; } @@ -87,7 +87,7 @@ h6 { /* ==================== 段落 ==================== */ p { margin: 20px 0; - color: #3B3B38; + color: hsl(var(--foreground)); line-height: 2; letter-spacing: 0px; font-size: 15px; @@ -97,15 +97,15 @@ p { blockquote { font-style: normal; padding: 15px 12px; - border-left: 7px solid rgba(228, 177, 160, 1); + border-left: 7px solid var(--md-accent-color); border-radius: 10px; - color: #3B3B38; - background-color: rgba(255, 255, 255, 0.6); + color: hsl(var(--foreground)); + background-color: var(--blockquote-background); margin: 12px 0; } blockquote > p { - color: #3B3B38; + color: hsl(var(--foreground)); font-size: 14px; margin: 0; } @@ -139,7 +139,7 @@ ul { li { margin: 0.2em 0; - color: #3B3B38; + color: hsl(var(--foreground)); font-size: 15px; } @@ -147,35 +147,35 @@ li { hr { border-style: solid; border-width: 1px 0 0; - border-color: #D97757; + border-color: var(--md-primary-color); margin: 0; } /* ==================== 强调 ==================== */ strong { - color: #3B3B38; + color: hsl(var(--foreground)); font-weight: bold; } /* ==================== 标记高亮 ==================== */ .markup-highlight { - background-color: #3B3B3B; + background-color: hsl(var(--foreground)); padding: 10px; - color: #FAF9F5; + color: var(--md-container-bg); } .markup-underline { text-decoration: underline; - text-decoration-color: #E4B1A0; + text-decoration-color: var(--md-accent-color); } /* ==================== 链接 ==================== */ a { - color: #D97757; + color: var(--md-primary-color); text-decoration: none; } /* ==================== 表格 ==================== */ th { - background: rgba(217, 119, 87, 0.1); + background: color-mix(in srgb, var(--md-primary-color) 10%, transparent); }