feat: refactor CSV filter & export section and enhance row styling in monthly view
All checks were successful
Build and Push Docker Image / build (push) Successful in 38s

This commit is contained in:
Felix Schlusche
2025-10-24 21:06:44 +02:00
parent fb33ea8144
commit 4bdd9310ea
2 changed files with 178 additions and 174 deletions

View File

@@ -418,128 +418,6 @@
</div> </div>
</div> </div>
</div> </div>
<!-- CSV Filter & Export Section (Collapsible) -->
<details class="mt-4 pt-4 border-t border-gray-700">
<summary class="cursor-pointer text-gray-300 hover:text-gray-100 font-medium flex items-center gap-2 select-none">
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform details-chevron"></i>
<i data-lucide="filter" class="w-5 h-5 text-blue-400"></i>
<span>CSV Filter & Export</span>
</summary>
<div class="mt-4 flex flex-wrap gap-4 items-end">
<div class="flex-1 min-w-[200px]">
<label for="filterFrom" class="block text-sm font-medium text-gray-300 mb-1">Von</label>
<input type="text" id="filterFrom"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="DD.MM.YYYY">
</div>
<div class="flex-1 min-w-[200px]">
<label for="filterTo" class="block text-sm font-medium text-gray-300 mb-1">Bis</label>
<input type="text" id="filterTo"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="DD.MM.YYYY">
</div>
<div class="flex gap-2">
<button id="btnFilter"
class="inline-flex items-center justify-center w-10 h-10 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 shadow-sm" title="Filtern">
<i data-lucide="search" class="w-5 h-5"></i>
</button>
<button id="btnClearFilter"
class="inline-flex items-center justify-center w-10 h-10 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 shadow-sm" title="Filter zurücksetzen">
<i data-lucide="x-circle" class="w-5 h-5"></i>
</button>
<button id="btnExport"
class="inline-flex items-center justify-center w-10 h-10 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-all duration-200 shadow-sm" title="Export (alle)">
<i data-lucide="download" class="w-5 h-5"></i>
</button>
<button id="btnExportDeviations"
class="inline-flex items-center justify-center w-10 h-10 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-all duration-200 shadow-sm" title="Export (nur Abweichungen)">
<i data-lucide="alert-circle" class="w-5 h-5"></i>
</button>
</div>
</div>
</details>
<!-- Settings Section (Collapsible) -->
<details class="mt-4 pt-4 border-t border-gray-700">
<summary class="cursor-pointer text-gray-300 hover:text-gray-100 font-medium flex items-center gap-2 select-none">
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform details-chevron"></i>
<i data-lucide="settings" class="w-5 h-5 text-purple-400"></i>
<span>Einstellungen</span>
</summary>
<div class="mt-4 mb-2 text-right">
<span id="versionInfo" class="text-xs text-gray-500 font-mono"></span>
</div>
<div class="mt-4 flex flex-wrap gap-4 items-center">
<div class="flex-1 min-w-[200px]">
<label for="employeeName" class="block text-sm font-medium text-gray-300 mb-1">Mitarbeitername</label>
<input type="text" id="employeeName" placeholder="Max Mustermann"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<div class="flex-1 min-w-[200px]">
<label for="employeeId" class="block text-sm font-medium text-gray-300 mb-1">Personalnummer</label>
<input type="text" id="employeeId" placeholder="12345"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
</div>
<div class="mt-4 flex flex-wrap gap-4 items-center">
<div class="flex-1 min-w-[200px]">
<label for="bundeslandSelect" class="block text-sm font-medium text-gray-300 mb-1">Bundesland (Feiertage)</label>
<select id="bundeslandSelect"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
<option value="BW">Baden-Württemberg</option>
<option value="BY">Bayern</option>
<option value="BE">Berlin</option>
<option value="BB">Brandenburg</option>
<option value="HB">Bremen</option>
<option value="HH">Hamburg</option>
<option value="HE">Hessen</option>
<option value="MV">Mecklenburg-Vorpommern</option>
<option value="NI">Niedersachsen</option>
<option value="NW">Nordrhein-Westfalen</option>
<option value="RP">Rheinland-Pfalz</option>
<option value="SL">Saarland</option>
<option value="SN">Sachsen</option>
<option value="ST">Sachsen-Anhalt</option>
<option value="SH">Schleswig-Holstein</option>
<option value="TH">Thüringen</option>
</select>
</div>
<div class="flex-1 min-w-[200px]">
<label for="vacationDaysInput" class="block text-sm font-medium text-gray-300 mb-1">Urlaubstage pro Jahr</label>
<input type="number" id="vacationDaysInput" min="0" max="50" value="30"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
</div>
<!-- Database Export/Import -->
<div class="mt-6 pt-4 border-t border-gray-600">
<h3 class="text-sm font-semibold text-gray-300 mb-3 flex items-center gap-2">
<i data-lucide="database" class="w-4 h-4 text-purple-400"></i>
Datenbank Verwaltung
</h3>
<div class="flex flex-wrap gap-3">
<button id="btnExportDB" class="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">
<i data-lucide="download" class="w-4 h-4"></i>
Datenbank exportieren
</button>
<button id="btnImportDB" class="flex items-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors">
<i data-lucide="upload" class="w-4 h-4"></i>
Datenbank importieren
</button>
<input type="file" id="importDBFile" accept=".json" class="hidden">
</div>
<p class="text-xs text-gray-500 mt-2">
<i data-lucide="info" class="w-3 h-3 inline"></i>
Export erstellt eine JSON-Datei mit allen Einträgen und Einstellungen. Import überschreibt alle vorhandenen Daten.
</p>
</div>
</details>
</div> </div>
<!-- Statistics --> <!-- Statistics -->
@@ -600,7 +478,7 @@
</div> </div>
<!-- Total Balance --> <!-- Total Balance -->
<div class="glass-card rounded-xl p-6 border-2 border-purple-500/30 shadow-lg shadow-purple-500/20"> <div class="glass-card rounded-xl p-6">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div> <div>
<div class="text-sm text-gray-300 mb-2 uppercase tracking-wide font-semibold flex items-center gap-1"> <div class="text-sm text-gray-300 mb-2 uppercase tracking-wide font-semibold flex items-center gap-1">
@@ -625,14 +503,12 @@
<!-- Left: Action Buttons (hidden on mobile, shown on desktop at start) --> <!-- Left: Action Buttons (hidden on mobile, shown on desktop at start) -->
<div class="hidden lg:flex gap-3 flex-wrap justify-start order-2 lg:order-1"> <div class="hidden lg:flex gap-3 flex-wrap justify-start order-2 lg:order-1">
<button id="btnToggleBulkEdit" <button id="btnToggleBulkEdit"
class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-gray-700 to-gray-600 text-gray-100 rounded-xl font-semibold" title="Mehrfachauswahl aktivieren"> class="btn-elevated inline-flex items-center justify-center w-12 h-12 bg-gradient-to-r from-gray-700 to-gray-600 text-gray-100 rounded-xl font-semibold" title="Mehrfachauswahl aktivieren">
<i data-lucide="check-square" class="w-5 h-5"></i> <i data-lucide="check-square" class="w-5 h-5"></i>
<span>Auswahl</span>
</button> </button>
<button id="btnAutoFill" <button id="btnAutoFill"
class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-indigo-600 to-indigo-500 text-white rounded-xl font-semibold" title="Monat ausfüllen (8h)"> class="btn-elevated inline-flex items-center justify-center w-12 h-12 bg-gradient-to-r from-indigo-600 to-indigo-500 text-white rounded-xl font-semibold" title="Monat ausfüllen (8h)">
<i data-lucide="calendar-check" class="w-5 h-5"></i> <i data-lucide="calendar-check" class="w-5 h-5"></i>
<span>Ausfüllen</span>
</button> </button>
</div> </div>
@@ -663,16 +539,14 @@
<!-- Mobile Action Buttons (shown only on mobile, below navigation) --> <!-- Mobile Action Buttons (shown only on mobile, below navigation) -->
<div class="flex lg:hidden gap-3 flex-wrap justify-center order-3"> <div class="flex lg:hidden gap-3 flex-wrap justify-center order-3">
<button onclick="document.getElementById('btnToggleBulkEdit').click()" <button onclick="document.getElementById('btnToggleBulkEdit').click()"
class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-gray-700 to-gray-600 text-gray-100 rounded-xl font-semibold" title="Mehrfachauswahl aktivieren"> class="btn-elevated inline-flex items-center justify-center w-12 h-12 bg-gradient-to-r from-gray-700 to-gray-600 text-gray-100 rounded-xl font-semibold" title="Mehrfachauswahl aktivieren">
<i data-lucide="check-square" class="w-5 h-5"></i> <i data-lucide="check-square" class="w-5 h-5"></i>
<span>Auswahl</span>
</button> </button>
<button onclick="document.getElementById('btnAutoFill').click()" <button onclick="document.getElementById('btnAutoFill').click()"
class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-indigo-600 to-indigo-500 text-white rounded-xl font-semibold" title="Monat ausfüllen (8h)"> class="btn-elevated inline-flex items-center justify-center w-12 h-12 bg-gradient-to-r from-indigo-600 to-indigo-500 text-white rounded-xl font-semibold" title="Monat ausfüllen (8h)">
<i data-lucide="calendar-check" class="w-5 h-5"></i> <i data-lucide="calendar-check" class="w-5 h-5"></i>
<span>Ausfüllen</span>
</button> </button>
<button onclick="document.getElementById('btnExportPDF').click()" <button id="btnExportPDFMobile" onclick="document.getElementById('btnExportPDF').click()"
class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-red-600 to-red-500 text-white rounded-xl font-semibold" title="Monat als PDF exportieren"> class="btn-elevated inline-flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-red-600 to-red-500 text-white rounded-xl font-semibold" title="Monat als PDF exportieren">
<i data-lucide="file-text" class="w-5 h-5"></i> <i data-lucide="file-text" class="w-5 h-5"></i>
<span>PDF Export</span> <span>PDF Export</span>
@@ -753,22 +627,22 @@
<div class="premium-table rounded-xl overflow-hidden border border-gray-700/50 shadow-2xl"> <div class="premium-table rounded-xl overflow-hidden border border-gray-700/50 shadow-2xl">
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="w-full"> <table class="w-full">
<thead class="bg-gradient-to-r from-gray-800 to-gray-700 border-b-2 border-blue-500/30"> <thead class="bg-gradient-to-r from-slate-800/80 to-slate-700/80 backdrop-blur-sm border-b border-blue-500/20">
<tr> <tr>
<th id="checkboxHeader" class="hidden px-2 py-4 text-center text-xs font-bold text-gray-300 uppercase tracking-wider"> <th id="checkboxHeader" class="hidden px-3 py-4 text-center text-xs font-semibold text-gray-300 uppercase tracking-wider">
<input type="checkbox" id="masterCheckbox" class="w-5 h-5 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500" title="Alle auswählen/abwählen"> <input type="checkbox" id="masterCheckbox" class="w-4 h-4 text-blue-500 bg-gray-700/50 border-gray-600 rounded focus:ring-2 focus:ring-blue-500/50" title="Alle auswählen/abwählen">
</th> </th>
<th class="px-2 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Tag</th> <th class="px-3 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Tag</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Datum</th> <th class="px-4 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Datum</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Start</th> <th class="px-4 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Start</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Ende</th> <th class="px-4 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Ende</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Pause (Min)</th> <th class="px-4 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Pause</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Netto (Std)</th> <th class="px-4 py-4 text-left text-xs font-semibold text-gray-300 uppercase tracking-wider">Netto</th>
<th class="px-6 py-4 text-center text-xs font-bold text-gray-300 uppercase tracking-wider">Ort</th> <th class="px-4 py-4 text-center text-xs font-semibold text-gray-300 uppercase tracking-wider">Ort</th>
<th class="px-6 py-4 text-center text-xs font-bold text-gray-300 uppercase tracking-wider">Action</th> <th class="px-4 py-4 text-center text-xs font-semibold text-gray-300 uppercase tracking-wider">Actions</th>
</tr> </tr>
</thead> </thead>
<tbody id="entriesTableBody" class="divide-y divide-gray-700/50"> <tbody id="entriesTableBody" class="divide-y divide-gray-600/50">
<!-- Entries will be inserted here dynamically --> <!-- Entries will be inserted here dynamically -->
</tbody> </tbody>
</table> </table>
@@ -881,6 +755,132 @@
</div> </div>
</div> </div>
<!-- CSV Filter & Export Section (Collapsible) -->
<div class="container mx-auto px-4 py-8 max-w-7xl">
<details class="premium-card rounded-xl p-6">
<summary class="cursor-pointer text-gray-300 hover:text-gray-100 font-medium flex items-center gap-2 select-none">
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform details-chevron"></i>
<i data-lucide="filter" class="w-5 h-5 text-blue-400"></i>
<span>CSV Filter & Export</span>
</summary>
<div class="mt-4 flex flex-wrap gap-4 items-end">
<div class="flex-1 min-w-[200px]">
<label for="filterFrom" class="block text-sm font-medium text-gray-300 mb-1">Von</label>
<input type="text" id="filterFrom"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="DD.MM.YYYY">
</div>
<div class="flex-1 min-w-[200px]">
<label for="filterTo" class="block text-sm font-medium text-gray-300 mb-1">Bis</label>
<input type="text" id="filterTo"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="DD.MM.YYYY">
</div>
<div class="flex gap-2">
<button id="btnFilter"
class="inline-flex items-center justify-center w-10 h-10 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 shadow-sm" title="Filtern">
<i data-lucide="search" class="w-5 h-5"></i>
</button>
<button id="btnClearFilter"
class="inline-flex items-center justify-center w-10 h-10 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 shadow-sm" title="Filter zurücksetzen">
<i data-lucide="x-circle" class="w-5 h-5"></i>
</button>
<button id="btnExport"
class="inline-flex items-center justify-center w-10 h-10 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-all duration-200 shadow-sm" title="Export (alle)">
<i data-lucide="download" class="w-5 h-5"></i>
</button>
<button id="btnExportDeviations"
class="inline-flex items-center justify-center w-10 h-10 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-all duration-200 shadow-sm" title="Export (nur Abweichungen)">
<i data-lucide="alert-circle" class="w-5 h-5"></i>
</button>
</div>
</div>
</details>
</div>
<!-- Settings Section (Collapsible) -->
<div class="container mx-auto px-4 pb-8 max-w-7xl">
<details class="premium-card rounded-xl p-6">
<summary class="cursor-pointer text-gray-300 hover:text-gray-100 font-medium flex items-center gap-2 select-none">
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform details-chevron"></i>
<i data-lucide="settings" class="w-5 h-5 text-purple-400"></i>
<span>Einstellungen</span>
</summary>
<div class="mt-4 mb-2 text-right">
<span id="versionInfo" class="text-xs text-gray-500 font-mono"></span>
</div>
<div class="mt-4 flex flex-wrap gap-4 items-center">
<div class="flex-1 min-w-[200px]">
<label for="employeeName" class="block text-sm font-medium text-gray-300 mb-1">Mitarbeitername</label>
<input type="text" id="employeeName" placeholder="Max Mustermann"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<div class="flex-1 min-w-[200px]">
<label for="employeeId" class="block text-sm font-medium text-gray-300 mb-1">Personalnummer</label>
<input type="text" id="employeeId" placeholder="12345"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
</div>
<div class="mt-4 flex flex-wrap gap-4 items-center">
<div class="flex-1 min-w-[200px]">
<label for="bundeslandSelect" class="block text-sm font-medium text-gray-300 mb-1">Bundesland (Feiertage)</label>
<select id="bundeslandSelect"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
<option value="BW">Baden-Württemberg</option>
<option value="BY">Bayern</option>
<option value="BE">Berlin</option>
<option value="BB">Brandenburg</option>
<option value="HB">Bremen</option>
<option value="HH">Hamburg</option>
<option value="HE">Hessen</option>
<option value="MV">Mecklenburg-Vorpommern</option>
<option value="NI">Niedersachsen</option>
<option value="NW">Nordrhein-Westfalen</option>
<option value="RP">Rheinland-Pfalz</option>
<option value="SL">Saarland</option>
<option value="SN">Sachsen</option>
<option value="ST">Sachsen-Anhalt</option>
<option value="SH">Schleswig-Holstein</option>
<option value="TH">Thüringen</option>
</select>
</div>
<div class="flex-1 min-w-[200px]">
<label for="vacationDaysInput" class="block text-sm font-medium text-gray-300 mb-1">Urlaubstage pro Jahr</label>
<input type="number" id="vacationDaysInput" min="0" max="50" value="30"
class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
</div>
<!-- Database Export/Import -->
<div class="mt-6 pt-4 border-t border-gray-600">
<h3 class="text-sm font-semibold text-gray-300 mb-3 flex items-center gap-2">
<i data-lucide="database" class="w-4 h-4 text-purple-400"></i>
Datenbank Verwaltung
</h3>
<div class="flex flex-wrap gap-3">
<button id="btnExportDB" class="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">
<i data-lucide="download" class="w-4 h-4"></i>
Datenbank exportieren
</button>
<button id="btnImportDB" class="flex items-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors">
<i data-lucide="upload" class="w-4 h-4"></i>
Datenbank importieren
</button>
<input type="file" id="importDBFile" accept=".json" class="hidden">
</div>
<p class="text-xs text-gray-500 mt-2">
<i data-lucide="info" class="w-3 h-3 inline"></i>
Export erstellt eine JSON-Datei mit allen Einträgen und Einstellungen. Import überschreibt alle vorhandenen Daten.
</p>
</div>
</details>
</div>
<!-- Flatpickr JS --> <!-- Flatpickr JS -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script> <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/de.js"></script> <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/de.js"></script>

