import type { components } from '$lib/generated/api'; import { fillDensityGaps, type MonthBucket } from '$lib/shared/utils/monthBuckets'; type TimelineEntryDTO = components['schemas']['TimelineEntryDTO']; /** * A year band with more letters than this renders as a compact density strip * (count + 12-month sparkline) instead of one card per letter (REQ-012). */ export const DENSE_THRESHOLD = 12; export function isDense(letterCount: number): boolean { return letterCount > DENSE_THRESHOLD; } /** * Buckets a band's letters into exactly 12 month buckets (`{year}-01`..`{year}-12`) * for the density sparkline. Each letter counts on its `eventDate` month; coarser * precisions (SEASON/YEAR/APPROX) count on whatever anchor month the backend put * in `eventDate`. Entries without an `eventDate` (e.g. UNKNOWN) are ignored — they * live in the "Ohne Datum" bucket, not a dated band. (REQ-027) */ export function monthHistogram(letters: TimelineEntryDTO[], year: number): MonthBucket[] { const counts = new Map(); for (const l of letters) { if (!l.eventDate) continue; const month = l.eventDate.slice(0, 7); // YYYY-MM counts.set(month, (counts.get(month) ?? 0) + 1); } const buckets = Array.from(counts.entries()).map(([month, count]) => ({ month, count })); return fillDensityGaps(buckets, `${year}-01-01`, `${year}-12-31`); }