feat(theme+comments): runtime colour theme and COMMENTS_ENABLED switch

Colour theme is configurable at runtime from two seed colours (brand + accent);
neutrals stay fixed for contrast safety. Tailwind v4 var()-based tokens let a
:root:root override recolour everything with no rebuild; the 50->950 ramps are
derived via a color-mix ladder. Config lives in the DB config table (admin UI:
Config > Farbschema, presets + custom pickers + live preview), served on the public
/event endpoint with env defaults (THEME_PRESET/PRIMARY/ACCENT), propagated live via
event-updated SSE, and cached in localStorage for a no-flash boot. The keepsake export
mirrors the same ladder in Rust so offline archives match the event theme.

COMMENTS_ENABLED (env, default true) is a boot-time kill-switch: the backend rejects
new comments with 403 and the frontend hides the comment button (feed card) and
panel/composer (lightbox). Existing comments stay in the DB, hidden, and return when
re-enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-19 15:21:55 +02:00
parent 6e0a760271
commit 57a907eca5
12 changed files with 765 additions and 99 deletions

View File

@@ -63,8 +63,25 @@ pub struct AppConfig {
pub app_port: u16,
/// Number of concurrent media compression workers (read once at boot).
pub compression_concurrency: usize,
/// Master switch for the comment feature (env `COMMENTS_ENABLED`, default true).
/// When false the backend rejects new comments and the frontend hides the whole
/// comment UI. Existing comments stay in the DB (hidden), so flipping it back
/// restores them. Boot-time immutable, like `compression_concurrency`.
pub comments_enabled: bool,
/// Default colour theme, used as the fallback when the DB config keys are unset.
/// Runtime overrides live in the `config` table (admin UI); these env vars only
/// seed the initial default. `preset` is an id the frontend knows (e.g.
/// "champagne-gold", "rose", … or "custom"); the two seeds are `#rrggbb` brand +
/// accent colours the whole palette is derived from.
pub default_theme_preset: String,
pub default_theme_primary: String,
pub default_theme_accent: String,
}
/// The shipped default brand/accent seed (champagne gold — matches the hand-tuned
/// ramp in tailwind-theme.css). Kept here so an unset env still yields the current look.
const DEFAULT_THEME_SEED: &str = "#8a6a2b";
impl AppConfig {
pub fn from_env() -> Result<Self> {
let app_env = std::env::var("APP_ENV").unwrap_or_else(|_| "development".to_string());
@@ -100,6 +117,20 @@ impl AppConfig {
.and_then(|v| v.parse().ok())
.filter(|&n| n >= 1)
.unwrap_or(2),
comments_enabled: std::env::var("COMMENTS_ENABLED")
.map(|v| {
!matches!(
v.trim().to_ascii_lowercase().as_str(),
"false" | "0" | "no" | "off"
)
})
.unwrap_or(true),
default_theme_preset: std::env::var("THEME_PRESET")
.unwrap_or_else(|_| "champagne-gold".to_string()),
default_theme_primary: std::env::var("THEME_PRIMARY")
.unwrap_or_else(|_| DEFAULT_THEME_SEED.to_string()),
default_theme_accent: std::env::var("THEME_ACCENT")
.unwrap_or_else(|_| DEFAULT_THEME_SEED.to_string()),
})
}
}