diff --git a/Brain.md b/Brain.md index 1a379d3..d5e0ca2 100644 --- a/Brain.md +++ b/Brain.md @@ -8,6 +8,7 @@ Eine ansprechende Landing Page fuer mischlabs.de, die alle Dienste als Kacheln m - [x] Dienste-Liste vom Screenshot erfasst (9 Services inkl. MiChess) - [x] Landing Page Design und Implementierung (index.html + style.css) - [x] Docker-Setup (Dockerfile, docker-compose.yml, nginx.conf) +- [x] PWA-Grundlage fuer iOS/Home-Screen-Installation - [x] Push zum Remote - [x] MiChess-Kachel hinzugefuegt (Commit lokal, Push steht aus wg. Auth-Fehler) - [ ] Push des MiChess-Commits (Git-Auth-Token erneuern) @@ -31,13 +32,14 @@ Eine ansprechende Landing Page fuer mischlabs.de, die alle Dienste als Kacheln m | 8 | tom.mischlabs.de | Persoenliche Seite | #ec4899 (Pink) | ## Technische Entscheidungen -- **Reines HTML + CSS** (kein Framework, kein JS) - maximale Performance, minimales Docker-Image +- **Reines HTML + CSS mit minimalem PWA-JS** (kein Framework) - maximale Performance, minimales Docker-Image - **nginx:alpine** als Base-Image - extrem leichtgewichtig (~5MB) - **Google Fonts (Inter)** fuer moderne Typografie - **Inline SVG Icons** - keine externen Dependencies - **CSS Grid** mit `auto-fill` + `minmax(240px, 1fr)` fuer responsives Layout - **Dark Theme** mit subtilen Glow-Effekten - **Staggered Animations**: Kacheln faden nacheinander ein (9 Stueck) +- **PWA**: Manifest, Apple-Touch-Icon, App-Icons und Service Worker fuer installierbare iOS/Web-App ## Docker-Setup - **Container-Name**: `mischlabs` @@ -51,6 +53,9 @@ Eine ansprechende Landing Page fuer mischlabs.de, die alle Dienste als Kacheln m mischlabs/ index.html - Haupt-HTML mit allen 9 Service-Kacheln style.css - Komplettes Styling (Dark Theme, Grid, Animationen) + manifest.webmanifest - PWA-Metadaten fuer installierbare App + sw.js - Schlanker Service Worker mit App-Shell-Cache + icons/ - App-Icons fuer iOS/PWA Dockerfile - nginx:alpine mit kopierten Static Files docker-compose.yml - Container-Definition (Name: mischlabs, Port 8085) nginx.conf - Server-Konfiguration, Caching, Security-Headers @@ -72,3 +77,28 @@ mischlabs/ - Git-Push-Fehler aufgetreten (Authentication failed) - Token muss erneuert werden - DNS: Alte A-Records (185.181.104.242) von INWX wurden geloescht, nur noch Tunnel-Eintraege - NAS hat kein git installiert - entweder Git Server Paket installieren oder wget nutzen + +## PWA-Stand 2026-05-21 +- MischLabs wurde als PWA vorbereitet. +- iOS-relevante Meta-Tags in `index.html`: + - `apple-mobile-web-app-capable` + - `apple-mobile-web-app-status-bar-style` + - `apple-mobile-web-app-title` + - `apple-touch-icon` +- Manifest: + - `name`: MischLabs + - `display`: standalone + - `theme_color`: #10b981 + - `background_color`: #0a0a0f +- Icons: + - `icons/apple-touch-icon.png` (180x180) + - `icons/icon-192.png` (192x192) + - `icons/icon-512.png` (512x512) + - `icons/maskable-512.png` (512x512, maskable) + - `icons/app-icon.svg` als editierbare Quelle +- Service Worker: + - Cache-Name: `mischlabs-pwa-v1` + - Cached die App-Shell (`/`, `index.html`, `style.css?v=8`, Manifest und Icons) + - Navigationen fallen offline auf `index.html` zurueck +- Dockerfile kopiert Manifest, Service Worker und Icons in das Nginx-Image. +- `nginx.conf` liefert `manifest.webmanifest` mit `application/manifest+json` und `sw.js` mit `no-cache` aus. diff --git a/Dockerfile b/Dockerfile index d28f5e8..899c79f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,5 +3,8 @@ FROM nginx:alpine COPY nginx.conf /etc/nginx/conf.d/default.conf COPY index.html /usr/share/nginx/html/ COPY style.css /usr/share/nginx/html/ +COPY manifest.webmanifest /usr/share/nginx/html/ +COPY sw.js /usr/share/nginx/html/ +COPY icons/ /usr/share/nginx/html/icons/ EXPOSE 80 diff --git a/icons/app-icon.svg b/icons/app-icon.svg new file mode 100644 index 0000000..d2e8ce7 --- /dev/null +++ b/icons/app-icon.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/apple-touch-icon.png b/icons/apple-touch-icon.png new file mode 100644 index 0000000..7fa4bf9 Binary files /dev/null and b/icons/apple-touch-icon.png differ diff --git a/icons/icon-192.png b/icons/icon-192.png new file mode 100644 index 0000000..04931c3 Binary files /dev/null and b/icons/icon-192.png differ diff --git a/icons/icon-512.png b/icons/icon-512.png new file mode 100644 index 0000000..2db3579 Binary files /dev/null and b/icons/icon-512.png differ diff --git a/icons/maskable-512.png b/icons/maskable-512.png new file mode 100644 index 0000000..7fc5c00 Binary files /dev/null and b/icons/maskable-512.png differ diff --git a/index.html b/index.html index 45e0d8d..1b90556 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,16 @@ MischLabs - Services - + + + + + + + + + +
@@ -160,5 +169,12 @@ + diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 0000000..2d45e55 --- /dev/null +++ b/manifest.webmanifest @@ -0,0 +1,34 @@ +{ + "name": "MischLabs", + "short_name": "MischLabs", + "description": "Self-hosted service hub for MischLabs.", + "lang": "de", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait", + "background_color": "#0a0a0f", + "theme_color": "#10b981", + "categories": ["productivity", "utilities"], + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} + diff --git a/nginx.conf b/nginx.conf index af61719..db01cf5 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,6 +9,16 @@ server { try_files $uri $uri/ /index.html; } + location = /manifest.webmanifest { + default_type application/manifest+json; + add_header Cache-Control "public, max-age=3600" always; + } + + location = /sw.js { + default_type application/javascript; + add_header Cache-Control "no-cache" always; + } + # Cache static assets location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 7d; diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..955d94e --- /dev/null +++ b/sw.js @@ -0,0 +1,56 @@ +const CACHE_NAME = 'mischlabs-pwa-v1'; +const APP_SHELL = [ + '/', + '/index.html', + '/style.css?v=8', + '/manifest.webmanifest', + '/icons/icon-192.png', + '/icons/icon-512.png', + '/icons/apple-touch-icon.png' +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)) + ); + self.skipWaiting(); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((keys) => ( + Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))) + )) + ); + self.clients.claim(); +}); + +self.addEventListener('fetch', (event) => { + const request = event.request; + + if (request.method !== 'GET') { + return; + } + + if (request.mode === 'navigate') { + event.respondWith( + fetch(request).catch(() => caches.match('/index.html')) + ); + return; + } + + event.respondWith( + caches.match(request).then((cached) => ( + cached || fetch(request).then((response) => { + if (!response || response.status !== 200 || response.type !== 'basic') { + return response; + } + + const responseToCache = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, responseToCache)); + return response; + }) + )) + ); +}); +