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
32 changes: 25 additions & 7 deletions site/vendor/pages-theme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const collections = { docs: docsCollection() };
| `tagline` | – | A few words for the start page's `<title>` and the OG image; see „Search engines" |
| `website` | – | The project's landing page (`https://judge.casoon.de`): header, footer, JSON-LD `sameAs` |
| `catalog` | repository name | Slug of the project's entry on casoon.dev (`#projekt-<slug>`), linked in the footer; `false` for none |
| `version` | – | Header badge, "Docs for vX" |
| `version` | the project's manifest | Header badge, "Docs for vX"; see „Version" |
| `license` | `MIT` | SPDX id for footer and JSON-LD; `false` for proprietary code names no licence |
| `branch` | `main` | "Edit this page" links |
| `accent` | CASOON petrol | `{ light, dark }` project colour; needs 4.5:1 on `#f6f6f5` and `#101010` |
Expand All @@ -80,6 +80,18 @@ export const collections = { docs: docsCollection() };
| `lang` | `en` | `en` or `de`: `<html lang>` and the theme's own UI strings (`lib/i18n.ts`); props passed by the project win |
| `showcaseLead` | – | Lead paragraph of the showcase overview, instead of the theme's generic one |

#### Version

Left out, `version` comes from the manifest next to `site/`: `version` in `package.json`, else
`[package]` or `[workspace.package]` in `Cargo.toml`. So the number is maintained in one place,
and a release updates the site by itself. Pages read it as `config.version` from
`virtual:casoon-pages/config` — a start page that shows the release in a `Badge` takes it from
there instead of typing it out.

A wrong number is worse than none, so anything that cannot be read with certainty yields none:
a workspace whose version sits in a member crate, a `package.json` without `version`, a project
with neither manifest. Those pass `version` themselves, and `false` shows none at all.

### Routes

| Route | Source |
Expand Down Expand Up @@ -222,13 +234,19 @@ in `astro.config.mjs`.
`website`, the project's catalog entry on casoon.dev and the catalog itself, all with
descriptive text in the page's `lang`.

`casoon.github.io` has no root repository, so there is no root `robots.txt` pointing at the
sitemaps. Register each site in Google Search Console instead, once per project:
The root `https://casoon.github.io/` comes from the repository `casoon/casoon.github.io`: an
overview of the project sites, the only `robots.txt` crawlers read for the domain (one `Sitemap:`
line per project), and the Google Search Console verification. Its URL-prefix property
`https://casoon.github.io/` covers every project site, so a project needs no property and no
verification file of its own. For a new site:

1. Deploy it and check that `https://casoon.github.io/<repo>/sitemap.xml` answers 200.
2. In `casoon/casoon.github.io`, add `Sitemap: https://casoon.github.io/<repo>/sitemap.xml` to
`robots.txt` and the site to `index.html`, then push.
3. In the property `https://casoon.github.io/`, *Sitemaps* → submit `<repo>/sitemap.xml`.

1. *Add property* → *URL prefix* → `https://casoon.github.io/<repo>/`.
2. Verify ownership with the *HTML file* method: put the downloaded `google<id>.html` into the
project's `site/public/` and deploy; it is served at `https://casoon.github.io/<repo>/google<id>.html`.
3. *Sitemaps* → submit `sitemap.xml` (resolved against the prefix).
Never set a custom domain on `casoon/casoon.github.io`: GitHub would redirect every project site
to it as well.

## Rules the theme enforces

Expand Down
6 changes: 3 additions & 3 deletions site/vendor/pages-theme/SOURCE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@casoon/pages-theme 0.7.3
source: gh-pages-template@884a602
synced: 2026-10-24
@casoon/pages-theme 0.8.0
source: gh-pages-template@a03f9ef
synced: 2026-10-26

