239 lines
9.7 KiB
HTML
239 lines
9.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de" class="h-full">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<!-- Kiosk-spezifische Meta-Tags -->
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="format-detection" content="telephone=no">
|
|
|
|
<title>{% block title %}MYP Druckerverwaltung{% endblock %}</title>
|
|
|
|
<!-- Critical CSS inline für sofortiges Rendering -->
|
|
<style>
|
|
/* CRITICAL INLINE CSS - Füge hier den Inhalt von critical-inline.css ein */
|
|
:root{--primary:#0073ce;--bg:#fafbfc;--surface:#fff;--text:#111827;--border:#e5e7eb;--shadow:0 2px 4px rgba(0,0,0,.05)}
|
|
*{box-sizing:border-box;margin:0;padding:0;contain:layout style}
|
|
body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);line-height:1.5;text-rendering:optimizeSpeed;-webkit-font-smoothing:antialiased}
|
|
.header{background:var(--surface);border-bottom:1px solid var(--border);padding:1rem;position:sticky;top:0;z-index:1000}
|
|
.nav{display:flex;gap:1rem}
|
|
.nav-item{padding:.5rem 1rem;border-radius:6px;text-decoration:none;color:#6b7280;transition:background .1s}
|
|
.nav-item:hover{background:var(--bg);color:var(--text)}
|
|
.nav-item.active{background:var(--primary);color:#fff}
|
|
.container{max-width:1200px;margin:0 auto;padding:0 1rem}
|
|
.btn{background:var(--primary);color:#fff;border:none;border-radius:6px;padding:.75rem 1.5rem;font-weight:600;cursor:pointer;transition:background .1s}
|
|
.btn:hover{background:#005a9f}
|
|
.card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:1rem;box-shadow:var(--shadow)}
|
|
.flex{display:flex}
|
|
.grid{display:grid;gap:1rem}
|
|
.hidden{display:none}
|
|
.w-full{width:100%}
|
|
.text-center{text-align:center}
|
|
.p-4{padding:1rem}
|
|
.mb-4{margin-bottom:1rem}
|
|
.status{display:inline-block;padding:.25rem .75rem;border-radius:999px;font-size:.75rem;font-weight:600;text-transform:uppercase}
|
|
.status-online{background:#d1fae5;color:#065f46}
|
|
.status-offline{background:#fee2e2;color:#991b1b}
|
|
.status-printing{background:#dbeafe;color:#1e40af}
|
|
.input{background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:.75rem;width:100%}
|
|
.input:focus{outline:none;border-color:var(--primary)}
|
|
@media (prefers-color-scheme:dark){:root{--bg:#1e293b;--surface:#334155;--text:#f8fafc;--border:#475569;--shadow:0 2px 4px rgba(0,0,0,.3)}}
|
|
@media (max-width:768px){.nav{flex-direction:column;gap:.5rem}}
|
|
@media (prefers-reduced-motion:reduce){*{transition:none!important}}
|
|
</style>
|
|
|
|
<!-- Kiosk-spezifische Optimierungen -->
|
|
<style>
|
|
/* Kiosk-spezifische Styles für bessere Performance */
|
|
* {
|
|
/* Deaktiviere Touch-Events für Kiosk */
|
|
touch-action: none;
|
|
-webkit-touch-callout: none;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
}
|
|
|
|
/* Nur Inputs sollen selektierbar sein */
|
|
input, textarea, [contenteditable] {
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
touch-action: manipulation;
|
|
}
|
|
|
|
/* Verhindere Zoom bei Double-Tap */
|
|
* {
|
|
-webkit-touch-callout: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
|
|
/* Optimiere für Vollbild-Kiosk */
|
|
html, body {
|
|
height: 100%;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* Vereinfachte Fokus-Styles für Keyboard-Navigation */
|
|
:focus-visible {
|
|
outline: 2px solid var(--primary);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* Loading-State für bessere UX */
|
|
.loading-skeleton {
|
|
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
|
background-size: 200% 100%;
|
|
animation: skeleton 1.5s infinite;
|
|
}
|
|
|
|
@keyframes skeleton {
|
|
0% { background-position: 200% 0; }
|
|
100% { background-position: -200% 0; }
|
|
}
|
|
</style>
|
|
|
|
<!-- DNS-Prefetch für lokale Ressourcen (falls nötig) -->
|
|
<link rel="dns-prefetch" href="//localhost">
|
|
|
|
<!-- Resource Hints für bessere Performance -->
|
|
<link rel="preload" href="/static/css/build/kiosk-production.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
|
|
<!-- Fallback CSS falls Preload fehlschlägt -->
|
|
<noscript>
|
|
<link rel="stylesheet" href="/static/css/build/kiosk-production.css">
|
|
</noscript>
|
|
|
|
<!-- Favicon für Kiosk-Modus -->
|
|
<link rel="icon" type="image/svg+xml" href="/static/icons/favicon.svg">
|
|
<link rel="icon" type="image/png" href="/static/icons/favicon-32x32.png">
|
|
|
|
{% block extra_head %}{% endblock %}
|
|
</head>
|
|
|
|
<body class="h-full bg-gray-50">
|
|
<!-- Loading-Overlay für bessere UX -->
|
|
<div id="loading-overlay" class="fixed inset-0 bg-white z-50 flex items-center justify-center" style="display: none;">
|
|
<div class="text-center">
|
|
<div class="loading-skeleton w-16 h-16 rounded-full mb-4 mx-auto"></div>
|
|
<p class="text-gray-600">Lädt...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Haupt-Layout -->
|
|
<div class="h-full flex flex-col">
|
|
<!-- Header -->
|
|
<header class="header">
|
|
<div class="container">
|
|
<nav class="nav">
|
|
<a href="/" class="nav-item {% if request.endpoint == 'dashboard' %}active{% endif %}">
|
|
<span class="icon icon-dashboard mr-2"></span>
|
|
Dashboard
|
|
</a>
|
|
<a href="/printers" class="nav-item {% if request.endpoint == 'printers' %}active{% endif %}">
|
|
<span class="icon icon-printer mr-2"></span>
|
|
Drucker
|
|
</a>
|
|
<a href="/jobs" class="nav-item {% if request.endpoint == 'jobs' %}active{% endif %}">
|
|
<span class="icon icon-queue mr-2"></span>
|
|
Jobs
|
|
</a>
|
|
<a href="/users" class="nav-item {% if request.endpoint == 'users' %}active{% endif %}">
|
|
<span class="icon icon-users mr-2"></span>
|
|
Benutzer
|
|
</a>
|
|
<a href="/settings" class="nav-item {% if request.endpoint == 'settings' %}active{% endif %}">
|
|
<span class="icon icon-settings mr-2"></span>
|
|
Einstellungen
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content -->
|
|
<main class="flex-1 container py-6">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<!-- Footer (optional) -->
|
|
{% block footer %}
|
|
<footer class="border-t border-gray-200 py-4">
|
|
<div class="container text-center text-sm text-gray-500">
|
|
MYP Druckerverwaltung - Kiosk-Modus
|
|
</div>
|
|
</footer>
|
|
{% endblock %}
|
|
</div>
|
|
|
|
<!-- JavaScript für optimale Performance -->
|
|
<script>
|
|
// Minimales JavaScript für Kiosk-Performance
|
|
|
|
// Entferne Loading-Overlay nach DOM-Ready
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const overlay = document.getElementById('loading-overlay');
|
|
if (overlay) {
|
|
overlay.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Deaktiviere Right-Click-Menü für Kiosk
|
|
document.addEventListener('contextmenu', function(e) {
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
// Deaktiviere F12, Ctrl+Shift+I etc. für Kiosk
|
|
document.addEventListener('keydown', function(e) {
|
|
if (
|
|
e.key === 'F12' ||
|
|
(e.ctrlKey && e.shiftKey && (e.key === 'I' || e.key === 'C' || e.key === 'J')) ||
|
|
(e.ctrlKey && e.key === 'U')
|
|
) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Verhindere Zoom via Keyboard
|
|
document.addEventListener('keydown', function(e) {
|
|
if ((e.ctrlKey || e.metaKey) && (e.key === '+' || e.key === '-' || e.key === '0')) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Optimiertes Form-Handling für bessere UX
|
|
document.addEventListener('submit', function(e) {
|
|
const form = e.target;
|
|
if (form.tagName === 'FORM') {
|
|
// Zeige Loading-State
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<span class="icon icon-refresh mr-2"></span>Lädt...';
|
|
}
|
|
}
|
|
});
|
|
|
|
// Einfache Error-Handling für bessere UX
|
|
window.addEventListener('error', function(e) {
|
|
console.warn('Fehler abgefangen:', e.error);
|
|
// Könnte hier eine einfache Fehler-Benachrichtigung zeigen
|
|
});
|
|
|
|
// Memory-Management für lange Kiosk-Sessions
|
|
if ('requestIdleCallback' in window) {
|
|
requestIdleCallback(function() {
|
|
// Cleanup ungenutzter Ressourcen in Idle-Zeit
|
|
if (typeof gc === 'function') {
|
|
gc(); // Falls verfügbar
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html> |