🎉 Improved documentation and logs for better system understanding & maintenance

This commit is contained in:
2025-06-01 04:15:25 +02:00
parent 5ee854cbc6
commit 1a3bfa4094
61 changed files with 4413 additions and 4110 deletions

View File

@ -6,10 +6,8 @@
{{ super() }}
<!-- CSRF Token für AJAX-Anfragen -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<script src="{{ url_for('static', filename='js/admin.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/admin-system.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/admin-live.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/admin-dashboard.js') }}" defer></script>
<!-- Konsolidierte Admin JavaScript Datei - verhindert Event-Handler-Konflikte -->
<script src="{{ url_for('static', filename='js/admin-unified.js') }}" defer></script>
<!-- Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center hidden">
@ -577,504 +575,4 @@
</div>
</div>
</div>
<script>
// Hilfsfunktionen sind in admin-system.js definiert
// Funktionen sind in admin-system.js definiert
// Event Listener für Admin-Buttons
document.addEventListener('DOMContentLoaded', function() {
// System Status Button
const systemStatusBtn = document.getElementById('system-status-btn');
if (systemStatusBtn) {
systemStatusBtn.addEventListener('click', function() {
loadSystemStatus();
});
}
// Analytics Button
const analyticsBtn = document.getElementById('analytics-btn');
if (analyticsBtn) {
analyticsBtn.addEventListener('click', function() {
window.location.href = '/analytics';
});
}
// Maintenance Button
const maintenanceBtn = document.getElementById('maintenance-btn');
if (maintenanceBtn) {
maintenanceBtn.addEventListener('click', function() {
showMaintenanceModal();
});
}
// Add User Button
const addUserBtn = document.getElementById('add-user-btn');
if (addUserBtn) {
addUserBtn.addEventListener('click', function() {
window.location.href = '/admin/users/add';
});
}
// Wartungs-Buttons
const clearCacheBtn = document.getElementById('clear-cache-btn');
if (clearCacheBtn) {
clearCacheBtn.addEventListener('click', clearCache);
}
const optimizeDbBtn = document.getElementById('optimize-db-btn');
if (optimizeDbBtn) {
optimizeDbBtn.addEventListener('click', optimizeDatabase);
}
const createBackupBtn = document.getElementById('create-backup-btn');
if (createBackupBtn) {
createBackupBtn.addEventListener('click', createBackup);
}
// Konfigurations-Buttons
const editSettingsBtn = document.getElementById('edit-settings-btn');
if (editSettingsBtn) {
editSettingsBtn.addEventListener('click', editSettings);
}
const updatePrintersBtn = document.getElementById('update-printers-btn');
if (updatePrintersBtn) {
updatePrintersBtn.addEventListener('click', updatePrinters);
}
const restartSystemBtn = document.getElementById('restart-system-btn');
if (restartSystemBtn) {
restartSystemBtn.addEventListener('click', restartSystem);
}
// Benutzer-Management Event Listeners
document.querySelectorAll('.edit-user-btn').forEach(btn => {
btn.addEventListener('click', function() {
const userId = this.dataset.userId;
window.location.href = `/admin/users/${userId}/edit`;
});
});
document.querySelectorAll('.delete-user-btn').forEach(btn => {
btn.addEventListener('click', function() {
const userId = this.dataset.userId;
const userName = this.dataset.userName;
deleteUser(userId, userName);
});
});
// Drucker-Management Event Listeners
document.querySelectorAll('.manage-printer-btn').forEach(btn => {
btn.addEventListener('click', function() {
const printerId = this.dataset.printerId;
window.location.href = `/admin/printers/${printerId}/manage`;
});
});
document.querySelectorAll('.settings-printer-btn').forEach(btn => {
btn.addEventListener('click', function() {
const printerId = this.dataset.printerId;
window.location.href = `/admin/printers/${printerId}/settings`;
});
});
// Logs-Tab Event-Handlers und Funktionen
const refreshLogsBtn = document.getElementById('refresh-logs-btn');
if (refreshLogsBtn) {
refreshLogsBtn.addEventListener('click', loadLogs);
}
const exportLogsBtn = document.getElementById('export-logs-btn');
if (exportLogsBtn) {
exportLogsBtn.addEventListener('click', function() {
window.location.href = '/api/admin/logs/export';
});
}
const logLevelFilter = document.getElementById('log-level-filter');
if (logLevelFilter) {
logLevelFilter.addEventListener('change', function() {
if (window.logsData) {
const level = this.value;
if (level === 'all') {
window.filteredLogs = [...window.logsData];
} else {
window.filteredLogs = window.logsData.filter(log =>
log.level.toLowerCase() === level.toLowerCase()
);
}
renderLogs();
}
});
}
// Logs beim Laden des Logs-Tabs automatisch laden
const urlParams = new URLSearchParams(window.location.search);
const activeTab = urlParams.get('tab');
if (activeTab === 'logs') {
// Kurz warten, damit das DOM vollständig geladen ist
setTimeout(loadLogs, 500);
}
// Start Live-Updates
startLiveUpdates();
});
// System Status laden und anzeigen
async function loadSystemStatus() {
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/system/status');
const data = await response.json();
if (data.success) {
showSystemStatusModal(data.status);
} else {
showNotification('Fehler beim Laden des System-Status', 'error');
}
} catch (error) {
console.error('System Status Fehler:', error);
showNotification('Verbindungsfehler beim Laden des System-Status', 'error');
} finally {
showLoadingOverlay(false);
}
}
// System Status Modal anzeigen
function showSystemStatusModal(status) {
const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black/60 backdrop-blur-sm z-50';
modal.innerHTML = `
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white dark:bg-slate-800 rounded-2xl p-8 max-w-2xl w-full shadow-2xl">
<div class="flex justify-between items-center mb-6">
<h3 class="text-2xl font-bold text-slate-900 dark:text-white">System Status</h3>
<button onclick="this.closest('.fixed').remove()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="p-4 bg-green-100 dark:bg-green-900/30 rounded-lg">
<h4 class="font-semibold text-green-800 dark:text-green-300">CPU Nutzung</h4>
<p class="text-2xl font-bold text-green-600">${status.cpu_usage || '12'}%</p>
</div>
<div class="p-4 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
<h4 class="font-semibold text-blue-800 dark:text-blue-300">RAM Nutzung</h4>
<p class="text-2xl font-bold text-blue-600">${status.memory_usage || '45'}%</p>
</div>
<div class="p-4 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
<h4 class="font-semibold text-purple-800 dark:text-purple-300">Festplatte</h4>
<p class="text-2xl font-bold text-purple-600">${status.disk_usage || '67'}%</p>
</div>
<div class="p-4 bg-orange-100 dark:bg-orange-900/30 rounded-lg">
<h4 class="font-semibold text-orange-800 dark:text-orange-300">Uptime</h4>
<p class="text-2xl font-bold text-orange-600">${status.uptime || '24h 15m'}</p>
</div>
</div>
<div class="mt-6 text-center">
<button onclick="this.closest('.fixed').remove()" class="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Schließen
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
}
// Wartungsmodus Modal anzeigen
function showMaintenanceModal() {
const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black/60 backdrop-blur-sm z-50';
modal.innerHTML = `
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white dark:bg-slate-800 rounded-2xl p-8 max-w-md w-full shadow-2xl">
<div class="flex justify-between items-center mb-6">
<h3 class="text-xl font-bold text-slate-900 dark:text-white">Wartungsmodus</h3>
<button onclick="this.closest('.fixed').remove()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<div class="space-y-4">
<button onclick="activateMaintenanceMode()" class="w-full px-4 py-3 bg-orange-600 text-white rounded-lg hover:bg-orange-700">
Wartungsmodus aktivieren
</button>
<button onclick="deactivateMaintenanceMode()" class="w-full px-4 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700">
Wartungsmodus deaktivieren
</button>
<button onclick="scheduleMaintenanceWindow()" class="w-full px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Wartungsfenster planen
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
}
// Wartungsmodus-Funktionen
async function activateMaintenanceMode() {
try {
const response = await fetch('/api/admin/maintenance/activate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Wartungsmodus aktiviert', 'success');
document.querySelector('.fixed').remove();
} else {
showNotification('Fehler beim Aktivieren des Wartungsmodus', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
}
}
async function deactivateMaintenanceMode() {
try {
const response = await fetch('/api/admin/maintenance/deactivate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Wartungsmodus deaktiviert', 'success');
document.querySelector('.fixed').remove();
} else {
showNotification('Fehler beim Deaktivieren des Wartungsmodus', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
}
}
// Cache leeren
async function clearCache() {
if (!confirm('Möchten Sie den Cache wirklich leeren?')) return;
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/cache/clear', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Cache erfolgreich geleert', 'success');
} else {
showNotification('Fehler beim Leeren des Cache', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
} finally {
showLoadingOverlay(false);
}
}
// Datenbank optimieren
async function optimizeDatabase() {
if (!confirm('Möchten Sie die Datenbank optimieren? Dies kann einige Minuten dauern.')) return;
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/database/optimize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Datenbank erfolgreich optimiert', 'success');
} else {
showNotification('Fehler bei der Datenbankoptimierung', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
} finally {
showLoadingOverlay(false);
}
}
// Backup erstellen
async function createBackup() {
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/database/backup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Backup erfolgreich erstellt', 'success');
} else {
showNotification('Fehler beim Erstellen des Backups', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
} finally {
showLoadingOverlay(false);
}
}
// Einstellungen bearbeiten
function editSettings() {
window.location.href = '/admin/settings';
}
// Drucker aktualisieren
async function updatePrinters() {
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/printers/update-all', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Drucker erfolgreich aktualisiert', 'success');
setTimeout(() => window.location.reload(), 2000);
} else {
showNotification('Fehler beim Aktualisieren der Drucker', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
} finally {
showLoadingOverlay(false);
}
}
// System neustarten
async function restartSystem() {
if (!confirm('Möchten Sie das System wirklich neustarten? Alle Verbindungen werden unterbrochen.')) return;
try {
showLoadingOverlay(true);
const response = await fetch('/api/admin/system/restart', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
showNotification('System wird neu gestartet...', 'info');
// Weiterleitung nach 5 Sekunden
setTimeout(() => {
window.location.href = '/';
}, 5000);
} catch (error) {
showNotification('Verbindungsfehler', 'error');
showLoadingOverlay(false);
}
}
// Benutzer löschen
async function deleteUser(userId, userName) {
if (!confirm(`Möchten Sie den Benutzer "${userName}" wirklich löschen?`)) return;
try {
showLoadingOverlay(true);
const response = await fetch(`/api/admin/users/${userId}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
showNotification('Benutzer erfolgreich gelöscht', 'success');
setTimeout(() => window.location.reload(), 1000);
} else {
showNotification('Fehler beim Löschen des Benutzers', 'error');
}
} catch (error) {
showNotification('Verbindungsfehler', 'error');
} finally {
showLoadingOverlay(false);
}
}
// Live-Updates starten
function startLiveUpdates() {
setInterval(async () => {
try {
const response = await fetch('/api/admin/stats/live');
const data = await response.json();
if (data.success) {
updateLiveStats(data.stats);
}
} catch (error) {
console.log('Live-Update Fehler:', error);
}
}, 10000); // Alle 10 Sekunden
}
// Live-Statistiken aktualisieren
function updateLiveStats(stats) {
const elements = {
'live-users-count': stats.total_users,
'live-printers-count': stats.total_printers,
'live-printers-online': stats.online_printers,
'live-jobs-active': stats.active_jobs,
'live-jobs-queued': stats.queued_jobs,
'live-success-rate': stats.success_rate
};
Object.entries(elements).forEach(([id, value]) => {
const element = document.getElementById(id);
if (element && value !== undefined) {
element.textContent = value + (id.includes('rate') ? '%' : '');
}
});
}
// Utility Functions
function showLoadingOverlay(show) {
const overlay = document.getElementById('loading-overlay');
if (overlay) {
overlay.classList.toggle('hidden', !show);
}
}
function showNotification(message, type = 'info') {
const colors = {
success: 'bg-green-600',
error: 'bg-red-600',
warning: 'bg-yellow-600',
info: 'bg-blue-600'
};
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full`;
notification.textContent = message;
document.body.appendChild(notification);
// Animation einblenden
setTimeout(() => {
notification.classList.remove('translate-x-full');
}, 100);
// Automatisch ausblenden nach 5 Sekunden
setTimeout(() => {
notification.classList.add('translate-x-full');
setTimeout(() => notification.remove(), 300);
}, 5000);
}
function scheduleMaintenanceWindow() {
showNotification('Wartungsfenster-Planung noch nicht implementiert', 'info');
document.querySelector('.fixed').remove();
}
</script>
{% endblock %}

View File

@ -27,32 +27,34 @@
.border-mercedes-silver { border-color: #d1d5db; }
.border-mercedes-blue { border-color: #0073ce; }
/* Advanced Calendar Styling */
/* Premium Calendar Container */
.fc {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--fc-border-color: #e2e8f0;
--fc-today-bg-color: rgba(0, 115, 206, 0.08);
--fc-border-color: #d1d5db;
--fc-today-bg-color: rgba(0, 115, 206, 0.12);
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border-radius: 16px;
overflow: hidden;
box-shadow:
0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
border: 1px solid #e5e7eb;
}
.dark .fc {
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
--fc-border-color: #334155;
--fc-today-bg-color: rgba(0, 115, 206, 0.15);
border-color: #374151;
}
/* Premium Header Toolbar */
/* Enhanced Header Toolbar */
.fc-header-toolbar {
margin-bottom: 0 !important;
padding: 1.5rem 2rem !important;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border: none !important;
border-bottom: 1px solid #e2e8f0 !important;
border-bottom: 2px solid #e5e7eb !important;
border-radius: 0 !important;
backdrop-filter: blur(10px);
}
@ -62,7 +64,7 @@
border-bottom-color: #334155 !important;
}
/* Premium Buttons */
/* Premium Navigation Buttons */
.fc-button {
background: linear-gradient(135deg, #0073ce 0%, #005ba3 100%) !important;
border: none !important;
@ -121,7 +123,7 @@
background: linear-gradient(135deg, #15803d 0%, #166534 100%) !important;
}
/* Elegant Typography */
/* Calendar Title Typography */
.fc-toolbar-title {
color: #000000 !important;
font-size: 1.875rem !important;
@ -139,11 +141,12 @@
-webkit-text-fill-color: transparent;
}
/* Premium Column Headers */
/* Enhanced Column Headers */
.fc-col-header {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%) !important;
background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%) !important;
border: none !important;
border-bottom: 2px solid #0073ce !important;
border-bottom: 3px solid #0073ce !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.dark .fc-col-header {
@ -157,7 +160,7 @@
font-size: 0.875rem !important;
text-transform: uppercase !important;
letter-spacing: 0.1em !important;
color: #374151 !important;
color: #1f2937 !important;
position: relative !important;
}
@ -165,27 +168,111 @@
color: #e2e8f0 !important;
}
/* Elegant Grid Styling */
/* Optimized Time Grid for Light Mode */
.fc-timegrid-axis {
font-weight: 700 !important;
color: #374151 !important;
font-size: 0.8rem !important;
background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%) !important;
border-right: 2px solid #e5e7eb !important;
text-align: center !important;
min-width: 65px !important;
}
.dark .fc-timegrid-axis {
color: #9ca3af !important;
background: linear-gradient(135deg, #1e293b 0%, #334155 100%) !important;
border-right-color: #374151 !important;
}
.fc-timegrid-axis-cushion {
padding: 0.75rem 0.5rem !important;
font-weight: 700 !important;
color: #1f2937 !important;
background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%) !important;
border-radius: 0 8px 8px 0 !important;
margin-right: 1px !important;
text-align: center !important;
min-width: 60px !important;
}
.dark .fc-timegrid-axis-cushion {
color: #e5e7eb !important;
background: linear-gradient(135deg, #1e293b 0%, #334155 100%) !important;
}
.fc-timegrid-slot-label {
font-variant-numeric: tabular-nums !important;
font-weight: 600 !important;
color: #1f2937 !important;
}
.dark .fc-timegrid-slot-label {
color: #d1d5db !important;
}
/* Enhanced Grid Styling */
.fc-daygrid-day, .fc-timegrid-slot {
border-color: #f1f5f9 !important;
border-color: #e5e7eb !important;
transition: background-color 0.2s ease !important;
background: #ffffff;
}
.dark .fc-daygrid-day, .dark .fc-timegrid-slot {
border-color: #1e293b !important;
background: #0f172a;
}
.fc-timegrid-col {
background: #ffffff !important;
border-left: 1px solid #d1d5db !important;
border-right: 1px solid #d1d5db !important;
}
.dark .fc-timegrid-col {
background: #0f172a !important;
border-left-color: #374151 !important;
border-right-color: #374151 !important;
}
.fc-timegrid-slot:hover {
background: rgba(0, 115, 206, 0.03) !important;
background: rgba(0, 115, 206, 0.06) !important;
}
.dark .fc-timegrid-slot:hover {
background: rgba(0, 115, 206, 0.08) !important;
}
/* Improved Time Slot Lines */
.fc-timegrid-slot-minor {
border-top: 1px solid #f3f4f6 !important;
}
.fc-timegrid-slot-major {
border-top: 2px solid #e5e7eb !important;
}
.dark .fc-timegrid-slot-minor {
border-top-color: #1e293b !important;
}
.dark .fc-timegrid-slot-major {
border-top-color: #374151 !important;
}
.fc-timegrid-body {
border-left: 2px solid #d1d5db !important;
}
.dark .fc-timegrid-body {
border-left-color: #374151 !important;
}
/* Enhanced Today Highlighting */
.fc-day-today {
background: linear-gradient(135deg, rgba(0, 115, 206, 0.08) 0%, rgba(0, 115, 206, 0.04) 100%) !important;
background: linear-gradient(135deg, rgba(0, 115, 206, 0.15) 0%, rgba(0, 115, 206, 0.08) 100%) !important;
position: relative !important;
border: 2px solid rgba(0, 115, 206, 0.3) !important;
}
.fc-day-today::before {
@ -194,13 +281,70 @@
top: 0;
left: 0;
right: 0;
height: 3px;
height: 4px;
background: linear-gradient(90deg, #0073ce, #00a8ff, #0073ce);
border-radius: 0 0 2px 2px;
border-radius: 0 0 4px 4px;
z-index: 10;
}
.dark .fc-day-today {
background: linear-gradient(135deg, rgba(0, 115, 206, 0.15) 0%, rgba(0, 115, 206, 0.08) 100%) !important;
background: linear-gradient(135deg, rgba(0, 115, 206, 0.20) 0%, rgba(0, 115, 206, 0.12) 100%) !important;
border-color: rgba(0, 115, 206, 0.4) !important;
}
/* Enhanced All-Day Events */
.fc-daygrid-body {
background: #ffffff !important;
border: 1px solid #e5e7eb !important;
border-top: none !important;
}
.dark .fc-daygrid-body {
background: #0f172a !important;
border-color: #374151 !important;
}
.fc-daygrid-event-harness {
margin: 2px 4px !important;
}
.fc-daygrid-event {
background: linear-gradient(135deg, #0073ce 0%, #005ba3 100%) !important;
border: none !important;
border-radius: 8px !important;
color: white !important;
font-weight: 600 !important;
font-size: 0.875rem !important;
padding: 0.5rem 0.75rem !important;
box-shadow:
0 4px 6px rgba(0, 115, 206, 0.25),
0 1px 3px rgba(0, 0, 0, 0.1) !important;
min-height: 28px !important;
}
.fc-daygrid-event:hover {
transform: translateY(-1px) !important;
box-shadow:
0 6px 12px rgba(0, 115, 206, 0.3),
0 2px 6px rgba(0, 0, 0, 0.15) !important;
}
.fc-daygrid-more-link {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%) !important;
color: white !important;
border-radius: 6px !important;
font-weight: 600 !important;
padding: 0.25rem 0.5rem !important;
box-shadow: 0 2px 4px rgba(245, 158, 11, 0.3) !important;
}
/* Weekend Highlighting */
.fc-day-sat, .fc-day-sun {
background: linear-gradient(135deg, #fafafa 0%, #f5f5f5 100%) !important;
}
.dark .fc-day-sat, .dark .fc-day-sun {
background: linear-gradient(135deg, #0c1220 0%, #0f172a 100%) !important;
}
/* Premium Event Styling */
@ -255,7 +399,7 @@
letter-spacing: 0.05em !important;
}
/* Premium Status Colors with Gradients */
/* Status-specific Event Colors */
.fc-event.event-running {
background: linear-gradient(135deg, #10b981 0%, #059669 80%, #047857 100%) !important;
color: white !important;
@ -326,21 +470,6 @@
}
}
/* Time Grid Enhancements */
.fc-timegrid-axis {
font-weight: 600 !important;
color: #6b7280 !important;
font-size: 0.75rem !important;
}
.dark .fc-timegrid-axis {
color: #9ca3af !important;
}
.fc-timegrid-slot-label {
font-variant-numeric: tabular-nums !important;
}
/* Premium Form Elements */
.mercedes-form-input {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@ -496,7 +625,7 @@
animation: calendar-load 0.6s ease-out;
}
/* Responsive Enhancements */
/* Responsive Optimizations */
@media (max-width: 768px) {
.fc-toolbar-title {
font-size: 1.25rem !important;
@ -515,6 +644,22 @@
padding: 0.75rem 0.5rem !important;
font-size: 0.75rem !important;
}
.fc-timegrid-axis-cushion {
min-width: 45px !important;
font-size: 0.75rem !important;
padding: 0.5rem 0.25rem !important;
}
.fc-timegrid-axis {
border-right-width: 1px !important;
}
.fc-daygrid-event {
font-size: 0.75rem !important;
padding: 0.375rem 0.5rem !important;
min-height: 24px !important;
}
}
</style>
{% endblock %}