fix(rcal): prevent multi-day event spans from displacing day cells
Multi-day event span bars used grid-row/grid-column inside the same CSS grid as auto-placed day cells. The grid auto-placement algorithm skipped cells occupied by explicitly-placed spans, pushing day numbers to wrong positions. Fix: make .ev-span position:absolute with .grid position:relative. Absolutely-positioned grid children still use grid-row/column for their containing block but don't participate in layout flow. Also account for expanded day-detail rows when calculating span grid rows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
245d2ec3b4
commit
bfdb320b3e
|
|
@ -1201,7 +1201,8 @@ class FolkCalendarView extends HTMLElement {
|
|||
html += this.renderDayDetail(this.expandedDay, dayEvents);
|
||||
}
|
||||
|
||||
// Multi-day event span bars
|
||||
// Multi-day event span bars (position:absolute so they don't
|
||||
// displace auto-placed day cells in the CSS grid)
|
||||
html += this.renderMultiDaySpans(year, month, firstDay, daysInMonth);
|
||||
|
||||
return html;
|
||||
|
|
@ -1224,6 +1225,24 @@ class FolkCalendarView extends HTMLElement {
|
|||
const totalRows = totalCells / 7;
|
||||
let html = "";
|
||||
|
||||
// If a day detail is expanded, figure out which grid row it inserted
|
||||
// so we can offset span bars below it by +1
|
||||
let detailAfterGridRow = -1;
|
||||
if (this.expandedDay) {
|
||||
const ed = new Date(this.expandedDay + "T00:00:00");
|
||||
if (ed.getFullYear() === year && ed.getMonth() === month) {
|
||||
const cellIdx = firstDay + ed.getDate() - 1;
|
||||
const posInRow = cellIdx % 7;
|
||||
// Detail is emitted when posInRow===6 or last day of month
|
||||
if (posInRow === 6 || ed.getDate() === daysInMonth) {
|
||||
detailAfterGridRow = Math.floor(cellIdx / 7) + 1;
|
||||
} else {
|
||||
// Detail is emitted after all days via the outer render
|
||||
detailAfterGridRow = totalRows + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: date string → cell index (clamped to grid)
|
||||
const dateToCellIdx = (ds: string): number => {
|
||||
const d = new Date(ds);
|
||||
|
|
@ -1260,7 +1279,10 @@ class FolkCalendarView extends HTMLElement {
|
|||
if (!placed) overflow++;
|
||||
}
|
||||
|
||||
const gridRow = row + 1;
|
||||
// Offset grid row if a detail panel was inserted above this row
|
||||
let gridRow = row + 1;
|
||||
if (detailAfterGridRow > 0 && gridRow > detailAfterGridRow) gridRow++;
|
||||
|
||||
for (let l = 0; l < lanes.length; l++) {
|
||||
for (const re of lanes[l]) {
|
||||
const color = re.ev.source_color || "#6366f1";
|
||||
|
|
@ -1270,11 +1292,11 @@ class FolkCalendarView extends HTMLElement {
|
|||
const contR = realEnd > rowEnd;
|
||||
const rL = contL ? "0" : "4px";
|
||||
const rR = contR ? "0" : "4px";
|
||||
html += `<div class="ev-span" style="grid-row:${gridRow};grid-column:${re.c0 + 1}/${re.c1 + 2};margin-top:${22 + l * 18}px;background:${color}25;border-left:2px solid ${color};border-radius:${rL} ${rR} ${rR} ${rL}" data-event-id="${re.ev.id}" title="${this.esc(re.ev.title)}"><span class="ev-span-text" style="color:${color}">${this.esc(re.ev.title)}</span></div>`;
|
||||
html += `<div class="ev-span" style="grid-row:${gridRow};grid-column:${re.c0 + 1}/${re.c1 + 2};left:0;right:0;margin-top:${22 + l * 18}px;background:${color}25;border-left:2px solid ${color};border-radius:${rL} ${rR} ${rR} ${rL}" data-event-id="${re.ev.id}" title="${this.esc(re.ev.title)}"><span class="ev-span-text" style="color:${color}">${this.esc(re.ev.title)}</span></div>`;
|
||||
}
|
||||
}
|
||||
if (overflow > 0) {
|
||||
html += `<div class="ev-span-more" style="grid-row:${gridRow};grid-column:1;margin-top:${22 + MAX_LANES * 18}px">+${overflow} more</div>`;
|
||||
html += `<div class="ev-span-more" style="grid-row:${gridRow};grid-column:1;left:0;margin-top:${22 + MAX_LANES * 18}px">+${overflow} more</div>`;
|
||||
}
|
||||
}
|
||||
return html;
|
||||
|
|
@ -2749,7 +2771,7 @@ class FolkCalendarView extends HTMLElement {
|
|||
/* ── Month Grid ── */
|
||||
.weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 4px; }
|
||||
.wd { text-align: center; font-size: 11px; color: var(--rs-text-muted); padding: 4px; font-weight: 600; }
|
||||
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
|
||||
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; position: relative; }
|
||||
.day { background: var(--rs-bg-surface); border: 1px solid var(--rs-border); border-radius: 6px; min-height: 80px; padding: 6px; cursor: pointer; position: relative; -webkit-tap-highlight-color: transparent; }
|
||||
.day:hover { border-color: var(--rs-border-strong); }
|
||||
.day.today { border-color: var(--rs-primary-hover); background: var(--rs-bg-active); }
|
||||
|
|
@ -2770,10 +2792,10 @@ class FolkCalendarView extends HTMLElement {
|
|||
.dot--tentative { border: 1px dashed; background: transparent !important; width: 6px; height: 6px; border-radius: 50%; display: inline-block; margin: 1px; }
|
||||
|
||||
/* ── Multi-day Span Bars ── */
|
||||
.ev-span { height: 16px; font-size: 10px; line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px; cursor: pointer; z-index: 2; align-self: start; pointer-events: auto; }
|
||||
.ev-span { position: absolute; height: 16px; font-size: 10px; line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px; cursor: pointer; z-index: 2; pointer-events: auto; }
|
||||
.ev-span:hover { filter: brightness(1.15); }
|
||||
.ev-span-text { font-weight: 500; }
|
||||
.ev-span-more { height: 14px; font-size: 9px; line-height: 14px; color: var(--rs-text-muted); z-index: 2; align-self: start; pointer-events: none; padding: 0 4px; }
|
||||
.ev-span-more { position: absolute; height: 14px; font-size: 9px; line-height: 14px; color: var(--rs-text-muted); z-index: 2; pointer-events: none; padding: 0 4px; }
|
||||
|
||||
/* ── Drop Target ── */
|
||||
.day.drop-target { background: rgba(245,158,11,0.15); border: 2px dashed var(--rs-warning); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue