/* ============================================================ BAN YARO — App Core Router, State-Management, Navigation, Initialisierung. ============================================================ */ const App = (() => { // ---------------------------------------------------------- // STATE — zentraler App-Zustand // ---------------------------------------------------------- const state = { user: null, // eingeloggter User (oder null) dogs: [], // Hunde des Users activeDog: null, // aktuell gewählter Hund page: 'diary', // aktive Seite }; // ---------------------------------------------------------- // SEITENDEFINITIONEN // Jede Seite: { id, title, load() } // load() wird beim ersten Aufruf einmalig ausgeführt // ---------------------------------------------------------- const pages = { diary: { title: 'Tagebuch', module: null }, health: { title: 'Gesundheit', module: null }, 'dog-profile': { title: 'Mein Hund', module: null }, map: { title: 'Karte', module: null }, routes: { title: 'Routen', module: null }, places: { title: 'Orte', module: null }, events: { title: 'Events', module: null }, poison: { title: 'Giftköder-Alarm', module: null }, walks: { title: 'Gassi-Treffen', module: null }, sitting: { title: 'Sitting', module: null }, forum: { title: 'Forum', module: null }, wiki: { title: 'Wiki', module: null }, knigge: { title: 'Knigge', module: null }, movies: { title: 'Filme', module: null }, settings: { title: 'Einstellungen', module: null }, }; // ---------------------------------------------------------- // ROUTER // ---------------------------------------------------------- function navigate(pageId, pushHistory = true) { if (!pages[pageId]) return; // Aktive Seite ausblenden document.querySelector('.page.active')?.classList.remove('active'); document.querySelectorAll('.nav-item.active, .sidebar-item.active') .forEach(el => el.classList.remove('active')); // Neue Seite einblenden document.getElementById(`page-${pageId}`)?.classList.add('active'); // Navigation markieren document.querySelectorAll(`[data-page="${pageId}"]`) .forEach(el => el.classList.add('active')); // Header-Titel setzen document.getElementById('header-title').textContent = pages[pageId].title; // History if (pushHistory) { history.pushState({ page: pageId }, '', `#${pageId}`); } state.page = pageId; UI.scrollTop(); // Seiten-Modul lazy laden (einmalig) _loadPage(pageId); } async function _loadPage(pageId) { const page = pages[pageId]; if (page.module) { // Bereits geladen → nur refresh aufrufen wenn vorhanden page.module.refresh?.(); return; } const container = document.querySelector(`#page-${pageId} .page-body`); if (!container) return; // Skeleton während Laden container.innerHTML = UI.skeleton(4); try { // Seiten-Script dynamisch laden await _loadScript(`/js/pages/${pageId}.js`); const mod = window[`Page_${pageId.replace(/-/g, '_')}`]; if (mod?.init) { await mod.init(container, state); page.module = mod; } else { // Platzhalter wenn Seite noch nicht gebaut container.innerHTML = UI.emptyState({ icon: '🚧', title: pages[pageId].title, text: 'Diese Seite ist noch in Entwicklung.', }); page.module = {}; // verhindert erneutes Laden } } catch { container.innerHTML = UI.emptyState({ icon: '🚧', title: pages[pageId].title, text: 'Diese Seite ist noch in Entwicklung.', }); page.module = {}; } } function _loadScript(src) { return new Promise((resolve, reject) => { if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; } const s = document.createElement('script'); s.src = src; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); }); } // ---------------------------------------------------------- // NAVIGATION EVENTS // ---------------------------------------------------------- function _bindNavigation() { // Bottom Nav + Sidebar Klicks document.addEventListener('click', e => { const item = e.target.closest('[data-page]'); if (item) { navigate(item.dataset.page); return; } // + Button if (e.target.closest('#nav-add')) { _showQuickAdd(); } }); // Browser Back/Forward window.addEventListener('popstate', e => { const page = e.state?.page || 'diary'; navigate(page, false); }); // Initial: URL-Hash auslesen const hash = location.hash.replace('#', ''); if (hash && pages[hash]) { navigate(hash, false); } } // ---------------------------------------------------------- // SCHNELL-HINZUFÜGEN (+ Button) // ---------------------------------------------------------- function _showQuickAdd() { UI.modal.open({ title: 'Was möchtest du hinzufügen?', body: `