diff --git a/loko/interventions/static/interventions/calendar/interventions_calendar.css b/loko/interventions/static/interventions/calendar/interventions_calendar.css index 4434e83..ed9ffc4 100644 --- a/loko/interventions/static/interventions/calendar/interventions_calendar.css +++ b/loko/interventions/static/interventions/calendar/interventions_calendar.css @@ -143,19 +143,20 @@ position: absolute; pointer-events: none; z-index: 1050; - background: rgba(15, 23, 42, 0.94); + background: rgba(15, 23, 42, 0.95); color: #fff; - padding: 0.45rem 0.75rem; + padding: 0.5rem 0.75rem; border-radius: 0.5rem; font-size: 0.75rem; line-height: 1.35; - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.22); - backdrop-filter: blur(4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28); + backdrop-filter: blur(6px); border: 1px solid rgba(255, 255, 255, 0.15); transition: opacity 0.12s ease, transform 0.12s ease; - white-space: nowrap; transform: translate(-50%, -100%); margin-top: -8px; + min-width: 170px; + max-width: 320px; } .canvas-timeline__tooltip.is-hidden { diff --git a/loko/interventions/static/interventions/calendar/interventions_calendar.js b/loko/interventions/static/interventions/calendar/interventions_calendar.js index add97e1..796042f 100644 --- a/loko/interventions/static/interventions/calendar/interventions_calendar.js +++ b/loko/interventions/static/interventions/calendar/interventions_calendar.js @@ -1849,7 +1849,16 @@ document.addEventListener('DOMContentLoaded', function () { if (milestoneHit) { dom.bodyEl.classList.add('is-hovering-item'); - showTimelineTooltip(milestoneHit); + // Trouver tous les jalons de la même intervention qui se superposent (à moins de 14px sur l'axe X) + const overlapThresholdPx = 14; + const overlappingHits = timelineState.hitRegions.filter(region => + region.isMilestone && + region.index === milestoneHit.index && + Math.abs((region.anchorX || (region.x + region.width / 2)) - (milestoneHit.anchorX || (milestoneHit.x + milestoneHit.width / 2))) <= overlapThresholdPx + ); + // Trier chronologiquement + overlappingHits.sort((a, b) => (a.date?.getTime?.() || 0) - (b.date?.getTime?.() || 0)); + showTimelineTooltip(overlappingHits.length > 0 ? overlappingHits : [milestoneHit], milestoneHit); return; } @@ -1870,47 +1879,99 @@ document.addEventListener('DOMContentLoaded', function () { } } - function showTimelineTooltip(hit) { + function showTimelineTooltip(hits, primaryHit) { const dom = timelineState.dom; if (!dom?.tooltipEl) return; + + const hitsList = Array.isArray(hits) ? hits : [hits]; + if (!hitsList.length) return; - let dateStr = ''; - if (hit.date instanceof Date && !Number.isNaN(hit.date.getTime())) { - dateStr = hit.date.toLocaleString(DOCUMENT_LOCALE, { + const anchorHit = primaryHit || hitsList[0]; + + const formatItemDate = (date) => { + if (!(date instanceof Date) || Number.isNaN(date.getTime())) return ''; + return date.toLocaleString(DOCUMENT_LOCALE, { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); - } + }; let content = ''; - if (hit.kind === 'status') { - const color = STATUS_COLORS[hit.statusCode] || DEFAULT_STATUS_COLOR; - const currentBadge = hit.isCurrent ? ` ${gettext('Actuel')}` : ''; - const userStr = hit.userName ? `
${escapeHtml(hit.userName)}
` : ''; - content = ` -
- - ${escapeHtml(hit.statusLabel || hit.statusCode)}${currentBadge} + + if (hitsList.length === 1) { + const hit = hitsList[0]; + const dateStr = formatItemDate(hit.date); + if (hit.kind === 'status') { + const color = STATUS_COLORS[hit.statusCode] || DEFAULT_STATUS_COLOR; + const currentBadge = hit.isCurrent ? ` ${gettext('Actuel')}` : ''; + const userStr = hit.userName ? `
${escapeHtml(hit.userName)}
` : ''; + content = ` +
+ + ${escapeHtml(hit.statusLabel || hit.statusCode)}${currentBadge} +
+
${escapeHtml(dateStr)}
+ ${userStr} + `; + } else { + content = ` +
+ + ${escapeHtml(hit.label || hit.milestoneType)} +
+
${escapeHtml(dateStr)}
+ `; + } + } else { + // Plusieurs événements superposés + const header = ` +
+ ${escapeHtml(anchorHit.itemCode || '')} + ${hitsList.length} ${gettext('étapes')}
-
${escapeHtml(dateStr)}
- ${userStr} - `; - } else if (hit.kind === 'milestone') { - content = ` -
- - ${escapeHtml(hit.label || hit.milestoneType)} -
-
${escapeHtml(dateStr)}
`; + + const rows = hitsList.map((hit, idx) => { + const dateStr = formatItemDate(hit.date); + const isBorder = idx < hitsList.length - 1 ? 'border-bottom border-light border-opacity-10 pb-1 mb-1' : ''; + if (hit.kind === 'status') { + const color = STATUS_COLORS[hit.statusCode] || DEFAULT_STATUS_COLOR; + const currentBadge = hit.isCurrent ? ` ${gettext('Actuel')}` : ''; + const userStr = hit.userName ? `(${escapeHtml(hit.userName)})` : ''; + return ` +
+ +
+
+ ${escapeHtml(hit.statusLabel || hit.statusCode)} + ${currentBadge} +
+
${escapeHtml(dateStr)}${userStr}
+
+
+ `; + } else { + return ` +
+ +
+
${escapeHtml(hit.label || hit.milestoneType)}
+
${escapeHtml(dateStr)}
+
+
+ `; + } + }).join(''); + + content = header + rows; } dom.tooltipEl.innerHTML = content; - dom.tooltipEl.style.left = `${hit.anchorX || (hit.x + hit.width / 2)}px`; - dom.tooltipEl.style.top = `${hit.anchorY || hit.y}px`; + dom.tooltipEl.style.left = `${anchorHit.anchorX || (anchorHit.x + anchorHit.width / 2)}px`; + dom.tooltipEl.style.top = `${anchorHit.anchorY || anchorHit.y}px`; dom.tooltipEl.classList.remove('is-hidden'); }