feat(web): Kalender-Plakette in der Farbe des Kalenders, Farbpunkt je Tooltip-Zeile

- groupEventsByDate sortiert jede Tagesgruppe jetzt nach Start aufsteigend
- Zaehl-Plakette im Monatsraster traegt die Farbe des Kalenders des fruehesten Termins (weisse Schrift), ohne Farbe unveraendert bg-primary
- Tooltip-Zeilen bekommen denselben Farbpunkt wie die Liste "Naechste Termine" (Rueckfall var(--muted-foreground))
- 3 neue Tests: calendar-month Test 2b, calendar-widget Test 3b/3c

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 14:25:21 +02:00
parent 5313fbc019
commit 1e4ec30190
4 changed files with 108 additions and 11 deletions
@@ -30,7 +30,9 @@ const TOOLTIP_EDGE_PX = 4;
*
* Oben ein Monatsraster (Nav-Zeile Zurueck/Monat/Weiter, Wochentagskopf,
* 42 Zellen ab Montag, Faehrmonatstage gedaempft, heutiger Tag hervorgehoben,
* Zaehl-Plakette an Tagen mit Terminen, Tooltip beim Ueberfahren), darunter
* Zaehl-Plakette an Tagen mit Terminen in der Farbe des Kalenders des
* fruehesten Termins des Tages (sonst Akzentfarbe), Tooltip beim Ueberfahren
* mit Farbpunkt je Zeile (quick-260916-jvj)), darunter
* der Block "Naechste Termine". Beide Bloecke lassen sich unabhaengig
* ein-/ausblenden (Config `showMonth`/`maxEvents`, siehe calendar-month.ts).
*
@@ -241,14 +243,25 @@ export function CalendarWidget({ config }: WidgetProps) {
onMouseLeave={() => setHover(null)}
>
<span>{day.date.getDate()}</span>
{hasEvents && (
<span
data-testid="calendar-day-count"
className="absolute bottom-px right-px flex h-[clamp(10px,3cqw,16px)] min-w-[clamp(10px,3cqw,16px)] items-center justify-center rounded-full bg-primary px-0.5 text-[clamp(7px,1.8cqw,10px)] font-semibold leading-none text-primary-foreground"
>
{day.events.length}
</span>
)}
{hasEvents &&
(() => {
const badgeColor = day.events[0]?.color;
const badgeClass = [
'absolute bottom-px right-px flex h-[clamp(10px,3cqw,16px)] min-w-[clamp(10px,3cqw,16px)] items-center justify-center rounded-full px-0.5 text-[clamp(7px,1.8cqw,10px)] font-semibold leading-none',
badgeColor ? 'text-white' : 'bg-primary text-primary-foreground',
]
.filter(Boolean)
.join(' ');
return (
<span
data-testid="calendar-day-count"
className={badgeClass}
style={badgeColor ? { backgroundColor: badgeColor } : undefined}
>
{day.events.length}
</span>
);
})()}
</div>
);
})}
@@ -313,6 +326,12 @@ export function CalendarWidget({ config }: WidgetProps) {
>
{hoverEvents.slice(0, 5).map((event) => (
<div key={event.id} className="flex gap-2">
<span
data-testid="tooltip-color-dot"
className="mt-1 h-2 w-2 shrink-0 rounded-full"
style={{ backgroundColor: event.color || 'var(--muted-foreground)' }}
aria-hidden="true"
/>
<span className="shrink-0 tabular-nums text-muted-foreground">
{event.allDay ? t('calendar.allDay') : formatEventTime(event.start)}
</span>