feat: vollständiges Dashboard-Redesign mit HeroUI - monolithische App.tsx aufgelöst, 16 Seiten, Context-API, collapsible Sidebar, neues Dashboard-Layout
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
This commit is contained in:
77
frontend/src/pages/ReactionRoles.tsx
Normal file
77
frontend/src/pages/ReactionRoles.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Card, CardContent, CardHeader, Input, TextArea, Button, Chip, Separator } from '@heroui/react';
|
||||
import { Tag, Save, Hash, List } from 'lucide-react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
import { SectionCard } from '../components/shared/SectionCard';
|
||||
|
||||
export function ReactionRoles() {
|
||||
const { reactionRoles, reactionDraft, setReactionDraft, saveReactionRole } = useApp();
|
||||
|
||||
return (
|
||||
<SectionCard title="Reaction Roles" subtitle="Sets anzeigen und neue Zuordnungen anlegen">
|
||||
<div className="grid gap-5 xl:grid-cols-[1fr_420px]">
|
||||
<div>
|
||||
<h3 className="mb-3 text-base font-semibold">Bestehende Sets ({reactionRoles.length})</h3>
|
||||
<div className="space-y-3">
|
||||
{reactionRoles.length ? reactionRoles.map((set, i) => (
|
||||
<Card key={set.id || i} className="border border-default-100 bg-default-50/20">
|
||||
<CardContent className="flex items-center gap-3 p-4">
|
||||
<div className="flex size-10 items-center justify-center rounded-xl bg-primary-500/10 text-primary-400">
|
||||
<Tag size={18} />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-semibold text-small truncate">{set.title || 'Reaction Role'}</div>
|
||||
<div className="text-tiny text-default-400 truncate">Channel: {set.channelId || '-'}</div>
|
||||
</div>
|
||||
<Chip size="sm" variant="flat">{(set.entries?.length || 0)} Eintr<EFBFBD>ge</Chip>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)) : (
|
||||
<div className="flex flex-col items-center gap-2 py-8 text-center text-small text-default-400">
|
||||
<Tag size={24} />
|
||||
Keine Sets
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card className="border border-default-100 bg-default-50/20">
|
||||
<CardHeader className="px-5 pt-5 pb-0">
|
||||
<h3 className="text-base font-semibold">Neues Set</h3>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4 p-5">
|
||||
<Input
|
||||
label="Titel"
|
||||
placeholder="Rollenauswahl"
|
||||
value={reactionDraft.title}
|
||||
onValueChange={(v) => setReactionDraft((s) => ({ ...s, title: v }))}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Channel ID"
|
||||
placeholder="Channel f<>r die Nachricht"
|
||||
value={reactionDraft.channelId}
|
||||
onValueChange={(v) => setReactionDraft((s) => ({ ...s, channelId: v }))}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label className="block text-small font-medium mb-1">Eintr<EFBFBD>ge</label>
|
||||
<TextArea
|
||||
placeholder="Emoji | Role ID | Label :emoji: | 123456789 | Rolle 1 :wave: | 987654321 | Rolle 2"
|
||||
minRows={6}
|
||||
value={reactionDraft.entries}
|
||||
onValueChange={(v) => setReactionDraft((s) => ({ ...s, entries: v }))}
|
||||
/>
|
||||
<p className="mt-1 text-tiny text-default-400">
|
||||
Pro Zeile: Emoji | Role ID | Label (optional) | Beschreibung (optional)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button color="primary" startContent={<Save size={16} />} onPress={saveReactionRole}>
|
||||
Reaction Role speichern
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</SectionCard>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user