Fork FancyScribe as BrevyScribe with the datasheet transforms built in
CI / check (push) Has been cancelled

Print generic datasheets - every option a unit could take, the way the
official cards read - instead of a record of one particular list.

The three Python scripts that used to rewrite the .ros file before upload
are now transforms in src/transforms/, running in the browser between
DOMParser and the roster parser. Most of each script was machinery for
preserving the file byte for byte on the way back to disk; in the browser
the document is never serialised, so only the domain logic came across.

Because they run on the parsed document rather than the uploaded file,
flipping a transform off rebuilds from the original XML with no
re-upload. Saved rosters therefore hold the raw roster XML rather than
the parsed object, under new localStorage keys.

The scripts' output over four 11th-edition rosters is checked in as test
fixtures, so the port is measured against an independent implementation
that was verified by printing the cards; scripts/update-fixtures.mjs
refuses to overwrite those without --force.

Two parser call sites now use :scope> rather than repeating the scope
element's own name, which means the same thing in a browser and also
works under jsdom, where the old form matched nothing.

Also: served at the root rather than a GitHub Pages subpath, PostHog
analytics removed, and deploy/ carries an nginx site for
scribe.luxick.de plus an rsync deploy script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 15:11:10 +02:00
parent 3a0fdc2c26
commit 62d6bd211b
45 changed files with 3317 additions and 191 deletions
+62
View File
@@ -0,0 +1,62 @@
# BrevyScribe is a static site: the build produces plain files and the app does
# all its work in the browser, so nginx serves it directly - there is no
# application server, no socket and nothing to proxy to.
#
# Install as /etc/nginx/sites-available/scribe.luxick.de, symlink it into
# sites-enabled, then `nginx -t && systemctl reload nginx`.
server {
listen 80;
listen [::]:80;
server_name scribe.luxick.de;
# Let certbot answer the challenge, send everything else to HTTPS.
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name scribe.luxick.de;
ssl_certificate /etc/letsencrypt/live/scribe.luxick.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/scribe.luxick.de/privkey.pem;
root /var/www/brevyscribe;
index index.html;
gzip on;
gzip_types text/css application/javascript image/svg+xml application/xml;
gzip_min_length 1024;
# Vite gives these content-hashed filenames, so they can never go stale.
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# The example rosters and the fonts keep their names across builds, so they
# get a short cache rather than an immutable one.
location ~* \.(rosz|woff2)$ {
expires 1h;
add_header Cache-Control "public";
}
# index.html names the hashed assets, so it must never be cached: a stale copy
# would point at a bundle that no longer exists.
location = /index.html {
add_header Cache-Control "no-cache";
}
# A single page app with no router, but serving index.html for an unknown path
# is friendlier than a bare 404.
location / {
try_files $uri $uri/ /index.html;
}
}