diff --git a/modules/rcal/components/folk-calendar-view.ts b/modules/rcal/components/folk-calendar-view.ts index 34299f7d..5172ed54 100644 --- a/modules/rcal/components/folk-calendar-view.ts +++ b/modules/rcal/components/folk-calendar-view.ts @@ -1689,11 +1689,12 @@ class FolkCalendarView extends HTMLElement { } // Compute row assignments for overlapping horizontal events + const MIN_DH_INTERVAL = Math.ceil(60 / HOUR_WIDTH * 60); // min display width (60px) → min interval const dhIntervals = timed.map(ev => { const s = new Date(ev.start_time), e = new Date(ev.end_time); const startMin = s.getHours() * 60 + s.getMinutes(); const endMin = e.getHours() * 60 + e.getMinutes(); - return { startMin, endMin: Math.max(endMin, startMin + 30) }; + return { startMin, endMin: Math.max(endMin, startMin + MIN_DH_INTERVAL) }; }); const dhLayout = this.computeEventColumns(dhIntervals); const DH_ROW_HEIGHT = 56; // min-height 48 + 8px gap @@ -2152,7 +2153,9 @@ class FolkCalendarView extends HTMLElement { } } - let eventsOverlay = ""; + // Build per-day event overlays (grid-aligned to avoid calc() rounding vs 1fr drift) + const MIN_INTERVAL_WEEK = Math.ceil(18 / HOUR_HEIGHT * 60); // min display height → min interval + const dayOverlays: string[] = []; for (let i = 0; i < 7; i++) { const ds = this.dateStr(days[i]); const dayTimed = this.getEventsForDate(ds).filter(ev => { @@ -2160,15 +2163,15 @@ class FolkCalendarView extends HTMLElement { return (en.getTime() - s.getTime()) < 86400000; }).sort((a, b) => a.start_time.localeCompare(b.start_time)); - // Compute sub-columns for overlapping events within this day const intervals = dayTimed.map(ev => { const s = new Date(ev.start_time), e = new Date(ev.end_time); const startMin = s.getHours() * 60 + s.getMinutes(); const endMin = e.getHours() * 60 + e.getMinutes(); - return { startMin, endMin: Math.max(endMin, startMin + 20) }; + return { startMin, endMin: Math.max(endMin, startMin + MIN_INTERVAL_WEEK) }; }); const dayLayout = this.computeEventColumns(intervals); + let dayHtml = ""; for (let j = 0; j < dayTimed.length; j++) { const ev = dayTimed[j]; const { startMin, endMin } = intervals[j]; @@ -2177,21 +2180,28 @@ class FolkCalendarView extends HTMLElement { const topPx = ((startMin - START_HOUR * 60) / 60) * HOUR_HEIGHT; const heightPx = Math.max((duration / 60) * HOUR_HEIGHT, 18); const es = this.getEventStyles(ev); - const colLeft = `calc(44px + ${i} * ((100% - 44px) / 7) + 2px + ${col} * ((100% - 44px) / 7 - 4px) / ${totalCols})`; - const colWidth = `calc(((100% - 44px) / 7 - 4px) / ${totalCols} - 1px)`; + const evLeft = totalCols > 1 ? `calc(${(col / totalCols * 100).toFixed(2)}% + 1px)` : "1px"; + const evWidth = totalCols > 1 ? `calc(${(100 / totalCols).toFixed(2)}% - 2px)` : "calc(100% - 2px)"; const showMeta = heightPx >= 36; const timeStr = `${this.formatTime(ev.start_time)}\u2013${this.formatTime(ev.end_time)}`; const locName = ev.location_name ? this.esc(ev.location_name) : ""; const virtualBadge = ev.is_virtual ? `\u{1F4BB}` : ""; - eventsOverlay += `
${virtualBadge}${this.esc(ev.title)}
${showMeta ? `
${timeStr}${locName ? `${locName}` : ""}
` : ""}
`; } + dayOverlays.push(dayHtml); } + // Grid-aligned overlay mirrors week-grid columns exactly (no calc drift) + const overlayDivs = dayOverlays.map(h => + `
${h}
` + ).join(""); + const eventsOverlay = `
${overlayDivs}
`; + let nowHtml = ""; const nowDay = days.findIndex(day => this.dateStr(day) === todayStr); if (nowDay >= 0) { @@ -2205,9 +2215,11 @@ class FolkCalendarView extends HTMLElement { return `
${headerHtml}
-
-
${gridHtml}
- ${eventsOverlay}${nowHtml} +
+
+
${gridHtml}
+ ${eventsOverlay}${nowHtml} +
`; }