From 6a571de240b86fd2548ae9f91f90cbd1ccca4b6e Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 22 May 2026 21:57:15 -0400 Subject: [PATCH] Add production www layout for levkin.ca hosting. - build:www maps / to spec and /folders to stack-folder - Umami tracking via stats.levkin.ca - nginx deploy config for site LXC Co-authored-by: Cursor --- deploy/nginx-levkin.conf | 15 ++ package.json | 1 + scripts/prepare-www.mjs | 60 ++++++ spec/index.html | 2 +- stack-folder/index.html | 2 +- www/assets/auto-DdJGDEee.png | Bin 0 -> 92310 bytes www/assets/cal-dark-CG5J0IJe.png | Bin 0 -> 47993 bytes www/assets/cal-light-sOepgTJC.png | Bin 0 -> 52677 bytes www/assets/caseware-CaGYkxOF.png | Bin 0 -> 184511 bytes www/assets/git-repos-B2iogTL_.png | Bin 0 -> 90539 bytes www/assets/iliadobkin-B_2flTdO.png | Bin 0 -> 171333 bytes www/assets/modulepreload-polyfill-B5Qt9EMX.js | 1 + www/assets/spec-BY4A7Wkv.js | 1 + www/assets/spec-BoGenpAF.css | 1 + www/assets/spec-Cv7nGqro.png | Bin 0 -> 109704 bytes www/assets/stackFolder-4cxThntN.js | 1 + www/assets/stackFolder-oqVQaMMI.css | 1 + www/favicon.svg | 4 + www/folders/index.html | 175 ++++++++++++++++ www/folders/previews/auto.png | Bin 0 -> 92310 bytes www/folders/previews/cal-dark.png | Bin 0 -> 47993 bytes www/folders/previews/cal-light.png | Bin 0 -> 52677 bytes www/folders/previews/caseware.png | Bin 0 -> 184511 bytes www/folders/previews/git-repos.png | Bin 0 -> 90539 bytes www/folders/previews/iliadobkin.png | Bin 0 -> 171333 bytes www/folders/previews/spec.png | Bin 0 -> 109704 bytes www/index.html | 191 ++++++++++++++++++ 27 files changed, 453 insertions(+), 2 deletions(-) create mode 100644 deploy/nginx-levkin.conf create mode 100644 scripts/prepare-www.mjs create mode 100644 www/assets/auto-DdJGDEee.png create mode 100644 www/assets/cal-dark-CG5J0IJe.png create mode 100644 www/assets/cal-light-sOepgTJC.png create mode 100644 www/assets/caseware-CaGYkxOF.png create mode 100644 www/assets/git-repos-B2iogTL_.png create mode 100644 www/assets/iliadobkin-B_2flTdO.png create mode 100644 www/assets/modulepreload-polyfill-B5Qt9EMX.js create mode 100644 www/assets/spec-BY4A7Wkv.js create mode 100644 www/assets/spec-BoGenpAF.css create mode 100644 www/assets/spec-Cv7nGqro.png create mode 100644 www/assets/stackFolder-4cxThntN.js create mode 100644 www/assets/stackFolder-oqVQaMMI.css create mode 100644 www/favicon.svg create mode 100644 www/folders/index.html create mode 100644 www/folders/previews/auto.png create mode 100644 www/folders/previews/cal-dark.png create mode 100644 www/folders/previews/cal-light.png create mode 100644 www/folders/previews/caseware.png create mode 100644 www/folders/previews/git-repos.png create mode 100644 www/folders/previews/iliadobkin.png create mode 100644 www/folders/previews/spec.png create mode 100644 www/index.html diff --git a/deploy/nginx-levkin.conf b/deploy/nginx-levkin.conf new file mode 100644 index 0000000..cbb5994 --- /dev/null +++ b/deploy/nginx-levkin.conf @@ -0,0 +1,15 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + root /var/www/levkin/www; + index index.html; + + location /folders/ { + try_files $uri $uri/ /folders/index.html; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/package.json b/package.json index e385ed4..741d7fb 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "vite build", + "build:www": "node scripts/prepare-www.mjs", "preview": "vite preview", "capture-previews": "node scripts/capture-previews.mjs", "test:folder": "node scripts/test-stack-folder.mjs" diff --git a/scripts/prepare-www.mjs b/scripts/prepare-www.mjs new file mode 100644 index 0000000..8a2796b --- /dev/null +++ b/scripts/prepare-www.mjs @@ -0,0 +1,60 @@ +#!/usr/bin/env node +/** + * Build Vite output and lay out www/ for production nginx: + * / → spec + * /folders/ → stack-folder + */ +import { cp, mkdir, rm, readFile, writeFile } from 'fs/promises'; +import { execSync } from 'child_process'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const root = join(dirname(fileURLToPath(import.meta.url)), '..'); +const dist = join(root, 'dist'); +const www = join(root, 'www'); +const umamiId = process.env.UMAMI_WEBSITE_ID || '2a3bc7b2-b827-4770-8b31-c94016667734'; + +const umamiScript = ` \n`; + +function injectUmami(html) { + if (html.includes('stats.levkin.ca')) return html; + return html.replace('', `${umamiScript} `); +} + +function patchHtml(html, patches) { + let out = html; + for (const [from, to] of patches) { + out = out.split(from).join(to); + } + return injectUmami(out); +} + +execSync('npm run build', { cwd: root, stdio: 'inherit' }); + +await rm(www, { recursive: true, force: true }); +await mkdir(join(www, 'assets'), { recursive: true }); +await mkdir(join(www, 'folders'), { recursive: true }); + +await cp(join(dist, 'assets'), join(www, 'assets'), { recursive: true }); +await cp(join(root, 'public', 'favicon.svg'), join(www, 'favicon.svg')); + +const specHtml = await readFile(join(dist, 'spec', 'index.html'), 'utf8'); +await writeFile( + join(www, 'index.html'), + patchHtml(specHtml, [ + ['← all options', '← folders'], + ]), + 'utf8', +); + +const folderHtml = await readFile(join(dist, 'stack-folder', 'index.html'), 'utf8'); +await cp(join(root, 'stack-folder', 'previews'), join(www, 'folders', 'previews'), { recursive: true }); +await writeFile( + join(www, 'folders', 'index.html'), + patchHtml(folderHtml, [ + ['href="/spec/"', 'href="/"'], + ]), + 'utf8', +); + +console.log(`www/ ready (Umami id: ${umamiId})`); diff --git a/spec/index.html b/spec/index.html index fd12445..abe16eb 100644 --- a/spec/index.html +++ b/spec/index.html @@ -24,7 +24,7 @@