feat(pwa): blue splash screen with the logo, status bar follows the theme
Manifest: short name, blue background/theme colour for the Android splash. index.html shows a plain blue screen with the logo until React mounts. theme-color starts blue and then follows the active theme background. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a3a709440f
commit
9bc8716f41
4 files changed
+32
-6
No files matched your search
@@ -61,3 +61,10 @@ Komponente: [CountBadge.tsx](../frontend/src/components/CountBadge.tsx), CSS-Kla
|
|||||||
- `inline`: im Textfluss.
|
- `inline`: im Textfluss.
|
||||||
- Zahlen im mobilen Menü (`MobileActionContext`, `badge: number`) werden automatisch als `CountBadge` gezeigt; Text-Badges wie „2 aktiv“ bleiben Textmarken.
|
- Zahlen im mobilen Menü (`MobileActionContext`, `badge: number`) werden automatisch als `CountBadge` gezeigt; Text-Badges wie „2 aktiv“ bleiben Textmarken.
|
||||||
- **Wichtig für neue Klassen:** Tailwind entfernt Klassen aus `@layer components`, die nicht wörtlich im Code stehen. Klassennamen deshalb nie zusammensetzen (`count-badge-${variant}`), sondern ausschreiben.
|
- **Wichtig für neue Klassen:** Tailwind entfernt Klassen aus `@layer components`, die nicht wörtlich im Code stehen. Klassennamen deshalb nie zusammensetzen (`count-badge-${variant}`), sondern ausschreiben.
|
||||||
|
|
||||||
|
## Ladebildschirm & Statusleiste
|
||||||
|
|
||||||
|
- `manifest.json`: `name` „MindSift“ (kurz, der Slogan steht in `description`), `background_color` und `theme_color` `#2563eb` – Android baut daraus den Splash-Screen.
|
||||||
|
- `index.html` enthält in `#root` einen reinen HTML-Platzhalter (vollflächig Blau, Logo in der Mitte, kein Text). React ersetzt ihn beim ersten Rendern, dazwischen blitzt nichts Weißes auf.
|
||||||
|
- `meta theme-color` startet blau und wird von [`theme.ts`](../frontend/src/lib/theme.ts) nach dem Start und bei jedem Theme-Wechsel auf `--bg-app` des aktiven Themes gesetzt, damit die Statusleiste zum Header passt.
|
||||||
|
|
||||||
+9
-2
@@ -3,7 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="theme-color" content="#0b0f19" />
|
<!-- Blue while loading (matches the splash screen); the app switches it to the theme background -->
|
||||||
|
<meta name="theme-color" content="#2563eb" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-title" content="MindSift" />
|
<meta name="apple-mobile-web-app-title" content="MindSift" />
|
||||||
@@ -49,7 +50,13 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-[#0b0f19] text-[#e3e3e3] antialiased selection:bg-[#8ab4f8]/30 selection:text-[#8ab4f8]">
|
<body class="bg-[#0b0f19] text-[#e3e3e3] antialiased selection:bg-[#8ab4f8]/30 selection:text-[#8ab4f8]">
|
||||||
<div id="root"></div>
|
<!-- Shown until React mounts and replaces it: full blue with the logo, no text, no white flash -->
|
||||||
|
<div id="root">
|
||||||
|
<div style="position:fixed;inset:0;background:#2563eb;display:flex;align-items:center;justify-content:center">
|
||||||
|
<!-- the icon's own blue square disappears on blue, so the visible brain is ~55% of this size -->
|
||||||
|
<img src="/icon.svg" width="128" height="128" alt="" style="display:block" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
<script>
|
<script>
|
||||||
if ('caches' in window) {
|
if ('caches' in window) {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"id": "/",
|
"id": "/",
|
||||||
"name": "MindSift — Der Kopf frei in drei Sekunden",
|
"name": "MindSift",
|
||||||
"short_name": "MindSift",
|
"short_name": "MindSift",
|
||||||
"description": "Instant Brain-Dump, Tinder-Style Triage, Workspace & Echtzeit-Familienlisten.",
|
"description": "MindSift — Der Kopf frei in drei Sekunden. Instant Brain-Dump, Tinder-Style Triage, Workspace & Echtzeit-Familienlisten.",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#0b0f19",
|
"background_color": "#2563eb",
|
||||||
"theme_color": "#0b0f19",
|
"theme_color": "#2563eb",
|
||||||
"orientation": "portrait-primary",
|
"orientation": "portrait-primary",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -132,6 +132,18 @@ function applyToDocument(themeId: ThemeId, customCss: string | null): void {
|
|||||||
root.setAttribute('data-theme', attr);
|
root.setAttribute('data-theme', attr);
|
||||||
const light = customCss !== null ? isLightColor(readCssVar(customCss, 'bg-app')) : themeId === 'light';
|
const light = customCss !== null ? isLightColor(readCssVar(customCss, 'bg-app')) : themeId === 'light';
|
||||||
root.classList.toggle('dark', !light);
|
root.classList.toggle('dark', !light);
|
||||||
|
syncThemeColorMeta();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The status bar (theme-color) starts blue for the splash screen; once the app runs it follows the
|
||||||
|
// active theme's background so it blends with the header.
|
||||||
|
function syncThemeColorMeta(): void {
|
||||||
|
const meta = document.querySelector('meta[name="theme-color"]');
|
||||||
|
if (!meta || typeof requestAnimationFrame === 'undefined') return;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const bg = getComputedStyle(document.documentElement).getPropertyValue('--bg-app').trim();
|
||||||
|
if (bg) meta.setAttribute('content', bg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function store(key: string, value: string | null): void {
|
function store(key: string, value: string | null): void {
|
||||||
|
|||||||
Reference in new issue
Block a user