P42 Dashboard: erster Stand
FastAPI-Backend und React-Frontend mit Konten, Sendungsverfolgung, Projekt-Artikeln, Vorrat & Einkauf mit Rezeptabgleich, Reise-Weltkarte, Kanban-Projekten mit Priorität, Server-Monitoring und den Designs Matrix und Blackwall. Betrieb per Docker hinter nginx (siehe DEPLOY.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
dd58b3d1f8
75 files changed
+11418
No files matched your search
@@ -0,0 +1,46 @@
|
||||
// Designs der Oberfläche. Die Auswahl wird pro Browser gespeichert; index.html setzt sie vor dem ersten
|
||||
// Zeichnen (kein Aufblitzen des falschen Designs), dieses Modul hält sie danach aktuell.
|
||||
const KEY = 'p42.design';
|
||||
const EVENT = 'p42:design';
|
||||
|
||||
export const THEMES = [
|
||||
{ key: 'matrix', name: 'Matrix', hint: 'Rotes Retro-Terminal', swatch: ['#ff3a3a', '#1d0505'], color: '#050000' },
|
||||
{ key: 'blackwall', name: 'Blackwall', hint: 'Cyberpunk-Netrunner', swatch: ['#ff2d6f', '#3ff6ff', '#1a0508'], color: '#060104' },
|
||||
];
|
||||
|
||||
const valid = (key) => THEMES.some((t) => t.key === key);
|
||||
|
||||
export function getTheme() {
|
||||
const current = document.documentElement.dataset.theme;
|
||||
return valid(current) ? current : 'matrix';
|
||||
}
|
||||
|
||||
export function setTheme(key) {
|
||||
if (!valid(key)) return;
|
||||
try { localStorage.setItem(KEY, key); } catch { /* ignorieren */ }
|
||||
const still = document.documentElement.classList.contains('calm')
|
||||
|| window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
// Überblenden, wo der Browser View Transitions kann; kurz warten, bis React den neuen Hintergrund gezeichnet hat
|
||||
if (document.startViewTransition && !still) {
|
||||
document.startViewTransition(async () => {
|
||||
apply(key);
|
||||
await new Promise((resolve) => { setTimeout(resolve, 40); });
|
||||
});
|
||||
} else {
|
||||
apply(key);
|
||||
}
|
||||
}
|
||||
|
||||
export function onThemeChange(fn) {
|
||||
window.addEventListener(EVENT, fn);
|
||||
return () => window.removeEventListener(EVENT, fn);
|
||||
}
|
||||
|
||||
function apply(key) {
|
||||
document.documentElement.dataset.theme = key;
|
||||
// Browser-Leiste (Handy) passend einfärben
|
||||
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', THEMES.find((t) => t.key === key).color);
|
||||
window.dispatchEvent(new Event(EVENT));
|
||||
}
|
||||
|
||||
apply(getTheme());
|
||||
Reference in new issue
Block a user