fix(ui): Platzhalter blitzt auch beim Tab-Wechsel nicht mehr auf

Die Frist von 220 ms galt nur beim Wechsel *innerhalb* der Dateiansicht. Beim
Wechsel zwischen den Menüpunkten entsteht die Seite jedes Mal neu – damit war
jeder Tab-Wechsel ein „erstes Laden", und genau dort war die Regel „beim ersten
Mal sofort zeigen" falsch herum. Die Frist gilt jetzt immer; 220 ms Leere ist
das ruhigere Bild, man kommt ohnehin von einer anderen Seite.

Als gemeinsamer Haken `useSkeleton`, statt die Logik in fünf Seiten zu
wiederholen.

Dabei wäre beinahe ein schlimmerer Geist entstanden: Im Wartefenster hat kurz
der **Leerzustand** aufgeblitzt – „Nothing shared with you yet", eine
Zehntelsekunde bevor die Liste kam. Der Platzhalter sieht nur nach Daten aus,
ein Satz behauptet etwas. Das Wartefenster bleibt jetzt überall leer.

Dazu drei Reste der Kalender-Übersetzung, die mein Suchmuster übersehen hatte,
weil sie in Template-Strings standen: der Löschen-Dialog des Kalenders und der
Wochentag-Hinweis im Terminfenster. Und das Datum in der Listenansicht stand
noch im deutschen Format („18. September 2026") in einer englischen
Oberfläche – jetzt „September 18, 2026".

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 20:15:45 +02:00
1 parent 0591a40d12
commit 4208676aa9
8 files changed
+58 -45

No files matched your search

+5 -4
View File
@@ -18,7 +18,7 @@ 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 { SkeletonRows, useSkeleton } from '../components/Skeleton'
import EmptyState from '../components/EmptyState'
type ViewMode = 'month' | 'week' | 'list'
@@ -104,6 +104,7 @@ export default function CalendarPage() {
const [viewMode, setViewMode] = useState<ViewMode>('month')
const [cursor, setCursor] = useState(new Date())
const [loading, setLoading] = useState(true)
const zeigeSkelett = useSkeleton(loading)
const [error, setError] = useState<string | null>(null)
const [showList, setShowList] = useState(() =>
typeof window === 'undefined' ? true : window.matchMedia('(min-width: 900px)').matches)
@@ -341,7 +342,7 @@ export default function CalendarPage() {
: 'All events'
if (loading) {
return <div className="aether-content"><SkeletonRows /></div>
return <div className="aether-content">{zeigeSkelett && <SkeletonRows />}</div>
}
return (
@@ -584,7 +585,7 @@ export default function CalendarPage() {
{deleteCalendar && (
<ConfirmDialog
title="Delete calendar"
message={`"${deleteCalendar.name}" mit allen Terminen darin unwiderruflich löschen?`}
message={`Permanently delete "${deleteCalendar.name}" and every event in it?`}
confirmLabel="Löschen" danger
onConfirm={confirmDeleteCalendar}
onCancel={() => setDeleteCalendar(null)}
@@ -1011,7 +1012,7 @@ function ListAgenda({ events, onEventClick, onEventDown }: {
fontSize: 12.5, fontWeight: 600, marginBottom: 6,
color: isSameDay(day, today) ? 'var(--color-primary)' : 'var(--color-text-muted)',
}}>
{weekdayLabels[(day.getDay() + 6) % 7]}, {day.getDate()}. {monthLabels[day.getMonth()]} {day.getFullYear()}
{weekdayLabels[(day.getDay() + 6) % 7]}, {monthLabels[day.getMonth()]} {day.getDate()}, {day.getFullYear()}
{isSameDay(day, today) && ' · today'}
</div>
{evs.map(ev => (