diff --git a/scripts/site.sh b/scripts/site.sh index b5d15ca..149f8cd 100755 --- a/scripts/site.sh +++ b/scripts/site.sh @@ -173,6 +173,26 @@ if [[ -d "$ASSETS" ]]; then cp -R "$ASSETS/." "$STAGED/assets/" fi +# The landing page is not a file anyone writes directly. Helium takes the content +# of site/src/landing-page.md, lifts that document out of the tree and re-inserts +# it as the root directory's *title document* — and a title document is what +# renders to index.html. +# +# So a root index.md or README.md is not merely redundant, it is a second writer +# to index.html. Laika renders documents in parallel, and nothing in Laika or in +# this script arbitrates between them: whichever finishes last wins, and if they +# overlap the file ends up holding both. That is not hypothetical. The published +# site once served an index.html that was the landing page written over the first +# half of a second, differently-templated copy of the same page — closing +# in the middle, the sidebar's link list dumped into the body +# below it. Both builds exited 0. +# +# Fail here instead, naming the file and where its content belongs. +for collision in index.md README.md; do + [[ -f "$STAGED/$collision" ]] || continue + die "site/src/$collision renders to index.html, and so does the generated landing page. Two writers, one file, no arbitration — see the note above homeLink in site/build/laika.scala. Put the front page's prose in site/src/landing-page.md instead." +done + # MEASURED, NOT ASSUMED: Laika 1.3.2 does not resolve a link target written # `./sibling.md` — it reads `.` as a path segment and reports "unresolved # internal reference". `sibling.md` resolves; `../other/page.md` resolves. diff --git a/site/README.md b/site/README.md index c0c78d9..d7df48a 100644 --- a/site/README.md +++ b/site/README.md @@ -16,7 +16,7 @@ scripts/site.sh --help # the pipeline, step by step | Path | What it is | Owner | | --- | --- | --- | -| `src/index.md` | The landing page. | this directory | +| `src/landing-page.md` | The prose of the front page, rendered below the header and the teasers. The filename is fixed by Helium, and `src/` must hold no `index.md` or `README.md` — see the note above `homeLink` in `build/laika.scala`. | this directory | | `src/getting-started.md` | Install, first request, error rails, pagination. | this directory | | `src/examples.md` | The `modules/examples` programs. Its table is generated at build time. | this directory | | `src/directory.conf` | Laika configuration for the content tree: title and sidebar order. | this directory | diff --git a/site/build/laika.scala b/site/build/laika.scala index aa47436..332d972 100644 --- a/site/build/laika.scala +++ b/site/build/laika.scala @@ -199,7 +199,24 @@ object Site: .favIcons(Favicon.internal(Root / "assets" / "favicon.svg", sizes = "32x32")) .site .topNavigationBar( - homeLink = IconLink.internal(Root / "index.md", HeliumIcon.home), + // `Root / "README"`, with no `.md` and no such file in site/src, is not a typo. + // + // MEASURED, NOT ASSUMED. The landing page configured below is not a page anyone writes directly. Helium takes + // the content of `site/src/landing-page.md`, lifts that document out of the content tree, and re-inserts it as + // the *title document* of the root directory — at the suffix-less path `/README`, because `README` is Laika's + // default title-document input name. A directory's title document is what renders to `index.html`, which is how + // the landing page comes to be the site's front page. + // + // So this is the only path that resolves to the front page. `Root / "landing-page.md"` fails link validation, + // because by the time links are resolved that document is gone from the tree. `Root / "README.md"` fails too: + // the re-inserted document carries no suffix. + // + // The consequence to keep in mind is that site/src must contain no `index.md` and no `README.md`. Either one + // would also render to `index.html`, and Laika renders documents in parallel — so the two writers race for the + // same file. That is not hypothetical: it is what produced a published `index.html` holding the landing page + // spliced on top of the tail of a second, differently-templated copy of the same page. scripts/site.sh fails + // the build if either file reappears. + homeLink = IconLink.internal(Root / "README", HeliumIcon.home), navLinks = Seq( TextLink.internal(Root / "getting-started.md", "Getting Started"), TextLink.internal(Root / "examples.md", "Examples"), @@ -212,6 +229,9 @@ object Site: .site .pageNavigation(depth = 3) + // Everything below the header and the teaser rows is the prose of `site/src/landing-page.md`. That file has no + // top-level heading of its own on purpose: `title` here already renders "codeberg4s" at 48px directly above it, + // and a second `

codeberg4s

` under it said the same word twice. withChrome.site .landingPage( title = Some(SiteInfo.title), diff --git a/site/src/directory.conf b/site/src/directory.conf index 64ab811..9494952 100644 --- a/site/src/directory.conf +++ b/site/src/directory.conf @@ -14,8 +14,11 @@ laika.title = codeberg4s # scripts/site.sh. If one of them is missing, Laika ignores the entry rather # than failing, and scripts/site.sh prints a warning naming what it generated in # its place. +# +# `landing-page.md` is deliberately absent from this list. Helium lifts that file +# out of the content tree and renders it as the site's landing page, so it is not +# a sidebar entry — see the note above `homeLink` in site/build/laika.scala. laika.navigationOrder = [ - index.md getting-started.md guides reference diff --git a/site/src/index.md b/site/src/landing-page.md similarity index 99% rename from site/src/index.md rename to site/src/landing-page.md index b375050..ed97982 100644 --- a/site/src/index.md +++ b/site/src/landing-page.md @@ -1,5 +1,3 @@ -# codeberg4s - A Scala 3 client for the [Codeberg](https://codeberg.org) and [Forgejo](https://forgejo.org) REST API v1. All 439 in-scope operations are implemented, on both error rails, against models built from captured responses