Compare commits

..

7 Commits

Author SHA1 Message Date
97ad77f2a4 Merge pull request 'dev' (#6) from dev into main
Reviewed-on: #6
2026-02-07 10:12:30 +00:00
62439d2d28 Enhance loading screen with animation and splash improvements
Updated the loading screen to include animated gold lines, a loader, and a spark effect. Adjusted splash visibility to ensure a minimum display time of 3 seconds and improved transitions for smoother visuals. Enhanced style and structure for better user experience during app initialization.
2026-02-06 18:52:16 +01:00
57cb9a57ef Replace preload mechanism with splash screen
The preload class was replaced by a more user-friendly splash screen design. This change ensures a smoother transition while loading assets and eliminates black background flashes. The splash overlay is automatically hidden and removed after the app is ready, providing a seamless loading experience.
2026-02-06 18:49:25 +01:00
e975d7aa25 Set up immediate theme application and manual SW updates
Moved theme application logic to occur immediately on app initialization to prevent UI flash. Added a check to wait for all fonts to load before making the app visible and adjusted Service Worker behavior to require manual updates instead of auto-reloading.
2026-02-06 18:47:13 +01:00
7c4754e506 "Enhance loading experience and optimize theme application
Added a fallback background and a preload lock for smoother loading transitions. Improved theme application by applying it prior to React rendering and removed theme flash. Adjusted Service Worker registration for better performance and reliability."
2026-02-06 18:44:44 +01:00
070057afb3 Set and persist theme preference in localStorage
Implemented logic to store and retrieve theme preferences using localStorage for both logged-in users and guests. This ensures the selected theme is applied immediately on load, preventing theme flash issues. Adjusted initialization to apply the correct theme at app startup.
2026-02-06 18:41:45 +01:00
6434256dfb Set dynamic theme color for PWA and Android status bar.
Added logic to update the theme-color meta tag dynamically based on the active theme. This improves the visual consistency of the application, particularly for PWA and Android users. Default theme color has also been updated in the configuration.
2026-02-06 18:39:04 +01:00
5 changed files with 254 additions and 10 deletions

View File

@@ -3,12 +3,180 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<title>Cluedo Sheet</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&family=IM+Fell+English:ital@0;1&display=swap" rel="stylesheet">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&family=IM+Fell+English:ital@0;1&display=swap"
rel="stylesheet"
/>
<style>
html,
body {
margin: 0;
height: 100%;
background: radial-gradient(
ellipse at top,
rgba(30, 30, 30, 0.95),
#000
);
}
/* Splash Overlay */
#app-splash {
position: fixed;
inset: 0;
z-index: 2147483647;
display: grid;
place-items: center;
background: radial-gradient(
ellipse at top,
rgba(30, 30, 30, 0.95),
#000
);
overflow: hidden;
opacity: 1;
transition: opacity 260ms ease;
}
#app-splash.hide {
opacity: 0;
pointer-events: none;
}
/* gold animated lines */
#app-splash::before,
#app-splash::after {
content: "";
position: absolute;
inset: -40%;
background:
linear-gradient(
90deg,
transparent,
rgba(233, 216, 166, 0.18),
transparent
);
transform: rotate(12deg);
animation: goldSweep 1.6s linear infinite;
opacity: 0.55;
filter: blur(0.2px);
pointer-events: none;
}
#app-splash::after {
transform: rotate(-12deg);
animation-duration: 2.2s;
opacity: 0.35;
}
@keyframes goldSweep {
0% { transform: translateX(-25%) rotate(12deg); }
100% { transform: translateX(25%) rotate(12deg); }
}
/* glassy card */
.splash-card {
position: relative;
width: min(520px, 90vw);
border-radius: 22px;
padding: 18px 16px;
background: rgba(20, 20, 22, 0.55);
border: 1px solid rgba(233, 216, 166, 0.16);
box-shadow: 0 18px 70px rgba(0,0,0,0.55);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
text-align: center;
overflow: hidden;
}
.splash-card::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, transparent, rgba(233,216,166,0.16), transparent);
opacity: 0.45;
pointer-events: none;
}
.splash-title {
position: relative;
font-family: "Cinzel Decorative", serif;
font-weight: 700;
letter-spacing: 0.06em;
color: rgba(245, 239, 220, 0.92);
font-size: 18px;
line-height: 1.25;
}
.splash-sub {
position: relative;
margin-top: 6px;
font-family: "IM Fell English", serif;
font-style: italic;
color: rgba(233, 216, 166, 0.78);
font-size: 13px;
}
/* Loader */
.loader {
position: relative;
margin: 14px auto 0;
width: 28px;
height: 28px;
border-radius: 999px;
border: 2px solid rgba(233, 216, 166, 0.18);
border-top-color: rgba(233, 216, 166, 0.92);
animation: spin 0.85s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* tiny spark at bottom */
.spark {
position: relative;
margin: 14px auto 0;
width: 160px;
height: 2px;
border-radius: 999px;
background: linear-gradient(90deg, transparent, rgba(233,216,166,0.65), transparent);
opacity: 0.6;
filter: blur(0.2px);
animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.35; transform: scaleX(0.92); }
50% { opacity: 0.85; transform: scaleX(1.02); }
}
</style>
<!-- Theme-Key sofort setzen -->
<script>
try {
const k = localStorage.getItem("hpTheme:guest") || "default";
document.documentElement.setAttribute("data-theme", k);
} catch {}
</script>
</head>
<body>
<div id="app-splash" aria-hidden="true">
<div class="splash-card">
<div class="splash-title">Zauber-Detektiv Notizbogen</div>
<div class="splash-sub">Magie wird vorbereitet…</div>
<div class="loader" aria-label="Laden"></div>
<div class="spark"></div>
</div>
</div>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>

