Feature: Übungen Desktop 2-zeilige Tabs + globale Suche über alle Kategorien — SW by-v496, APP_VER 473

This commit is contained in:
rene 2026-04-29 13:07:41 +02:00
parent 81ee1a063e
commit a3679354c8
4 changed files with 52 additions and 15 deletions

View file

@ -685,6 +685,20 @@
white-space: nowrap;
}
/* Übungen: Tabs auf 2 Zeilen */
#page-uebungen #ueb-tabs {
display: grid;
grid-template-columns: repeat(var(--ueb-tab-cols, 5), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
padding-bottom: var(--space-2);
}
#page-uebungen #ueb-tabs .by-tab {
justify-content: center;
text-align: center;
white-space: nowrap;
}
/* Karte: Legende auf 2 Zeilen
#page-map nötig für Spezifität > .map-legend (components.css lädt später) */
#page-map .map-legend {

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '472'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '473'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => {

View file

@ -578,8 +578,11 @@ window.Page_uebungen = (() => {
</div>
`;
_container.querySelector('#ueb-quicksetup-btn').addEventListener('click', _openQuickSetupModal);
_container.querySelector('#ueb-tabs')?.style.setProperty('--ueb-tab-cols', Math.ceil(TABS.length / 2));
_container.querySelector('#ueb-search')?.addEventListener('input', e => {
_searchQuery = e.target.value.trim().toLowerCase();
const tabs = _container.querySelector('#ueb-tabs');
if (tabs) tabs.style.display = _searchQuery ? 'none' : '';
_renderContent();
});
_bindTabs();
@ -961,12 +964,15 @@ window.Page_uebungen = (() => {
case 'hundesport':
case 'koerperpflege':
case 'welpe-basics': {
const list = _exercisesByTab[_activeTab] || [];
el.innerHTML = list.length
? _renderUebungsList(list)
: `<div style="padding:var(--space-6);text-align:center;color:var(--c-text-muted)">
${UI.icon('spinner')} Übungen werden geladen
</div>`;
if (_searchQuery) {
el.innerHTML = _renderAllResults();
} else {
const list = _exercisesByTab[_activeTab] || [];
const html = list.length ? _renderUebungsList(list) : '';
el.innerHTML = html
? `<div style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)">${html}</div>`
: `<div style="padding:var(--space-6);text-align:center;color:var(--c-text-muted)">${UI.icon('spinner')} Übungen werden geladen…</div>`;
}
break;
}
case 'grundlagen': el.innerHTML = _renderGrundlagen(); break;
@ -1004,16 +1010,33 @@ window.Page_uebungen = (() => {
(u.beschreibung || '').toLowerCase().includes(_searchQuery)
)
: list;
if (!filtered.length) {
if (!filtered.length) return '';
return filtered.map((u, i) => _renderCard(u, i)).join('');
}
function _renderAllResults() {
const q = _searchQuery;
const allExercises = Object.entries(_exercisesByTab)
.filter(([tab]) => !['grundlagen','ki-trainer'].includes(tab))
.flatMap(([, list]) => list)
.filter(u =>
u.name.toLowerCase().includes(q) ||
(u.beschreibung || '').toLowerCase().includes(q)
);
if (!allExercises.length) {
return `<div style="padding:var(--space-8);text-align:center;color:var(--c-text-muted)">
${UI.icon('magnifying-glass')} Keine Übungen gefunden für ${_esc(_searchQuery)}"
${UI.icon('magnifying-glass')} Keine Übungen gefunden für ${_esc(q)}"
</div>`;
}
return `
<div style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)">
${filtered.map((u, i) => _renderCard(u, i)).join('')}
</div>
`;
return `<div style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)">
${allExercises.map((u, i) => `
<div>
<div style="font-size:var(--text-xs);font-weight:var(--weight-semibold);
color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.05em;
margin-bottom:var(--space-1);padding:0 var(--space-2)">${_esc(u.kategorie)}</div>
${_renderCard(u, i)}
</div>`).join('')}
</div>`;
}
function _sessionStatsChip(tab, name) {

View file

@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache
============================================================ */
const CACHE_VERSION = 'by-v495';
const CACHE_VERSION = 'by-v496';
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten