"Update templates for improved UI/UX"

This commit is contained in:
Till Tomczak 2025-05-29 17:24:06 +02:00
parent 731a9fe6f1
commit ef8b5bf177
8 changed files with 299 additions and 461 deletions

View File

@ -1418,6 +1418,12 @@ def jobs_page():
"""Zeigt die Übersichtsseite für Druckaufträge an.""" """Zeigt die Übersichtsseite für Druckaufträge an."""
return render_template("jobs.html") return render_template("jobs.html")
@app.route("/jobs/new")
@login_required
def new_job_page():
"""Zeigt die Seite zum Erstellen neuer Druckaufträge an."""
return render_template("jobs.html")
@app.route("/stats") @app.route("/stats")
@login_required @login_required
def stats_page(): def stats_page():
@ -4343,19 +4349,19 @@ if __name__ == "__main__":
ssl_context = get_ssl_context() ssl_context = get_ssl_context()
if ssl_context: if ssl_context:
app_logger.info("Starte HTTPS-Server auf 0.0.0.0:8443") app_logger.info("Starte HTTPS-Server auf 0.0.0.0:443")
app.run( app.run(
host="0.0.0.0", host="0.0.0.0",
port=8443, port=443,
debug=False, debug=False,
ssl_context=ssl_context, ssl_context=ssl_context,
threaded=True threaded=True
) )
else: else:
app_logger.info("Starte HTTP-Server auf 0.0.0.0:8080") app_logger.info("Starte HTTP-Server auf 0.0.0.0:80")
app.run( app.run(
host="0.0.0.0", host="0.0.0.0",
port=8080, port=80,
debug=False, debug=False,
threaded=True threaded=True
) )
@ -4371,9 +4377,3 @@ if __name__ == "__main__":
except: except:
pass pass
sys.exit(1) sys.exit(1)
try:
stop_queue_manager()
except:
pass
sys.exit(1)

View File

@ -769,4 +769,5 @@ document.addEventListener('DOMContentLoaded', function() {
}; };
}); });
</script> </script>
{% endblock %}
{% endblock %} {% endblock %}

View File

