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.
Cherry-pick von 7a2085b (master) auf beta; die selected-Day-Regel aus beta
(color-mix) bleibt erhalten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a45bf6ea73
commit
a30375aa63
+10
-4
@@ -587,11 +587,17 @@ a { color: var(--primary); text-decoration: none; }
|
|||||||
color: #fff; font-weight: 700;
|
color: #fff; font-weight: 700;
|
||||||
}
|
}
|
||||||
.mini-day.selected:not(.today) { background: color-mix(in srgb, var(--day-selected-base) 15%, transparent); color: var(--primary); font-weight: 600; }
|
.mini-day.selected:not(.today) { background: color-mix(in srgb, var(--day-selected-base) 15%, transparent); color: var(--primary); font-weight: 600; }
|
||||||
.mini-day.has-events::after {
|
/* One dot per calendar with an event that day, in that calendar's colour. */
|
||||||
content: ''; position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
|
.mini-dots {
|
||||||
width: 4px; height: 4px; border-radius: 50%; background: var(--primary);
|
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 ──────────────────────────────────────── */
|
/* ── Calendar List ──────────────────────────────────────── */
|
||||||
.cal-list { padding: 8px 0; }
|
.cal-list { padding: 8px 0; }
|
||||||
|
|||||||
+24
-7
@@ -608,6 +608,8 @@ function updateViewButtons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Mini Calendar ─────────────────────────────────────────
|
// ── Mini Calendar ─────────────────────────────────────────
|
||||||
|
const MINI_MAX_DOTS = 4;
|
||||||
|
|
||||||
function renderMiniCal() {
|
function renderMiniCal() {
|
||||||
const d = state.currentDate;
|
const d = state.currentDate;
|
||||||
const miniD = new Date(d.getFullYear(), d.getMonth(), 1);
|
const miniD = new Date(d.getFullYear(), d.getMonth(), 1);
|
||||||
@@ -625,10 +627,14 @@ function renderMiniCal() {
|
|||||||
const DOW_LABELS = weekStartDay === 'sunday' ? DOW_SUNDAY : DOW_MONDAY;
|
const DOW_LABELS = weekStartDay === 'sunday' ? DOW_SUNDAY : DOW_MONDAY;
|
||||||
miniDowEls.forEach((el, i) => { el.textContent = DOW_LABELS[i]; });
|
miniDowEls.forEach((el, i) => { el.textContent = DOW_LABELS[i]; });
|
||||||
|
|
||||||
// Build event date set — mark every day an event spans, not just its start
|
// Build per-day colour sets — one dot per calendar that has at least one event
|
||||||
// day, so multi-day events (Urlaub/Ferien) show a dot across the whole range.
|
// that day, in that calendar's colour. Every day an event spans is marked, not
|
||||||
const eventDates = new Set();
|
// just its start day, so multi-day events (Urlaub/Ferien) mark the whole range.
|
||||||
state.events.forEach(ev => {
|
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);
|
const s = new Date(ev.start);
|
||||||
let end = new Date(ev.end || ev.start);
|
let end = new Date(ev.end || ev.start);
|
||||||
// All-day events store an exclusive end → step back to the last real day.
|
// All-day events store an exclusive end → step back to the last real day.
|
||||||
@@ -637,7 +643,10 @@ function renderMiniCal() {
|
|||||||
const last = new Date(end.getFullYear(), end.getMonth(), end.getDate());
|
const last = new Date(end.getFullYear(), end.getMonth(), end.getDate());
|
||||||
let guard = 0;
|
let guard = 0;
|
||||||
while (cur <= last && guard++ < 400) {
|
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);
|
cur.setDate(cur.getDate() + 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -653,7 +662,8 @@ function renderMiniCal() {
|
|||||||
const isOther = day.getMonth() !== miniD.getMonth();
|
const isOther = day.getMonth() !== miniD.getMonth();
|
||||||
const isToday_ = isToday(day);
|
const isToday_ = isToday(day);
|
||||||
const isSelected = isSameDay(day, state.currentDate);
|
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 = [
|
const cls = [
|
||||||
'mini-day',
|
'mini-day',
|
||||||
isOther ? 'other-month' : '',
|
isOther ? 'other-month' : '',
|
||||||
@@ -661,7 +671,14 @@ function renderMiniCal() {
|
|||||||
isSelected && !isToday_ ? 'selected' : '',
|
isSelected && !isToday_ ? 'selected' : '',
|
||||||
hasEvs ? 'has-events' : '',
|
hasEvs ? 'has-events' : '',
|
||||||
].filter(Boolean).join(' ');
|
].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('');
|
}).join('');
|
||||||
|
|
||||||
document.getElementById('mini-days').innerHTML = html;
|
document.getElementById('mini-days').innerHTML = html;
|
||||||
|
|||||||
Reference in New Issue
Block a user