🎉 Improved documentation and logs for better system understanding & maintenance
This commit is contained in:
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
Reference in New Issue
Block a user