331 lines
20 KiB
HTML
331 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="description" content="MYP Platform - Mercedes-Benz 3D Druck Management System">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<meta name="theme-color" content="#000000">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
|
|
<title>{% block title %}MYP Platform - Mercedes-Benz{% endblock %}</title>
|
|
|
|
<!-- PWA Manifest -->
|
|
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
|
|
|
|
<!-- Optimized CSS Bundle -->
|
|
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
|
|
<link href="{{ url_for('static', filename='css/components.min.css') }}" rel="stylesheet">
|
|
|
|
<!-- FontAwesome -->
|
|
<link href="{{ url_for('static', filename='fontawesome/css/all.min.css') }}" rel="stylesheet">
|
|
|
|
{% block extra_css %}{% endblock %}
|
|
|
|
<!-- Dark Mode Script -->
|
|
<script>
|
|
(function(){
|
|
const savedMode = localStorage.getItem('myp-dark-mode');
|
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
const isDark = savedMode === 'true' || (savedMode === null && prefersDark);
|
|
|
|
if (isDark) {
|
|
document.documentElement.classList.add('dark');
|
|
document.querySelector('meta[name="theme-color"]').content = '#000000';
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
document.querySelector('meta[name="theme-color"]').content = '#ffffff';
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
{% block head %}{% endblock %}
|
|
</head>
|
|
|
|
<body class="min-h-screen bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100">
|
|
<!-- Navigation Bar -->
|
|
<nav class="bg-white dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex items-center justify-between h-16">
|
|
<!-- Logo -->
|
|
<div class="flex items-center">
|
|
<a href="{{ url_for('dashboard') if current_user.is_authenticated else url_for('index') }}" class="flex items-center space-x-3">
|
|
<div class="w-8 h-8">
|
|
<svg class="w-full h-full text-slate-900 dark:text-white" fill="currentColor" viewBox="0 0 80 80">
|
|
<path d="M58.6,4.5C53,1.6,46.7,0,40,0c-6.7,0-13,1.6-18.6,4.5v0C8.7,11.2,0,24.6,0,40c0,15.4,8.7,28.8,21.5,35.5C27,78.3,33.3,80,40,80c6.7,0,12.9-1.7,18.5-4.6C71.3,68.8,80,55.4,80,40C80,24.6,71.3,11.2,58.6,4.5z M4,40c0-13.1,7-24.5,17.5-30.9v0C26.6,6,32.5,4.2,39,4l-4.5,32.7L21.5,46.8v0L8.3,57.1C5.6,52,4,46.2,4,40z M58.6,70.8C53.1,74.1,46.8,76,40,76c-6.8,0-13.2-1.9-18.6-5.2c-4.9-2.9-8.9-6.9-11.9-11.7l11.9-4.9v0L40,46.6l18.6,7.5v0l12,4.9C67.6,63.9,63.4,67.9,58.6,70.8z M58.6,46.8L58.6,46.8l-12.9-10L41.1,4c6.3,0.2,12.3,2,17.4,5.1v0C69,15.4,76,26.9,76,40c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div class="text-lg font-bold text-slate-900 dark:text-white">MYP Platform</div>
|
|
<div class="text-xs text-slate-600 dark:text-slate-400">Mercedes-Benz</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Navigation Links -->
|
|
{% if current_user.is_authenticated %}
|
|
<div class="hidden md:flex items-center space-x-4">
|
|
{% set current_route = request.endpoint %}
|
|
|
|
<a href="{{ url_for('dashboard') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'dashboard' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-tachometer-alt mr-2"></i>Dashboard
|
|
</a>
|
|
|
|
<a href="{{ url_for('printers_page') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'printers_page' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-print mr-2"></i>Drucker
|
|
</a>
|
|
|
|
<a href="{{ url_for('jobs_page') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'jobs_page' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-tasks mr-2"></i>Aufträge
|
|
</a>
|
|
|
|
<a href="{{ url_for('calendar.calendar_view') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'calendar.calendar_view' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-calendar mr-2"></i>Kalender
|
|
</a>
|
|
|
|
<a href="{{ url_for('energy.energy_dashboard') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'energy.energy_dashboard' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-bolt mr-2"></i>Energie
|
|
</a>
|
|
|
|
<a href="{{ url_for('stats_page') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if current_route == 'stats_page' else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-chart-bar mr-2"></i>Statistiken
|
|
</a>
|
|
|
|
<a href="{{ url_for('tapo_control.tapo_overview') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if 'tapo' in current_route else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-plug mr-2"></i>Smart Plugs
|
|
</a>
|
|
|
|
<a href="{{ url_for('guest.guest_request_form') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-blue-100 dark:bg-blue-900 text-blue-900 dark:text-blue-100' if 'guest' in current_route else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-user-plus mr-2"></i>Gast-Anfrage
|
|
</a>
|
|
|
|
{% if current_user.is_admin %}
|
|
<a href="{{ url_for('admin.admin_dashboard') }}"
|
|
class="px-3 py-2 rounded-md text-sm font-medium {{ 'bg-purple-100 dark:bg-purple-900 text-purple-900 dark:text-purple-100' if 'admin' in current_route else 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700' }}">
|
|
<i class="fas fa-cog mr-2"></i>Admin
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- User Menu -->
|
|
<div class="flex items-center space-x-3">
|
|
<!-- Dark Mode Toggle -->
|
|
<button id="darkModeToggle"
|
|
class="p-2 rounded-lg text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-700"
|
|
title="Farbschema wechseln">
|
|
<svg class="w-5 h-5 sun-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path>
|
|
</svg>
|
|
<svg class="w-5 h-5 moon-icon hidden" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- User Dropdown -->
|
|
<div class="relative">
|
|
<button id="user-menu-button"
|
|
class="flex items-center space-x-2 p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-700"
|
|
aria-expanded="false">
|
|
<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white text-sm font-medium">
|
|
{{ current_user.email[0].upper() if current_user.email else 'U' }}
|
|
</div>
|
|
<span class="hidden sm:block text-sm font-medium text-slate-900 dark:text-white">
|
|
{{ current_user.email.split('@')[0] if current_user.email else 'Benutzer' }}
|
|
</span>
|
|
</button>
|
|
|
|
<div id="user-dropdown"
|
|
class="hidden absolute right-0 mt-2 w-48 bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-slate-200 dark:border-slate-600 z-50">
|
|
<div class="py-1">
|
|
<a href="{{ url_for('users.user_profile') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-user w-4 h-4 mr-3"></i>
|
|
Profil
|
|
</a>
|
|
<a href="{{ url_for('users.user_settings') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-cog w-4 h-4 mr-3"></i>
|
|
Einstellungen
|
|
</a>
|
|
|
|
<a href="{{ url_for('guest.guest_requests_overview') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-clipboard-list w-4 h-4 mr-3"></i>
|
|
Meine Anfragen
|
|
</a>
|
|
|
|
<a href="{{ url_for('legal.system_info') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-info-circle w-4 h-4 mr-3"></i>
|
|
System-Info
|
|
</a>
|
|
|
|
<div class="border-t border-slate-200 dark:border-slate-600"></div>
|
|
|
|
<a href="{{ url_for('legal.imprint') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-building w-4 h-4 mr-3"></i>
|
|
Impressum
|
|
</a>
|
|
|
|
<a href="{{ url_for('legal.privacy') }}"
|
|
class="flex items-center px-4 py-2 text-sm text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<i class="fas fa-shield-alt w-4 h-4 mr-3"></i>
|
|
Datenschutz
|
|
</a>
|
|
|
|
<div class="border-t border-slate-200 dark:border-slate-600"></div>
|
|
<button onclick="handleLogout()"
|
|
class="flex items-center w-full px-4 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20">
|
|
<i class="fas fa-sign-out-alt w-4 h-4 mr-3"></i>
|
|
Abmelden
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<a href="{{ url_for('auth.login') }}"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium">Anmelden</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Flash Messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-4">
|
|
{% for category, message in messages %}
|
|
<div class="mb-4 p-4 rounded-lg {{ 'bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300' if category == 'error' else 'bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300' if category == 'success' else 'bg-yellow-50 dark:bg-yellow-900/20 text-yellow-700 dark:text-yellow-300' if category == 'warning' else 'bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300' }}">
|
|
<div class="flex items-center">
|
|
<i class="fas {{ 'fa-exclamation-triangle' if category == 'error' else 'fa-check-circle' if category == 'success' else 'fa-exclamation-triangle' if category == 'warning' else 'fa-info-circle' }} mr-2"></i>
|
|
{{ message }}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<!-- Main Content -->
|
|
<main class="flex-1 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<!-- Footer -->
|
|
<footer class="bg-white dark:bg-slate-800 border-t border-slate-200 dark:border-slate-700 mt-auto">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="py-8">
|
|
<div class="flex flex-col md:flex-row justify-between items-center">
|
|
<div class="flex items-center space-x-3 mb-4 md:mb-0">
|
|
<div class="w-6 h-6">
|
|
<svg class="w-full h-full text-slate-900 dark:text-white" fill="currentColor" viewBox="0 0 80 80">
|
|
<path d="M58.6,4.5C53,1.6,46.7,0,40,0c-6.7,0-13,1.6-18.6,4.5v0C8.7,11.2,0,24.6,0,40c0,15.4,8.7,28.8,21.5,35.5C27,78.3,33.3,80,40,80c6.7,0,12.9-1.7,18.5-4.6C71.3,68.8,80,55.4,80,40C80,24.6,71.3,11.2,58.6,4.5z M4,40c0-13.1,7-24.5,17.5-30.9v0C26.6,6,32.5,4.2,39,4l-4.5,32.7L21.5,46.8v0L8.3,57.1C5.6,52,4,46.2,4,40z M58.6,70.8C53.1,74.1,46.8,76,40,76c-6.8,0-13.2-1.9-18.6-5.2c-4.9-2.9-8.9-6.9-11.9-11.7l11.9-4.9v0L40,46.6l18.6,7.5v0l12,4.9C67.6,63.9,63.4,67.9,58.6,70.8z M58.6,46.8L58.6,46.8l-12.9-10L41.1,4c6.3,0.2,12.3,2,17.4,5.1v0C69,15.4,76,26.9,76,40c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900 dark:text-white">Mercedes-Benz MYP Platform</div>
|
|
<div class="text-xs text-slate-600 dark:text-slate-400">Manage Your Printers - Version 3.0</div>
|
|
</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 dark:text-slate-400">
|
|
© 2024 Mercedes-Benz Group AG. Alle Rechte vorbehalten.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Essential JavaScript -->
|
|
<script>
|
|
// Logout Handler
|
|
function handleLogout() {
|
|
if (confirm('Möchten Sie sich wirklich abmelden?')) {
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '{{ url_for("auth.logout") }}';
|
|
|
|
const csrfToken = document.querySelector('meta[name="csrf-token"]');
|
|
if (csrfToken) {
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = 'csrf_token';
|
|
input.value = csrfToken.getAttribute('content');
|
|
form.appendChild(input);
|
|
}
|
|
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
}
|
|
|
|
// Simple UI initialization
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Dark mode toggle
|
|
const darkModeToggle = document.getElementById('darkModeToggle');
|
|
if (darkModeToggle) {
|
|
darkModeToggle.addEventListener('click', function() {
|
|
document.documentElement.classList.toggle('dark');
|
|
const isDark = document.documentElement.classList.contains('dark');
|
|
localStorage.setItem('myp-dark-mode', isDark);
|
|
document.querySelector('meta[name="theme-color"]').content = isDark ? '#000000' : '#ffffff';
|
|
|
|
// Update icons
|
|
const sunIcon = document.querySelector('.sun-icon');
|
|
const moonIcon = document.querySelector('.moon-icon');
|
|
if (sunIcon && moonIcon) {
|
|
sunIcon.classList.toggle('hidden', isDark);
|
|
moonIcon.classList.toggle('hidden', !isDark);
|
|
}
|
|
});
|
|
|
|
// Update initial icon state
|
|
const isDark = document.documentElement.classList.contains('dark');
|
|
const sunIcon = document.querySelector('.sun-icon');
|
|
const moonIcon = document.querySelector('.moon-icon');
|
|
if (sunIcon && moonIcon) {
|
|
sunIcon.classList.toggle('hidden', isDark);
|
|
moonIcon.classList.toggle('hidden', !isDark);
|
|
}
|
|
}
|
|
|
|
// User dropdown
|
|
const userMenuButton = document.getElementById('user-menu-button');
|
|
const userDropdown = document.getElementById('user-dropdown');
|
|
if (userMenuButton && userDropdown) {
|
|
userMenuButton.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
userDropdown.classList.toggle('hidden');
|
|
userMenuButton.setAttribute('aria-expanded',
|
|
userDropdown.classList.contains('hidden') ? 'false' : 'true');
|
|
});
|
|
|
|
// Close dropdown when clicking outside
|
|
document.addEventListener('click', function() {
|
|
userDropdown.classList.add('hidden');
|
|
userMenuButton.setAttribute('aria-expanded', 'false');
|
|
});
|
|
|
|
// Prevent dropdown from closing when clicking inside
|
|
userDropdown.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
{% block scripts %}{% endblock %}
|
|
</body>
|
|
</html> |