Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

The [pdf-archiver.io](https://pdf-archiver.io) website: a Swift package that generates static HTML
with [Publish](https://github.com/JohnSundell/Publish) and Plot. `README.md` documents the project
for contributors — the paths, the language layout, and how to add a page or a language. This file
adds what is not written there.

## Commands

```bash
swift run # build the generator and write the site to Output/
swift build # compile only
python3 -m http.server --directory Output # serve the generated site
```

There are no tests and no linter. Verification is `swift run` finishing green plus reading the files
it wrote to `Output/`. Every asset is linked absolutely (`/css/styles.css`), so opening
`Output/index.html` over `file://` renders unstyled — serve the folder instead.

`Output/` and `.publish/` are generated and git-ignored; never edit anything below them.

## Pipeline

`SiteGenerator.swift` lists the publishing steps, and their **order is the architecture** — each
custom step in `PublishingSteps.swift` repairs something Publish does that this site cannot use:

- `.buildPressKitArchive()` zips `presskit/` into `presskit.zip` at publish time, so the archive is
never versioned.
- `.moveGermanIndexPageToLanguageRoot()` turns `Content/de/index.md` into `/de` rather than
`/de/index`.
- `.removeFAQEntryPages()` deletes the per-question pages after HTML generation — the entries only
ever appear collected on `/faq` and `/de/faq`.
- `.generateCanonicalSiteMap(excluding:)` replaces Publish's site map, which omits the home pages
and spells URLs without their trailing slash.
- `.moveNotFoundPageToRoot()` writes `/404.html`, the only error page GitHub Pages serves.

## Invariants worth knowing before changing anything

- **The URL is the language.** `SiteLanguage(path:)` reads the leading path component, so a page's
language, strings and `lang` attribute all follow from where its file sits. Nothing carries the
language in front matter.
- **Every internal link ends in a slash.** GitHub Pages 301-redirects `/faq` to `/faq/`, so
`Path.directoryPath` and `canonicalURL(for:)` in `CanonicalPaths.swift` exist to keep the
canonical tag, the `hreflang` links and the site map pointing at the page instead of a redirect.
Use them for anything URL-shaped; `url(for:)` alone is one redirect off.
- **The home pages have no Markdown body.** `/` and `/de` are built from `SiteStrings`; their
Markdown files carry only `title` and `description`. Copy changes on the home page happen in
`Localization/SiteStrings+English.swift` and `+German.swift`, which must stay structurally
identical — `SiteStrings` has no optional members.
- **FAQ entries are ordered by file name.** `Content/faq/NN-slug.md`, sorted by path; the number is
the running order on the page. `/de/faq` renders the same English entries, because the FAQ itself
is not translated.
- **`Resources/` is copied verbatim into the site root; `root-resources/` holds files that must sit
unchanged at the root** (`CNAME`, `robots.txt`, `.well-known/`). Folder traversal skips dotted
folders, so `apple-app-site-association` is copied by name in a separate step, and the Pages
workflow needs `include-hidden-files: true` — universal links break silently otherwise.
- **The head is hand-assembled** in `Theme/DocumentHead.swift`: the full favicon set, `hreflang`
pairs, and JSON-LD that is emitted on the home pages only. `Website.favicon` and
`tagHTMLConfig` are deliberately `nil` so Publish adds nothing of its own.

## Front end

`Resources/css/styles.css` is the whole stylesheet, token-driven (`--font-heading`, `--font-body`,
`--font-mono`, the colour tokens) with a `prefers-color-scheme` block that only redefines tokens.
Headings are set in Charter, self-hosted from `Resources/assets/fonts/` under the Bitstream licence
that ships beside it as `charter-license.txt`. The other font files in that folder are leftovers of
the previous site and are referenced by nothing.

## Conventions

Base branch `develop`; branches are named `feature/…`. Pushing to `develop` builds on GitHub Actions
and publishes the Pages artifact — no branch holds the generated HTML. Pull requests build too, so a
broken generator surfaces before the merge.
Binary file added Resources/assets/fonts/charter-bold.woff2
Binary file not shown.
3 changes: 3 additions & 0 deletions Resources/assets/fonts/charter-license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This is a copy of the Charter fonts which Bitstream contributed to the X consortium. This is the original notice included with the fonts:

(c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA. You are hereby granted permission under all Bitstream propriety rights to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts for any purpose and without restriction; provided, that this notice is left intact on all copies of such fonts and that Bitstream's trademark is acknowledged as shown below on all unmodified copies of the 4 Charter Type 1 fonts. BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
Binary file added Resources/assets/fonts/charter-regular.woff2
Binary file not shown.
20 changes: 20 additions & 0 deletions Resources/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
Warm paper throughout, one dark card for "Keep it.", and the filename as the page's
signature: typed out in the hero, at rest at the end, its separators reused as dividers. */

/* Charter, Matthew Carter's 1987 text face. Bitstream gave it to the X Consortium for any use;
its licence has to travel with the files, so it sits next to them as charter-license.txt. */
@font-face {
font-family: Charter;
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/assets/fonts/charter-regular.woff2") format("woff2");
}

@font-face {
font-family: Charter;
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/assets/fonts/charter-bold.woff2") format("woff2");
}

:root {
color-scheme: light dark;

Expand All @@ -23,6 +41,7 @@


--wrap: 72rem;
--font-heading: Charter, Georgia, "Times New Roman", serif;
--font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
Expand Down Expand Up @@ -63,6 +82,7 @@ h1,
h2,
h3 {
margin: 0;
font-family: var(--font-heading);
line-height: 1.08;
letter-spacing: -0.02em;
text-wrap: balance;
Expand Down