Manually merge from 'pre-kjol' into 'master'

This commit is contained in:
2026-07-15 15:11:29 -04:00
parent f2e0d22255
commit 342de9e18a
9 changed files with 365 additions and 188 deletions

View File

@@ -18,6 +18,25 @@ interface IconProps {
style?: Partial<CSSStyleProperties>;
}
// Vite-style HMR API the dev bundler injects into every module (see
// internal/bundler/hmr_server.go + docs/hmr.md); undefined in production.
// `declare global` is required here — a bare `interface ImportMeta` in a
// module file wouldn't merge with the ambient one `import.meta`'s type
// actually resolves against.
declare global {
interface ImportMeta {
hot?: {
readonly data: Record<string, any>;
accept(cb?: (mod: any) => void): void;
accept(deps: string | string[], cb?: (mod: any) => void): void;
dispose(cb: (data: Record<string, any>) => void): void;
prune(cb: (data: Record<string, any>) => void): void;
invalidate(): void;
decline(): void;
};
}
}
// The FontAwesome family + default weight are theme-driven so this component
// stays identical across projects. Each project's CSS theme sets `--fa-style`
// (classic → far/fas, sharp → fasr/fass) and `--fa-default-solid` (0/1). Read
@@ -49,7 +68,19 @@ const ICON_INLINE = "inline-block align-middle";
// lookup for the same name. This shared component ships with it EMPTY: each
// project registers its own SVGs from its app entry (see frontend/src/appIcons.ts)
// via registerIcon, so Icons.tsx stays identical across projects.
const customIcons: Record<string, CustomIconDef> = {};
// Persisted across this module's own HMR reloads (see docs/hmr.md). Icons.tsx
// is an HMR boundary, and its FA icon subset import churns on every SPA source
// edit (generateFAIcons regenerates it each time), so this module reloads far
// more often than one would expect from editing Icons.tsx itself. A fresh
// module instance would otherwise start with an empty registry, since
// registerIcon() only runs once — from appIcons.ts's side-effect import at
// initial page load — blanking custom icons (playground, e-cd, ...) until a
// full page refresh. import.meta.hot.data survives across reloads of this
// module, so stash the registry there instead of a plain module-scoped const.
const customIcons: Record<string, CustomIconDef> =
(import.meta.hot?.data.customIcons as Record<string, CustomIconDef> | undefined) ?? {};
if (import.meta.hot) import.meta.hot.data.customIcons = customIcons;
// Register a custom icon under `name`, overriding FontAwesome for that name.
// Call from the app's own icon module (e.g. appIcons.ts), imported for side