diff --git a/toolkit/cli.py b/toolkit/cli.py
index 892ae29..225d540 100644
--- a/toolkit/cli.py
+++ b/toolkit/cli.py
@@ -142,6 +142,164 @@ def cmd_themes(args):
print(f" {name:24s} {theme.description}")
+def cmd_gallery(args):
+ """Render all themes side by side in a browser gallery."""
+ from concurrent.futures import ThreadPoolExecutor
+
+ # Use provided markdown or a built-in sample
+ if args.input:
+ md_text = Path(args.input).read_text(encoding="utf-8")
+ else:
+ md_text = _gallery_sample_markdown()
+
+ names = list_themes()
+ results = {}
+
+ def render_theme(name):
+ theme = load_theme(name)
+ converter = WeChatConverter(theme=theme)
+ result = converter.convert(md_text)
+ return name, theme.description, result.html
+
+ # Parallel rendering
+ with ThreadPoolExecutor(max_workers=8) as pool:
+ for name, desc, html in pool.map(lambda n: render_theme(n), names):
+ results[name] = (desc, html)
+
+ # Build gallery HTML
+ gallery_html = _build_gallery_html(results, names)
+ output = args.output or "/tmp/wewrite-gallery.html"
+ Path(output).write_text(gallery_html, encoding="utf-8")
+ print(f"Gallery: {output} ({len(names)} themes)")
+
+ if not args.no_open:
+ webbrowser.open(f"file://{Path(output).absolute()}")
+
+
+def _gallery_sample_markdown():
+ return """# 示例文章标题
+
+## 第一部分
+
+这是一段正常的文章内容,用来展示不同主题的排版效果。WeWrite 支持多种排版主题,每种都有独特的视觉风格。
+
+说实话,选主题这件事——看截图永远不如看实际渲染效果。
+
+## 关键数据
+
+| 指标 | 数值 | 变化 |
+|------|------|------|
+| 阅读量 | 12,580 | +23% |
+| 分享率 | 4.7% | +0.8% |
+| 完读率 | 68% | -2% |
+
+## 代码示例
+
+```python
+def hello():
+ print("Hello, WeWrite!")
+```
+
+> 好的排版不是让读者注意到设计,而是让读者忘记设计,只记住内容。
+
+## 列表展示
+
+- 第一个要点:简洁是设计的灵魂
+- 第二个要点:一致性比创意更重要
+- 第三个要点:移动端体验优先
+
+**加粗文本**和*斜体文本*的样式也需要关注。
+
+最后这段用来展示文章结尾的留白和间距效果。一篇好文章的结尾,应该像一首好歌的最后一个音符——恰到好处地收束。
+"""
+
+
+def _join_newline(items):
+ """Join items with comma + newline (workaround for f-string limitation)."""
+ return ",\n".join(items)
+
+
+def _build_gallery_html(results, names):
+ cards = []
+ for name in names:
+ desc, html = results[name]
+ # Escape for embedding in JS
+ escaped_html = html.replace('\\', '\\\\').replace('`', '\\`').replace('$', '\\$')
+ cards.append(f"""
+
+
{name}
+
{desc}
+
+
+
""")
+
+ # Store HTML data for copy
+ data_entries = []
+ for name in names:
+ desc, html = results[name]
+ safe = html.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
+ data_entries.append(f" '{name}': '{safe}'")
+
+ return f"""
+
+
+
+
+WeWrite 主题画廊
+
+
+
+
+
+{''.join(cards)}
+
+已复制到剪贴板
+
+
+"""
+
+
def main():
parser = argparse.ArgumentParser(
prog="wewrite",
@@ -169,6 +327,12 @@ def main():
# themes
sub.add_parser("themes", help="List available themes")
+ # gallery
+ p_gallery = sub.add_parser("gallery", help="Open theme gallery in browser")
+ p_gallery.add_argument("input", nargs="?", default=None, help="Markdown file (optional, uses sample if omitted)")
+ p_gallery.add_argument("-o", "--output", help="Output HTML file path")
+ p_gallery.add_argument("--no-open", action="store_true", help="Don't open browser")
+
args = parser.parse_args()
try:
@@ -178,6 +342,8 @@ def main():
cmd_publish(args)
elif args.command == "themes":
cmd_themes(args)
+ elif args.command == "gallery":
+ cmd_gallery(args)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
diff --git a/toolkit/converter.py b/toolkit/converter.py
index 1b1a5ac..a3b07b2 100644
--- a/toolkit/converter.py
+++ b/toolkit/converter.py
@@ -49,6 +49,12 @@ class WeChatConverter:
title = self._extract_title(markdown_text)
markdown_text = self._strip_h1(markdown_text)
+ # Pre-process container blocks (:::dialogue, :::timeline, etc.)
+ markdown_text = self._preprocess_containers(markdown_text)
+
+ # CJK fix: auto-space between CJK and Latin characters
+ markdown_text = self._fix_cjk_spacing(markdown_text)
+
# Parse Markdown → HTML
html = self._markdown_to_html(markdown_text)
@@ -58,12 +64,24 @@ class WeChatConverter:
# Process images (ensure responsive styling)
html, images = self._process_images(html)
+ # CJK fix: move punctuation outside bold tags
+ html = self._fix_cjk_bold_punctuation(html)
+
+ # CJK fix: convert ul/ol to section-based lists (WeChat renders native lists unreliably)
+ html = self._convert_lists_to_sections(html)
+
+ # Convert external links to footnotes (WeChat blocks external links)
+ html = self._convert_links_to_footnotes(html)
+
# Apply inline CSS from theme
html = self._apply_inline_styles(html)
# Apply WeChat compatibility fixes
html = self._apply_wechat_fixes(html)
+ # Inject dark mode attributes
+ html = self._inject_darkmode(html)
+
# Generate digest from plain text
digest = self._generate_digest(html)
@@ -201,6 +219,294 @@ class WeChatConverter:
return str(soup)
+ # -- CJK compatibility fixes --
+
+ def _fix_cjk_spacing(self, text: str) -> str:
+ """Auto-insert thin space between CJK and Latin/digit characters.
+
+ WeChat renders CJK-Latin without spacing, making mixed text hard to read.
+ This inserts a thin space (U+200A) at CJK↔Latin boundaries.
+ Runs on raw Markdown before parsing, skipping code blocks and links.
+ """
+ # CJK unicode ranges
+ cjk = r'[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\uff00-\uffef]'
+ latin = r'[A-Za-z0-9]'
+
+ lines = text.split('\n')
+ result = []
+ in_code_block = False
+
+ for line in lines:
+ if line.strip().startswith('```'):
+ in_code_block = not in_code_block
+ result.append(line)
+ continue
+ if in_code_block:
+ result.append(line)
+ continue
+
+ # CJK followed by Latin
+ line = re.sub(f'({cjk})({latin})', r'\1 \2', line)
+ # Latin followed by CJK
+ line = re.sub(f'({latin})({cjk})', r'\1 \2', line)
+ result.append(line)
+
+ return '\n'.join(result)
+
+ def _fix_cjk_bold_punctuation(self, html: str) -> str:
+ """Move Chinese punctuation outside bold/strong tags.
+
+ WeChat renders bold CJK punctuation with ugly spacing.
+ Move trailing punctuation (,。!?;:、) outside .
+ """
+ # Match: 内容+中文标点 → 内容标点
+ pattern = r'()(.*?)([,。!?;:、]+)()'
+ return re.sub(pattern, r'\1\2\4\3', html)
+
+ def _convert_lists_to_sections(self, html: str) -> str:
+ """Convert / to styled elements.
+
+ WeChat's native list rendering is unreliable (inconsistent bullet
+ style, broken indentation on some devices). Using section+span
+ for bullets/numbers gives full control over appearance.
+ """
+ soup = BeautifulSoup(html, "html.parser")
+ text_color = self._theme.colors.get("text", "#333333")
+ primary = self._theme.colors.get("primary", "#2563eb")
+
+ for ul in soup.find_all("ul"):
+ section = soup.new_tag("section")
+ for li in ul.find_all("li", recursive=False):
+ item = soup.new_tag("section", style=f"display: flex; align-items: flex-start; margin-bottom: 8px; color: {text_color}")
+ bullet = soup.new_tag("span", style=f"color: {primary}; margin-right: 8px; flex-shrink: 0; font-size: 18px; line-height: 1.6")
+ bullet.string = "•"
+ content = soup.new_tag("span", style="flex: 1")
+ for child in list(li.children):
+ content.append(child.extract() if hasattr(child, 'extract') else child)
+ item.append(bullet)
+ item.append(content)
+ section.append(item)
+ ul.replace_with(section)
+
+ for idx, ol in enumerate(soup.find_all("ol")):
+ section = soup.new_tag("section")
+ for num, li in enumerate(ol.find_all("li", recursive=False), 1):
+ item = soup.new_tag("section", style=f"display: flex; align-items: flex-start; margin-bottom: 8px; color: {text_color}")
+ number = soup.new_tag("span", style=f"color: {primary}; margin-right: 8px; flex-shrink: 0; font-weight: 700; line-height: 1.8")
+ number.string = f"{num}."
+ content = soup.new_tag("span", style="flex: 1")
+ for child in list(li.children):
+ content.append(child.extract() if hasattr(child, 'extract') else child)
+ item.append(number)
+ item.append(content)
+ section.append(item)
+ ol.replace_with(section)
+
+ return str(soup)
+
+ # -- External link → footnote conversion --
+
+ def _convert_links_to_footnotes(self, html: str) -> str:
+ """Convert external links to superscript footnote numbers.
+
+ WeChat blocks external links — readers see dead text. This converts
+ each external link to a superscript number with the URL collected
+ into a reference list appended at the end.
+ """
+ soup = BeautifulSoup(html, "html.parser")
+ footnotes = []
+ counter = 0
+ primary = self._theme.colors.get("primary", "#2563eb")
+
+ for a in soup.find_all("a"):
+ href = a.get("href", "")
+ if not href or href.startswith("#"):
+ continue # skip anchors
+
+ counter += 1
+ text = a.get_text()
+ footnotes.append((counter, text, href))
+
+ # Replace with text + superscript number
+ sup = soup.new_tag("sup")
+ sup_link = soup.new_tag("span", style=f"color: {primary}; font-size: 12px")
+ sup_link.string = f"[{counter}]"
+ sup.append(sup_link)
+ a.replace_with(text, sup)
+
+ if footnotes:
+ # Append reference section
+ hr = soup.new_tag("hr", style="border: none; border-top: 1px solid #e5e5e5; margin: 32px 0 16px")
+ soup.append(hr)
+ ref_title = soup.new_tag("p", style="font-size: 13px; color: #999999; margin-bottom: 8px; font-weight: 700")
+ ref_title.string = "参考链接"
+ soup.append(ref_title)
+ for num, text, href in footnotes:
+ ref = soup.new_tag("p", style="font-size: 12px; color: #999999; margin: 2px 0; word-break: break-all")
+ ref.string = f"[{num}] {text}: {href}"
+ soup.append(ref)
+
+ return str(soup)
+
+ # -- Dark mode --
+
+ def _inject_darkmode(self, html: str) -> str:
+ """Inject data-darkmode-* attributes for WeChat dark mode.
+
+ WeChat auto-inverts colors in dark mode, which often breaks
+ designed color schemes. Explicit darkmode attributes tell WeChat
+ exactly what colors to use instead of guessing.
+ """
+ darkmode = self._theme.colors.get("darkmode", {})
+ if not darkmode:
+ return html
+
+ soup = BeautifulSoup(html, "html.parser")
+ dm_text = darkmode.get("text", "#c8c8c8")
+ dm_bg = darkmode.get("background", "#1e1e1e")
+ dm_primary = darkmode.get("primary", "#6aadff")
+
+ # Body-level elements (p, li, section, span)
+ for tag_name in ("p", "span", "section"):
+ for elem in soup.find_all(tag_name):
+ style = elem.get("style", "")
+ # Only set if element has a color
+ if "color" in style:
+ elem["data-darkmode-color"] = dm_text
+ elem["data-darkmode-bgcolor"] = "transparent"
+
+ # Headings
+ dm_heading = darkmode.get("text", "#e0e0e0")
+ for tag_name in ("h1", "h2", "h3", "h4"):
+ for elem in soup.find_all(tag_name):
+ elem["data-darkmode-color"] = dm_heading
+ elem["data-darkmode-bgcolor"] = "transparent"
+
+ # Code blocks
+ dm_code_bg = darkmode.get("code_bg", "#2d2d2d")
+ dm_code_color = darkmode.get("code_color", "#d4d4d4")
+ for pre in soup.find_all("pre"):
+ pre["data-darkmode-bgcolor"] = dm_code_bg
+ pre["data-darkmode-color"] = dm_code_color
+ for code in soup.find_all("code"):
+ code["data-darkmode-color"] = dm_code_color
+
+ # Blockquotes
+ dm_quote_bg = darkmode.get("quote_bg", "#2a2a2a")
+ for bq in soup.find_all("blockquote"):
+ bq["data-darkmode-bgcolor"] = dm_quote_bg
+ bq["data-darkmode-color"] = dm_text
+
+ # Strong/em with primary color
+ for strong in soup.find_all("strong"):
+ strong["data-darkmode-color"] = dm_primary
+
+ return str(soup)
+
+ # -- Container block syntax --
+
+ def _preprocess_containers(self, text: str) -> str:
+ """Pre-process :::container blocks into styled HTML before Markdown parsing.
+
+ Supports:
+ :::dialogue — chat bubble layout
+ :::timeline — vertical timeline with dots
+ :::callout — Obsidian-style callout (tip/warning/info/danger)
+ :::quote — styled pull quote
+ """
+ text = self._process_dialogue(text)
+ text = self._process_timeline(text)
+ text = self._process_callout(text)
+ text = self._process_quote_block(text)
+ return text
+
+ def _process_dialogue(self, text: str) -> str:
+ """Convert :::dialogue blocks to chat bubble HTML."""
+ primary = self._theme.colors.get("primary", "#2563eb")
+
+ def replace_dialogue(match):
+ content = match.group(1).strip()
+ bubbles = []
+ for line in content.split('\n'):
+ line = line.strip()
+ if not line:
+ continue
+ if line.startswith('> '):
+ # Right-aligned (reply) bubble
+ msg = line[2:].strip()
+ bubbles.append(f'')
+ else:
+ # Left-aligned bubble
+ bubbles.append(f'')
+ return '\n'.join(bubbles)
+
+ return re.sub(r':::dialogue\n(.*?)\n:::', replace_dialogue, text, flags=re.DOTALL)
+
+ def _process_timeline(self, text: str) -> str:
+ """Convert :::timeline blocks to vertical timeline HTML."""
+ primary = self._theme.colors.get("primary", "#2563eb")
+
+ def replace_timeline(match):
+ content = match.group(1).strip()
+ items = []
+ for line in content.split('\n'):
+ line = line.strip()
+ if not line:
+ continue
+ # Format: "**title** description" or just "description"
+ items.append(
+ f''
+ )
+ return '\n'.join(items)
+
+ return re.sub(r':::timeline\n(.*?)\n:::', replace_timeline, text, flags=re.DOTALL)
+
+ def _process_callout(self, text: str) -> str:
+ """Convert :::callout blocks to styled callout boxes.
+
+ Syntax: :::callout tip/warning/info/danger
+ """
+ colors_map = {
+ "tip": ("#059669", "#ecfdf5", "💡"),
+ "warning": ("#d97706", "#fffbeb", "⚠️"),
+ "info": ("#2563eb", "#eff6ff", "ℹ️"),
+ "danger": ("#dc2626", "#fef2f2", "🚨"),
+ }
+
+ def replace_callout(match):
+ ctype = match.group(1).strip().lower()
+ content = match.group(2).strip()
+ color, bg, icon = colors_map.get(ctype, colors_map["info"])
+ return (f'')
+
+ return re.sub(r':::callout\s+(\w+)\n(.*?)\n:::', replace_callout, text, flags=re.DOTALL)
+
+ def _process_quote_block(self, text: str) -> str:
+ """Convert :::quote blocks to styled pull quotes."""
+ primary = self._theme.colors.get("primary", "#2563eb")
+
+ def replace_quote(match):
+ content = match.group(1).strip()
+ return (f'')
+
+ return re.sub(r':::quote\n(.*?)\n:::', replace_quote, text, flags=re.DOTALL)
+
+ # -- Digest generation --
+
def _generate_digest(self, html: str, max_bytes: int = 120) -> str:
"""Generate a digest that fits within WeChat's byte limit (120 bytes UTF-8)."""
soup = BeautifulSoup(html, "html.parser")
diff --git a/toolkit/themes/bauhaus.yaml b/toolkit/themes/bauhaus.yaml
new file mode 100644
index 0000000..2093034
--- /dev/null
+++ b/toolkit/themes/bauhaus.yaml
@@ -0,0 +1,207 @@
+name: "bauhaus"
+description: "包豪斯设计风格:纯白底黑色为主,红蓝黄色块点缀,几何感强烈"
+colors:
+ primary: "#e63226"
+ secondary: "#004592"
+ text: "#1a1a1a"
+ text_light: "#555555"
+ background: "#ffffff"
+ code_bg: "#f0f0f0"
+ code_color: "#004592"
+ quote_border: "#e63226"
+ quote_bg: "#fff5f5"
+ border_radius: "0px"
+darkmode:
+ background: "#111111"
+ text: "#e8e8e8"
+ text_light: "#a0a0a0"
+ primary: "#f04438"
+ code_bg: "#222222"
+ code_color: "#5b9bd5"
+ quote_bg: "#1e1212"
+ quote_border: "#f04438"
+base_css: |
+ body {
+ font-family: "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1a1a1a;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 30px;
+ font-weight: 900;
+ color: #1a1a1a;
+ margin: 36px 0 18px 0;
+ padding: 12px 16px;
+ background: #e63226;
+ color: #ffffff;
+ line-height: 1.3;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 800;
+ color: #004592;
+ margin: 32px 0 14px 0;
+ padding: 8px 0;
+ border-bottom: 4px solid #1a1a1a;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 700;
+ color: #1a1a1a;
+ margin: 24px 0 12px 0;
+ padding-left: 12px;
+ border-left: 6px solid #f5b700;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 700;
+ color: #1a1a1a;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1a1a1a;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 800;
+ color: #e63226;
+ }
+
+ em {
+ font-style: italic;
+ color: #555555;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f0f0f0;
+ color: #004592;
+ padding: 2px 6px;
+ border-radius: 0px;
+ border: 1px solid #ddd;
+ }
+
+ pre {
+ background: #1a1a1a;
+ color: #f0f0f0;
+ padding: 16px;
+ border-radius: 0px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border-left: 6px solid #e63226;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #f0f0f0;
+ padding: 0;
+ border-radius: 0;
+ border: none;
+ }
+
+ blockquote {
+ border-left: 6px solid #e63226;
+ background: #fff5f5;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0;
+ color: #1a1a1a;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #1a1a1a;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1a1a1a;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #004592;
+ }
+
+ th {
+ background: #004592;
+ color: #ffffff;
+ font-weight: 700;
+ padding: 10px 14px;
+ text-align: left;
+ border: 2px solid #1a1a1a;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 2px solid #1a1a1a;
+ color: #1a1a1a;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 0px;
+ border: 2px solid #1a1a1a;
+ }
+
+ a {
+ color: #004592;
+ text-decoration: none;
+ font-weight: 700;
+ border-bottom: 2px solid #f5b700;
+ }
+
+ hr {
+ border: none;
+ height: 4px;
+ background: #1a1a1a;
+ margin: 28px 0;
+ }
diff --git a/toolkit/themes/bold-green.yaml b/toolkit/themes/bold-green.yaml
new file mode 100644
index 0000000..e31004f
--- /dev/null
+++ b/toolkit/themes/bold-green.yaml
@@ -0,0 +1,198 @@
+name: "bold-green"
+description: "大胆森林绿风格:白底绿色主色,清新自然,适合环保健康和可持续发展内容"
+colors:
+ primary: "#16a34a"
+ secondary: "#22c55e"
+ text: "#1a2e1a"
+ text_light: "#4a6a4a"
+ background: "#ffffff"
+ code_bg: "#f0fdf4"
+ code_color: "#15803d"
+ quote_border: "#16a34a"
+ quote_bg: "#f0fdf4"
+ border_radius: "8px"
+darkmode:
+ background: "#0f1a0f"
+ text: "#d8e8d8"
+ text_light: "#8aaa8a"
+ primary: "#4ade80"
+ code_bg: "#162816"
+ code_color: "#6ee7a0"
+ quote_bg: "#142014"
+ quote_border: "#4ade80"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a2e1a;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 700;
+ color: #ffffff;
+ margin: 32px 0 16px 0;
+ padding: 12px 16px;
+ background: #16a34a;
+ border-radius: 8px;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #16a34a;
+ margin: 28px 0 14px 0;
+ padding: 8px 0 8px 12px;
+ border-left: 4px solid #16a34a;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #15803d;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1a2e1a;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a2e1a;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #16a34a;
+ }
+
+ em {
+ font-style: italic;
+ color: #4a6a4a;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f0fdf4;
+ color: #15803d;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #f0fdf4;
+ color: #1a2e1a;
+ padding: 16px;
+ border-radius: 8px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #bbf7d0;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #1a2e1a;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #16a34a;
+ background: #f0fdf4;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 8px 8px 0;
+ color: #1a2e1a;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #1a2e1a;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a2e1a;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #16a34a;
+ }
+
+ th {
+ background: #16a34a;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #16a34a;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #d1fae5;
+ color: #1a2e1a;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 8px;
+ }
+
+ a {
+ color: #16a34a;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 2px solid #d1fae5;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/bold-navy.yaml b/toolkit/themes/bold-navy.yaml
new file mode 100644
index 0000000..d364437
--- /dev/null
+++ b/toolkit/themes/bold-navy.yaml
@@ -0,0 +1,197 @@
+name: "bold-navy"
+description: "大胆藏青风格:白底藏青主色,稳重专业,适合金融商务和行业分析内容"
+colors:
+ primary: "#1e3a5f"
+ secondary: "#2c5282"
+ text: "#1a1a2e"
+ text_light: "#4a5568"
+ background: "#ffffff"
+ code_bg: "#f0f4f8"
+ code_color: "#1e3a5f"
+ quote_border: "#1e3a5f"
+ quote_bg: "#f0f4f8"
+ border_radius: "6px"
+darkmode:
+ background: "#0a0f1a"
+ text: "#d8dce8"
+ text_light: "#8890a0"
+ primary: "#5b8cc8"
+ code_bg: "#141a28"
+ code_color: "#7ca8e0"
+ quote_bg: "#101828"
+ quote_border: "#5b8cc8"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a2e;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 700;
+ color: #1e3a5f;
+ margin: 32px 0 16px 0;
+ padding-bottom: 12px;
+ border-bottom: 3px solid #1e3a5f;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #1e3a5f;
+ margin: 28px 0 14px 0;
+ padding: 8px 0 8px 12px;
+ border-left: 4px solid #1e3a5f;
+ border-bottom: 1px solid #e2e8f0;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #2c5282;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1a1a2e;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a2e;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #1e3a5f;
+ }
+
+ em {
+ font-style: italic;
+ color: #4a5568;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f0f4f8;
+ color: #1e3a5f;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #1e3a5f;
+ color: #e2e8f0;
+ padding: 16px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #e2e8f0;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #1e3a5f;
+ background: #f0f4f8;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 6px 6px 0;
+ color: #2c5282;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #2c5282;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a2e;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #1e3a5f;
+ }
+
+ th {
+ background: #1e3a5f;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #1e3a5f;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #e2e8f0;
+ color: #1a1a2e;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 6px;
+ }
+
+ a {
+ color: #2c5282;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 2px solid #e2e8f0;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/bytedance.yaml b/toolkit/themes/bytedance.yaml
new file mode 100644
index 0000000..48a9c9b
--- /dev/null
+++ b/toolkit/themes/bytedance.yaml
@@ -0,0 +1,199 @@
+name: "bytedance"
+description: "字节跳动风:白底品牌蓝,现代无衬线,大间距,适合科技产品内容"
+colors:
+ primary: "#1966FF"
+ secondary: "#4e8fff"
+ text: "#1f2329"
+ text_light: "#646a73"
+ background: "#ffffff"
+ code_bg: "#f5f6f7"
+ code_color: "#1966FF"
+ quote_border: "#1966FF"
+ quote_bg: "#f0f5ff"
+ border_radius: "8px"
+darkmode:
+ background: "#1a1a1a"
+ text: "#e8e8e8"
+ text_light: "#a0a0a0"
+ primary: "#4e8fff"
+ code_bg: "#2a2a2a"
+ code_color: "#6ea8fe"
+ quote_bg: "#1e2a3a"
+ quote_border: "#4e8fff"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 2;
+ color: #1f2329;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 24px;
+ word-wrap: break-word;
+ letter-spacing: 0.02em;
+ }
+
+ h1 {
+ font-size: 28px;
+ font-weight: 800;
+ color: #1f2329;
+ margin: 40px 0 20px 0;
+ padding-bottom: 14px;
+ border-bottom: 3px solid #1966FF;
+ line-height: 1.4;
+ letter-spacing: -0.01em;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #1f2329;
+ margin: 36px 0 16px 0;
+ padding: 10px 0 10px 14px;
+ border-left: 4px solid #1966FF;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #1966FF;
+ margin: 28px 0 14px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1f2329;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 2;
+ color: #1f2329;
+ margin: 16px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #1966FF;
+ }
+
+ em {
+ font-style: italic;
+ color: #646a73;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f5f6f7;
+ color: #1966FF;
+ padding: 2px 8px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #f5f6f7;
+ color: #1f2329;
+ padding: 20px;
+ border-radius: 8px;
+ overflow-x: auto;
+ margin: 20px 0;
+ line-height: 1.6;
+ border: 1px solid #e5e6e8;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #1f2329;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #1966FF;
+ background: #f0f5ff;
+ margin: 20px 0;
+ padding: 16px 20px;
+ border-radius: 0 8px 8px 0;
+ color: #1f2329;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #1f2329;
+ }
+
+ ul {
+ padding-left: 28px;
+ margin: 16px 0;
+ }
+
+ ol {
+ padding-left: 28px;
+ margin: 16px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 2;
+ color: #1f2329;
+ margin: 8px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 20px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #1966FF;
+ }
+
+ th {
+ background: #1966FF;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 12px 16px;
+ text-align: left;
+ border: 1px solid #1966FF;
+ }
+
+ td {
+ padding: 12px 16px;
+ border: 1px solid #e5e6e8;
+ color: #1f2329;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 28px auto;
+ border-radius: 8px;
+ }
+
+ a {
+ color: #1966FF;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #e5e6e8;
+ margin: 32px 0;
+ }
diff --git a/toolkit/themes/elegant-rose.yaml b/toolkit/themes/elegant-rose.yaml
new file mode 100644
index 0000000..8f592f6
--- /dev/null
+++ b/toolkit/themes/elegant-rose.yaml
@@ -0,0 +1,198 @@
+name: "elegant-rose"
+description: "优雅玫瑰风格:浅粉底玫瑰色点缀,温柔精致,适合女性生活和时尚内容"
+colors:
+ primary: "#be185d"
+ secondary: "#db2777"
+ text: "#3d1f2e"
+ text_light: "#7a5068"
+ background: "#fdf2f8"
+ code_bg: "#fce7f3"
+ code_color: "#be185d"
+ quote_border: "#be185d"
+ quote_bg: "#fce7f3"
+ border_radius: "12px"
+darkmode:
+ background: "#1a0f14"
+ text: "#e8d0dc"
+ text_light: "#a07888"
+ primary: "#f472b6"
+ code_bg: "#2a1520"
+ code_color: "#f9a8d4"
+ quote_bg: "#221018"
+ quote_border: "#f472b6"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.85;
+ color: #3d1f2e;
+ background: #fdf2f8;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 700;
+ color: #be185d;
+ margin: 32px 0 16px 0;
+ text-align: center;
+ padding-bottom: 12px;
+ border-bottom: 2px solid #f9a8d4;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #be185d;
+ margin: 28px 0 14px 0;
+ padding: 8px 0 8px 12px;
+ border-left: 4px solid #be185d;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #db2777;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #3d1f2e;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.85;
+ color: #3d1f2e;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #be185d;
+ }
+
+ em {
+ font-style: italic;
+ color: #7a5068;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #fce7f3;
+ color: #be185d;
+ padding: 2px 6px;
+ border-radius: 6px;
+ }
+
+ pre {
+ background: #fce7f3;
+ color: #3d1f2e;
+ padding: 16px;
+ border-radius: 12px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #fbcfe8;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #3d1f2e;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #be185d;
+ background: #fce7f3;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 12px 12px 0;
+ color: #7a5068;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #7a5068;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.85;
+ color: #3d1f2e;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #be185d;
+ }
+
+ th {
+ background: #be185d;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #be185d;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #fbcfe8;
+ color: #3d1f2e;
+ }
+
+ tr {
+ background: #fdf2f8;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 12px;
+ }
+
+ a {
+ color: #be185d;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #fbcfe8;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/focus-red.yaml b/toolkit/themes/focus-red.yaml
new file mode 100644
index 0000000..fec6753
--- /dev/null
+++ b/toolkit/themes/focus-red.yaml
@@ -0,0 +1,197 @@
+name: "focus-red"
+description: "聚焦红风格:白底中国红标题和引用边框,醒目有力,适合新闻评论和观点输出"
+colors:
+ primary: "#dc2626"
+ secondary: "#ef4444"
+ text: "#1a1a1a"
+ text_light: "#555555"
+ background: "#ffffff"
+ code_bg: "#fef2f2"
+ code_color: "#b91c1c"
+ quote_border: "#dc2626"
+ quote_bg: "#fef2f2"
+ border_radius: "6px"
+darkmode:
+ background: "#1a0f0f"
+ text: "#e8d8d8"
+ text_light: "#a08888"
+ primary: "#f87171"
+ code_bg: "#2a1515"
+ code_color: "#fca5a5"
+ quote_bg: "#221010"
+ quote_border: "#f87171"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a1a;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 800;
+ color: #dc2626;
+ margin: 32px 0 16px 0;
+ padding-bottom: 12px;
+ border-bottom: 3px solid #dc2626;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #dc2626;
+ margin: 28px 0 14px 0;
+ padding: 8px 0 8px 12px;
+ border-left: 4px solid #dc2626;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #1a1a1a;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1a1a1a;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a1a;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #dc2626;
+ }
+
+ em {
+ font-style: italic;
+ color: #555555;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #fef2f2;
+ color: #b91c1c;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #fef2f2;
+ color: #1a1a1a;
+ padding: 16px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #fecaca;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #1a1a1a;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #dc2626;
+ background: #fef2f2;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 6px 6px 0;
+ color: #333333;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #333333;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #1a1a1a;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #dc2626;
+ }
+
+ th {
+ background: #dc2626;
+ color: #ffffff;
+ font-weight: 700;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #dc2626;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #e5e7eb;
+ color: #1a1a1a;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 6px;
+ }
+
+ a {
+ color: #dc2626;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 2px solid #fecaca;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/github.yaml b/toolkit/themes/github.yaml
new file mode 100644
index 0000000..47b9e69
--- /dev/null
+++ b/toolkit/themes/github.yaml
@@ -0,0 +1,198 @@
+name: "github"
+description: "GitHub风格:白底蓝色链接,等宽代码块,简洁清晰,适合技术文档和开发者内容"
+colors:
+ primary: "#0969da"
+ secondary: "#0550ae"
+ text: "#1f2328"
+ text_light: "#656d76"
+ background: "#ffffff"
+ code_bg: "#f6f8fa"
+ code_color: "#0550ae"
+ quote_border: "#d0d7de"
+ quote_bg: "#f6f8fa"
+ border_radius: "6px"
+darkmode:
+ background: "#0d1117"
+ text: "#e6edf3"
+ text_light: "#8b949e"
+ primary: "#58a6ff"
+ code_bg: "#161b22"
+ code_color: "#79c0ff"
+ quote_bg: "#161b22"
+ quote_border: "#30363d"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1f2328;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 600;
+ color: #1f2328;
+ margin: 32px 0 16px 0;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #d1d9e0;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 600;
+ color: #1f2328;
+ margin: 28px 0 14px 0;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #d1d9e0;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #1f2328;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1f2328;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1f2328;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 600;
+ color: #1f2328;
+ }
+
+ em {
+ font-style: italic;
+ color: #1f2328;
+ }
+
+ code {
+ font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
+ font-size: 13.6px;
+ background: rgba(175,184,193,0.2);
+ color: #1f2328;
+ padding: 3px 6px;
+ border-radius: 6px;
+ }
+
+ pre {
+ background: #f6f8fa;
+ color: #1f2328;
+ padding: 16px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.5;
+ border: 1px solid #d1d9e0;
+ }
+
+ pre code {
+ font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
+ font-size: 13.6px;
+ background: none;
+ color: #1f2328;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #d0d7de;
+ background: transparent;
+ margin: 16px 0;
+ padding: 4px 16px;
+ border-radius: 0;
+ color: #656d76;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #656d76;
+ }
+
+ ul {
+ padding-left: 28px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 28px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.75;
+ color: #1f2328;
+ margin: 4px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #f6f8fa;
+ }
+
+ th {
+ background: #f6f8fa;
+ color: #1f2328;
+ font-weight: 600;
+ padding: 8px 14px;
+ text-align: left;
+ border: 1px solid #d1d9e0;
+ }
+
+ td {
+ padding: 8px 14px;
+ border: 1px solid #d1d9e0;
+ color: #1f2328;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 6px;
+ }
+
+ a {
+ color: #0969da;
+ text-decoration: none;
+ font-weight: 400;
+ }
+
+ hr {
+ border: none;
+ height: 2px;
+ background: #d1d9e0;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/ink.yaml b/toolkit/themes/ink.yaml
new file mode 100644
index 0000000..4c97cd6
--- /dev/null
+++ b/toolkit/themes/ink.yaml
@@ -0,0 +1,204 @@
+name: "ink"
+description: "水墨中国风:宣纸底墨色文字,中文衬线字体,留白疏朗,适合文化和人文内容"
+colors:
+ primary: "#4a4a4a"
+ secondary: "#6b6b6b"
+ text: "#1a1a1a"
+ text_light: "#666666"
+ background: "#f8f5f0"
+ code_bg: "#f0ebe3"
+ code_color: "#555555"
+ quote_border: "#999999"
+ quote_bg: "#f4f0e8"
+ border_radius: "2px"
+darkmode:
+ background: "#1a1816"
+ text: "#d8d2c8"
+ text_light: "#9a9488"
+ primary: "#b0a898"
+ code_bg: "#252220"
+ code_color: "#c0b8a8"
+ quote_bg: "#222018"
+ quote_border: "#706858"
+base_css: |
+ body {
+ font-family: "Songti SC", "SimSun", "Noto Serif SC", Georgia, serif;
+ font-size: 16px;
+ line-height: 2;
+ color: #1a1a1a;
+ background: #f8f5f0;
+ max-width: 680px;
+ margin: 0 auto;
+ padding: 28px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 28px;
+ font-weight: 700;
+ color: #1a1a1a;
+ margin: 48px 0 24px 0;
+ text-align: center;
+ line-height: 1.4;
+ letter-spacing: 0.1em;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #1a1a1a;
+ margin: 40px 0 16px 0;
+ text-align: center;
+ padding-bottom: 12px;
+ line-height: 1.4;
+ letter-spacing: 0.05em;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333333;
+ margin: 32px 0 14px 0;
+ line-height: 1.4;
+ letter-spacing: 0.03em;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333333;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 2;
+ color: #1a1a1a;
+ margin: 16px 0;
+ text-indent: 2em;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #1a1a1a;
+ }
+
+ em {
+ font-style: italic;
+ color: #666666;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f0ebe3;
+ color: #555555;
+ padding: 2px 6px;
+ border-radius: 2px;
+ }
+
+ pre {
+ background: #f0ebe3;
+ color: #1a1a1a;
+ padding: 16px;
+ border-radius: 2px;
+ overflow-x: auto;
+ margin: 20px 0;
+ line-height: 1.6;
+ border: 1px solid #ddd5c8;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #1a1a1a;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 3px solid #999999;
+ background: #f4f0e8;
+ margin: 20px 0;
+ padding: 14px 18px;
+ border-radius: 0 2px 2px 0;
+ color: #555555;
+ font-style: italic;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #555555;
+ text-indent: 0;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 16px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 16px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 2;
+ color: #1a1a1a;
+ margin: 8px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 20px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #4a4a4a;
+ }
+
+ th {
+ background: #4a4a4a;
+ color: #f8f5f0;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #4a4a4a;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #ddd5c8;
+ color: #1a1a1a;
+ }
+
+ tr {
+ background: #f8f5f0;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 32px auto;
+ border-radius: 2px;
+ }
+
+ a {
+ color: #555555;
+ text-decoration: underline;
+ }
+
+ hr {
+ border: none;
+ text-align: center;
+ margin: 36px 0;
+ height: 20px;
+ background: transparent;
+ border-bottom: 1px solid #ccc5b8;
+ }
diff --git a/toolkit/themes/midnight.yaml b/toolkit/themes/midnight.yaml
new file mode 100644
index 0000000..9f260d5
--- /dev/null
+++ b/toolkit/themes/midnight.yaml
@@ -0,0 +1,197 @@
+name: "midnight"
+description: "午夜深色主题:深蓝黑底白色文字,蓝色高亮,适合技术和深夜阅读内容"
+colors:
+ primary: "#60a5fa"
+ secondary: "#93c5fd"
+ text: "#e2e8f0"
+ text_light: "#94a3b8"
+ background: "#0f172a"
+ code_bg: "#1e293b"
+ code_color: "#7dd3fc"
+ quote_border: "#60a5fa"
+ quote_bg: "#172040"
+ border_radius: "8px"
+darkmode:
+ background: "#0f172a"
+ text: "#e2e8f0"
+ text_light: "#94a3b8"
+ primary: "#60a5fa"
+ code_bg: "#1e293b"
+ code_color: "#7dd3fc"
+ quote_bg: "#172040"
+ quote_border: "#60a5fa"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #e2e8f0;
+ background: #0f172a;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 700;
+ color: #f1f5f9;
+ margin: 32px 0 16px 0;
+ padding-bottom: 12px;
+ border-bottom: 2px solid #60a5fa;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #60a5fa;
+ margin: 28px 0 14px 0;
+ padding: 8px 0 8px 12px;
+ border-left: 4px solid #60a5fa;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #93c5fd;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #cbd5e1;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #e2e8f0;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #60a5fa;
+ }
+
+ em {
+ font-style: italic;
+ color: #94a3b8;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #1e293b;
+ color: #7dd3fc;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #1e293b;
+ color: #e2e8f0;
+ padding: 16px;
+ border-radius: 8px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #334155;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #e2e8f0;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #60a5fa;
+ background: #172040;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 8px 8px 0;
+ color: #cbd5e1;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #cbd5e1;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #e2e8f0;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #1e3a5f;
+ }
+
+ th {
+ background: #1e3a5f;
+ color: #f1f5f9;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #334155;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #334155;
+ color: #e2e8f0;
+ }
+
+ tr {
+ background: #0f172a;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 8px;
+ }
+
+ a {
+ color: #60a5fa;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #334155;
+ margin: 24px 0;
+ }
diff --git a/toolkit/themes/minimal-gold.yaml b/toolkit/themes/minimal-gold.yaml
new file mode 100644
index 0000000..0e484be
--- /dev/null
+++ b/toolkit/themes/minimal-gold.yaml
@@ -0,0 +1,202 @@
+name: "minimal-gold"
+description: "极简金色风格:白底金色细线点缀,奢华但克制,适合高端品牌和精品内容"
+colors:
+ primary: "#b8860b"
+ secondary: "#d4a843"
+ text: "#2a2a2a"
+ text_light: "#6b6b6b"
+ background: "#ffffff"
+ code_bg: "#faf8f3"
+ code_color: "#8b6914"
+ quote_border: "#b8860b"
+ quote_bg: "#fdfbf5"
+ border_radius: "4px"
+darkmode:
+ background: "#141210"
+ text: "#e0dcd0"
+ text_light: "#9a9488"
+ primary: "#d4a843"
+ code_bg: "#1e1c18"
+ code_color: "#e0c060"
+ quote_bg: "#1a1810"
+ quote_border: "#d4a843"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #2a2a2a;
+ background: #ffffff;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ letter-spacing: 0.01em;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 600;
+ color: #2a2a2a;
+ margin: 36px 0 18px 0;
+ text-align: center;
+ padding-bottom: 14px;
+ border-bottom: 1px solid #b8860b;
+ line-height: 1.4;
+ letter-spacing: 0.05em;
+ }
+
+ h2 {
+ font-size: 21px;
+ font-weight: 600;
+ color: #2a2a2a;
+ margin: 30px 0 14px 0;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #d4c59a;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #b8860b;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #2a2a2a;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #2a2a2a;
+ margin: 12px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #b8860b;
+ }
+
+ em {
+ font-style: italic;
+ color: #6b6b6b;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #faf8f3;
+ color: #8b6914;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #faf8f3;
+ color: #2a2a2a;
+ padding: 16px;
+ border-radius: 4px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #e8e0c8;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #2a2a2a;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 2px solid #b8860b;
+ background: #fdfbf5;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 4px 4px 0;
+ color: #6b6b6b;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #6b6b6b;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 12px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.8;
+ color: #2a2a2a;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #2a2a2a;
+ }
+
+ th {
+ background: #2a2a2a;
+ color: #d4a843;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #2a2a2a;
+ letter-spacing: 0.03em;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #e8e0c8;
+ color: #2a2a2a;
+ }
+
+ tr {
+ background: #ffffff;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 4px;
+ }
+
+ a {
+ color: #b8860b;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #d4c59a;
+ margin: 28px auto;
+ width: 40%;
+ }
diff --git a/toolkit/themes/minimal.yaml b/toolkit/themes/minimal.yaml
index 92a95b8..8483b02 100644
--- a/toolkit/themes/minimal.yaml
+++ b/toolkit/themes/minimal.yaml
@@ -11,6 +11,15 @@ colors:
quote_border: "#cccccc"
quote_bg: "#f9f9f9"
border_radius: "4px"
+ darkmode:
+ background: "#1a1a1a"
+ text: "#c0c0c0"
+ text_light: "#888888"
+ primary: "#e0e0e0"
+ code_bg: "#252525"
+ code_color: "#c0c0c0"
+ quote_bg: "#222222"
+ quote_border: "#555555"
base_css: |
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
diff --git a/toolkit/themes/newspaper.yaml b/toolkit/themes/newspaper.yaml
new file mode 100644
index 0000000..353e176
--- /dev/null
+++ b/toolkit/themes/newspaper.yaml
@@ -0,0 +1,206 @@
+name: "newspaper"
+description: "经典报纸风格:米黄底深棕文字,衬线字体质感,适合深度报道和评论"
+colors:
+ primary: "#8b4513"
+ secondary: "#a0522d"
+ text: "#2c2416"
+ text_light: "#5c4a3a"
+ background: "#f5f0e8"
+ code_bg: "#ede7db"
+ code_color: "#8b4513"
+ quote_border: "#8b4513"
+ quote_bg: "#f0eade"
+ border_radius: "2px"
+darkmode:
+ background: "#1e1a14"
+ text: "#ddd5c8"
+ text_light: "#a09580"
+ primary: "#c8915a"
+ code_bg: "#2a2418"
+ code_color: "#d4a574"
+ quote_bg: "#28221a"
+ quote_border: "#c8915a"
+base_css: |
+ body {
+ font-family: Georgia, "Songti SC", "SimSun", "Noto Serif SC", serif;
+ font-size: 16px;
+ line-height: 1.9;
+ color: #2c2416;
+ background: #f5f0e8;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 28px;
+ font-weight: 700;
+ color: #2c2416;
+ margin: 36px 0 16px 0;
+ text-align: center;
+ padding-bottom: 12px;
+ border-bottom: 3px double #8b4513;
+ line-height: 1.3;
+ letter-spacing: 0.03em;
+ }
+
+ h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: #2c2416;
+ margin: 30px 0 14px 0;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #8b4513;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 700;
+ color: #5c4a3a;
+ margin: 24px 0 12px 0;
+ line-height: 1.4;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ font-size: 16px;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 700;
+ color: #5c4a3a;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.9;
+ color: #2c2416;
+ margin: 14px 0;
+ text-align: justify;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #2c2416;
+ }
+
+ em {
+ font-style: italic;
+ color: #5c4a3a;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #ede7db;
+ color: #8b4513;
+ padding: 2px 6px;
+ border-radius: 2px;
+ }
+
+ pre {
+ background: #ede7db;
+ color: #2c2416;
+ padding: 16px;
+ border-radius: 2px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #d4cbb8;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #2c2416;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 3px solid #8b4513;
+ background: #f0eade;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 2px 2px 0;
+ color: #5c4a3a;
+ font-style: italic;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #5c4a3a;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 14px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 14px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.9;
+ color: #2c2416;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #8b4513;
+ }
+
+ th {
+ background: #8b4513;
+ color: #f5f0e8;
+ font-weight: 700;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #8b4513;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #d4cbb8;
+ color: #2c2416;
+ }
+
+ tr {
+ background: #f5f0e8;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 2px;
+ border: 1px solid #d4cbb8;
+ }
+
+ a {
+ color: #8b4513;
+ text-decoration: underline;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #d4cbb8;
+ margin: 28px auto;
+ width: 60%;
+ }
diff --git a/toolkit/themes/professional-clean.yaml b/toolkit/themes/professional-clean.yaml
index a06c926..ba451e4 100644
--- a/toolkit/themes/professional-clean.yaml
+++ b/toolkit/themes/professional-clean.yaml
@@ -11,6 +11,15 @@ colors:
quote_border: "#2563eb"
quote_bg: "#eff6ff"
border_radius: "8px"
+ darkmode:
+ background: "#1e1e1e"
+ text: "#c8c8c8"
+ text_light: "#999999"
+ primary: "#6aadff"
+ code_bg: "#2d2d2d"
+ code_color: "#d4d4d4"
+ quote_bg: "#252525"
+ quote_border: "#4a90d9"
base_css: |
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
diff --git a/toolkit/themes/sspai.yaml b/toolkit/themes/sspai.yaml
new file mode 100644
index 0000000..c475fb1
--- /dev/null
+++ b/toolkit/themes/sspai.yaml
@@ -0,0 +1,198 @@
+name: "sspai"
+description: "少数派风格:暖白底红色点缀,清爽文艺,适合数码生活和效率工具内容"
+colors:
+ primary: "#c7372f"
+ secondary: "#d4524b"
+ text: "#333333"
+ text_light: "#888888"
+ background: "#fafaf7"
+ code_bg: "#f5f2ed"
+ code_color: "#c7372f"
+ quote_border: "#c7372f"
+ quote_bg: "#fdf5f4"
+ border_radius: "6px"
+darkmode:
+ background: "#1c1c1a"
+ text: "#e0ddd8"
+ text_light: "#9a9790"
+ primary: "#e05a52"
+ code_bg: "#2a2825"
+ code_color: "#e87c76"
+ quote_bg: "#2a2220"
+ quote_border: "#e05a52"
+base_css: |
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ font-size: 16px;
+ line-height: 1.85;
+ color: #333333;
+ background: #fafaf7;
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 20px;
+ word-wrap: break-word;
+ }
+
+ h1 {
+ font-size: 26px;
+ font-weight: 700;
+ color: #1a1a1a;
+ margin: 36px 0 18px 0;
+ text-align: center;
+ line-height: 1.4;
+ }
+
+ h2 {
+ font-size: 21px;
+ font-weight: 700;
+ color: #c7372f;
+ margin: 30px 0 14px 0;
+ padding-bottom: 8px;
+ border-bottom: 2px solid #c7372f;
+ line-height: 1.4;
+ }
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333333;
+ margin: 24px 0 12px 0;
+ padding-left: 10px;
+ border-left: 3px solid #c7372f;
+ line-height: 1.4;
+ }
+
+ h4 {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333333;
+ margin: 20px 0 10px 0;
+ line-height: 1.4;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.85;
+ color: #333333;
+ margin: 14px 0;
+ }
+
+ strong {
+ font-weight: 700;
+ color: #c7372f;
+ }
+
+ em {
+ font-style: italic;
+ color: #666666;
+ }
+
+ code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: #f5f2ed;
+ color: #c7372f;
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ pre {
+ background: #f5f2ed;
+ color: #333333;
+ padding: 16px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 16px 0;
+ line-height: 1.6;
+ border: 1px solid #e8e4dc;
+ }
+
+ pre code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 14px;
+ background: none;
+ color: #333333;
+ padding: 0;
+ border-radius: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid #c7372f;
+ background: #fdf5f4;
+ margin: 16px 0;
+ padding: 12px 16px;
+ border-radius: 0 6px 6px 0;
+ color: #555555;
+ }
+
+ blockquote p {
+ margin: 8px 0;
+ color: #555555;
+ }
+
+ ul {
+ padding-left: 24px;
+ margin: 14px 0;
+ }
+
+ ol {
+ padding-left: 24px;
+ margin: 14px 0;
+ }
+
+ li {
+ font-size: 16px;
+ line-height: 1.85;
+ color: #333333;
+ margin: 6px 0;
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 16px 0;
+ font-size: 15px;
+ }
+
+ thead {
+ background: #c7372f;
+ }
+
+ th {
+ background: #c7372f;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 10px 14px;
+ text-align: left;
+ border: 1px solid #c7372f;
+ }
+
+ td {
+ padding: 10px 14px;
+ border: 1px solid #e8e4dc;
+ color: #333333;
+ }
+
+ tr {
+ background: #fafaf7;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ display: block;
+ margin: 24px auto;
+ border-radius: 6px;
+ }
+
+ a {
+ color: #c7372f;
+ text-decoration: none;
+ font-weight: 500;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #e8e4dc;
+ margin: 28px 0;
+ }
diff --git a/toolkit/themes/tech-modern.yaml b/toolkit/themes/tech-modern.yaml
index 656cb3a..646c17c 100644
--- a/toolkit/themes/tech-modern.yaml
+++ b/toolkit/themes/tech-modern.yaml
@@ -11,6 +11,15 @@ colors:
quote_border: "#7c3aed"
quote_bg: "#f8f5ff"
border_radius: "8px"
+ darkmode:
+ background: "#1a1a2e"
+ text: "#c8c8c8"
+ text_light: "#999999"
+ primary: "#a78bfa"
+ code_bg: "#1e1e2e"
+ code_color: "#c8cad8"
+ quote_bg: "#232340"
+ quote_border: "#7c3aed"
base_css: |
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
diff --git a/toolkit/themes/warm-editorial.yaml b/toolkit/themes/warm-editorial.yaml
index 669cf67..418a135 100644
--- a/toolkit/themes/warm-editorial.yaml
+++ b/toolkit/themes/warm-editorial.yaml
@@ -11,6 +11,15 @@ colors:
quote_border: "#d97706"
quote_bg: "#fffbeb"
border_radius: "8px"
+ darkmode:
+ background: "#1e1e1e"
+ text: "#d4c8b8"
+ text_light: "#a09080"
+ primary: "#f0a830"
+ code_bg: "#2a2520"
+ code_color: "#d4b896"
+ quote_bg: "#2a2418"
+ quote_border: "#d97706"
base_css: |
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;