Files
eranos/public/theme.js
T
Alex Gleason 7c50fa9a90 remove user-customizable theme system
Agora's colors and fonts are now hardcoded in the bundle. There is no
runtime CSS-variable injection, no remote-loaded theme, no font-family
override from event data, no background image, no recolored favicon.
Switching themes only toggles the .dark class on <html>.

Removed:

- src/themes.ts: ThemeConfig, ThemesConfig, CoreThemeColors, ThemeFont,
  ThemeBackground, themePresets (22 presets), buildThemeCssFromCore,
  deriveTokensFromCore, the 'custom' Theme variant. Now exports only
  resolveTheme(theme) -> 'light' | 'dark'.
- src/lib/fontLoader.ts: deleted. Mounted arbitrary @font-face rules with
  event-sourced URLs and font-family overrides — the primary CSS-injection
  vector. sanitizeCssString moved to src/lib/cssSanitize.ts (still used by
  the Letter feature).
- AppProvider hooks useApplyFonts / useApplyBackground / useApplyFavicon.
- useTheme.applyCustomTheme — the entrypoint that wrote external palettes
  to global theme state.
- ColorMomentEyeButton + its callers in NoteCard and PostDetailPage. Color
  Moments (kind 3367) still render as palette art, but the 'Set as theme'
  button is gone.
- LetterAttachment in LetterDetailSheet — the gift-box UI that applied an
  attached color moment as the recipient's theme.
- paletteToTheme() from colorMomentUtils — only getColors() remains.
- customTheme / themes fields from AppConfig, AppConfigSchema,
  EncryptedSettings, EncryptedSettingsSchema. Existing customTheme values
  in localStorage and encrypted NIP-78 settings are now ignored.
- 14 unused @fontsource packages. Only the 10 letter fonts and the 2 base
  UI fonts (Inter Variable, Bebas Neue) remain. noto-sans-nushu is kept
  for the encrypted-letter obfuscation indicator.

Added:

- Static :root {} and .dark {} blocks in src/index.css with the 19 shadcn
  tokens hardcoded. These were previously injected at runtime by
  AppProvider; without them the app would lose all colors when the runtime
  injector was removed.
- src/lib/cssSanitize.ts holding the sanitizeCssString helper for the
  Letter feature's font-family interpolation.

Simplified:

- public/theme.js: no longer reads customTheme or themes from localStorage,
  just resolves system/light/dark with hardcoded built-ins. Must stay in
  sync with src/index.css colors.
- src/lib/fonts.ts: trimmed to only the 10 letter fonts. findBundledFont
  and resolveCssFamily removed (they were only used by fontLoader).
2026-05-23 14:31:04 -05:00

46 lines
1.7 KiB
JavaScript

// Reads the saved theme from localStorage and applies it to <html> and the
// preloader background before first paint. Runs as a blocking <script> so
// there's no flash of the wrong theme.
//
// Agora's colors are hardcoded in src/index.css via :root {} and .dark {}
// blocks. There is no custom-theme branch; the only thing this script
// does is set the right class on <html> and paint the preloader with the
// matching background + primary color so the page doesn't flash white
// in dark mode (or vice versa) before the React bundle boots.
//
// The colors below MUST stay in sync with the values in src/index.css.
(function () {
var builtins = {
dark: { bg: 'hsl(0 0% 10%)', primary: 'hsl(24 100% 50%)' },
light: { bg: 'hsl(0 0% 100%)', primary: 'hsl(24 100% 50%)' }
};
var theme = 'system';
try {
var cfg = JSON.parse(localStorage.getItem('nostr:app-config') || '{}');
if (cfg.theme === 'dark' || cfg.theme === 'light' || cfg.theme === 'system') {
theme = cfg.theme;
}
} catch (e) {}
if (theme === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
var colors = builtins[theme] || builtins.dark;
document.documentElement.className = theme;
document.body.style.background = colors.bg;
var p = document.getElementById('preloader');
if (p) {
p.style.background = colors.bg;
var logo = p.querySelector('[data-logo]');
if (logo) logo.style.background = colors.primary;
var spinner = p.querySelector('[data-spinner]');
if (spinner) {
spinner.style.borderColor = colors.primary.replace(')', ' / 0.25)');
spinner.style.borderTopColor = colors.primary;
}
}
})();