Files
EventSnap/frontend/src/app.html
MechaCat02 57a907eca5 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>
2026-07-19 15:21:55 +02:00

109 lines
4.1 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<!-- viewport-fit=cover activates the env(safe-area-inset-*) padding used by the
bottom nav, sheets, toasts and FAB on notched / home-indicator devices. -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="text-scale" content="scale" />
<!-- Light/dark theme-color so the browser chrome matches the active theme. -->
<meta name="theme-color" content="#faf9f7" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#100f0f" media="(prefers-color-scheme: dark)" />
<!-- Installable PWA keepsake: manifest + Apple home-screen metadata. -->
<link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
<link rel="icon" href="%sveltekit.assets%/icon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="%sveltekit.assets%/icon.svg" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="EventSnap" />
<!--
FOUC guard: apply the dark class *before* paint, so reloads of pages with
theme=dark don't flash a white screen. Mirrors the logic in
`src/lib/theme-store.ts`; kept in sync by hand (it's 6 lines).
-->
<!-- nonce is required: our CSP sets script-src 'self', and SvelteKit's
mode:'auto' only hashes scripts *it* injects, not this template-authored
one. %sveltekit.nonce% is substituted per request and added to the CSP. -->
<script nonce="%sveltekit.nonce%">
(function () {
try {
var pref = localStorage.getItem('eventsnap_theme') || 'system';
var dark =
pref === 'dark' ||
(pref === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (dark) document.documentElement.classList.add('dark');
} catch (_) {}
// Colour-theme FOUC guard: re-apply the cached palette override before paint so
// a custom/preset theme doesn't flash the default gold. The value is a ready-to-
// inject `:root:root{…}` string from event-config-store (empty for the default
// theme); refreshed from /event once the app mounts.
try {
var css = localStorage.getItem('eventsnap_palette_css');
if (css) {
var s = document.createElement('style');
s.id = 'es-theme';
s.textContent = css;
document.head.appendChild(s);
}
} catch (_) {}
})();
</script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
<!--
Cold-start placeholder. With `ssr = false` the app renders entirely client-side,
so `%sveltekit.body%` is empty until the JS bundle mounts. This themed spinner
(the FOUC guard above has already applied `.dark`) fills that gap instead of a
blank flash, and mirrors the /-route splash. The root layout's onMount removes
it once the app has painted. Inline <style> is permitted by our CSP
(style-src 'unsafe-inline'); intentionally no <script> here so script-src stays 'self'.
-->
<div id="app-boot" role="status" aria-label="Lädt">
<span class="app-boot__spinner"></span>
<span class="app-boot__label">EventSnap</span>
</div>
<style>
#app-boot {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.75rem;
background: #faf9f7;
}
html.dark #app-boot {
background: #100f0f;
}
.app-boot__spinner {
width: 2rem;
height: 2rem;
border-radius: 9999px;
border: 2px solid #e5e4e1;
border-top-color: #8a6a2b;
animation: app-boot-spin 0.6s linear infinite;
}
html.dark .app-boot__spinner {
border-color: #3b3a38;
border-top-color: #c6a24a;
}
.app-boot__label {
font-family: Georgia, 'Times New Roman', serif;
font-size: 1rem;
font-weight: 600;
letter-spacing: 0.01em;
color: #8a6a2b;
}
@keyframes app-boot-spin {
to {
transform: rotate(360deg);
}
}
</style>
</body>
</html>