Initial commit: Lageplan v1.0 - Next.js 15.5, React 19

This commit is contained in:
Pepe Ziberi
2026-02-21 11:57:44 +01:00
commit adf3dc8c1d
167 changed files with 34265 additions and 0 deletions

0
public/.gitkeep Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
public/1x/Element 1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
public/2x/Element 1@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
public/3x/Element 1@3x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
public/4x/Element 1@4x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
public/Front_Pepe.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

16
public/SVG/Element 1.svg Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 751.13 754.43">
<defs>
<style>
.cls-1 {
fill: #e41313;
}
</style>
</defs>
<g id="Ebene_1-2" data-name="Ebene 1">
<g>
<path class="cls-1" d="M750.46,590.12c-.14,84.87-80.94,164.13-164.84,164.16l-417.85.15c-41.23.02-80.97-17.81-110.92-45.41C22.8,677.64.27,633.05.24,586.16l-.24-422.7C5.62,75.03,77.43,4.25,166.02,0h420.61c62.96,3.69,119.27,41.03,146.88,97.42,12.43,24.66,17.66,51.06,17.62,78.93l-.67,413.76ZM370.18,625.88c68.31,1.54,132.18-29.97,171.03-85.28,19.04-27.11,29.77-59.07,31.22-92.31,2.32-53.09-17.94-99.1-49.2-140.66-16.25-21.6-34.32-40.41-53.32-59.63l-43.23-43.74c-12.68-12.83-21.88-27.8-28.68-44.35-10.42-25.91-11.61-52.65-2.26-80.45-22.44,9.87-41.94,24.28-58.9,41.82-32.89,34-50.93,79.43-49.03,126.79.86,21.44,6.18,40.62,13.88,60.14,3.95,10.01,6.17,20.15,5.8,30.69-.57,16.13-12.7,28.03-28.8,28.13-9.24.06-17.69-3.81-23.17-10.35-5.88-7.01-7.61-16.24-6.35-25.41,2.35-17.02-3.73-32.8-18.26-42-69.49,73.43-78.46,184.2-13.01,262.78,37.6,45.14,92.49,72.48,152.3,73.83Z"/>
<path class="cls-1" d="M490.63,521.64c-17.79,22.43-41.28,37.71-67.84,46.68-59.05,19.93-124.13,1.45-163.53-46.85-25.25-30.95-37.66-72.35-28.81-112.76,30.31,30.19,79.51,27.67,110.75,2.18,36.69-29.94,30.9-75.91,14.6-116.82-6.76-16.96-10.43-34.03-11.76-52.32s2.8-36.52,9.95-52.81c11.14,34.99,32.99,58.35,58.82,82.14,7.59,6.99,15.55,12.82,22.13,20.89,20.88,25.59,29.46,58.1,25.52,90.79-3.27,27.11-12.78,51.87-30.01,73.44,41.77-13.36,65.73-42.83,67.49-87.7,28.98,50.16,29.42,106.82-7.32,153.13Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
public/logo-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

13
public/logo.svg Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Ebene_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 751.13 754.43">
<!-- Generator: Adobe Illustrator 30.3.0, SVG Export Plug-In . SVG Version: 2.1.3 Build 157) -->
<defs>
<style>
.st0 {
fill: #e41313;
}
</style>
</defs>
<path class="st0" d="M750.46,590.12c-.14,84.87-80.94,164.13-164.84,164.16l-417.85.15c-41.23.02-80.97-17.81-110.92-45.41C22.8,677.64.27,633.05.24,586.16l-.24-422.7C5.62,75.03,77.43,4.25,166.02,0h420.61c62.96,3.69,119.27,41.03,146.88,97.42,12.43,24.66,17.66,51.06,17.62,78.93l-.67,413.76ZM370.18,625.88c68.31,1.54,132.18-29.97,171.03-85.28,19.04-27.11,29.77-59.07,31.22-92.31,2.32-53.09-17.94-99.1-49.2-140.66-16.25-21.6-34.32-40.41-53.32-59.63l-43.23-43.74c-12.68-12.83-21.88-27.8-28.68-44.35-10.42-25.91-11.61-52.65-2.26-80.45-22.44,9.87-41.94,24.28-58.9,41.82-32.89,34-50.93,79.43-49.03,126.79.86,21.44,6.18,40.62,13.88,60.14,3.95,10.01,6.17,20.15,5.8,30.69-.57,16.13-12.7,28.03-28.8,28.13-9.24.06-17.69-3.81-23.17-10.35-5.88-7.01-7.61-16.24-6.35-25.41,2.35-17.02-3.73-32.8-18.26-42-69.49,73.43-78.46,184.2-13.01,262.78,37.6,45.14,92.49,72.48,152.3,73.83Z"/>
<path class="st0" d="M490.63,521.64c-17.79,22.43-41.28,37.71-67.84,46.68-59.05,19.93-124.13,1.45-163.53-46.85-25.25-30.95-37.66-72.35-28.81-112.76,30.31,30.19,79.51,27.67,110.75,2.18,36.69-29.94,30.9-75.91,14.6-116.82-6.76-16.96-10.43-34.03-11.76-52.32s2.8-36.52,9.95-52.81c11.14,34.99,32.99,58.35,58.82,82.14,7.59,6.99,15.55,12.82,22.13,20.89,20.88,25.59,29.46,58.1,25.52,90.79-3.27,27.11-12.78,51.87-30.01,73.44,41.77-13.36,65.73-42.83,67.49-87.7,28.98,50.16,29.42,106.82-7.32,153.13Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

