diff --git a/lib/content/conformance.sh b/lib/content/conformance.sh index f4382aa4..664dd8ea 100755 --- a/lib/content/conformance.sh +++ b/lib/content/conformance.sh @@ -15,7 +15,7 @@ if [ ! -x "$SX_SERVER" ]; then fi fi -SUITES=(block doc render api meta page markdown text section stats table validate store snapshot crdt crdt-store sync md-import md-doc fed) +SUITES=(block doc render api meta page page-full markdown text section stats table validate store snapshot crdt crdt-store sync md-import md-doc fed) OUT_JSON="lib/content/scoreboard.json" OUT_MD="lib/content/scoreboard.md" @@ -48,6 +48,7 @@ run_suite() { (load "lib/content/stats.sx") (load "lib/content/table.sx") (load "lib/content/page.sx") +(load "lib/content/page-full.sx") (load "lib/content/markdown.sx") (load "lib/content/validate.sx") (load "lib/content/store.sx") diff --git a/lib/content/page-full.sx b/lib/content/page-full.sx new file mode 100644 index 00000000..b941aaba --- /dev/null +++ b/lib/content/page-full.sx @@ -0,0 +1,23 @@ +;; content-on-sx — SEO-complete HTML page. +;; +;; content/page-full extends content/page with a lang attribute and a +;; drawn from the document excerpt (plain text, +;; truncated). Composes the page, metadata and text layers. +;; +;; Requires (loaded by harness): page.sx (ct-html-escape, content/page-title), +;; text.sx (content/excerpt), render.sx (asHTML). + +(define CONTENT-EXCERPT-LEN 160) + +(define + content/page-full + (fn + (doc) + (str + "
Hello world
") + +;; description escaped +(content-test + "page-full escapes description" + (content/page-full + (doc-with-title + (doc-append (doc-empty "x") (mk-text "p" "a < b & c")) + "T")) + "a < b & c
") + +;; title falls back to id, empty description for empty doc +(content-test + "page-full empty" + (content/page-full (doc-empty "fallback")) + "Bye now
") diff --git a/plans/content-on-sx.md b/plans/content-on-sx.md index 7800b3f9..222846ae 100644 --- a/plans/content-on-sx.md +++ b/plans/content-on-sx.md @@ -19,7 +19,7 @@ injected adapter, not core. ## Status (rolling) -`bash lib/content/conformance.sh` → **481/481** (Phases 1–4 COMPLETE + extensions: HTML/SX escaping, Markdown render + import/export incl. tables & frontmatter (full round-trip), CRDT replication, tree-aware validation, snapshot cache, doc metadata, plain-text render, nested block trees, doc stats, table block, HTML page wrapper) +`bash lib/content/conformance.sh` → **485/485** (Phases 1–4 COMPLETE + extensions: HTML/SX escaping, Markdown render + import/export incl. tables & frontmatter (full round-trip), CRDT replication, tree-aware validation, snapshot cache, doc metadata, plain-text render, nested block trees, doc stats, table block, HTML page wrapper + SEO page) ## Ground rules @@ -90,9 +90,14 @@ lib/content/api.sx ── (content/edit) (content/render) (content/history) ─ - [x] document statistics (`stats.sx`: word/char/block counts, reading time) - [x] table block (`table.sx`: CtTable, renders html/sx/text/md, validated) - [x] HTML page wrapper (`page.sx`: content/page, escaped title from metadata) +- [x] SEO page (`page-full.sx`: content/page-full, lang + meta description from excerpt) ## Progress log +- 2026-06-07 — Extension: SEO-complete page (`page-full.sx`). `content/page-full` + extends content/page with `` and a `` + drawn from the document excerpt (plain text, escaped, 160 chars), composing the + page/metadata/text layers into the SEO-ready artifact. 4 tests; suite 485/485. - 2026-06-07 — Extension: Markdown document export (`md-doc.sx`). `content/markdown-doc` emits a `---` frontmatter block from metadata (title/slug/tags, only present fields) ahead of the Markdown body, or plain