3.4 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||
|---|---|---|---|---|---|---|---|---|
| guide | Theming | How the canonical themes are loaded, selected by administrators, and applied to the SPA via CSS custom properties. |
|
2026-07-22T13:40:00Z |
Theme catalog
HIPCTF ships canonical themes defined as JSON files in backend/themes/. The
catalog is identified by THEME_IDS in
backend/src/common/types/theme-ids.ts; the default is classic.
Each theme contains an id, display name, and token set containing colors,
font family, radii, and spacing values. The frontend maps the supported visual
tokens to CSS custom properties.
Administrator workflow
- Sign in as an administrator and open Admin area → General, or navigate
to
/admin/general. - Wait for the settings and available-theme requests to finish.
- Choose a value from Global theme (
data-testid="general-themeKey"). - Click Save (
data-testid="general-save"). - Verify that
Saved.appears and that the page uses the selected colors, font, and corner radii. Reloading the application should preserve the theme.
The selector lists themes exposed by GET /api/v1/admin/general/themes. Only
theme JSON files present in the configured THEMES_DIR are listed, while the
loader still maintains canonical fallback themes for bootstrap and runtime
safety.
Backend loading
ThemeLoaderService (backend/src/common/utils/theme-loader.service.ts)
runs on module initialization:
- Reads theme JSON files from
THEMES_DIR(default./themes). - Validates IDs and tokens; malformed files are skipped or reported through the loader's validation path.
- Backfills missing canonical themes so the application always has a valid catalog.
- Validates the configured
SETTINGS_KEYS.THEME_KEY; an unknown value falls back toclassicand is persisted as the repaired setting.
The selected theme is sent to the SPA in GET /api/v1/bootstrap (see
System Endpoints). Administrators can read and update the
selection through Admin Endpoints. A successful general-settings
update emits a general SSE event containing the new themeKey.
Frontend application
BootstrapService (frontend/src/app/core/services/bootstrap.service.ts)
fetches /api/v1/bootstrap once per application lifecycle, stores the payload
in signals, and applies the returned theme before the UI is rendered. The
applyThemeToCss helper in
frontend/src/app/core/services/bootstrap.types.ts writes these tokens to
document.documentElement:
| Theme token | CSS custom property |
|---|---|
primary, secondary, accent, surface, text |
--color-* |
success, warning, danger |
--color-* |
fontFamily |
--font-family |
radii.sm, radii.md, radii.lg |
--radius-sm, --radius-md, --radius-lg |
Reapplying a theme replaces the existing values. clearThemeCss removes every
property managed by the helper. Components consume the properties through
var(--token) in the global stylesheet and component styles.
Verification
The frontend theme tests in tests/frontend/bootstrap-theme.spec.ts verify
that all tokens are written, missing tokens are a no-op, reapplication replaces
values, zero-valued radii are preserved, and cleanup removes every managed
property.