// Main timetable: stages-as-rows × time-axis Gantt. // - Click empty cell → AddPerformance modal. // - Click block → floating Popover. // - Drag block → move (snap 15min); drag right edge → resize. // - Overlapping bookings stack vertically inside their stage row (lane-packed). // - Parking column on the right shows pending availability + parked bookings; // drag from parking → timetable to schedule, drag block → parking to unschedule. const TT = (function () { const STAGE_COL_W = 220; const PARKING_W = 280; const LANE_PAD = 4; // top/bottom padding inside row // ─── Block ────────────────────────────────────────────────────────── function Block({ perf, artist, stage, sections, pxPerMin, laneTop, laneHeight, conflicting, capWarn, b2bRight, b2bLeft, isSelected, showPercent, onSelect, onStartDragMove, onStartDragResize, }) { const status = window.CrewliHelpers.STATUS[perf.status]; const left = perf.start * pxPerMin; const width = (perf.end - perf.start) * pxPerMin; const time = window.CrewliHelpers.fmtTime(perf.start, window.CrewliData.TIME.startHour) + "–" + window.CrewliHelpers.fmtTime(perf.end, window.CrewliData.TIME.startHour); const adv = window.CrewliHelpers.advanceCount(artist, sections); const advPct = Math.round(adv.done / adv.total * 100); const blockStyle = { left, width, top: laneTop, height: laneHeight, background: status.blockBg, borderColor: conflicting ? "#d63d4b" : status.blockBorder, color: status.blockFg, }; const isCancelled = perf.status === "cancelled"; if (isCancelled) { blockStyle.borderColor = "#c4202f"; blockStyle.background = `repeating-linear-gradient(135deg, rgba(214,61,75,0.32) 0 7px, rgba(214,61,75,0.10) 7px 15px), #ffffff`; blockStyle.color = "#7a1219"; } const compact = laneHeight < 42; const showTime = width > 64; return (
Gebruik Lineup per dag om stages te activeren, of voeg een nieuwe stage toe.