View File

@@ -342,6 +342,14 @@ export default function App() {
setThemeKey(key);
applyTheme(key);
// ✅ sofort für nächsten Start merken (verhindert Flash)
try {
localStorage.setItem(`hpTheme:${(me?.email || "guest").toLowerCase()}`, key);
localStorage.setItem("hpTheme:guest", key); // fallback, falls noch nicht eingeloggt
} catch {
// ignore
}
try {
await api("/auth/theme", {
method: "PATCH",
@@ -351,6 +359,7 @@ export default function App() {
// theme locally already applied; ignore backend error
}
};
// ===== Stats (always fresh on open) =====
const openStatsModal = async () => {

View File

@@ -1,14 +1,51 @@
import React from "react";
import { createRoot } from "react-dom/client";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import { applyTheme, DEFAULT_THEME_KEY } from "./styles/themes";
import { registerSW } from "virtual:pwa-register";
createRoot(document.getElementById("root")).render(<App />);
registerSW({ immediate: true });
const updateSW = registerSW({
async function bootstrap() {
// Theme sofort setzen
try {
const key = localStorage.getItem("hpTheme:guest") || DEFAULT_THEME_KEY;
applyTheme(key);
} catch {
applyTheme(DEFAULT_THEME_KEY);
}
// Fonts abwarten (verhindert Layout-Sprung)
try {
if (document.fonts?.ready) {
await document.fonts.ready;
}
} catch {}
// App rendern
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
// Splash mind. 3 Sekunden anzeigen (3000ms)
const MIN_SPLASH_MS = 3000;
const tStart = performance.now();
const hideSplash = () => {
const splash = document.getElementById("app-splash");
if (!splash) return;
splash.classList.add("hide");
setTimeout(() => splash.remove(), 320);
};
const elapsed = performance.now() - tStart;
const remaining = Math.max(0, MIN_SPLASH_MS - elapsed);
setTimeout(hideSplash, remaining);
// Service Worker ohne Auto-Reload-Flash
registerSW({
immediate: true,
onNeedRefresh() {
updateSW(true); // sofort neue Version aktivieren
window.location.reload();
console.info("Neue Version verfügbar");
// optional: später Toast "Update verfügbar"
},
});
}
bootstrap();

View File

@@ -195,6 +195,32 @@ export const THEMES = {
export const DEFAULT_THEME_KEY = "default";
export function setThemeColorMeta(color) {
try {
const safe = typeof color === "string" ? color.trim() : "";
if (!safe) return;
// only allow solid colors (hex, rgb, hsl); ignore urls/gradients/rgba overlays
const looksSolid =
safe.startsWith("#") ||
safe.startsWith("rgb(") ||
safe.startsWith("hsl(") ||
safe.startsWith("oklch(");
if (!looksSolid) return;
let meta = document.querySelector('meta[name="theme-color"]');
if (!meta) {
meta = document.createElement("meta");
meta.setAttribute("name", "theme-color");
document.head.appendChild(meta);
}
meta.setAttribute("content", safe);
} catch {
// ignore
}
}
export function applyTheme(themeKey) {
const t = THEMES[themeKey] || THEMES[DEFAULT_THEME_KEY];
const root = document.documentElement;
@@ -202,6 +228,10 @@ export function applyTheme(themeKey) {
for (const [k, v] of Object.entries(t.tokens)) {
root.style.setProperty(`--hp-${k}`, v);
}
// ✅ PWA/Android Statusbar dynamisch an Theme anpassen
// Nimmt (falls vorhanden) statusBarColor, sonst pageBg
setThemeColorMeta(t.tokens.statusBarColor || t.tokens.pageBg || "#000000");
}
export function themeStorageKey(email) {

View File

@@ -20,7 +20,7 @@ export default defineConfig({
scope: "/",
display: "standalone",
background_color: "#1c140d",
theme_color: "#caa45a",
theme_color: "#000000",
icons: [
{ src: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }
]