fix: HeroUI v3 compound API (Card.Content/Card.Header) + @heroui/styles CSS import
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled

This commit is contained in:
Pepe44DEV
2026-07-01 04:34:39 +02:00
parent 2a116d4182
commit e9b0f25d71
3 changed files with 52 additions and 50 deletions

View File

@@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@heroui/react": "^3.2.1", "@heroui/react": "^3.2.1",
"@heroui/styles": "^3.2.1",
"framer-motion": "^12.23.24", "framer-motion": "^12.23.24",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"react": "^19.2.0", "react": "^19.2.0",

View File

@@ -2,8 +2,6 @@ import {
Avatar, Avatar,
Button, Button,
Card, Card,
CardContent,
CardHeader,
Chip, Chip,
Input, Input,
Spinner, Spinner,
@@ -504,13 +502,13 @@ function App() {
className="papo-card" className="papo-card"
onPress={() => setCurrentGuildId(guild.id)} onPress={() => setCurrentGuildId(guild.id)}
> >
<CardContent className="flex flex-row items-center gap-4 p-5"> <Card.Content className="flex flex-row items-center gap-4 p-5">
<Avatar src={guildIconUrl(guild)} name={guild.name} radius="lg" /> <Avatar src={guildIconUrl(guild)} name={guild.name} radius="lg" />
<div> <div>
<div className="text-lg font-semibold">{guild.name}</div> <div className="text-lg font-semibold">{guild.name}</div>
<div className="text-sm text-white/50">ID: {guild.id}</div> <div className="text-sm text-white/50">ID: {guild.id}</div>
</div> </div>
</CardContent> </Card.Content>
</Card> </Card>
))} ))}
</div> </div>
@@ -550,7 +548,7 @@ function App() {
</div> </div>
<Card className="papo-card mt-auto"> <Card className="papo-card mt-auto">
<CardContent className="gap-3 p-4"> <Card.Content className="gap-3 p-4">
<div className="text-xs uppercase tracking-[0.18em] text-white/45">Angemeldet als</div> <div className="text-xs uppercase tracking-[0.18em] text-white/45">Angemeldet als</div>
<div className="font-semibold"> <div className="font-semibold">
{user?.username} {user?.username}
@@ -567,14 +565,14 @@ function App() {
> >
Logout Logout
</Button> </Button>
</CardContent> </Card.Content>
</Card> </Card>
</aside> </aside>
<main className="px-4 py-6 md:px-8"> <main className="px-4 py-6 md:px-8">
<div className="mx-auto max-w-[1520px]"> <div className="mx-auto max-w-[1520px]">
<Card className="papo-card mb-5"> <Card className="papo-card mb-5">
<CardContent className="flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between"> <Card.Content className="flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between">
<div> <div>
<h1 className="papo-section-title">Guild Dashboard</h1> <h1 className="papo-section-title">Guild Dashboard</h1>
<p className="papo-section-subtitle">Komplettes HeroUI-Rework fuer dein Bot-Dashboard</p> <p className="papo-section-subtitle">Komplettes HeroUI-Rework fuer dein Bot-Dashboard</p>
@@ -596,13 +594,13 @@ function App() {
</label> </label>
{statusMessage ? <div className="mt-2 text-sm text-warning-300">{statusMessage}</div> : null} {statusMessage ? <div className="mt-2 text-sm text-warning-300">{statusMessage}</div> : null}
</div> </div>
</CardContent> </Card.Content>
</Card> </Card>
{section === 'overview' && ( {section === 'overview' && (
<div className="space-y-5"> <div className="space-y-5">
<Card className="papo-card"> <Card className="papo-card">
<CardContent className="flex flex-col gap-5 p-5 xl:flex-row xl:items-center xl:justify-between"> <Card.Content className="flex flex-col gap-5 p-5 xl:flex-row xl:items-center xl:justify-between">
<div className="flex min-w-0 items-center gap-4"> <div className="flex min-w-0 items-center gap-4">
<Avatar className="h-20 w-20" radius="lg" src={guildIconUrl(selectedGuild)} /> <Avatar className="h-20 w-20" radius="lg" src={guildIconUrl(selectedGuild)} />
<div className="min-w-0"> <div className="min-w-0">
@@ -625,7 +623,7 @@ function App() {
> >
Bot aktiv Bot aktiv
</Chip> </Chip>
</CardContent> </Card.Content>
</Card> </Card>
<div className="grid gap-5 xl:grid-cols-[1.05fr_1.05fr_1fr]"> <div className="grid gap-5 xl:grid-cols-[1.05fr_1.05fr_1fr]">
@@ -644,24 +642,24 @@ function App() {
/> />
<Card className="papo-card"> <Card className="papo-card">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div> <div>
<h2 className="text-2xl font-bold">Activity</h2> <h2 className="text-2xl font-bold">Activity</h2>
<p className="mt-1 text-sm text-white/50">Live-Statistiken aus deinem Bot</p> <p className="mt-1 text-sm text-white/50">Live-Statistiken aus deinem Bot</p>
</div> </div>
</CardHeader> </Card.Header>
<CardContent className="gap-3 p-5"> <Card.Content className="gap-3 p-5">
<ActivityTile icon={<MessageSquare size={18} />} kind="messages" label="Messages (24h)" value={activity?.messages24h ?? 0} /> <ActivityTile icon={<MessageSquare size={18} />} kind="messages" label="Messages (24h)" value={activity?.messages24h ?? 0} />
<ActivityTile icon={<Command size={18} />} kind="commands" label="Commands (24h)" value={activity?.commands24h ?? 0} /> <ActivityTile icon={<Command size={18} />} kind="commands" label="Commands (24h)" value={activity?.commands24h ?? 0} />
<ActivityTile icon={<Shield size={18} />} kind="automod" label="Automod (24h)" value={activity?.automod24h ?? 0} /> <ActivityTile icon={<Shield size={18} />} kind="automod" label="Automod (24h)" value={activity?.automod24h ?? 0} />
<Button className="mt-2 justify-between" endContent={<ChevronRight size={16} />} variant="bordered" onPress={() => setSection('settings')}> <Button className="mt-2 justify-between" endContent={<ChevronRight size={16} />} variant="bordered" onPress={() => setSection('settings')}>
Alle Logs anzeigen Alle Logs anzeigen
</Button> </Button>
</CardContent> </Card.Content>
</Card> </Card>
<Card className="papo-card"> <Card className="papo-card">
<CardHeader className="flex items-center justify-between px-5 pt-5 pb-0"> <Card.Header className="flex items-center justify-between px-5 pt-5 pb-0">
<div> <div>
<h2 className="text-2xl font-bold">Guild Logs</h2> <h2 className="text-2xl font-bold">Guild Logs</h2>
<p className="mt-1 text-sm text-white/50">Neueste Ereignisse</p> <p className="mt-1 text-sm text-white/50">Neueste Ereignisse</p>
@@ -669,13 +667,13 @@ function App() {
<Button endContent={<ChevronRight size={16} />} size="sm" variant="light" onPress={() => setSection('settings')}> <Button endContent={<ChevronRight size={16} />} size="sm" variant="light" onPress={() => setSection('settings')}>
Alle anzeigen Alle anzeigen
</Button> </Button>
</CardHeader> </Card.Header>
<CardContent className="p-5"> <Card.Content className="p-5">
<div className="papo-scroll max-h-[360px] space-y-3 overflow-auto pr-2"> <div className="papo-scroll max-h-[360px] space-y-3 overflow-auto pr-2">
{logs.length ? ( {logs.length ? (
logs.map((log, index) => ( logs.map((log, index) => (
<Card key={`${log.timestamp}-${index}`} className="border border-white/5 bg-white/[0.03]"> <Card key={`${log.timestamp}-${index}`} className="border border-white/5 bg-white/[0.03]">
<CardContent className="gap-2 p-4"> <Card.Content className="gap-2 p-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Chip color={log.level === 'warn' ? 'warning' : log.level === 'error' ? 'danger' : 'default'} size="sm" variant="bordered"> <Chip color={log.level === 'warn' ? 'warning' : log.level === 'error' ? 'danger' : 'default'} size="sm" variant="bordered">
{(log.level || 'info').toUpperCase()} {(log.level || 'info').toUpperCase()}
@@ -683,38 +681,38 @@ function App() {
<span className="text-xs text-white/45">{formatDate(log.timestamp)}</span> <span className="text-xs text-white/45">{formatDate(log.timestamp)}</span>
</div> </div>
<div className="text-sm text-white/80">{log.category ? `[${log.category}] ` : ''}{log.message || '-'}</div> <div className="text-sm text-white/80">{log.category ? `[${log.category}] ` : ''}{log.message || '-'}</div>
</CardContent> </Card.Content>
</Card> </Card>
)) ))
) : ( ) : (
<div className="text-sm text-white/45">Keine Logs</div> <div className="text-sm text-white/45">Keine Logs</div>
)} )}
</div> </div>
</CardContent> </Card.Content>
</Card> </Card>
</div> </div>
<Card className="papo-card"> <Card className="papo-card">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div> <div>
<h2 className="text-2xl font-bold">Schnellzugriff</h2> <h2 className="text-2xl font-bold">Schnellzugriff</h2>
<p className="mt-1 text-sm text-white/50">Die wichtigsten Bereiche deines Dashboards</p> <p className="mt-1 text-sm text-white/50">Die wichtigsten Bereiche deines Dashboards</p>
</div> </div>
</CardHeader> </Card.Header>
<CardContent className="grid gap-4 p-5 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-6"> <Card.Content className="grid gap-4 p-5 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-6">
{navItems {navItems
.filter((item) => !['overview', 'admin'].includes(item.key)) .filter((item) => !['overview', 'admin'].includes(item.key))
.slice(0, 6) .slice(0, 6)
.map((item) => ( .map((item) => (
<Card key={item.key} isPressable className="border border-white/6 bg-white/[0.03]" onPress={() => setSection(item.key)}> <Card key={item.key} isPressable className="border border-white/6 bg-white/[0.03]" onPress={() => setSection(item.key)}>
<CardContent className="gap-3 p-4"> <Card.Content className="gap-3 p-4">
<div className="papo-icon-badge">{item.icon}</div> <div className="papo-icon-badge">{item.icon}</div>
<div className="font-semibold">{item.label}</div> <div className="font-semibold">{item.label}</div>
<div className="text-sm text-white/45">HeroUI-Komponenten fuer den Bereich {item.label}</div> <div className="text-sm text-white/45">HeroUI-Komponenten fuer den Bereich {item.label}</div>
</CardContent> </Card.Content>
</Card> </Card>
))} ))}
</CardContent> </Card.Content>
</Card> </Card>
</div> </div>
)} )}
@@ -914,13 +912,13 @@ function App() {
<div className="grid gap-3 xl:grid-cols-2"> <div className="grid gap-3 xl:grid-cols-2">
{modules.map((module) => ( {modules.map((module) => (
<Card key={module.key} className="border border-white/6 bg-white/[0.03]"> <Card key={module.key} className="border border-white/6 bg-white/[0.03]">
<CardContent className="flex flex-row items-center justify-between gap-4 p-4"> <Card.Content className="flex flex-row items-center justify-between gap-4 p-4">
<div> <div>
<div className="font-semibold">{module.name}</div> <div className="font-semibold">{module.name}</div>
<div className="text-sm text-white/45">{module.description || ''}</div> <div className="text-sm text-white/45">{module.description || ''}</div>
</div> </div>
<Switch isSelected={module.enabled} onValueChange={(value) => void toggleModule(module.key, value)} /> <Switch isSelected={module.enabled} onValueChange={(value) => void toggleModule(module.key, value)} />
</CardContent> </Card.Content>
</Card> </Card>
))} ))}
</div> </div>
@@ -933,14 +931,14 @@ function App() {
<div className="space-y-3"> <div className="space-y-3">
{(events || []).map((event) => ( {(events || []).map((event) => (
<Card key={event.id} className="border border-white/6 bg-white/[0.03]"> <Card key={event.id} className="border border-white/6 bg-white/[0.03]">
<CardContent className="gap-2 p-4"> <Card.Content className="gap-2 p-4">
<div className="flex items-center justify-between gap-3"> <div className="flex items-center justify-between gap-3">
<div className="font-semibold">{event.title}</div> <div className="font-semibold">{event.title}</div>
<Button color="danger" size="sm" variant="flat" onPress={() => deleteEvent(event.id)}>Löschen</Button> <Button color="danger" size="sm" variant="flat" onPress={() => deleteEvent(event.id)}>Löschen</Button>
</div> </div>
<div className="text-sm text-white/45">{event.description || 'Keine Beschreibung'}</div> <div className="text-sm text-white/45">{event.description || 'Keine Beschreibung'}</div>
<div className="text-xs text-white/35">{formatDate(event.startsAt)}</div> <div className="text-xs text-white/35">{formatDate(event.startsAt)}</div>
</CardContent> </Card.Content>
</Card> </Card>
))} ))}
</div> </div>
@@ -973,13 +971,13 @@ function App() {
function SectionCard(props: { title: string; subtitle: string; children: React.ReactNode }) { function SectionCard(props: { title: string; subtitle: string; children: React.ReactNode }) {
return ( return (
<Card className="papo-card"> <Card className="papo-card">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div> <div>
<h2 className="text-2xl font-bold">{props.title}</h2> <h2 className="text-2xl font-bold">{props.title}</h2>
<p className="mt-1 text-sm text-white/50">{props.subtitle}</p> <p className="mt-1 text-sm text-white/50">{props.subtitle}</p>
</div> </div>
</CardHeader> </Card.Header>
<CardContent className="p-5">{props.children}</CardContent> <Card.Content className="p-5">{props.children}</Card.Content>
</Card> </Card>
); );
} }
@@ -987,10 +985,10 @@ function SectionCard(props: { title: string; subtitle: string; children: React.R
function FormCard(props: { title: string; children: React.ReactNode }) { function FormCard(props: { title: string; children: React.ReactNode }) {
return ( return (
<Card className="border border-white/6 bg-white/[0.03]"> <Card className="border border-white/6 bg-white/[0.03]">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div className="text-lg font-semibold">{props.title}</div> <div className="text-lg font-semibold">{props.title}</div>
</CardHeader> </Card.Header>
<CardContent className="gap-4 p-5">{props.children}</CardContent> <Card.Content className="gap-4 p-5">{props.children}</Card.Content>
</Card> </Card>
); );
} }
@@ -998,14 +996,14 @@ function FormCard(props: { title: string; children: React.ReactNode }) {
function ListCard(props: { title: string; items: string[] }) { function ListCard(props: { title: string; items: string[] }) {
return ( return (
<Card className="border border-white/6 bg-white/[0.03]"> <Card className="border border-white/6 bg-white/[0.03]">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div className="text-lg font-semibold">{props.title}</div> <div className="text-lg font-semibold">{props.title}</div>
</CardHeader> </Card.Header>
<CardContent className="p-5"> <Card.Content className="p-5">
<div className="papo-scroll max-h-[460px] space-y-3 overflow-auto pr-1"> <div className="papo-scroll max-h-[460px] space-y-3 overflow-auto pr-1">
{props.items.length ? props.items.map((item, index) => <div key={`${item}-${index}`} className="rounded-xl border border-white/6 bg-white/[0.02] px-4 py-3 text-sm text-white/75">{item}</div>) : <div className="text-sm text-white/45">Keine Daten</div>} {props.items.length ? props.items.map((item, index) => <div key={`${item}-${index}`} className="rounded-xl border border-white/6 bg-white/[0.02] px-4 py-3 text-sm text-white/75">{item}</div>) : <div className="text-sm text-white/45">Keine Daten</div>}
</div> </div>
</CardContent> </Card.Content>
</Card> </Card>
); );
} }
@@ -1013,30 +1011,30 @@ function ListCard(props: { title: string; items: string[] }) {
function InfoPanel(props: { title: string; items: Array<{ icon: React.ReactNode; label: string; value: string }>; actionLabel: string; onAction: () => void }) { function InfoPanel(props: { title: string; items: Array<{ icon: React.ReactNode; label: string; value: string }>; actionLabel: string; onAction: () => void }) {
return ( return (
<Card className="papo-card"> <Card className="papo-card">
<CardHeader className="px-5 pt-5 pb-0"> <Card.Header className="px-5 pt-5 pb-0">
<div> <div>
<h2 className="text-2xl font-bold">{props.title}</h2> <h2 className="text-2xl font-bold">{props.title}</h2>
<p className="mt-1 text-sm text-white/50">Wichtige Guild-Daten auf einen Blick</p> <p className="mt-1 text-sm text-white/50">Wichtige Guild-Daten auf einen Blick</p>
</div> </div>
</CardHeader> </Card.Header>
<CardContent className="gap-4 p-5"> <Card.Content className="gap-4 p-5">
<div className="grid gap-3 md:grid-cols-2"> <div className="grid gap-3 md:grid-cols-2">
{props.items.map((item) => ( {props.items.map((item) => (
<Card key={item.label} className="border border-white/6 bg-white/[0.03]"> <Card key={item.label} className="border border-white/6 bg-white/[0.03]">
<CardContent className="gap-3 p-4"> <Card.Content className="gap-3 p-4">
<div className="flex items-center gap-2 text-sm uppercase tracking-[0.14em] text-white/45"> <div className="flex items-center gap-2 text-sm uppercase tracking-[0.14em] text-white/45">
<span className="text-warning-300">{item.icon}</span> <span className="text-warning-300">{item.icon}</span>
{item.label} {item.label}
</div> </div>
<div className="text-xl font-bold">{item.value}</div> <div className="text-xl font-bold">{item.value}</div>
</CardContent> </Card.Content>
</Card> </Card>
))} ))}
</div> </div>
<Button className="justify-between" endContent={<ChevronRight size={16} />} variant="bordered" onPress={props.onAction}> <Button className="justify-between" endContent={<ChevronRight size={16} />} variant="bordered" onPress={props.onAction}>
{props.actionLabel} {props.actionLabel}
</Button> </Button>
</CardContent> </Card.Content>
</Card> </Card>
); );
} }
@@ -1044,7 +1042,7 @@ function InfoPanel(props: { title: string; items: Array<{ icon: React.ReactNode;
function ActivityTile(props: { icon: React.ReactNode; label: string; value: number; kind: 'messages' | 'commands' | 'automod' }) { function ActivityTile(props: { icon: React.ReactNode; label: string; value: number; kind: 'messages' | 'commands' | 'automod' }) {
return ( return (
<Card className="border border-white/6 bg-white/[0.03]"> <Card className="border border-white/6 bg-white/[0.03]">
<CardContent className="flex flex-row items-center justify-between gap-4 p-4"> <Card.Content className="flex flex-row items-center justify-between gap-4 p-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="papo-icon-badge">{props.icon}</div> <div className="papo-icon-badge">{props.icon}</div>
<div> <div>
@@ -1055,7 +1053,7 @@ function ActivityTile(props: { icon: React.ReactNode; label: string; value: numb
<svg className="papo-chart" viewBox="0 0 120 40"> <svg className="papo-chart" viewBox="0 0 120 40">
<path d={sparkPath(props.kind)} stroke={chartColor(props.kind)} /> <path d={sparkPath(props.kind)} stroke={chartColor(props.kind)} />
</svg> </svg>
</CardContent> </Card.Content>
</Card> </Card>
); );
} }
@@ -1072,13 +1070,13 @@ function SettingsLayout(props: { title: string; subtitle: string; children: Reac
</Button> </Button>
</FormCard> </FormCard>
<Card className="border border-white/6 bg-white/[0.03]"> <Card className="border border-white/6 bg-white/[0.03]">
<CardContent className="items-start gap-4 p-5"> <Card.Content className="items-start gap-4 p-5">
<div className="text-lg font-semibold">Design-Richtung</div> <div className="text-lg font-semibold">Design-Richtung</div>
<p className="text-sm text-white/55"> <p className="text-sm text-white/55">
Dieser Bereich nutzt jetzt dieselbe HeroUI-Oberfläche wie dein Overview-Dashboard. Dieser Bereich nutzt jetzt dieselbe HeroUI-Oberfläche wie dein Overview-Dashboard.
Die tieferen Spezial-Workflows aus dem alten Inline-Dashboard werden hier schrittweise in echte React-Komponenten überführt. Die tieferen Spezial-Workflows aus dem alten Inline-Dashboard werden hier schrittweise in echte React-Komponenten überführt.
</p> </p>
</CardContent> </Card.Content>
</Card> </Card>
</div> </div>
</SectionCard> </SectionCard>

View File

@@ -1,4 +1,7 @@
@import "tailwindcss"; @import "tailwindcss";
@import "@heroui/styles";
@custom-variant dark (&:is(.dark *));
:root { :root {
color-scheme: dark; color-scheme: dark;