feat(mini-cal): ein Punkt je Kalender in dessen Farbe pro Tag

Statt eines einzelnen Punkts in --primary zeigt der Mini-Kalender jetzt fuer
jeden Kalender, der an dem Tag mindestens einen Termin hat, einen Punkt in
dessen Farbe (max. 4, stabil nach erstem Auftreten sortiert). Die Farbquelle
ist dieselbe wie in Monats-/Wochenansicht: ev.color || ev.calendarColor.

Ausserdem laeuft der Mini-Kalender jetzt ueber filterEvents(), damit
ausgeblendete Gruppenmitglieder keinen Punkt mehr erzeugen. Auf dem
"heute"-Kreis bekommen die Punkte einen duennen weissen Ring, damit sie auf
der farbigen Flaeche lesbar bleiben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-07 13:01:36 +02:00
co-authored by Claude Opus 5
parent f791160d1a
commit 7a2085b961
2 changed files with 34 additions and 11 deletions
+10 -4
View File
@@ -551,11 +551,17 @@ a { color: var(--primary); text-decoration: none; }
color: #fff; font-weight: 700;
}
.mini-day.selected:not(.today) { background: var(--primary-dim); color: var(--primary); font-weight: 600; }
.mini-day.has-events::after {
content: ''; position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
width: 4px; height: 4px; border-radius: 50%; background: var(--primary);
/* One dot per calendar with an event that day, in that calendar's colour. */
.mini-dots {
position: absolute; bottom: 1px; left: 0; right: 0;
display: flex; justify-content: center; align-items: center; gap: 2px;
line-height: 0; pointer-events: none;
}
.mini-day.today.has-events::after { background: #fff; }
.mini-dots i {
width: 4px; height: 4px; border-radius: 50%; flex: none;
}
/* Today's cell is a filled circle — ring the dots so they stay readable on it. */
.mini-day.today .mini-dots i { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.9); }
/* ── Calendar List ──────────────────────────────────────── */
.cal-list { padding: 8px 0; }
+24 -7
View File
@@ -559,6 +559,8 @@ function updateViewButtons() {
}
// ── Mini Calendar ─────────────────────────────────────────
const MINI_MAX_DOTS = 4;
function renderMiniCal() {
const d = state.currentDate;
const miniD = new Date(d.getFullYear(), d.getMonth(), 1);
@@ -576,10 +578,14 @@ function renderMiniCal() {
const DOW_LABELS = weekStartDay === 'sunday' ? DOW_SUNDAY : DOW_MONDAY;
miniDowEls.forEach((el, i) => { el.textContent = DOW_LABELS[i]; });
// Build event date set — mark every day an event spans, not just its start
// day, so multi-day events (Urlaub/Ferien) show a dot across the whole range.
const eventDates = new Set();
state.events.forEach(ev => {
// Build per-day colour sets — one dot per calendar that has at least one event
// that day, in that calendar's colour. Every day an event spans is marked, not
// just its start day, so multi-day events (Urlaub/Ferien) mark the whole range.
const dayColors = new Map(); // 'y-m-d' → Set of colours
const colorRank = new Map(); // colour → first-seen index, for a stable dot order
filterEvents(state.events).forEach(ev => {
const color = ev.color || ev.calendarColor || '#4285f4';
if (!colorRank.has(color)) colorRank.set(color, colorRank.size);
const s = new Date(ev.start);
let end = new Date(ev.end || ev.start);
// All-day events store an exclusive end → step back to the last real day.
@@ -588,7 +594,10 @@ function renderMiniCal() {
const last = new Date(end.getFullYear(), end.getMonth(), end.getDate());
let guard = 0;
while (cur <= last && guard++ < 400) {
eventDates.add(`${cur.getFullYear()}-${cur.getMonth()}-${cur.getDate()}`);
const key = `${cur.getFullYear()}-${cur.getMonth()}-${cur.getDate()}`;
let set = dayColors.get(key);
if (!set) { set = new Set(); dayColors.set(key, set); }
set.add(color);
cur.setDate(cur.getDate() + 1);
}
});
@@ -604,7 +613,8 @@ function renderMiniCal() {
const isOther = day.getMonth() !== miniD.getMonth();
const isToday_ = isToday(day);
const isSelected = isSameDay(day, state.currentDate);
const hasEvs = eventDates.has(`${day.getFullYear()}-${day.getMonth()}-${day.getDate()}`);
const colors = dayColors.get(`${day.getFullYear()}-${day.getMonth()}-${day.getDate()}`);
const hasEvs = !!colors;
const cls = [
'mini-day',
isOther ? 'other-month' : '',
@@ -612,7 +622,14 @@ function renderMiniCal() {
isSelected && !isToday_ ? 'selected' : '',
hasEvs ? 'has-events' : '',
].filter(Boolean).join(' ');
return `<div class="${cls}" data-date="${dateKey(day)}">${day.getDate()}</div>`;
// At most MINI_MAX_DOTS dots — more than that no longer fits under the digit.
const dots = hasEvs
? '<span class="mini-dots">' + [...colors]
.sort((a, b) => colorRank.get(a) - colorRank.get(b))
.slice(0, MINI_MAX_DOTS)
.map(c => `<i style="background:${c}"></i>`).join('') + '</span>'
: '';
return `<div class="${cls}" data-date="${dateKey(day)}">${day.getDate()}${dots}</div>`;
}).join('');
document.getElementById('mini-days').innerHTML = html;