feat: auto-generated docs sidebar, Decap CMS, content migration infra

Docs restructure:
- Move flat docs into section subdirs (getting-started/, core/,
  components/, reference/) with _index.md for each
- Sidebar auto-generates from content structure — no manual menu entries
- New doc pages appear automatically when created in a section

Decap CMS:
- admin/index.html + config.yml for browser-based editing
- Local mode (npx decap-server) — no OAuth needed
- Collections for all content types: docs, articles, essays, notes, pages

Hugo head.html updated for new CSS layer filenames.
decap-server added as devDependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ludo 2026-04-11 18:02:34 +02:00
parent 86464f3e21
commit dd810f5a63
Signed by: ludo
GPG key ID: F6E479DEFAB84D6E
22 changed files with 1624 additions and 140 deletions

1447
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,10 +9,11 @@
"open-props": "^1.7.0" "open-props": "^1.7.0"
}, },
"devDependencies": { "devDependencies": {
"cssnano": "^7.0.0",
"decap-server": "^3.6.0",
"postcss": "^8.4.0", "postcss": "^8.4.0",
"postcss-cli": "^11.0.0", "postcss-cli": "^11.0.0",
"postcss-import": "^16.0.0",
"postcss-custom-media": "^11.0.0", "postcss-custom-media": "^11.0.0",
"cssnano": "^7.0.0" "postcss-import": "^16.0.0"
} }
} }

View file

@ -0,0 +1,4 @@
---
title: "Components"
weight: 30
---

View file

@ -0,0 +1,4 @@
---
title: "Core"
weight: 20
---

View file

@ -0,0 +1,4 @@
---
title: "Getting Started"
weight: 10
---

View file

@ -0,0 +1,4 @@
---
title: "Reference"
weight: 40
---

View file

@ -39,95 +39,12 @@ title = 'ASW — Agentic Semantic Web'
url = "/tags/" url = "/tags/"
weight = 6 weight = 6
# ── Docs sidebar menu ───────────────────────────────────────────────── # ── Docs sidebar ─────────────────────────────────────────────────────
# Parent entries (identifier set, no url) render as <small> section labels. # Auto-generated from content/docs/ subdirectories.
# Child entries (parent set) render as sidebar nav links. # Each subdir with _index.md becomes an h3 section header.
# Pages within are listed by weight. No manual menu entries needed.
[[menus.docs]] # To add a new section: mkdir content/docs/newsection/ + _index.md
name = "Getting Started" # To add a new page: create .md in the right subdir with weight.
identifier = "docs-getting-started"
weight = 10
[[menus.docs]]
name = "Introduction"
url = "/docs/introduction/"
parent = "docs-getting-started"
weight = 11
[[menus.docs]]
name = "Core"
identifier = "docs-core"
weight = 20
[[menus.docs]]
name = "Reset"
url = "/docs/reset/"
parent = "docs-core"
weight = 21
[[menus.docs]]
name = "Semantic HTML"
url = "/docs/on-semantic-html/"
parent = "docs-core"
weight = 22
[[menus.docs]]
name = "Data Attributes"
url = "/docs/data-attributes/"
parent = "docs-core"
weight = 23
[[menus.docs]]
name = "Components"
identifier = "docs-components"
weight = 30
[[menus.docs]]
name = "Layouts"
url = "/docs/layouts/"
parent = "docs-components"
weight = 31
[[menus.docs]]
name = "Components"
url = "/docs/components/"
parent = "docs-components"
weight = 32
[[menus.docs]]
name = "Accordion & Dialog"
url = "/docs/accordion-dialog/"
parent = "docs-components"
weight = 33
[[menus.docs]]
name = "Navigation"
url = "/docs/navigation/"
parent = "docs-components"
weight = 34
[[menus.docs]]
name = "Reference"
identifier = "docs-reference"
weight = 40
[[menus.docs]]
name = "Charts"
url = "/docs/charts/"
parent = "docs-reference"
weight = 41
[[menus.docs]]
name = "Syntax Highlighting"
url = "/docs/chroma/"
parent = "docs-reference"
weight = 42
[[menus.docs]]
name = "ASW Vocabulary"
url = "/articles/asw-vocabulary/"
parent = "docs-reference"
weight = 43
# ── Markup settings ─────────────────────────────────────────────────── # ── Markup settings ───────────────────────────────────────────────────
[markup.goldmark.renderer] [markup.goldmark.renderer]

