diff --git a/.gitignore b/.gitignore index a46f740..055e128 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ ui/dist/ ui/.angular/ src/shared/version.gen.ts release/ + +# headless screenshot workspace (scripts/shot.ts) +.shot/ diff --git a/scripts/shot.ts b/scripts/shot.ts new file mode 100644 index 0000000..07247d1 --- /dev/null +++ b/scripts/shot.ts @@ -0,0 +1,106 @@ +// Headless screenshot of the skin harness, so the Win7 look can be reviewed +// visually during development rather than inferred from a clean build log. +// +// bun scripts/shot.ts [--dark] [--width 1200] [--height 1400] [--out path.png] +// bun scripts/shot.ts --url http://localhost:4200 (any page, not just the harness) +// +// Firefox is used because it ships on this machine and has a built-in +// --screenshot mode; no Chromium/puppeteer download is needed. Two constraints +// it imposes: +// - a DEDICATED PROFILE is mandatory. A running Firefox holds a lock on the +// default profile and the headless run aborts with "Firefox is already +// running, but is not responding". +// - it renders with Gecko, NOT the WebKitGTK engine the app actually uses. +// Good enough for skin fidelity (layout, colour, gradients, borders); +// useless for engine-specific behaviour or native window transparency. +// Real confirmation is still `bun run start`. +// +// The harness links the REAL hashed stylesheet from ui/dist (produced by the +// normal `bun run build:ui`), so there is no second build pipeline to keep in +// sync. +// +// The composed page is written INTO that same dist folder, and this is not +// incidental: Firefox's security.fileuri.strict_origin_policy stops a file:// +// document from loading a stylesheet that lives in a different directory. Host +// the page elsewhere and it renders completely unstyled — which looks exactly +// like "the skin is broken" rather than "the CSS never loaded". Keeping them +// co-located also lets media/ fonts resolve. +import { existsSync, mkdirSync, readdirSync, rmSync } from "node:fs"; +import path from "node:path"; + +const ROOT = path.join(import.meta.dir, ".."); +const DIST = path.join(ROOT, "ui", "dist", "ui", "browser"); +const HARNESS = path.join(ROOT, "ui", "dev", "harness.html"); +const WORK = path.join(ROOT, ".shot"); + +function arg(name: string): string | undefined { + const i = process.argv.indexOf(`--${name}`); + return i >= 0 ? process.argv[i + 1] : undefined; +} +const flag = (name: string) => process.argv.includes(`--${name}`); + +function fail(message: string): never { + console.error(`[shot] ERROR: ${message}`); + process.exit(1); +} + +// ---- resolve the built stylesheet ---- + +if (!existsSync(DIST)) fail(`no build output at ${DIST} — run: bun run build:ui`); +const styles = readdirSync(DIST).find((f) => f.startsWith("styles-") && f.endsWith(".css")); +if (!styles) fail(`no styles-*.css in ${DIST} — run: bun run build:ui`); + +// ---- compose the page ---- + +mkdirSync(WORK, { recursive: true }); +const profile = path.join(WORK, "profile"); +mkdirSync(profile, { recursive: true }); + +const url = arg("url"); +let target: string; + +if (url) { + target = url; +} else { + const dark = flag("dark"); + let html = await Bun.file(HARNESS).text(); + // replaceAll, not replace: the harness documents its own {{STYLES}} token in + // a header comment that precedes the , so a first-match replace + // substitutes the comment and silently leaves the stylesheet unlinked. + html = html.replaceAll("{{STYLES}}", styles); // relative: page sits next to it + // The preload bakes these attributes in the real app; do it by hand here. + if (dark) html = html.replace(' + + + + + 7.css harness + + + + +

1 — Window frame, glass, drop shadow, active colour

+
+
+
reference — .window.glass.active
+
+
+
+
miniSCP
+
+ + + +
+
+

Glass frame, 6px radius, drop shadow.

+
+
+
+
+
ours — bare .title-bar, no wrapper
+
+
+
+
miniSCP
+
+ + + +
+
+
+

No frame, no shadow, no glass.

+
+
+
+
+
+ +

2 — ListView (file panel)

+
+
+
reference — <table>
+ + + + + + + + + + + + + + +
NameSizeModified
..——
Documents—3/29/2007 12:00 AM
report.pdf27 KB3/23/2007 12:00 AM
notes.txt4 KB3/13/2007 12:00 AM
+
+
+
ours — div grid (7.css never applies)
+
+
+
Name
+
Size
+
Modified
+
+
..
—
—
+
Documents
—
3/29/2007
+
report.pdf
27 KB
3/23/2007
+
+
+
+ +

3 — Context menu

+
+
+
reference — ul[role=menu]
+ +
+
+
ours — div > button + hand-written CSS
+
+ + +
+ + +
+
+
+ +

4 — Controls 7.css already owns (sanity check)

+
+
+
buttons / textbox / progress
+
+
+ +
+
+
+
+
+
tabs — menu[role=tablist]
+ + + + + +
Tab body
+
+
+ +