Add utility functions for date formatting, time rounding, and notifications

- Implemented functions to format dates between YYYY-MM-DD and DD.MM.YYYY
- Added functions to get today's date in ISO format
- Created functions to round time to the nearest 15 minutes
- Developed a function to format time as HH:MM
- Added a function to format duration in HH:MM:SS
- Implemented a toast notification system with auto-remove functionality
- Added functions to get day of the week and month names in German
This commit is contained in:
Felix Schlusche
2025-10-23 17:53:03 +02:00
parent c20f6d9dff
commit e1be63b1ca
5 changed files with 556 additions and 48 deletions

View File

@@ -258,6 +258,19 @@
flex-shrink: 0;
}
/* Details/Summary chevron rotation */
details[open] .details-chevron {
transform: rotate(180deg);
}
details summary {
list-style: none;
}
details summary::-webkit-details-marker {
display: none;
}
/* Blink animation for running timer icon */
@keyframes blink {
0%, 100% { opacity: 1; }
@@ -402,49 +415,57 @@
</div>
</div>
<!-- Date Range Filter -->
<div class="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>
<!-- 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>
<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>
<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>
<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 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>
</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 text-sm flex items-center gap-2">
<span class="text-lg">⚙️</span>
<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 flex flex-wrap gap-4 items-center">
@@ -560,8 +581,9 @@
<!-- Month Navigation -->
<div class="mb-8 glass-card rounded-xl p-5 border border-gray-700/50">
<div class="flex items-center justify-between flex-wrap gap-4">
<div class="flex gap-3 flex-wrap">
<div class="grid grid-cols-1 lg:grid-cols-3 items-center gap-4">
<!-- 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">
<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">
<i data-lucide="check-square" class="w-5 h-5"></i>
@@ -572,14 +594,10 @@
<i data-lucide="calendar-check" class="w-5 h-5"></i>
<span>Ausfüllen</span>
</button>
<button id="btnExportPDF"
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>
<span>PDF Export</span>
</button>
</div>
<div id="monthNavigation" class="flex items-center gap-4">
<!-- Center: Month Navigation (always visible and centered) -->
<div id="monthNavigation" class="flex items-center justify-center gap-4 order-1 lg:order-2">
<button id="btnPrevMonth"
class="btn-elevated inline-flex items-center justify-center w-12 h-12 bg-gradient-to-br from-gray-700 to-gray-600 text-gray-100 rounded-xl">
<i data-lucide="chevron-left" class="w-6 h-6"></i>
@@ -593,7 +611,33 @@
</button>
</div>
<div class="w-48"></div> <!-- Spacer for alignment -->
<!-- Right: Export Button (hidden on mobile, shown on desktop at end) -->
<div class="hidden lg:flex justify-end order-3">
<button id="btnExportPDF"
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>
<span>PDF Export</span>
</button>
</div>
<!-- Mobile Action Buttons (shown only on mobile, below navigation) -->
<div class="flex lg:hidden gap-3 flex-wrap justify-center order-3">
<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">
<i data-lucide="check-square" class="w-5 h-5"></i>
<span>Auswahl</span>
</button>
<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)">
<i data-lucide="calendar-check" class="w-5 h-5"></i>
<span>Ausfüllen</span>
</button>
<button 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">
<i data-lucide="file-text" class="w-5 h-5"></i>
<span>PDF Export</span>
</button>
</div>
</div>
</div>
@@ -789,8 +833,12 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
<!-- App Logic -->
<script src="app.js"></script>
<!-- App Logic - Load in correct order -->
<script src="js/state.js"></script>
<script src="js/utils.js"></script>
<script src="js/holidays.js"></script>
<script src="js/api.js"></script>
<script src="js/main.js"></script>
<!-- Initialize Lucide Icons -->
<script>