fix(ui): Tabs filtern korrekt nach Folder; Soundzähler als Badge im Header

This commit is contained in:
vibe-bot 2025-08-08 02:44:08 +02:00
parent 7920fa7abe
commit 0553fd5892
3 changed files with 12 additions and 10 deletions

View file

@ -50,9 +50,13 @@ export default function App() {
const filtered = useMemo(() => {
const q = query.trim().toLowerCase();
if (!q) return sounds;
return sounds.filter((s) => s.name.toLowerCase().includes(q));
}, [sounds, query]);
let base = sounds;
if (activeFolder !== '__all__') {
base = sounds.filter((s: any) => (activeFolder === '' ? !s.folder : s.folder === activeFolder));
}
if (!q) return base;
return base.filter((s) => s.name.toLowerCase().includes(q));
}, [sounds, query, activeFolder]);
async function handlePlay(name: string, rel?: string) {
setError(null);
@ -73,6 +77,7 @@ export default function App() {
<header>
<h1>Discord Soundboard</h1>
<p>Schicke dem Bot per privater Nachricht eine .mp3 neue Sounds erscheinen automatisch.</p>
<div className="badge">Geladene Sounds: {total}</div>
</header>
<section className="controls">
@ -145,7 +150,7 @@ export default function App() {
))}
{filtered.length === 0 && <div className="hint">Keine Sounds gefunden.</div>}
</section>
<div className="footer-info">Geladene Sounds: {total}</div>
{/* footer counter entfällt, da oben sichtbar */}
</div>
);
}

View file

@ -5,7 +5,7 @@ const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
export async function fetchSounds(q?: string, folderKey?: string): Promise<SoundsResponse> {
const url = new URL(`${API_BASE}/sounds`, window.location.origin);
if (q) url.searchParams.set('q', q);
if (folderKey) url.searchParams.set('folder', folderKey);
if (folderKey !== undefined) url.searchParams.set('folder', folderKey);
const res = await fetch(url.toString());
if (!res.ok) throw new Error('Fehler beim Laden der Sounds');
return res.json();

View file

@ -14,6 +14,7 @@ body {
header { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
header h1 { margin: 0; font-weight: 800; letter-spacing: .3px; }
header p { opacity: .8; }
.badge { align-self: flex-start; background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.18); padding: 6px 10px; border-radius: 999px; font-size: 13px; }
.controls { display: grid; grid-template-columns: 1fr minmax(240px, 300px) 220px; gap: 12px; align-items: center; margin-bottom: 18px; }
.control input, .control select {
@ -49,11 +50,7 @@ header p { opacity: .8; }
.hint { opacity: .7; padding: 24px 0; }
.footer-info {
margin-top: 14px;
opacity: .8;
font-size: 14px;
}
/* footer-info entfernt */
.tabs { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.tab {