From 750b761098ca5986c15368b631a34f1a8d411943 Mon Sep 17 00:00:00 2001 From: LennarX Date: Fri, 17 Jul 2026 22:27:04 +0200 Subject: [PATCH 1/5] feat: render the tool repo's LICENSE as a dynamic site page Fetch LICENSE from the flashtrace clone at build time (next to the docs/ input), render it verbatim in a
 at /license/, and point
the footer link there instead of github.com. Fails the build loudly
if the file is missing, same as the docs.

Co-Authored-By: Claude Fable 5 
---
 build.mjs       | 22 ++++++++++++++++++++--
 src/layout.mjs  |  2 +-
 src/license.mjs | 21 +++++++++++++++++++++
 3 files changed, 42 insertions(+), 3 deletions(-)
 create mode 100644 src/license.mjs

diff --git a/build.mjs b/build.mjs
index af8e426..5fed98a 100644
--- a/build.mjs
+++ b/build.mjs
@@ -10,6 +10,7 @@ import { Marked } from 'marked';
 import { docShell, esc, GITHUB_URL, highlightTokens, SITE_URL } from './src/layout.mjs';
 import { renderLanding } from './src/landing.mjs';
 import { renderImpressum } from './src/impressum.mjs';
+import { renderLicense } from './src/license.mjs';
 
 const root = path.dirname(fileURLToPath(import.meta.url));
 const dist = path.join(root, 'dist');
@@ -32,6 +33,15 @@ function locateDocs() {
 
 const docsDir = locateDocs();
 
+// --- license: raw text from the tool repo root, next to docs/ ---------------
+
+const licensePath = path.join(docsDir, '..', 'LICENSE');
+if (!existsSync(licensePath)) {
+  console.error(`error: LICENSE not found at ${licensePath}`);
+  process.exit(1);
+}
+const licenseText = readFileSync(licensePath, 'utf8');
+
 // --- version: release tag from env, else the tool repo's package.json ------
 
 function readVersion() {
@@ -174,13 +184,21 @@ writeFileSync(path.join(dist, 'index.html'), renderLanding({ version, gitRef }))
 mkdirSync(path.join(dist, 'impressum'), { recursive: true });
 writeFileSync(path.join(dist, 'impressum', 'index.html'), renderImpressum({ version }));
 
+mkdirSync(path.join(dist, 'license'), { recursive: true });
+writeFileSync(path.join(dist, 'license', 'index.html'), renderLicense({ version, text: licenseText }));
+
 for (const page of pages) {
   const dir = page.slug ? path.join(dist, 'docs', page.slug) : path.join(dist, 'docs');
   mkdirSync(dir, { recursive: true });
   writeFileSync(path.join(dir, 'index.html'), renderDoc(page));
 }
 
-const sitePaths = ['/', ...pages.map((p) => (p.slug ? `/docs/${p.slug}/` : '/docs/')), '/impressum/'];
+const sitePaths = [
+  '/',
+  ...pages.map((p) => (p.slug ? `/docs/${p.slug}/` : '/docs/')),
+  '/license/',
+  '/impressum/',
+];
 writeFileSync(
   path.join(dist, 'sitemap.xml'),
   `
@@ -194,4 +212,4 @@ cpSync(path.join(root, 'public'), dist, { recursive: true });
 cpSync(path.join(root, 'src', 'styles', 'site.css'), path.join(dist, 'site.css'));
 cpSync(path.join(root, 'src', 'scripts', 'site.js'), path.join(dist, 'site.js'));
 
-console.log(`built ${pages.length + 2} pages into dist/ (flashtrace ${version || 'unknown version'})`);
+console.log(`built ${pages.length + 3} pages into dist/ (flashtrace ${version || 'unknown version'})`);
diff --git a/src/layout.mjs b/src/layout.mjs
index b97e930..b4937ce 100644
--- a/src/layout.mjs
+++ b/src/layout.mjs
@@ -75,7 +75,7 @@ function footer({ version }) {
       Docs
       GitHub
       Discussions
-      License
+      License
       Legal Notice
     
     
diff --git a/src/license.mjs b/src/license.mjs
new file mode 100644
index 0000000..87b3791
--- /dev/null
+++ b/src/license.mjs
@@ -0,0 +1,21 @@
+// License page - renders the tool repo's LICENSE (plain text, pre-formatted
+// with spaces for centering) verbatim inside the site shell.
+import { esc, pageShell } from './layout.mjs';
+
+export function renderLicense({ version, text }) {
+  const body = `
+ +
`; + return pageShell({ + title: 'License ยท flashtrace', + description: 'The Apache License, Version 2.0 that flashtrace is distributed under.', + path: '/license/', + version, + active: '', + body, + bodyClass: 'page-legal', + }); +} From b1e1e87a8b80827cdb30c267c018d5850a8cb54e Mon Sep 17 00:00:00 2001 From: LennarX Date: Fri, 17 Jul 2026 22:49:47 +0200 Subject: [PATCH 2/5] feat: center and shrink-wrap the license text block The 46rem doc column hugged the left of the 80rem section and the
 stretched wider than its 77-column text, so the license looked
off-center. Center the legal content column, widen the license page
to 52rem, center its heading, and shrink-wrap the 
 to its text
so the raw file's space-centered header reads as intended.

Co-Authored-By: Claude Fable 5 
---
 src/license.mjs     |  2 +-
 src/styles/site.css | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/license.mjs b/src/license.mjs
index 87b3791..e71323a 100644
--- a/src/license.mjs
+++ b/src/license.mjs
@@ -4,7 +4,7 @@ import { esc, pageShell } from './layout.mjs';
 
 export function renderLicense({ version, text }) {
   const body = `
-