Vendored copy. Do not edit here: change the theme in gh-pages-template,
then run scripts/sync-theme.sh <this repo>.
24 changes: 20 additions & 4 deletions site/vendor/pages-theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { existsSync } from 'node:fs';
import { existsSync, readFileSync } from 'node:fs';
import { writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import mdx from '@astrojs/mdx';
import type { AstroIntegration } from 'astro';
import type { Lang } from './lib/i18n';
import { renderOgImage } from './lib/og';
import { projectVersion } from './lib/version';

export interface PackageLink {
/** Label shown in the footer and as badge, e.g. "crates.io" or "npm". */
Expand All @@ -26,8 +27,9 @@ export interface CasoonPagesOptions {
catalog?: string | false;
/** GitHub repository as "owner/name". Omit for a private repository: no GitHub or edit links. */
repo?: string;
/** Current release, shown in the header and on docs pages. */
version?: string;
/** Current release, shown in the header and on docs pages.
* Omitted: read from package.json or Cargo.toml next to site/. `false` shows none. */
version?: string | false;
/** SPDX licence identifier, or false for proprietary code (no licence named). Default: "MIT". */
license?: string | false;
/** Default branch, used for "Edit this page" links. Default: "main". */
Expand Down Expand Up @@ -108,7 +110,10 @@ export default function casoonPages(options: CasoonPagesOptions): AstroIntegrati
catalog:
options.catalog === false ? '' : (options.catalog ?? options.repo?.split('/')[1] ?? ''),
repo: options.repo ?? '',
version: options.version ?? '',
version:
options.version === false
? ''
: (options.version ?? projectVersion(resolve(root, '..'))),
license: options.license ?? 'MIT',
branch: options.branch ?? 'main',
accent: options.accent ?? null,
Expand Down Expand Up @@ -162,6 +167,17 @@ export default function casoonPages(options: CasoonPagesOptions): AstroIntegrati
},
});
},
// Project pages may import the virtual modules too (`config.version` on a start page),
// so the declarations go into the project's generated types, not just the theme's.
'astro:config:done': ({ injectTypes }) => {
injectTypes({
filename: 'virtual.d.ts',
content: readFileSync(new URL('./virtual.d.ts', import.meta.url), 'utf8').replace(
"'./index'",
"'@casoon/pages-theme'"
),
});
},
// Sitemap and OG image need absolute URLs, so both depend on `site`.
'astro:build:done': async ({ dir, pages }) => {
const base = site;
Expand Down
50 changes: 50 additions & 0 deletions site/vendor/pages-theme/lib/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

/**
* The project's current release, read from the manifest next to site/ so it is never
* maintained twice. npm projects keep it in package.json, Rust projects in Cargo.toml
* (also as `[workspace.package]`, which a crate inherits with `version.workspace = true`).
*
* A wrong number on the page is worse than none: anything this cannot read with certainty
* yields '', and the project passes `version` itself.
*/
export function projectVersion(repoRoot: string): string {
return fromPackageJson(repoRoot) || fromCargoToml(repoRoot) || '';
}

function read(path: string): string | null {
try {
return readFileSync(path, 'utf8');
} catch {
return null;
}
}

function fromPackageJson(repoRoot: string): string {
const raw = read(join(repoRoot, 'package.json'));
if (raw === null) return '';
try {
const { version } = JSON.parse(raw) as { version?: unknown };
return typeof version === 'string' ? version : '';
} catch {
return '';
}
}

function fromCargoToml(repoRoot: string): string {
const raw = read(join(repoRoot, 'Cargo.toml'));
if (raw === null) return '';
return section(raw, 'package') || section(raw, 'workspace.package');
}

/** First `version = "…"` inside [<name>], stopping at the next table header. */
function section(toml: string, name: string): string {
const start = toml.search(new RegExp(`^\\[${name.replaceAll('.', '\\.')}\\]\\s*$`, 'm'));
if (start === -1) return '';
const rest = toml.slice(start);
const next = rest.indexOf('\n[', 1);
const body = next === -1 ? rest : rest.slice(0, next);
const match = body.match(/^version\s*=\s*"([^"]+)"/m);
return match ? match[1] : '';
}
2 changes: 1 addition & 1 deletion site/vendor/pages-theme/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@casoon/pages-theme",
"version": "0.7.3",
"version": "0.8.0",
"private": true,
"description": "Shared Astro theme for the GitHub Pages sites of CASOON open-source projects",
"type": "module",
Expand Down
Loading