add system font stack to admin reset CSS so setup/admin pages render sans-serif on all devices instead of falling through to browser default. pass path_resolver to CSSGenerator.generate on cache miss paths so font URLs resolve to digested paths in production. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71 lines
4.0 KiB
Markdown
71 lines
4.0 KiB
Markdown
# Admin font loading
|
|
|
|
Status: Complete (Option A + cache miss fix)
|
|
|
|
## Problem
|
|
|
|
Custom fonts don't load on admin or setup pages. The setup page at `/setup` renders in the browser's default serif font on production.
|
|
|
|
### Root cause
|
|
|
|
The admin CSS (`admin.css`) has **no `@font-face` declarations** and **no `font-family` on body/root**. Font family CSS variables are defined in `theme-primitives.css` (e.g. `--p-font-inter: 'Inter', system-ui, sans-serif`) but the actual woff2 font files are only loaded via `@font-face` rules generated at runtime by `CSSGenerator` for shop pages (injected into `<style>` tags via `ThemeHook` / `LoadTheme` plug).
|
|
|
|
Admin and setup pages use the `root.html.heex` layout which loads `admin.css` only — no generated theme CSS, no `@font-face` declarations.
|
|
|
|
### Why it works locally
|
|
|
|
If you have Inter or other theme fonts installed on your system, the browser resolves the font-family names without needing `@font-face`. On production or other machines without the fonts installed, it falls through to browser defaults (usually serif).
|
|
|
|
### Secondary bug: cache miss path
|
|
|
|
Three places regenerate CSS on ETS cache miss **without** the `path_resolver` for digested font URLs. This means if the cache is cold (after invalidation, restart race, etc.), the cached CSS contains bare paths like `/fonts/inter-v20-latin-regular.woff2` which 404 in production (only digested paths are served).
|
|
|
|
Affected files:
|
|
- `lib/berrypod_web/plugs/load_theme.ex:30` — `CSSGenerator.generate(settings)` (no resolver)
|
|
- `lib/berrypod_web/theme_hook.ex:29` — same
|
|
- `lib/berrypod_web/controllers/error_html.ex:117` — same
|
|
|
|
`CSSCache.warm/0` does it correctly: `CSSGenerator.generate(settings, &BerrypodWeb.Endpoint.static_path/1)`
|
|
|
|
## Options
|
|
|
|
### Option A: Quick fix — system font stack for admin
|
|
|
|
Add `font-family: system-ui, -apple-system, sans-serif` to the admin reset CSS. Admin pages get a clean sans-serif font without loading any custom font files.
|
|
|
|
Pros: zero extra bytes, fast, no font loading flash
|
|
Cons: admin and shop have completely different typographic feel
|
|
|
|
### Option B: Load Inter for admin pages
|
|
|
|
Add static `@font-face` declarations for Inter (the default body font) to admin.css. Admin gets a consistent font with minimal overhead (~50KB for regular + medium weights).
|
|
|
|
Pros: consistent typography across admin/shop
|
|
Cons: extra font loading, static declarations need updating if font files change
|
|
|
|
### Option C: Shared font loading infrastructure
|
|
|
|
Rethink the split between admin and shop CSS. Currently they're two completely separate stacks:
|
|
- **Shop**: runtime-generated CSS with `@font-face` via `CSSGenerator`, theme tokens, semantic layer
|
|
- **Admin**: hand-written CSS with DaisyUI-derived colour themes, no font loading
|
|
|
|
Could unify font loading so both share the same `@font-face` declarations (either static in a shared CSS file, or via a shared plug/hook). The theme font primitives are already in `theme-primitives.css` which both stacks import.
|
|
|
|
This is a bigger piece of work and might be overengineering for the current state — the admin and shop serve very different purposes and their CSS stacks reflect that.
|
|
|
|
### Option D: Full admin CSS rework
|
|
|
|
Rebuild admin CSS to share more with the shop CSS architecture. Both would use the three-layer system (primitives, attributes, semantic) with the admin getting its own semantic layer but sharing primitives and font loading.
|
|
|
|
This is the most ambitious option and would need its own plan. Worth considering if the admin UI is going to grow significantly, but could be premature for MVP.
|
|
|
|
## Recommendation
|
|
|
|
Fix the cache miss bug regardless (Option A baseline). For fonts specifically, Option A or B are both reasonable quick wins. Option C/D are worth revisiting when the admin UI needs a bigger rework.
|
|
|
|
## Related
|
|
|
|
- Cache miss bug affects shop pages too (not just admin)
|
|
- `CSSCache.warm/0` runs on startup so the bug only manifests on race conditions or manual invalidation
|
|
- The `@font-face` declarations in generated CSS use bare paths without `path_resolver`, which 404s in production
|