refactor(ui): remove admin-tools, strip emojis, and align design strictly with philippurbschat.de
This commit is contained in:
parent
588e1c1cb4
commit
76640d8bbf
11 changed files with 330 additions and 501 deletions
|
|
@ -1,136 +0,0 @@
|
||||||
<?php
|
|
||||||
// Schritt 1: Das Projekt meldet sich beim Türsteher
|
|
||||||
$current_project = 'admin-tools';
|
|
||||||
require_once '../auth.php'; // Der Türsteher prüft, ob du Admin bist
|
|
||||||
|
|
||||||
// Schritt 2: Prüfen, ob das Formular abgeschickt wurde
|
|
||||||
$generated_hash = null;
|
|
||||||
$original_password = '';
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['password_to_hash'])) {
|
|
||||||
$original_password = $_POST['password_to_hash'];
|
|
||||||
$generated_hash = password_hash($original_password, PASSWORD_DEFAULT);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Admin: Hash-Generator</title>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Lato:wght@400;700&display=swap" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
/* ... komplettes CSS von vorher ... */
|
|
||||||
:root {
|
|
||||||
--primary-color: #00e6e6; /* Aqua Blue */
|
|
||||||
--secondary-color: #ff66b2; /* Hot Pink */
|
|
||||||
--background-color: #121212;
|
|
||||||
--box-bg-color: #1f1f1f;
|
|
||||||
--text-color: #e0e0e0;
|
|
||||||
--error-color: #ff4d4d;
|
|
||||||
--glow-effect: none;
|
|
||||||
--retro-font: "Press Start 2P", cursive;
|
|
||||||
--modern-font: "Lato", sans-serif;
|
|
||||||
--cat-body-color: #8a2be2;
|
|
||||||
--cat-detail-color: var(--secondary-color);
|
|
||||||
--cat-eye-color: var(--primary-color);
|
|
||||||
--pixel-size: 2px;
|
|
||||||
}
|
|
||||||
body { font-family: var(--modern-font); background-color: var(--background-color); color: var(--text-color); margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow: hidden; position: relative; }
|
|
||||||
body::before { content: ""; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: repeating-linear-gradient(transparent, rgba(0, 0, 0, 0.3) 1px, transparent 4px); pointer-events: none; animation: scanlines 4s linear infinite; z-index: 100; }
|
|
||||||
.container { text-align: center; padding: 2rem; max-width: 90%; width: 400px; }
|
|
||||||
.header h1 { font-family: var(--retro-font); color: var(--primary-color); font-size: 2.5rem; text-shadow: none; margin-bottom: 0.5rem; }
|
|
||||||
.header p { font-family: var(--retro-font); color: var(--secondary-color); font-size: 1rem; margin-bottom: 2rem; }
|
|
||||||
.pixel-cat { position: relative; width: calc(30 * var(--pixel-size)); height: calc(35 * var(--pixel-size)); margin: 0 auto -10px; z-index: 10; }
|
|
||||||
.cat-body { position: absolute; top: calc(15 * var(--pixel-size)); left: calc(5 * var(--pixel-size)); width: calc(20 * var(--pixel-size)); height: calc(15 * var(--pixel-size)); background-color: var(--cat-body-color); z-index: 1; }
|
|
||||||
.cat-head { position: absolute; top: calc(5 * var(--pixel-size)); left: calc(8 * var(--pixel-size)); width: calc(14 * var(--pixel-size)); height: calc(10 * var(--pixel-size)); background-color: var(--cat-body-color); z-index: 2; }
|
|
||||||
.cat-ear { position: absolute; width: calc(4 * var(--pixel-size)); height: calc(5 * var(--pixel-size)); background-color: var(--cat-body-color); z-index: 0; }
|
|
||||||
.cat-ear.left { top: calc(0 * var(--pixel-size)); left: calc(7 * var(--pixel-size)); }
|
|
||||||
.cat-ear.right { top: calc(0 * var(--pixel-size)); right: calc(7 * var(--pixel-size)); }
|
|
||||||
.cat-eye { position: absolute; width: calc(2 * var(--pixel-size)); height: calc(2 * var(--pixel-size)); background-color: var(--cat-eye-color); z-index: 3; animation: eye-blink 10s infinite; }
|
|
||||||
.cat-eye.left { top: calc(8 * var(--pixel-size)); left: calc(10 * var(--pixel-size)); }
|
|
||||||
.cat-eye.right { top: calc(8 * var(--pixel-size)); right: calc(10 * var(--pixel-size)); }
|
|
||||||
.cat-nose { position: absolute; top: calc(11 * var(--pixel-size)); left: calc(14 * var(--pixel-size)); width: calc(2 * var(--pixel-size)); height: calc(1 * var(--pixel-size)); background-color: var(--cat-detail-color); z-index: 3; }
|
|
||||||
.cat-tail { position: absolute; top: calc(19 * var(--pixel-size)); left: calc(22 * var(--pixel-size)); width: calc(3 * var(--pixel-size)); height: calc(10 * var(--pixel-size)); background-color: var(--cat-body-color); transform-origin: bottom center; animation: tail-wag 15s infinite; z-index: 0; }
|
|
||||||
.main-content { background-color: var(--box-bg-color); padding: 2rem; border: 2px solid var(--cat-body-color); box-shadow: none; border-radius: 0; position: relative; overflow: hidden; min-height: 350px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
|
|
||||||
.input-group { margin-bottom: 1.5rem; text-align: left; width: 100%; }
|
|
||||||
.input-group label { display: block; font-family: var(--retro-font); color: var(--text-color); margin-bottom: 0.5rem; font-size: 0.8rem; }
|
|
||||||
.input-group input { width: 100%; padding: 10px; border: 2px solid var(--primary-color); background-color: rgba(0, 0, 0, 0.4); color: var(--primary-color); font-family: var(--retro-font); outline: none; box-shadow: none; transition: box-shadow 0.3s ease, border-color 0.3s ease; box-sizing: border-box; }
|
|
||||||
.input-group input:focus { border-color: var(--secondary-color); }
|
|
||||||
.login-btn, .retry-btn { width: 100%; padding: 12px; background-color: var(--primary-color); color: var(--background-color); font-family: var(--retro-font); border: none; cursor: pointer; font-size: 1rem; text-transform: uppercase; transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease; text-decoration: none; display: block; box-sizing: border-box; margin-bottom: 1rem; }
|
|
||||||
.login-btn:hover, .retry-btn:hover { transform: translateY(-2px); background-color: var(--secondary-color); box-shadow: 0 4px 8px rgba(0,0,0,0.3); }
|
|
||||||
.result { margin-top: 2rem; background-color: rgba(0,0,0,0.4); padding: 1rem; text-align: left; font-family: monospace; color: var(--primary-color); word-wrap: break-word; width: 100%; box-sizing: border-box; }
|
|
||||||
.result code { font-size: 0.9rem; }
|
|
||||||
/* --- NEU: Style für klickbaren Hash --- */
|
|
||||||
.result code {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s ease;
|
|
||||||
}
|
|
||||||
.result code:hover {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
@keyframes scanlines { 0% { background-position: 0 0; } 100% { background-position: 0 50px; } }
|
|
||||||
@keyframes tail-wag { 0%, 90% { transform: rotate(0deg); } 92.5% { transform: rotate(0deg); } 95% { transform: rotate(25deg); } 97.5% { transform: rotate(0deg); } 100% { transform: rotate(0deg); } }
|
|
||||||
@keyframes eye-blink { 0%, 99% { transform: scaleY(1); } 100% { transform: scaleY(0); } }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div style="position: fixed; top: 16px; left: 16px; z-index: 200; display: flex; gap: 16px; font-family: var(--retro-font); font-size: 0.65rem;">
|
|
||||||
<a href="/admin" style="color: var(--primary-color); text-decoration: none; padding: 6px 10px; background: rgba(0,0,0,0.6); border: 1px solid var(--primary-color);">< /ADMIN</a>
|
|
||||||
<a href="/admin/users" style="color: var(--primary-color); text-decoration: none; padding: 6px 10px; background: rgba(0,0,0,0.6); border: 1px solid var(--primary-color);">BENUTZER</a>
|
|
||||||
<a href="/" style="color: var(--secondary-color); text-decoration: none; padding: 6px 10px; background: rgba(0,0,0,0.6); border: 1px solid var(--secondary-color);">HOME</a>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<header class="header">
|
|
||||||
<h1>ADMIN TOOLS</h1>
|
|
||||||
<p>Password Hash Generator</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="pixel-cat"></div>
|
|
||||||
|
|
||||||
<main class="main-content">
|
|
||||||
<form action="index.php" method="POST" style="width: 100%;">
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="password_input">NEW PASSWORD</label>
|
|
||||||
<input type="text" id="password_input" name="password_to_hash" placeholder="> Enter new key" autofocus>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="login-btn">GENERATE HASH</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<?php if ($generated_hash): ?>
|
|
||||||
<div class="result">
|
|
||||||
<strong>Original:</strong> <?php echo htmlspecialchars($original_password); ?><br><br>
|
|
||||||
<strong id="hash-label">Hash (klicken zum Kopieren):</strong><br>
|
|
||||||
<code id="hash-output"><?php echo $generated_hash; ?></code>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<a href="../index.php" class="retry-btn" style="margin-top: 2rem; background-color: #555;">BACK</a>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const hashOutput = document.getElementById('hash-output');
|
|
||||||
const hashLabel = document.getElementById('hash-label');
|
|
||||||
|
|
||||||
if (hashOutput) {
|
|
||||||
hashOutput.addEventListener('click', () => {
|
|
||||||
const hashText = hashOutput.innerText;
|
|
||||||
navigator.clipboard.writeText(hashText).then(() => {
|
|
||||||
// Erfolgreich kopiert! Gib dem Nutzer Feedback.
|
|
||||||
hashLabel.innerText = 'Kopiert! ✔️';
|
|
||||||
// Ändere es nach 2 Sekunden zurück.
|
|
||||||
setTimeout(() => {
|
|
||||||
hashLabel.innerHTML = 'Hash (klicken zum Kopieren):';
|
|
||||||
}, 2000);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('Fehler beim Kopieren: ', err);
|
|
||||||
hashLabel.innerText = 'Fehler beim Kopieren!';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -4,7 +4,6 @@ class ModuleService {
|
||||||
'dinos' => [
|
'dinos' => [
|
||||||
'slug' => 'dinos',
|
'slug' => 'dinos',
|
||||||
'name' => 'Dino Generator',
|
'name' => 'Dino Generator',
|
||||||
'icon' => '🦖',
|
|
||||||
'badge' => 'AI Art',
|
'badge' => 'AI Art',
|
||||||
'description' => 'KI Dino-Bilderstellung & Google Photos Sync',
|
'description' => 'KI Dino-Bilderstellung & Google Photos Sync',
|
||||||
'path' => '/dinos',
|
'path' => '/dinos',
|
||||||
|
|
@ -13,7 +12,6 @@ class ModuleService {
|
||||||
'plants' => [
|
'plants' => [
|
||||||
'slug' => 'plants',
|
'slug' => 'plants',
|
||||||
'name' => 'Plant Tracker',
|
'name' => 'Plant Tracker',
|
||||||
'icon' => '🪴',
|
|
||||||
'badge' => 'AI Vision',
|
'badge' => 'AI Vision',
|
||||||
'description' => 'Pflanzen-Tracking, Pflege & KI-Erkennung',
|
'description' => 'Pflanzen-Tracking, Pflege & KI-Erkennung',
|
||||||
'path' => '/plants',
|
'path' => '/plants',
|
||||||
|
|
@ -22,7 +20,6 @@ class ModuleService {
|
||||||
'storymachine' => [
|
'storymachine' => [
|
||||||
'slug' => 'storymachine',
|
'slug' => 'storymachine',
|
||||||
'name' => 'Story Machine',
|
'name' => 'Story Machine',
|
||||||
'icon' => '📖',
|
|
||||||
'badge' => 'Creative',
|
'badge' => 'Creative',
|
||||||
'description' => 'Interaktive Kinder-Geschichtenmaschine',
|
'description' => 'Interaktive Kinder-Geschichtenmaschine',
|
||||||
'path' => '/storymachine',
|
'path' => '/storymachine',
|
||||||
|
|
@ -31,25 +28,14 @@ class ModuleService {
|
||||||
'cooles-feature' => [
|
'cooles-feature' => [
|
||||||
'slug' => 'cooles-feature',
|
'slug' => 'cooles-feature',
|
||||||
'name' => 'Web Audio Synth',
|
'name' => 'Web Audio Synth',
|
||||||
'icon' => '🎛️',
|
|
||||||
'badge' => 'Audio Lab',
|
'badge' => 'Audio Lab',
|
||||||
'description' => 'Interaktive Web Audio API Synthese',
|
'description' => 'Interaktive Web Audio API Synthese',
|
||||||
'path' => '/cooles-feature',
|
'path' => '/cooles-feature',
|
||||||
'adminOnly' => false
|
'adminOnly' => false
|
||||||
],
|
],
|
||||||
'admin-tools' => [
|
|
||||||
'slug' => 'admin-tools',
|
|
||||||
'name' => 'Admin Tools',
|
|
||||||
'icon' => '🛠️',
|
|
||||||
'badge' => 'System',
|
|
||||||
'description' => 'Hash Generator, Diagnostik & Systemwerkzeuge',
|
|
||||||
'path' => '/admin-tools',
|
|
||||||
'adminOnly' => true
|
|
||||||
],
|
|
||||||
'test' => [
|
'test' => [
|
||||||
'slug' => 'test',
|
'slug' => 'test',
|
||||||
'name' => 'Test Environment',
|
'name' => 'Test Environment',
|
||||||
'icon' => '🧪',
|
|
||||||
'badge' => 'Sandbox',
|
'badge' => 'Sandbox',
|
||||||
'description' => 'Test- und Entwicklungsumgebung',
|
'description' => 'Test- und Entwicklungsumgebung',
|
||||||
'path' => '/test',
|
'path' => '/test',
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ switch ($action) {
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'is_admin' => 1,
|
'is_admin' => 1,
|
||||||
'status' => 'Active',
|
'status' => 'Active',
|
||||||
'projects' => ModuleService::getAll() ? array_keys(ModuleService::getAll()) : ['dinos','plants','storymachine','cooles-feature','admin-tools','test']
|
'projects' => ModuleService::getAll() ? array_keys(ModuleService::getAll()) : ['dinos','plants','storymachine','cooles-feature','test']
|
||||||
];
|
];
|
||||||
if (!empty($password)) {
|
if (!empty($password)) {
|
||||||
$data['password'] = $password;
|
$data['password'] = $password;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,55 +1,56 @@
|
||||||
<?php require_once __DIR__ . '/../inc/admin_header.php'; ?>
|
<?php require_once __DIR__ . '/../inc/admin_header.php'; ?>
|
||||||
<div class="max-w-6xl w-full mx-auto flex flex-col md:flex-row gap-6 p-6">
|
<?php
|
||||||
<aside class="w-full md:w-64 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-lg p-4 h-fit">
|
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
<div class="flex items-center gap-2 mb-6 border-b border-slate-700/50 pb-3">
|
?>
|
||||||
<span class="text-xl">⚙️</span>
|
<div class="max-w-7xl w-full mx-auto flex flex-col md:flex-row gap-6 p-4 sm:p-6">
|
||||||
<h2 class="text-emerald-400 font-mono font-bold text-lg tracking-tight">System_Admin</h2>
|
<!-- Sidebar Navigation -->
|
||||||
|
<aside class="w-full md:w-56 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-4 h-fit shrink-0">
|
||||||
|
<div class="mb-4 pb-3 border-b border-slate-800">
|
||||||
|
<h2 class="text-xs font-mono uppercase tracking-[0.2em] text-slate-400 font-bold">Navigation</h2>
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex flex-col gap-2 font-mono text-sm">
|
<nav class="flex flex-col gap-1.5 font-mono text-xs">
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin" class="px-3 py-2 bg-emerald-500/10 text-emerald-400 rounded-md border border-emerald-500/20 transition-all">> Dashboard</a>
|
<a href="<?= $baseUrl ?>/admin" class="px-3 py-2 bg-cyan-500/10 text-cyan-400 border border-cyan-500/30 rounded-xl transition-all">Dashboard</a>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin/users" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Benutzer</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Benutzer</a>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin/settings" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Einstellungen</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Einladungslinks</a>
|
||||||
|
<a href="<?= $baseUrl ?>/admin/settings" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Einstellungen</a>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
<main class="flex-1 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
|
||||||
<div class="bg-slate-800/80 px-4 py-3 border-b border-slate-700/50 flex items-center gap-2">
|
<main class="flex-1 min-w-0 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-3xl p-6 sm:p-8 shadow-2xl relative overflow-hidden flex flex-col">
|
||||||
<div class="w-3 h-3 rounded-full bg-rose-500"></div>
|
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-cyan-500/40 to-transparent"></div>
|
||||||
<div class="w-3 h-3 rounded-full bg-amber-500"></div>
|
|
||||||
<div class="w-3 h-3 rounded-full bg-emerald-500"></div>
|
<header class="mb-8 border-b border-slate-800 pb-6">
|
||||||
<div class="ml-2 font-mono text-xs text-slate-400">philcore-dashboard.sh</div>
|
<h1 class="text-xl sm:text-2xl font-black text-slate-100 font-mono tracking-tight">
|
||||||
<div class="ml-auto text-[10px] text-slate-500 font-mono italic">terminal_session_main</div>
|
<span class="text-cyan-400">/</span> System Dashboard
|
||||||
|
</h1>
|
||||||
|
<p class="text-slate-400 font-mono text-xs mt-1">Statusübersicht für <span class="text-cyan-400"><?= htmlspecialchars(Auth::user() ?? 'Admin') ?></span></p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<div class="p-5 bg-slate-950/80 rounded-2xl border border-slate-800">
|
||||||
|
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">Datenbank-Verbindung</h3>
|
||||||
|
<p class="text-emerald-400 font-mono text-sm flex items-center gap-2">
|
||||||
|
<span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
|
||||||
|
<?= htmlspecialchars($health['db_status'] ?? 'Online') ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-5 bg-slate-950/80 rounded-2xl border border-slate-800">
|
||||||
|
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">PHP Engine</h3>
|
||||||
|
<p class="text-cyan-400 font-mono text-sm">v<?= htmlspecialchars($health['php_version'] ?? 'N/A') ?> (<?= htmlspecialchars($health['memory'] ?? 'N/A') ?>)</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-5 bg-slate-950/80 rounded-2xl border border-slate-800">
|
||||||
|
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">Festplattenspeicher</h3>
|
||||||
|
<p class="text-slate-300 font-mono text-sm"><?= htmlspecialchars($health['disk_free'] ?? 'Verfügbar') ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="p-5 bg-slate-950/80 rounded-2xl border border-slate-800">
|
||||||
|
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">Schreibrechte</h3>
|
||||||
|
<p class="font-mono text-sm <?= ($health['writable'] ?? '') === 'OK' ? 'text-emerald-400' : 'text-rose-400' ?>"><?= htmlspecialchars($health['writable'] ?? 'OK') ?></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 sm:p-8 flex-1">
|
|
||||||
<header class="mb-8 border-b border-slate-800 pb-6">
|
<div class="mt-8 p-4 bg-slate-950/60 rounded-2xl border border-slate-800/80 font-mono text-xs text-slate-500 space-y-1">
|
||||||
<h1 class="text-3xl font-extrabold text-transparent bg-clip-text bg-linear-to-r from-emerald-400 to-cyan-400 tracking-tight mb-2">> Dashboard_</h1>
|
<p><span class="text-slate-600">[<?= date('H:i:s') ?>]</span> Umgebungs-Modus: <?= htmlspecialchars($health['env_status'] ?? 'Produktion') ?></p>
|
||||||
<p class="text-slate-400 font-mono text-sm">System-Status für <span class="text-emerald-400"><?= htmlspecialchars(Auth::user() ?? 'Phili') ?></span></p>
|
<p><span class="text-slate-600">[<?= date('H:i:s') ?>]</span> Alle Module und Schnittstellen betriebsbereit.</p>
|
||||||
</header>
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
||||||
<div class="p-5 bg-slate-950/80 rounded-lg border border-slate-800/80 shadow-inner">
|
|
||||||
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">> db_connection</h3>
|
|
||||||
<p class="text-emerald-400 font-mono text-sm flex items-center gap-2">
|
|
||||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>
|
|
||||||
<?= htmlspecialchars($health['db_status'] ?? 'Error') ?>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="p-5 bg-slate-950/80 rounded-lg border border-slate-800/80 shadow-inner">
|
|
||||||
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">> php_engine</h3>
|
|
||||||
<p class="text-cyan-400 font-mono text-sm">v<?= htmlspecialchars($health['php_version'] ?? 'N/A') ?> (<?= htmlspecialchars($health['memory'] ?? 'N/A') ?>)</p>
|
|
||||||
</div>
|
|
||||||
<div class="p-5 bg-slate-950/80 rounded-lg border border-slate-800/80 shadow-inner">
|
|
||||||
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">> disk_space</h3>
|
|
||||||
<p class="text-slate-300 font-mono text-sm"><?= htmlspecialchars($health['disk_free'] ?? 'Locked') ?></p>
|
|
||||||
</div>
|
|
||||||
<div class="p-5 bg-slate-950/80 rounded-lg border border-slate-800/80 shadow-inner">
|
|
||||||
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-2">> write_permissions</h3>
|
|
||||||
<p class="font-mono text-sm <?= ($health['writable'] ?? '') === 'OK' ? 'text-emerald-400' : 'text-rose-500' ?>"><?= htmlspecialchars($health['writable'] ?? 'Failed') ?></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-8 p-4 bg-black/40 rounded border border-slate-800 font-mono text-[10px] text-slate-500 leading-relaxed">
|
|
||||||
<p>> [<?= date('H:i:s') ?>] SYS_LOAD: OPTIMAL</p>
|
|
||||||
<p>> [<?= date('H:i:s') ?>] ENV_STATUS: <?= htmlspecialchars($health['env_status'] ?? 'Unknown') ?></p>
|
|
||||||
<p>> [<?= date('H:i:s') ?>] Alle Systeme bereit.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,48 @@
|
||||||
<?php require_once __DIR__ . '/../inc/admin_header.php'; ?>
|
<?php require_once __DIR__ . '/../inc/admin_header.php'; ?>
|
||||||
<div class="max-w-6xl w-full mx-auto flex flex-col md:flex-row gap-6 p-6">
|
<?php
|
||||||
<aside class="w-full md:w-64 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-lg p-4 h-fit">
|
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
<div class="flex items-center gap-2 mb-6 border-b border-slate-700/50 pb-3">
|
?>
|
||||||
<span class="text-xl">⚙️</span>
|
<div class="max-w-7xl w-full mx-auto flex flex-col md:flex-row gap-6 p-4 sm:p-6">
|
||||||
<h2 class="text-emerald-400 font-mono font-bold text-lg tracking-tight">System_Admin</h2>
|
<!-- Sidebar Navigation -->
|
||||||
|
<aside class="w-full md:w-56 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-4 h-fit shrink-0">
|
||||||
|
<div class="mb-4 pb-3 border-b border-slate-800">
|
||||||
|
<h2 class="text-xs font-mono uppercase tracking-[0.2em] text-slate-400 font-bold">Navigation</h2>
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex flex-col gap-2 font-mono text-sm">
|
<nav class="flex flex-col gap-1.5 font-mono text-xs">
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Dashboard</a>
|
<a href="<?= $baseUrl ?>/admin" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Dashboard</a>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin/users" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Benutzer</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Benutzer</a>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin/settings" class="px-3 py-2 bg-emerald-500/10 text-emerald-400 rounded-md border border-emerald-500/20 transition-all">> Einstellungen</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Einladungslinks</a>
|
||||||
|
<a href="<?= $baseUrl ?>/admin/settings" class="px-3 py-2 bg-cyan-500/10 text-cyan-400 border border-cyan-500/30 rounded-xl transition-all">Einstellungen</a>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
<main class="flex-1 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
|
||||||
<div class="bg-slate-800/80 px-4 py-3 border-b border-slate-700/50 flex items-center gap-2">
|
<main class="flex-1 min-w-0 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-3xl p-6 sm:p-8 shadow-2xl relative overflow-hidden flex flex-col">
|
||||||
<div class="w-3 h-3 rounded-full bg-rose-500"></div>
|
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-cyan-500/40 to-transparent"></div>
|
||||||
<div class="w-3 h-3 rounded-full bg-amber-500"></div>
|
|
||||||
<div class="w-3 h-3 rounded-full bg-emerald-500"></div>
|
<header class="mb-8 border-b border-slate-800 pb-6">
|
||||||
<div class="ml-2 font-mono text-xs text-slate-400">philcore-settings.sh</div>
|
<h1 class="text-xl sm:text-2xl font-black text-slate-100 font-mono tracking-tight">
|
||||||
</div>
|
<span class="text-cyan-400">/</span> System-Einstellungen
|
||||||
<div class="p-6 sm:p-8 flex-1">
|
</h1>
|
||||||
<header class="mb-8 border-b border-slate-800 pb-6">
|
<p class="text-slate-400 font-mono text-xs mt-1">Konfiguration und Umgebungsvariablen.</p>
|
||||||
<h1 class="text-3xl font-extrabold text-transparent bg-clip-text bg-linear-to-r from-emerald-400 to-cyan-400 tracking-tight mb-2">> <?= htmlspecialchars($title) ?>_</h1>
|
</header>
|
||||||
<p class="text-slate-400 font-mono text-sm">Systemkonfiguration anpassen.</p>
|
|
||||||
</header>
|
<div class="space-y-6">
|
||||||
<div class="space-y-6">
|
<div class="p-6 bg-slate-950/80 rounded-2xl border border-slate-800 space-y-4">
|
||||||
<div class="p-5 bg-slate-950/80 rounded-lg border border-slate-800/80 shadow-inner">
|
<h3 class="text-slate-400 font-mono text-xs uppercase tracking-wider font-bold">Umgebungsvariablen (.env)</h3>
|
||||||
<h3 class="text-slate-500 font-mono text-xs uppercase tracking-wider mb-4">> env_variables</h3>
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-slate-400 font-mono text-sm mb-1">APP_NAME</label>
|
<label class="block text-slate-400 font-mono text-xs mb-1.5 uppercase tracking-wider">APP_NAME</label>
|
||||||
<input type="text" value="<?= htmlspecialchars(Config::get('APP_NAME', 'PhilCore')) ?>" class="w-full bg-slate-900 border border-slate-700 rounded p-2 text-emerald-400 font-mono text-sm focus:outline-none" readonly>
|
<input type="text" value="<?= htmlspecialchars(Config::get('APP_NAME', 'philippurbschat.de')) ?>" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-cyan-400 font-mono text-xs focus:outline-none" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-slate-400 font-mono text-sm mb-1">GEMINI_API_KEY</label>
|
<label class="block text-slate-400 font-mono text-xs mb-1.5 uppercase tracking-wider">BASE_URL</label>
|
||||||
<input type="text" value="<?= substr(Config::get('GEMINI_API_KEY', ''), 0, 5) ?>*******************" class="w-full bg-slate-900 border border-slate-700 rounded p-2 text-emerald-400 font-mono text-sm focus:outline-none" readonly>
|
<input type="text" value="<?= htmlspecialchars(Config::get('BASE_URL', 'https://philippurbschat.de/')) ?>" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-300 font-mono text-xs focus:outline-none" readonly>
|
||||||
<p class="text-xs text-slate-500 mt-2 font-mono tracking-tighter">// Hinweis: Änderungen direkt in der .env vornehmen.</p>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
|
<label class="block text-slate-400 font-mono text-xs mb-1.5 uppercase tracking-wider">GEMINI_API_KEY</label>
|
||||||
|
<input type="text" value="<?= substr(Config::get('GEMINI_API_KEY', ''), 0, 6) ?>*******************" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-cyan-400 font-mono text-xs focus:outline-none" readonly>
|
||||||
|
<p class="text-[11px] text-slate-500 mt-2 font-mono">// Änderungen direkt in der .env-Datei auf dem Server vornehmen.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -85,9 +85,8 @@ $modules = $allModules ?? ModuleService::getAll();
|
||||||
<input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" <?= $isChecked ? 'checked' : '' ?> class="module-checkbox mt-1 w-4 h-4 accent-emerald-500">
|
<input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" <?= $isChecked ? 'checked' : '' ?> class="module-checkbox mt-1 w-4 h-4 accent-emerald-500">
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<div class="flex items-center justify-between gap-1 mb-1">
|
<div class="flex items-center justify-between gap-1 mb-1">
|
||||||
<span class="text-sm font-bold text-slate-200 font-mono flex items-center gap-1.5 truncate">
|
<span class="text-sm font-bold text-slate-200 font-mono tracking-wider uppercase">
|
||||||
<span><?= $mod['icon'] ?></span>
|
<?= htmlspecialchars($mod['name']) ?>
|
||||||
<span><?= htmlspecialchars($mod['name']) ?></span>
|
|
||||||
</span>
|
</span>
|
||||||
<span class="text-[10px] font-mono px-1.5 py-0.5 rounded bg-slate-900 border border-slate-800 text-slate-400 shrink-0">
|
<span class="text-[10px] font-mono px-1.5 py-0.5 rounded bg-slate-900 border border-slate-800 text-slate-400 shrink-0">
|
||||||
<?= htmlspecialchars($mod['badge'] ?? $slug) ?>
|
<?= htmlspecialchars($mod['badge'] ?? $slug) ?>
|
||||||
|
|
@ -102,11 +101,11 @@ $modules = $allModules ?? ModuleService::getAll();
|
||||||
|
|
||||||
<!-- Submit Buttons -->
|
<!-- Submit Buttons -->
|
||||||
<div class="pt-4 border-t border-slate-800 flex items-center justify-between">
|
<div class="pt-4 border-t border-slate-800 flex items-center justify-between">
|
||||||
<a href="<?= $baseUrl ?>/admin/users" class="text-slate-500 hover:text-slate-300 font-mono text-xs uppercase">
|
<a href="<?= $baseUrl ?>/admin/users" class="text-slate-500 hover:text-slate-300 font-mono text-xs uppercase tracking-wider">
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</a>
|
</a>
|
||||||
<button type="submit" class="bg-emerald-500/20 border border-emerald-500/50 text-emerald-400 hover:bg-emerald-500/30 hover:text-emerald-300 font-bold font-mono uppercase tracking-wider py-3 px-6 rounded-xl transition-all duration-300 shadow-[0_0_15px_rgba(16,185,129,0.15)] cursor-pointer">
|
<button type="submit" class="bg-cyan-500/10 border border-cyan-500/30 text-cyan-400 hover:bg-cyan-500/20 hover:text-cyan-300 font-bold font-mono uppercase tracking-wider py-3 px-6 rounded-xl transition-all duration-300 shadow-[0_0_15px_rgba(6,182,212,0.15)] cursor-pointer">
|
||||||
💾 Benutzer speichern
|
Benutzer speichern →
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -3,249 +3,229 @@
|
||||||
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
$currentTab = $activeTab ?? ($_GET['tab'] ?? 'users');
|
$currentTab = $activeTab ?? ($_GET['tab'] ?? 'users');
|
||||||
?>
|
?>
|
||||||
<div class="max-w-7xl w-full mx-auto flex flex-col md:flex-row gap-4 sm:gap-6 p-2 sm:p-4">
|
<div class="max-w-7xl w-full mx-auto flex flex-col md:flex-row gap-6 p-4 sm:p-6">
|
||||||
<!-- Sidebar Navigation -->
|
<!-- Sidebar Navigation -->
|
||||||
<aside class="w-full md:w-64 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-lg p-4 h-fit shrink-0">
|
<aside class="w-full md:w-56 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-4 h-fit shrink-0">
|
||||||
<div class="flex items-center gap-2 mb-6 border-b border-slate-700/50 pb-3">
|
<div class="mb-4 pb-3 border-b border-slate-800">
|
||||||
<span class="text-xl">⚙️</span>
|
<h2 class="text-xs font-mono uppercase tracking-[0.2em] text-slate-400 font-bold">Navigation</h2>
|
||||||
<h2 class="text-emerald-400 font-mono font-bold text-lg tracking-tight">System_Admin</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex flex-col gap-2 font-mono text-sm">
|
<nav class="flex flex-col gap-1.5 font-mono text-xs">
|
||||||
<a href="<?= $baseUrl ?>/admin" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Dashboard</a>
|
<a href="<?= $baseUrl ?>/admin" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Dashboard</a>
|
||||||
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="px-3 py-2 <?= $currentTab === 'users' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'hover:bg-slate-800 text-slate-400 hover:text-slate-200' ?> rounded-md transition-all">> Benutzer (<?= count($users ?? []) ?>)</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="px-3 py-2 <?= $currentTab === 'users' ? 'bg-cyan-500/10 text-cyan-400 border border-cyan-500/30' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?> rounded-xl transition-all">Benutzer (<?= count($users ?? []) ?>)</a>
|
||||||
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="px-3 py-2 <?= $currentTab === 'invites' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'hover:bg-slate-800 text-slate-400 hover:text-slate-200' ?> rounded-md transition-all">> Einladungslinks (<?= count($invitations ?? []) ?>)</a>
|
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="px-3 py-2 <?= $currentTab === 'invites' ? 'bg-cyan-500/10 text-cyan-400 border border-cyan-500/30' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?> rounded-xl transition-all">Einladungslinks (<?= count($invitations ?? []) ?>)</a>
|
||||||
<a href="<?= $baseUrl ?>/admin-tools" class="px-3 py-2 hover:bg-slate-800 text-cyan-400 hover:text-cyan-300 rounded-md transition-all">> Admin-Tools</a>
|
<a href="<?= $baseUrl ?>/admin/settings" class="px-3 py-2 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 rounded-xl transition-all">Einstellungen</a>
|
||||||
<a href="<?= $baseUrl ?>/admin/settings" class="px-3 py-2 hover:bg-slate-800 text-slate-400 hover:text-slate-200 rounded-md transition-all">> Einstellungen</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Main Content Area -->
|
<!-- Main Content Area -->
|
||||||
<main class="flex-1 min-w-0 bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
<main class="flex-1 min-w-0 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-3xl p-6 sm:p-8 shadow-2xl relative overflow-hidden flex flex-col">
|
||||||
<!-- Top Toolbar -->
|
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-cyan-500/40 to-transparent"></div>
|
||||||
<div class="bg-slate-800/80 px-4 py-3 border-b border-slate-700/50 flex flex-wrap items-center justify-between gap-3">
|
|
||||||
<div class="flex items-center gap-2">
|
<!-- Top Header & Tabs -->
|
||||||
<div class="w-3 h-3 rounded-full bg-rose-500 hidden sm:block"></div>
|
<div class="flex flex-wrap items-center justify-between gap-4 mb-8 pb-6 border-b border-slate-800">
|
||||||
<div class="w-3 h-3 rounded-full bg-amber-500 hidden sm:block"></div>
|
<div>
|
||||||
<div class="w-3 h-3 rounded-full bg-emerald-500 hidden sm:block"></div>
|
<h1 class="text-xl sm:text-2xl font-black text-slate-100 font-mono tracking-tight">
|
||||||
<div class="sm:ml-2 font-mono text-xs text-slate-400">auth-matrix.sh</div>
|
<span class="text-cyan-400">/</span> <?= $currentTab === 'invites' ? 'Einladungslinks' : 'Benutzerverwaltung' ?>
|
||||||
|
</h1>
|
||||||
|
<p class="text-slate-400 text-xs font-mono mt-1">
|
||||||
|
<?= $currentTab === 'invites' ? 'Geheime Registrierungs-Links mit vorkonfigurierten Modul-Rechten.' : 'Verwalte Benutzerkonten und individuelle Modul-Zugriffe.' ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="text-xs font-mono px-3 py-1.5 rounded-lg border transition-all <?= $currentTab === 'users' ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/50' : 'bg-slate-900/50 text-slate-400 border-slate-700 hover:text-slate-200' ?>">
|
<a href="<?= $baseUrl ?>/admin/users?tab=users" class="text-xs font-mono px-3.5 py-2 rounded-xl border transition-all <?= $currentTab === 'users' ? 'bg-cyan-500/10 text-cyan-400 border-cyan-500/40' : 'bg-slate-950/60 text-slate-400 border-slate-800 hover:text-slate-200' ?>">
|
||||||
👥 Benutzer
|
Benutzer
|
||||||
</a>
|
</a>
|
||||||
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="text-xs font-mono px-3 py-1.5 rounded-lg border transition-all <?= $currentTab === 'invites' ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/50' : 'bg-slate-900/50 text-slate-400 border-slate-700 hover:text-slate-200' ?>">
|
<a href="<?= $baseUrl ?>/admin/users?tab=invites" class="text-xs font-mono px-3.5 py-2 rounded-xl border transition-all <?= $currentTab === 'invites' ? 'bg-cyan-500/10 text-cyan-400 border-cyan-500/40' : 'bg-slate-950/60 text-slate-400 border-slate-800 hover:text-slate-200' ?>">
|
||||||
✉️ Einladungslinks
|
Einladungslinks
|
||||||
</a>
|
</a>
|
||||||
<a href="<?= $baseUrl ?>/admin/user_form" class="text-xs font-mono bg-emerald-500/20 text-emerald-400 border border-emerald-500/50 px-3 py-1.5 rounded-lg hover:bg-emerald-500/40 transition-colors whitespace-nowrap">
|
<a href="<?= $baseUrl ?>/admin/user_form" class="text-xs font-mono bg-cyan-500/10 text-cyan-400 border border-cyan-500/30 px-3.5 py-2 rounded-xl hover:bg-cyan-500/20 transition-all font-bold whitespace-nowrap">
|
||||||
+ NEW_USER
|
+ Neuer Benutzer
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4 sm:p-6 flex-1">
|
<?php if ($currentTab === 'invites'): ?>
|
||||||
<?php if ($currentTab === 'invites'): ?>
|
<!-- ================= TAB: EINLADUNGSLINKS ================= -->
|
||||||
<!-- ================= TAB: EINLADUNGSLINKS ================= -->
|
<!-- Link Generator -->
|
||||||
<header class="mb-6 border-b border-slate-800 pb-4">
|
<div class="bg-slate-950/80 border border-slate-800 rounded-2xl p-5 sm:p-6 mb-8 relative group">
|
||||||
<h1 class="text-xl sm:text-2xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 to-cyan-400 font-mono tracking-tight mb-1">
|
<h2 class="text-xs font-mono uppercase tracking-wider text-cyan-400 font-bold mb-4">
|
||||||
> Einladungs-System_
|
Neuen Einladungslink generieren
|
||||||
</h1>
|
</h2>
|
||||||
<p class="text-slate-400 font-mono text-xs sm:text-sm">
|
<form action="<?= $baseUrl ?>/admin/invite_create" method="POST" class="space-y-4">
|
||||||
Erstelle geheime Registrierungs-Links mit vorkonfigurierten Modul-Zugriffsrechten. Nicht öffentlich & vor Suchmaschinen geschützt.
|
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Generator Card -->
|
|
||||||
<div class="bg-slate-950/70 border border-emerald-500/30 rounded-xl p-5 mb-8">
|
|
||||||
<h2 class="text-sm font-bold font-mono text-emerald-400 uppercase tracking-wider mb-4 flex items-center gap-2">
|
|
||||||
<span>⚡</span> Neuen Einladungslink generieren
|
|
||||||
</h2>
|
|
||||||
<form action="<?= $baseUrl ?>/admin/invite_create" method="POST" class="space-y-4">
|
|
||||||
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-slate-400 font-mono text-xs uppercase mb-1.5">Notiz / Empfänger</label>
|
|
||||||
<input type="text" name="note" placeholder="z.B. Für Peter Müller" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 text-xs font-mono focus:outline-none focus:border-emerald-500">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-slate-400 font-mono text-xs uppercase mb-1.5">Max. Nutzungen</label>
|
|
||||||
<input type="number" name="max_uses" value="1" min="1" max="100" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 text-xs font-mono focus:outline-none focus:border-emerald-500">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-slate-400 font-mono text-xs uppercase mb-1.5">Gültigkeit in Tagen (optional)</label>
|
|
||||||
<input type="number" name="days_valid" placeholder="z.B. 7 (leer = unbegrenzt)" min="1" max="365" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 text-xs font-mono focus:outline-none focus:border-emerald-500">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-slate-400 font-mono text-xs uppercase mb-2">Automatisch freigeschaltete Module:</label>
|
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-1.5">Notiz / Empfänger</label>
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-6 gap-2">
|
<input type="text" name="note" placeholder="z.B. Für Alex" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-200 text-xs font-mono focus:outline-none focus:border-cyan-500 transition-colors">
|
||||||
<?php foreach ($allModules as $slug => $mod): ?>
|
|
||||||
<label class="flex items-center gap-2 p-2 bg-slate-900 border border-slate-800 hover:border-emerald-500/40 rounded-lg cursor-pointer transition-colors text-xs font-mono">
|
|
||||||
<input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" class="accent-emerald-500">
|
|
||||||
<span><?= $mod['icon'] ?></span>
|
|
||||||
<span class="text-slate-300 truncate"><?= htmlspecialchars($mod['name']) ?></span>
|
|
||||||
</label>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div class="pt-2">
|
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-1.5">Max. Nutzungen</label>
|
||||||
<button type="submit" class="bg-emerald-500/20 border border-emerald-500/50 hover:bg-emerald-500/30 text-emerald-400 font-mono text-xs uppercase tracking-wider py-2.5 px-5 rounded-lg transition-all font-bold">
|
<input type="number" name="max_uses" value="1" min="1" max="100" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-200 text-xs font-mono focus:outline-none focus:border-cyan-500 transition-colors">
|
||||||
Link generieren & Speichern →
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<div>
|
||||||
</div>
|
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-1.5">Gültigkeit in Tagen (optional)</label>
|
||||||
|
<input type="number" name="days_valid" placeholder="z.B. 7 (leer = unbegrenzt)" min="1" max="365" class="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-200 text-xs font-mono focus:outline-none focus:border-cyan-500 transition-colors">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Invites Table -->
|
<div>
|
||||||
<h3 class="text-xs font-mono uppercase text-slate-400 tracking-wider mb-3">Bestehende Einladungslinks</h3>
|
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-2">Automatisch freizuschaltende Module</label>
|
||||||
<div class="overflow-x-auto border border-slate-800/80 rounded-lg">
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-2.5">
|
||||||
<table class="w-full text-left font-mono text-xs text-slate-400">
|
<?php foreach ($allModules as $slug => $mod): ?>
|
||||||
<thead class="bg-slate-950/80 text-emerald-400 uppercase text-[10px]">
|
<label class="flex items-center gap-2.5 p-3 bg-slate-900/80 border border-slate-800 hover:border-cyan-500/40 rounded-xl cursor-pointer transition-colors text-xs font-mono">
|
||||||
<tr>
|
<input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" class="accent-cyan-500">
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Token & Link</th>
|
<span class="text-slate-300 uppercase tracking-wider text-[11px] font-bold"><?= htmlspecialchars($mod['name']) ?></span>
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Notiz</th>
|
</label>
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Vordefinierte Module</th>
|
<?php endforeach; ?>
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Nutzungen</th>
|
</div>
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Gültig bis</th>
|
</div>
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800">Status</th>
|
|
||||||
<th class="px-3 py-2.5 border-b border-slate-800 text-right">Aktion</th>
|
<div class="pt-2">
|
||||||
|
<button type="submit" class="bg-cyan-500/10 border border-cyan-500/30 hover:bg-cyan-500/20 text-cyan-400 font-mono text-xs uppercase tracking-wider py-3 px-5 rounded-xl transition-all font-bold cursor-pointer">
|
||||||
|
Link generieren →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Existing Invites Table -->
|
||||||
|
<div class="overflow-x-auto border border-slate-800 rounded-2xl">
|
||||||
|
<table class="w-full text-left font-mono text-xs text-slate-400">
|
||||||
|
<thead class="bg-slate-950 text-cyan-400 uppercase text-[10px] tracking-wider">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Token & Link</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Notiz</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Module</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Nutzungen</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Gültig bis</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800">Status</th>
|
||||||
|
<th class="px-4 py-3 border-b border-slate-800 text-right">Aktion</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-slate-800/60 bg-slate-900/30">
|
||||||
|
<?php if (empty($invitations)): ?>
|
||||||
|
<tr><td colspan="7" class="px-4 py-6 text-center text-slate-500">Noch keine Einladungslinks erstellt.</td></tr>
|
||||||
|
<?php else: foreach ($invitations as $inv):
|
||||||
|
$fullUrl = $baseUrl . '/register?token=' . $inv['token'];
|
||||||
|
?>
|
||||||
|
<tr class="hover:bg-slate-800/30 transition-colors">
|
||||||
|
<td class="px-4 py-3.5">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-slate-300 font-mono text-[11px] select-all"><?= substr($inv['token'], 0, 10) ?>...</span>
|
||||||
|
<button type="button" onclick="copyInviteLink('<?= $fullUrl ?>', this)" class="px-2.5 py-1 bg-cyan-500/10 hover:bg-cyan-500/20 text-cyan-400 border border-cyan-500/30 rounded-lg text-[10px] transition-colors cursor-pointer tracking-wider uppercase">
|
||||||
|
Kopieren
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3.5 text-slate-200"><?= htmlspecialchars($inv['note'] ?: '-') ?></td>
|
||||||
|
<td class="px-4 py-3.5">
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<?php if (empty($inv['assigned_projects'])): ?>
|
||||||
|
<span class="text-slate-600">-</span>
|
||||||
|
<?php else: foreach ($inv['assigned_projects'] as $slug):
|
||||||
|
$mod = $allModules[$slug] ?? null;
|
||||||
|
?>
|
||||||
|
<span class="px-2 py-0.5 bg-slate-950 border border-slate-800 rounded-md text-[10px] text-slate-300 uppercase">
|
||||||
|
<?= htmlspecialchars($mod['name'] ?? $slug) ?>
|
||||||
|
</span>
|
||||||
|
<?php endforeach; endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3.5 text-slate-300"><?= $inv['uses_count'] ?> / <?= $inv['max_uses'] > 0 ? $inv['max_uses'] : '∞' ?></td>
|
||||||
|
<td class="px-4 py-3.5 text-slate-400"><?= $inv['expires_at'] ? date('d.m.Y H:i', strtotime($inv['expires_at'])) : 'Unbegrenzt' ?></td>
|
||||||
|
<td class="px-4 py-3.5">
|
||||||
|
<?php if ($inv['is_valid']): ?>
|
||||||
|
<span class="px-2 py-0.5 bg-emerald-500/10 text-emerald-400 border border-emerald-500/30 rounded-md text-[10px] uppercase">Aktiv</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="px-2 py-0.5 bg-rose-500/10 text-rose-400 border border-rose-500/30 rounded-md text-[10px] uppercase">Inaktiv</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3.5 text-right">
|
||||||
|
<form action="<?= $baseUrl ?>/admin/invite_delete/<?= $inv['id'] ?>" method="POST" class="inline" onsubmit="return confirm('Diesen Einladungslink wirklich löschen?');">
|
||||||
|
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
||||||
|
<button type="submit" class="text-rose-400 hover:text-rose-300 text-xs cursor-pointer">Löschen</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
<?php endforeach; endif; ?>
|
||||||
<tbody class="divide-y divide-slate-800/50 bg-slate-900/50">
|
</tbody>
|
||||||
<?php if (empty($invitations)): ?>
|
</table>
|
||||||
<tr><td colspan="7" class="px-4 py-4 text-center text-slate-500">Noch keine Einladungslinks erstellt.</td></tr>
|
</div>
|
||||||
<?php else: foreach ($invitations as $inv):
|
|
||||||
$fullUrl = $baseUrl . '/register?token=' . $inv['token'];
|
<?php else: ?>
|
||||||
?>
|
<!-- ================= TAB: BENUTZERVERWALTUNG ================= -->
|
||||||
<tr class="hover:bg-slate-800/40 transition-colors">
|
<div class="overflow-x-auto border border-slate-800 rounded-2xl">
|
||||||
<td class="px-3 py-3">
|
<table class="w-full text-left font-mono text-xs text-slate-400">
|
||||||
<div class="flex items-center gap-2">
|
<thead class="bg-slate-950 text-cyan-400 uppercase text-[10px] tracking-wider">
|
||||||
<span class="text-slate-300 font-mono text-[11px] select-all"><?= substr($inv['token'], 0, 10) ?>...</span>
|
<tr>
|
||||||
<button type="button" onclick="copyInviteLink('<?= $fullUrl ?>', this)" class="px-2 py-0.5 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 rounded text-[10px] transition-colors cursor-pointer" title="Kopieren">
|
<th class="px-4 py-3.5 border-b border-slate-800">ID</th>
|
||||||
📋 Kopieren
|
<th class="px-4 py-3.5 border-b border-slate-800">Name</th>
|
||||||
</button>
|
<th class="px-4 py-3.5 border-b border-slate-800">Email</th>
|
||||||
</div>
|
<th class="px-4 py-3.5 border-b border-slate-800">Rolle</th>
|
||||||
</td>
|
<th class="px-4 py-3.5 border-b border-slate-800">Freigeschaltete Module</th>
|
||||||
<td class="px-3 py-3 text-slate-300"><?= htmlspecialchars($inv['note'] ?: '-') ?></td>
|
<th class="px-4 py-3.5 border-b border-slate-800">Status</th>
|
||||||
<td class="px-3 py-3">
|
<th class="px-4 py-3.5 border-b border-slate-800 text-right">Aktionen</th>
|
||||||
<div class="flex flex-wrap gap-1">
|
</tr>
|
||||||
<?php if (empty($inv['assigned_projects'])): ?>
|
</thead>
|
||||||
<span class="text-slate-500">-</span>
|
<tbody class="divide-y divide-slate-800/60 bg-slate-900/30">
|
||||||
<?php else: foreach ($inv['assigned_projects'] as $slug):
|
<?php if (empty($users)): ?>
|
||||||
$mod = $allModules[$slug] ?? null;
|
<tr><td colspan="7" class="px-4 py-6 text-center text-slate-500">Keine Benutzer vorhanden.</td></tr>
|
||||||
?>
|
<?php else: foreach ($users as $u): ?>
|
||||||
<span class="inline-flex items-center gap-1 px-1.5 py-0.5 bg-slate-950 border border-slate-800 rounded text-[10px] text-slate-300">
|
<tr class="hover:bg-slate-800/30 transition-colors">
|
||||||
<?= $mod['icon'] ?? '📦' ?> <?= htmlspecialchars($mod['name'] ?? $slug) ?>
|
<td class="px-4 py-3.5 text-slate-500">#<?= $u['id'] ?></td>
|
||||||
</span>
|
<td class="px-4 py-3.5 text-slate-200 font-bold"><?= htmlspecialchars($u['name']) ?></td>
|
||||||
<?php endforeach; endif; ?>
|
<td class="px-4 py-3.5 text-slate-400 break-all"><?= htmlspecialchars($u['email']) ?></td>
|
||||||
</div>
|
<td class="px-4 py-3.5">
|
||||||
</td>
|
<?php if (!empty($u['is_admin'])): ?>
|
||||||
<td class="px-3 py-3 text-slate-300 font-mono"><?= $inv['uses_count'] ?> / <?= $inv['max_uses'] > 0 ? $inv['max_uses'] : '∞' ?></td>
|
<span class="px-2 py-0.5 bg-fuchsia-500/10 text-fuchsia-400 border border-fuchsia-500/30 rounded-md text-[10px] font-bold uppercase tracking-wider">Admin</span>
|
||||||
<td class="px-3 py-3 text-slate-400"><?= $inv['expires_at'] ? date('d.m.Y H:i', strtotime($inv['expires_at'])) : 'Unbegrenzt' ?></td>
|
<?php else: ?>
|
||||||
<td class="px-3 py-3">
|
<span class="text-slate-500 uppercase tracking-wider text-[10px]">User</span>
|
||||||
<?php if ($inv['is_valid']): ?>
|
<?php endif; ?>
|
||||||
<span class="px-2 py-0.5 bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 rounded text-[10px]">Aktiv</span>
|
</td>
|
||||||
<?php else: ?>
|
<td class="px-4 py-3.5">
|
||||||
<span class="px-2 py-0.5 bg-rose-500/10 text-rose-400 border border-rose-500/20 rounded text-[10px]">Inaktiv</span>
|
<div class="flex flex-wrap gap-1 max-w-xs">
|
||||||
<?php endif; ?>
|
<?php
|
||||||
</td>
|
$proj = $u['projects'] ?? [];
|
||||||
<td class="px-3 py-3 text-right">
|
if (!empty($u['is_admin'])): ?>
|
||||||
<form action="<?= $baseUrl ?>/admin/invite_delete/<?= $inv['id'] ?>" method="POST" class="inline" onsubmit="return confirm('Diesen Einladungslink wirklich löschen?');">
|
<span class="px-2 py-0.5 bg-fuchsia-950/60 border border-fuchsia-800/40 rounded-md text-[10px] text-fuchsia-300 uppercase tracking-wider">
|
||||||
|
Alle Module (Vollzugriff)
|
||||||
|
</span>
|
||||||
|
<?php elseif (empty($proj)): ?>
|
||||||
|
<span class="text-slate-600 italic text-[10px]">Keine</span>
|
||||||
|
<?php else: foreach ($proj as $slug):
|
||||||
|
$mod = $allModules[$slug] ?? null;
|
||||||
|
?>
|
||||||
|
<span class="px-2 py-0.5 bg-slate-950 border border-slate-800 rounded-md text-[10px] text-slate-300 uppercase">
|
||||||
|
<?= htmlspecialchars($mod['name'] ?? $slug) ?>
|
||||||
|
</span>
|
||||||
|
<?php endforeach; endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3.5">
|
||||||
|
<form action="<?= $baseUrl ?>/admin/user_toggle_status/<?= $u['id'] ?>" method="POST" class="inline">
|
||||||
|
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
||||||
|
<button type="submit" class="px-2.5 py-1 rounded-lg text-[10px] font-mono border transition-all cursor-pointer uppercase tracking-wider <?= $u['status'] === 'Active' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30 hover:bg-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border-rose-500/30 hover:bg-rose-500/20' ?>" title="Klicken zum Umschalten">
|
||||||
|
<?= $u['status'] === 'Active' ? 'Aktiv' : 'Inaktiv' ?>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3.5 text-right whitespace-nowrap">
|
||||||
|
<div class="flex justify-end items-center gap-3">
|
||||||
|
<a href="<?= $baseUrl ?>/admin/user_form/<?= $u['id'] ?>" class="text-cyan-400 hover:text-cyan-300">Bearbeiten</a>
|
||||||
|
<form action="<?= $baseUrl ?>/admin/user_delete/<?= $u['id'] ?>" method="POST" class="inline" onsubmit="return confirm('Benutzer <?= htmlspecialchars(addslashes($u['name'])) ?> wirklich löschen?');">
|
||||||
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
||||||
<button type="submit" class="text-rose-400 hover:text-rose-300 text-xs">Löschen</button>
|
<button type="submit" class="text-rose-400 hover:text-rose-300">Löschen</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</td>
|
||||||
<?php endforeach; endif; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
<!-- ================= TAB: BENUTZERVERWALTUNG ================= -->
|
|
||||||
<header class="mb-6 border-b border-slate-800 pb-4">
|
|
||||||
<h1 class="text-xl sm:text-2xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 to-cyan-400 font-mono tracking-tight mb-1">
|
|
||||||
> Benutzerverwaltung_
|
|
||||||
</h1>
|
|
||||||
<p class="text-slate-400 font-mono text-xs sm:text-sm">
|
|
||||||
Registrierte Benutzer und individuelle Modulfreigaben.
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="overflow-x-auto border border-slate-800/80 rounded-lg">
|
|
||||||
<table class="w-full text-left font-mono text-xs text-slate-400">
|
|
||||||
<thead class="bg-slate-950/80 text-emerald-400 text-[10px] sm:text-xs uppercase">
|
|
||||||
<tr>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">ID</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">Name</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">Email</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">Rolle</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">Freigeschaltete Module</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800">Status</th>
|
|
||||||
<th class="px-3 sm:px-4 py-3 border-b border-slate-800 text-right">Aktionen</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
<?php endforeach; endif; ?>
|
||||||
<tbody class="divide-y divide-slate-800/50 bg-slate-900/50">
|
</tbody>
|
||||||
<?php if (empty($users)): ?>
|
</table>
|
||||||
<tr><td colspan="7" class="px-4 py-4 text-center text-slate-500">Keine Benutzer vorhanden.</td></tr>
|
</div>
|
||||||
<?php else: foreach ($users as $u): ?>
|
<?php endif; ?>
|
||||||
<tr class="hover:bg-slate-800/40 transition-colors">
|
|
||||||
<td class="px-3 sm:px-4 py-3">#<?= $u['id'] ?></td>
|
|
||||||
<td class="px-3 sm:px-4 py-3 text-slate-200 font-bold"><?= htmlspecialchars($u['name']) ?></td>
|
|
||||||
<td class="px-3 sm:px-4 py-3 text-slate-400 break-all"><?= htmlspecialchars($u['email']) ?></td>
|
|
||||||
<td class="px-3 sm:px-4 py-3">
|
|
||||||
<?php if (!empty($u['is_admin'])): ?>
|
|
||||||
<span class="px-2 py-0.5 bg-fuchsia-500/10 text-fuchsia-400 border border-fuchsia-500/30 rounded text-[10px] font-bold">Admin</span>
|
|
||||||
<?php else: ?>
|
|
||||||
<span class="text-slate-500">User</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td class="px-3 sm:px-4 py-3">
|
|
||||||
<div class="flex flex-wrap gap-1 max-w-xs">
|
|
||||||
<?php
|
|
||||||
$proj = $u['projects'] ?? [];
|
|
||||||
if (!empty($u['is_admin'])): ?>
|
|
||||||
<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-fuchsia-950/60 border border-fuchsia-700/40 rounded text-[10px] text-fuchsia-300">
|
|
||||||
★ Alle Module (Vollzugriff)
|
|
||||||
</span>
|
|
||||||
<?php elseif (empty($proj)): ?>
|
|
||||||
<span class="text-slate-600 italic">Keine Module</span>
|
|
||||||
<?php else: foreach ($proj as $slug):
|
|
||||||
$mod = $allModules[$slug] ?? null;
|
|
||||||
?>
|
|
||||||
<span class="inline-flex items-center gap-1 px-1.5 py-0.5 bg-slate-950 border border-slate-800 rounded text-[10px] text-slate-300">
|
|
||||||
<?= $mod['icon'] ?? '📦' ?> <?= htmlspecialchars($mod['name'] ?? $slug) ?>
|
|
||||||
</span>
|
|
||||||
<?php endforeach; endif; ?>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="px-3 sm:px-4 py-3">
|
|
||||||
<form action="<?= $baseUrl ?>/admin/user_toggle_status/<?= $u['id'] ?>" method="POST" class="inline">
|
|
||||||
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
|
||||||
<button type="submit" class="px-2.5 py-1 rounded text-[11px] font-mono border transition-all cursor-pointer <?= $u['status'] === 'Active' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30 hover:bg-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border-rose-500/30 hover:bg-rose-500/20' ?>" title="Klicken zum Umschalten">
|
|
||||||
<?= $u['status'] === 'Active' ? '● Aktiv' : '○ Inaktiv' ?>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
<td class="px-3 sm:px-4 py-3 text-right whitespace-nowrap">
|
|
||||||
<div class="flex justify-end items-center gap-3">
|
|
||||||
<a href="<?= $baseUrl ?>/admin/user_form/<?= $u['id'] ?>" class="text-cyan-400 hover:text-cyan-300">Bearbeiten</a>
|
|
||||||
<form action="<?= $baseUrl ?>/admin/user_delete/<?= $u['id'] ?>" method="POST" class="inline" onsubmit="return confirm('Benutzer <?= htmlspecialchars(addslashes($u['name'])) ?> wirklich löschen?');">
|
|
||||||
<input type="hidden" name="csrf_token" value="<?= Security::csrf() ?>">
|
|
||||||
<button type="submit" class="text-rose-400 hover:text-rose-300">Löschen</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; endif; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -276,13 +256,13 @@ function copyInviteLink(url, btn) {
|
||||||
|
|
||||||
function showSuccess() {
|
function showSuccess() {
|
||||||
var originalText = btn.innerHTML;
|
var originalText = btn.innerHTML;
|
||||||
btn.innerHTML = '✓ Kopiert!';
|
btn.innerHTML = 'Kopiert';
|
||||||
btn.classList.remove('bg-emerald-500/10', 'text-emerald-400');
|
btn.classList.remove('bg-cyan-500/10', 'text-cyan-400');
|
||||||
btn.classList.add('bg-emerald-500', 'text-slate-950', 'font-bold');
|
btn.classList.add('bg-cyan-500', 'text-slate-950', 'font-bold');
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
btn.innerHTML = originalText;
|
btn.innerHTML = originalText;
|
||||||
btn.classList.remove('bg-emerald-500', 'text-slate-950', 'font-bold');
|
btn.classList.remove('bg-cyan-500', 'text-slate-950', 'font-bold');
|
||||||
btn.classList.add('bg-emerald-500/10', 'text-emerald-400');
|
btn.classList.add('bg-cyan-500/10', 'text-cyan-400');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,18 +65,9 @@
|
||||||
<p class="text-slate-600 font-mono text-[10px] mt-1">Wende dich an Philipp, um Zugriff auf Tools zu erhalten.</p>
|
<p class="text-slate-600 font-mono text-[10px] mt-1">Wende dich an Philipp, um Zugriff auf Tools zu erhalten.</p>
|
||||||
</div>
|
</div>
|
||||||
<?php else: foreach ($accessibleModules as $mod): ?>
|
<?php else: foreach ($accessibleModules as $mod): ?>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?><?= ltrim($mod['path'], '/') ?>" class="flex items-center justify-between w-full bg-slate-950/80 border border-slate-700/60 hover:border-emerald-500/50 rounded-2xl p-3.5 sm:p-4 text-slate-200 text-sm transition-all shadow-lg hover:shadow-emerald-500/20 group/btn">
|
<a href="<?= Config::get('BASE_URL', '/') ?><?= ltrim($mod['path'], '/') ?>" class="flex items-center justify-between w-full bg-slate-950/80 border border-slate-700/60 hover:border-emerald-500/50 rounded-2xl p-4 text-slate-200 text-sm transition-all shadow-lg hover:shadow-emerald-500/20 group/btn">
|
||||||
<div class="flex items-center gap-3 min-w-0">
|
<span class="font-mono font-bold uppercase tracking-wider text-slate-200 group-hover/btn:text-emerald-400 transition-colors"><?= htmlspecialchars($mod['name']) ?></span>
|
||||||
<span class="text-2xl shrink-0"><?= $mod['icon'] ?></span>
|
<span class="text-slate-500 group-hover/btn:text-emerald-400 group-hover/btn:translate-x-1 transition-all">→</span>
|
||||||
<div class="min-w-0">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="font-mono font-bold tracking-wider text-slate-100 group-hover/btn:text-emerald-400 transition-colors"><?= htmlspecialchars($mod['name']) ?></span>
|
|
||||||
<span class="text-[10px] font-mono px-1.5 py-0.5 rounded bg-slate-900 border border-slate-800 text-slate-400 shrink-0"><?= htmlspecialchars($mod['badge']) ?></span>
|
|
||||||
</div>
|
|
||||||
<p class="text-[11px] text-slate-500 font-mono truncate"><?= htmlspecialchars($mod['description']) ?></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span class="text-slate-500 group-hover/btn:text-emerald-400 group-hover/btn:translate-x-1 transition-all shrink-0 ml-2">→</span>
|
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach; endif; ?>
|
<?php endforeach; endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="theme-color" content="#020617">
|
<meta name="theme-color" content="#020617">
|
||||||
<title>Admin | <?= htmlspecialchars(Config::get('APP_NAME', 'PhilCore')) ?></title>
|
<title>Admin | <?= htmlspecialchars(Config::get('APP_NAME', 'Philipp Urbschat')) ?></title>
|
||||||
<link rel="stylesheet" href="/css/app.css">
|
<link rel="stylesheet" href="/css/app.css">
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||||
|
|
@ -12,18 +12,20 @@
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||||
<link rel="shortcut icon" href="/favicon.ico">
|
<link rel="shortcut icon" href="/favicon.ico">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-[#0b1120] text-slate-300 min-h-screen bg-grid-admin font-sans selection-pink">
|
<body class="bg-[#020617] text-slate-300 min-h-screen font-sans selection-pink">
|
||||||
<header class="p-4 border-b border-slate-800 bg-slate-900/50 backdrop-blur-md sticky top-0 z-50">
|
<div class="crt-overlay pointer-events-none"></div>
|
||||||
<div class="container mx-auto flex justify-between items-center">
|
<header class="px-6 py-4 border-b border-slate-800/80 bg-slate-950/80 backdrop-blur-xl sticky top-0 z-50">
|
||||||
<div class="flex items-center gap-2 text-emerald-400 font-bold">
|
<div class="max-w-7xl mx-auto flex justify-between items-center">
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin" class="flex items-center gap-2 hover:text-emerald-300 transition-colors">
|
<div class="flex items-center gap-3">
|
||||||
👾 <span class="tracking-tight"><?= htmlspecialchars(Config::get('APP_NAME', 'PhilCore')) ?></span>
|
<a href="<?= Config::get('BASE_URL', '/') ?>admin" class="text-xs font-mono font-bold tracking-widest text-slate-200 hover:text-cyan-400 uppercase transition-colors flex items-center gap-2">
|
||||||
<span class="text-slate-600 ml-1 text-xs font-mono">/ Admin</span>
|
<span class="w-2 h-2 rounded-full bg-cyan-400 animate-pulse"></span>
|
||||||
|
philippurbschat.de <span class="text-slate-500 font-normal">/ admin</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-4 text-xs font-mono">
|
<div class="flex items-center gap-5 text-xs font-mono">
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>admin-tools" class="text-cyan-400 hover:text-cyan-300 transition-colors flex items-center gap-1">🛠️ Admin-Tools</a>
|
<a href="<?= Config::get('BASE_URL', '/') ?>admin/users?tab=users" class="text-slate-400 hover:text-cyan-400 transition-colors">Users</a>
|
||||||
<a href="<?= Config::get('BASE_URL', '/') ?>" class="text-slate-400 hover:text-emerald-400 transition-colors">← Zurück zur Website</a>
|
<a href="<?= Config::get('BASE_URL', '/') ?>admin/users?tab=invites" class="text-slate-400 hover:text-cyan-400 transition-colors">Invites</a>
|
||||||
|
<a href="<?= Config::get('BASE_URL', '/') ?>" class="text-slate-500 hover:text-emerald-400 transition-colors">← Website</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ $baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
<div class="max-w-md w-full my-8 relative z-10">
|
<div class="max-w-md w-full my-8 relative z-10">
|
||||||
<!-- Logo / Brand Header -->
|
<!-- Logo / Brand Header -->
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<a href="<?= $baseUrl ?>" class="inline-flex items-center gap-2 text-slate-200 hover:text-emerald-400 font-mono text-sm uppercase tracking-widest transition-colors">
|
<a href="<?= $baseUrl ?>" class="inline-flex items-center gap-2 text-slate-200 hover:text-cyan-400 font-mono text-xs uppercase tracking-widest transition-colors">
|
||||||
<span class="text-emerald-400 font-bold">👾</span> philippurbschat.de
|
<span class="w-2 h-2 rounded-full bg-cyan-400 animate-pulse"></span> philippurbschat.de
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -30,31 +30,30 @@ $baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
|
|
||||||
<?php if (!empty($valid)): ?>
|
<?php if (!empty($valid)): ?>
|
||||||
<!-- Valid Invitation Card -->
|
<!-- Valid Invitation Card -->
|
||||||
<div class="bg-slate-900/90 border border-emerald-500/30 rounded-3xl p-6 sm:p-8 backdrop-blur-xl shadow-[0_0_40px_rgba(16,185,129,0.12)] relative overflow-hidden">
|
<div class="bg-slate-900/90 border border-cyan-500/30 rounded-3xl p-6 sm:p-8 backdrop-blur-xl shadow-[0_0_40px_rgba(6,182,212,0.12)] relative overflow-hidden">
|
||||||
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-emerald-500 to-transparent"></div>
|
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-cyan-500 to-transparent"></div>
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<span class="inline-block px-3 py-1 bg-emerald-500/10 border border-emerald-500/30 rounded-full text-emerald-400 font-mono text-xs uppercase tracking-wider mb-3">
|
<span class="inline-block px-3 py-1 bg-cyan-500/10 border border-cyan-500/30 rounded-full text-cyan-400 font-mono text-[11px] uppercase tracking-wider mb-3">
|
||||||
✓ Einladung bestätigt
|
Einladung bestätigt
|
||||||
</span>
|
</span>
|
||||||
<h1 class="text-2xl font-black text-slate-100 font-mono tracking-tight">Account erstellen</h1>
|
<h1 class="text-2xl font-black text-slate-100 font-mono tracking-tight">Account erstellen</h1>
|
||||||
<p class="text-slate-400 text-sm mt-1">Vergib dein persönliches Passwort, um deinen Zugang zu aktivieren.</p>
|
<p class="text-slate-400 text-xs mt-1 font-mono">Vergib dein persönliches Passwort, um deinen Zugang zu aktivieren.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if (!empty($note)): ?>
|
<?php if (!empty($note)): ?>
|
||||||
<div class="bg-slate-950/70 border border-slate-800 rounded-xl p-3 mb-5 font-mono text-xs text-slate-400">
|
<div class="bg-slate-950/70 border border-slate-800 rounded-xl p-3 mb-5 font-mono text-xs text-slate-400">
|
||||||
<span class="text-emerald-400">Hinweis:</span> <?= htmlspecialchars($note) ?>
|
<span class="text-cyan-400">Hinweis:</span> <?= htmlspecialchars($note) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (!empty($assignedModules)): ?>
|
<?php if (!empty($assignedModules)): ?>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-2">Für dich freigeschaltete Module:</label>
|
<label class="block text-slate-400 font-mono text-[11px] uppercase tracking-wider mb-2">Freigeschaltete Module:</label>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<?php foreach ($assignedModules as $mod): ?>
|
<?php foreach ($assignedModules as $mod): ?>
|
||||||
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-slate-950/80 border border-slate-700/80 rounded-xl text-xs font-mono text-slate-200">
|
<span class="inline-flex items-center px-3 py-1.5 bg-slate-950/80 border border-slate-800 rounded-xl text-xs font-mono text-slate-300 uppercase tracking-wider">
|
||||||
<span><?= $mod['icon'] ?></span>
|
<?= htmlspecialchars($mod['name']) ?>
|
||||||
<span><?= htmlspecialchars($mod['name']) ?></span>
|
|
||||||
</span>
|
</span>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -100,8 +99,8 @@ $baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
|
||||||
<div class="bg-slate-900/90 border border-rose-500/30 rounded-3xl p-6 sm:p-8 backdrop-blur-xl shadow-[0_0_40px_rgba(244,63,94,0.15)] relative overflow-hidden text-center">
|
<div class="bg-slate-900/90 border border-rose-500/30 rounded-3xl p-6 sm:p-8 backdrop-blur-xl shadow-[0_0_40px_rgba(244,63,94,0.15)] relative overflow-hidden text-center">
|
||||||
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-rose-500 to-transparent"></div>
|
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-rose-500 to-transparent"></div>
|
||||||
|
|
||||||
<div class="w-14 h-14 bg-rose-500/10 border border-rose-500/30 rounded-2xl flex items-center justify-center mx-auto mb-4 text-2xl">
|
<div class="w-12 h-12 bg-rose-500/10 border border-rose-500/20 rounded-2xl flex items-center justify-center mx-auto mb-4 text-rose-400">
|
||||||
🔒
|
<svg class="w-5 h-5" 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"/></svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="text-2xl font-black text-slate-100 font-mono tracking-tight mb-3">Zugriff beschränkt</h1>
|
<h1 class="text-2xl font-black text-slate-100 font-mono tracking-tight mb-3">Zugriff beschränkt</h1>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue