feat(ui): Platzhalter beim Laden und ordentliche Leerzustände

Beim Laden stand ein Kreisel in der Mitte. Der sagt „warte", aber nicht,
worauf – und wenn die Daten kommen, klappt das Layout um. Jetzt steht dort ein
Platzhalter in der Form des Kommenden: Kacheln in der Kachelansicht, Zeilen in
der Liste. Die Maße sind aus FileViews.tsx abgeschrieben, nicht geschätzt;
weichen sie ab, springt es beim Wechsel wieder und der Zweck wäre dahin.

Leerzustände sagen jetzt, warum nichts da ist, und bieten den Knopf an, der an
dieser Stelle weiterhilft. Der leere Papierkorb bekommt bewusst keinen: Er ist
ein guter Zustand, kein Mangel, und ein Knopf, der nur da ist damit einer da
ist, führt nirgendwohin.

Beides respektiert prefers-reduced-motion.

Nebenbei gefunden: `@keyframes spin` lag als Inline-<style> in **sechs**
Komponenten, und zwei Nutzer (AuditTab, SearchBox) hatten gar keine eigene
Kopie. Dass es lief, war Zufall – @keyframes gilt fürs ganze Dokument, es
genügte also, dass irgendeine der sechs gerade im Bild war. Kaputt wäre es an
dem Tag gewesen, an dem jemand die letzte Kopie entfernt. Steht jetzt einmal
in index.css.

Nicht angefasst: der Sprachmix. CalendarPage ist durchgehend deutsch, die
übrige Oberfläche englisch, betroffen sind sechs Dateien. Eine halbe
Übersetzung wäre schlimmer als keine – das gehört in einem Zug gemacht, samt
der Entscheidung, welche Sprache die Oberfläche spricht. In TESTING.md notiert.

Geprüft: tsc sauber, 41 Vitest-Tests, alle 234 Prüfungen der sieben
Selbsttest-Suiten grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-18 16:33:25 +02:00
1 parent 94a803bf7a
commit 1d10c6bd0e
13 files changed
+281 -57

No files matched your search

+13 -2
View File
@@ -18,6 +18,8 @@ import {
import { useEventDrag } from '../components/calendar/useEventDrag'
import { TrashIcon, RenameIcon, DownloadIcon, PeopleIcon } from '../components/icons'
import ShareWithDialog from '../components/ShareWithDialog'
import { SkeletonRows } from '../components/Skeleton'
import EmptyState from '../components/EmptyState'
type ViewMode = 'month' | 'week' | 'list'
@@ -339,7 +341,10 @@ export default function CalendarPage() {
: 'Alle Termine'
if (loading) {
return <div style={{ padding: 24, color: 'var(--color-text-muted)' }}>Lädt…</div>
// Deutsch, wie der Rest dieser Seite. Sie fällt damit aus der sonst
// englischen Oberfläche heraus – das ist bekannt und gehört in einem
// Zug erledigt, nicht halb.
return <div className="aether-content"><SkeletonRows /></div>
}
return (
@@ -991,7 +996,13 @@ function ListAgenda({ events, onEventClick, onEventDown }: {
}, [events])
if (groups.length === 0) {
return <p style={{ padding: 24, color: 'var(--color-text-muted)', fontSize: 13 }}>Keine Termine.</p>
return (
<EmptyState
icon="📅"
title="Keine Termine"
hint="In diesem Zeitraum steht nichts an."
/>
)
}
const today = new Date()