diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..7a73a41
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,2 @@
+{
+}
\ No newline at end of file
diff --git a/app.js b/app.js
index 4775cfb..b29641a 100644
--- a/app.js
+++ b/app.js
@@ -5,33 +5,56 @@ const loginBtn = document.getElementById("login-btn");
const loginStatus = document.getElementById("login-status");
const userDisplay = document.getElementById("user-display");
-loginBtn.addEventListener("click", () => {
+loginBtn.addEventListener("click", async () => {
const user = document.getElementById("username").value.trim();
const pass = document.getElementById("password").value.trim();
- const found = USERS.find(u => u.username === user && u.password === pass);
+ if (!user || !pass) {
+ loginStatus.textContent = "Bitte Dienstkennung und Passwort eingeben.";
+ return;
+ }
loginStatus.textContent = "Authentifizierung läuft…";
- setTimeout(() => {
- if (!found) {
- loginStatus.textContent = "Zugang verweigert – ungültige Anmeldedaten.";
- return;
- }
+ // Kurze Verzögerung für realistischen Effekt
+ await new Promise(r => setTimeout(r, 800));
+
+ const found = await authenticateUser(user, pass);
+
+ if (!found) {
+ loginStatus.textContent = "Zugang verweigert – ungültige Anmeldedaten.";
+ return;
+ }
+
+ loginScreen.style.display = "none";
+ app.style.display = "flex";
- loginScreen.style.display = "none";
- app.style.display = "flex";
+ userDisplay.textContent = found.username.toUpperCase();
- userDisplay.textContent = found.username.toUpperCase();
+ document.getElementById("audit-log").textContent =
+ "Zugriff protokolliert – " +
+ new Date().toLocaleString("de-DE") +
+ " – Benutzer: " +
+ found.username;
- document.getElementById("audit-log").textContent =
- "Zugriff protokolliert – " +
- new Date().toLocaleString("de-DE") +
- " – Benutzer: " +
- found.username;
+ loadAndRender();
+});
- loadAndRender();
- }, 700);
+// LOGOUT
+document.getElementById("logout-btn").addEventListener("click", () => {
+ app.style.display = "none";
+ loginScreen.style.display = "flex";
+ document.getElementById("username").value = "";
+ document.getElementById("password").value = "";
+ loginStatus.textContent = "";
+});
+
+// Enter-Taste im Login
+document.getElementById("password").addEventListener("keydown", (e) => {
+ if (e.key === "Enter") loginBtn.click();
+});
+document.getElementById("username").addEventListener("keydown", (e) => {
+ if (e.key === "Enter") loginBtn.click();
});
// LOCAL STORAGE PERSONS
diff --git a/index.html b/index.html
index ffda592..5fcd073 100644
--- a/index.html
+++ b/index.html
@@ -2,31 +2,49 @@
@@ -71,8 +112,11 @@
Module
@@ -82,6 +126,7 @@
Module
+
@@ -89,79 +134,94 @@
Module
-
Personen – Trefferliste
-
-
-
- | ID |
- Name |
- Geburtsdatum |
- Status |
- Region |
-
-
-
-
+
Personen – Trefferliste
+
+
+
+
+ | ID |
+ Name |
+ Geburtsdatum |
+ Status |
+ Region |
+
+
+
+
+
-
Personen – Details
+
Personen – Details
-
Bitte einen Datensatz aus der Liste auswählen.
+
+
+
Bitte einen Datensatz aus der Liste auswählen.
+
-
Fahrzeuge – Trefferliste
-
-
-
- | ID |
- Kennzeichen |
- Typ |
- Status |
- Region |
-
-
-
-
+
Fahrzeuge – Trefferliste
+
+
+
+
+ | ID |
+ Kennzeichen |
+ Typ |
+ Status |
+ Region |
+
+
+
+
+
-
Fahrzeuge – Details
+
Fahrzeuge – Details
-
Bitte ein Fahrzeug aus der Liste auswählen.
+
+
+
Bitte ein Fahrzeug aus der Liste auswählen.
+
-
Fälle – Trefferliste
-
-
-
- | AZ |
- Titel |
- Status |
- Region |
- Ermittler |
-
-
-
-
+
Fälle – Trefferliste
+
+
+
+
+ | AZ |
+ Titel |
+ Status |
+ Region |
+ Ermittler |
+
+
+
+
+
-
Fälle – Details
+
Fälle – Details
-
Bitte einen Fall aus der Liste auswählen.
+
+
+
Bitte einen Fall aus der Liste auswählen.
+
-
Kartenansicht
+
Kartenansicht – Einsatzgebiet Rhein-Main
-
- Darstellung beispielhaft (Raum Rhein-Main). Für Filmzwecke kannst du diesen Ausschnitt nutzen.
-
-
Neuen Personendatensatz hinzufügen
+
Neuen Personendatensatz hinzufügen
-
-
+
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
+
-
+
diff --git a/style.css b/style.css
index 0bff615..139b041 100644
--- a/style.css
+++ b/style.css
@@ -2,15 +2,16 @@
box-sizing: border-box;
margin: 0;
padding: 0;
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
body {
- background: #05070b;
+ background: #0a0e1a;
color: #e5e7eb;
+ overflow: hidden;
}
-/* LOGIN */
+/* ===== LOGIN ===== */
.login-screen {
position: fixed;
@@ -18,73 +19,142 @@ body {
display: flex;
align-items: center;
justify-content: center;
- background: radial-gradient(circle at top, #111827, #020617);
+ background: linear-gradient(135deg, #0a0e1a 0%, #1a1f3a 50%, #0a0e1a 100%);
+}
+
+.login-screen::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: url('data:image/svg+xml,
');
+ opacity: 0.5;
}
.login-box {
- background: #020617;
- border: 1px solid #1f2937;
- padding: 2rem 2.5rem;
- width: 360px;
- box-shadow: 0 0 40px rgba(0,0,0,0.7);
+ position: relative;
+ background: rgba(10, 14, 26, 0.9);
+ border: 1px solid rgba(59, 130, 246, 0.3);
+ padding: 2.5rem 3rem;
+ width: 400px;
+ box-shadow: 0 0 60px rgba(59, 130, 246, 0.1), 0 0 120px rgba(0,0,0,0.5);
text-align: center;
- border-radius: 6px;
+ border-radius: 12px;
+ backdrop-filter: blur(20px);
+}
+
+.login-header {
+ margin-bottom: 1.5rem;
}
.login-logo {
- width: 100%;
+ width: 80%;
+ max-width: 280px;
margin-bottom: 1rem;
+ border-radius: 8px;
+}
+
+.login-badge {
+ display: inline-block;
+ padding: 0.25rem 1rem;
+ background: rgba(239, 68, 68, 0.15);
+ border: 1px solid rgba(239, 68, 68, 0.4);
+ color: #ef4444;
+ font-size: 0.7rem;
+ font-weight: 700;
+ letter-spacing: 0.2em;
border-radius: 4px;
}
.login-box h1 {
- font-size: 1.2rem;
- margin-bottom: 1.5rem;
- letter-spacing: 0.12em;
- color: #60a5fa;
+ font-size: 1.8rem;
+ margin-bottom: 0.5rem;
+ letter-spacing: 0.15em;
+ color: #3b82f6;
+ font-weight: 800;
}
-.login-box label {
- display: block;
- margin-top: 0.75rem;
- margin-bottom: 0.25rem;
+.login-subtitle {
+ font-size: 0.8rem;
+ color: #6b7280;
+ margin-bottom: 2rem;
+ line-height: 1.5;
+}
+
+.login-form {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.input-group {
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+
+.input-group i {
+ position: absolute;
+ left: 12px;
+ color: #6b7280;
font-size: 0.85rem;
- color: #9ca3af;
- text-align: left;
}
-.login-box input {
+.input-group input {
width: 100%;
- padding: 0.5rem 0.6rem;
- background: #020617;
- border: 1px solid #374151;
+ padding: 0.75rem 0.75rem 0.75rem 2.5rem;
+ background: rgba(15, 23, 42, 0.8);
+ border: 1px solid #1e293b;
color: #e5e7eb;
- border-radius: 4px;
+ border-radius: 8px;
+ font-size: 0.9rem;
+ transition: border-color 0.2s, box-shadow 0.2s;
+}
+
+.input-group input:focus {
+ outline: none;
+ border-color: #3b82f6;
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.login-box button {
- margin-top: 1rem;
+ margin-top: 0.5rem;
width: 100%;
- padding: 0.6rem;
- background: #2563eb;
+ padding: 0.75rem;
+ background: linear-gradient(135deg, #2563eb, #1d4ed8);
border: none;
color: white;
font-weight: 600;
+ font-size: 0.9rem;
cursor: pointer;
- border-radius: 4px;
+ border-radius: 8px;
+ transition: transform 0.1s, box-shadow 0.2s;
}
.login-box button:hover {
- background: #1d4ed8;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
+}
+
+.login-box button:active {
+ transform: translateY(0);
}
.login-status {
- margin-top: 0.75rem;
+ margin-top: 1rem;
font-size: 0.8rem;
- color: #9ca3af;
+ color: #f97316;
+ min-height: 1.2em;
+}
+
+.login-footer {
+ margin-top: 1.5rem;
+ font-size: 0.7rem;
+ color: #ef4444;
+ opacity: 0.7;
}
-/* APP LAYOUT */
+
+/* ===== APP LAYOUT ===== */
.app {
height: 100vh;
@@ -93,55 +163,108 @@ body {
}
.topbar {
- height: 56px;
- background: #020617;
- border-bottom: 1px solid #111827;
+ height: 60px;
+ background: rgba(10, 14, 26, 0.95);
+ border-bottom: 1px solid rgba(59, 130, 246, 0.15);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1.5rem;
+ backdrop-filter: blur(10px);
}
.topbar-left {
display: flex;
align-items: center;
+ gap: 1rem;
}
.topbar-logo {
- height: 40px;
- margin-right: 1rem;
- border-radius: 4px;
+ height: 42px;
+ border-radius: 6px;
+}
+
+.topbar-brand {
+ display: flex;
+ flex-direction: column;
}
.logo {
- font-weight: 700;
+ font-weight: 800;
letter-spacing: 0.2em;
- color: #60a5fa;
- margin-right: 0.75rem;
+ color: #3b82f6;
+ font-size: 1.1rem;
}
.subtitle {
- font-size: 0.8rem;
- color: #9ca3af;
+ font-size: 0.7rem;
+ color: #6b7280;
+ letter-spacing: 0.05em;
}
.topbar-right {
display: flex;
align-items: center;
- gap: 0.75rem;
+ gap: 1rem;
+}
+
+.topbar-status {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.topbar-user {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
font-size: 0.85rem;
+ color: #94a3b8;
+ padding: 0.4rem 0.75rem;
+ background: rgba(30, 41, 59, 0.5);
+ border-radius: 6px;
+ border: 1px solid #1e293b;
+}
+
+.btn-logout {
+ background: rgba(239, 68, 68, 0.1);
+ border: 1px solid rgba(239, 68, 68, 0.3);
+ color: #ef4444;
+ padding: 0.5rem 0.6rem;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background 0.2s;
+}
+
+.btn-logout:hover {
+ background: rgba(239, 68, 68, 0.2);
}
.badge {
- padding: 0.15rem 0.5rem;
- border-radius: 999px;
- font-size: 0.7rem;
+ padding: 0.2rem 0.6rem;
+ border-radius: 6px;
+ font-size: 0.65rem;
+ font-weight: 600;
+ letter-spacing: 0.05em;
border: 1px solid;
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+}
+
+.badge i {
+ font-size: 0.5rem;
}
.badge-green {
- border-color: #22c55e;
+ border-color: rgba(34, 197, 94, 0.4);
color: #22c55e;
+ background: rgba(34, 197, 94, 0.08);
+}
+
+.badge-blue {
+ border-color: rgba(59, 130, 246, 0.4);
+ color: #3b82f6;
+ background: rgba(59, 130, 246, 0.08);
}
.layout {
@@ -150,66 +273,107 @@ body {
min-height: 0;
}
-/* SIDEBAR */
+
+/* ===== SIDEBAR ===== */
.sidebar {
- width: 220px;
- background: #020617;
- border-right: 1px solid #111827;
- padding: 1rem;
+ width: 240px;
+ background: rgba(10, 14, 26, 0.95);
+ border-right: 1px solid rgba(59, 130, 246, 0.1);
+ padding: 1.25rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
+.sidebar-top {}
+
.sidebar h2 {
- font-size: 0.9rem;
+ font-size: 0.75rem;
text-transform: uppercase;
- letter-spacing: 0.12em;
+ letter-spacing: 0.15em;
color: #6b7280;
- margin-bottom: 0.75rem;
+ margin-bottom: 1rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.sidebar ul {
list-style: none;
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
}
.sidebar li {
- padding: 0.4rem 0.5rem;
- font-size: 0.9rem;
- color: #e5e7eb;
+ padding: 0.6rem 0.75rem;
+ font-size: 0.85rem;
+ color: #94a3b8;
cursor: pointer;
- border-radius: 0.25rem;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+ transition: all 0.15s;
+}
+
+.sidebar li i {
+ width: 18px;
+ text-align: center;
+ font-size: 0.8rem;
}
.sidebar li:hover {
- background: #111827;
+ background: rgba(59, 130, 246, 0.08);
+ color: #e5e7eb;
}
.sidebar li.active {
- background: #1f2937;
+ background: rgba(59, 130, 246, 0.15);
+ color: #3b82f6;
+ font-weight: 600;
+ border: 1px solid rgba(59, 130, 246, 0.2);
}
.sidebar-footer {
+ padding-top: 1rem;
+ border-top: 1px solid #1e293b;
+}
+
+.audit-header {
font-size: 0.75rem;
color: #6b7280;
+ margin-bottom: 0.4rem;
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+}
+
+.sidebar-footer small {
+ font-size: 0.7rem;
+ color: #475569;
+ line-height: 1.4;
}
-/* MAIN */
+
+/* ===== MAIN CONTENT ===== */
.main {
flex: 1;
- padding: 1rem 1.5rem;
+ padding: 1.25rem;
display: flex;
flex-direction: column;
gap: 1rem;
+ overflow-y: auto;
+ background: #0d1117;
}
.search-section {
- background: #020617;
- border: 1px solid #111827;
- padding: 0.75rem 1rem;
- border-radius: 0.25rem;
+ background: rgba(10, 14, 26, 0.8);
+ border: 1px solid #1e293b;
+ padding: 1rem 1.25rem;
+ border-radius: 10px;
}
.search-row {
@@ -217,183 +381,313 @@ body {
gap: 0.5rem;
}
-.search-row input {
+.search-input-wrapper {
flex: 1;
- padding: 0.5rem 0.6rem;
- background: #020617;
- border: 1px solid #374151;
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+
+.search-input-wrapper i {
+ position: absolute;
+ left: 12px;
+ color: #6b7280;
+}
+
+.search-input-wrapper input {
+ width: 100%;
+ padding: 0.65rem 0.75rem 0.65rem 2.5rem;
+ background: rgba(15, 23, 42, 0.8);
+ border: 1px solid #1e293b;
color: #e5e7eb;
- border-radius: 4px;
+ border-radius: 8px;
+ font-size: 0.85rem;
+ transition: border-color 0.2s;
+}
+
+.search-input-wrapper input:focus {
+ outline: none;
+ border-color: #3b82f6;
}
.search-row button {
- padding: 0.5rem 0.9rem;
- background: #2563eb;
+ padding: 0.65rem 1.25rem;
+ background: linear-gradient(135deg, #2563eb, #1d4ed8);
border: none;
color: white;
- font-size: 0.9rem;
+ font-size: 0.85rem;
+ font-weight: 600;
cursor: pointer;
- border-radius: 4px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ transition: transform 0.1s;
}
.search-row button:hover {
- background: #1d4ed8;
+ transform: translateY(-1px);
}
.filters-row {
- margin-top: 0.5rem;
+ margin-top: 0.75rem;
+ display: flex;
+ align-items: center;
+ gap: 1rem;
}
.filters-row select {
- padding: 0.35rem 0.5rem;
- background: #020617;
- border: 1px solid #374151;
+ padding: 0.4rem 0.75rem;
+ background: rgba(15, 23, 42, 0.8);
+ border: 1px solid #1e293b;
color: #e5e7eb;
- font-size: 0.85rem;
- border-radius: 4px;
+ font-size: 0.8rem;
+ border-radius: 6px;
+}
+
+.result-count {
+ font-size: 0.75rem;
+ color: #6b7280;
}
-/* CONTENT */
+
+/* ===== CONTENT GRID ===== */
.content {
display: grid;
- grid-template-columns: 2fr 1.3fr;
+ grid-template-columns: 1.8fr 1.2fr;
gap: 1rem;
+ flex: 1;
min-height: 0;
}
.results, .details {
- background: #020617;
- border: 1px solid #111827;
- border-radius: 0.25rem;
- padding: 0.75rem 1rem;
+ background: rgba(10, 14, 26, 0.8);
+ border: 1px solid #1e293b;
+ border-radius: 10px;
+ padding: 1rem 1.25rem;
display: flex;
flex-direction: column;
min-height: 0;
+ overflow: hidden;
}
.results h2, .details h2 {
- font-size: 0.9rem;
+ font-size: 0.8rem;
text-transform: uppercase;
- letter-spacing: 0.12em;
+ letter-spacing: 0.1em;
color: #6b7280;
- margin-bottom: 0.5rem;
+ margin-bottom: 0.75rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding-bottom: 0.75rem;
+ border-bottom: 1px solid #1e293b;
+}
+
+.table-wrapper {
+ overflow-y: auto;
+ flex: 1;
}
.results table {
width: 100%;
border-collapse: collapse;
- font-size: 0.85rem;
+ font-size: 0.8rem;
}
.results thead {
- background: #020617;
- border-bottom: 1px solid #111827;
+ position: sticky;
+ top: 0;
+ background: #0a0e1a;
+ z-index: 1;
}
-.results th, .results td {
- padding: 0.35rem 0.25rem;
+.results th {
+ padding: 0.5rem 0.5rem;
text-align: left;
+ color: #6b7280;
+ font-weight: 600;
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ border-bottom: 1px solid #1e293b;
+}
+
+.results td {
+ padding: 0.5rem 0.5rem;
+ text-align: left;
+ border-bottom: 1px solid rgba(30, 41, 59, 0.5);
}
.results tbody tr {
cursor: pointer;
+ transition: background 0.1s;
}
-.results tbody tr:nth-child(even) {
- background: #020617;
+.results tbody tr:hover {
+ background: rgba(59, 130, 246, 0.06);
}
-.results tbody tr:hover {
- background: #111827;
+.results tbody tr:active {
+ background: rgba(59, 130, 246, 0.12);
}
.status-pill {
- padding: 0.1rem 0.4rem;
- border-radius: 999px;
- font-size: 0.7rem;
+ padding: 0.15rem 0.5rem;
+ border-radius: 6px;
+ font-size: 0.65rem;
+ font-weight: 600;
+ letter-spacing: 0.03em;
border: 1px solid;
}
.status-AKTIV {
- border-color: #60a5fa;
+ border-color: rgba(59, 130, 246, 0.4);
color: #60a5fa;
+ background: rgba(59, 130, 246, 0.08);
}
.status-GESUCHT {
- border-color: #f97316;
+ border-color: rgba(249, 115, 22, 0.4);
color: #f97316;
+ background: rgba(249, 115, 22, 0.08);
}
.status-ARCHIVIERT {
- border-color: #6b7280;
- color: #6b7280;
+ border-color: rgba(107, 114, 128, 0.4);
+ color: #9ca3af;
+ background: rgba(107, 114, 128, 0.08);
}
-.details-content p {
+
+/* ===== DETAILS PANEL ===== */
+
+.details {
+ overflow-y: auto;
+}
+
+.empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 3rem 1rem;
+ color: #475569;
+}
+
+.empty-state i {
+ font-size: 2rem;
+ margin-bottom: 0.75rem;
+ opacity: 0.5;
+}
+
+.empty-state p {
font-size: 0.85rem;
- margin-bottom: 0.25rem;
}
-.details-content .label {
- font-size: 0.75rem;
- text-transform: uppercase;
- letter-spacing: 0.12em;
- color: #6b7280;
- margin-top: 0.5rem;
+.details-content {
+ animation: fadeIn 0.2s ease;
}
-/* BILDER */
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(4px); }
+ to { opacity: 1; transform: translateY(0); }
+}
.details-content img {
width: 100%;
- border-radius: 6px;
+ border-radius: 8px;
margin-bottom: 1rem;
+ border: 1px solid #1e293b;
+}
+
+.details-content .label {
+ font-size: 0.65rem;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: #6b7280;
+ margin-top: 0.75rem;
+ font-weight: 600;
+}
+
+.details-content p {
+ font-size: 0.85rem;
+ margin-top: 0.15rem;
+ color: #e5e7eb;
}
.result-photo {
- width: 40px;
- height: 40px;
+ width: 36px;
+ height: 36px;
object-fit: cover;
- border-radius: 4px;
+ border-radius: 6px;
margin-right: 0.5rem;
vertical-align: middle;
+ border: 1px solid #1e293b;
}
-/* ADMIN PANEL */
+/* ===== ADMIN PANEL ===== */
.admin-panel {
- background: #020617;
- border: 1px solid #111827;
- padding: 1rem;
- margin-top: 1rem;
- border-radius: 0.25rem;
+ background: rgba(10, 14, 26, 0.8);
+ border: 1px solid #1e293b;
+ padding: 1.5rem;
+ margin-top: 0.5rem;
+ border-radius: 10px;
}
.admin-panel h2 {
- font-size: 0.9rem;
+ font-size: 0.85rem;
text-transform: uppercase;
color: #6b7280;
- margin-bottom: 0.75rem;
+ margin-bottom: 1.25rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ letter-spacing: 0.08em;
+}
+
+.admin-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+}
+
+.admin-field {
+ display: flex;
+ flex-direction: column;
+}
+
+.admin-field.full-width {
+ grid-column: 1 / -1;
}
.admin-panel label {
- display: block;
- margin-top: 0.5rem;
- font-size: 0.8rem;
- color: #9ca3af;
+ font-size: 0.75rem;
+ color: #94a3b8;
+ margin-bottom: 0.3rem;
+ font-weight: 500;
}
.admin-panel input,
.admin-panel select,
.admin-panel textarea {
width: 100%;
- margin-top: 0.25rem;
- padding: 0.4rem;
- background: #020617;
- border: 1px solid #374151;
+ padding: 0.6rem 0.75rem;
+ background: rgba(15, 23, 42, 0.8);
+ border: 1px solid #1e293b;
color: #e5e7eb;
- border-radius: 4px;
+ border-radius: 8px;
+ font-size: 0.85rem;
+ transition: border-color 0.2s;
+}
+
+.admin-panel input:focus,
+.admin-panel select:focus,
+.admin-panel textarea:focus {
+ outline: none;
+ border-color: #3b82f6;
}
.admin-panel textarea {
@@ -402,44 +696,55 @@ body {
}
.admin-panel button {
- margin-top: 1rem;
+ margin-top: 1.25rem;
width: 100%;
- padding: 0.6rem;
- background: #2563eb;
+ padding: 0.75rem;
+ background: linear-gradient(135deg, #2563eb, #1d4ed8);
border: none;
color: white;
+ font-weight: 600;
+ font-size: 0.9rem;
cursor: pointer;
- border-radius: 4px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ transition: transform 0.1s;
}
.admin-panel button:hover {
- background: #1d4ed8;
+ transform: translateY(-1px);
}
-/* MAP VIEW */
+
+/* ===== MAP VIEW ===== */
.map-view {
grid-column: 1 / span 2;
- background: #020617;
- border: 1px solid #111827;
- border-radius: 0.25rem;
- padding: 0.75rem 1rem;
+ background: rgba(10, 14, 26, 0.8);
+ border: 1px solid #1e293b;
+ border-radius: 10px;
+ padding: 1rem 1.25rem;
}
.map-view h2 {
- font-size: 0.9rem;
+ font-size: 0.8rem;
text-transform: uppercase;
- letter-spacing: 0.12em;
+ letter-spacing: 0.1em;
color: #6b7280;
- margin-bottom: 0.5rem;
+ margin-bottom: 0.75rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.map-container {
width: 100%;
- height: 350px;
- border-radius: 4px;
+ height: 400px;
+ border-radius: 8px;
overflow: hidden;
- margin-bottom: 0.5rem;
+ border: 1px solid #1e293b;
}
.map-container iframe {
@@ -447,34 +752,71 @@ body {
height: 100%;
}
-.map-hint {
- font-size: 0.8rem;
- color: #9ca3af;
+/* ===== SCROLLBAR ===== */
+
+::-webkit-scrollbar {
+ width: 6px;
}
-/* UTILS */
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #1e293b;
+ border-radius: 3px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #334155;
+}
+
+/* ===== UTILS ===== */
.hidden {
display: none !important;
}
-/* RESPONSIVE */
+/* ===== RESPONSIVE ===== */
-@media (max-width: 900px) {
+@media (max-width: 1100px) {
.content {
grid-template-columns: 1fr;
}
+ .map-view {
+ grid-column: 1;
+ }
}
-@media (max-width: 700px) {
+@media (max-width: 768px) {
.layout {
flex-direction: column;
}
.sidebar {
+ width: 100%;
flex-direction: row;
align-items: center;
- width: 100%;
border-right: none;
- border-bottom: 1px solid #111827;
+ border-bottom: 1px solid #1e293b;
+ padding: 0.75rem 1rem;
+ }
+ .sidebar-top {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ width: 100%;
+ }
+ .sidebar h2 {
+ display: none;
+ }
+ .sidebar ul {
+ flex-direction: row;
+ gap: 0.25rem;
+ }
+ .sidebar-footer {
+ display: none;
+ }
+ .topbar-status {
+ display: none;
}
}
diff --git a/users.js b/users.js
index 6f30990..706a994 100644
--- a/users.js
+++ b/users.js
@@ -1,5 +1,49 @@
-const USERS = [
- { username: "Hessen7504", password: "cobra11" },
- { username: "Hessen3840", password: "cobra111" },
- { username: "admin", password: "rootaccess" }
+// ============================================================
+// POLIS – Authentifizierungsmodul
+// ============================================================
+// Zugangsdaten sind als SHA-256 Hashes gespeichert.
+// Passwörter können NICHT im Klartext ausgelesen werden.
+// Benutzer müssen ihre Zugangsdaten bereits kennen.
+// ============================================================
+
+const USERS_HASHED = [
+ {
+ usernameHash: "5e98b64a2cfa94a131b215cd03c9c43fd4dc602acfb7d597480f27ce9a29f9e7",
+ passwordHash: "cb2a35ff149a556cf437b63692856294f409207d5d53dd6584c4cb0bb1ea0bd5",
+ role: "operator"
+ },
+ {
+ usernameHash: "6644ae39e5f414cdbedf4b14694c3fdf4e8c932ada781d38dabc21a4ffa0ab20",
+ passwordHash: "96fa370bc7a55fb029e53a75d8eeec5cb98d10110cc5f1192e1ec5ad94f06d69",
+ role: "operator"
+ },
+ {
+ usernameHash: "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
+ passwordHash: "778c78fa79d89cd2a93096b793485141f88f6eb44c18fdb78f0912997293373f",
+ role: "admin"
+ }
];
+
+// SHA-256 Hash-Funktion (Web Crypto API)
+async function hashSHA256(text) {
+ const encoder = new TextEncoder();
+ const data = encoder.encode(text);
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ return hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
+}
+
+// Authentifizierung prüfen – gibt User-Objekt oder null zurück
+async function authenticateUser(username, password) {
+ const uHash = await hashSHA256(username);
+ const pHash = await hashSHA256(password);
+
+ const match = USERS_HASHED.find(
+ u => u.usernameHash === uHash && u.passwordHash === pHash
+ );
+
+ if (match) {
+ return { username: username, role: match.role };
+ }
+ return null;
+}