Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 22x 22x 22x 22x 22x 22x 22x 22x 22x | /**
* @module shared/theme-init
* @description Centralised loader for the inline anti-flash theme-init
* bootstrap. The bootstrap is kept in `js/theme-init.js` as the canonical
* source; all HTML generators (article template, news-indexes template,
* any future root-page generator) inline its minified body via this
* helper so every page ships identical bytes.
*
* The bootstrap must be inlined (not loaded via `<script src>`) to avoid
* a FOUC window while the external request resolves. Inlining is the
* only way to set `data-theme` synchronously before first paint.
*
* @author Hack23 AB
* @license Apache-2.0
*/
import { readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
/**
* Strip comments + compress whitespace to keep the inline payload small.
* Removes:
* - JSDoc `/** ... * /` blocks
* - Single-line `// ...` comments
* - `/* ... * /` inline block comments
* - Leading indentation and multiple blank lines
* The resulting IIFE remains functionally identical.
*/
function minifyBootstrap(src: string): string {
return src
// strip JSDoc / block comments
.replace(/\/\*[\s\S]*?\*\//g, '')
// strip line comments (but only those at line start to avoid breaking URL-like fragments)
.replace(/^\s*\/\/.*$/gm, '')
// collapse whitespace between tokens
.replace(/\s+/g, ' ')
// tighten around punctuation
.replace(/\s*([;{}(),=!<>+\-*/])\s*/g, '$1')
.trim();
}
function loadBootstrap(): string {
try {
// From scripts/shared/theme-init.ts → repo root is two parents up.
const path = join(__dirname, '..', '..', 'js', 'theme-init.js');
const raw = readFileSync(path, 'utf-8');
return minifyBootstrap(raw);
} catch {
// Defensive fallback: hand-written copy identical to js/theme-init.js.
// Kept in sync manually; `tests/theme-init.test.ts` asserts they match.
return "(function(){var key='riksdagsmonitor-theme';var t=null;try{t=localStorage.getItem(key);}catch(e){}if(t!=='dark'&&t!=='light'){if(t!==null){try{localStorage.removeItem(key);}catch(e){}}t=(window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light';}document.documentElement.setAttribute('data-theme',t);}());";
}
}
/**
* Minified, single-line IIFE sourced from `js/theme-init.js`.
* Safe to embed inside a `<script>…</script>` tag directly.
*/
export const THEME_INIT_INLINE: string = loadBootstrap();
/**
* Ready-to-inject `<script>` tag containing the inline theme bootstrap.
* Use in template literals, e.g.:
*
* ```ts
* html += THEME_INIT_SCRIPT_TAG;
* ```
*/
export const THEME_INIT_SCRIPT_TAG: string = `<script>${THEME_INIT_INLINE}</script>`;
|