CTAO Science Portal: static Astro site with git-based CMS (Sveltia + Gitea)

Portal code only; editorial content lives in the ctao/content repo on the
demo machine's Gitea and is overlaid at build time (see README.md and
deploy/README.md). Live demo: https://astro.isl-dev.grid.cyfronet.pl
This commit is contained in:
2026-09-08 13:49:21 +02:00
parent 845c1ccf0d
commit 2817353c46
50 changed files with 11564 additions and 44 deletions
+38
View File
@@ -0,0 +1,38 @@
// Deterministic internal-link check over the built site (zero dependencies).
// Run AFTER `astro build`: scans dist/**/*.html for root-relative href/src
// values and fails (exit 1) if any target has no file in dist/. External
// URLs, mailto:, data: and pure-#fragment links are out of scope.
import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
import { join } from 'node:path';
const DIST = new URL('../dist', import.meta.url).pathname;
if (!existsSync(DIST)) { console.error('dist/ not found — run `npm run build` first'); process.exit(1); }
const htmlFiles = [];
(function walk(dir) {
for (const name of readdirSync(dir)) {
const p = join(dir, name);
if (statSync(p).isDirectory()) walk(p);
else if (name.endsWith('.html')) htmlFiles.push(p);
}
})(DIST);
const resolves = (path) => {
const clean = decodeURI(path.split(/[?#]/)[0]);
if (clean === '/') return true;
return ['', '.html', '/index.html'].some((suffix) =>
existsSync(join(DIST, clean.replace(/\/$/, '') + suffix)));
};
let broken = 0;
for (const file of htmlFiles) {
const html = readFileSync(file, 'utf8');
for (const [, , url] of html.matchAll(/\s(href|src)="(\/[^"]*)"/g)) {
if (!resolves(url)) {
console.error(`broken: ${url} (in ${file.slice(DIST.length + 1)})`);
broken++;
}
}
}
console.log(broken ? `${broken} broken internal link(s)` : `OK — ${htmlFiles.length} pages, all internal links resolve`);
process.exit(broken ? 1 : 0);
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Local dev: put the content repo's files where the build expects them.
# Usage: ./scripts/link-content.sh [path-to-content-clone] (default ../ctao-content)
# Copies (not symlinks) so the dev tree behaves exactly like the machine
# build overlay; re-run after pulling content changes.
set -euo pipefail
cd "$(dirname "$0")/.."
src="${1:-../ctao-content}"
for d in news pages uploads; do
[ -d "$src/$d" ] || { echo "content clone incomplete: $src/$d missing (git clone <gitea>/ctao/content.git first)"; exit 1; }
done
rm -rf src/content/news src/content/pages public/uploads
mkdir -p src/content public
cp -a "$src/news" src/content/news
cp -a "$src/pages" src/content/pages
cp -a "$src/uploads" public/uploads
echo "content linked from $src"