feat: Server Admin UI postapokalyptisches Rost/Stahl/Beton-Theme

- Farbpalette komplett auf dunklen Asphalt/Beton, verwitterten Stahl,
  Rost-Orange, Marsstaub umgestellt
- Share Tech Mono (Google Fonts) fuer Ueberschriften, Labels, Buttons
- Noise-Overlay (SVG feTurbulence) fuer Beton-Textur
- Scrollbar-Styling (WebKit) im Theme
- Cards mit Rost-Border-Left-Akzent und dunklem Box-Shadow
- Modals mit Rost-Border, Tabellen mit alternierenden dunklen Zeilen
- Stat-Cards: Werte in Rost-Orange (#C1440E)
- Dekorative h2-Prefixe (Quadrat-Symbol)
- Keine JS-Logik oder API-Aenderungen

Closes #88
This commit is contained in:
Jens Reinemann 2026-05-17 11:53:41 +02:00
parent 1df2d1cff5
commit 9004baede1

View file

@ -4,62 +4,94 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Krisenvorrat Admin</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f5f5f5; color: #222; }
header { background: #1a1a2e; color: #fff; padding: 16px 24px; display: flex; justify-content: space-between; align-items: center; }
header h1 { font-size: 1.2rem; }
#logout-btn { background: transparent; border: 1px solid #ccc; color: #ccc; padding: 6px 14px; border-radius: 4px; cursor: pointer; }
body { font-family: system-ui, sans-serif; background: #16140F; color: #E8D5B0; position: relative; }
body::before {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 200px 200px;
}
body > * { position: relative; z-index: 1; }
h1, h2, h3, label, .stat-label, .inv-stats-toggle { font-family: 'Share Tech Mono', 'Courier New', monospace; }
h1, h2 { letter-spacing: 0.05em; }
h2::before { content: '▣ '; color: #C1440E; }
header { background: #1A1815; color: #E8D5B0; padding: 16px 24px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #C1440E; }
header h1 { font-size: 1.2rem; text-transform: uppercase; }
#logout-btn { background: transparent; border: 1px solid #4A3F2F; color: #A89070; padding: 6px 14px; border-radius: 3px; cursor: pointer; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; font-size: .85rem; }
#logout-btn:hover { border-color: #C1440E; color: #E8D5B0; }
main { max-width: 960px; margin: 32px auto; padding: 0 16px; }
.card { background: #fff; border-radius: 8px; padding: 32px; box-shadow: 0 1px 4px rgba(0,0,0,.1); margin-bottom: 24px; }
h2 { margin-bottom: 20px; font-size: 1.1rem; }
label { display: block; margin-bottom: 4px; font-size: .875rem; color: #555; }
input, select { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 14px; font-size: 1rem; }
button.primary { background: #1a1a2e; color: #fff; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 1rem; }
button.primary:hover { background: #2d2d5e; }
button.danger { background: #c0392b; color: #fff; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; }
button.secondary { background: #eee; color: #333; border: 1px solid #ccc; padding: 6px 12px; border-radius: 4px; cursor: pointer; }
button.info { background: #2980b9; color: #fff; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; }
.error { color: #c0392b; margin-bottom: 12px; font-size: .875rem; }
.card { background: #242119; border: 1px solid #4A3F2F; border-left: 3px solid #8B3A0F; border-radius: 3px; padding: 32px; box-shadow: 0 2px 8px rgba(0,0,0,0.6); margin-bottom: 24px; }
h2 { margin-bottom: 20px; font-size: 1.1rem; color: #E8D5B0; }
label { display: block; margin-bottom: 4px; font-size: .875rem; color: #A89070; text-transform: uppercase; }
input, select { width: 100%; padding: 8px 12px; border: 1px solid #4A3F2F; border-radius: 3px; margin-bottom: 14px; font-size: 1rem; background: #1C1A14; color: #E8D5B0; }
input:focus, select:focus { outline: none; border-color: #C1440E; box-shadow: 0 0 0 3px rgba(193,68,14,0.4); }
button.primary { background: #C1440E; color: #E8D5B0; border: none; padding: 10px 20px; border-radius: 3px; cursor: pointer; font-size: .9rem; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; text-shadow: 0 1px 2px rgba(0,0,0,0.4); }
button.primary:hover { background: #D95A20; }
button.danger { background: #8B1A1A; color: #E8D5B0; border: none; padding: 6px 12px; border-radius: 3px; cursor: pointer; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; font-size: .85rem; }
button.danger:hover { background: #A52020; }
button.secondary { background: transparent; color: #A89070; border: 1px solid #4A3F2F; padding: 6px 12px; border-radius: 3px; cursor: pointer; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; font-size: .85rem; }
button.secondary:hover { border-color: #A89070; color: #E8D5B0; }
button.info { background: #C1440E; color: #E8D5B0; border: none; padding: 6px 12px; border-radius: 3px; cursor: pointer; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; font-size: .85rem; }
button.info:hover { background: #D95A20; }
.error { color: #D95A20; margin-bottom: 12px; font-size: .875rem; }
table { width: 100%; border-collapse: collapse; margin-top: 16px; }
th, td { padding: 10px 14px; text-align: left; border-bottom: 1px solid #eee; font-size: .9rem; }
th { background: #f9f9f9; font-weight: 600; }
th, td { padding: 10px 14px; text-align: left; border-bottom: 1px solid #4A3F2F; font-size: .9rem; color: #E8D5B0; }
th { background: #2E2B22; font-weight: 600; font-family: 'Share Tech Mono', 'Courier New', monospace; text-transform: uppercase; font-size: .8rem; color: #A89070; }
tr:nth-child(even) { background: #1E1C17; }
tr:nth-child(odd) { background: #242119; }
tr:hover { background: #2E2B22; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
.inv-badge { display: inline-block; font-size: .75rem; background: #e8f4f8; color: #2980b9; border: 1px solid #aad4e8; border-radius: 4px; padding: 2px 7px; font-family: monospace; cursor: default; }
.inv-group { background: #f0f7ff; border: 1px solid #c3dff7; border-radius: 6px; padding: 14px 18px; margin-bottom: 12px; }
.inv-group h3 { font-size: .85rem; color: #555; margin-bottom: 8px; font-weight: 600; }
.inv-badge { display: inline-block; font-size: .75rem; background: #3A2E10; color: #C8A840; border: 1px solid #8B6914; border-radius: 3px; padding: 2px 7px; font-family: monospace; cursor: default; }
.inv-group { background: #1E1C17; border: 1px solid #4A3F2F; border-radius: 3px; padding: 14px 18px; margin-bottom: 12px; }
.inv-group h3 { font-size: .85rem; color: #A89070; margin-bottom: 8px; font-weight: 600; }
.inv-group ul { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.inv-group ul li { background: #fff; border: 1px solid #ddd; border-radius: 4px; padding: 4px 10px; font-size: .875rem; }
.inv-group ul li { background: #242119; border: 1px solid #4A3F2F; border-radius: 3px; padding: 4px 10px; font-size: .875rem; color: #E8D5B0; }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; margin-bottom: 8px; }
.stat-card { background: #f0f7ff; border: 1px solid #c3dff7; border-radius: 8px; padding: 16px; text-align: center; }
.stat-card .stat-value { font-size: 1.8rem; font-weight: 700; color: #1a1a2e; margin-bottom: 4px; }
.stat-card .stat-label { font-size: .8rem; color: #666; text-transform: uppercase; letter-spacing: .5px; }
#add-user-form { display: none; background: #f9f9f9; border: 1px solid #ddd; border-radius: 6px; padding: 20px; margin-top: 16px; }
.stat-card { background: #1E1C17; border: 1px solid #4A3F2F; border-radius: 3px; padding: 16px; text-align: center; }
.stat-card .stat-value { font-size: 1.8rem; font-weight: 700; color: #C1440E; margin-bottom: 4px; }
.stat-card .stat-label { font-size: .8rem; color: #A89070; text-transform: uppercase; letter-spacing: .5px; }
#add-user-form { display: none; background: #1E1C17; border: 1px solid #4A3F2F; border-radius: 3px; padding: 20px; margin-top: 16px; }
#add-user-form.open { display: block; }
#add-user-form h3 { margin-bottom: 14px; font-size: 1rem; }
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 100; justify-content: center; align-items: center; }
#add-user-form h3 { margin-bottom: 14px; font-size: 1rem; color: #E8D5B0; }
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.7); z-index: 100; justify-content: center; align-items: center; }
.modal-overlay.open { display: flex; }
.modal { background: #fff; border-radius: 8px; padding: 28px; width: 400px; max-width: 95vw; }
.modal h3 { margin-bottom: 16px; }
.modal { background: #242119; border: 2px solid #C1440E; border-radius: 3px; padding: 28px; width: 400px; max-width: 95vw; }
.modal h3 { margin-bottom: 16px; color: #E8D5B0; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 16px; }
/* Per-inventory stats */
.inv-stats-toggle { background: none; border: none; cursor: pointer; font-size: .85rem; color: #2980b9; padding: 0; margin-top: 12px; text-decoration: underline; }
.inv-stats-toggle { background: none; border: none; cursor: pointer; font-size: .85rem; color: #C1440E; padding: 0; margin-top: 12px; text-decoration: underline; }
.inv-stats-toggle:hover { color: #D95A20; }
#inv-stats-section { display: none; margin-top: 16px; }
#inv-stats-section.open { display: block; }
#inv-stats-table th { cursor: pointer; user-select: none; white-space: nowrap; }
#inv-stats-table th:hover { background: #eef; }
#inv-stats-table th .sort-arrow { margin-left: 4px; color: #aaa; font-size: .8rem; }
#inv-stats-table th:hover { background: #3A3428; }
#inv-stats-table th .sort-arrow { margin-left: 4px; color: #6B5B3E; font-size: .8rem; }
/* Inventory list table */
.table-controls { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.table-controls input[type=text] { flex: 1; min-width: 180px; margin: 0; }
.table-controls select { width: auto; margin: 0; }
#inv-table th { cursor: pointer; user-select: none; white-space: nowrap; }
#inv-table th:hover { background: #eef; }
#inv-table th .sort-arrow { margin-left: 4px; color: #aaa; font-size: .8rem; }
#inv-table th:hover { background: #3A3428; }
#inv-table th .sort-arrow { margin-left: 4px; color: #6B5B3E; font-size: .8rem; }
.paging-bar { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.paging-bar button { padding: 4px 10px; font-size: .85rem; }
.paging-bar span { font-size: .85rem; color: #666; }
footer { text-align: center; padding: 24px 16px; margin-top: 40px; font-size: .8rem; color: #999; }
.paging-bar span { font-size: .85rem; color: #A89070; }
footer { text-align: center; padding: 24px 16px; margin-top: 40px; font-size: .8rem; color: #6B5B3E; border-top: 1px solid #4A3F2F; }
/* Scrollbar styling */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: #1A1815; }
::-webkit-scrollbar-thumb { background: #4A3F2F; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #C1440E; }
</style>
</head>
<body>
@ -191,7 +223,7 @@
<div id="del-modal" class="modal-overlay">
<div class="modal">
<h3>Benutzer löschen?</h3>
<p id="del-confirm-text" style="margin-bottom:16px; font-size:.9rem; color:#555"></p>
<p id="del-confirm-text" style="margin-bottom:16px; font-size:.9rem; color:#A89070"></p>
<div class="modal-actions">
<button class="secondary" onclick="closeModal()">Abbrechen</button>
<button class="danger" onclick="confirmDelete()">Löschen</button>
@ -203,7 +235,7 @@
<div id="assign-modal" class="modal-overlay">
<div class="modal">
<h3>Inventar zuweisen</h3>
<p style="margin-bottom:14px; font-size:.875rem; color:#555">Wähle ein bestehendes Inventar für diesen Benutzer:</p>
<p style="margin-bottom:14px; font-size:.875rem; color:#A89070">Wähle ein bestehendes Inventar für diesen Benutzer:</p>
<div id="assign-error" class="error" style="display:none"></div>
<label>Inventar</label>
<select id="assign-inventory-select"></select>