refine dashboard theme and orange accent styling
This commit is contained in:
@@ -3,6 +3,22 @@
|
|||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--app-bg: #110f0d;
|
||||||
|
--app-bg-soft: #181513;
|
||||||
|
--app-panel: #1d1a1f;
|
||||||
|
--app-panel-strong: #221e24;
|
||||||
|
--app-panel-muted: #171419;
|
||||||
|
--app-border: rgba(255, 255, 255, 0.08);
|
||||||
|
--app-border-strong: rgba(255, 166, 77, 0.22);
|
||||||
|
--app-text: #f6f2ee;
|
||||||
|
--app-text-muted: #b8aca1;
|
||||||
|
--app-accent: #ff8a3d;
|
||||||
|
--app-accent-strong: #ff6a00;
|
||||||
|
--app-accent-soft: rgba(255, 138, 61, 0.14);
|
||||||
|
--app-accent-glow: rgba(255, 138, 61, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
html, body, #root {
|
html, body, #root {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
@@ -10,8 +26,11 @@ html, body, #root {
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
background: #111111;
|
background:
|
||||||
color: #f5f5f7;
|
radial-gradient(circle at top left, rgba(255, 106, 0, 0.12), transparent 22%),
|
||||||
|
radial-gradient(circle at top right, rgba(255, 138, 61, 0.08), transparent 18%),
|
||||||
|
linear-gradient(180deg, #0f0d0c 0%, #141110 100%);
|
||||||
|
color: var(--app-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@@ -56,8 +75,8 @@ input:focus,
|
|||||||
textarea:focus,
|
textarea:focus,
|
||||||
select:focus {
|
select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: rgba(58, 150, 255, 0.9);
|
border-color: var(--app-accent);
|
||||||
box-shadow: 0 0 0 3px rgba(58, 150, 255, 0.18);
|
box-shadow: 0 0 0 3px rgba(255, 138, 61, 0.16);
|
||||||
background: rgba(255, 255, 255, 0.08);
|
background: rgba(255, 255, 255, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +87,88 @@ label {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.surface-card {
|
||||||
|
background: linear-gradient(180deg, rgba(31, 27, 33, 0.96), rgba(23, 20, 25, 0.96));
|
||||||
|
border: 1px solid var(--app-border);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surface-card-strong {
|
||||||
|
background: linear-gradient(180deg, rgba(36, 30, 24, 0.98), rgba(25, 21, 18, 0.98));
|
||||||
|
border: 1px solid var(--app-border-strong);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.03),
|
||||||
|
0 18px 50px rgba(0, 0, 0, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surface-card-muted {
|
||||||
|
background: rgba(255, 255, 255, 0.025);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-text {
|
||||||
|
color: var(--app-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-chip {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
color: #ffb37f;
|
||||||
|
border: 1px solid rgba(255, 138, 61, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-button {
|
||||||
|
background: linear-gradient(135deg, var(--app-accent) 0%, var(--app-accent-strong) 100%);
|
||||||
|
color: white;
|
||||||
|
border: 1px solid rgba(255, 166, 77, 0.45);
|
||||||
|
box-shadow: 0 10px 24px rgba(255, 106, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-button:hover {
|
||||||
|
filter: brightness(1.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-button-soft {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
color: #ffbc8e;
|
||||||
|
border: 1px solid rgba(255, 138, 61, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-button {
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.09);
|
||||||
|
color: var(--app-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button:hover {
|
||||||
|
background: rgba(255, 138, 61, 0.08);
|
||||||
|
color: var(--app-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button-active {
|
||||||
|
background: linear-gradient(135deg, rgba(255, 138, 61, 0.22), rgba(255, 106, 0, 0.24));
|
||||||
|
color: white;
|
||||||
|
border: 1px solid rgba(255, 138, 61, 0.28);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-shell {
|
||||||
|
background: linear-gradient(180deg, rgba(16, 14, 13, 0.98), rgba(18, 15, 14, 0.98));
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-mark {
|
||||||
|
background: linear-gradient(135deg, var(--app-accent) 0%, var(--app-accent-strong) 100%);
|
||||||
|
box-shadow: 0 12px 30px rgba(255, 106, 0, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtle {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
.scrollbar-thin {
|
.scrollbar-thin {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
|
scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Chip, Tooltip, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Avatar } from '@heroui/react';
|
import { Button, Chip, Tooltip, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Avatar } from '@heroui/react';
|
||||||
import { Moon, Sun, Bell, ChevronDown, LogOut, Settings } from 'lucide-react';
|
import { Moon, Sun, ChevronDown, LogOut, Settings } from 'lucide-react';
|
||||||
import { useTheme } from '../../hooks/useTheme';
|
import { useTheme } from '../../hooks/useTheme';
|
||||||
import { useApp } from '../../context/AppContext';
|
import { useApp } from '../../context/AppContext';
|
||||||
|
|
||||||
@@ -30,14 +30,14 @@ export function Header() {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<div className="flex items-center gap-1.5 text-sm text-default-400 min-w-0">
|
<div className="flex items-center gap-1.5 text-sm section-subtle min-w-0">
|
||||||
<button className="hover:text-foreground transition-colors" onClick={() => setSection('overview')}>
|
<button className="hover:text-white transition-colors" onClick={() => setSection('overview')}>
|
||||||
Dashboard
|
Dashboard
|
||||||
</button>
|
</button>
|
||||||
{section !== 'overview' && (
|
{section !== 'overview' && (
|
||||||
<>
|
<>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="text-foreground font-medium truncate">{navLabels[section] || section}</span>
|
<span className="accent-text font-semibold truncate">{navLabels[section] || section}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -45,20 +45,20 @@ export function Header() {
|
|||||||
|
|
||||||
<div className="flex items-center gap-2 shrink-0">
|
<div className="flex items-center gap-2 shrink-0">
|
||||||
{statusMessage && (
|
{statusMessage && (
|
||||||
<Chip color="warning" size="sm" variant="solid" className="max-w-[220px]">
|
<Chip size="sm" variant="flat" className="accent-chip max-w-[220px]">
|
||||||
<span className="truncate">{statusMessage}</span>
|
<span className="truncate">{statusMessage}</span>
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Tooltip content={dark ? 'Helles Design' : 'Dunkles Design'} placement="bottom">
|
<Tooltip content={dark ? 'Helles Design' : 'Dunkles Design'} placement="bottom">
|
||||||
<Button isIconOnly radius="lg" size="sm" variant="bordered" onPress={toggle}>
|
<Button isIconOnly radius="lg" size="sm" variant="light" className="ghost-button" onPress={toggle}>
|
||||||
{dark ? <Sun size={16} /> : <Moon size={16} />}
|
{dark ? <Sun size={16} /> : <Moon size={16} />}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Dropdown placement="bottom-end">
|
<Dropdown placement="bottom-end">
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
<Button className="gap-2" radius="lg" size="sm" variant="bordered">
|
<Button className="ghost-button gap-2" radius="lg" size="sm" variant="light">
|
||||||
<Avatar name={user?.username} size="sm" className="size-6" />
|
<Avatar name={user?.username} size="sm" className="size-6" />
|
||||||
<span className="hidden sm:inline text-sm">{user?.username}</span>
|
<span className="hidden sm:inline text-sm">{user?.username}</span>
|
||||||
<ChevronDown size={14} />
|
<ChevronDown size={14} />
|
||||||
|
|||||||
@@ -63,13 +63,13 @@ export function Sidebar() {
|
|||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={`flex h-full flex-col transition-all duration-200 ${collapsed ? 'w-20' : 'w-72'}`}>
|
<aside className={`sidebar-shell flex h-full flex-col transition-all duration-200 ${collapsed ? 'w-20' : 'w-72'}`}>
|
||||||
<div className={`flex items-center gap-3 px-4 pt-4 pb-3 ${collapsed ? 'justify-center' : ''}`}>
|
<div className={`flex items-center gap-3 px-4 pt-4 pb-3 ${collapsed ? 'justify-center' : ''}`}>
|
||||||
<Avatar name="Papo" radius="lg" />
|
<div className="brand-mark flex size-10 items-center justify-center rounded-2xl font-black text-white">P</div>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="text-base font-bold">Papo</div>
|
<div className="text-base font-bold">Papo</div>
|
||||||
<div className="text-[10px] uppercase tracking-widest text-default-400">Dashboard</div>
|
<div className="text-[10px] uppercase tracking-widest section-subtle">Dashboard</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -102,7 +102,7 @@ export function Sidebar() {
|
|||||||
{navGroups.map((group) => (
|
{navGroups.map((group) => (
|
||||||
<div key={group.label}>
|
<div key={group.label}>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<div className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-widest text-default-400">
|
<div className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-[0.18em] section-subtle">
|
||||||
{group.label}
|
{group.label}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -114,10 +114,9 @@ export function Sidebar() {
|
|||||||
return (
|
return (
|
||||||
<Tooltip key={item.key} content={collapsed ? item.label : ''} placement="right" offset={8}>
|
<Tooltip key={item.key} content={collapsed ? item.label : ''} placement="right" offset={8}>
|
||||||
<Button
|
<Button
|
||||||
className="h-10 justify-start gap-3 px-3 font-medium"
|
className={`nav-button h-10 justify-start gap-3 px-3 font-medium ${isActive ? 'nav-button-active' : ''}`}
|
||||||
color={isActive ? 'primary' : 'default'}
|
|
||||||
radius="lg"
|
radius="lg"
|
||||||
variant={isActive ? 'solid' : 'flat'}
|
variant="light"
|
||||||
size="sm"
|
size="sm"
|
||||||
startContent={item.icon}
|
startContent={item.icon}
|
||||||
onPress={() => setSection(item.key)}
|
onPress={() => setSection(item.key)}
|
||||||
@@ -133,16 +132,15 @@ export function Sidebar() {
|
|||||||
{user?.isAdmin && (
|
{user?.isAdmin && (
|
||||||
<div>
|
<div>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<div className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-widest text-default-400">
|
<div className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-[0.18em] section-subtle">
|
||||||
Admin
|
Admin
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Tooltip content={collapsed ? 'Admin' : ''} placement="right" offset={8}>
|
<Tooltip content={collapsed ? 'Admin' : ''} placement="right" offset={8}>
|
||||||
<Button
|
<Button
|
||||||
className="h-10 justify-start gap-3 px-3 font-medium"
|
className={`nav-button h-10 justify-start gap-3 px-3 font-medium ${section === 'admin' ? 'nav-button-active' : ''}`}
|
||||||
color={section === 'admin' ? 'warning' : 'default'}
|
|
||||||
radius="lg"
|
radius="lg"
|
||||||
variant={section === 'admin' ? 'solid' : 'flat'}
|
variant="light"
|
||||||
size="sm"
|
size="sm"
|
||||||
startContent={<Wrench size={18} />}
|
startContent={<Wrench size={18} />}
|
||||||
onPress={() => setSection('admin')}
|
onPress={() => setSection('admin')}
|
||||||
@@ -158,26 +156,26 @@ export function Sidebar() {
|
|||||||
<div className="p-3 flex flex-col gap-2">
|
<div className="p-3 flex flex-col gap-2">
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
className="w-full"
|
className="ghost-button w-full"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="bordered"
|
variant="light"
|
||||||
onPress={() => setCollapsed((c) => !c)}
|
onPress={() => setCollapsed((c) => !c)}
|
||||||
>
|
>
|
||||||
{collapsed ? <PanelLeft size={16} /> : <PanelLeftClose size={16} />}
|
{collapsed ? <PanelLeft size={16} /> : <PanelLeftClose size={16} />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardContent className={`flex items-center gap-3 p-2 ${collapsed ? 'justify-center' : ''}`}>
|
<CardContent className={`flex items-center gap-3 p-2 ${collapsed ? 'justify-center' : ''}`}>
|
||||||
<Avatar name={user?.username} size="sm" className="shrink-0" />
|
<Avatar name={user?.username} size="sm" className="shrink-0" />
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<>
|
<>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="truncate text-xs font-semibold">{user?.username}</div>
|
<div className="truncate text-xs font-semibold">{user?.username}</div>
|
||||||
<div className="text-[10px] text-default-400">Angemeldet</div>
|
<div className="text-[10px] section-subtle">Angemeldet</div>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip content="Abmelden" placement="top">
|
<Tooltip content="Abmelden" placement="top">
|
||||||
<Button isIconOnly color="danger" radius="lg" size="sm" variant="flat" onPress={handleLogout}>
|
<Button isIconOnly radius="lg" size="sm" variant="light" className="ghost-button" onPress={handleLogout}>
|
||||||
<LogOut size={14} />
|
<LogOut size={14} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ type Props = {
|
|||||||
|
|
||||||
export function SectionCard({ title, subtitle, children, action }: Props) {
|
export function SectionCard({ title, subtitle, children, action }: Props) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className="surface-card-strong">
|
||||||
<CardHeader className="flex items-start justify-between gap-4">
|
<CardHeader className="flex items-start justify-between gap-4">
|
||||||
<div className="min-w-0 flex flex-col gap-1">
|
<div className="min-w-0 flex flex-col gap-1">
|
||||||
<CardTitle>{title}</CardTitle>
|
<CardTitle>{title}</CardTitle>
|
||||||
{subtitle && <CardDescription>{subtitle}</CardDescription>}
|
{subtitle && <CardDescription className="section-subtle">{subtitle}</CardDescription>}
|
||||||
</div>
|
</div>
|
||||||
{action && <div className="shrink-0">{action}</div>}
|
{action && <div className="shrink-0">{action}</div>}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ export function StatCard({ icon, label, value, trend, color = 'primary' }: Props
|
|||||||
const chipColor = color === 'default' ? 'default' : color;
|
const chipColor = color === 'default' ? 'default' : color;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardContent className="flex flex-col gap-2 p-4">
|
<CardContent className="flex flex-col gap-2 p-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Chip color={chipColor} size="sm" variant="flat" startContent={icon}>
|
<Chip color={chipColor} size="sm" variant="flat" startContent={icon} className={color === 'primary' ? 'accent-chip' : undefined}>
|
||||||
{label}
|
{label}
|
||||||
</Chip>
|
</Chip>
|
||||||
{trend && (
|
{trend && (
|
||||||
@@ -26,7 +26,7 @@ export function StatCard({ icon, label, value, trend, color = 'primary' }: Props
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-2xl font-bold tracking-tight">{value}</div>
|
<div className="text-2xl font-bold tracking-tight">{value}</div>
|
||||||
<div className="text-tiny text-default-500">{label}</div>
|
<div className="text-tiny section-subtle">{label}</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function Dashboard() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<Card>
|
<Card className="surface-card-strong">
|
||||||
<CardContent className="flex flex-col gap-6 xl:flex-row xl:items-center xl:justify-between">
|
<CardContent className="flex flex-col gap-6 xl:flex-row xl:items-center xl:justify-between">
|
||||||
<div className="flex min-w-0 items-center gap-5">
|
<div className="flex min-w-0 items-center gap-5">
|
||||||
<Avatar className="size-20 shrink-0" radius="lg" src={guildIconUrl(selectedGuild)} />
|
<Avatar className="size-20 shrink-0" radius="lg" src={guildIconUrl(selectedGuild)} />
|
||||||
@@ -33,10 +33,10 @@ export function Dashboard() {
|
|||||||
Online
|
Online
|
||||||
</Chip>
|
</Chip>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-small text-default-400">ID: {guildInfo?.id || selectedGuild?.id}</div>
|
<div className="mt-1 text-small section-subtle">ID: {guildInfo?.id || selectedGuild?.id}</div>
|
||||||
<div className="mt-3 flex flex-wrap gap-2">
|
<div className="mt-3 flex flex-wrap gap-2">
|
||||||
{Object.entries(moduleFlags).filter(([, v]) => v).map(([key]) => (
|
{Object.entries(moduleFlags).filter(([, v]) => v).map(([key]) => (
|
||||||
<Chip key={key} color="primary" size="sm" variant="flat">
|
<Chip key={key} size="sm" variant="flat" className="accent-chip">
|
||||||
{key.replace('Enabled', '').replace(/([A-Z])/g, ' $1').trim()}
|
{key.replace('Enabled', '').replace(/([A-Z])/g, ' $1').trim()}
|
||||||
</Chip>
|
</Chip>
|
||||||
))}
|
))}
|
||||||
@@ -44,7 +44,7 @@ export function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 shrink-0">
|
<div className="flex gap-2 shrink-0">
|
||||||
<Chip color="primary" radius="sm" size="sm" variant="flat" startContent={<Gauge size={12} />}>
|
<Chip radius="sm" size="sm" variant="flat" startContent={<Gauge size={12} />} className="accent-chip">
|
||||||
Ping: {guildInfo?.ping || '-'}ms
|
Ping: {guildInfo?.ping || '-'}ms
|
||||||
</Chip>
|
</Chip>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,7 +65,7 @@ export function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-5 xl:grid-cols-2 2xl:grid-cols-3">
|
<div className="grid gap-5 xl:grid-cols-2 2xl:grid-cols-3">
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-bold">Activity Bereich</h2>
|
<h2 className="text-lg font-bold">Activity Bereich</h2>
|
||||||
@@ -80,25 +80,25 @@ export function Dashboard() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader className="flex items-center justify-between">
|
<CardHeader className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-bold">Guild Logs</h2>
|
<h2 className="text-lg font-bold">Guild Logs</h2>
|
||||||
<p className="mt-0.5 text-tiny text-default-400">Letzte Ereignisse</p>
|
<p className="mt-0.5 text-tiny text-default-400">Letzte Ereignisse</p>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" variant="light" endContent={<ChevronRight size={14} />} onPress={() => setSection('settings')}>
|
<Button size="sm" variant="light" className="ghost-button" endContent={<ChevronRight size={14} />} onPress={() => setSection('settings')}>
|
||||||
Alle
|
Alle
|
||||||
</Button>
|
</Button>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ScrollShadow className="max-h-[320px] space-y-2 pr-1" hideScrollBar>
|
<ScrollShadow className="max-h-[320px] space-y-2 pr-1" hideScrollBar>
|
||||||
{logs.length ? logs.slice(0, 15).map((log, i) => (
|
{logs.length ? logs.slice(0, 15).map((log, i) => (
|
||||||
<Card key={`${log.timestamp}-${i}`}>
|
<Card key={`${log.timestamp}-${i}`} className="surface-card-muted">
|
||||||
<CardContent className="flex items-start gap-3 p-3">
|
<CardContent className="flex items-start gap-3 p-3">
|
||||||
<div className={`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-lg ${
|
<div className={`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-lg ${
|
||||||
log.level === 'error' ? 'bg-danger-500/10 text-danger-400' :
|
log.level === 'error' ? 'bg-danger-500/10 text-danger-400' :
|
||||||
log.level === 'warn' ? 'bg-warning-500/10 text-warning-400' :
|
log.level === 'warn' ? 'bg-warning-500/10 text-warning-400' :
|
||||||
'bg-primary-500/10 text-primary-400'
|
'bg-orange-500/10 text-orange-300'
|
||||||
}`}>
|
}`}>
|
||||||
{log.level === 'error' ? <Shield size={12} /> :
|
{log.level === 'error' ? <Shield size={12} /> :
|
||||||
log.level === 'warn' ? <Bell size={12} /> :
|
log.level === 'warn' ? <Bell size={12} /> :
|
||||||
@@ -131,7 +131,7 @@ export function Dashboard() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<h2 className="text-lg font-bold">Quick Actions</h2>
|
<h2 className="text-lg font-bold">Quick Actions</h2>
|
||||||
<p className="mt-0.5 text-tiny text-default-400">Schnellzugriff</p>
|
<p className="mt-0.5 text-tiny text-default-400">Schnellzugriff</p>
|
||||||
@@ -140,10 +140,10 @@ export function Dashboard() {
|
|||||||
{quickActions.map((action) => (
|
{quickActions.map((action) => (
|
||||||
<Button
|
<Button
|
||||||
key={action.key}
|
key={action.key}
|
||||||
className="justify-start font-medium"
|
color="default"
|
||||||
color={action.color}
|
|
||||||
startContent={action.icon}
|
startContent={action.icon}
|
||||||
variant={action.color === 'default' ? 'bordered' : 'solid'}
|
variant="light"
|
||||||
|
className={`justify-start font-medium ${action.color === 'default' ? 'ghost-button' : 'accent-button'}`}
|
||||||
onPress={() => setSection(action.key as any)}
|
onPress={() => setSection(action.key as any)}
|
||||||
>
|
>
|
||||||
{action.label}
|
{action.label}
|
||||||
@@ -157,9 +157,9 @@ export function Dashboard() {
|
|||||||
{(['tickets', 'supportlogin', 'automod', 'welcome', 'birthday', 'reactionroles'] as const).map((key) => {
|
{(['tickets', 'supportlogin', 'automod', 'welcome', 'birthday', 'reactionroles'] as const).map((key) => {
|
||||||
const item = navItemMap[key];
|
const item = navItemMap[key];
|
||||||
return (
|
return (
|
||||||
<Card key={key} isPressable onPress={() => setSection(key)}>
|
<Card key={key} isPressable onPress={() => setSection(key)} className="surface-card">
|
||||||
<CardContent className="flex flex-col items-start gap-2">
|
<CardContent className="flex flex-col items-start gap-2">
|
||||||
<Chip color="primary" size="sm" variant="flat" startContent={item.icon}>
|
<Chip size="sm" variant="flat" startContent={item.icon} className="accent-chip">
|
||||||
{item.label}
|
{item.label}
|
||||||
</Chip>
|
</Chip>
|
||||||
<div className="font-semibold text-sm">{item.label}</div>
|
<div className="font-semibold text-sm">{item.label}</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function ModulesPage() {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
||||||
{activeModules.map((module) => (
|
{activeModules.map((module) => (
|
||||||
<Card key={module.key} className="border border-success-400/25 bg-success-500/5">
|
<Card key={module.key} className="surface-card-strong">
|
||||||
<CardContent className="flex flex-row items-center justify-between gap-4 p-4">
|
<CardContent className="flex flex-row items-center justify-between gap-4 p-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="font-semibold">{module.name}</div>
|
<div className="font-semibold">{module.name}</div>
|
||||||
@@ -28,7 +28,7 @@ export function ModulesPage() {
|
|||||||
<div className="text-small text-default-400 truncate">{module.description}</div>
|
<div className="text-small text-default-400 truncate">{module.description}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Switch isSelected={module.enabled} color="success" onChange={(v) => toggleModule(module.key, v)} />
|
<Switch isSelected={module.enabled} color="warning" onChange={(v) => toggleModule(module.key, v)} />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
@@ -44,7 +44,7 @@ export function ModulesPage() {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
||||||
{inactiveModules.map((module) => (
|
{inactiveModules.map((module) => (
|
||||||
<Card key={module.key} className="border border-default-200/20 bg-default-100/5">
|
<Card key={module.key} className="surface-card">
|
||||||
<CardContent className="flex flex-row items-center justify-between gap-4 p-4">
|
<CardContent className="flex flex-row items-center justify-between gap-4 p-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="font-semibold">{module.name}</div>
|
<div className="font-semibold">{module.name}</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function SupportLogin() {
|
|||||||
return (
|
return (
|
||||||
<SectionCard title="Support Login" subtitle="Login-Panel fuer Supporter konfigurieren">
|
<SectionCard title="Support Login" subtitle="Login-Panel fuer Supporter konfigurieren">
|
||||||
<div className="grid gap-5 xl:grid-cols-[1fr_400px]">
|
<div className="grid gap-5 xl:grid-cols-[1fr_400px]">
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Panel-Konfiguration</CardTitle>
|
<CardTitle>Panel-Konfiguration</CardTitle>
|
||||||
@@ -77,10 +77,10 @@ export function SupportLogin() {
|
|||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button color="primary" startContent={<Save size={16} />} onPress={saveSupportLogin}>
|
<Button variant="light" className="accent-button" startContent={<Save size={16} />} onPress={saveSupportLogin}>
|
||||||
Speichern & Panel senden
|
Speichern & Panel senden
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="bordered" startContent={<Send size={16} />}>
|
<Button variant="light" className="ghost-button" startContent={<Send size={16} />}>
|
||||||
Panel manuell senden
|
Panel manuell senden
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,7 +88,7 @@ export function SupportLogin() {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Live Vorschau</CardTitle>
|
<CardTitle>Live Vorschau</CardTitle>
|
||||||
@@ -96,10 +96,10 @@ export function SupportLogin() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Card>
|
<Card className="surface-card-muted">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<LogIn size={16} />
|
<LogIn size={16} className="accent-text" />
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>{supportLogin?.config?.title || 'Support Login'}</CardTitle>
|
<CardTitle>{supportLogin?.config?.title || 'Support Login'}</CardTitle>
|
||||||
<CardDescription>{supportLogin?.config?.description || 'Melde dich als Support an/ab.'}</CardDescription>
|
<CardDescription>{supportLogin?.config?.description || 'Melde dich als Support an/ab.'}</CardDescription>
|
||||||
@@ -107,14 +107,14 @@ export function SupportLogin() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex gap-2">
|
<CardContent className="flex gap-2">
|
||||||
<Button size="sm" color="primary">{supportLogin?.config?.loginLabel || 'Login'}</Button>
|
<Button size="sm" variant="light" className="accent-button">{supportLogin?.config?.loginLabel || 'Login'}</Button>
|
||||||
<Button size="sm" variant="bordered">{supportLogin?.config?.logoutLabel || 'Logout'}</Button>
|
<Button size="sm" variant="light" className="ghost-button">{supportLogin?.config?.logoutLabel || 'Logout'}</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Aktive Supporter</CardTitle>
|
<CardTitle>Aktive Supporter</CardTitle>
|
||||||
@@ -123,7 +123,7 @@ export function SupportLogin() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex flex-col gap-2">
|
<CardContent className="flex flex-col gap-2">
|
||||||
{supportLogin?.status?.active?.length ? supportLogin.status.active.map((s, i) => (
|
{supportLogin?.status?.active?.length ? supportLogin.status.active.map((s, i) => (
|
||||||
<Card key={i}>
|
<Card key={i} className="surface-card-muted">
|
||||||
<CardContent className="flex items-center gap-3">
|
<CardContent className="flex items-center gap-3">
|
||||||
<Avatar name={s.username?.[0]} size="sm" className="size-6" />
|
<Avatar name={s.username?.[0]} size="sm" className="size-6" />
|
||||||
<span className="font-medium">{s.username || s.userId}</span>
|
<span className="font-medium">{s.username || s.userId}</span>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function Welcome() {
|
|||||||
return (
|
return (
|
||||||
<SectionCard title="Willkommen" subtitle="Welcome-Embeds und Join-Nachrichten">
|
<SectionCard title="Willkommen" subtitle="Welcome-Embeds und Join-Nachrichten">
|
||||||
<div className="grid gap-5 xl:grid-cols-2">
|
<div className="grid gap-5 xl:grid-cols-2">
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Welcome konfigurieren</CardTitle>
|
<CardTitle>Welcome konfigurieren</CardTitle>
|
||||||
@@ -66,13 +66,13 @@ export function Welcome() {
|
|||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<Button color="primary" size="lg" startContent={<Save size={16} />} onPress={() => saveSettingsPayload({ welcomeConfig: settings.welcomeConfig || {} }, 'Welcome gespeichert')}>
|
<Button size="lg" variant="light" className="accent-button" startContent={<Save size={16} />} onPress={() => saveSettingsPayload({ welcomeConfig: settings.welcomeConfig || {} }, 'Welcome gespeichert')}>
|
||||||
Speichern
|
Speichern
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="surface-card">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Live Vorschau</CardTitle>
|
<CardTitle>Live Vorschau</CardTitle>
|
||||||
@@ -80,22 +80,22 @@ export function Welcome() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex flex-col gap-4">
|
<CardContent className="flex flex-col gap-4">
|
||||||
<Card>
|
<Card className="surface-card-muted">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Sparkles size={16} />
|
<Sparkles size={16} className="accent-text" />
|
||||||
<CardTitle>{settings.welcomeConfig?.embedTitle || 'Willkommen!'}</CardTitle>
|
<CardTitle>{settings.welcomeConfig?.embedTitle || 'Willkommen!'}</CardTitle>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<p className="text-default-700 dark:text-default-300">{settings.welcomeConfig?.embedDescription || 'Willkommen auf dem Server!'}</p>
|
<p className="text-default-700 dark:text-default-300">{settings.welcomeConfig?.embedDescription || 'Willkommen auf dem Server!'}</p>
|
||||||
{settings.welcomeConfig?.embedFooter && (
|
{settings.welcomeConfig?.embedFooter && (
|
||||||
<p className="text-small text-default-500">{settings.welcomeConfig.embedFooter}</p>
|
<p className="text-small section-subtle">{settings.welcomeConfig.embedFooter}</p>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<p className="text-small text-default-500">
|
<p className="text-small section-subtle">
|
||||||
Nutze {'{user}'} fuer den Benutzernamen und {'{server}'} fuer den Servernamen.
|
Nutze {'{user}'} fuer den Benutzernamen und {'{server}'} fuer den Servernamen.
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user