diff --git a/docs/site/README.md b/docs/site/README.md index e4fce7f..741459c 100644 --- a/docs/site/README.md +++ b/docs/site/README.md @@ -11,5 +11,7 @@ python3 -m venv .venv && .venv/bin/pip install markdown .venv/bin/python docs/site/build.py /path/to/public_html/noema ``` -The output is intentionally not linked from the site navigation and carries a -`noindex` robots directive. +The output uses the dixon.cx page shell and is indexable, with canonical, +Open Graph, Twitter and TechArticle JSON-LD metadata. Add any new chapter to the +`` block of dixon.cx's `sitemap.xml`, then run +`scripts/site-seo-audit.py` there. diff --git a/docs/site/build.py b/docs/site/build.py index fac3eaf..ec1e4dd 100644 --- a/docs/site/build.py +++ b/docs/site/build.py @@ -6,8 +6,9 @@ Usage: python3 docs/site/build.py OUTPUT_DIR Sources: the repository's Markdown documents, the OpenAPI document, the UI screenshots, and the authored pages in docs/site/pages/*.md. A page file may pull a repository document in with a line `{{include path [demote]}}`. -The output follows the dixon.cx page skeleton; the section is deliberately -not linked from the site navigation and is marked noindex. +The output follows the dixon.cx page shell (css/site.css, navy rail) with the +full SEO head: indexable, canonical, Open Graph, Twitter and TechArticle JSON-LD. +Every page must also be listed in the Noema block of dixon.cx's sitemap.xml. """ import html import json @@ -91,121 +92,76 @@ HEAD = """ - + - + + {titletag} | Andy Dixon - + + + + + - - - - - - - - + + + + + {style} + + + + + - - - + + +
+ +
+
-
- -
Phone:
- -

Hidden from the page source until you click: friction against scrapers, not a guarantee.

-
-
Email:
-

web@dixon.cx

-
    -
  • -
-
- -
- -
-
- -
- - -
- - -
-
""" -TAIL = """
+TAIL = """
-
+ +
- -
-
-
- - - - - + """ +# dixon.cx house style: plain ASCII punctuation on every published page. +PLAIN = str.maketrans({"\u2014": "-", "\u2013": "-", "\u2018": "'", "\u2019": "'", "\u201c": '"', "\u201d": '"', "\u2026": "..."}) + LINK_MAP = { "ARCHITECTURE.md": "architecture", "SECURITY.md": "security", "THREAT_MODEL.md": "security", "PLAN.md": "development", "CONTRIBUTING.md": "development", "CHANGELOG.md": "development", "README.md": "index", @@ -348,7 +304,16 @@ def render_page(idx, slug, title, summary, md): {contents} ''' canonical = SITE + BASE + ("" if slug == "index" else slug) - page = HEAD.format(title=html.escape(title), titletag=html.escape(title if slug == "index" else title + " | Noema"), desc=html.escape(summary), canonical=canonical, style=STYLE) + head_box + "\n".join(boxes) + nav_box + TAIL + ld = {"@context": "https://schema.org", "@type": "TechArticle", "headline": title, "description": summary, + "author": {"@type": "Person", "name": "Andy Dixon", "url": SITE + "/"}, + "publisher": {"@type": "Person", "name": "Andy Dixon", "url": SITE + "/"}, + "mainEntityOfPage": canonical, "inLanguage": "en-GB"} + if slug != "index": + ld["isPartOf"] = {"@type": "CreativeWork", "name": "Noema", "url": SITE + BASE} + jsonld = "\n".join("\t\t" + l for l in json.dumps(ld, indent=2, ensure_ascii=False).replace("