View File

@@ -1015,15 +1015,15 @@ function renderMonthlyView(entries) {
const entryType = entry.entryType || 'work'; const entryType = entry.entryType || 'work';
// Row color based on entry type and location // Row color based on entry type and location
let rowClass = 'hover:bg-gray-700'; let rowClass = 'hover:bg-slate-600/40 transition-colors';
if (entryType === 'vacation') { if (entryType === 'vacation') {
rowClass = 'hover:bg-yellow-900 bg-yellow-950'; rowClass = 'hover:bg-yellow-800/50 bg-yellow-900/30 transition-colors';
} else if (entryType === 'flextime') { } else if (entryType === 'flextime') {
rowClass = 'hover:bg-cyan-900 bg-cyan-950'; rowClass = 'hover:bg-cyan-800/50 bg-cyan-900/30 transition-colors';
} else if (location === 'home') { } else if (location === 'home') {
rowClass = 'hover:bg-green-900 bg-green-950'; rowClass = 'hover:bg-green-800/50 bg-green-900/30 transition-colors';
} else if (weekend) { } else if (weekend) {
rowClass = 'hover:bg-gray-700 bg-gray-700'; rowClass = 'hover:bg-slate-600/50 bg-slate-700/30 transition-colors';
} }
@@ -1041,13 +1041,13 @@ function renderMonthlyView(entries) {
if (entryType === 'vacation') { if (entryType === 'vacation') {
displayIcon = '<i data-lucide="plane" class="w-4 h-4 inline"></i>'; displayIcon = '<i data-lucide="plane" class="w-4 h-4 inline"></i>';
displayText = 'Urlaub'; displayText = 'Urlaub';
displayTimes = `<td class="px-6 py-4 whitespace-nowrap text-sm text-center text-gray-400" colspan="3"> displayTimes = `<td class="px-4 py-3 whitespace-nowrap text-sm text-center text-gray-400" colspan="3">
<span class="italic">Urlaub</span> <span class="italic">Urlaub</span>
</td>`; </td>`;
} else if (entryType === 'flextime') { } else if (entryType === 'flextime') {
displayIcon = '<i data-lucide="clock" class="w-4 h-4 inline"></i>'; displayIcon = '<i data-lucide="clock" class="w-4 h-4 inline"></i>';
displayText = 'Gleitzeit'; displayText = 'Gleitzeit';
displayTimes = `<td class="px-6 py-4 whitespace-nowrap text-sm text-center text-gray-400" colspan="3"> displayTimes = `<td class="px-4 py-3 whitespace-nowrap text-sm text-center text-gray-400" colspan="3">
<span class="italic">Gleittag (8h)</span> <span class="italic">Gleittag (8h)</span>
</td>`; </td>`;
} else { } else {
@@ -1063,15 +1063,15 @@ function renderMonthlyView(entries) {
: entry.endTime; : entry.endTime;
displayTimes = ` displayTimes = `
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-100 editable-cell" <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-100 editable-cell"
data-field="startTime" data-id="${entry.id}" data-value="${entry.startTime}"> data-field="startTime" data-id="${entry.id}" data-value="${entry.startTime}">
${entry.startTime} ${entry.startTime}
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-100 ${isTimerRunning ? '' : 'editable-cell'}" <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-100 ${isTimerRunning ? '' : 'editable-cell'}"
${isTimerRunning ? '' : `data-field="endTime" data-id="${entry.id}" data-value="${entry.endTime}"`}> ${isTimerRunning ? '' : `data-field="endTime" data-id="${entry.id}" data-value="${entry.endTime}"`}>
${endTimeDisplay} ${endTimeDisplay}
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-100 ${isTimerRunning ? '' : 'editable-cell'}" <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-100 ${isTimerRunning ? '' : 'editable-cell'}"
${isTimerRunning ? `id="current-day-pause"` : `data-field="pauseMinutes" data-id="${entry.id}" data-value="${entry.pauseMinutes}"`}> ${isTimerRunning ? `id="current-day-pause"` : `data-field="pauseMinutes" data-id="${entry.id}" data-value="${entry.pauseMinutes}"`}>
${entry.pauseMinutes} ${entry.pauseMinutes}
</td>`; </td>`;
@@ -1079,28 +1079,28 @@ function renderMonthlyView(entries) {
// Checkbox column (always present for consistent layout) // Checkbox column (always present for consistent layout)
const checkboxCell = bulkEditMode ? ` const checkboxCell = bulkEditMode ? `
<td class="px-2 py-4 whitespace-nowrap text-center"> <td class="px-2 py-3 whitespace-nowrap text-center">
<input type="checkbox" class="entry-checkbox w-5 h-5 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500" <input type="checkbox" class="entry-checkbox w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500"
data-id="${entry.id}" ${selectedEntries.has(entry.id) ? 'checked' : ''}> data-id="${entry.id}" ${selectedEntries.has(entry.id) ? 'checked' : ''}>
</td> </td>
` : '<td class="hidden"></td>'; ` : '<td class="hidden"></td>';
row.innerHTML = checkboxCell + ` row.innerHTML = checkboxCell + `
<td class="px-2 py-4 whitespace-nowrap text-sm font-medium ${weekend ? 'text-blue-400' : 'text-gray-100'}">${dayOfWeek}</td> <td class="px-2 py-3 whitespace-nowrap text-sm font-medium ${weekend ? 'text-blue-400' : 'text-gray-100'}">${dayOfWeek}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-100">${formatDateDisplay(entry.date)}</td> <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-100">${formatDateDisplay(entry.date)}</td>
${displayTimes} ${displayTimes}
<td class="px-6 py-4 whitespace-nowrap text-sm font-semibold text-gray-100" id="${isToday ? 'current-day-net-hours' : ''}">${entry.netHours.toFixed(2)}</td> <td class="px-4 py-3 whitespace-nowrap text-sm font-semibold text-gray-100" id="${isToday ? 'current-day-net-hours' : ''}">${entry.netHours.toFixed(2)}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center text-gray-100"> <td class="px-4 py-3 whitespace-nowrap text-sm text-center text-gray-100">
<span class="text-lg">${displayIcon}</span> ${displayText} <span class="text-lg">${displayIcon}</span> ${displayText}
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center"> <td class="px-4 py-3 whitespace-nowrap text-sm text-center">
<div class="flex gap-2 justify-center"> <div class="flex gap-2 justify-center">
${entryType === 'work' ? ` ${entryType === 'work' ? `
<button class="btn-edit inline-flex items-center justify-center w-8 h-8 text-blue-500 hover:text-blue-600 hover:bg-blue-500/10 rounded transition-all" data-id="${entry.id}" title="Bearbeiten"> <button class="btn-edit inline-flex items-center justify-center w-8 h-8 text-blue-400/80 hover:text-blue-400 hover:bg-blue-500/10 rounded transition-all" data-id="${entry.id}" title="Bearbeiten">
<i data-lucide="pencil" class="w-4 h-4"></i> <i data-lucide="pencil" class="w-4 h-4"></i>
</button> </button>
` : ''} ` : ''}
<button class="btn-delete inline-flex items-center justify-center w-8 h-8 text-red-500 hover:text-red-600 hover:bg-red-500/10 rounded transition-all" data-id="${entry.id}" title="Löschen"> <button class="btn-delete inline-flex items-center justify-center w-8 h-8 text-red-400/80 hover:text-red-400 hover:bg-red-500/10 rounded transition-all" data-id="${entry.id}" title="Löschen">
<i data-lucide="trash-2" class="w-4 h-4"></i> <i data-lucide="trash-2" class="w-4 h-4"></i>
</button> </button>
</div> </div>
@@ -1113,8 +1113,8 @@ function renderMonthlyView(entries) {
// Don't mark future days as red, only past workdays without entries // Don't mark future days as red, only past workdays without entries
const isFutureDay = dateObj > today; const isFutureDay = dateObj > today;
let emptyRowClass = weekend ? 'hover:bg-gray-700 bg-gray-700' : let emptyRowClass = weekend ? 'hover:bg-slate-600/50 bg-slate-700/30 transition-colors' :
isFutureDay ? 'hover:bg-gray-700' : 'hover:bg-gray-700 bg-red-950/40'; isFutureDay ? 'hover:bg-slate-600/40 transition-colors' : 'hover:bg-slate-600/40 bg-red-900/30 transition-colors';
row.className = emptyRowClass; row.className = emptyRowClass;
@@ -1127,29 +1127,29 @@ function renderMonthlyView(entries) {
// Checkbox cell for empty days (in bulk edit mode) // Checkbox cell for empty days (in bulk edit mode)
const checkboxCell = bulkEditMode ? ` const checkboxCell = bulkEditMode ? `
<td class="px-2 py-4 whitespace-nowrap text-center"> <td class="px-2 py-3 whitespace-nowrap text-center">
<input type="checkbox" class="empty-day-checkbox w-5 h-5 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500" <input type="checkbox" class="empty-day-checkbox w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500"
data-date="${dateISO}" ${selectedEntries.has(dateISO) ? 'checked' : ''}> data-date="${dateISO}" ${selectedEntries.has(dateISO) ? 'checked' : ''}>
</td> </td>
` : '<td class="hidden"></td>'; ` : '<td class="hidden"></td>';
const colspan = bulkEditMode ? '5' : '5'; const colspan = bulkEditMode ? '5' : '5';
row.innerHTML = checkboxCell + ` row.innerHTML = checkboxCell + `
<td class="px-2 py-4 whitespace-nowrap text-sm font-medium ${weekend ? 'text-blue-400' : 'text-gray-100'}">${dayOfWeek}</td> <td class="px-2 py-3 whitespace-nowrap text-sm font-medium ${weekend ? 'text-blue-400' : 'text-gray-100'}">${dayOfWeek}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-100">${formatDateDisplay(dateISO)}</td> <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-100">${formatDateDisplay(dateISO)}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm ${holidayName ? 'text-blue-400 font-semibold' : 'text-gray-500'}" colspan="${colspan}"> <td class="px-4 py-3 whitespace-nowrap text-sm ${holidayName ? 'text-blue-400 font-semibold' : 'text-gray-500'}" colspan="${colspan}">
<span class="italic">${displayText}</span> <span class="italic">${displayText}</span>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center"> <td class="px-4 py-3 whitespace-nowrap text-sm text-center">
<div class="flex gap-1 justify-center"> <div class="flex gap-1 justify-center">
<button class="btn-add-work inline-flex items-center justify-center w-7 h-7 text-indigo-500 hover:text-indigo-600 hover:bg-indigo-500/10 rounded transition-all" data-date="${dateISO}" title="Arbeit eintragen"> <button class="btn-add-work inline-flex items-center justify-center w-7 h-7 text-indigo-400/80 hover:text-indigo-400 hover:bg-indigo-500/10 rounded transition-all" data-date="${dateISO}" title="Arbeit eintragen">
<i data-lucide="plus" class="w-4 h-4"></i> <i data-lucide="plus" class="w-4 h-4"></i>
</button> </button>
${!weekend ? ` ${!weekend ? `
<button class="btn-add-vacation inline-flex items-center justify-center w-7 h-7 text-amber-500 hover:text-amber-600 hover:bg-amber-500/10 rounded transition-all" data-date="${dateISO}" title="Urlaub eintragen"> <button class="btn-add-vacation inline-flex items-center justify-center w-7 h-7 text-amber-400/80 hover:text-amber-400 hover:bg-amber-500/10 rounded transition-all" data-date="${dateISO}" title="Urlaub eintragen">
<i data-lucide="plane" class="w-4 h-4"></i> <i data-lucide="plane" class="w-4 h-4"></i>
</button> </button>
<button class="btn-add-flextime inline-flex items-center justify-center w-7 h-7 text-cyan-500 hover:text-cyan-600 hover:bg-cyan-500/10 rounded transition-all" data-date="${dateISO}" title="Gleitzeit eintragen"> <button class="btn-add-flextime inline-flex items-center justify-center w-7 h-7 text-cyan-400/80 hover:text-cyan-400 hover:bg-cyan-500/10 rounded transition-all" data-date="${dateISO}" title="Gleitzeit eintragen">
<i data-lucide="clock" class="w-4 h-4"></i> <i data-lucide="clock" class="w-4 h-4"></i>
</button> </button>
` : ''} ` : ''}
@@ -1290,10 +1290,14 @@ async function loadMonthlyView() {
(displayYear === today.getFullYear() && displayMonth >= today.getMonth()); (displayYear === today.getFullYear() && displayMonth >= today.getMonth());
const pdfButton = document.getElementById('btnExportPDF'); const pdfButton = document.getElementById('btnExportPDF');
const pdfButtonMobile = document.getElementById('btnExportPDFMobile');
if (isCurrentOrFutureMonth) { if (isCurrentOrFutureMonth) {
pdfButton.style.display = 'none'; pdfButton.style.display = 'none';
if (pdfButtonMobile) pdfButtonMobile.style.display = 'none';
} else { } else {
pdfButton.style.display = ''; pdfButton.style.display = '';
if (pdfButtonMobile) pdfButtonMobile.style.display = '';
} }
} }