new file: .gitignore
new file: README.md new file: database/schema.sql new file: paper-plugin/pom.xml new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/PaperLoggerPlugin.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/database/DatabaseManager.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/BlockListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/EntityListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/InventoryListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/WorldListener.java new file: paper-plugin/src/main/resources/config.yml new file: paper-plugin/src/main/resources/plugin.yml new file: paper-plugin/target/classes/config.yml new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/PaperLoggerPlugin.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand$RsConsumer.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager$ThrowingRunnable.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/BlockListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/EntityListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/InventoryListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/WorldListener.class new file: paper-plugin/target/classes/plugin.yml new file: paper-plugin/target/maven-archiver/pom.properties new file: paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file: paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file: paper-plugin/target/mclogger-paper-1.0.0.jar new file: paper-plugin/target/original-mclogger-paper-1.0.0.jar new file: velocity-plugin/pom.xml new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.java new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.java new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.java new file: velocity-plugin/src/main/resources/velocity-config.yml new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager$ThrowingRunnable.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.class new file: velocity-plugin/target/classes/velocity-config.yml new file: velocity-plugin/target/classes/velocity-plugin.json new file: velocity-plugin/target/maven-archiver/pom.properties new file: velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file: velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file: velocity-plugin/target/mclogger-velocity-1.0.0.jar new file: velocity-plugin/target/original-mclogger-velocity-1.0.0.jar new file: web/Dockerfile new file: web/app.py new file: web/blueprints/__init__.py new file: web/blueprints/auth.py new file: web/blueprints/group_admin.py new file: web/blueprints/panel.py new file: web/blueprints/site_admin.py new file: web/config.py new file: web/crypto.py new file: web/docker-compose.yml new file: web/panel_db.py new file: web/requirements.txt new file: web/static/css/style.css new file: web/static/js/main.js new file: web/templates/_pagination.html new file: web/templates/admin/base.html new file: web/templates/admin/dashboard.html new file: web/templates/admin/group_edit.html new file: web/templates/admin/group_members.html new file: web/templates/admin/groups.html new file: web/templates/admin/user_edit.html new file: web/templates/admin/users.html new file: web/templates/auth/admin_login.html new file: web/templates/auth/login.html new file: web/templates/base.html new file: web/templates/blocks.html new file: web/templates/chat.html new file: web/templates/commands.html new file: web/templates/dashboard.html new file: web/templates/deaths.html new file: web/templates/group_admin/base.html new file: web/templates/group_admin/dashboard.html new file: web/templates/group_admin/database.html new file: web/templates/group_admin/member_edit.html new file: web/templates/group_admin/members.html new file: web/templates/login.html new file: web/templates/panel/blocks.html new file: web/templates/panel/chat.html new file: web/templates/panel/commands.html new file: web/templates/panel/dashboard.html new file: web/templates/panel/deaths.html new file: web/templates/panel/no_db.html new file: web/templates/panel/perms.html new file: web/templates/panel/player_detail.html new file: web/templates/panel/players.html new file: web/templates/panel/proxy.html new file: web/templates/panel/server_events.html new file: web/templates/panel/sessions.html new file: web/templates/perms.html new file: web/templates/player_detail.html new file: web/templates/players.html new file: web/templates/proxy.html new file: web/templates/server_events.html new file: web/templates/sessions.html
This commit is contained in:
230
web/static/css/style.css
Normal file
230
web/static/css/style.css
Normal file
@@ -0,0 +1,230 @@
|
||||
/* ============================================================
|
||||
MCLogger – Admin Interface CSS
|
||||
Author: SimolZimol
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
--sidebar-width: 230px;
|
||||
--sidebar-bg: #0f1117;
|
||||
--sidebar-border: #1e2230;
|
||||
--topbar-bg: #13161f;
|
||||
--content-bg: #181c27;
|
||||
--card-bg: #1e2230;
|
||||
--card-border: #2a2f42;
|
||||
--text-muted-custom: #6b7280;
|
||||
--accent-green: #1db954;
|
||||
}
|
||||
|
||||
/* ── Layout ─────────────────────────────────────────────── */
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--content-bg);
|
||||
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Sidebar ─────────────────────────────────────────────── */
|
||||
#sidebar {
|
||||
width: var(--sidebar-width);
|
||||
min-width: var(--sidebar-width);
|
||||
background: var(--sidebar-bg);
|
||||
border-right: 1px solid var(--sidebar-border);
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
transition: width .25s ease, min-width .25s ease;
|
||||
}
|
||||
|
||||
#sidebar.collapsed {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
}
|
||||
|
||||
#sidebar.collapsed .sidebar-brand div,
|
||||
#sidebar.collapsed .sidebar-brand small,
|
||||
#sidebar.collapsed .nav-link span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
padding: .25rem 0;
|
||||
}
|
||||
|
||||
#sidebar .nav-link {
|
||||
color: #9ca3af;
|
||||
border-radius: 6px;
|
||||
padding: .45rem .75rem;
|
||||
font-size: .875rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
transition: background .15s, color .15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#sidebar .nav-link i {
|
||||
font-size: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#sidebar .nav-link:hover { background: rgba(255,255,255,.05); color: #e5e7eb; }
|
||||
#sidebar .nav-link.active { background: rgba(29,185,84,.15); color: var(--accent-green); }
|
||||
|
||||
/* ── Topbar ──────────────────────────────────────────────── */
|
||||
.topbar {
|
||||
background: var(--topbar-bg);
|
||||
border-bottom: 1px solid var(--sidebar-border);
|
||||
height: 52px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ── Content ─────────────────────────────────────────────── */
|
||||
#page-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--content-bg);
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* ── Cards ───────────────────────────────────────────────── */
|
||||
.card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: rgba(0,0,0,.2);
|
||||
border-bottom: 1px solid var(--card-border);
|
||||
font-size: .85rem;
|
||||
font-weight: 600;
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
/* ── Statistik-Karten ────────────────────────────────────── */
|
||||
.stat-card { transition: transform .15s; cursor: default; }
|
||||
.stat-card:hover { transform: translateY(-2px); }
|
||||
|
||||
.stat-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
color: #f3f4f6;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: .72rem;
|
||||
color: var(--text-muted-custom);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* ── Tabellen ────────────────────────────────────────────── */
|
||||
.table {
|
||||
color: #d1d5db;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.table > thead {
|
||||
font-size: .75rem;
|
||||
letter-spacing: .03em;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.table-hover > tbody > tr:hover > td {
|
||||
background: rgba(255,255,255,.04);
|
||||
}
|
||||
|
||||
.table-dark {
|
||||
--bs-table-bg: rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
/* ── Badges ──────────────────────────────────────────────── */
|
||||
.badge { font-size: .7rem; font-weight: 500; }
|
||||
|
||||
/* ── Inputs ──────────────────────────────────────────────── */
|
||||
.form-control, .form-select {
|
||||
background-color: #111827;
|
||||
border-color: var(--card-border);
|
||||
color: #e5e7eb;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: var(--accent-green);
|
||||
box-shadow: 0 0 0 2px rgba(29,185,84,.25);
|
||||
background-color: #111827;
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.form-control::placeholder { color: #6b7280; }
|
||||
|
||||
/* ── Buttons ─────────────────────────────────────────────── */
|
||||
.btn-success { background-color: var(--accent-green); border-color: var(--accent-green); }
|
||||
.btn-success:hover { background-color: #17a34a; border-color: #17a34a; }
|
||||
|
||||
/* ── Pagination ──────────────────────────────────────────── */
|
||||
.page-link {
|
||||
background-color: var(--card-bg);
|
||||
border-color: var(--card-border);
|
||||
color: #9ca3af;
|
||||
font-size: .8rem;
|
||||
}
|
||||
.page-link:hover { background-color: rgba(255,255,255,.07); color: #f3f4f6; }
|
||||
.page-item.active .page-link { background-color: var(--accent-green); border-color: var(--accent-green); color: #000; }
|
||||
.page-item.disabled .page-link { background-color: transparent; }
|
||||
|
||||
/* ── Login-Seite ─────────────────────────────────────────── */
|
||||
body .card.shadow-lg {
|
||||
background: #1e2230;
|
||||
border: 1px solid #2a2f42;
|
||||
}
|
||||
|
||||
/* ── Scrollbars ──────────────────────────────────────────── */
|
||||
::-webkit-scrollbar { width: 6px; height: 6px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: #374151; border-radius: 3px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #4b5563; }
|
||||
|
||||
/* ── Diverse ─────────────────────────────────────────────── */
|
||||
.blink {
|
||||
animation: blink-anim 1.5s infinite;
|
||||
}
|
||||
@keyframes blink-anim {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: .2; }
|
||||
}
|
||||
|
||||
.font-monospace { font-family: 'Consolas', 'Cascadia Code', monospace !important; }
|
||||
|
||||
.text-truncate { max-width: 250px; }
|
||||
|
||||
/* Chart.js Canvas */
|
||||
canvas { max-height: 250px; }
|
||||
|
||||
/* Alert */
|
||||
.alert { font-size: .85rem; }
|
||||
|
||||
/* sticky-top in dark scrollable containers */
|
||||
.sticky-top { z-index: 1; }
|
||||
97
web/static/js/main.js
Normal file
97
web/static/js/main.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/* ============================================================
|
||||
MCLogger – main.js
|
||||
Author: SimolZimol
|
||||
============================================================ */
|
||||
|
||||
// ── Sidebar Toggle ────────────────────────────────────────
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const btn = document.getElementById('sidebarToggle');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
|
||||
if (btn && sidebar) {
|
||||
btn.addEventListener('click', () => {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
localStorage.setItem('sidebar-collapsed', sidebar.classList.contains('collapsed'));
|
||||
});
|
||||
|
||||
// Zustand beim Laden wiederherstellen
|
||||
if (localStorage.getItem('sidebar-collapsed') === 'true') {
|
||||
sidebar.classList.add('collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
// Online-Count aktualisieren
|
||||
updateOnlineCount();
|
||||
setInterval(updateOnlineCount, 30_000);
|
||||
|
||||
// Tooltips initialisieren
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
|
||||
new bootstrap.Tooltip(el);
|
||||
});
|
||||
|
||||
// Automatisch Tabellen sortieren ermöglichen
|
||||
initTableSort();
|
||||
});
|
||||
|
||||
// ── Online-Count API ──────────────────────────────────────
|
||||
function updateOnlineCount() {
|
||||
fetch('/api/online')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
const el = document.getElementById('online-count');
|
||||
if (el) el.textContent = data.length;
|
||||
})
|
||||
.catch(() => {/* Ignorieren wenn nicht eingeloggt */});
|
||||
}
|
||||
|
||||
// ── Einfache Tabellen-Sortierung ──────────────────────────
|
||||
function initTableSort() {
|
||||
document.querySelectorAll('th[data-sort]').forEach(th => {
|
||||
th.style.cursor = 'pointer';
|
||||
th.addEventListener('click', () => {
|
||||
const table = th.closest('table');
|
||||
const idx = Array.from(th.parentNode.children).indexOf(th);
|
||||
const asc = th.dataset.order !== 'asc';
|
||||
th.dataset.order = asc ? 'asc' : 'desc';
|
||||
|
||||
const rows = Array.from(table.querySelectorAll('tbody tr'));
|
||||
rows.sort((a, b) => {
|
||||
const av = a.cells[idx]?.textContent.trim() ?? '';
|
||||
const bv = b.cells[idx]?.textContent.trim() ?? '';
|
||||
return asc ? av.localeCompare(bv, 'de', {numeric: true}) : bv.localeCompare(av, 'de', {numeric: true});
|
||||
});
|
||||
const tbody = table.querySelector('tbody');
|
||||
rows.forEach(r => tbody.appendChild(r));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Formatierung ──────────────────────────────────────────
|
||||
function fmtDuration(sec) {
|
||||
sec = parseInt(sec) || 0;
|
||||
const h = Math.floor(sec / 3600);
|
||||
const m = Math.floor((sec % 3600) / 60);
|
||||
const s = sec % 60;
|
||||
if (h) return `${h}h ${m}m`;
|
||||
if (m) return `${m}m ${s}s`;
|
||||
return `${s}s`;
|
||||
}
|
||||
|
||||
// ── Live-Chat-Reload (optional) ───────────────────────────
|
||||
if (window.location.pathname === '/chat') {
|
||||
// Kein automatisches Reload im Chat (würde Filter zurücksetzen)
|
||||
}
|
||||
|
||||
// ── Kopieren in Zwischenablage ────────────────────────────
|
||||
document.querySelectorAll('.copy-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const target = document.querySelector(btn.dataset.target);
|
||||
if (target) {
|
||||
navigator.clipboard.writeText(target.textContent.trim())
|
||||
.then(() => {
|
||||
btn.innerHTML = '<i class="bi bi-check2"></i>';
|
||||
setTimeout(() => btn.innerHTML = '<i class="bi bi-clipboard"></i>', 1500);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user