From 0f53984407008731ee78d44b7009815ef0d4ce1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20T=C3=B6rcsv=C3=A1ri?= Date: Sat, 20 Jun 2026 08:01:50 +0200 Subject: [PATCH] feat(standalone): bottom-right version + source badge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A small fixed bottom-right overlay (VersionBadge) shown app-wide — on the home page AND inside the loaded editor — surfacing this build's release tag and a link to the source. The tag links to the exact commit when known (the pcbjam commit pins the kicad + wxwidgets submodule revisions → our GPLv3 corresponding-source pointer, mirroring site Footer's BUILD_SHA), else the tag's release page, else the repo root. build-demo.mjs injects VITE_APP_TAG / VITE_GIT_SHA / VITE_REPO_URL (new --repo flag, defaults to github.com/emergence-engineering/pcbjam). Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/deploy/build-demo.mjs | 27 +++++++++- web/standalone/src/App.tsx | 17 ++++--- .../src/components/VersionBadge.tsx | 49 +++++++++++++++++++ web/standalone/src/lib/config.ts | 20 ++++++++ web/standalone/src/vite-env.d.ts | 6 +++ 5 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 web/standalone/src/components/VersionBadge.tsx diff --git a/scripts/deploy/build-demo.mjs b/scripts/deploy/build-demo.mjs index d3ae1f7..be4830f 100644 --- a/scripts/deploy/build-demo.mjs +++ b/scripts/deploy/build-demo.mjs @@ -22,20 +22,39 @@ import { import { join, resolve } from "node:path"; function parseArgs(argv) { - const a = { tag: null, cdn: "https://cdn.pcbjam.com" }; + const a = { + tag: null, + cdn: "https://cdn.pcbjam.com", + repo: "https://github.com/emergence-engineering/pcbjam", + }; for (let i = 2; i < argv.length; i++) { const next = () => argv[++i]; switch (argv[i]) { case "--tag": a.tag = next(); break; case "--cdn": a.cdn = next(); break; + case "--repo": a.repo = next(); break; default: throw new Error(`unknown arg: ${argv[i]}`); } } if (!a.tag) throw new Error("--tag is required"); a.cdn = a.cdn.replace(/\/+$/, ""); + a.repo = a.repo.replace(/\/+$/, ""); return a; } +// Best-effort source commit for the version badge's corresponding-source link; +// empty string if git isn't available (CI shallow checkout etc.) — the badge +// then falls back to the tag's release page. +function gitSha(cwd) { + try { + return execFileSync("git", ["rev-parse", "HEAD"], { cwd }) + .toString() + .trim(); + } catch { + return ""; + } +} + function main() { const a = parseArgs(process.argv); const repoRoot = resolve(process.cwd()); @@ -55,12 +74,18 @@ function main() { // Built-in offline symbols (no backend); cross-tab collab only. VITE_LIBS_SOURCE: "static", VITE_YJS_PROVIDER: "broadcastchannel", + // Build identity for the version badge. The commit is the GPLv3 + // corresponding-source pointer (pins the kicad + wxwidgets submodules). + VITE_APP_TAG: a.tag, + VITE_GIT_SHA: gitSha(repoRoot), + VITE_REPO_URL: a.repo, }; console.log(`build-demo: tag=${a.tag} cdn=${a.cdn}`); console.log(` VITE_WASM_ROOT=${env.VITE_WASM_ROOT}`); console.log(` VITE_WASM_MANIFEST=${env.VITE_WASM_MANIFEST}`); console.log(` VITE_PROJECT_MANIFEST_URL=${env.VITE_PROJECT_MANIFEST_URL}`); + console.log(` VITE_APP_TAG=${env.VITE_APP_TAG} VITE_GIT_SHA=${env.VITE_GIT_SHA || "(none)"}`); // Keep the dev-only WASM symlink out of the bundle (it'd copy 100s of MB into // dist/; the CDN serves it). In CI it isn't present, so this is a no-op there. diff --git a/web/standalone/src/App.tsx b/web/standalone/src/App.tsx index ed1b7f3..2708238 100644 --- a/web/standalone/src/App.tsx +++ b/web/standalone/src/App.tsx @@ -1,4 +1,5 @@ import { Route, Routes } from "react-router-dom"; +import { VersionBadge } from "@/components/VersionBadge"; import { HomePage } from "@/pages/HomePage"; import { LibToolPage } from "@/pages/LibToolPage"; import { ProjectView } from "@/pages/ProjectView"; @@ -6,11 +7,15 @@ import { ToolPage } from "@/pages/ToolPage"; export default function App() { return ( - - } /> - } /> - } /> - } /> - + <> + + } /> + } /> + } /> + } /> + + {/* Version + source link, bottom-right on every route (home + editor). */} + + ); } diff --git a/web/standalone/src/components/VersionBadge.tsx b/web/standalone/src/components/VersionBadge.tsx new file mode 100644 index 0000000..98a4d63 --- /dev/null +++ b/web/standalone/src/components/VersionBadge.tsx @@ -0,0 +1,49 @@ +import { Github } from "lucide-react"; +import { APP_GIT_SHA, APP_TAG, REPO_URL } from "@/lib/config"; + +/** + * Small bottom-right overlay showing this build's version + a link to the + * source. The standalone is GPLv3, so the tag links to the exact commit + * (corresponding-source pointer — the repo commit pins the kicad + wxwidgets + * submodule revisions) when known, else the tag's release page, else the repo + * root. Mounted app-wide (App.tsx) so it shows on the home page AND inside the + * loaded editor. `fixed` keeps it viewport-anchored on every route; z-20 sits + * under the editor's boot overlay (z-30) so it's hidden until the tool is up. + */ +export function VersionBadge() { + const tag = APP_TAG ?? "dev"; + const versionUrl = APP_GIT_SHA + ? `${REPO_URL}/commit/${APP_GIT_SHA}` + : APP_TAG + ? `${REPO_URL}/releases/tag/${APP_TAG}` + : REPO_URL; + const versionTitle = APP_GIT_SHA + ? `commit ${APP_GIT_SHA.slice(0, 12)} — GPL corresponding source` + : APP_TAG + ? `release ${APP_TAG}` + : "source repository"; + + return ( +
+ + pcbjam {tag} + + · + + source + +
+ ); +} diff --git a/web/standalone/src/lib/config.ts b/web/standalone/src/lib/config.ts index 6412189..83f5003 100644 --- a/web/standalone/src/lib/config.ts +++ b/web/standalone/src/lib/config.ts @@ -24,6 +24,26 @@ export const WASM_MANIFEST_FILE = import.meta.env.VITE_WASM_MANIFEST || null; /** @deprecated Use WASM_ROOT + resolveWasmBase(). Kept for back-compat. */ export const WASM_ASSET_BASE_URL = WASM_ROOT; +// --- build identity (version badge + GPLv3 corresponding-source pointer) ------- +// The standalone is GPLv3; the badge surfaces the build's tag + a link to the +// exact source. The repo commit pins the kicad + wxwidgets submodule revisions, +// so APP_GIT_SHA → github.com/.../commit/ is our corresponding-source +// pointer (mirrors site/src/components/Footer.astro's BUILD_SHA). All three are +// injected at build time by scripts/deploy/build-demo.mjs; unset in a plain dev +// checkout (badge then shows "dev" → repo root). + +/** Release tag for this build (e.g. "2.7.7"); shown in the version badge. */ +export const APP_TAG = import.meta.env.VITE_APP_TAG || null; + +/** Source commit this build was made from; the badge links to it as the GPLv3 + * corresponding-source pointer. */ +export const APP_GIT_SHA = import.meta.env.VITE_GIT_SHA || null; + +/** Public source repository for the GPL editor (no trailing slash). */ +export const REPO_URL = ( + import.meta.env.VITE_REPO_URL || "https://github.com/emergence-engineering/pcbjam" +).replace(/\/+$/, ""); + /** * Where the standalone reads PROJECTS from (env VITE_PROJECT_SOURCE): * "remote" (default) — the @pcbjam/shared REST backend at API_BASE_URL. diff --git a/web/standalone/src/vite-env.d.ts b/web/standalone/src/vite-env.d.ts index d10c44d..d5c29e0 100644 --- a/web/standalone/src/vite-env.d.ts +++ b/web/standalone/src/vite-env.d.ts @@ -6,6 +6,12 @@ interface ImportMetaEnv { readonly VITE_WASM_ROOT?: string; /** Per-release WASM manifest file under VITE_WASM_ROOT (e.g. "manifest-2.7.7.json"); enables versioned per-tool folders. */ readonly VITE_WASM_MANIFEST?: string; + /** Release tag for this build (e.g. "2.7.7"); shown in the version badge. */ + readonly VITE_APP_TAG?: string; + /** Source commit this build was made from; the badge links to it as the GPLv3 corresponding-source pointer. */ + readonly VITE_GIT_SHA?: string; + /** Public source repo URL for the GPL editor (default github.com/emergence-engineering/pcbjam). */ + readonly VITE_REPO_URL?: string; /** @deprecated legacy alias for VITE_WASM_ROOT. */ readonly VITE_WASM_ASSET_BASE_URL?: string; /** Project source: "remote" (default, REST backend) | "static" (read-only CDN gallery, no backend). */