28
public/manifest.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "Lageplan Feuerwehr Krokier-App",
"short_name": "Lageplan",
"description": "Digitale Einsatzdokumentation für Schweizer Feuerwehren. Lagepläne erstellen, Journal führen, Rapporte generieren.",
"start_url": "/app",
"display": "standalone",
"orientation": "any",
"background_color": "#ffffff",
"theme_color": "#dc2626",
"lang": "de-CH",
"categories": ["productivity", "utilities"],
"icons": [
{
"src": "/logo.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "/logo-icon.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
}
],
"screenshots": [],
"prefer_related_applications": false
}

94
public/sw.js Normal file
View File

@@ -0,0 +1,94 @@
const TILE_CACHE = 'lageplan-tiles-v2'
const STATIC_CACHE = 'lageplan-static-v2'
const APP_CACHE = 'lageplan-app-v2'
// Pre-cache essential app shell on install
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(APP_CACHE).then((cache) =>
cache.addAll([
'/app',
'/logo.svg',
'/logo-icon.png',
'/manifest.json',
]).catch(() => {})
)
)
self.skipWaiting()
})
// Cache strategy: Network First for API, Cache First for tiles, Stale While Revalidate for static assets
self.addEventListener('fetch', (event) => {
const url = event.request.url
const { pathname } = new URL(url)
// Skip non-GET requests
if (event.request.method !== 'GET') return
// API requests: network only (don't cache dynamic data)
if (pathname.startsWith('/api/')) return
// Cache map tiles from OpenStreetMap (Cache First)
if (url.includes('tile.openstreetmap.org') || url.includes('api.maptiler.com')) {
event.respondWith(
caches.open(TILE_CACHE).then((cache) =>
cache.match(event.request).then((cached) => {
if (cached) return cached
return fetch(event.request).then((response) => {
if (response.ok) {
cache.put(event.request, response.clone())
}
return response
}).catch(() => new Response('', { status: 503 }))
})
)
)
return
}
// Static assets (JS, CSS, images): Stale While Revalidate
if (pathname.match(/\.(js|css|png|jpg|jpeg|svg|ico|woff2?)$/)) {
event.respondWith(
caches.open(STATIC_CACHE).then((cache) =>
cache.match(event.request).then((cached) => {
const fetchPromise = fetch(event.request).then((response) => {
if (response.ok) cache.put(event.request, response.clone())
return response
}).catch(() => cached || new Response('', { status: 503 }))
return cached || fetchPromise
})
)
)
return
}
// App pages: Network First with cache fallback
if (pathname === '/app' || pathname === '/' || pathname.startsWith('/app')) {
event.respondWith(
fetch(event.request).then((response) => {
if (response.ok) {
const clone = response.clone()
caches.open(APP_CACHE).then((cache) => cache.put(event.request, clone))
}
return response
}).catch(() =>
caches.match(event.request).then((cached) => cached || caches.match('/app'))
)
)
return
}
})
// Clean old caches on activation
self.addEventListener('activate', (event) => {
const currentCaches = [TILE_CACHE, STATIC_CACHE, APP_CACHE]
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys
.filter((k) => !currentCaches.includes(k))
.map((k) => caches.delete(k))
)
).then(() => self.clients.claim())
)
})