View file

@ -15,46 +15,19 @@
<section data-layout="docs"> <section data-layout="docs">
<nav aria-label="Documentation" data-nav="sidebar"> <nav aria-label="Documentation" data-nav="sidebar">
{{- $menu := index .Site.Menus "docs" -}} {{- $top := .FirstSection -}}
{{- if $menu -}} {{- range $top.Sections.ByWeight -}}
{{- range $menu -}} <h3>{{ .Title }}</h3>
{{- if .HasChildren -}} <ul>
<h3>{{ .Name }}</h3> {{- range .RegularPages.ByWeight -}}
<ul> <li>
{{- range .Children -}} <a href="{{ .RelPermalink }}"
<li> {{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
<a href="{{ .URL }}" {{- .LinkTitle -}}
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}> </a>
{{- .Name -}} </li>
</a>
</li>
{{- end -}}
</ul>
{{- else -}}
<ul>
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
</ul>
{{- end -}}
{{- end -}}
{{- else -}}
{{- with .CurrentSection -}}
<h3>{{ .Title }}</h3>
<ul>
{{- range .RegularPages -}}
<li>
<a href="{{ .RelPermalink }}"
{{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .LinkTitle -}}
</a>
</li>
{{- end -}}
</ul>
{{- end -}} {{- end -}}
</ul>
{{- end -}} {{- end -}}
</nav> </nav>

View file

@ -22,16 +22,18 @@
<link rel="stylesheet" href="/vendor/open-props.min.css"> <link rel="stylesheet" href="/vendor/open-props.min.css">
<link rel="stylesheet" href="/vendor/media.min.css"> <link rel="stylesheet" href="/vendor/media.min.css">
<link rel="stylesheet" href="/css/layers/00-reset.css"> <link rel="stylesheet" href="/css/layers/00-reset.css">
<link rel="stylesheet" href="/css/layers/01-asw.css"> <link rel="stylesheet" href="/css/layers/01-tokens.css">
<link rel="stylesheet" href="/css/layers/02-semantic.css"> <link rel="stylesheet" href="/css/layers/02-typography.css">
<link rel="stylesheet" href="/css/layers/03-components.css"> <link rel="stylesheet" href="/css/layers/03-landmarks.css">
<link rel="stylesheet" href="/css/layers/04-data-attrs.css"> <link rel="stylesheet" href="/css/layers/04-forms.css">
<link rel="stylesheet" href="/css/layers/05-utilities.css"> <link rel="stylesheet" href="/css/layers/05-components.css">
<link rel="stylesheet" href="/css/layers/06-charts.css"> <link rel="stylesheet" href="/css/layers/06-navigation.css">
<link rel="stylesheet" href="/css/layers/07-chroma.css"> <link rel="stylesheet" href="/css/layers/07-data-attrs.css">
<link rel="stylesheet" href="/css/layers/08-layout.css"> <link rel="stylesheet" href="/css/layers/08-utilities.css">
<link rel="stylesheet" href="/css/layers/08a-paper.css"> <link rel="stylesheet" href="/css/layers/09-charts.css">
<link rel="stylesheet" href="/css/layers/09-landing.css"> <link rel="stylesheet" href="/css/layers/10-chroma.css">
<link rel="stylesheet" href="/css/layers/11-layout.css">
<link rel="stylesheet" href="/css/layers/12-landing.css">
{{- else }} {{- else }}
<link rel="stylesheet" href="/asw.css"> <link rel="stylesheet" href="/asw.css">
{{- end }} {{- end }}

View file

@ -0,0 +1,117 @@
# Decap CMS — ASW site content manager
#
# LOCAL MODE: run `npx decap-server` from site/ directory
# No OAuth, no Forgejo auth — reads/writes files directly.
#
# PRODUCTION MODE: switch backend to gitea (see packs/hugo/admin/config.yml)
local_backend: true
backend:
name: git-gateway
media_folder: static/images
public_folder: /images
slug:
encoding: ascii
clean_accents: true
collections:
- name: docs-getting-started
label: "Docs: Getting Started"
folder: content/docs/getting-started
create: true
slug: "{{slug}}"
fields: &doc-fields
- { label: Title, name: title, widget: string }
- { label: Description, name: description, widget: string, required: false }
- { label: Type, name: type, widget: hidden, default: docs }
- { label: Weight, name: weight, widget: number, required: false, hint: "Sort order in sidebar" }
- { label: Date, name: date, widget: datetime, format: "YYYY-MM-DD" }
- { label: Tags, name: tags, widget: list, required: false }
- { label: AI Disclosure, name: ai-disclosure, widget: select, options: ["generated", "assisted", "none"], default: "assisted" }
- { label: AI Model, name: ai-model, widget: string, required: false }
- { label: AI Provider, name: ai-provider, widget: string, required: false, default: "Anthropic" }
- { label: Body, name: body, widget: markdown }
- name: docs-core
label: "Docs: Core"
folder: content/docs/core
create: true
slug: "{{slug}}"
fields: *doc-fields
- name: docs-components
label: "Docs: Components"
folder: content/docs/components
create: true
slug: "{{slug}}"
fields: *doc-fields
- name: docs-reference
label: "Docs: Reference"
folder: content/docs/reference
create: true
slug: "{{slug}}"
fields: *doc-fields
- name: articles
label: Articles
label_singular: Article
folder: content/articles
create: true
slug: "{{slug}}"
fields:
- { label: Title, name: title, widget: string }
- { label: Description, name: description, widget: string, required: false }
- { label: Date, name: date, widget: datetime, format: "YYYY-MM-DD" }
- { label: Tags, name: tags, widget: list, required: false }
- { label: AI Disclosure, name: ai-disclosure, widget: select, options: ["generated", "assisted", "none"], default: "assisted" }
- { label: AI Model, name: ai-model, widget: string, required: false }
- { label: AI Provider, name: ai-provider, widget: string, required: false, default: "Anthropic" }
- { label: Body, name: body, widget: markdown }
- name: essays
label: Essays
label_singular: Essay
folder: content/essays
create: true
slug: "{{slug}}"
fields:
- { label: Title, name: title, widget: string }
- { label: Description, name: description, widget: string }
- { label: Abstract, name: abstract, widget: text, required: false }
- { label: Author, name: author, widget: string, required: false }
- { label: Eyebrow, name: eyebrow, widget: string, required: false, default: "Essay" }
- { label: Type, name: type, widget: hidden, default: essay }
- { label: Date, name: date, widget: datetime, format: "YYYY-MM-DD" }
- { label: Tags, name: tags, widget: list, required: false }
- { label: Draft, name: draft, widget: boolean, default: true }
- { label: AI Disclosure, name: ai-disclosure, widget: select, options: ["generated", "assisted", "none"], default: "assisted" }
- { label: AI Model, name: ai-model, widget: string, required: false }
- { label: AI Provider, name: ai-provider, widget: string, required: false, default: "Anthropic" }
- { label: Body, name: body, widget: markdown }
- name: notes
label: Notes
label_singular: Note
folder: content/notes
create: true
slug: "{{slug}}"
fields:
- { label: Title, name: title, widget: string }
- { label: Date, name: date, widget: datetime, format: "YYYY-MM-DD" }
- { label: Tags, name: tags, widget: list, required: false }
- { label: Body, name: body, widget: markdown }
- name: pages
label: Pages
label_singular: Page
folder: content/pages
create: true
slug: "{{slug}}"
fields:
- { label: Title, name: title, widget: string }
- { label: Description, name: description, widget: string, required: false }
- { label: Body, name: body, widget: markdown }

View file

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASW Content Manager</title>
</head>
<body>
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
</body>
</html>