@ -518,9 +518,9 @@
} }
setupEventListeners() { setupEventListeners() {
// Refresh Button // Refresh Button
const refreshBtn = document.getElementById('refreshDashboard'); const refreshBtn = document.getElementById('refreshDashboard');
if (refreshBtn) { if (refreshBtn) {
refreshBtn.addEventListener('click', () => { refreshBtn.addEventListener('click', () => {
this.refreshDashboard(); this.refreshDashboard();
}); });

View File

@ -32,55 +32,7 @@
} }
.focus\:border-mercedes-blue:focus { border-color: #0073ce; } .focus\:border-mercedes-blue:focus { border-color: #0073ce; }
/* Enhanced Page Header */ /* Enhanced Form Elements */
.guest-header {
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border: 1px solid #e2e8f0;
box-shadow:
0 10px 25px -5px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
position: relative;
overflow: hidden;
}
.dark .guest-header {
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
border-color: #334155;
}
.guest-header::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(0, 115, 206, 0.1), transparent);
transition: left 0.5s;
}
.guest-header:hover::before {
left: 100%;
}
/* Enhanced Form Container */
.guest-form-container {
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border: 1px solid #e2e8f0;
box-shadow:
0 20px 40px -12px rgba(0, 0, 0, 0.1),
0 8px 16px -4px rgba(0, 0, 0, 0.05);
border-radius: 16px;
position: relative;
overflow: hidden;
}
.dark .guest-form-container {
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
border-color: #334155;
}
/* Enhanced Form Inputs */
.mercedes-form-input { .mercedes-form-input {
transition: all 0.2s ease; transition: all 0.2s ease;
border: 1px solid #d1d5db; border: 1px solid #d1d5db;
@ -166,100 +118,6 @@
75% { transform: translateX(5px); } 75% { transform: translateX(5px); }
} }
/* Enhanced Info Banner */
.info-banner {
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
border: 1px solid #bfdbfe;
border-radius: 12px;
position: relative;
overflow: hidden;
}
.dark .info-banner {
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%);
border-color: #3b82f6;
}
.info-banner::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background: linear-gradient(180deg, #3b82f6, #1d4ed8);
}
/* Enhanced Buttons */
.btn-primary {
background: linear-gradient(135deg, #0073ce 0%, #1e40af 100%);
border: none;
color: white;
padding: 0.75rem 2rem;
border-radius: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
display: inline-flex;
align-items: center;
text-decoration: none;
box-shadow: 0 4px 14px 0 rgba(0, 115, 206, 0.39);
}
.btn-primary::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-primary:hover::before {
left: 100%;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(0, 115, 206, 0.5);
}
.btn-secondary {
background: transparent;
border: 2px solid #0073ce;
color: #0073ce;
padding: 0.75rem 2rem;
border-radius: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
text-decoration: none;
}
.btn-secondary:hover {
background: #0073ce;
color: white;
transform: translateY(-2px);
}
.dark .btn-secondary {
border-color: #60a5fa;
color: #60a5fa;
}
.dark .btn-secondary:hover {
background: #60a5fa;
color: #1e293b;
}
/* Progress Indicators */ /* Progress Indicators */
.progress-step { .progress-step {
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%); background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
@ -329,24 +187,6 @@
} }
} }
/* Responsive Design */
@media (max-width: 768px) {
.guest-form-container {
margin: 1rem;
padding: 1.5rem !important;
}
.btn-primary,
.btn-secondary {
width: 100%;
justify-content: center;
}
.upload-area {
height: 120px;
}
}
/* Success Animation */ /* Success Animation */
.success-checkmark { .success-checkmark {
animation: checkmark 0.6s ease-in-out; animation: checkmark 0.6s ease-in-out;
@ -367,6 +207,23 @@
} }
} }
/* Responsive Design */
@media (max-width: 768px) {
.dashboard-card {
padding: 1rem !important;
}
.btn-primary,
.btn-secondary {
width: 100%;
justify-content: center;
}
.upload-area {
height: 120px;
}
}
/* Accessibility Enhancements */ /* Accessibility Enhancements */
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
*, *::before, *::after { *, *::before, *::after {
@ -382,74 +239,54 @@
outline: 2px solid #0073ce; outline: 2px solid #0073ce;
outline-offset: 2px; outline-offset: 2px;
} }
/* Custom Scrollbar */
.custom-scroll::-webkit-scrollbar {
width: 6px;
}
.custom-scroll::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 3px;
}
.custom-scroll::-webkit-scrollbar-thumb {
background: #0073ce;
border-radius: 3px;
}
.custom-scroll::-webkit-scrollbar-thumb:hover {
background: #1e40af;
}
</style> </style>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="space-y-8"> <div class="space-y-8">
<!-- Enhanced Page Header --> <!-- Enhanced Page Header -->
<div class="guest-header p-6 rounded-xl relative"> <div class="dashboard-card p-6">
<div class="relative z-10"> <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6"> <div class="flex items-center gap-6">
<div class="flex items-center gap-4"> <div class="w-16 h-16 flex-shrink-0 bg-mercedes-blue text-white rounded-xl flex items-center justify-center">
<div class="w-16 h-16 flex-shrink-0 bg-mercedes-blue text-white rounded-xl flex items-center justify-center"> <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/> </svg>
</div>
<div>
<h1 class="text-4xl font-bold text-mercedes-black dark:text-white tracking-tight">Gastanfrage</h1>
<p class="text-mercedes-gray dark:text-slate-400 mt-1 text-lg">Stellen Sie Ihre 3D-Druckauftrag Anfrage mit Mercedes-Benz Qualitätsstandards</p>
<div class="flex items-center mt-2 text-sm text-mercedes-blue">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
</div> <span>Bearbeitungszeit: 24-48 Stunden</span>
<div>
<h1 class="text-4xl font-bold text-mercedes-black dark:text-white tracking-tight">Gastanfrage</h1>
<p class="text-mercedes-gray dark:text-slate-400 mt-1 text-lg">Stellen Sie Ihre 3D-Druckauftrag Anfrage</p>
<div class="flex items-center mt-2 text-sm text-mercedes-blue">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Bearbeitungszeit: 24-48 Stunden
</div>
</div> </div>
</div> </div>
<div class="flex flex-wrap gap-3"> </div>
<a href="{{ url_for('guest.guest_requests_overview') if url_for else '/guest/requests' }}" <div class="flex flex-wrap gap-3">
class="btn-secondary flex items-center gap-2"> <a href="{{ url_for('guest.guest_requests_overview') if url_for else '/guest/requests' }}"
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="btn-secondary flex items-center gap-2">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
</svg> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
<span>Anträge Übersicht</span> </svg>
</a> <span>Anträge Übersicht</span>
<a href="{{ url_for('index') if url_for else '/' }}" </a>
class="btn-secondary flex items-center gap-2"> <a href="{{ url_for('index') if url_for else '/' }}"
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="btn-secondary flex items-center gap-2">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
</svg> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
<span>Startseite</span> </svg>
</a> <span>Startseite</span>
</div> </a>
</div> </div>
</div> </div>
</div> </div>
<!-- Progress Indicator --> <!-- Progress Indicator -->
<div class="guest-form-container p-6"> <div class="dashboard-card p-6">
<div class="mb-8"> <div class="mb-8">
<h2 class="text-lg font-semibold text-mercedes-black dark:text-white mb-4">Antrags-Fortschritt</h2>
<div class="flex items-center justify-between max-w-md mx-auto"> <div class="flex items-center justify-between max-w-md mx-auto">
<div class="flex items-center"> <div class="flex items-center">
<div class="progress-step active">1</div> <div class="progress-step active">1</div>
@ -472,8 +309,8 @@
</div> </div>
<!-- Enhanced Info Banner --> <!-- Enhanced Info Banner -->
<div class="info-banner p-6 relative"> <div class="dashboard-card p-6">
<div class="flex items-start gap-4 relative z-10"> <div class="flex items-start gap-4">
<div class="w-12 h-12 bg-blue-500 text-white rounded-xl flex items-center justify-center flex-shrink-0"> <div class="w-12 h-12 bg-blue-500 text-white rounded-xl flex items-center justify-center flex-shrink-0">
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 20 20"> <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/> <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
@ -498,15 +335,15 @@
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 2.26a2 2 0 001.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
<span>E-Mail-Benachrichtigung über Status</span> <span>Professionelle 3D-Druck-Qualität</span>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg> </svg>
<span>Automatischer Druckstart nach Genehmigung</span> <span>Kostenlose Beratung inklusive</span>
</div> </div>
</div> </div>
</div> </div>
@ -514,7 +351,7 @@
</div> </div>
<!-- Enhanced Form Container --> <!-- Enhanced Form Container -->
<div class="guest-form-container p-8"> <div class="dashboard-card p-8">
<div class="mb-8"> <div class="mb-8">
<h2 class="text-2xl font-bold text-mercedes-black dark:text-white mb-3"> <h2 class="text-2xl font-bold text-mercedes-black dark:text-white mb-3">
Druckantrag einreichen Druckantrag einreichen
@ -536,10 +373,10 @@
</svg> </svg>
Persönliche Angaben Persönliche Angaben
</h3> </h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Name --> <!-- Name -->
<div> <div>
<label for="{{ form.name.id if form else 'name' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="{{ form.name.id if form else 'name' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Vollständiger Name * Vollständiger Name *
</label> </label>
@ -552,20 +389,20 @@
{% endif %} {% endif %}
{% if form and form.name.errors %} {% if form and form.name.errors %}
<div class="mt-2 text-sm text-mercedes-red"> <div class="mt-2 text-sm text-mercedes-red">
{% for error in form.name.errors %} {% for error in form.name.errors %}
<p class="flex items-center"> <p class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
{{ error }} {{ error }}
</p> </p>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<!-- E-Mail --> <!-- E-Mail -->
<div> <div>
<label for="{{ form.email.id if form else 'email' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="{{ form.email.id if form else 'email' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
E-Mail-Adresse * E-Mail-Adresse *
</label> </label>
@ -581,16 +418,16 @@
</p> </p>
{% if form and form.email.errors %} {% if form and form.email.errors %}
<div class="mt-2 text-sm text-mercedes-red"> <div class="mt-2 text-sm text-mercedes-red">
{% for error in form.email.errors %} {% for error in form.email.errors %}
<p class="flex items-center"> <p class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
{{ error }} {{ error }}
</p> </p>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -603,10 +440,10 @@
</svg> </svg>
Projekt-Details Projekt-Details
</h3> </h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Drucker --> <!-- Drucker -->
<div> <div>
<label for="{{ form.printer_id.id if form else 'printer_id' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="{{ form.printer_id.id if form else 'printer_id' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Gewünschter Drucker * Gewünschter Drucker *
</label> </label>
@ -625,24 +462,24 @@
</p> </p>
{% if form and form.printer_id.errors %} {% if form and form.printer_id.errors %}
<div class="mt-2 text-sm text-mercedes-red"> <div class="mt-2 text-sm text-mercedes-red">
{% for error in form.printer_id.errors %} {% for error in form.printer_id.errors %}
<p class="flex items-center"> <p class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
{{ error }} {{ error }}
</p> </p>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<!-- Geschätzte Dauer --> <!-- Geschätzte Dauer -->
<div> <div>
<label for="{{ form.duration_min.id if form else 'duration_min' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="{{ form.duration_min.id if form else 'duration_min' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Geschätzte Druckdauer * Geschätzte Druckdauer *
</label> </label>
<div class="relative"> <div class="relative">
{% if form %} {% if form %}
{{ form.duration_min(class="mercedes-form-input block w-full px-4 py-3 pr-20", placeholder="z.B. 120", required="required") }} {{ form.duration_min(class="mercedes-form-input block w-full px-4 py-3 pr-20", placeholder="z.B. 120", required="required") }}
{% else %} {% else %}
@ -652,27 +489,27 @@
{% endif %} {% endif %}
<div class="absolute inset-y-0 right-0 flex items-center pr-4 pointer-events-none"> <div class="absolute inset-y-0 right-0 flex items-center pr-4 pointer-events-none">
<span class="text-mercedes-gray dark:text-slate-400 text-sm font-medium">Minuten</span> <span class="text-mercedes-gray dark:text-slate-400 text-sm font-medium">Minuten</span>
</div>
</div> </div>
</div>
<p class="mt-1 text-xs text-mercedes-gray dark:text-slate-400"> <p class="mt-1 text-xs text-mercedes-gray dark:text-slate-400">
Ungefähre Druckzeit basierend auf der Dateigröße und Komplexität Ungefähre Druckzeit basierend auf der Dateigröße und Komplexität
</p> </p>
{% if form and form.duration_min.errors %} {% if form and form.duration_min.errors %}
<div class="mt-2 text-sm text-mercedes-red"> <div class="mt-2 text-sm text-mercedes-red">
{% for error in form.duration_min.errors %} {% for error in form.duration_min.errors %}
<p class="flex items-center"> <p class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
{{ error }} {{ error }}
</p> </p>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div>
</div> </div>
</div>
<!-- Projektbeschreibung --> <!-- Projektbeschreibung -->
<div class="mt-6"> <div class="mt-6">
<label for="{{ form.reason.id if form else 'reason' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="{{ form.reason.id if form else 'reason' }}" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Projektbeschreibung * Projektbeschreibung *
@ -689,16 +526,16 @@
</p> </p>
{% if form and form.reason.errors %} {% if form and form.reason.errors %}
<div class="mt-2 text-sm text-mercedes-red"> <div class="mt-2 text-sm text-mercedes-red">
{% for error in form.reason.errors %} {% for error in form.reason.errors %}
<p class="flex items-center"> <p class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
{{ error }} {{ error }}
</p> </p>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -706,8 +543,8 @@
<div class="bg-gray-50 dark:bg-slate-800/50 rounded-xl p-6"> <div class="bg-gray-50 dark:bg-slate-800/50 rounded-xl p-6">
<h3 class="text-lg font-semibold text-mercedes-black dark:text-white mb-4 flex items-center"> <h3 class="text-lg font-semibold text-mercedes-black dark:text-white mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-mercedes-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 mr-2 text-mercedes-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
</svg> </svg>
3D-Datei hochladen 3D-Datei hochladen
</h3> </h3>
@ -728,8 +565,8 @@
<span class="px-2 py-1 bg-mercedes-blue text-white rounded">OBJ</span> <span class="px-2 py-1 bg-mercedes-blue text-white rounded">OBJ</span>
<span class="px-2 py-1 bg-mercedes-blue text-white rounded">3MF</span> <span class="px-2 py-1 bg-mercedes-blue text-white rounded">3MF</span>
<span class="px-2 py-1 bg-mercedes-blue text-white rounded">GCODE</span> <span class="px-2 py-1 bg-mercedes-blue text-white rounded">GCODE</span>
</div>
</div> </div>
</div>
{% if form %} {% if form %}
{{ form.file(class="hidden", id="file-input") }} {{ form.file(class="hidden", id="file-input") }}
{% else %} {% else %}
@ -780,21 +617,21 @@
<button type="submit" id="submit-button" <button type="submit" id="submit-button"
class="btn-primary" disabled> class="btn-primary" disabled>
<svg class="w-5 h-5 mr-2" id="submit-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 mr-2" id="submit-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
</svg> </svg>
<svg class="w-5 h-5 mr-2 animate-spin hidden" id="submit-spinner" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg class="w-5 h-5 mr-2 animate-spin hidden" id="submit-spinner" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg> </svg>
<span id="submit-text">Antrag einreichen</span> <span id="submit-text">Antrag einreichen</span>
</button> </button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<!-- Enhanced Status Check Section --> <!-- Enhanced Status Check Section -->
<div class="guest-form-container p-8"> <div class="dashboard-card p-8">
<div class="text-center"> <div class="text-center">
<div class="inline-flex items-center justify-center w-16 h-16 bg-mercedes-green text-white rounded-xl mb-6"> <div class="inline-flex items-center justify-center w-16 h-16 bg-mercedes-green text-white rounded-xl mb-6">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -839,7 +676,7 @@
}; };
let isSubmitting = false; let isSubmitting = false;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
initializeGuestRequestForm(); initializeGuestRequestForm();
}); });

View File

@ -603,7 +603,7 @@
<strong>Präzision, Geschwindigkeit und Zuverlässigkeit</strong> nach höchsten Standards. <strong>Präzision, Geschwindigkeit und Zuverlässigkeit</strong> nach höchsten Standards.
</p> </p>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-8"> <div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<!-- Enhanced Step 1 --> <!-- Enhanced Step 1 -->
<div class="process-step text-center"> <div class="process-step text-center">
@ -669,7 +669,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Process Timeline --> <!-- Process Timeline -->
<div class="mt-16 relative"> <div class="mt-16 relative">
<div class="absolute top-8 left-0 right-0 h-1 bg-gradient-to-r from-blue-500 via-green-500 via-purple-500 to-orange-500 opacity-30"></div> <div class="absolute top-8 left-0 right-0 h-1 bg-gradient-to-r from-blue-500 via-green-500 via-purple-500 to-orange-500 opacity-30"></div>

View File

@ -253,15 +253,15 @@
<!-- Mercedes-Benz Logo --> <!-- Mercedes-Benz Logo -->
<div class="mercedes-logo inline-flex items-center justify-center w-20 h-20 bg-white/10 backdrop-blur-sm rounded-full mb-6 border border-white/20"> <div class="mercedes-logo inline-flex items-center justify-center w-20 h-20 bg-white/10 backdrop-blur-sm rounded-full mb-6 border border-white/20">
<svg class="w-10 h-10 text-mercedes-black dark:text-white" viewBox="0 0 80 80" fill="currentColor"> <svg class="w-10 h-10 text-mercedes-black dark:text-white" viewBox="0 0 80 80" fill="currentColor">
<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 <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 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 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 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 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"/> c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
</svg> </svg>
</div> </div>
<h2 class="text-3xl font-bold text-mercedes-black dark:text-white mb-2"> <h2 class="text-3xl font-bold text-mercedes-black dark:text-white mb-2">
Bei MYP Platform anmelden Bei MYP Platform anmelden
</h2> </h2>
@ -273,7 +273,7 @@
<div class="security-indicator"> <div class="security-indicator">
<svg class="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg> </svg>
Sichere SSL-Verbindung aktiv Sichere SSL-Verbindung aktiv
</div> </div>
</div> </div>
@ -292,7 +292,7 @@
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-mercedes-silver" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="h-5 w-5 text-mercedes-silver" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207"/>
</svg> </svg>
</div> </div>
{% if form %} {% if form %}
{{ form.email(class="mercedes-input block w-full pl-10 pr-3 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue", placeholder="ihre.email@mercedes-benz.com", autocomplete="email") }} {{ form.email(class="mercedes-input block w-full pl-10 pr-3 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue", placeholder="ihre.email@mercedes-benz.com", autocomplete="email") }}
@ -301,7 +301,7 @@
class="mercedes-input block w-full pl-10 pr-3 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue" class="mercedes-input block w-full pl-10 pr-3 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue"
placeholder="ihre.email@mercedes-benz.com" autocomplete="email"> placeholder="ihre.email@mercedes-benz.com" autocomplete="email">
{% endif %} {% endif %}
</div> </div>
{% if form and form.email.errors %} {% if form and form.email.errors %}
<div class="mt-1 text-sm text-mercedes-red"> <div class="mt-1 text-sm text-mercedes-red">
{% for error in form.email.errors %} {% for error in form.email.errors %}
@ -309,18 +309,18 @@
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<!-- Password --> <!-- Password -->
<div> <div>
<label for="password" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="password" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Passwort Passwort
</label> </label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-mercedes-silver" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="h-5 w-5 text-mercedes-silver" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg> </svg>
</div> </div>
{% if form %} {% if form %}
{{ form.password(class="mercedes-input block w-full pl-10 pr-10 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue", placeholder="Ihr Passwort", autocomplete="current-password") }} {{ form.password(class="mercedes-input block w-full pl-10 pr-10 py-3 rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue", placeholder="Ihr Passwort", autocomplete="current-password") }}
@ -366,8 +366,8 @@
<input type="checkbox" id="remember_me" name="remember_me" <input type="checkbox" id="remember_me" name="remember_me"
class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2"> class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2">
<label for="remember_me" class="ml-2 text-sm text-mercedes-black dark:text-slate-300"> <label for="remember_me" class="ml-2 text-sm text-mercedes-black dark:text-slate-300">
Angemeldet bleiben Angemeldet bleiben
</label> </label>
{% endif %} {% endif %}
</div> </div>
@ -381,11 +381,11 @@
<!-- Rate Limiting Warning --> <!-- Rate Limiting Warning -->
<div id="rate-limit-warning" class="hidden bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-3"> <div id="rate-limit-warning" class="hidden bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-3">
<div class="flex"> <div class="flex">
<svg class="h-5 w-5 text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="h-5 w-5 text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg> </svg>
<div class="ml-3"> <div class="ml-3">
<p class="text-sm text-yellow-800 dark:text-yellow-200"> <p class="text-sm text-yellow-800 dark:text-yellow-200">
<strong>Sicherheitshinweis:</strong> Bei mehreren fehlgeschlagenen Anmeldeversuchen wird Ihr Konto vorübergehend gesperrt. <strong>Sicherheitshinweis:</strong> Bei mehreren fehlgeschlagenen Anmeldeversuchen wird Ihr Konto vorübergehend gesperrt.
</p> </p>
@ -405,7 +405,7 @@
</button> </button>
</div> </div>
</form> </form>
</div> </div>
<!-- Alternative Actions --> <!-- Alternative Actions -->
<div class="text-center space-y-4"> <div class="text-center space-y-4">
@ -436,7 +436,7 @@
</svg> </svg>
Zurück zur Startseite Zurück zur Startseite
</a> </a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -450,7 +450,7 @@
const MAX_ATTEMPTS = 5; const MAX_ATTEMPTS = 5;
const LOCKOUT_DURATION = 15 * 60 * 1000; // 15 minutes const LOCKOUT_DURATION = 15 * 60 * 1000; // 15 minutes
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
initializeLoginForm(); initializeLoginForm();
checkRateLimit(); checkRateLimit();
setupFormValidation(); setupFormValidation();
@ -588,7 +588,7 @@
document.addEventListener('keypress', function(e) { document.addEventListener('keypress', function(e) {
// Enter key submits form // Enter key submits form
if (e.key === 'Enter' && e.target.form === document.getElementById('loginForm')) { if (e.key === 'Enter' && e.target.form === document.getElementById('loginForm')) {
e.preventDefault(); e.preventDefault();
document.getElementById('loginForm').dispatchEvent(new Event('submit')); document.getElementById('loginForm').dispatchEvent(new Event('submit'));
} }
}); });
@ -899,8 +899,8 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg> </svg>
${message} ${message}
</div> </div>
`; `;
input.parentNode.appendChild(errorDiv); input.parentNode.appendChild(errorDiv);
@ -917,8 +917,8 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg> </svg>
${message} ${message}
</div> </div>
`; `;
input.parentNode.appendChild(warningDiv); input.parentNode.appendChild(warningDiv);
} }
@ -941,7 +941,7 @@
form.reset(); form.reset();
const inputs = form.querySelectorAll('input'); const inputs = form.querySelectorAll('input');
inputs.forEach(input => { inputs.forEach(input => {
clearError(input); clearError(input);
}); });
@ -981,9 +981,9 @@
document.body.appendChild(toast); document.body.appendChild(toast);
// Animate in // Animate in
setTimeout(() => { setTimeout(() => {
toast.classList.remove('translate-x-full', 'opacity-0'); toast.classList.remove('translate-x-full', 'opacity-0');
}, 100); }, 100);
// Auto-remove after 5 seconds // Auto-remove after 5 seconds
setTimeout(() => { setTimeout(() => {

View File

@ -451,8 +451,8 @@
<div class="w-16 h-16 flex-shrink-0 bg-mercedes-blue text-white rounded-xl flex items-center justify-center"> <div class="w-16 h-16 flex-shrink-0 bg-mercedes-blue text-white rounded-xl flex items-center justify-center">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
</svg> </svg>
</div> </div>
<div> <div>
<h1 class="text-4xl font-bold text-mercedes-black dark:text-white tracking-tight">3D-Drucker</h1> <h1 class="text-4xl font-bold text-mercedes-black dark:text-white tracking-tight">3D-Drucker</h1>
<p class="text-mercedes-gray dark:text-slate-400 mt-1 text-lg">Live-Überwachung und Verwaltung Ihrer Produktionseinheiten</p> <p class="text-mercedes-gray dark:text-slate-400 mt-1 text-lg">Live-Überwachung und Verwaltung Ihrer Produktionseinheiten</p>
@ -501,12 +501,12 @@
<div class="flex items-center text-xs text-green-600 dark:text-green-400"> <div class="flex items-center text-xs text-green-600 dark:text-green-400">
<div class="w-2 h-2 bg-green-500 rounded-full mr-2 status-pulse"></div> <div class="w-2 h-2 bg-green-500 rounded-full mr-2 status-pulse"></div>
<span>Betriebsbereit</span> <span>Betriebsbereit</span>
</div> </div>
</div> </div>
<div class="w-12 h-12 bg-green-100 dark:bg-green-900/30 rounded-xl flex items-center justify-center"> <div class="w-12 h-12 bg-green-100 dark:bg-green-900/30 rounded-xl flex items-center justify-center">
<div class="w-6 h-6 bg-green-500 rounded-full"></div> <div class="w-6 h-6 bg-green-500 rounded-full"></div>
</div>
</div> </div>
</div>
<div class="mt-4 pt-4 border-t border-green-200 dark:border-green-800"> <div class="mt-4 pt-4 border-t border-green-200 dark:border-green-800">
<div class="text-xs text-mercedes-gray dark:text-slate-400"> <div class="text-xs text-mercedes-gray dark:text-slate-400">
<span class="font-medium" id="online-percentage">0%</span> aller Drucker <span class="font-medium" id="online-percentage">0%</span> aller Drucker
@ -522,12 +522,12 @@
<div class="flex items-center text-xs text-red-600 dark:text-red-400"> <div class="flex items-center text-xs text-red-600 dark:text-red-400">
<div class="w-2 h-2 bg-red-500 rounded-full mr-2"></div> <div class="w-2 h-2 bg-red-500 rounded-full mr-2"></div>
<span>Nicht verfügbar</span> <span>Nicht verfügbar</span>
</div> </div>
</div> </div>
<div class="w-12 h-12 bg-red-100 dark:bg-red-900/30 rounded-xl flex items-center justify-center"> <div class="w-12 h-12 bg-red-100 dark:bg-red-900/30 rounded-xl flex items-center justify-center">
<div class="w-6 h-6 bg-red-500 rounded-full"></div> <div class="w-6 h-6 bg-red-500 rounded-full"></div>
</div>
</div> </div>
</div>
<div class="mt-4 pt-4 border-t border-red-200 dark:border-red-800"> <div class="mt-4 pt-4 border-t border-red-200 dark:border-red-800">
<div class="text-xs text-mercedes-gray dark:text-slate-400"> <div class="text-xs text-mercedes-gray dark:text-slate-400">
<span class="font-medium" id="offline-percentage">0%</span> aller Drucker <span class="font-medium" id="offline-percentage">0%</span> aller Drucker
@ -543,12 +543,12 @@
<div class="flex items-center text-xs text-blue-600 dark:text-blue-400"> <div class="flex items-center text-xs text-blue-600 dark:text-blue-400">
<div class="w-2 h-2 bg-blue-500 rounded-full mr-2 status-pulse"></div> <div class="w-2 h-2 bg-blue-500 rounded-full mr-2 status-pulse"></div>
<span>Druckt gerade</span> <span>Druckt gerade</span>
</div> </div>
</div> </div>
<div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-xl flex items-center justify-center"> <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-xl flex items-center justify-center">
<div class="w-6 h-6 bg-blue-500 rounded-full animate-pulse"></div> <div class="w-6 h-6 bg-blue-500 rounded-full animate-pulse"></div>
</div>
</div> </div>
</div>
<div class="mt-4 pt-4 border-t border-blue-200 dark:border-blue-800"> <div class="mt-4 pt-4 border-t border-blue-200 dark:border-blue-800">
<div class="text-xs text-mercedes-gray dark:text-slate-400"> <div class="text-xs text-mercedes-gray dark:text-slate-400">
<span class="font-medium" id="active-percentage">0%</span> Auslastung <span class="font-medium" id="active-percentage">0%</span> Auslastung
@ -566,7 +566,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
</svg> </svg>
<span>Drucker registriert</span> <span>Drucker registriert</span>
</div> </div>
</div> </div>
<div class="w-12 h-12 bg-mercedes-silver rounded-xl flex items-center justify-center"> <div class="w-12 h-12 bg-mercedes-silver rounded-xl flex items-center justify-center">
<svg class="w-6 h-6 text-mercedes-black dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-6 h-6 text-mercedes-black dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -688,7 +688,7 @@
<option value="">Alle Standorte</option> <option value="">Alle Standorte</option>
<!-- Wird dynamisch gefüllt --> <!-- Wird dynamisch gefüllt -->
</select> </select>
</div> </div>
<!-- Model Filter --> <!-- Model Filter -->
<div> <div>
@ -702,9 +702,9 @@
<option value="">Alle Modelle</option> <option value="">Alle Modelle</option>
<!-- Wird dynamisch gefüllt --> <!-- Wird dynamisch gefüllt -->
</select> </select>
</div> </div>
</div> </div>
<!-- Advanced Filter Options --> <!-- Advanced Filter Options -->
<div class="mt-6 flex flex-wrap items-center justify-between gap-4"> <div class="mt-6 flex flex-wrap items-center justify-between gap-4">
<div class="flex flex-wrap gap-4"> <div class="flex flex-wrap gap-4">
@ -770,8 +770,8 @@
</button> </button>
</div> </div>
</div> </div>
<!-- Loading State --> <!-- Loading State -->
<div id="loading-state" class="space-y-6"> <div id="loading-state" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="printer-card p-6"> <div class="printer-card p-6">
@ -835,9 +835,9 @@
<div class="text-center"> <div class="text-center">
<div class="text-mercedes-gray dark:text-slate-400 mb-4"> <div class="text-mercedes-gray dark:text-slate-400 mb-4">
<svg class="w-8 h-8 mx-auto mb-3 animate-spin text-mercedes-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-8 h-8 mx-auto mb-3 animate-spin text-mercedes-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg> </svg>
</div> </div>
<p class="text-mercedes-gray dark:text-slate-400">Lade Drucker-Informationen...</p> <p class="text-mercedes-gray dark:text-slate-400">Lade Drucker-Informationen...</p>
</div> </div>
</div> </div>
@ -846,16 +846,16 @@
<div id="printers-container" class="hidden"> <div id="printers-container" class="hidden">
<div id="printers-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div id="printers-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Printers will be loaded here --> <!-- Printers will be loaded here -->
</div> </div>
<!-- Empty State --> <!-- Empty State -->
<div id="empty-state" class="hidden col-span-full py-16 text-center"> <div id="empty-state" class="hidden col-span-full py-16 text-center">
<div class="max-w-md mx-auto"> <div class="max-w-md mx-auto">
<div class="text-mercedes-silver mb-6"> <div class="text-mercedes-silver mb-6">
<svg class="w-20 h-20 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg class="w-20 h-20 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
</svg> </svg>
</div> </div>
<h3 class="text-2xl font-semibold text-mercedes-black dark:text-white mb-3">Keine Drucker gefunden</h3> <h3 class="text-2xl font-semibold text-mercedes-black dark:text-white mb-3">Keine Drucker gefunden</h3>
<p class="text-mercedes-gray dark:text-slate-400 mb-8 leading-relaxed"> <p class="text-mercedes-gray dark:text-slate-400 mb-8 leading-relaxed">
Es wurden keine 3D-Drucker gefunden, die den aktuellen Filterkriterien entsprechen. Es wurden keine 3D-Drucker gefunden, die den aktuellen Filterkriterien entsprechen.
@ -865,11 +865,11 @@
<button onclick="clearAllFilters()" class="btn-secondary"> <button onclick="clearAllFilters()" class="btn-secondary">
Filter zurücksetzen Filter zurücksetzen
</button> </button>
<button onclick="openAddPrinterModal()" class="btn-primary"> <button onclick="openAddPrinterModal()" class="btn-primary">
Ersten Drucker hinzufügen Ersten Drucker hinzufügen
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<!-- No Results State --> <!-- No Results State -->
@ -898,7 +898,7 @@
<div class="flex items-center justify-center min-h-screen p-4"> <div class="flex items-center justify-center min-h-screen p-4">
<div class="mercedes-modal max-w-2xl w-full p-8 transform transition-all duration-300 scale-95 opacity-0" id="printerModalContent"> <div class="mercedes-modal max-w-2xl w-full p-8 transform transition-all duration-300 scale-95 opacity-0" id="printerModalContent">
<div class="flex justify-between items-center mb-6"> <div class="flex justify-between items-center mb-6">
<div> <div>
<h3 id="printerModalTitle" class="text-2xl font-bold text-mercedes-black dark:text-white mb-2"> <h3 id="printerModalTitle" class="text-2xl font-bold text-mercedes-black dark:text-white mb-2">
Drucker hinzufügen Drucker hinzufügen
</h3> </h3>
@ -913,7 +913,7 @@
<form id="printerForm" class="space-y-6"> <form id="printerForm" class="space-y-6">
<input type="hidden" id="printerId" name="printerId"> <input type="hidden" id="printerId" name="printerId">
<!-- Basic Information --> <!-- Basic Information -->
<div class="space-y-4"> <div class="space-y-4">
<h4 class="text-lg font-semibold text-mercedes-black dark:text-white border-b border-mercedes-silver pb-2"> <h4 class="text-lg font-semibold text-mercedes-black dark:text-white border-b border-mercedes-silver pb-2">
@ -921,20 +921,20 @@
</h4> </h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label for="printerName" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="printerName" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Drucker-Name <span class="text-red-500">*</span> Drucker-Name <span class="text-red-500">*</span>
</label> </label>
<input type="text" id="printerName" name="name" required <input type="text" id="printerName" name="name" required
class="mercedes-form-input block w-full px-4 py-3 rounded-lg" class="mercedes-form-input block w-full px-4 py-3 rounded-lg"
placeholder="z.B. Ultimaker S3 #01"> placeholder="z.B. Ultimaker S3 #01">
<p class="text-xs text-mercedes-gray dark:text-slate-400 mt-1">Eindeutiger Name zur Identifikation</p> <p class="text-xs text-mercedes-gray dark:text-slate-400 mt-1">Eindeutiger Name zur Identifikation</p>
</div> </div>
<div> <div>
<label for="printerModel" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="printerModel" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Modell Modell
</label> </label>
<select id="printerModel" name="model" class="mercedes-form-input block w-full px-4 py-3 rounded-lg"> <select id="printerModel" name="model" class="mercedes-form-input block w-full px-4 py-3 rounded-lg">
<option value="">Modell auswählen...</option> <option value="">Modell auswählen...</option>
<option value="Ultimaker S3">Ultimaker S3</option> <option value="Ultimaker S3">Ultimaker S3</option>
@ -953,30 +953,30 @@
<input type="text" id="customModel" name="customModel" <input type="text" id="customModel" name="customModel"
class="mercedes-form-input block w-full px-4 py-3 rounded-lg" class="mercedes-form-input block w-full px-4 py-3 rounded-lg"
placeholder="Geben Sie das Druckermodell ein"> placeholder="Geben Sie das Druckermodell ein">
</div> </div>
<div> <div>
<label for="printerLocation" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="printerLocation" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
Standort <span class="text-red-500">*</span> Standort <span class="text-red-500">*</span>
</label> </label>
<input type="text" id="printerLocation" name="location" required <input type="text" id="printerLocation" name="location" required
class="mercedes-form-input block w-full px-4 py-3 rounded-lg" class="mercedes-form-input block w-full px-4 py-3 rounded-lg"
placeholder="z.B. Produktionshalle A, Raum 101"> placeholder="z.B. Produktionshalle A, Raum 101">
</div> </div>
<div> <div>
<label for="printerIP" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2"> <label for="printerIP" class="block text-sm font-medium text-mercedes-black dark:text-slate-300 mb-2">
IP-Adresse IP-Adresse
</label> </label>
<input type="text" id="printerIP" name="ip_address" <input type="text" id="printerIP" name="ip_address"
class="mercedes-form-input block w-full px-4 py-3 rounded-lg" class="mercedes-form-input block w-full px-4 py-3 rounded-lg"
placeholder="192.168.1.100" placeholder="192.168.1.100"
pattern="^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$"> pattern="^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$">
<p class="text-xs text-mercedes-gray dark:text-slate-400 mt-1">Für Netzwerk-Überwachung</p> <p class="text-xs text-mercedes-gray dark:text-slate-400 mt-1">Für Netzwerk-Überwachung</p>
</div> </div>
</div> </div>
</div> </div>
<!-- Technical Specifications --> <!-- Technical Specifications -->
<div class="space-y-4"> <div class="space-y-4">
<h4 class="text-lg font-semibold text-mercedes-black dark:text-white border-b border-mercedes-silver pb-2"> <h4 class="text-lg font-semibold text-mercedes-black dark:text-white border-b border-mercedes-silver pb-2">
@ -1056,14 +1056,14 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-4"> <div class="space-y-4">
<div class="flex items-center"> <div class="flex items-center">
<input type="checkbox" id="printerActive" name="active" checked <input type="checkbox" id="printerActive" name="active" checked
class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2"> class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2">
<label for="printerActive" class="ml-3 text-sm text-mercedes-black dark:text-slate-300"> <label for="printerActive" class="ml-3 text-sm text-mercedes-black dark:text-slate-300">
Drucker aktiv Drucker aktiv
</label> </label>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<input type="checkbox" id="autoQueue" name="auto_queue" <input type="checkbox" id="autoQueue" name="auto_queue"
class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2"> class="w-4 h-4 text-mercedes-blue bg-white dark:bg-slate-800 border-mercedes-silver rounded focus:ring-mercedes-blue focus:ring-2">
@ -1123,22 +1123,22 @@
</button> </button>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<button type="button" onclick="closePrinterModal()" class="btn-secondary"> <button type="button" onclick="closePrinterModal()" class="btn-secondary">
Abbrechen Abbrechen
</button> </button>
<button type="submit" class="btn-primary flex items-center gap-2"> <button type="submit" class="btn-primary flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg> </svg>
Speichern Speichern
</button> </button>
</div>
</div>
</form>
</div>
</div> </div>
</div> </div>
</form>
</div>
</div>
</div>
<!-- Enhanced Printer Details Modal --> <!-- Enhanced Printer Details Modal -->
<div id="printerDetailsModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm hidden z-50"> <div id="printerDetailsModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm hidden z-50">
<div class="flex items-center justify-center min-h-screen p-4"> <div class="flex items-center justify-center min-h-screen p-4">
@ -1149,14 +1149,14 @@
Drucker Details Drucker Details
</h3> </h3>
<p class="text-mercedes-gray dark:text-slate-400">Live-Informationen und Steuerungsoptionen</p> <p class="text-mercedes-gray dark:text-slate-400">Live-Informationen und Steuerungsoptionen</p>
</div> </div>
<button onclick="closePrinterDetailsModal()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors"> <button onclick="closePrinterDetailsModal()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors">
<svg class="w-6 h-6 text-mercedes-gray dark:text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-6 h-6 text-mercedes-gray dark:text-slate-400" 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"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg> </svg>
</button> </button>
</div> </div>
<div id="printerDetailsContent" class="space-y-6"> <div id="printerDetailsContent" class="space-y-6">
<!-- Content will be loaded dynamically --> <!-- Content will be loaded dynamically -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
@ -1213,10 +1213,10 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
let allPrinters = []; let allPrinters = [];
@ -1273,22 +1273,22 @@ class PrinterManager {
try { try {
this.showLoadingState(); this.showLoadingState();
const response = await fetch('/api/printers'); const response = await fetch('/api/printers');
const data = await response.json(); const data = await response.json();
if (data.success) { if (data.success) {
allPrinters = data.printers || []; allPrinters = data.printers || [];
this.applyFilters(); this.applyFilters();
this.updateStatistics(); this.updateStatistics();
this.populateFilterDropdowns(); this.populateFilterDropdowns();
this.updateLastUpdateTime(); this.updateLastUpdateTime();
} else { } else {
this.showError('Fehler beim Laden der Drucker: ' + data.message); this.showError('Fehler beim Laden der Drucker: ' + data.message);
} }
} catch (error) { } catch (error) {
console.error('Error loading printers:', error); console.error('Error loading printers:', error);
this.showError('Fehler beim Laden der Drucker'); this.showError('Fehler beim Laden der Drucker');
} finally { } finally {
this.hideLoadingState(); this.hideLoadingState();
} }
} }
@ -1366,20 +1366,20 @@ class PrinterManager {
} }
displayPrinters() { displayPrinters() {
const grid = document.getElementById('printers-grid'); const grid = document.getElementById('printers-grid');
const emptyState = document.getElementById('empty-state'); const emptyState = document.getElementById('empty-state');
const noResultsState = document.getElementById('no-results-state'); const noResultsState = document.getElementById('no-results-state');
if (allPrinters.length === 0) { if (allPrinters.length === 0) {
grid.innerHTML = ''; grid.innerHTML = '';
emptyState.classList.remove('hidden'); emptyState.classList.remove('hidden');
noResultsState.classList.add('hidden'); noResultsState.classList.add('hidden');
return; return;
} }
if (filteredPrinters.length === 0) { if (filteredPrinters.length === 0) {
grid.innerHTML = ''; grid.innerHTML = '';
emptyState.classList.add('hidden'); emptyState.classList.add('hidden');
noResultsState.classList.remove('hidden'); noResultsState.classList.remove('hidden');
return; return;
} }
@ -1400,24 +1400,24 @@ class PrinterManager {
const statusClasses = this.getStatusClasses(printer.status); const statusClasses = this.getStatusClasses(printer.status);
const temperature = printer.temperature || {}; const temperature = printer.temperature || {};
const currentJob = printer.current_job || {}; const currentJob = printer.current_job || {};
return ` return `
<div class="printer-card ${statusClasses.container} p-6" data-printer-id="${printer.id}"> <div class="printer-card ${statusClasses.container} p-6" data-printer-id="${printer.id}">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-12 h-12 ${statusClasses.iconBg} rounded-xl flex items-center justify-center"> <div class="w-12 h-12 ${statusClasses.iconBg} rounded-xl flex items-center justify-center">
${this.getStatusIcon(printer.status)} ${this.getStatusIcon(printer.status)}
</div> </div>
<div> <div>
<h3 class="text-lg font-semibold text-mercedes-black dark:text-white">${printer.name}</h3> <h3 class="text-lg font-semibold text-mercedes-black dark:text-white">${printer.name}</h3>
<p class="text-sm text-mercedes-gray dark:text-slate-400">${printer.model || 'Unbekanntes Modell'}</p> <p class="text-sm text-mercedes-gray dark:text-slate-400">${printer.model || 'Unbekanntes Modell'}</p>
</div> </div>
</div> </div>
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${statusClasses.badge}"> <span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${statusClasses.badge}">
${this.getStatusText(printer.status)} ${this.getStatusText(printer.status)}
</span> </span>
</div> </div>
${printer.status === 'printing' && currentJob.progress ? ` ${printer.status === 'printing' && currentJob.progress ? `
<div class="mb-4"> <div class="mb-4">
<div class="flex justify-between text-sm text-mercedes-gray dark:text-slate-400 mb-2"> <div class="flex justify-between text-sm text-mercedes-gray dark:text-slate-400 mb-2">
@ -1430,7 +1430,7 @@ class PrinterManager {
${currentJob.time_remaining ? ` ${currentJob.time_remaining ? `
<div class="text-xs text-mercedes-gray dark:text-slate-400 mt-1"> <div class="text-xs text-mercedes-gray dark:text-slate-400 mt-1">
Verbleibend: ${this.formatDuration(currentJob.time_remaining)} Verbleibend: ${this.formatDuration(currentJob.time_remaining)}
</div> </div>
` : ''} ` : ''}
</div> </div>
` : ''} ` : ''}
@ -1463,30 +1463,30 @@ class PrinterManager {
<p class="text-mercedes-black dark:text-white">${this.formatUptime(printer.uptime)}</p> <p class="text-mercedes-black dark:text-white">${this.formatUptime(printer.uptime)}</p>
</div> </div>
`} `}
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<button onclick="printerManager.openPrinterDetails('${printer.id}')" <button onclick="printerManager.openPrinterDetails('${printer.id}')"
class="printer-action-btn btn-details flex-1"> class="printer-action-btn btn-details flex-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
</svg> </svg>
Details Details
</button> </button>
<button onclick="printerManager.editPrinter('${printer.id}')" <button onclick="printerManager.editPrinter('${printer.id}')"
class="printer-action-btn btn-edit flex-1"> class="printer-action-btn btn-edit flex-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg> </svg>
Bearbeiten Bearbeiten
</button> </button>
${this.getPrinterActionButton(printer)} ${this.getPrinterActionButton(printer)}
</div>
</div> </div>
</div> `;
`; }
}
createPrinterListItem(printer) { createPrinterListItem(printer) {
const statusClasses = this.getStatusClasses(printer.status); const statusClasses = this.getStatusClasses(printer.status);
@ -1575,47 +1575,47 @@ class PrinterManager {
} }
getStatusClasses(status) { getStatusClasses(status) {
const classes = { const classes = {
'online': { 'online': {
container: 'status-online', container: 'status-online',
iconBg: 'bg-green-100 dark:bg-green-900/30 text-green-600', iconBg: 'bg-green-100 dark:bg-green-900/30 text-green-600',
badge: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' badge: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400'
}, },
'offline': { 'offline': {
container: 'status-offline', container: 'status-offline',
iconBg: 'bg-red-100 dark:bg-red-900/30 text-red-600', iconBg: 'bg-red-100 dark:bg-red-900/30 text-red-600',
badge: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400' badge: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400'
}, },
'printing': { 'printing': {
container: 'status-printing', container: 'status-printing',
iconBg: 'bg-blue-100 dark:bg-blue-900/30 text-blue-600', iconBg: 'bg-blue-100 dark:bg-blue-900/30 text-blue-600',
badge: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400' badge: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400'
}, },
'error': { 'error': {
container: 'status-error', container: 'status-error',
iconBg: 'bg-orange-100 dark:bg-orange-900/30 text-orange-600', iconBg: 'bg-orange-100 dark:bg-orange-900/30 text-orange-600',
badge: 'bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-400' badge: 'bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-400'
}, },
'maintenance': { 'maintenance': {
container: 'status-maintenance', container: 'status-maintenance',
iconBg: 'bg-purple-100 dark:bg-purple-900/30 text-purple-600', iconBg: 'bg-purple-100 dark:bg-purple-900/30 text-purple-600',
badge: 'bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-400' badge: 'bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-400'
} }
}; };
return classes[status] || classes['offline']; return classes[status] || classes['offline'];
} }
getStatusIcon(status) { getStatusIcon(status) {
const icons = { const icons = {
'online': '<div class="w-3 h-3 bg-green-500 rounded-full"></div>', 'online': '<div class="w-3 h-3 bg-green-500 rounded-full"></div>',
'offline': '<div class="w-3 h-3 bg-red-500 rounded-full"></div>', 'offline': '<div class="w-3 h-3 bg-red-500 rounded-full"></div>',
'printing': '<div class="w-3 h-3 bg-blue-500 rounded-full status-pulse"></div>', 'printing': '<div class="w-3 h-3 bg-blue-500 rounded-full status-pulse"></div>',
'error': '<div class="w-3 h-3 bg-orange-500 rounded-full"></div>', 'error': '<div class="w-3 h-3 bg-orange-500 rounded-full"></div>',
'maintenance': '<div class="w-3 h-3 bg-purple-500 rounded-full"></div>' 'maintenance': '<div class="w-3 h-3 bg-purple-500 rounded-full"></div>'
}; };
return icons[status] || icons['offline']; return icons[status] || icons['offline'];
} }
getStatusText(status) { getStatusText(status) {
const texts = { const texts = {
'online': 'Online', 'online': 'Online',
@ -1629,7 +1629,7 @@ class PrinterManager {
} }
updateStatistics() { updateStatistics() {
const stats = { const stats = {
total: allPrinters.length, total: allPrinters.length,
online: allPrinters.filter(p => ['online', 'idle'].includes(p.status)).length, online: allPrinters.filter(p => ['online', 'idle'].includes(p.status)).length,
offline: allPrinters.filter(p => p.status === 'offline').length, offline: allPrinters.filter(p => p.status === 'offline').length,
@ -1689,11 +1689,11 @@ class PrinterManager {
} }
populateFilterDropdowns() { populateFilterDropdowns() {
// Populate location filter // Populate location filter
const locationFilter = document.getElementById('filterLocation'); const locationFilter = document.getElementById('filterLocation');
const locations = [...new Set(allPrinters.map(p => p.location).filter(Boolean))]; const locations = [...new Set(allPrinters.map(p => p.location).filter(Boolean))];
locationFilter.innerHTML = '<option value="">Alle Standorte</option>' + locationFilter.innerHTML = '<option value="">Alle Standorte</option>' +
locations.map(location => `<option value="${location}">${location}</option>`).join(''); locations.map(location => `<option value="${location}">${location}</option>`).join('');
// Populate model filter // Populate model filter
const modelFilter = document.getElementById('filterModel'); const modelFilter = document.getElementById('filterModel');
@ -1781,9 +1781,9 @@ class PrinterManager {
content.classList.remove('scale-100', 'opacity-100'); content.classList.remove('scale-100', 'opacity-100');
content.classList.add('scale-95', 'opacity-0'); content.classList.add('scale-95', 'opacity-0');
setTimeout(() => { setTimeout(() => {
modal.classList.add('hidden'); modal.classList.add('hidden');
}, 200); }, 200);
} }
} }
@ -1845,7 +1845,7 @@ function toggleGridView(view) {
gridBtn.classList.remove('text-mercedes-gray', 'hover:bg-mercedes-silver'); gridBtn.classList.remove('text-mercedes-gray', 'hover:bg-mercedes-silver');
listBtn.classList.remove('bg-mercedes-blue', 'text-white'); listBtn.classList.remove('bg-mercedes-blue', 'text-white');
listBtn.classList.add('text-mercedes-gray', 'hover:bg-mercedes-silver'); listBtn.classList.add('text-mercedes-gray', 'hover:bg-mercedes-silver');
} else { } else {
listBtn.classList.add('bg-mercedes-blue', 'text-white'); listBtn.classList.add('bg-mercedes-blue', 'text-white');
listBtn.classList.remove('text-mercedes-gray', 'hover:bg-mercedes-silver'); listBtn.classList.remove('text-mercedes-gray', 'hover:bg-mercedes-silver');
gridBtn.classList.remove('bg-mercedes-blue', 'text-white'); gridBtn.classList.remove('bg-mercedes-blue', 'text-white');

View File

@ -261,7 +261,7 @@
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
if (key !== 'avatar') { // Don't store file data if (key !== 'avatar') { // Don't store file data
originalFormData[key] = value; originalFormData[key] = value;
} }
} }
} }
@ -586,7 +586,7 @@
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
if (key !== 'avatar') { if (key !== 'avatar') {
profileData[key] = value; profileData[key] = value;
} }
} }