Tagebuch:
- Day-One-Listenansicht: Wochentag + Tageszahl + Meta-Zeile (Zeit/Ort/Wetter)
- 4 Ansichten: Liste, Medien-Mosaik, Kalender (mit Sprungbuttons), Karte (GPS-Marker)
- Detail-Ansicht inline im Content-Bereich (kein Fullscreen-Overlay mehr)
- Hero-Bild vollständig sichtbar (object-fit:contain), Lightbox mit Safe-Area
- 2-Spalten-Layout Desktop: Text + Leaflet-Karte + POI-Liste
- EXIF-GPS-Extraktion bei Foto-Upload, historisches Wetter via Archive-API
- NoteStation-Import: Fotos in diary_media (80 Einträge migriert, 94 Medien)
- Stats-Endpoints: /diary/stats, /diary/calendar, /diary/locations
Notiz-Feature:
- Generische notes-Tabelle (parent_type + parent_id + meta_json)
- 📝-Button in 8 Bereichen, Notizblock-Seite mit KI-Analyse
- KI-Toggle in Einstellungen, notes_ki_enabled in User-Profil
Icons & Design:
- fill:currentColor Fix für welcome/onboarding/friends.js
- --c-icon Variable, --c-text-muted Dark Mode aufgehellt
- 15+ neue Phosphor-Icons aus lokaler Kopie
- CSS Network-First im SW, Cache-Control-Middleware
Infrastruktur:
- Wiki-Anreicherungs-Scheduler-Jobs entfernt (abgeschlossen)
- auth.py: notes_ki_enabled + is_social_media im User-Response
477 lines
19 KiB
HTML
477 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<meta name="theme-color" content="#C4843A">
|
|
<meta name="description" content="Ban Yaro — Die kostenlose Hunde-App für Deutschland. Tagebuch, Impfpass, Giftköder-Alarm, Gassi-Community, Hundesitting. DSGVO-konform, ohne App Store.">
|
|
<meta name="keywords" content="Hunde App, Hunde Tagebuch, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundesitting, Hunde Wiki, Hunderassen, PWA Hunde, DSGVO Hunde App">
|
|
<link rel="canonical" href="https://banyaro.app/">
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:title" content="Ban Yaro — Die deutschsprachige Hunde-Plattform">
|
|
<meta property="og:description" content="Alles rund um deinen Hund — Tagebuch, Impfpass, Giftköder-Alarm, Gassi-Community, Hundesitting. Kostenlos, DSGVO-konform, ohne App Store.">
|
|
<meta property="og:url" content="https://banyaro.app/">
|
|
<meta property="og:image" content="https://banyaro.app/icons/icon-512.png">
|
|
<meta property="og:locale" content="de_DE">
|
|
<meta property="og:site_name" content="Ban Yaro">
|
|
|
|
<!-- Twitter Card -->
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="Ban Yaro — Die deutschsprachige Hunde-Plattform">
|
|
<meta name="twitter:description" content="Alles rund um deinen Hund — Tagebuch, Impfpass, Giftköder-Alarm, Gassi-Community. Kostenlos, DSGVO-konform.">
|
|
<meta name="twitter:image" content="https://banyaro.app/icons/icon-512.png">
|
|
|
|
<!-- Structured Data -->
|
|
<script type="application/ld+json">
|
|
{
|
|
"@context": "https://schema.org",
|
|
"@type": "MobileApplication",
|
|
"name": "Ban Yaro",
|
|
"alternateName": "Ban Yaro — Die Hunde-Plattform",
|
|
"description": "Ban Yaro ist die kostenlose, deutschsprachige All-in-One Hunde-App. Digitales Tagebuch, Impfpass, Giftköder-Alarm, Gassi-Community, Hundesitting und mehr — DSGVO-konform, ohne App Store.",
|
|
"url": "https://banyaro.app",
|
|
"applicationCategory": "LifestyleApplication",
|
|
"applicationSubCategory": "PetApplication",
|
|
"operatingSystem": "iOS, Android, Web",
|
|
"inLanguage": "de",
|
|
"offers": {
|
|
"@type": "Offer",
|
|
"price": "0",
|
|
"priceCurrency": "EUR",
|
|
"availability": "https://schema.org/InStock"
|
|
},
|
|
"publisher": {
|
|
"@type": "Organization",
|
|
"name": "Ban Yaro",
|
|
"url": "https://banyaro.app"
|
|
},
|
|
"featureList": [
|
|
"Digitales Hunde-Tagebuch mit Fotos und GPS",
|
|
"Digitaler Impfpass und Gesundheitsakte",
|
|
"Giftköder-Alarm mit Push-Benachrichtigungen",
|
|
"Gassi-Community und GPS-Routen",
|
|
"Hundesitting-Vermittlung mit 8% Provision",
|
|
"NFC-Halsband-Tags",
|
|
"Hunde-Wiki mit Rassendatenbank",
|
|
"Verlorener Hund Alarm",
|
|
"Forum für Hundebesitzer",
|
|
"Offline-Modus via Service Worker"
|
|
],
|
|
"areaServed": ["DE", "AT", "CH"]
|
|
}
|
|
</script>
|
|
|
|
<!-- Favicons -->
|
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16.png">
|
|
|
|
<!-- PWA -->
|
|
<link rel="manifest" href="/manifest.json">
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/icons/icon-180.png">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="Ban Yaro">
|
|
|
|
<title>Ban Yaro</title>
|
|
|
|
<!-- Theme vor CSS setzen — verhindert Flash of unstyled content -->
|
|
<script>
|
|
(function() {
|
|
var t = localStorage.getItem('by_theme');
|
|
if (t === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
|
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
|
|
// 'system' (oder kein Wert) → kein data-theme → @media prefers-color-scheme greift
|
|
})();
|
|
</script>
|
|
|
|
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
|
<link rel="stylesheet" href="/css/design-system.css?v=382">
|
|
<link rel="stylesheet" href="/css/layout.css?v=382">
|
|
<link rel="stylesheet" href="/css/components.css?v=382">
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Offline-Banner -->
|
|
<div id="offline-banner">Kein Internet — du bist offline</div>
|
|
|
|
<!-- Backdrop + Sidebar direkt im body (kein Ancestor-Stacking-Context) -->
|
|
<div id="sidebar-backdrop" class="sidebar-backdrop"></div>
|
|
|
|
<nav id="sidebar" role="navigation" aria-label="Hauptnavigation">
|
|
<div class="sidebar-logo" id="sidebar-dog-switcher">
|
|
<img class="sidebar-logo-img" src="/icons/icon-180.png" alt="Ban Yaro">
|
|
<span class="sidebar-logo-text" style="cursor:pointer" title="Über Ban Yaro">Ban Yaro</span>
|
|
</div>
|
|
|
|
<div class="sidebar-add">
|
|
<button class="btn btn-primary btn-full" id="sidebar-add">+ Neu erstellen</button>
|
|
</div>
|
|
|
|
<div class="sidebar-nav">
|
|
<span class="sidebar-section-label">Mein Hund</span>
|
|
<div class="sidebar-item active" data-page="diary">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#book-open"></use></svg> Tagebuch
|
|
</div>
|
|
<div class="sidebar-item" data-page="health">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> Gesundheit
|
|
</div>
|
|
<div class="sidebar-item" data-page="uebungen">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#target"></use></svg> Übungen
|
|
</div>
|
|
<div class="sidebar-item" data-page="trainingsplaene">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#clipboard-text"></use></svg> Trainingspläne
|
|
</div>
|
|
<div class="sidebar-item" data-page="notes">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notizblock
|
|
</div>
|
|
|
|
<span class="sidebar-section-label">Entdecken</span>
|
|
<div class="sidebar-item" data-page="map">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#map-trifold"></use></svg> Karte
|
|
</div>
|
|
<div class="sidebar-item" data-page="routes">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#path"></use></svg> Routen
|
|
</div>
|
|
<div class="sidebar-item" data-page="events">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#calendar-dots"></use></svg> Events
|
|
</div>
|
|
|
|
<span class="sidebar-section-label">Soziales</span>
|
|
<div class="sidebar-item" data-page="friends">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#users"></use></svg> Freunde
|
|
<span class="sidebar-item-badge" id="friends-badge" style="display:none">0</span>
|
|
</div>
|
|
<div class="sidebar-item" data-page="chat">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#chat-circle-dots"></use></svg> Nachrichten
|
|
<span class="sidebar-item-badge" id="chat-badge" style="display:none">0</span>
|
|
</div>
|
|
|
|
|
|
<span class="sidebar-section-label">Community</span>
|
|
<div class="sidebar-item" data-page="poison">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning-octagon"></use></svg> Giftköder
|
|
<span class="sidebar-item-badge" id="poison-badge" style="display:none">0</span>
|
|
</div>
|
|
<div class="sidebar-item" data-page="walks">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg> Gassi-Treffen
|
|
</div>
|
|
<div class="sidebar-item" data-page="sitting">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#house-line"></use></svg> Sitting
|
|
</div>
|
|
<div class="sidebar-item" data-page="forum">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#push-pin"></use></svg> Forum
|
|
</div>
|
|
<div class="sidebar-item" data-page="lost">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#magnifying-glass"></use></svg> Verlorener Hund
|
|
<span class="sidebar-item-badge" id="lost-badge" style="display:none">0</span>
|
|
</div>
|
|
|
|
<span class="sidebar-section-label">Wissen</span>
|
|
<div class="sidebar-item" data-page="wiki">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#books"></use></svg> Wiki
|
|
</div>
|
|
<div class="sidebar-item" data-page="knigge">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#handshake"></use></svg> Knigge
|
|
</div>
|
|
<div class="sidebar-item" data-page="movies">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#film-slate"></use></svg> Filme
|
|
</div>
|
|
<div class="sidebar-item" data-page="erste-hilfe">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> Erste Hilfe
|
|
</div>
|
|
|
|
<div class="sidebar-item" data-page="social" id="sidebar-social"
|
|
style="display:none;color:var(--c-warning,#f59e0b)">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#camera"></use></svg> Social Media
|
|
</div>
|
|
|
|
<div class="sidebar-item" data-page="moderation" id="sidebar-moderation"
|
|
style="display:none;color:var(--c-warning,#f59e0b)">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#eye"></use></svg> Moderation
|
|
</div>
|
|
|
|
<div class="sidebar-item" data-page="admin" id="sidebar-admin"
|
|
style="display:none;color:var(--c-danger,#ef4444)">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#shield"></use></svg> Admin
|
|
</div>
|
|
|
|
<div class="sidebar-item sidebar-item--user" id="sidebar-user">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#user"></use></svg>
|
|
<span id="sidebar-username">Anmelden</span>
|
|
</div>
|
|
|
|
<div style="margin-top:var(--space-4);padding-top:var(--space-3);
|
|
border-top:1px solid var(--c-border,#e5e7eb);
|
|
font-size:var(--text-xs);color:var(--c-text-muted);
|
|
display:flex;gap:var(--space-3);padding-bottom:var(--space-2)">
|
|
<span data-page="impressum" style="cursor:pointer;text-decoration:underline">Impressum</span>
|
|
<span data-page="datenschutz" style="cursor:pointer;text-decoration:underline">Datenschutz</span>
|
|
</div>
|
|
<!-- bot-trap: kein echter Nutzer klickt hier -->
|
|
<a href="/api/wiki/trap" aria-hidden="true" tabindex="-1"
|
|
style="position:absolute;width:1px;height:1px;opacity:0;pointer-events:none"
|
|
rel="nofollow noindex">.</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- ============================================================
|
|
APP SHELL
|
|
============================================================ -->
|
|
<div id="app">
|
|
|
|
<!-- MOBILE HEADER -->
|
|
<header id="app-header">
|
|
<button class="header-back hidden" id="header-back" aria-label="Zurück"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#arrow-left"></use></svg></button>
|
|
<div id="header-dog-switcher" class="dog-switcher">
|
|
<span class="header-title" id="header-title">Ban Yaro</span>
|
|
</div>
|
|
<div id="header-actions"></div>
|
|
<button id="header-user-btn" aria-label="Profil"
|
|
style="width:36px;height:36px;border-radius:50%;border:2px solid var(--c-border);
|
|
background:var(--c-surface-2);cursor:pointer;flex-shrink:0;
|
|
display:flex;align-items:center;justify-content:center;overflow:hidden;
|
|
padding:0;position:relative">
|
|
<svg id="header-user-icon" class="ph-icon" aria-hidden="true"
|
|
style="width:18px;height:18px;color:var(--c-text-muted)">
|
|
<use href="/icons/phosphor.svg#user"></use>
|
|
</svg>
|
|
<span id="chat-nav-badge" class="hidden"
|
|
style="position:absolute;top:-3px;right:-3px;width:10px;height:10px;
|
|
border-radius:50%;background:var(--c-danger);
|
|
pointer-events:none;z-index:1"></span>
|
|
</button>
|
|
<button class="header-menu-btn" id="header-menu-btn" aria-label="Menü" style="position:relative">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#list"></use></svg>
|
|
<span id="notif-nav-badge" class="hidden"
|
|
style="position:absolute;top:4px;right:4px;width:10px;height:10px;
|
|
border-radius:50%;background:var(--c-danger);
|
|
pointer-events:none;z-index:1"></span>
|
|
</button>
|
|
</header>
|
|
|
|
<!-- HAUPT-INHALTSBEREICH -->
|
|
<main id="page-content" role="main">
|
|
|
|
<!-- Jede Seite ist ein <section class="page"> -->
|
|
<section class="page" id="page-welcome">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-onboarding">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page active" id="page-diary">
|
|
<div class="page-body page-container">
|
|
<!-- wird von diary.js befüllt -->
|
|
</div>
|
|
</section>
|
|
|
|
<section class="page" id="page-health">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-dog-profile">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-map">
|
|
<div class="page-body page-container-wide"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-routes">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-events">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-poison">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-walks">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-sitting">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-forum">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-wiki">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-knigge">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-movies">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-uebungen">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-trainingsplaene">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-erste-hilfe">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-lost">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-settings">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-social">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-admin">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-moderation">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-friends">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-chat">
|
|
<div class="page-body page-container-chat"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-impressum">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-datenschutz">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-widget">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-notifications">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
<section class="page" id="page-notes">
|
|
<div class="page-body page-container"></div>
|
|
</section>
|
|
|
|
</main>
|
|
|
|
<!-- MOBILE BOTTOM NAVIGATION -->
|
|
<nav id="bottom-nav" role="navigation" aria-label="Hauptnavigation">
|
|
<div class="nav-item" data-page="map">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#map-trifold"></use></svg>
|
|
<span class="nav-item-label">Karte</span>
|
|
</div>
|
|
<div class="nav-item" data-page="routes">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#path"></use></svg>
|
|
<span class="nav-item-label">Routen</span>
|
|
</div>
|
|
<!-- Mittlerer + Button -->
|
|
<div class="nav-item nav-item-center" id="nav-add">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#plus"></use></svg>
|
|
</div>
|
|
<div class="nav-item active" data-page="diary">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#book-open"></use></svg>
|
|
<span class="nav-item-label">Tagebuch</span>
|
|
</div>
|
|
<div class="nav-item" data-page="forum">
|
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#push-pin"></use></svg>
|
|
<span class="nav-item-label">Forum</span>
|
|
</div>
|
|
</nav>
|
|
|
|
</div><!-- #app -->
|
|
|
|
<!-- TOAST CONTAINER (außerhalb der App, immer sichtbar) -->
|
|
<div class="toast-container" id="toast-container" role="alert" aria-live="polite"></div>
|
|
|
|
<!-- MODAL CONTAINER -->
|
|
<div id="modal-container"></div>
|
|
|
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
|
<script src="/js/api.js?v=94"></script>
|
|
<script src="/js/ui.js?v=94"></script>
|
|
<script src="/js/app.js?v=94"></script>
|
|
|
|
<!-- Feature-Seiten werden lazy geladen -->
|
|
|
|
<!-- Umami Analytics (self-hosted, cookiefrei, DSGVO-konform) -->
|
|
<script defer src="https://umami.motocamp.de/script.js" data-website-id="d1b5fe13-0e6f-4461-a176-c5439cbbc27f"></script>
|
|
|
|
|
|
<!-- Offline-Banner Logik -->
|
|
<script>
|
|
(function() {
|
|
var _wasOffline = false;
|
|
var banner = document.getElementById('offline-banner');
|
|
|
|
function setOffline() {
|
|
_wasOffline = true;
|
|
if (banner) banner.style.display = 'block';
|
|
}
|
|
|
|
function setOnline() {
|
|
if (banner) banner.style.display = 'none';
|
|
if (_wasOffline) {
|
|
_wasOffline = false;
|
|
// UI.toast ist verfügbar sobald ui.js geladen ist
|
|
if (window.UI && UI.toast) {
|
|
UI.toast.success('Wieder online');
|
|
}
|
|
}
|
|
}
|
|
|
|
window.addEventListener('offline', setOffline);
|
|
window.addEventListener('online', setOnline);
|
|
|
|
// Initialzustand prüfen
|
|
if (!navigator.onLine) setOffline();
|
|
})();
|
|
</script>
|
|
|
|
<!-- Service Worker -->
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' })
|
|
.catch(err => console.log('SW Registration failed:', err));
|
|
});
|
|
// Wenn ein neuer SW die Kontrolle übernimmt (nach Update),
|
|
// Seite neu laden — sonst hat app.js neue Seiten-JS aber altes api.js im Speicher.
|
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
window.location.reload();
|
|
});
|
|
navigator.serviceWorker.addEventListener('message', e => {
|
|
if (e.data?.type === 'CHECK_NEARBY_ALERTS') {
|
|
window.App?._checkNearbyAlerts?.();
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|