()
| 26 | |
| 27 | |
| 28 | def build() -> None: |
| 29 | md_text = SRC.read_text(encoding="utf-8") |
| 30 | |
| 31 | # 去掉正文里手写的「## 目录」块(侧栏已提供同等导航,避免重复) |
| 32 | md_text = re.sub(r"\n## 目录\n.*?\n---\n", "\n\n---\n", md_text, count=1, flags=re.S) |
| 33 | |
| 34 | # H1 作为页面标题 |
| 35 | m = re.search(r"^#\s+(.+?)\s*$", md_text, flags=re.M) |
| 36 | page_title = m.group(1).strip() if m else "新手教程" |
| 37 | |
| 38 | mdp = markdown.Markdown( |
| 39 | extensions=["extra", "toc", "sane_lists"], |
| 40 | extension_configs={"toc": {"toc_depth": "2-3", "slugify": slugify_cjk, "permalink": "#"}}, |
| 41 | ) |
| 42 | body_html = mdp.convert(md_text) |
| 43 | toc_html = mdp.toc |
| 44 | |
| 45 | # img + 紧随的斜体说明 → <figure><figcaption> |
| 46 | body_html = re.sub( |
| 47 | r"<p>\s*(<img[^>]*>)\s*(?:<br\s*/?>)?\s*<em>(.*?)</em>\s*</p>", |
| 48 | r'<figure>\1<figcaption>\2</figcaption></figure>', |
| 49 | body_html, |
| 50 | flags=re.S, |
| 51 | ) |
| 52 | body_html = re.sub(r"<p>\s*(<img[^>]*>)\s*</p>", r"<figure>\1</figure>", body_html) |
| 53 | |
| 54 | html = ( |
| 55 | TEMPLATE.replace("__TITLE__", page_title) |
| 56 | .replace("__TOC__", toc_html) |
| 57 | .replace("__BODY__", body_html) |
| 58 | ) |
| 59 | OUT.write_text(html, encoding="utf-8") |
| 60 | print(f"✅ 写入 {OUT.relative_to(ROOT)}({OUT.stat().st_size // 1024} KB)") |
| 61 | |
| 62 | |
| 63 | TEMPLATE = r"""<!DOCTYPE html> |
no outgoing calls
no test coverage detected