diff --git a/web/index.html b/web/index.html index b7e9dd3..593ed31 100644 --- a/web/index.html +++ b/web/index.html @@ -510,7 +510,6 @@ System User Custom - Kategorien
@@ -939,16 +938,44 @@ $ python web/serve.py
`).join(''); } + // Filter state + let currentType = null; + let currentQuery = ''; + + function parseTypeFromHash() { + const match = window.location.hash.match(/[?&]type=([^&]+)/); + return match ? decodeURIComponent(match[1]) : null; + } + + function setNavActive(type) { + document.querySelectorAll('.nav a').forEach(a => { + const m = (a.getAttribute('href') || '').match(/type=([^&]+)/); + const aType = m ? m[1] : null; + a.classList.toggle('active', aType === type); + }); + } + + function applyFilters() { + let list = allTemplates; + if (currentType) { + list = list.filter(t => t.type === currentType); + } + if (currentQuery) { + const q = currentQuery; + list = list.filter(t => + (t.name || '').toLowerCase().includes(q) || + (t.description || '').toLowerCase().includes(q) || + (t.tags || []).some(tag => tag.toLowerCase().includes(q)) + ); + } + setNavActive(currentType); + renderTemplates(list); + } + // Search - document.getElementById('search').addEventListener('input', async (e) => { - const query = e.target.value.toLowerCase(); - const templates = await loadTemplates(); - const filtered = templates.filter(t => - t.name.toLowerCase().includes(query) || - t.description.toLowerCase().includes(query) || - t.tags.some(tag => tag.toLowerCase().includes(query)) - ); - renderTemplates(filtered); + document.getElementById('search').addEventListener('input', (e) => { + currentQuery = e.target.value.toLowerCase(); + applyFilters(); }); // Close modal on overlay click @@ -961,69 +988,29 @@ $ python web/serve.py if (e.key === 'Escape') closeModal(); }); - // Handle navigation filter clicks via hash - window.addEventListener('hashchange', async () => { - const hash = window.location.hash.substring(2); - let templates = await loadTemplates(); - let typeFilter = hash.split('=')[1]; - - // Filter templates by type - if (typeFilter && typeFilter !== 'Alle') { - templates = templates.filter(t => t.type === typeFilter); - } - - // Update active state in navigation - document.querySelectorAll('.nav a').forEach(a => { - a.classList.remove('active'); - if (a.textContent === 'Alle' && (!typeFilter || typeFilter === 'Alle')) { - a.classList.add('active'); - } else if (a.getAttribute('href').includes(`type=${typeFilter}`)) { - a.classList.add('active'); - } - }); - - renderTemplates(templates); + // Hash -> type filter + window.addEventListener('hashchange', () => { + currentType = parseTypeFromHash(); + applyFilters(); }); - // Click handler for navigation + // Nav clicks set the hash; hashchange drives filtering document.querySelectorAll('.nav a').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); - // Spezialbehandlung für "Alle" - if (link.textContent.trim() === 'Alle') { - window.location.hash = '#'; - } else { - const href = link.getAttribute('href'); - const type = href.substring(href.indexOf('=') + 1); - window.location.hash = `#?type=${type}`; + const target = link.getAttribute('href') || '#'; + if (window.location.hash === target || (target === '#' && window.location.hash === '')) { + return; // same target, no hashchange would fire } + window.location.hash = target; }); }); // Initial load loadTemplates().then(t => { allTemplates = t; - - // Check for initial hash - const hash = window.location.hash.substring(2); - let typeFilter = hash ? hash.split('=')[1] : undefined; - let filteredTemplates = t; - - if (typeFilter && typeFilter !== 'Alle') { - filteredTemplates = t.filter(template => template.type === typeFilter); - } - - // Update active state - document.querySelectorAll('.nav a').forEach(a => { - a.classList.remove('active'); - if (!typeFilter || a.textContent === 'Alle') { - a.classList.add('active'); - } else if (a.getAttribute('href').includes(`type=${typeFilter}`)) { - a.classList.add('active'); - } - }); - - renderTemplates(filteredTemplates); + currentType = parseTypeFromHash(); + applyFilters(); });