diff --git a/app/static/app/css/custom.css b/app/static/app/css/custom.css index 1e83e8b..6f2566d 100644 --- a/app/static/app/css/custom.css +++ b/app/static/app/css/custom.css @@ -173,6 +173,69 @@ height: 15vh; } +/* Neu hinzugefügte Icons (Filter-Toggle, Maximieren) in Grau statt Schwarz/Weiß. + invert(50%) bildet jede Ausgangsfarbe (schwarz, weiß, hell-grau) auf denselben + neutralen Grauton ab - unabhängig davon, welches der beiden Icons gerade angezeigt wird. */ +#toggleSortOptionsIcon, +#openViewOfEntryIcon { + filter: invert(50%); +} + +/* Tabelle maximieren: Timer-Karte klappt weg, Aktivitäten-Tabelle wächst. + overflow bleibt im normalen Zustand "visible", damit Rand/Schatten der Timer-Karte + nicht abgeschnitten werden - nur beim Einklappen selbst wird geclippt. */ +#timerCard { + max-height: 20vh; + opacity: 1; + overflow: visible; + transition: max-height 0.4s ease-in-out, opacity 0.3s ease-in-out, padding 0.4s ease-in-out; +} + +#timerCard.timerCollapsed { + max-height: 0; + opacity: 0; + overflow: hidden; + padding-top: 0 !important; + padding-bottom: 0 !important; + pointer-events: none; +} + +#ActivitysTable { + transition: height 0.4s ease-in-out; +} + +#ActivitysTable.ActivitysTableMaximized { + height: 65vh !important; +} + +/* Filter/Sortierung ein- und ausblenden. + overflow bleibt im geöffneten Zustand "visible", damit das Dropdown-Menü (sortFieldMenu) + unterhalb der Zeile nicht abgeschnitten wird - nur beim Einklappen selbst wird geclippt. */ +#sortOptionsRow { + max-height: 3rem; + opacity: 1; + overflow: visible; + transition: max-height 0.3s ease-in-out, opacity 0.25s ease-in-out, margin-top 0.3s ease-in-out; +} + +#sortOptionsRow.sortOptionsCollapsed { + max-height: 0; + opacity: 0; + overflow: hidden; + margin-top: 0 !important; + pointer-events: none; +} + +.sortFieldOption { + cursor: pointer; +} + +.sortFieldOption:hover, +.sortFieldOption:active { + background-color: rgb(120,170,86); + color: white; +} + .header-bg-block { padding: 0; overflow: hidden; diff --git a/app/static/app/js/dbcontrol.js b/app/static/app/js/dbcontrol.js index 5789c80..a71fffa 100644 --- a/app/static/app/js/dbcontrol.js +++ b/app/static/app/js/dbcontrol.js @@ -293,16 +293,24 @@ function filterEntriesByServiceYear(serviceYearLabel) { } // Tabelle auf dem Dashboard mit Infos füllen -function fillTableWithEntries(entries) { +// sortField: 'date' | 'duration' | 'type' - sortDirection: 'asc' | 'desc' +function fillTableWithEntries(entries, sortField = 'date', sortDirection = 'asc') { const tableBody = document.getElementById('entriesTableBody'); - entries.sort((a, b) => new Date(a.date) - new Date(b.date)); - + const sortedEntries = entries.slice().sort((a, b) => { + const valA = (sortField === 'date') ? new Date(a.date) : a[sortField]; + const valB = (sortField === 'date') ? new Date(b.date) : b[sortField]; + + if (valA < valB) return (sortDirection === 'asc') ? -1 : 1; + if (valA > valB) return (sortDirection === 'asc') ? 1 : -1; + return 0; + }); + // Zuerst den Inhalt der Tabelle löschen (falls schon Daten da sind) tableBody.innerHTML = ''; - + // Iteriere durch die Einträge und füge Zeilen hinzu - entries.forEach(entry => { + sortedEntries.forEach(entry => { const row = document.createElement('tr'); //EVENTUELL MAL IN DER ZUKUNFT - UM EINTRÄGE ZU SEITE WISCHEN diff --git a/app/static/app/js/home01.js b/app/static/app/js/home01.js index d06a10b..e432e42 100644 --- a/app/static/app/js/home01.js +++ b/app/static/app/js/home01.js @@ -5,6 +5,18 @@ const NewEntryButton = document.getElementById('newEntrySubmitButton') const SETStudySaveButton = document.getElementById('SETStudySaveButton') const SETMonthGoalSaveButton = document.getElementById('SETMonthGoalSaveButton') const rule55hCheck = document.getElementById('rule55hCheck') +const openViewOfEntry = document.getElementById('openViewOfEntry') +const openViewOfEntryIcon = document.getElementById('openViewOfEntryIcon') +const ActivitysTable = document.getElementById('ActivitysTable') +const timerCard = document.getElementById('timerCard') +const toggleSortOptions = document.getElementById('toggleSortOptions') +const sortOptionsRow = document.getElementById('sortOptionsRow') +const sortFieldButton = document.getElementById('sortFieldButton') +const sortFieldLabel = document.getElementById('sortFieldLabel') +const sortFieldMenu = document.getElementById('sortFieldMenu') +const sortFieldOptions = document.querySelectorAll('.sortFieldOption') +const sortDirectionToggle = document.getElementById('sortDirectionToggle') +const sortDirectionIcon = document.getElementById('sortDirectionIcon') var allowToSend = false; const monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]; const currentDate = new Date(); @@ -13,6 +25,16 @@ const currentDate = new Date(); // live aktualisiert, damit getActualDataAndFillView() sie synchron verwenden kann. var rule55Active = false; +// Sortierung der Aktivitäten-Tabelle: wird aus dem Cache (localStorage) geladen/gespeichert. +var sortField = 'date'; +var sortDirection = 'asc'; + +// Ob die Filter/Sortier-Optionen gerade sichtbar sind (wird ebenfalls im Cache gespeichert). +var isFilterVisible = true; + +// Ob die Aktivitäten-Tabelle gerade maximiert ist (Timer-Karte ist dann ausgeblendet). +var isTableMaximized = false; + // // Trigger @@ -27,6 +49,12 @@ document.addEventListener('DOMContentLoaded', (event) => { // 55h-Regel Einstellung laden, bevor die erste Jahresansicht berechnet wird await loadRule55Setting(); + // Gespeicherte Sortierung der Aktivitäten-Tabelle aus dem Cache laden + loadSortPreference(); + + // Gespeicherte Sichtbarkeit der Filter/Sortier-Optionen aus dem Cache laden + loadFilterVisibility(); + // Bildschirm mit dem Inhalt für den aktuellen Tag füllen getActualDataAndFillView(); @@ -76,6 +104,112 @@ rule55hCheck.addEventListener('change', () => { }) }) +// +// TABELLE MAXIMIEREN +// + +// Aktivitäten-Tabelle vergrößern/verkleinern: Timer-Karte klappt beim Maximieren +// animiert weg, um Platz zu schaffen; die Tabelle wächst gleichzeitig. +openViewOfEntry.addEventListener('click', () => { + isTableMaximized = !isTableMaximized + ActivitysTable.classList.toggle('ActivitysTableMaximized', isTableMaximized) + timerCard.classList.toggle('timerCollapsed', isTableMaximized) + openViewOfEntryIcon.src = isTableMaximized + ? openViewOfEntryIcon.src.replace('open.png', 'close.png') + : openViewOfEntryIcon.src.replace('close.png', 'open.png') + openViewOfEntry.title = isTableMaximized ? 'Tabelle minimieren' : 'Tabelle maximieren' +}) + +// +// SORTIERUNG DER AKTIVITÄTEN-TABELLE +// + +// Lädt die gespeicherte Sortierung aus dem Cache (localStorage) und synchronisiert die Steuerelemente +function loadSortPreference() { + try { + const saved = JSON.parse(localStorage.getItem('piomintTableSort')) + if (saved && saved.field) { + sortField = saved.field + sortDirection = (saved.direction === 'desc') ? 'desc' : 'asc' + } + } catch (error) { + console.error('Sortierung konnte nicht aus dem Cache geladen werden:', error) + } + const selectedOption = Array.from(sortFieldOptions).find(option => option.dataset.value === sortField) + sortFieldLabel.innerText = selectedOption ? selectedOption.dataset.label : 'Datum' + sortDirectionIcon.innerText = (sortDirection === 'asc') ? 'A → Z' : 'Z → A' +} + +// Speichert die aktuelle Sortierung im Cache (localStorage) +function saveSortPreference() { + try { + localStorage.setItem('piomintTableSort', JSON.stringify({ field: sortField, direction: sortDirection })) + } catch (error) { + console.error('Sortierung konnte nicht im Cache gespeichert werden:', error) + } +} + +// Eigener Dropdown für die Sortier-Eigenschaft (statt