diff --git a/apps/frontend/index.html b/apps/frontend/index.html index 00cbd67..ef055dd 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -24,6 +24,20 @@ var root = document.documentElement; root.classList.toggle("dark", dark); root.style.colorScheme = dark ? "dark" : "light"; + + var accent = localStorage.getItem("accent"); + if (accent && /^#[0-9a-fA-F]{6}$/.test(accent)) { + var hex = accent.slice(1); + var r = parseInt(hex.slice(0, 2), 16) / 255; + var g = parseInt(hex.slice(2, 4), 16) / 255; + var b = parseInt(hex.slice(4, 6), 16) / 255; + var lin = function (c) { + return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); + }; + var lum = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b); + root.style.setProperty("--c-accent", accent); + root.style.setProperty("--c-accent-contrast", lum > 0.45 ? "#0b1220" : "#ffffff"); + } } catch (e) { /* ignore */ } diff --git a/apps/frontend/src/pages/Settings.tsx b/apps/frontend/src/pages/Settings.tsx index 7ceacae..adbc455 100644 --- a/apps/frontend/src/pages/Settings.tsx +++ b/apps/frontend/src/pages/Settings.tsx @@ -7,6 +7,17 @@ const MODES: { value: ThemeMode; label: string; icon: string }[] = [ { value: "auto", label: "Auto", icon: "auto" }, ]; +const PRESETS = [ + "#047857", + "#2563eb", + "#e11d48", + "#d97706", + "#7c3aed", + "#0284c7", + "#16a34a", + "#db2777", +]; + function Icon({ name }: { name: string }) { const common = { class: "h-4 w-4", @@ -43,6 +54,7 @@ function Icon({ name }: { name: string }) { export function SettingsPage() { const current = () => themeStore.mode; + const customAccent = () => themeStore.accent; return (
+ Wähle die Hauptfarbe der App. +
+
Kickern – deine Kicker-Liga auf einen Blick.
diff --git a/apps/frontend/src/stores/themeStore.ts b/apps/frontend/src/stores/themeStore.ts
index e280383..bd45927 100644
--- a/apps/frontend/src/stores/themeStore.ts
+++ b/apps/frontend/src/stores/themeStore.ts
@@ -3,6 +3,7 @@ import { createSignal, createEffect } from "solid-js";
export type ThemeMode = "light" | "dark" | "auto";
const STORAGE_KEY = "theme";
+const ACCENT_KEY = "accent";
const media = window.matchMedia("(prefers-color-scheme: dark)");
const root = document.documentElement;
@@ -46,6 +47,59 @@ createEffect(() => {
apply(mode);
});
+export type AccentColor = string | null;
+
+function readableText(color: string): string {
+ const hex = color.replace("#", "");
+ const full =
+ hex.length === 3
+ ? hex
+ .split("")
+ .map((c) => c + c)
+ .join("")
+ : hex;
+ const r = parseInt(full.slice(0, 2), 16) / 255;
+ const g = parseInt(full.slice(2, 4), 16) / 255;
+ const b = parseInt(full.slice(4, 6), 16) / 255;
+ const lin = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
+ const lum = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
+ return lum > 0.45 ? "#0b1220" : "#ffffff";
+}
+
+function readAccent(): string | null {
+ try {
+ const raw = localStorage.getItem(ACCENT_KEY);
+ if (raw && /^#[0-9a-fA-F]{6}$/.test(raw)) return raw;
+ } catch {
+ /* ignore */
+ }
+ return null;
+}
+
+const [getAccent, setAccentSignal] = createSignal