Further dashboard refinements and tweaks
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled

This commit is contained in:
Pepe44DEV
2026-07-01 03:37:09 +02:00
parent 17fa8c3edb
commit 6d51e150ff

View File

@@ -39,6 +39,38 @@ router.get('/', (req, res) => {
// - Play/Pause/Skip/Loop als UI-Controls anbieten und Bot-Status spiegeln. // - Play/Pause/Skip/Loop als UI-Controls anbieten und Bot-Status spiegeln.
// TODO: AUTOMOD: Konfiguration (Schwellenwerte, Filter, Logging) im Dashboard editierbar machen. // TODO: AUTOMOD: Konfiguration (Schwellenwerte, Filter, Logging) im Dashboard editierbar machen.
// - Grenzwerte, Whitelist/Badwords und Log-Ziel in ein Formular ueberfuehren. // - Grenzwerte, Whitelist/Badwords und Log-Ziel in ein Formular ueberfuehren.
const svgIcon = (paths: string, cls = 'icon', viewBox = '0 0 24 24') =>
`<span class="${cls}"><svg viewBox="${viewBox}" fill="none" aria-hidden="true">${paths}</svg></span>`;
const sparkline = (cls: string, stroke: string, d: string) =>
`<svg class="activity-chart ${cls}" viewBox="0 0 120 40" fill="none" aria-hidden="true"><path d="${d}" stroke="${stroke}" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"></path></svg>`;
const icons = {
overview: svgIcon(`<path d="M4 10.5 12 4l8 6.5"></path><path d="M6.5 9.5V19h11V9.5"></path><path d="M10 19v-4.5h4V19"></path>`),
tickets: svgIcon(`<path d="M4 8.5h16v4a2 2 0 0 0 0 4v4H4v-4a2 2 0 0 0 0-4v-4Z"></path><path d="M9 8.5v12"></path><path d="M14 11.5h2.5"></path><path d="M14 15.5h2.5"></path>`),
automod: svgIcon(`<path d="M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z"></path><path d="m9.5 12 1.7 1.7L14.8 10"></path>`),
welcome: svgIcon(`<path d="M12 6.5v11"></path><path d="M7.5 11 12 6.5 16.5 11"></path><path d="M5 17.5c1.8-1.3 4.1-2 7-2s5.2.7 7 2"></path>`),
dynamicvoice: svgIcon(`<path d="M12 5v14"></path><rect x="9" y="3.5" width="6" height="10" rx="3"></rect><path d="M7 11.5a5 5 0 0 0 10 0"></path><path d="M9.5 20h5"></path>`),
birthday: svgIcon(`<path d="M7 10h10v10H7z"></path><path d="M12 10V6"></path><path d="M9 6.5c0-1 1.2-1.9 2.2-.8L12 6.5l.8-.8c1-1.1 2.2-.2 2.2.8 0 1.4-1.2 2.3-3 3.5-1.8-1.2-3-2.1-3-3.5Z"></path>`),
reactionroles: svgIcon(`<path d="M7.5 13.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Z"></path><path d="M16.5 17.5a3 3 0 1 0 0-6"></path><path d="M3.5 19c1.2-2.2 3.2-3.5 6-3.5s4.8 1.3 6 3.5"></path><path d="M14.5 13.5c1.3.2 2.3.7 3.1 1.6"></path>`),
statuspage: svgIcon(`<path d="M5 17.5h14"></path><path d="M7.5 14.5 10 11l2.5 2 4-5"></path><path d="M6 5.5h12"></path>`),
serverstats: svgIcon(`<path d="M5 18.5V10"></path><path d="M12 18.5V6.5"></path><path d="M19 18.5v-4"></path><path d="M3.5 18.5h17"></path>`),
settings: svgIcon(`<path d="m12 4 1 .6 1.2-.3 1 1.8 1.2.4v2l.9.9-.5 1.1.5 1.1-.9.9v2l-1.2.4-1 1.8-1.2-.3-1 .6-1-.6-1.2.3-1-1.8-1.2-.4v-2l-.9-.9.5-1.1-.5-1.1.9-.9v-2l1.2-.4 1-1.8 1.2.3L12 4Z"></path><circle cx="12" cy="12" r="2.7"></circle>`),
modules: svgIcon(`<path d="M5 5.5h6v6H5z"></path><path d="M13 5.5h6v6h-6z"></path><path d="M5 13.5h6v6H5z"></path><path d="M16 13.5h3v6h-6v-3"></path>`),
events: svgIcon(`<rect x="4.5" y="6" width="15" height="13" rx="2"></rect><path d="M8 4.5v3"></path><path d="M16 4.5v3"></path><path d="M4.5 10h15"></path><path d="M8.5 13h3"></path><path d="M8.5 16h6"></path>`),
admin: svgIcon(`<path d="M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z"></path><path d="M12 9v6"></path><path d="M9 12h6"></path>`),
owner: svgIcon(`<path d="M12 6.2 13.6 9.4l3.5.5-2.5 2.5.6 3.5L12 14.2 8.8 16l.6-3.5-2.5-2.5 3.5-.5L12 6.2Z"></path>`, 'metric-icon owner'),
created: svgIcon(`<rect x="5" y="6" width="14" height="13" rx="2"></rect><path d="M8 4.5v3"></path><path d="M16 4.5v3"></path><path d="M5 10h14"></path>`, 'metric-icon created'),
members: svgIcon(`<path d="M8 12.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5Z"></path><path d="M16.5 11.8a2.2 2.2 0 1 0 0-4.4"></path><path d="M4.8 17.5c.9-1.8 2.6-2.8 5-2.8s4.1 1 5 2.8"></path><path d="M14.5 14.8c1.3.2 2.3.8 3 1.8"></path>`, 'metric-icon members'),
channels: svgIcon(`<path d="M4.5 8h15"></path><path d="M4.5 16h15"></path><path d="M9 4.5v15"></path>`, 'metric-icon channels'),
open: svgIcon(`<path d="M4.5 9.5 16 4.5l3.5 3-11.5 5-3.5-3Z"></path><path d="M8 12.5v7l11.5-5v-7"></path>`, 'metric-icon open'),
closed: svgIcon(`<path d="M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z"></path>`, 'metric-icon closed'),
message: svgIcon(`<path d="M6 7.5h12a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H11l-4 3v-3H6a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2Z"></path>`, 'activity-icon-svg message'),
command: svgIcon(`<path d="M8 8a2.5 2.5 0 1 0 0 5h3"></path><path d="M16 8a2.5 2.5 0 1 1 0 5h-3"></path><path d="M12 5.5v13"></path>`, 'activity-icon-svg command'),
shield: svgIcon(`<path d="M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z"></path>`, 'activity-icon-svg shield'),
arrow: svgIcon(`<path d="M8 6.5 15 12 8 17.5"></path>`, 'button-icon'),
list: svgIcon(`<path d="M8 7h10"></path><path d="M8 12h10"></path><path d="M8 17h10"></path><path d="M4.5 7h.01"></path><path d="M4.5 12h.01"></path><path d="M4.5 17h.01"></path>`, 'button-icon'),
bot: svgIcon(`<rect x="7" y="8" width="10" height="8" rx="2"></rect><path d="M12 5.5v2.5"></path><path d="M9.5 12h.01"></path><path d="M14.5 12h.01"></path>`, 'status-bot'),
logout: svgIcon(`<path d="M10 6H7a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h3"></path><path d="m13 15 3-3-3-3"></path><path d="M9 12h7"></path>`, 'button-icon')
};
const sidebar = ` const sidebar = `
<aside class="sidebar"> <aside class="sidebar">
<div class="brand"> <div class="brand">
@@ -67,7 +99,7 @@ router.get('/', (req, res) => {
<div class="sidebar-user-label">Angemeldet als</div> <div class="sidebar-user-label">Angemeldet als</div>
<div class="sidebar-user-name" id="userInfo"></div> <div class="sidebar-user-name" id="userInfo"></div>
</div> </div>
<button id="logoutBtn" class="logout">Logout</button> <button id="logoutBtn" class="logout">${icons.logout} Logout</button>
</aside> </aside>
`; `;
@@ -213,7 +245,20 @@ router.get('/', (req, res) => {
.nav { display:flex; flex-direction:column; gap:8px; } .nav { display:flex; flex-direction:column; gap:8px; }
.nav a { display:flex; align-items:center; gap:12px; padding:13px 14px; border-radius:16px; color:var(--muted); text-decoration:none; font-size:14px; font-weight:700; transition:background 160ms ease, color 160ms ease, box-shadow 160ms ease, border-color 160ms ease, transform 160ms ease; border:1px solid transparent; background:rgba(255,255,255,0.02); position:relative; overflow:hidden; } .nav a { display:flex; align-items:center; gap:12px; padding:13px 14px; border-radius:16px; color:var(--muted); text-decoration:none; font-size:14px; font-weight:700; transition:background 160ms ease, color 160ms ease, box-shadow 160ms ease, border-color 160ms ease, transform 160ms ease; border:1px solid transparent; background:rgba(255,255,255,0.02); position:relative; overflow:hidden; }
.nav a::before { content:''; position:absolute; inset:0; background:linear-gradient(90deg, rgba(255,255,255,0.08), transparent 55%); opacity:0; transition:opacity 160ms ease; } .nav a::before { content:''; position:absolute; inset:0; background:linear-gradient(90deg, rgba(255,255,255,0.08), transparent 55%); opacity:0; transition:opacity 160ms ease; }
.nav a .icon { opacity:0.9; width:18px; display:inline-flex; justify-content:center; font-size:15px; } .nav a .icon { opacity:1; width:18px; height:18px; display:inline-flex; justify-content:center; align-items:center; font-size:0; color:transparent; position:relative; flex-shrink:0; }
.nav a .icon::before { content:''; width:18px; height:18px; background-repeat:no-repeat; background-position:center; background-size:18px 18px; opacity:0.92; }
.nav a:nth-child(1) .icon::before { background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 10.5 12 4l8 6.5'/%3E%3Cpath d='M6.5 9.5V19h11V9.5'/%3E%3Cpath d='M10 19v-4.5h4V19'/%3E%3C/svg%3E"); }
.nav a:nth-child(2) .icon::before { background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8.5h16v4a2 2 0 0 0 0 4v4H4v-4a2 2 0 0 0 0-4v-4Z'/%3E%3Cpath d='M9 8.5v12'/%3E%3Cpath d='M14 11.5h2.5M14 15.5h2.5'/%3E%3C/svg%3E"); }
.nav a:nth-child(3) .icon::before, .nav a:nth-child(12) .icon::before, .nav a:nth-child(13) .icon::before { background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z'/%3E%3Cpath d='m9.5 12 1.7 1.7L14.8 10'/%3E%3C/svg%3E"); }
.nav a:nth-child(4) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6.5v11'/%3E%3Cpath d='M7.5 11 12 6.5 16.5 11'/%3E%3Cpath d='M5 17.5c1.8-1.3 4.1-2 7-2s5.2.7 7 2'/%3E%3C/svg%3E\"); }
.nav a:nth-child(5) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='3.5' width='6' height='10' rx='3'/%3E%3Cpath d='M12 5v14M7 11.5a5 5 0 0 0 10 0M9.5 20h5'/%3E%3C/svg%3E\"); }
.nav a:nth-child(6) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 10h10v10H7zM12 10V6'/%3E%3Cpath d='M9 6.5c0-1 1.2-1.9 2.2-.8L12 6.5l.8-.8c1-1.1 2.2-.2 2.2.8 0 1.4-1.2 2.3-3 3.5-1.8-1.2-3-2.1-3-3.5Z'/%3E%3C/svg%3E\"); }
.nav a:nth-child(7) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 13.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Z'/%3E%3Cpath d='M16.5 17.5a3 3 0 1 0 0-6'/%3E%3Cpath d='M3.5 19c1.2-2.2 3.2-3.5 6-3.5s4.8 1.3 6 3.5'/%3E%3Cpath d='M14.5 13.5c1.3.2 2.3.7 3.1 1.6'/%3E%3C/svg%3E\"); }
.nav a:nth-child(8) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 17.5h14M7.5 14.5 10 11l2.5 2 4-5M6 5.5h12'/%3E%3C/svg%3E\"); }
.nav a:nth-child(9) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 18.5V10M12 18.5V6.5M19 18.5v-4M3.5 18.5h17'/%3E%3C/svg%3E\"); }
.nav a:nth-child(10) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 4 1 .6 1.2-.3 1 1.8 1.2.4v2l.9.9-.5 1.1.5 1.1-.9.9v2l-1.2.4-1 1.8-1.2-.3-1 .6-1-.6-1.2.3-1-1.8-1.2-.4v-2l-.9-.9.5-1.1-.5-1.1.9-.9v-2l1.2-.4 1-1.8 1.2.3L12 4Z'/%3E%3Ccircle cx='12' cy='12' r='2.7'/%3E%3C/svg%3E\"); }
.nav a:nth-child(11) .icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 5.5h6v6H5zM13 5.5h6v6h-6zM5 13.5h6v6H5zM16 13.5h3v6h-6v-3'/%3E%3C/svg%3E\"); }
.nav a.active .icon::before { filter:drop-shadow(0 0 8px rgba(249,115,22,0.2)); }
.nav a.active { background:linear-gradient(90deg, rgba(249,115,22,0.34), rgba(249,115,22,0.14)); color:#fff2e6; border-color:var(--border-strong); box-shadow:0 16px 30px rgba(249,115,22,0.22); transform:translateX(2px); } .nav a.active { background:linear-gradient(90deg, rgba(249,115,22,0.34), rgba(249,115,22,0.14)); color:#fff2e6; border-color:var(--border-strong); box-shadow:0 16px 30px rgba(249,115,22,0.22); transform:translateX(2px); }
.nav a.active::before, .nav a:hover::before { opacity:1; } .nav a.active::before, .nav a:hover::before { opacity:1; }
.nav a:hover { background:rgba(255,255,255,0.06); color:var(--text); border-color:rgba(255,255,255,0.09); } .nav a:hover { background:rgba(255,255,255,0.06); color:var(--text); border-color:rgba(255,255,255,0.09); }
@@ -343,15 +388,20 @@ router.get('/', (req, res) => {
.activity-list { display:flex; flex-direction:column; gap:12px; margin-top:14px; } .activity-list { display:flex; flex-direction:column; gap:12px; margin-top:14px; }
.activity-card { display:flex; align-items:center; justify-content:space-between; gap:14px; padding:16px 18px; border:1px solid rgba(255,255,255,0.08); border-radius:18px; background:linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.025)); box-shadow:0 16px 32px rgba(0,0,0,0.24); } .activity-card { display:flex; align-items:center; justify-content:space-between; gap:14px; padding:16px 18px; border:1px solid rgba(255,255,255,0.08); border-radius:18px; background:linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.025)); box-shadow:0 16px 32px rgba(0,0,0,0.24); }
.activity-card-main { display:flex; align-items:center; gap:12px; } .activity-card-main { display:flex; align-items:center; gap:12px; }
.activity-icon { width:42px; height:42px; border-radius:14px; display:flex; align-items:center; justify-content:center; font-size:18px; background:rgba(249,115,22,0.12); border:1px solid rgba(249,115,22,0.18); color:#ffd7b0; } .activity-icon { width:42px; height:42px; border-radius:14px; display:flex; align-items:center; justify-content:center; font-size:0; color:transparent; background:rgba(249,115,22,0.12); border:1px solid rgba(249,115,22,0.18); position:relative; flex-shrink:0; }
.activity-icon.commands { background:rgba(234,88,12,0.12); color:#fdba74; } .activity-icon.commands { background:rgba(151,71,255,0.12); border-color:rgba(168,85,247,0.2); }
.activity-icon.automod { background:rgba(21,128,61,0.14); color:#86efac; border-color:rgba(34,197,94,0.16); } .activity-icon.automod { background:rgba(21,128,61,0.14); color:#86efac; border-color:rgba(34,197,94,0.16); }
.activity-icon::before { content:''; width:19px; height:19px; background-repeat:no-repeat; background-position:center; background-size:19px 19px; }
.activity-icon.message::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f7c086' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 7.5h12a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H11l-4 3v-3H6a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2Z'/%3E%3C/svg%3E\"); }
.activity-icon.commands::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c084fc' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 8a2.5 2.5 0 1 0 0 5h3M16 8a2.5 2.5 0 1 1 0 5h-3M12 5.5v13'/%3E%3C/svg%3E\"); }
.activity-icon.automod::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234ade80' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z'/%3E%3C/svg%3E\"); }
.activity-value { font-size:18px; font-weight:800; color:var(--text); margin-top:2px; } .activity-value { font-size:18px; font-weight:800; color:var(--text); margin-top:2px; }
.activity-spark { width:92px; height:28px; border-radius:999px; position:relative; overflow:hidden; } .activity-spark { width:92px; height:28px; display:flex; align-items:center; justify-content:flex-end; position:relative; }
.activity-spark::before { content:''; position:absolute; inset:0; border-radius:999px; opacity:0.9; } .activity-spark::before { content:''; width:92px; height:28px; background-repeat:no-repeat; background-position:center; background-size:92px 28px; opacity:0.98; }
.activity-spark.messages::before { background:linear-gradient(135deg, transparent 0 10%, rgba(255,255,255,0) 10% 16%, rgba(255,176,102,0.95) 16% 20%, transparent 20% 36%, rgba(255,176,102,0.95) 36% 44%, transparent 44% 58%, rgba(255,176,102,0.8) 58% 65%, transparent 65%); } .activity-spark.messages::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 40' fill='none'%3E%3Cpath d='M4 26 C16 12, 24 10, 34 18 S54 30, 64 22 S80 6, 92 14 S108 20, 116 18' stroke='%23f2b36f' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\"); }
.activity-spark.commands::before { background:linear-gradient(135deg, transparent 0 12%, rgba(168,85,247,0.9) 12% 18%, transparent 18% 34%, rgba(192,132,252,0.92) 34% 46%, transparent 46% 62%, rgba(168,85,247,0.72) 62% 70%, transparent 70%); } .activity-spark.commands::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 40' fill='none'%3E%3Cpath d='M4 22 C14 10, 22 12, 34 20 S54 28, 66 16 S82 8, 92 14 S108 24, 116 22' stroke='%23b26cff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\"); }
.activity-spark.automod::before { background:linear-gradient(135deg, transparent 0 18%, rgba(74,222,128,0.86) 18% 24%, transparent 24% 42%, rgba(74,222,128,0.95) 42% 51%, transparent 51% 66%, rgba(34,197,94,0.78) 66% 74%, transparent 74%); } .activity-spark.automod::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 40' fill='none'%3E%3Cpath d='M4 28 C14 24, 22 10, 34 12 S54 30, 66 22 S84 8, 96 14 S110 18, 116 16' stroke='%2348d883' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\"); }
.activity-chart { width:92px; height:28px; opacity:0.95; }
.logs-panel .log-list { margin-top:14px; } .logs-panel .log-list { margin-top:14px; }
.panel-action { margin-top:18px; width:100%; justify-content:center; } .panel-action { margin-top:18px; width:100%; justify-content:center; }
.panel-action.secondary-btn { display:flex; align-items:center; justify-content:center; gap:10px; } .panel-action.secondary-btn { display:flex; align-items:center; justify-content:center; gap:10px; }
@@ -359,8 +409,26 @@ router.get('/', (req, res) => {
.quick-actions-grid { display:grid; grid-template-columns:repeat(6, minmax(0, 1fr)); gap:14px; margin-top:16px; } .quick-actions-grid { display:grid; grid-template-columns:repeat(6, minmax(0, 1fr)); gap:14px; margin-top:16px; }
.quick-action { text-align:left; padding:16px 16px 14px; border-radius:18px; border:1px solid rgba(255,255,255,0.08); background:linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.02)); box-shadow:0 16px 32px rgba(0,0,0,0.22); } .quick-action { text-align:left; padding:16px 16px 14px; border-radius:18px; border:1px solid rgba(255,255,255,0.08); background:linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.02)); box-shadow:0 16px 32px rgba(0,0,0,0.22); }
.quick-action-head { display:flex; align-items:center; gap:10px; margin-bottom:8px; font-weight:800; color:var(--text); } .quick-action-head { display:flex; align-items:center; gap:10px; margin-bottom:8px; font-weight:800; color:var(--text); }
.quick-action-icon { width:38px; height:38px; border-radius:14px; display:flex; align-items:center; justify-content:center; font-size:17px; background:rgba(249,115,22,0.14); color:#ffd7b0; border:1px solid rgba(249,115,22,0.18); } .quick-action-icon { width:38px; height:38px; border-radius:14px; display:flex; align-items:center; justify-content:center; font-size:0; color:transparent; background:rgba(249,115,22,0.14); border:1px solid rgba(249,115,22,0.18); position:relative; flex-shrink:0; }
.quick-action-icon::before { content:''; width:18px; height:18px; background-repeat:no-repeat; background-position:center; background-size:18px 18px; }
.quick-action:nth-child(1) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8.5h16v4a2 2 0 0 0 0 4v4H4v-4a2 2 0 0 0 0-4v-4Z'/%3E%3Cpath d='M9 8.5v12M14 11.5h2.5M14 15.5h2.5'/%3E%3C/svg%3E\"); }
.quick-action:nth-child(2) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5 18.5 6v5.3c0 4.3-2.6 7.6-6.5 9.2-3.9-1.6-6.5-4.9-6.5-9.2V6L12 3.5Z'/%3E%3Cpath d='m9.5 12 1.7 1.7L14.8 10'/%3E%3C/svg%3E\"); }
.quick-action:nth-child(3) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6.5v11M7.5 11 12 6.5 16.5 11M5 17.5c1.8-1.3 4.1-2 7-2s5.2.7 7 2'/%3E%3C/svg%3E\"); }
.quick-action:nth-child(4) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='3.5' width='6' height='10' rx='3'/%3E%3Cpath d='M12 5v14M7 11.5a5 5 0 0 0 10 0M9.5 20h5'/%3E%3C/svg%3E\"); }
.quick-action:nth-child(5) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 13.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Z'/%3E%3Cpath d='M16.5 17.5a3 3 0 1 0 0-6'/%3E%3Cpath d='M3.5 19c1.2-2.2 3.2-3.5 6-3.5s4.8 1.3 6 3.5'/%3E%3Cpath d='M14.5 13.5c1.3.2 2.3.7 3.1 1.6'/%3E%3C/svg%3E\"); }
.quick-action:nth-child(6) .quick-action-icon::before { background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f4b06b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 17.5h14M7.5 14.5 10 11l2.5 2 4-5M6 5.5h12'/%3E%3C/svg%3E\"); }
.quick-action p { margin:0; color:var(--muted); font-size:12px; line-height:1.5; } .quick-action p { margin:0; color:var(--muted); font-size:12px; line-height:1.5; }
.detail-head { display:flex; align-items:center; gap:8px; margin-bottom:8px; }
.metric-icon { width:18px; height:18px; display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; }
.metric-icon svg, .activity-icon-svg svg, .button-icon svg, .status-bot svg, .icon svg { width:100%; height:100%; stroke:currentColor; }
.metric-icon.owner { color:#f4b06b; }
.metric-icon.created { color:#c084fc; }
.metric-icon.members { color:#f5c04f; }
.metric-icon.channels { color:#8ab4ff; }
.metric-icon.open { color:#f59e0b; }
.metric-icon.closed { color:#4ade80; }
.button-icon { width:16px; height:16px; display:inline-flex; align-items:center; justify-content:center; color:#d8cdbd; }
.status-bot { width:18px; height:18px; display:inline-flex; align-items:center; justify-content:center; color:#22c55e; }
.spinner { width:28px; height:28px; border:3px solid rgba(255,255,255,0.12); border-top-color:var(--accent); border-radius:50%; animation:spin .6s linear infinite; margin:12px auto; } .spinner { width:28px; height:28px; border:3px solid rgba(255,255,255,0.12); border-top-color:var(--accent); border-radius:50%; animation:spin .6s linear infinite; margin:12px auto; }
@media (max-width: 1180px) { @media (max-width: 1180px) {
.layout { flex-direction:column; } .layout { flex-direction:column; }
@@ -417,7 +485,7 @@ router.get('/', (req, res) => {
</div> </div>
</div> </div>
<div class="overview-status"> <div class="overview-status">
<span class="status-dot"></span> ${icons.bot}
<span>Bot aktiv</span> <span>Bot aktiv</span>
</div> </div>
</section> </section>
@@ -425,12 +493,12 @@ router.get('/', (req, res) => {
<section class="card overview-panel"> <section class="card overview-panel">
<p class="section-title">Guild Infos</p> <p class="section-title">Guild Infos</p>
<div class="detail-grid"> <div class="detail-grid">
<div class="detail-tile overview-stat"><div class="detail-label">Owner</div><div class="overview-stat-value" id="guildOwner">-</div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.owner}<div class="detail-label">Owner</div></div><div class="overview-stat-value" id="guildOwner">-</div></div>
<div class="detail-tile overview-stat"><div class="detail-label">Erstellt</div><div class="overview-stat-value" id="guildCreated">-</div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.created}<div class="detail-label">Erstellt</div></div><div class="overview-stat-value" id="guildCreated">-</div></div>
<div class="detail-tile overview-stat"><div class="detail-label">Member</div><div class="overview-stat-value" id="guildMembers">-</div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.members}<div class="detail-label">Member</div></div><div class="overview-stat-value" id="guildMembers">-</div></div>
<div class="detail-tile overview-stat"><div class="detail-label">Channels</div><div class="overview-stat-value" id="guildChannels">-</div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.channels}<div class="detail-label">Channels</div></div><div class="overview-stat-value" id="guildChannels">-</div></div>
<div class="detail-tile overview-stat"><div class="detail-label">Tickets offen</div><div class="overview-stat-value" id="openCount">-</div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.open}<div class="detail-label">Tickets offen</div></div><div class="overview-stat-value" id="openCount">-</div></div>
<div class="detail-tile overview-stat"><div class="detail-label">Tickets IP / Closed</div><div class="overview-stat-value"><span id="ipCount">-</span> / <span id="closedCount">-</span></div></div> <div class="detail-tile overview-stat"><div class="detail-head">${icons.closed}<div class="detail-label">Tickets IP / Closed</div></div><div class="overview-stat-value"><span id="ipCount">-</span> / <span id="closedCount">-</span></div></div>
</div> </div>
<button type="button" class="secondary-btn panel-action" data-nav-target="serverstats">Server Statistiken ansehen</button> <button type="button" class="secondary-btn panel-action" data-nav-target="serverstats">Server Statistiken ansehen</button>
</section> </section>
@@ -471,7 +539,10 @@ router.get('/', (req, res) => {
<button type="button" class="secondary-btn panel-action" data-nav-target="settings">Alle Logs anzeigen</button> <button type="button" class="secondary-btn panel-action" data-nav-target="settings">Alle Logs anzeigen</button>
</section> </section>
<section class="card overview-panel logs-panel"> <section class="card overview-panel logs-panel">
<div class="row" style="justify-content:space-between; align-items:center;">
<p class="section-title">Guild Logs</p> <p class="section-title">Guild Logs</p>
<button type="button" class="secondary-btn" data-nav-target="settings">Alle anzeigen</button>
</div>
<ul class="log-list" id="guildLogs"></ul> <ul class="log-list" id="guildLogs"></ul>
</section> </section>
</div> </div>