refactor: rename content types to semantic taxonomy
- vault → notes (PKM-exported content) - posts → articles (short-form, no TOC) - papers → essays (long-form, with TOC) - type: post → type: article (posts are just short articles) - layouts/paper → layouts/essay - 08a-paper.css → 08a-essay.css - CSS: fix redundant li resets, remove role="main" from article, replace <small> prev/next labels, add console layout - Update hugo.toml menus, internal URLs, front matter throughout - Add docs/context.md, docs/css-refactor-plan.md
This commit is contained in:
parent
1408a52e8b
commit
15a6db9c0e
31 changed files with 788 additions and 70 deletions
73
docs/template-h1-title.md
Normal file
73
docs/template-h1-title.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Template Design: Handling the Markdown H1 / Front Matter Title Conflict
|
||||
|
||||
## The Problem
|
||||
|
||||
Standard markdown convention — Obsidian, agent-written files, generic `.md` — opens
|
||||
with a level-1 heading as the document title:
|
||||
|
||||
```markdown
|
||||
# My Note Title
|
||||
|
||||
Body text...
|
||||
```
|
||||
|
||||
Hugo templates also render a title from front matter:
|
||||
|
||||
```html
|
||||
<h1>{{ .Title }}</h1>
|
||||
```
|
||||
|
||||
When both exist, the page gets two `<h1>` elements: one from the template,
|
||||
one from the rendered markdown content. The content one also carries an
|
||||
auto-generated `id` attribute from Hugo's heading anchor renderer.
|
||||
|
||||
## The Two Template Contracts
|
||||
|
||||
**Default (`_default/single.html`)** — bare markdown, minimal or no front matter.
|
||||
The `# Title` in content IS the h1. The template header renders only metadata
|
||||
(type, date, author, tags). No title rendered from front matter.
|
||||
|
||||
**Vault (`vault/single.html`)** — enriched front matter (`title`, `type`, `date`,
|
||||
`author`, `tags`). Front matter `title` is authoritative. The `# Title` in content
|
||||
is still present (markdown convention) but must be suppressed.
|
||||
|
||||
## The Fix: Engine-Agnostic Regex Strip
|
||||
|
||||
When a template owns the title (renders `<h1>{{ .Title }}</h1>` from front matter),
|
||||
strip the first h1 from the rendered content before outputting it.
|
||||
|
||||
**Hugo:**
|
||||
```
|
||||
{{ replaceRE "<h1[^>]*>.*?</h1>" "" .Content 1 | safeHTML }}
|
||||
```
|
||||
|
||||
**Jinja2 / Flask:**
|
||||
```python
|
||||
import re
|
||||
content = re.sub(r'<h1[^>]*>.*?</h1>', '', content, count=1, flags=re.DOTALL)
|
||||
```
|
||||
|
||||
**Nunjucks / Liquid / any engine:** equivalent string replace on the rendered HTML.
|
||||
|
||||
This is a string operation on already-rendered HTML, not a template-engine concept.
|
||||
It ports to any engine without modification.
|
||||
|
||||
## Why Not Other Approaches
|
||||
|
||||
- **Author convention** (don't write `# Title` in vault files): breaks compatibility
|
||||
with the entire markdown ecosystem.
|
||||
- **Hugo render hooks** (`layouts/vault/_markup/render-heading.html`): Hugo-specific,
|
||||
not portable.
|
||||
- **CSS `display: none`**: h1 still exists in DOM — screen readers read it,
|
||||
search engines index it. Semantically wrong.
|
||||
|
||||
## Engine-Agnostic Principle
|
||||
|
||||
ASW templates are prototyped in Hugo but must be portable to Flask/Jinja2 or
|
||||
any other engine. Template logic should express *what*, not *how*:
|
||||
|
||||
- What: "strip h1 from content if front matter title is present"
|
||||
- How: engine-specific implementation of the same string operation
|
||||
|
||||
Hugo-specific features (render hooks, shortcodes) are acceptable as prototyping
|
||||
tools but should not become load-bearing parts of the template design.
|
||||
Loading…
Add table
Add a link
Reference in a new issue