Add initial schema for entries and settings tables

- Created 'entries' table to track time entries with fields for date, start time, end time, pause minutes, location, and entry type.
- Created 'settings' table to store key-value pairs for application settings with an updated timestamp.
This commit is contained in:
Felix Schlusche
2025-10-23 14:27:25 +02:00
parent b2823731f1
commit b0dd773fba
10 changed files with 1345 additions and 308 deletions

View File

@@ -8,6 +8,9 @@
<!-- Tailwind CSS via CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<!-- Flatpickr CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
@@ -15,6 +18,115 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/themes/dark.css">
<style>
/* Premium Background with Texture */
body {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
background-attachment: fixed;
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(circle at 20% 50%, rgba(59, 130, 246, 0.05) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(139, 92, 246, 0.05) 0%, transparent 50%),
radial-gradient(circle at 40% 20%, rgba(16, 185, 129, 0.03) 0%, transparent 50%);
pointer-events: none;
z-index: 0;
}
/* Glass morphism effect */
.glass-card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 8px 32px 0 rgba(0, 0, 0, 0.37),
inset 0 1px 0 0 rgba(255, 255, 255, 0.05);
}
/* Premium card with elevation */
.premium-card {
background: linear-gradient(135deg, rgba(51, 65, 85, 0.9) 0%, rgba(30, 41, 59, 0.9) 100%);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow:
0 20px 60px -15px rgba(0, 0, 0, 0.5),
0 8px 20px -8px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.premium-card:hover {
transform: translateY(-2px);
box-shadow:
0 30px 80px -20px rgba(0, 0, 0, 0.6),
0 12px 30px -10px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
/* Gradient text */
.gradient-text {
background: linear-gradient(135deg, #60a5fa 0%, #a78bfa 50%, #34d399 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Elevated button styles */
.btn-elevated {
box-shadow:
0 4px 14px 0 rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.btn-elevated::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.btn-elevated:hover::before {
left: 100%;
}
.btn-elevated:hover {
transform: translateY(-2px);
box-shadow:
0 8px 20px 0 rgba(0, 0, 0, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.btn-elevated:active {
transform: translateY(0);
box-shadow:
0 2px 8px 0 rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
/* Table with depth */
.premium-table {
background: linear-gradient(180deg, rgba(31, 41, 55, 0.95) 0%, rgba(17, 24, 39, 0.95) 100%);
backdrop-filter: blur(10px);
box-shadow:
0 10px 40px -10px rgba(0, 0, 0, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.05);
}
/* Custom styles for better tumbler/wheel experience */
.flatpickr-time input {
font-size: 1.2rem;
@@ -33,11 +145,29 @@
/* Editable cell styles */
.editable-cell {
cursor: pointer;
transition: background-color 0.2s;
transition: all 0.2s ease;
position: relative;
}
.editable-cell::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
transition: all 0.3s ease;
transform: translateX(-50%);
}
.editable-cell:hover::after {
width: 80%;
}
.editable-cell:hover {
background-color: #374151;
background: linear-gradient(180deg, rgba(59, 130, 246, 0.1) 0%, rgba(139, 92, 246, 0.05) 100%);
transform: translateY(-1px);
}
.editable-cell.editing {
@@ -52,6 +182,7 @@
font-size: 0.875rem;
background-color: #1f2937;
color: #f3f4f6;
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
}
/* Toast Notification Styles */
@@ -68,34 +199,37 @@
.toast {
padding: 16px 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: 12px;
box-shadow:
0 10px 40px rgba(0, 0, 0, 0.3),
0 0 0 1px rgba(255, 255, 255, 0.1) inset;
display: flex;
align-items: center;
gap: 12px;
animation: slideIn 0.3s ease-out;
font-size: 14px;
font-weight: 500;
backdrop-filter: blur(10px);
}
@keyframes slideIn {
from {
transform: translateX(400px);
transform: translateX(400px) scale(0.9);
opacity: 0;
}
to {
transform: translateX(0);
transform: translateX(0) scale(1);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
transform: translateX(0) scale(1);
opacity: 1;
}
to {
transform: translateX(400px);
transform: translateX(400px) scale(0.9);
opacity: 0;
}
}
@@ -105,17 +239,17 @@
}
.toast-success {
background-color: #10b981;
background: linear-gradient(135deg, rgba(16, 185, 129, 0.95), rgba(5, 150, 105, 0.95));
color: white;
}
.toast-error {
background-color: #ef4444;
background: linear-gradient(135deg, rgba(239, 68, 68, 0.95), rgba(220, 38, 38, 0.95));
color: white;
}
.toast-info {
background-color: #3b82f6;
background: linear-gradient(135deg, rgba(59, 130, 246, 0.95), rgba(37, 99, 235, 0.95));
color: white;
}
@@ -123,33 +257,146 @@
font-size: 20px;
flex-shrink: 0;
}
/* Blink animation for running timer icon */
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.timer-running-icon {
animation: blink 2s ease-in-out infinite;
filter: drop-shadow(0 0 8px rgba(59, 130, 246, 0.6));
}
/* Stat card glow effect */
.stat-card {
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
.stat-card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
opacity: 0;
transition: opacity 0.3s ease;
}
.stat-card:hover::before {
opacity: 1;
}
.stat-card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
/* Input fields with premium styling */
input[type="text"],
input[type="number"],
select {
background: rgba(31, 41, 55, 0.8) !important;
border: 1px solid rgba(255, 255, 255, 0.1) !important;
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
0 0 0 1px rgba(255, 255, 255, 0.05) !important;
transition: all 0.3s ease !important;
}
input[type="text"]:focus,
input[type="number"]:focus,
select:focus {
border-color: rgba(59, 130, 246, 0.5) !important;
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
0 0 0 3px rgba(59, 130, 246, 0.1),
0 0 20px rgba(59, 130, 246, 0.2) !important;
outline: none !important;
}
/* Scrollbar styling */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: rgba(15, 23, 42, 0.5);
}
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #475569, #334155);
border-radius: 5px;
border: 2px solid rgba(15, 23, 42, 0.5);
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, #64748b, #475569);
}
</style>
</head>
<body class="bg-gray-900 min-h-screen">
<body class="min-h-screen relative">
<!-- Toast Container -->
<div id="toastContainer" class="toast-container"></div>
<div class="container mx-auto px-4 py-8 max-w-6xl">
<div class="container mx-auto px-4 py-8 max-w-6xl relative z-10">
<!-- Header -->
<div class="bg-gray-800 rounded-lg shadow-md p-6 mb-6 border border-gray-700">
<h1 class="text-3xl font-bold text-gray-100 mb-4">⏱️ Zeiterfassung</h1>
<div class="premium-card rounded-xl p-6 mb-8">
<h1 class="text-4xl font-bold mb-4 flex items-center gap-3 text-white">
<i data-lucide="clock" class="w-10 h-10 text-white"></i>
Zeiterfassung
</h1>
<!-- Start/Stop Timer Section -->
<div class="mb-6 p-4 bg-gradient-to-r from-gray-700 to-gray-800 rounded-lg border border-gray-600">
<div class="mb-6 p-6 glass-card rounded-xl">
<div class="flex flex-wrap items-center justify-between gap-4">
<div>
<div class="text-sm text-gray-400 mb-1">Heutige Arbeitszeit</div>
<div id="timerDisplay" class="text-4xl font-bold text-gray-100">00:00:00</div>
<div id="timerStatus" class="text-sm text-gray-400 mt-1">Nicht gestartet</div>
<div class="text-sm text-gray-400 mb-2 font-medium">Heutige Arbeitszeit</div>
<div id="timerDisplay" class="text-5xl font-bold text-white">00:00:00</div>
<button id="timerStatus" class="text-sm text-blue-400 hover:text-blue-300 mt-2 underline cursor-pointer transition-all" title="Startzeit manuell eingeben">
Nicht gestartet
</button>
<input type="text" id="manualStartTimeInput" class="hidden">
</div>
<div class="flex gap-3">
<button id="btnStartWork"
class="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-2xl shadow-md" title="Start">
▶️
class="btn-elevated inline-flex items-center justify-center gap-2 px-8 py-4 bg-gradient-to-r from-green-600 to-green-500 text-white rounded-xl font-semibold text-lg" title="Start">
<i data-lucide="play" class="w-6 h-6"></i>
<span>Start</span>
</button>
<button id="btnStopWork" disabled
class="px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors text-2xl shadow-md disabled:opacity-50 disabled:cursor-not-allowed" title="Stop">
⏹️
class="btn-elevated inline-flex items-center justify-center gap-2 px-8 py-4 bg-gradient-to-r from-red-600 to-red-500 text-white rounded-xl font-semibold text-lg disabled:opacity-50 disabled:cursor-not-allowed" title="Stop">
<i data-lucide="square" class="w-6 h-6"></i>
<span>Stop</span>
</button>
</div>
</div>
</div>
<!-- Manual Start Time Picker Modal -->
<div id="manualTimePickerModal" class="hidden fixed inset-0 bg-black bg-opacity-70 backdrop-blur-sm flex items-center justify-center z-50">
<div class="premium-card rounded-2xl p-8 max-w-sm w-full mx-4">
<h3 class="text-xl font-bold text-gray-100 mb-6">Startzeit eingeben</h3>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-300 mb-2">Zeit (HH:MM)</label>
<input type="text" id="manualTimeInput"
class="w-full px-4 py-3 bg-gray-700 text-gray-100 border border-gray-600 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 text-lg"
placeholder="09:00" readonly>
</div>
<div class="flex gap-3">
<button id="btnConfirmManualTime"
class="btn-elevated flex-1 px-4 py-3 bg-gradient-to-r from-blue-600 to-blue-500 text-white rounded-xl font-semibold">
Bestätigen
</button>
<button id="btnCancelManualTime"
class="flex-1 px-4 py-2.5 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 font-medium">
Abbrechen
</button>
</div>
</div>
@@ -171,25 +418,25 @@
placeholder="DD.MM.YYYY">
</div>
<div class="flex gap-3">
<div class="flex gap-2">
<button id="btnFilter"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-xl" title="Filtern">
🔍
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="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-xl" title="Filter zurücksetzen">
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="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-xl" title="Export (alle)">
📥
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="px-4 py-2 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors text-xl" title="Export (nur Abweichungen)">
⚠️
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>
@@ -223,43 +470,73 @@
<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>
</details>
</div>
<!-- Statistics -->
<div class="mb-6 bg-gray-800 rounded-lg shadow-md p-6 border border-gray-700">
<h2 class="text-xl font-bold text-gray-100 mb-4">📊 Statistiken</h2>
<div class="mb-8 premium-card rounded-xl p-6">
<h2 class="text-2xl font-bold text-gray-100 mb-6 flex items-center gap-2">
<i data-lucide="bar-chart-3" class="w-7 h-7 text-blue-400"></i>
Statistiken
</h2>
<!-- Current Month Stats -->
<div class="mb-4">
<h3 class="text-sm font-semibold text-gray-300 mb-2">Aktueller Monat</h3>
<div class="mb-6">
<h3 class="text-sm font-semibold text-gray-300 mb-3 uppercase tracking-wider">Aktueller Monat</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
<div class="text-sm text-gray-400 mb-1">Soll</div>
<div id="statTargetHours" class="text-2xl font-bold text-gray-100">0h</div>
<div class="stat-card glass-card rounded-xl p-5 border border-gray-600">
<div class="text-xs text-gray-400 mb-2 uppercase tracking-wide">Soll</div>
<div id="statTargetHours" class="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-cyan-400">0h</div>
</div>
<div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
<div class="text-sm text-gray-400 mb-1">Ist</div>
<div id="statActualHours" class="text-2xl font-bold text-gray-100">0h</div>
<div class="stat-card glass-card rounded-xl p-5 border border-gray-600">
<div class="text-xs text-gray-400 mb-2 uppercase tracking-wide">Ist</div>
<div id="statActualHours" class="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-emerald-400">0h</div>
</div>
<div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
<div class="text-sm text-gray-400 mb-1">Saldo (Monat)</div>
<div id="statBalance" class="text-2xl font-bold text-gray-100">0h</div>
<div class="stat-card glass-card rounded-xl p-5 border border-gray-600">
<div class="text-xs text-gray-400 mb-2 uppercase tracking-wide">Saldo (Monat)</div>
<div id="statBalance" class="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400">0h</div>
</div>
<div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
<div class="text-sm text-gray-400 mb-1">Arbeitstage</div>
<div id="statWorkdays" class="text-2xl font-bold text-gray-100">0</div>
<div class="stat-card glass-card rounded-xl p-5 border border-gray-600">
<div class="text-xs text-gray-400 mb-2 uppercase tracking-wide">Arbeitstage</div>
<div id="statWorkdays" class="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-orange-400">0</div>
</div>
</div>
</div>
<!-- Vacation Stats -->
<div class="mb-6">
<h3 id="vacationYearLabel" class="text-sm font-semibold text-gray-300 mb-3 flex items-center gap-2 uppercase tracking-wider">
<i data-lucide="plane" class="w-4 h-4 text-amber-400"></i>
Urlaub 2025
</h3>
<div class="grid grid-cols-3 gap-4">
<div class="stat-card glass-card rounded-xl p-5 border border-yellow-600/30">
<div class="text-xs text-yellow-300 mb-2 uppercase tracking-wide">Genommen</div>
<div id="statVacationTaken" class="text-3xl font-bold text-yellow-100">0</div>
</div>
<div class="stat-card glass-card rounded-xl p-5 border border-cyan-600/30">
<div class="text-xs text-cyan-300 mb-2 uppercase tracking-wide">Geplant</div>
<div id="statVacationPlanned" class="text-3xl font-bold text-cyan-100">0</div>
</div>
<div class="stat-card glass-card rounded-xl p-5 border border-green-600/30">
<div class="text-xs text-green-300 mb-2 uppercase tracking-wide">Verfügbar</div>
<div id="statVacationRemaining" class="text-3xl font-bold text-green-100">0 / 30</div>
</div>
</div>
</div>
<!-- Total Balance -->
<div class="bg-gradient-to-r from-gray-700 to-gray-600 rounded-lg p-4 border border-gray-600">
<div class="glass-card rounded-xl p-6 border-2 border-purple-500/30 shadow-lg shadow-purple-500/20">
<div class="flex justify-between items-center">
<div>
<div class="text-sm text-gray-300 mb-1">Gesamt-Saldo (inkl. Vormonat)</div>
<div id="statTotalBalance" class="text-3xl font-bold text-gray-100">0h</div>
<div class="text-sm text-gray-300 mb-2 uppercase tracking-wide font-semibold">Gesamt-Saldo (inkl. Vormonat)</div>
<div id="statTotalBalance" class="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-purple-400 via-pink-400 to-blue-400">0h</div>
</div>
<div class="text-right">
<div class="text-xs text-gray-400">Übertrag Vormonat</div>
@@ -270,34 +547,32 @@
</div>
<!-- Month Navigation -->
<div class="mb-6 bg-gray-800 rounded-lg shadow-md p-4 border border-gray-700">
<div class="flex items-center justify-between">
<div class="flex gap-3">
<button id="btnAddEntry"
class="px-4 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors text-xl" title="Neuer Eintrag">
<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">
<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>
<span>Auswahl</span>
</button>
<button id="btnAutoFill"
class="px-4 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors text-xl" title="Monat ausfüllen (8h)">
🔄
</button>
<button id="btnToggleBulkEdit"
class="px-4 py-3 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-xl" title="Mehrfachauswahl aktivieren">
☑️
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>
</div>
<div class="flex items-center gap-4">
<div id="monthNavigation" class="flex items-center gap-4">
<button id="btnPrevMonth"
class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-xl">
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>
</button>
<h2 id="currentMonthDisplay" class="text-2xl font-bold text-gray-100 min-w-[200px] text-center">
<h2 id="currentMonthDisplay" class="text-2xl font-bold text-white min-w-[200px] text-center">
<!-- Month name will be inserted here -->
</h2>
<button id="btnNextMonth"
class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-xl">
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-right" class="w-6 h-6"></i>
</button>
</div>
@@ -306,65 +581,81 @@
</div>
<!-- Bulk Edit Actions Bar -->
<div id="bulkEditBar" class="hidden mb-6 bg-amber-900 rounded-lg shadow-md p-4 border border-amber-700">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<span id="selectedCount" class="text-white font-semibold">0 ausgewählt</span>
<div id="bulkEditBar" class="hidden mb-6 bg-gray-800 rounded-lg shadow p-4 border border-gray-700">
<div class="flex items-center justify-between flex-wrap gap-3">
<div class="flex items-center gap-3">
<span id="selectedCount" class="text-gray-300 font-medium">0 ausgewählt</span>
<button id="btnSelectAll"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-semibold">
Alle auswählen
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 text-sm font-medium">
<i data-lucide="check-check" class="w-4 h-4"></i>
<span>Alle</span>
</button>
<button id="btnDeselectAll"
class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-sm font-semibold">
Auswahl aufheben
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 text-sm font-medium">
<i data-lucide="x" class="w-4 h-4"></i>
<span>Keine</span>
</button>
</div>
<div class="flex gap-3">
<div class="flex gap-2 flex-wrap">
<button id="btnBulkSetOffice"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-semibold" title="Alle auf Präsenz setzen">
🏢 Präsenz
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 text-sm font-medium shadow-sm" title="Alle auf Präsenz setzen">
<i data-lucide="building-2" class="w-4 h-4"></i>
<span>Präsenz</span>
</button>
<button id="btnBulkSetHome"
class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm font-semibold" title="Alle auf Home Office setzen">
🏠 Home Office
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-all duration-200 text-sm font-medium shadow-sm" title="Alle auf Home Office setzen">
<i data-lucide="home" class="w-4 h-4"></i>
<span>Home</span>
</button>
<button id="btnBulkSetVacation"
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-all duration-200 text-sm font-medium shadow-sm" title="Urlaub eintragen">
<i data-lucide="plane" class="w-4 h-4"></i>
<span>Urlaub</span>
</button>
<button id="btnBulkSetFlextime"
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-cyan-600 text-white rounded-lg hover:bg-cyan-700 transition-all duration-200 text-sm font-medium shadow-sm" title="Gleittage eintragen">
<i data-lucide="clock" class="w-4 h-4"></i>
<span>Gleitzeit</span>
</button>
<button id="btnBulkDelete"
class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors text-sm font-semibold" title="Ausgewählte löschen">
🗑️ Löschen
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-all duration-200 text-sm font-medium shadow-sm" title="Ausgewählte löschen">
<i data-lucide="trash-2" class="w-4 h-4"></i>
<span>Löschen</span>
</button>
</div>
</div>
</div>
<!-- Entries Table -->
<div class="bg-gray-800 rounded-lg shadow-md overflow-hidden border border-gray-700">
<div class="premium-table rounded-xl overflow-hidden border border-gray-700/50 shadow-2xl">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-700 border-b border-gray-600">
<thead class="bg-gradient-to-r from-gray-800 to-gray-700 border-b-2 border-blue-500/30">
<tr>
<th id="checkboxHeader" class="hidden px-2 py-3 text-center text-xs font-medium text-gray-400 uppercase tracking-wider">
<th id="checkboxHeader" class="hidden px-2 py-4 text-center text-xs font-bold 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">
</th>
<th class="px-2 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Tag</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Datum</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Start</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Ende</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Pause (Min)</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Netto (Std)</th>
<th class="px-6 py-3 text-center text-xs font-medium text-gray-400 uppercase tracking-wider">Ort</th>
<th class="px-6 py-3 text-center text-xs font-medium text-gray-400 uppercase tracking-wider">Action</th>
<th class="px-2 py-4 text-left text-xs font-bold 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-6 py-4 text-left text-xs font-bold 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-6 py-4 text-left text-xs font-bold text-gray-300 uppercase tracking-wider">Pause (Min)</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-6 py-4 text-center text-xs font-bold 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>
</tr>
</thead>
<tbody id="entriesTableBody" class="bg-gray-800 divide-y divide-gray-700">
<tbody id="entriesTableBody" class="divide-y divide-gray-700/50">
<!-- Entries will be inserted here dynamically -->
</tbody>
</table>
</div>
<!-- Empty State -->
<div id="emptyState" class="hidden p-12 text-center">
<p class="text-gray-400 text-lg">Keine Einträge vorhanden.</p>
<div id="emptyState" class="hidden p-16 text-center">
<i data-lucide="inbox" class="w-16 h-16 mx-auto mb-4 text-gray-600"></i>
<p class="text-gray-400 text-xl font-semibold">Keine Einträge vorhanden.</p>
<p class="text-gray-500 mt-2">Klicken Sie auf "Neuer Eintrag", um zu beginnen.</p>
</div>
</div>
@@ -438,12 +729,14 @@
</label>
<div class="flex gap-3">
<button type="button" id="btnLocationOffice"
class="flex-1 px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold flex items-center justify-center gap-2">
🏢 Präsenz
class="flex-1 px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 font-medium flex items-center justify-center gap-2 shadow-sm">
<i data-lucide="building-2" class="w-5 h-5"></i>
<span>Präsenz</span>
</button>
<button type="button" id="btnLocationHome"
class="flex-1 px-4 py-3 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors font-semibold flex items-center justify-center gap-2">
🏠 Home Office
class="flex-1 px-4 py-3 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 font-medium flex items-center justify-center gap-2">
<i data-lucide="home" class="w-5 h-5"></i>
<span>Home Office</span>
</button>
</div>
<input type="hidden" id="modalLocation" value="office">
@@ -452,12 +745,14 @@
<!-- Buttons -->
<div class="flex gap-3 mt-6">
<button type="submit"
class="flex-1 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold">
Speichern
class="flex-1 inline-flex items-center justify-center gap-2 px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 font-medium shadow-sm">
<i data-lucide="check" class="w-5 h-5"></i>
<span>Speichern</span>
</button>
<button type="button" id="btnCancelModal"
class="flex-1 px-6 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition-colors font-semibold">
Abbrechen
class="flex-1 inline-flex items-center justify-center gap-2 px-6 py-2.5 bg-gray-700 text-gray-100 rounded-lg hover:bg-gray-600 transition-all duration-200 font-medium">
<i data-lucide="x" class="w-5 h-5"></i>
<span>Abbrechen</span>
</button>
</div>
</form>
@@ -470,5 +765,10 @@
<!-- App Logic -->
<script src="app.js"></script>
<!-- Initialize Lucide Icons -->
<script>
lucide.createIcons();
</script>
</body>
</html>