Files
Projektarbeit-MYP/backend/app/templates/base.html
Till Tomczak e21104611f feat: Update Tailwind CSS integration in base template
- Replaced Tailwind CSS CDN link with a local stylesheet reference to `tailwind.min.css` for improved performance and customization.
- Updated comments to reflect the change in Tailwind CSS sourcing.
2025-05-24 19:32:22 +02:00

504 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}MYP - Mercedes 3D Printing Platform{% endblock %}</title>
<!-- Lokale Tailwind CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/tailwind.min.css') }}">
<!-- Custom CSS für Mercedes Farben -->
<style>
:root {
--mercedes-silver: #C0C0C0;
--mercedes-dark-gray: #2D2D2D;
--mercedes-light-gray: #F5F5F5;
--mercedes-blue: #0066CC;
--mercedes-green: #00B04F;
--mercedes-red: #E60012;
--mercedes-yellow: #FFD700;
--mercedes-black: #000000;
--mercedes-white: #FFFFFF;
}
/* Mercedes Color Classes */
.bg-mercedes-silver { background-color: var(--mercedes-silver); }
.bg-mercedes-dark-gray { background-color: var(--mercedes-dark-gray); }
.bg-mercedes-light-gray { background-color: var(--mercedes-light-gray); }
.bg-mercedes-blue { background-color: var(--mercedes-blue); }
.bg-mercedes-green { background-color: var(--mercedes-green); }
.bg-mercedes-red { background-color: var(--mercedes-red); }
.bg-mercedes-yellow { background-color: var(--mercedes-yellow); }
.bg-mercedes-black { background-color: var(--mercedes-black); }
.bg-mercedes-white { background-color: var(--mercedes-white); }
.text-mercedes-silver { color: var(--mercedes-silver); }
.text-mercedes-dark-gray { color: var(--mercedes-dark-gray); }
.text-mercedes-light-gray { color: var(--mercedes-light-gray); }
.text-mercedes-blue { color: var(--mercedes-blue); }
.text-mercedes-green { color: var(--mercedes-green); }
.text-mercedes-red { color: var(--mercedes-red); }
.text-mercedes-yellow { color: var(--mercedes-yellow); }
.text-mercedes-black { color: var(--mercedes-black); }
.text-mercedes-white { color: var(--mercedes-white); }
.border-mercedes-silver { border-color: var(--mercedes-silver); }
.border-mercedes-dark-gray { border-color: var(--mercedes-dark-gray); }
.border-mercedes-light-gray { border-color: var(--mercedes-light-gray); }
.border-mercedes-blue { border-color: var(--mercedes-blue); }
.border-mercedes-green { border-color: var(--mercedes-green); }
.border-mercedes-red { border-color: var(--mercedes-red); }
.border-mercedes-yellow { border-color: var(--mercedes-yellow); }
.border-mercedes-black { border-color: var(--mercedes-black); }
.border-mercedes-white { border-color: var(--mercedes-white); }
/* Mercedes Gradient */
.mercedes-gradient {
background: linear-gradient(135deg, var(--mercedes-black) 0%, var(--mercedes-dark-gray) 100%);
}
/* Mercedes Shadow */
.mercedes-shadow {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.mercedes-shadow-lg {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
/* Mercedes Button */
.mercedes-button {
transition: all 0.2s ease-in-out;
border-radius: 0.5rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.mercedes-button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.mercedes-button:active {
transform: translateY(0);
}
/* Mercedes Card */
.mercedes-card {
background: var(--mercedes-white);
border: 1px solid var(--mercedes-light-gray);
border-radius: 0.75rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease-in-out;
}
.mercedes-card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
/* Mercedes Input */
.mercedes-input {
border: 2px solid var(--mercedes-light-gray);
border-radius: 0.5rem;
padding: 0.75rem 1rem;
transition: all 0.2s ease-in-out;
background: var(--mercedes-white);
}
.mercedes-input:focus {
outline: none;
border-color: var(--mercedes-blue);
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}
/* Mercedes Table */
.mercedes-table {
background: var(--mercedes-white);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.mercedes-table th {
background: var(--mercedes-dark-gray);
color: var(--mercedes-white);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 1rem;
}
.mercedes-table td {
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--mercedes-light-gray);
}
.mercedes-table tr:hover {
background: var(--mercedes-light-gray);
}
/* Mercedes Modal */
.mercedes-modal {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
.mercedes-modal-content {
background: var(--mercedes-white);
border-radius: 1rem;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
max-height: 90vh;
overflow-y: auto;
}
/* Mercedes Progress Bar */
.mercedes-progress {
background: var(--mercedes-light-gray);
border-radius: 9999px;
overflow: hidden;
}
.mercedes-progress-bar {
background: linear-gradient(90deg, var(--mercedes-blue), var(--mercedes-green));
height: 100%;
transition: width 0.3s ease-in-out;
}
/* Mercedes Status Badges */
.status-online { background: var(--mercedes-green); color: white; }
.status-offline { background: var(--mercedes-red); color: white; }
.status-busy { background: var(--mercedes-yellow); color: var(--mercedes-black); }
.status-maintenance { background: var(--mercedes-silver); color: var(--mercedes-black); }
.status-pending { background: var(--mercedes-yellow); color: var(--mercedes-black); }
.status-printing { background: var(--mercedes-blue); color: white; }
.status-completed { background: var(--mercedes-green); color: white; }
.status-failed { background: var(--mercedes-red); color: white; }
.status-cancelled { background: var(--mercedes-silver); color: var(--mercedes-black); }
/* Mercedes Navigation */
.mercedes-nav-item {
position: relative;
transition: all 0.2s ease-in-out;
}
.mercedes-nav-item:hover::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 2px;
background: var(--mercedes-silver);
}
/* Mercedes Animations */
@keyframes mercedes-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.mercedes-pulse {
animation: mercedes-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes mercedes-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.mercedes-spin {
animation: mercedes-spin 1s linear infinite;
}
/* Mercedes Responsive */
@media (max-width: 768px) {
.mercedes-card {
margin: 0.5rem;
}
.mercedes-table {
font-size: 0.875rem;
}
.mercedes-button {
padding: 0.5rem 1rem;
font-size: 0.875rem;
}
}
/* Mercedes Dark Mode Support */
@media (prefers-color-scheme: dark) {
.mercedes-card {
background: var(--mercedes-dark-gray);
border-color: var(--mercedes-silver);
color: var(--mercedes-white);
}
.mercedes-input {
background: var(--mercedes-dark-gray);
color: var(--mercedes-white);
border-color: var(--mercedes-silver);
}
}
</style>
{% block head %}{% endblock %}
</head>
<body class="h-full bg-gradient-to-br from-mercedes-light-gray to-white font-sans">
<!-- Navigation -->
<nav class="mercedes-gradient mercedes-shadow sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<!-- Logo und Marke -->
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<svg class="h-10 w-10 text-mercedes-silver" 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.5
C27,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,40
c0-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.8
C53.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.9
C67.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,40
c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
</svg>
</div>
<div class="text-white">
<h1 class="text-xl font-bold tracking-wide">MYP</h1>
<p class="text-xs text-mercedes-silver">3D Printing Platform</p>
</div>
</div>
<!-- Navigation Links -->
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-8">
<a href="/dashboard" class="mercedes-nav-item text-white hover:text-mercedes-silver px-3 py-2 text-sm font-medium transition-colors duration-200">
Dashboard
</a>
<a href="/printers" class="mercedes-nav-item text-white hover:text-mercedes-silver px-3 py-2 text-sm font-medium transition-colors duration-200">
Drucker
</a>
<a href="/jobs" class="mercedes-nav-item text-white hover:text-mercedes-silver px-3 py-2 text-sm font-medium transition-colors duration-200">
Jobs
</a>
<a href="/stats" class="mercedes-nav-item text-white hover:text-mercedes-silver px-3 py-2 text-sm font-medium transition-colors duration-200">
Statistiken
</a>
{% if current_user.is_authenticated and current_user.is_admin %}
<a href="/admin" class="mercedes-nav-item text-mercedes-yellow hover:text-white px-3 py-2 text-sm font-medium transition-colors duration-200">
Admin
</a>
{% endif %}
</div>
</div>
<!-- User Menu -->
<div class="flex items-center space-x-4">
{% if current_user.is_authenticated %}
<div class="text-white text-sm">
<span class="text-mercedes-silver">Willkommen,</span>
<span class="font-medium">{{ current_user.email }}</span>
</div>
<button onclick="logout()" class="bg-mercedes-red hover:bg-red-700 text-white px-4 py-2 rounded-lg text-sm font-medium mercedes-button transition-all duration-200">
Abmelden
</button>
{% else %}
<a href="/login" class="bg-mercedes-blue hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-medium mercedes-button transition-all duration-200">
Anmelden
</a>
{% endif %}
</div>
<!-- Mobile menu button -->
<div class="md:hidden">
<button type="button" class="text-white hover:text-mercedes-silver focus:outline-none focus:text-mercedes-silver" onclick="toggleMobileMenu()">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
</div>
</div>
<!-- Mobile menu -->
<div id="mobile-menu" class="md:hidden hidden">
<div class="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-mercedes-gray">
<a href="/dashboard" class="text-white hover:text-mercedes-silver block px-3 py-2 text-base font-medium">Dashboard</a>
<a href="/printers" class="text-white hover:text-mercedes-silver block px-3 py-2 text-base font-medium">Drucker</a>
<a href="/jobs" class="text-white hover:text-mercedes-silver block px-3 py-2 text-base font-medium">Jobs</a>
<a href="/stats" class="text-white hover:text-mercedes-silver block px-3 py-2 text-base font-medium">Statistiken</a>
{% if current_user.is_authenticated and current_user.is_admin %}
<a href="/admin" class="text-mercedes-yellow hover:text-white block px-3 py-2 text-base font-medium">Admin</a>
{% endif %}
</div>
</div>
</nav>
<!-- Flash Messages -->
<div id="flash-messages" class="fixed top-20 right-4 z-40 space-y-2">
<!-- Flash messages will be inserted here by JavaScript -->
</div>
<!-- Main Content -->
<main class="min-h-screen">
{% block content %}{% endblock %}
</main>
<!-- Footer -->
<footer class="mercedes-gradient text-white py-8 mt-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="flex items-center space-x-4 mb-4 md:mb-0">
<svg class="h-8 w-8 text-mercedes-silver" 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.5
C27,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,40
c0-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.8
C53.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.9
C67.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,40
c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
</svg>
<div>
<p class="text-sm font-medium">MYP - 3D Printing Platform</p>
<p class="text-xs text-mercedes-silver">Powered by Mercedes Excellence</p>
</div>
</div>
<div class="text-center md:text-right">
<p class="text-sm text-mercedes-silver">© 2024 MYP Platform. Alle Rechte vorbehalten.</p>
<p class="text-xs text-mercedes-silver mt-1">Version 1.0</p>
</div>
</div>
</div>
</footer>
<!-- JavaScript -->
<script>
// Mobile menu toggle
function toggleMobileMenu() {
const menu = document.getElementById('mobile-menu');
menu.classList.toggle('hidden');
}
// Logout function
async function logout() {
try {
const response = await fetch('/auth/logout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
});
if (response.ok) {
window.location.href = '/login';
} else {
showFlashMessage('Fehler beim Abmelden', 'error');
}
} catch (error) {
showFlashMessage('Netzwerkfehler beim Abmelden', 'error');
}
}
// Flash message system
function showFlashMessage(message, type = 'info') {
const container = document.getElementById('flash-messages');
const messageDiv = document.createElement('div');
let bgColor = 'bg-mercedes-blue';
let textColor = 'text-white';
switch(type) {
case 'success':
bgColor = 'bg-mercedes-green';
break;
case 'error':
bgColor = 'bg-mercedes-red';
break;
case 'warning':
bgColor = 'bg-mercedes-yellow';
textColor = 'text-mercedes-black';
break;
}
messageDiv.className = `${bgColor} ${textColor} px-6 py-3 rounded-lg shadow-lg mercedes-shadow transform transition-all duration-300 translate-x-full`;
messageDiv.innerHTML = `
<div class="flex items-center justify-between">
<span class="font-medium">${message}</span>
<button onclick="this.parentElement.parentElement.remove()" class="ml-4 text-lg font-bold hover:opacity-75">×</button>
</div>
`;
container.appendChild(messageDiv);
// Animate in
setTimeout(() => {
messageDiv.classList.remove('translate-x-full');
}, 100);
// Auto remove after 5 seconds
setTimeout(() => {
messageDiv.classList.add('translate-x-full');
setTimeout(() => {
if (messageDiv.parentElement) {
messageDiv.remove();
}
}, 300);
}, 5000);
}
// API helper function
async function apiCall(url, options = {}) {
try {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'API-Fehler');
}
return data;
} catch (error) {
showFlashMessage(error.message, 'error');
throw error;
}
}
// Format date helper
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleString('de-DE', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
}
// Format duration helper
function formatDuration(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (hours > 0) {
return `${hours}h ${minutes}m ${secs}s`;
} else if (minutes > 0) {
return `${minutes}m ${secs}s`;
} else {
return `${secs}s`;
}
}
</script>
{% block scripts %}{% endblock %}
</body>
</html>