@kolkrabbi/kol-framework 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/index.js +2 -0
- package/src/loaderApp.js +14 -0
- package/src/vite.js +71 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Site shell and page layout",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"module": "./src/index.js",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./src/index.js",
|
|
11
|
+
"./vite": "./src/vite.js",
|
|
11
12
|
"./src/*": "./src/*",
|
|
12
13
|
"./kol-framework.css": "./kol-framework.css",
|
|
13
14
|
"./kol-brand-color.css": "./kol-brand-color.css"
|
|
@@ -21,8 +22,8 @@
|
|
|
21
22
|
"react-router-dom": "^6.0.0 || ^7.0.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
|
-
"@kolkrabbi/kol-component": "^0.
|
|
25
|
-
"@kolkrabbi/kol-icons": "^0.
|
|
25
|
+
"@kolkrabbi/kol-component": "^0.266.0",
|
|
26
|
+
"@kolkrabbi/kol-icons": "^0.39.0"
|
|
26
27
|
},
|
|
27
28
|
"files": [
|
|
28
29
|
"src",
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,8 @@ export { useDragResize } from '@kolkrabbi/kol-component'
|
|
|
17
17
|
export { default as ShellHeader, HEADER_ICON } from './ShellHeader.jsx'
|
|
18
18
|
export { default as ThemeToggle } from './ThemeToggle.jsx'
|
|
19
19
|
export { useTheme, applyTheme, getInitialTheme, THEME_STORAGE_KEY, THEME_BOOT_SCRIPT } from './theme.js'
|
|
20
|
+
/* the app loader's runtime half — the build half is `loaderApp()` in `@kolkrabbi/kol-framework/vite` */
|
|
21
|
+
export { hideLoaderApp } from './loaderApp.js'
|
|
20
22
|
export { default as Layout } from './Layout.jsx'
|
|
21
23
|
export { default as PageSection } from './PageSection.jsx'
|
|
22
24
|
export { default as PortalFooter } from './PortalFooter.jsx'
|
package/src/loaderApp.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hideLoaderApp — the app loader's other half (`loaderApp()` in `@kolkrabbi/kol-framework/vite` writes it into
|
|
3
|
+
* index.html). Call it once React has committed: two frames later the loader fades (240 ms, none under reduced
|
|
4
|
+
* motion — the CSS drops the transition) and leaves the DOM. Safe to call when there is no loader.
|
|
5
|
+
*/
|
|
6
|
+
export function hideLoaderApp() {
|
|
7
|
+
if (typeof document === 'undefined') return
|
|
8
|
+
const el = document.getElementById('kol-loader-app')
|
|
9
|
+
if (!el) return
|
|
10
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
11
|
+
el.classList.add('is-done')
|
|
12
|
+
setTimeout(() => { el.remove(); document.getElementById('kol-loader-app-css')?.remove() }, 300)
|
|
13
|
+
}))
|
|
14
|
+
}
|
package/src/vite.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugins for KOL apps — Node-side, no React (import from `@kolkrabbi/kol-framework/vite` in vite.config).
|
|
3
|
+
*
|
|
4
|
+
* devFavicon — THE DEV TAB IS TELLABLE AT A GLANCE (2026-10-17 — user: "I need to be able to tell which tabs
|
|
5
|
+
* are localhost dev and which are production"). On the dev server the favicon becomes a solid tile with the
|
|
6
|
+
* app's letters; a build never sees it (`apply: 'serve'`). It REPLACES the page's icon link: fxr appended a
|
|
7
|
+
* second one and browsers pick their own (Firefox kept prod's), mirror swapped it at runtime after load.
|
|
8
|
+
* Each app picks its letters and ground once — the table lives in 16-app-anatomy.md § Dev favicon.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} [opts]
|
|
11
|
+
* @param {string} [opts.label='DEV'] 1–3 letters, fitted to the tile
|
|
12
|
+
* @param {string} [opts.ground='#7C5CFF'] the tile's colour — unique per app
|
|
13
|
+
* @param {string} [opts.ink='#FFFFFF']
|
|
14
|
+
*/
|
|
15
|
+
export function devFavicon({ label = 'DEV', ground = '#7C5CFF', ink = '#FFFFFF' } = {}) {
|
|
16
|
+
const text = String(label).slice(0, 3).toUpperCase()
|
|
17
|
+
const size = text.length === 1 ? 28 : text.length === 2 ? 20 : 15
|
|
18
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="6" fill="${ground}"/>`
|
|
19
|
+
+ `<text x="16" y="${(16 + size * 0.36).toFixed(1)}" text-anchor="middle" font-family="Arial Black, Arial, sans-serif" font-weight="900" font-size="${size}"`
|
|
20
|
+
+ `${text.length > 1 ? ' textLength="28" lengthAdjust="spacingAndGlyphs"' : ''} fill="${ink}">${text}</text></svg>`
|
|
21
|
+
const link = `<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,${encodeURIComponent(svg)}">`
|
|
22
|
+
return {
|
|
23
|
+
name: 'kol-dev-favicon',
|
|
24
|
+
apply: 'serve',
|
|
25
|
+
transformIndexHtml(html) {
|
|
26
|
+
return /<link rel="icon"[^>]*>/.test(html) ? html.replace(/<link rel="icon"[^>]*>/, link) : html.replace('</head>', `${link}</head>`)
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* loaderApp — THE APP LOADER, OWNED ONCE (AppLoader, kol-monitor 2026-10-17 — user: *"shouldnt that loader just be
|
|
33
|
+
* owned in DS and consumed by the fxr monitor and mirror? with custom graphic input as prop?"*). The app's mark
|
|
34
|
+
* centred on the theme's ground, pulsing while the bundle downloads. It has to be static HTML in `index.html` —
|
|
35
|
+
* a React component would only appear after the wait it covers — so this plugin writes it there: fxr's loader,
|
|
36
|
+
* once, with the graphic as an option. Call `hideLoaderApp()` (kol-framework) after the first commit.
|
|
37
|
+
*
|
|
38
|
+
* Ground and ink follow the stored `data-theme`, else the system (run `THEME_BOOT_SCRIPT` before it, as every
|
|
39
|
+
* KOL app does). Reduced motion: no pulse, no fade.
|
|
40
|
+
*
|
|
41
|
+
* @param {Object} opts
|
|
42
|
+
* @param {string} opts.graphic an SVG — the markup itself, or a path (relative to the app root) to an .svg file;
|
|
43
|
+
* draw it in `currentColor` so it takes the ground's ink
|
|
44
|
+
* @param {number} [opts.size=64] the mark's edge in px
|
|
45
|
+
*/
|
|
46
|
+
export function loaderApp({ graphic, size = 64 } = {}) {
|
|
47
|
+
let root = process.cwd()
|
|
48
|
+
const css = `#kol-loader-app{position:fixed;inset:0;z-index:2147483647;display:grid;place-items:center;background:#FAFAFA;color:#0E0E11;transition:opacity 240ms ease}`
|
|
49
|
+
+ `@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) #kol-loader-app{background:#121215;color:#FFFFFF}}`
|
|
50
|
+
+ `:root[data-theme="dark"] #kol-loader-app{background:#121215;color:#FFFFFF}`
|
|
51
|
+
+ `#kol-loader-app svg{width:${size}px;height:${size}px;animation:kol-loader-app-pulse 1.6s ease-in-out infinite}`
|
|
52
|
+
+ `#kol-loader-app.is-done{opacity:0;pointer-events:none}`
|
|
53
|
+
+ `@keyframes kol-loader-app-pulse{50%{opacity:.35}}`
|
|
54
|
+
+ `@media (prefers-reduced-motion: reduce){#kol-loader-app svg{animation:none}#kol-loader-app{transition:none}}`
|
|
55
|
+
return {
|
|
56
|
+
name: 'kol-loader-app',
|
|
57
|
+
configResolved(config) { root = config.root },
|
|
58
|
+
async transformIndexHtml(html) {
|
|
59
|
+
let svg = String(graphic ?? '').trim()
|
|
60
|
+
if (svg && !svg.startsWith('<')) {
|
|
61
|
+
const { readFile } = await import('node:fs/promises')
|
|
62
|
+
const { resolve } = await import('node:path')
|
|
63
|
+
svg = (await readFile(resolve(root, svg), 'utf8')).trim()
|
|
64
|
+
}
|
|
65
|
+
svg = svg.replace(/<\?xml[^>]*>/, '').replace(/<!--[\s\S]*?-->/g, '')
|
|
66
|
+
return html
|
|
67
|
+
.replace('</head>', `<style id="kol-loader-app-css">${css}</style></head>`)
|
|
68
|
+
.replace(/<body([^>]*)>/, `<body$1><div id="kol-loader-app" aria-hidden="true">${svg}</div>`)
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
}
|