specpipe 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1319 -0
- package/bin/devkit.js +3 -0
- package/package.json +61 -0
- package/src/cli.js +76 -0
- package/src/commands/check.js +33 -0
- package/src/commands/diff.js +84 -0
- package/src/commands/init-adopt.js +54 -0
- package/src/commands/init-agents.js +118 -0
- package/src/commands/init-global.js +102 -0
- package/src/commands/init.js +311 -0
- package/src/commands/list.js +54 -0
- package/src/commands/remove.js +133 -0
- package/src/commands/upgrade.js +215 -0
- package/src/lib/agent-guards.js +100 -0
- package/src/lib/agent-install.js +161 -0
- package/src/lib/agents.js +280 -0
- package/src/lib/claude-global.js +183 -0
- package/src/lib/detector.js +93 -0
- package/src/lib/hasher.js +21 -0
- package/src/lib/installer.js +213 -0
- package/src/lib/logger.js +16 -0
- package/src/lib/manifest.js +102 -0
- package/src/lib/reconcile.js +56 -0
- package/templates/.claude/CLAUDE.md +79 -0
- package/templates/.claude/hooks/comment-guard.js +126 -0
- package/templates/.claude/hooks/file-guard.js +216 -0
- package/templates/.claude/hooks/glob-guard.js +104 -0
- package/templates/.claude/hooks/path-guard.sh +118 -0
- package/templates/.claude/hooks/self-review.sh +27 -0
- package/templates/.claude/hooks/sensitive-guard.sh +227 -0
- package/templates/.claude/settings.json +68 -0
- package/templates/docs/WORKFLOW.md +325 -0
- package/templates/docs/specs/.gitkeep +0 -0
- package/templates/hooks/specpipe-read-guard.sh +42 -0
- package/templates/hooks/specpipe-shell-guard.sh +65 -0
- package/templates/rules/specpipe-guards.md +40 -0
- package/templates/scripts/test-hooks.sh +66 -0
- package/templates/skills/sp-build/SKILL.md +776 -0
- package/templates/skills/sp-challenge/SKILL.md +255 -0
- package/templates/skills/sp-commit/SKILL.md +174 -0
- package/templates/skills/sp-explore/SKILL.md +730 -0
- package/templates/skills/sp-fix/SKILL.md +266 -0
- package/templates/skills/sp-humanize/SKILL.md +212 -0
- package/templates/skills/sp-investigate/SKILL.md +648 -0
- package/templates/skills/sp-md-render/SKILL.md +200 -0
- package/templates/skills/sp-md-render/components.md +415 -0
- package/templates/skills/sp-md-render/template.html +283 -0
- package/templates/skills/sp-plan/SKILL.md +947 -0
- package/templates/skills/sp-review/SKILL.md +268 -0
- package/templates/skills/sp-scaffold/SKILL.md +237 -0
- package/templates/skills/sp-scaffold/references/ARCHITECTURE.md.tmpl +228 -0
- package/templates/skills/sp-scaffold/references/DESIGN.md.tmpl +113 -0
- package/templates/skills/sp-scaffold/references/adr/NNNN-template.md +92 -0
- package/templates/skills/sp-scaffold/references/stack-profiles/react.md +36 -0
- package/templates/skills/sp-spec-render/SKILL.md +254 -0
- package/templates/skills/sp-spec-render/components.md +418 -0
- package/templates/skills/sp-spec-render/examples/user-auth.html +749 -0
- package/templates/skills/sp-spec-render/examples/user-auth.md +114 -0
- package/templates/skills/sp-spec-render/template.html +222 -0
- package/templates/skills/sp-voices/SKILL.md +1184 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: |
|
|
3
|
+
Render any markdown file into a self-contained, scannable HTML view:
|
|
4
|
+
sidebar TOC with scroll-spy, anchored headings, code copy buttons,
|
|
5
|
+
Mermaid diagrams, callouts (note/warn/danger/tip), step cards,
|
|
6
|
+
comparison cards, collapsible long sections, light/dark theme, TOC search.
|
|
7
|
+
|
|
8
|
+
Use when asked to "render markdown", "md sang html", "xem md đẹp",
|
|
9
|
+
"preview this doc", "make this readable", "md2html", or for any
|
|
10
|
+
long-form markdown that is not a /sp-plan spec (investigation reports,
|
|
11
|
+
explore docs, design notes, retros, READMEs, RFCs, meeting notes).
|
|
12
|
+
|
|
13
|
+
Proactively suggest when the user is reading a long .md in chat
|
|
14
|
+
("hard to scan", "lots to read", "tl;dr this") or after a skill that
|
|
15
|
+
writes a long markdown artefact finishes (e.g. /sp-investigate,
|
|
16
|
+
/sp-explore, /retro).
|
|
17
|
+
|
|
18
|
+
For /sp-plan spec files (structured stories + acceptance scenarios),
|
|
19
|
+
use [[sp-spec-render]] instead — it understands S-NNN / AS-NNN /
|
|
20
|
+
C-NNN / P-badges. This skill is the generic counterpart for arbitrary
|
|
21
|
+
markdown without a fixed schema.
|
|
22
|
+
|
|
23
|
+
Idempotent: re-rendering overwrites the previous .html. Safe anytime.
|
|
24
|
+
allowed-tools: Read, Write, Bash, Glob, Grep
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Render an arbitrary markdown file into a self-contained `<file>.html` next to it.
|
|
28
|
+
|
|
29
|
+
The source `.md` is the truth. The HTML is a **view layer**: regenerable, never hand-edited. `template.html` and `components.md` are read-only inputs.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Inputs
|
|
34
|
+
|
|
35
|
+
`$ARGUMENTS` may be:
|
|
36
|
+
|
|
37
|
+
- **Path to a .md file** (`docs/investigate/payment-bug-2026-05-16.md`) — render to `<file>.html` next to it.
|
|
38
|
+
- **`--out <path>`** — custom output destination.
|
|
39
|
+
- **Path to a directory** — list `*.md` files inside and prompt the user to pick.
|
|
40
|
+
- **Empty** — prompt the user for a file path.
|
|
41
|
+
|
|
42
|
+
Output is written to `<file>.html` (or `--out`) and overwrites any existing file.
|
|
43
|
+
|
|
44
|
+
**Refuse politely** if the file looks like a /sp-plan spec (has `### S-\d{3}:` headings) — tell the user to run `/sp-spec-render` instead. Quick check: `grep -q '^### S-[0-9]\{3\}:' <file>`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Skill files (read once before generating)
|
|
49
|
+
|
|
50
|
+
Resolved relative to this `SKILL.md`:
|
|
51
|
+
|
|
52
|
+
- `template.html` — HTML skeleton with embedded CSS, JS, Mermaid CDN, SVG sprite. Contains `{{PLACEHOLDER}}` strings and `<!-- TOC_ENTRIES -->`, `<!-- CONTENT_START -->`, `<!-- CONTENT_END -->` slots. **Read once, never modified.**
|
|
53
|
+
- `components.md` — Catalog of HTML snippets to copy verbatim. **Read once.**
|
|
54
|
+
- `examples/` — Reference input/output pairs (if any). If empty, proceed without — the catalog is enough.
|
|
55
|
+
|
|
56
|
+
**Read all available inputs before producing any output.** Do not invent CSS classes, do not generate component markup from scratch, do not add new `<style>` or `<script>` tags.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Workflow
|
|
61
|
+
|
|
62
|
+
### Step 1 — Resolve and classify input
|
|
63
|
+
|
|
64
|
+
1. Parse `$ARGUMENTS` to find the source `.md`.
|
|
65
|
+
2. Reject if it looks like a /sp-plan spec (see above).
|
|
66
|
+
3. Read the source fully. Read `template.html` and `components.md`.
|
|
67
|
+
4. **Detect language** of the source prose. Default `vi` if Vietnamese dominates, `en` for English, otherwise the source's language. UI labels translate to match — see placeholder table in Step 3.
|
|
68
|
+
|
|
69
|
+
### Step 2 — Analyze content (analyzer pattern)
|
|
70
|
+
|
|
71
|
+
Walk the markdown and decide, for each chunk, the best component (see `components.md`). This is the core difference from `sp-spec-render`: there is no fixed schema. Use judgment.
|
|
72
|
+
|
|
73
|
+
Heuristics:
|
|
74
|
+
|
|
75
|
+
| Source pattern | Component |
|
|
76
|
+
|---|---|
|
|
77
|
+
| First `# Title` | Page title (template `<h1>`) |
|
|
78
|
+
| First paragraph after H1, ≤ 200 chars | Subtitle (`{{SUBTITLE}}`) |
|
|
79
|
+
| `## Section` | `<h2 id="...">` section anchor |
|
|
80
|
+
| `### Subsection` | `<h3 id="...">` |
|
|
81
|
+
| Prose paragraphs | `<p>` |
|
|
82
|
+
| Numbered actions ("Step 1: …", `1. Do X` chains ≥ 3 with imperative verbs) | Step cards (§4) |
|
|
83
|
+
| Fenced ```mermaid block | Mermaid diagram (§7) |
|
|
84
|
+
| Other fenced ```lang code | Code block with copy button (§6) |
|
|
85
|
+
| `> [!NOTE]` / `> [!TIP]` / `> [!WARNING]` / `> [!DANGER]` / `> [!IMPORTANT]` (GFM admonitions) | Callout (§5) |
|
|
86
|
+
| Blockquote starting with "Don't" / "Never" / "Cảnh báo" / "Lưu ý" | Mapped DANGER / WARN / NOTE callout |
|
|
87
|
+
| GFM table | `<table class="md-table">` (§8) |
|
|
88
|
+
| Pros/cons or "X vs Y" pair | Comparison cards (§9) |
|
|
89
|
+
| Inline `<details>` | Pass through |
|
|
90
|
+
| H3 section > 80 lines, or "Appendix" / "Full log" / "Phụ lục" | Wrap in `<details class="collapsible">` (§10) |
|
|
91
|
+
| Plain `ul` / `ol` not matching step heuristic | `<ul>` / `<ol>` (§11) |
|
|
92
|
+
| Inline `` `code` `` | `<code>` verbatim |
|
|
93
|
+
| Source has `## TL;DR` / `## Tóm tắt` | TL;DR card (§3) at top |
|
|
94
|
+
|
|
95
|
+
**TL;DR is optional here** (unlike spec-render). Only render if the source has it.
|
|
96
|
+
|
|
97
|
+
**Counts:** count H2 sections, code blocks, Mermaid diagrams → topbar meta.
|
|
98
|
+
|
|
99
|
+
### Step 3 — Build output buffer
|
|
100
|
+
|
|
101
|
+
Copy `template.html` into an in-memory string. Replace placeholders:
|
|
102
|
+
|
|
103
|
+
| Placeholder | Value |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `{{LANG}}` | ISO 639-1 from detection |
|
|
106
|
+
| `{{TITLE}}` | First H1 text, or filename slug if absent |
|
|
107
|
+
| `{{SUBTITLE}}` | First paragraph after H1 (≤ 200 chars); empty if none |
|
|
108
|
+
| `{{DOC_TYPE}}` | `DOC` / `INVESTIGATION` / `EXPLORE` / `RFC` / `NOTES` / `RETRO` (infer from filename prefix; fallback `DOC`) |
|
|
109
|
+
| `{{DOC_TYPE_CLASS}}` | lowercase of above |
|
|
110
|
+
| `{{LAST_UPDATED}}` | ISO date from frontmatter (`date:` / `**Last updated**:`) else `$(date +%Y-%m-%d)` |
|
|
111
|
+
| `{{UPDATED_LABEL}}` | "updated" / "cập nhật" / matched language |
|
|
112
|
+
| `{{META_EXTRA}}` | `<span class="sep">·</span><span>N sections</span>` + optional diagrams / code blocks; skip zero counts |
|
|
113
|
+
| `{{TOC_LABEL}}` | "Contents" / "Mục lục" / matched |
|
|
114
|
+
| `{{SEARCH_PLACEHOLDER}}` | "Search…" / "Tìm trong trang…" / matched |
|
|
115
|
+
| `{{SKIP_LABEL}}` | "Skip to content" / "Bỏ qua menu" / matched |
|
|
116
|
+
| `{{THEME_TIP}}` | "Toggle theme" / "Đổi theme" / matched |
|
|
117
|
+
| `{{COPY_LABEL}}` | "Copy" / "Sao chép" / matched |
|
|
118
|
+
| `{{COPIED_LABEL}}` | "Copied" / "Đã chép" / matched |
|
|
119
|
+
|
|
120
|
+
### Step 4 — Render TOC
|
|
121
|
+
|
|
122
|
+
Replace `<!-- TOC_ENTRIES -->`. One entry per H2; H3 nested with `.toc a.h3` indent. Flat list ordered by appearance:
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<a href="#section-id" data-target="section-id">Section title</a>
|
|
126
|
+
<a href="#sub-id" data-target="sub-id" class="h3">Subsection</a>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 5 — Render body
|
|
130
|
+
|
|
131
|
+
Replace the slot between `<!-- CONTENT_START -->` and `<!-- CONTENT_END -->` with body markup in source order. Use only components in `components.md`.
|
|
132
|
+
|
|
133
|
+
**Identifier preservation:** function names, file paths, routes, env vars, CLI flags stay verbatim in `<code>`.
|
|
134
|
+
|
|
135
|
+
**Mermaid:** ```mermaid block → `<div class="mermaid">…</div>`. CDN script in template renders it.
|
|
136
|
+
|
|
137
|
+
### Step 6 — Write file
|
|
138
|
+
|
|
139
|
+
Write the buffer to `<file>.html` (or `--out`). **One Write call.**
|
|
140
|
+
|
|
141
|
+
### Step 7 — Verify
|
|
142
|
+
|
|
143
|
+
Re-read the written file and check:
|
|
144
|
+
|
|
145
|
+
- [ ] No leftover `{{PLACEHOLDER}}` strings.
|
|
146
|
+
- [ ] No leftover slot comments.
|
|
147
|
+
- [ ] Every TOC `href="#x"` resolves to an element with `id="x"` (sample 5).
|
|
148
|
+
- [ ] Count of `<h2 id` matches H2 count from source.
|
|
149
|
+
- [ ] Each ```mermaid block produced one `<div class="mermaid">`.
|
|
150
|
+
|
|
151
|
+
Fix with targeted Edits if needed — don't rewrite the file.
|
|
152
|
+
|
|
153
|
+
Report:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
✓ Rendered <filename> → <path>
|
|
157
|
+
<N sections> · <N diagrams> · <N code blocks> · lang: <xx>
|
|
158
|
+
Open: open <path>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Rules
|
|
164
|
+
|
|
165
|
+
1. **Source is truth.** Never hand-edit HTML.
|
|
166
|
+
2. **One Write call.** Build buffer in memory, write once.
|
|
167
|
+
3. **No new CSS or components.** Use only template classes and `components.md` snippets.
|
|
168
|
+
4. **Never paraphrase technical content.** Identifiers, code, paths verbatim in `<code>`.
|
|
169
|
+
5. **Don't invent TL;DR.** Only render if source has it.
|
|
170
|
+
6. **No emojis in chrome.** Use SVG icons from template sprite. Source emojis pass through inside prose only.
|
|
171
|
+
7. **Long sections collapse.** > 80 lines under one H3 → wrap in `<details>`.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Edge cases
|
|
176
|
+
|
|
177
|
+
- **Empty file / no headings** → render the prose as a single block, no TOC entries.
|
|
178
|
+
- **Heading ID collision** → suffix `-2`, `-3`; mirror in TOC.
|
|
179
|
+
- **Mermaid syntax invalid** → still emit `<div class="mermaid">`; the CDN shows its own inline error.
|
|
180
|
+
- **Frontmatter** → strip from body; read `date:` / `**Last updated**:` only.
|
|
181
|
+
- **Raw HTML in source** → pass through except `<script>` and `<style>` (strip for safety).
|
|
182
|
+
- **Source is a /sp-plan spec** → STOP, tell user to run `/sp-spec-render`.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Anti-patterns
|
|
187
|
+
|
|
188
|
+
- ❌ Edit loop to assemble HTML — build buffer, Write once.
|
|
189
|
+
- ❌ New `<style>` blocks or inline CSS attributes.
|
|
190
|
+
- ❌ Inventing components not in `components.md`.
|
|
191
|
+
- ❌ Translating identifiers, routes, function names, CLI flags.
|
|
192
|
+
- ❌ Adding emojis to UI chrome.
|
|
193
|
+
- ❌ Rendering a spec file — defer to [[sp-spec-render]].
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Relationship with other skills
|
|
198
|
+
|
|
199
|
+
- [[sp-spec-render]] — sibling for /sp-plan specs (story cards, AS dl/dt, P-badges). This skill is the generic fallback.
|
|
200
|
+
- `/sp-investigate`, `/sp-explore`, `/retro` produce long markdown artefacts; suggest this skill at the end so the user can render an HTML view.
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
# Components catalog for sp-md-render
|
|
2
|
+
|
|
3
|
+
Copy these snippets verbatim into the body slot. Do not invent new CSS classes. Do not add `<style>` or `<script>` tags — the template already has them.
|
|
4
|
+
|
|
5
|
+
All `id` attributes must be kebab-case slugs derived from the heading text, deduplicated by appending `-2`, `-3` on collision.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## §1. Section headings
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<h2 id="kebab-slug">Section title</h2>
|
|
13
|
+
<h3 id="kebab-slug-sub">Subsection</h3>
|
|
14
|
+
<h4>Eyebrow / non-anchored label</h4>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
H1 is reserved for the page title (template). Don't emit additional H1s.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## §2. TOC entries (sidebar)
|
|
22
|
+
|
|
23
|
+
Placed inside `<nav class="toc">`. One link per H2; H3 nested via `.h3` class.
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<a href="#section-id" data-target="section-id">Section title</a>
|
|
27
|
+
<a href="#section-id-sub" data-target="section-id-sub" class="h3">Subsection</a>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`data-target` MUST match the element `id` exactly — the scroll-spy uses it.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## §3. TL;DR card
|
|
35
|
+
|
|
36
|
+
Render only if the source has a `## TL;DR` / `## Tóm tắt` / `## Summary` section. Place before the first H2.
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<aside class="tldr">
|
|
40
|
+
<div class="tldr-label">TL;DR</div>
|
|
41
|
+
<ul>
|
|
42
|
+
<li>Bullet one.</li>
|
|
43
|
+
<li>Bullet two.</li>
|
|
44
|
+
</ul>
|
|
45
|
+
</aside>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Max ~10 bullets. Keep each ≤ 1 line. If source is prose, render as `<p>` inside the card instead of `<ul>`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## §4. Step cards
|
|
53
|
+
|
|
54
|
+
Use when source has 3+ sequential imperative items (numbered list with verbs, "Step N:", "Bước N:").
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<ol class="steps">
|
|
58
|
+
<li class="step">
|
|
59
|
+
<div class="step-title">Open the dashboard</div>
|
|
60
|
+
<div class="step-body">Navigate to <code>/admin/dashboard</code> and sign in.</div>
|
|
61
|
+
</li>
|
|
62
|
+
<li class="step">
|
|
63
|
+
<div class="step-title">Run the migration</div>
|
|
64
|
+
<div class="step-body">
|
|
65
|
+
<p>Execute <code>bin/migrate up</code>. Wait for the green check.</p>
|
|
66
|
+
</div>
|
|
67
|
+
</li>
|
|
68
|
+
</ol>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The numbered badge is generated via CSS counter. Don't hardcode "1.", "2." in the title.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## §5. Callouts
|
|
76
|
+
|
|
77
|
+
Map GFM admonitions to the matching variant. Source emojis in callout body pass through; do NOT add emojis to the title.
|
|
78
|
+
|
|
79
|
+
### NOTE — neutral aside
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<div class="callout note">
|
|
83
|
+
<svg class="ico" aria-hidden="true"><use href="#i-note"/></svg>
|
|
84
|
+
<div>
|
|
85
|
+
<div class="callout-title">Note</div>
|
|
86
|
+
<p>Body text. Identifiers like <code>SHA256</code> stay verbatim.</p>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### TIP — recommendation
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<div class="callout tip">
|
|
95
|
+
<svg class="ico" aria-hidden="true"><use href="#i-tip"/></svg>
|
|
96
|
+
<div>
|
|
97
|
+
<div class="callout-title">Tip</div>
|
|
98
|
+
<p>Body text.</p>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### WARN — caution
|
|
104
|
+
|
|
105
|
+
```html
|
|
106
|
+
<div class="callout warn">
|
|
107
|
+
<svg class="ico" aria-hidden="true"><use href="#i-warn"/></svg>
|
|
108
|
+
<div>
|
|
109
|
+
<div class="callout-title">Warning</div>
|
|
110
|
+
<p>Body text.</p>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### DANGER — destructive / irreversible
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<div class="callout danger">
|
|
119
|
+
<svg class="ico" aria-hidden="true"><use href="#i-danger"/></svg>
|
|
120
|
+
<div>
|
|
121
|
+
<div class="callout-title">Danger</div>
|
|
122
|
+
<p>Body text.</p>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Title translation:** match `{{LANG}}` — vi: Ghi chú / Mẹo / Cảnh báo / Nguy hiểm. en: Note / Tip / Warning / Danger.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## §6. Code blocks
|
|
132
|
+
|
|
133
|
+
The copy button is auto-injected by template JS. Optional language label appears top-left.
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<pre class="code"><span class="lang">bash</span><code>cd /tmp
|
|
137
|
+
./build.sh --release</code></pre>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
No language? Omit the `<span class="lang">`:
|
|
141
|
+
|
|
142
|
+
```html
|
|
143
|
+
<pre class="code"><code>raw text without language hint</code></pre>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**HTML-escape** `<`, `>`, `&` inside the `<code>` body. Do not syntax-highlight (no extra spans).
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## §7. Mermaid diagram
|
|
151
|
+
|
|
152
|
+
For fenced ```mermaid blocks. The CDN script in the template renders them on load.
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<div class="mermaid">
|
|
156
|
+
graph TD
|
|
157
|
+
A[Start] --> B{Decision}
|
|
158
|
+
B -->|yes| C[Do thing]
|
|
159
|
+
B -->|no| D[Skip]
|
|
160
|
+
</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Preserve source Mermaid syntax verbatim — do NOT HTML-escape inside `.mermaid`.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## §8. Tables
|
|
168
|
+
|
|
169
|
+
GFM table → HTML table. Wraps with horizontal scroll on narrow screens via CSS.
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<table class="md-table">
|
|
173
|
+
<thead>
|
|
174
|
+
<tr><th>Column A</th><th>Column B</th></tr>
|
|
175
|
+
</thead>
|
|
176
|
+
<tbody>
|
|
177
|
+
<tr><td>value 1</td><td><code>identifier</code></td></tr>
|
|
178
|
+
<tr><td>value 2</td><td>value 3</td></tr>
|
|
179
|
+
</tbody>
|
|
180
|
+
</table>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## §9. Comparison cards
|
|
186
|
+
|
|
187
|
+
For "X vs Y", pros/cons, or two-column trade-off discussions.
|
|
188
|
+
|
|
189
|
+
### Generic two-column
|
|
190
|
+
|
|
191
|
+
```html
|
|
192
|
+
<div class="compare">
|
|
193
|
+
<div>
|
|
194
|
+
<h4>Option A</h4>
|
|
195
|
+
<p>Body for A.</p>
|
|
196
|
+
</div>
|
|
197
|
+
<div>
|
|
198
|
+
<h4>Option B</h4>
|
|
199
|
+
<p>Body for B.</p>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Pros / cons (left=good, right=bad)
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<div class="compare pro">
|
|
208
|
+
<div>
|
|
209
|
+
<h4>Pros</h4>
|
|
210
|
+
<ul><li>Fast</li><li>Cheap</li></ul>
|
|
211
|
+
</div>
|
|
212
|
+
<div>
|
|
213
|
+
<h4>Cons</h4>
|
|
214
|
+
<ul><li>Risky migration</li></ul>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The `.pro` variant adds green/red left borders.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## §10. Collapsible section
|
|
224
|
+
|
|
225
|
+
Use for appendices, full logs, long detail sections (> 80 lines under one H3), or anything labeled "Details" / "Phụ lục" / "Full log".
|
|
226
|
+
|
|
227
|
+
```html
|
|
228
|
+
<details class="collapsible">
|
|
229
|
+
<summary>Show full stack trace</summary>
|
|
230
|
+
<div>
|
|
231
|
+
<pre class="code"><code>... long output ...</code></pre>
|
|
232
|
+
</div>
|
|
233
|
+
</details>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Defaults closed. Open by default only if the source explicitly opens it.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## §11. Plain lists
|
|
241
|
+
|
|
242
|
+
Use when content does not match the step-card heuristic — short scannable items, mixed prose, non-sequential.
|
|
243
|
+
|
|
244
|
+
```html
|
|
245
|
+
<ul>
|
|
246
|
+
<li>First item with <code>some-code</code>.</li>
|
|
247
|
+
<li>Second item.
|
|
248
|
+
<ul>
|
|
249
|
+
<li>Nested.</li>
|
|
250
|
+
</ul>
|
|
251
|
+
</li>
|
|
252
|
+
</ul>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Ordered:
|
|
256
|
+
|
|
257
|
+
```html
|
|
258
|
+
<ol>
|
|
259
|
+
<li>One.</li>
|
|
260
|
+
<li>Two.</li>
|
|
261
|
+
</ol>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## §12. Blockquote (non-callout)
|
|
267
|
+
|
|
268
|
+
For quotations, citations, or "as said by X" passages that are NOT admonitions.
|
|
269
|
+
|
|
270
|
+
```html
|
|
271
|
+
<blockquote>
|
|
272
|
+
<p>The best code is no code at all.</p>
|
|
273
|
+
</blockquote>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## §13. Horizontal rule
|
|
279
|
+
|
|
280
|
+
```html
|
|
281
|
+
<hr>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Use sparingly — markdown `---` between major sections only.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## §14. Inline elements
|
|
289
|
+
|
|
290
|
+
- Inline code: `<code>identifier</code>`
|
|
291
|
+
- Bold: `<strong>important</strong>`
|
|
292
|
+
- Italic: `<em>nuance</em>`
|
|
293
|
+
- Link: `<a href="https://example.com">label</a>` (external links open in same tab; do not auto-add `target="_blank"`)
|
|
294
|
+
- Image: `<img src="path/to/image.png" alt="alt text">`
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## §16. Task list (GFM `- [ ]`)
|
|
299
|
+
|
|
300
|
+
Map `- [ ]` / `- [x]` lines (GitHub-flavored markdown task list). Render checked items strikethrough automatically via CSS.
|
|
301
|
+
|
|
302
|
+
```html
|
|
303
|
+
<ul class="task-list">
|
|
304
|
+
<li class="task-item">
|
|
305
|
+
<input type="checkbox" disabled>
|
|
306
|
+
<span class="task-text">Open ticket and reproduce locally.</span>
|
|
307
|
+
</li>
|
|
308
|
+
<li class="task-item">
|
|
309
|
+
<input type="checkbox" disabled checked>
|
|
310
|
+
<span class="task-text">Write failing test in <code>tests/billing.spec.ts</code>.</span>
|
|
311
|
+
</li>
|
|
312
|
+
</ul>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Always emit `disabled` on the checkbox — the HTML is a view, not interactive state. `checked` reflects the source `- [x]`.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## §17. Strikethrough
|
|
320
|
+
|
|
321
|
+
Map markdown `~~text~~` → `<del>`. Inline element, lives inside paragraphs/lists.
|
|
322
|
+
|
|
323
|
+
```html
|
|
324
|
+
<p>Migration was <del>scheduled for Friday</del> pushed to Monday.</p>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Use `<del>` (semantic) over `<s>` (presentational). Color is muted via CSS — do not add inline styles.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## §18. Footnotes
|
|
332
|
+
|
|
333
|
+
Map Pandoc/GFM style: inline `[^1]` → superscript ref linking to a footnotes section at the bottom of the page.
|
|
334
|
+
|
|
335
|
+
**Inline reference (in body):**
|
|
336
|
+
|
|
337
|
+
```html
|
|
338
|
+
<sup class="fn-ref"><a href="#fn-1" id="fnref-1">1</a></sup>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Footnotes section (once, at end of `<main>` after all body content):**
|
|
342
|
+
|
|
343
|
+
```html
|
|
344
|
+
<section class="footnotes" aria-label="Footnotes">
|
|
345
|
+
<h4>Footnotes</h4>
|
|
346
|
+
<ol>
|
|
347
|
+
<li id="fn-1">
|
|
348
|
+
The full citation or note. Identifiers stay verbatim: <code>RFC 8707</code>.
|
|
349
|
+
<a class="fn-back" href="#fnref-1" aria-label="Back to text">↩</a>
|
|
350
|
+
</li>
|
|
351
|
+
<li id="fn-2">
|
|
352
|
+
Second note.
|
|
353
|
+
<a class="fn-back" href="#fnref-2" aria-label="Back to text">↩</a>
|
|
354
|
+
</li>
|
|
355
|
+
</ol>
|
|
356
|
+
</section>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Numbering must match between body refs and list items. Heading label "Footnotes" translates per `{{LANG}}` — vi: "Chú thích". The target item (when navigated via `#fn-N`) gets a highlight ring via `:target` CSS — no extra markup needed.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## §19. Figure with caption
|
|
364
|
+
|
|
365
|
+
Wrap an image that has a caption (markdown `` or explicit caption prose right after) into `<figure>`.
|
|
366
|
+
|
|
367
|
+
```html
|
|
368
|
+
<figure>
|
|
369
|
+
<img src="diagrams/auth-flow.png" alt="OAuth flow with PKCE">
|
|
370
|
+
<figcaption>Figure 1: OAuth 2.1 + PKCE handshake. Token exchange happens server-side.</figcaption>
|
|
371
|
+
</figure>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
If the source image has no caption, use plain `<img>` (§14) instead — do not invent caption text.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## §20. Anchor copy link (auto-injected)
|
|
379
|
+
|
|
380
|
+
**You do not emit this markup.** Template JS auto-adds a `<a class="anchor" href="#id">#</a>` to every `<h2 id>` and `<h3 id>` on page load. Hover the heading to reveal it; click to copy the deep link to clipboard.
|
|
381
|
+
|
|
382
|
+
What you must ensure:
|
|
383
|
+
|
|
384
|
+
- Every section heading you want copyable has an `id` attribute.
|
|
385
|
+
- Do not emit your own `.anchor` element — the JS handles it.
|
|
386
|
+
|
|
387
|
+
CSS hides it by default and shows on `:hover` of the parent heading; on mobile it stays inline at .45 opacity so it's discoverable without hover.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## §21. UI label translations
|
|
392
|
+
|
|
393
|
+
UI chrome labels go into placeholders (template). Provide values matching `{{LANG}}`:
|
|
394
|
+
|
|
395
|
+
| Placeholder | en | vi |
|
|
396
|
+
|---|---|---|
|
|
397
|
+
| `{{TOC_LABEL}}` | Contents | Mục lục |
|
|
398
|
+
| `{{SEARCH_PLACEHOLDER}}` | Search… | Tìm trong trang… |
|
|
399
|
+
| `{{SKIP_LABEL}}` | Skip to content | Bỏ qua menu |
|
|
400
|
+
| `{{THEME_TIP}}` | Toggle theme | Đổi theme |
|
|
401
|
+
| `{{UPDATED_LABEL}}` | updated | cập nhật |
|
|
402
|
+
| `{{COPY_LABEL}}` | Copy | Sao chép |
|
|
403
|
+
| `{{COPIED_LABEL}}` | Copied | Đã chép |
|
|
404
|
+
| Footnotes heading (§18) | Footnotes | Chú thích |
|
|
405
|
+
|
|
406
|
+
Callout title translations (in body markup, not placeholders):
|
|
407
|
+
|
|
408
|
+
| Variant | en | vi |
|
|
409
|
+
|---|---|---|
|
|
410
|
+
| note | Note | Ghi chú |
|
|
411
|
+
| tip | Tip | Mẹo |
|
|
412
|
+
| warn | Warning | Cảnh báo |
|
|
413
|
+
| danger | Danger | Nguy hiểm |
|
|
414
|
+
|
|
415
|
+
For other source languages, translate consistently across all labels and titles.
|