This commit is contained in:
ed committed 2026-08-25 12:41:14 -04:00
1 parent d4221f1455
commit 0703c7a1fc
4 files changed
+132 -15

No files matched your search

+1
View File
@@ -22,3 +22,4 @@ secrets/*
!secrets/README.md
scripts/twitter/__pycache__
scripts/twitter/tests/__pycache__
publish/quartz-patches/__pycache__
+1 -1
View File
@@ -1,4 +1,4 @@
# Threadwell\
# Threadwell
Recovered threads and submerged records.
+34 -14
View File
@@ -1,4 +1,4 @@
"""Single source of truth for the Threadwell site base.
"""Keep in-site links under the /Threadwell/ path.
Two stages:
@@ -6,13 +6,11 @@ Two stages:
relative URLs in the SPA click handler resolve from a directory base.
2. After `npx quartz build`, rewrite every built HTML file:
- add `<base href="<abs>">` so relative URL resolution works even when
the URL bar lacks a trailing slash
- rewrite the sidebar `<a class="page-title">` href to the absolute site
base, not the directory the page is in
- set `<base href>` to that page's directory under the site path so
Quartz page-relative `../` links do not resolve against the domain root
- rewrite the sidebar `<a class="page-title">` href to the site path
The base URL is read from `publish/quartz.config.yaml`'s `baseUrl`. Change
that line; the next deploy uses the new value everywhere.
`baseUrl` in `publish/quartz.config.yaml` is the single source of truth.
Idempotent. Safe to re-run.
"""
@@ -64,7 +62,9 @@ def read_base_url() -> tuple[str, str]:
ABS_BASE, REL_BASE = read_base_url()
HEAD_RE: re.Pattern[str] = re.compile(r"(<head[^>]*>)", re.IGNORECASE)
BASE_TAG = f'<base href="{ABS_BASE}">\n'
BASE_RE: re.Pattern[str] = re.compile(
r"<base\s+href=\"[^\"]*\"\s*/?>\s*", re.IGNORECASE
)
TITLE_LINK: re.Pattern[str] = re.compile(
r'(<h2[^>]*class="page-title"><a\s+href=")[^"]*(">)'
)
@@ -131,18 +131,38 @@ def patch_spa() -> bool:
# --- post-build HTML rewrites ----------------------------------------------
def page_dir_href(html_path: Path, public: Path, rel_base: str) -> str:
"""Return the path-absolute directory of a built HTML file.
`public/archive/threads/h/slug/index.html` with rel_base `/Threadwell/`
becomes `/Threadwell/archive/threads/h/slug/`.
"""
rel = html_path.relative_to(public).as_posix()
if rel.endswith("/index.html"):
dir_rel = rel[: -len("index.html")]
elif rel == "index.html":
dir_rel = ""
else:
cut = rel.rfind("/")
dir_rel = rel[: cut + 1] if cut >= 0 else ""
return f"{rel_base.rstrip('/')}/{dir_rel}"
def rewrite_html(path: Path) -> str | None:
"""Return 'base' / 'title' / None for what changed."""
text = path.read_text(encoding="utf-8", errors="ignore")
out = text
actions = []
actions: list[str] = []
expected_base = f'<base href="{page_dir_href(path, PUBLIC, REL_BASE)}">'
m = HEAD_RE.search(out)
if m and "quartz-base" not in out:
out = out[: m.end()] + "\n" + BASE_TAG + out[m.end():]
actions.append("base")
if out.count("<base ") != 1 or expected_base not in out:
out = BASE_RE.sub("", out)
m = HEAD_RE.search(out)
if m is not None:
out = out[: m.end()] + "\n" + expected_base + "\n" + out[m.end() :].lstrip()
actions.append("base")
if 'class="page-title"' in out:
out2 = TITLE_LINK.sub(rf"\g<1>{ABS_BASE}\g<2>", out)
out2 = TITLE_LINK.sub(rf"\g<1>{REL_BASE}\g<2>", out)
if out2 != out:
out = out2
actions.append("title")
+96
View File
@@ -0,0 +1,96 @@
from __future__ import annotations
import re
import tempfile
import unittest
from pathlib import Path
from urllib.parse import urljoin
import apply
DEEP_REL: str = "../../../../archive/threads/notimothylottes/"
DEEP_SLUG: str = (
"archive/threads/notimothylottes/2025-02-04-gelatinous-pixel-soup/index.html"
)
PAGE_BASE: str = (
"/Threadwell/archive/threads/notimothylottes/2025-02-04-gelatinous-pixel-soup/"
)
SAMPLE: str = (
"<html><head></head><body>"
'<h2 class="page-title"><a href="./">Threadwell</a></h2>'
f'<a class="internal" href="{DEEP_REL}">NOTimothyLottes</a>'
"</body></html>"
)
def _write_public(root: Path, rel: str, html: str) -> Path:
path = root / rel
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(html, encoding="utf-8")
return path
class ApplyBaseTests(unittest.TestCase):
def setUp(self) -> None:
self._public = apply.PUBLIC
self._tmp = tempfile.TemporaryDirectory()
self.public = Path(self._tmp.name)
apply.PUBLIC = self.public
def tearDown(self) -> None:
apply.PUBLIC = self._public
self._tmp.cleanup()
def test_deep_page_base_is_page_directory(self) -> None:
path = _write_public(self.public, DEEP_SLUG, SAMPLE)
apply.rewrite_html(path)
text = path.read_text(encoding="utf-8")
self.assertIn(f'<base href="{PAGE_BASE}">', text)
self.assertNotIn('<base href="https://edsabode.dev/Threadwell/">', text)
self.assertNotIn('<base href="/Threadwell/">', text)
def test_deep_page_relative_link_keeps_threadwell_prefix(self) -> None:
path = _write_public(self.public, DEEP_SLUG, SAMPLE)
apply.rewrite_html(path)
text = path.read_text(encoding="utf-8")
match = re.search(r'<base href="([^"]+)">', text)
self.assertIsNotNone(match)
assert match is not None
resolved = urljoin("https://edsabode.dev" + match.group(1), DEEP_REL)
self.assertEqual(
resolved,
"https://edsabode.dev/Threadwell/archive/threads/notimothylottes/",
)
def test_homepage_base_is_site_path(self) -> None:
path = _write_public(self.public, "index.html", SAMPLE)
apply.rewrite_html(path)
text = path.read_text(encoding="utf-8")
self.assertIn('<base href="/Threadwell/">', text)
def test_title_link_is_site_path_not_domain_root(self) -> None:
path = _write_public(self.public, DEEP_SLUG, SAMPLE)
apply.rewrite_html(path)
text = path.read_text(encoding="utf-8")
self.assertIn(
'<h2 class="page-title"><a href="/Threadwell/">',
text,
)
self.assertNotIn('href="https://edsabode.dev/Threadwell/"', text)
def test_rewrite_replaces_site_root_base_and_stays_idempotent(self) -> None:
html = SAMPLE.replace(
"<head></head>",
'<head><base href="https://edsabode.dev/Threadwell/"></head>',
)
path = _write_public(self.public, DEEP_SLUG, html)
apply.rewrite_html(path)
apply.rewrite_html(path)
text = path.read_text(encoding="utf-8")
self.assertEqual(text.count("<base "), 1)
self.assertIn(f'<base href="{PAGE_BASE}">', text)
if __name__ == "__main__":
unittest.main()