Better calendar (colors per tool, grid layout, legend) + fix listings render
This commit is contained in:
+50
-20
@@ -441,38 +441,68 @@ async function loadCalendar() {
|
|||||||
function calPrev() { calMonth--; if(calMonth<1){calMonth=12;calYear--;} loadCalendar(); }
|
function calPrev() { calMonth--; if(calMonth<1){calMonth=12;calYear--;} loadCalendar(); }
|
||||||
function calNext() { calMonth++; if(calMonth>12){calMonth=1;calYear++;} loadCalendar(); }
|
function calNext() { calMonth++; if(calMonth>12){calMonth=1;calYear++;} loadCalendar(); }
|
||||||
|
|
||||||
|
// Palette de couleurs par outil (stable par ID)
|
||||||
|
const CAL_COLORS = [
|
||||||
|
'#6366f1','#22c55e','#f59e0b','#38bdf8','#f472b6',
|
||||||
|
'#a78bfa','#34d399','#fb923c','#60a5fa','#e879f9','#4ade80'
|
||||||
|
];
|
||||||
|
function toolColor(toolId) { return CAL_COLORS[(toolId - 1) % CAL_COLORS.length]; }
|
||||||
|
|
||||||
function renderCalendar(rentals) {
|
function renderCalendar(rentals) {
|
||||||
const title = document.getElementById('cal-title');
|
document.getElementById('cal-title').textContent =
|
||||||
title.textContent = new Date(calYear, calMonth-1, 1).toLocaleDateString('fr-FR', {month:'long', year:'numeric'});
|
new Date(calYear, calMonth-1, 1).toLocaleDateString('fr-FR', {month:'long', year:'numeric'});
|
||||||
|
|
||||||
const today = new Date().toISOString().slice(0,10);
|
const today = new Date().toISOString().slice(0,10);
|
||||||
const firstDay = new Date(calYear, calMonth-1, 1).getDay();
|
const firstDay = new Date(calYear, calMonth-1, 1).getDay();
|
||||||
const daysInMonth = new Date(calYear, calMonth, 0).getDate();
|
const daysInMonth = new Date(calYear, calMonth, 0).getDate();
|
||||||
const startOffset = (firstDay + 6) % 7; // Monday start
|
const startOffset = (firstDay + 6) % 7;
|
||||||
|
|
||||||
let html = `<table class="cal-table"><thead><tr>`;
|
// Légende des outils présents ce mois
|
||||||
['Lun','Mar','Mer','Jeu','Ven','Sam','Dim'].forEach(d => html += `<th>${d}</th>`);
|
const toolsInMonth = [...new Map(rentals.map(r => [r.tool_id, r])).values()];
|
||||||
html += '</tr></thead><tbody><tr>';
|
const legend = toolsInMonth.map(r =>
|
||||||
|
`<span class="cal-legend-item"><span class="cal-legend-dot" style="background:${toolColor(r.tool_id)}"></span>${esc(r.tool_name)}</span>`
|
||||||
|
).join('');
|
||||||
|
|
||||||
for (let i=0; i<startOffset; i++) html += '<td></td>';
|
let html = `<div class="cal-legend">${legend}</div>
|
||||||
let col = startOffset;
|
<div class="cal-grid-wrap">
|
||||||
|
<div class="cal-grid">`;
|
||||||
|
|
||||||
for (let day=1; day<=daysInMonth; day++) {
|
['Lun','Mar','Mer','Jeu','Ven','Sam','Dim'].forEach((d, i) => {
|
||||||
|
html += `<div class="cal-header-cell${i>=5?' cal-weekend':''}">${d}</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < startOffset; i++) html += `<div class="cal-cell cal-empty"></div>`;
|
||||||
|
|
||||||
|
for (let day = 1; day <= daysInMonth; day++) {
|
||||||
const dateStr = `${calYear}-${String(calMonth).padStart(2,'0')}-${String(day).padStart(2,'0')}`;
|
const dateStr = `${calYear}-${String(calMonth).padStart(2,'0')}-${String(day).padStart(2,'0')}`;
|
||||||
const dayRentals = rentals.filter(r => r.start_date <= dateStr && r.end_date >= dateStr);
|
const dayRentals = rentals.filter(r => r.start_date <= dateStr && r.end_date >= dateStr);
|
||||||
const isToday = dateStr === today;
|
const isToday = dateStr === today;
|
||||||
const numEl = isToday ? `<div class="cal-day-num today">${day}</div>` : `<div class="cal-day-num">${day}</div>`;
|
const dow = (startOffset + day - 1) % 7;
|
||||||
const events = dayRentals.map(r =>
|
const isWeekend = dow >= 5;
|
||||||
`<div class="cal-event" onclick="openRentalDetail(${r.id})" title="${esc(r.tool_name)} — ${esc(r.client_name)} (${esc(r.platform_name||'Direct')})">
|
|
||||||
🔨 ${esc(r.tool_name)}
|
const events = dayRentals.map(r => {
|
||||||
</div>`
|
const color = toolColor(r.tool_id);
|
||||||
).join('');
|
const isStart = r.start_date === dateStr;
|
||||||
html += `<td>${numEl}${events}</td>`;
|
const isEnd = r.end_date === dateStr;
|
||||||
col++;
|
const label = isStart ? `🔨 ${esc(r.tool_name)}` : esc(r.tool_name);
|
||||||
if (col % 7 === 0 && day < daysInMonth) html += '</tr><tr>';
|
return `<div class="cal-event-block${isStart?' cal-event-start':''}${isEnd?' cal-event-end':''}"
|
||||||
|
style="background:${color}22;border-left:3px solid ${color};color:${color}"
|
||||||
|
onclick="openRentalDetail(${r.id})"
|
||||||
|
title="${esc(r.tool_name)} → ${esc(r.client_name)}">${label}</div>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
html += `<div class="cal-cell${isToday?' cal-today':''}${isWeekend?' cal-weekend':''}">
|
||||||
|
<div class="cal-day-num${isToday?' today':''}">${day}</div>
|
||||||
|
${events}
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
while (col % 7 !== 0) { html += '<td></td>'; col++; }
|
|
||||||
html += '</tr></tbody></table>';
|
// Remplir la dernière ligne
|
||||||
|
const total = startOffset + daysInMonth;
|
||||||
|
const remaining = total % 7 === 0 ? 0 : 7 - (total % 7);
|
||||||
|
for (let i = 0; i < remaining; i++) html += `<div class="cal-cell cal-empty"></div>`;
|
||||||
|
|
||||||
|
html += `</div></div>`;
|
||||||
document.getElementById('calendar-wrap').innerHTML = html;
|
document.getElementById('calendar-wrap').innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-8
@@ -91,14 +91,31 @@ h3 { font-size: 1rem; font-weight: 600; color: var(--muted); }
|
|||||||
|
|
||||||
/* Calendar */
|
/* Calendar */
|
||||||
.cal-nav { display: flex; align-items: center; gap: 12px; }
|
.cal-nav { display: flex; align-items: center; gap: 12px; }
|
||||||
.cal-nav span { font-weight: 600; min-width: 140px; text-align: center; }
|
.cal-nav span { font-weight: 600; min-width: 160px; text-align: center; font-size: 1rem; }
|
||||||
.cal-table { width: 100%; border-collapse: collapse; }
|
|
||||||
.cal-table th { padding: 8px; text-align: center; font-size: 0.8rem; color: var(--muted); border-bottom: 1px solid var(--border); }
|
.cal-legend { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; min-height: 20px; }
|
||||||
.cal-table td { padding: 4px; vertical-align: top; min-width: 80px; min-height: 80px; border: 1px solid var(--border); border-radius: 4px; }
|
.cal-legend-item { display: flex; align-items: center; gap: 6px; font-size: .78rem; color: var(--muted); }
|
||||||
.cal-day-num { font-size: 0.8rem; color: var(--muted); padding: 2px 4px; }
|
.cal-legend-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||||||
.cal-day-num.today { background: var(--primary); color: #fff; border-radius: 50%; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; }
|
|
||||||
.cal-event { font-size: 0.7rem; padding: 2px 5px; border-radius: 4px; margin-bottom: 2px; cursor: pointer; background: rgba(99,102,241,0.25); color: var(--primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.cal-grid-wrap { overflow-x: auto; }
|
||||||
.cal-event:hover { background: rgba(99,102,241,0.45); }
|
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; min-width: 560px; }
|
||||||
|
|
||||||
|
.cal-header-cell { text-align: center; font-size: .75rem; font-weight: 600; color: var(--muted); padding: 6px 4px; text-transform: uppercase; letter-spacing: .05em; }
|
||||||
|
.cal-header-cell.cal-weekend { color: var(--warning); }
|
||||||
|
|
||||||
|
.cal-cell { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 6px; min-height: 90px; display: flex; flex-direction: column; gap: 3px; transition: border-color .15s; }
|
||||||
|
.cal-cell:hover { border-color: var(--primary); }
|
||||||
|
.cal-cell.cal-empty { background: transparent; border-color: transparent; }
|
||||||
|
.cal-cell.cal-today { border-color: var(--primary); background: rgba(99,102,241,.07); }
|
||||||
|
.cal-cell.cal-weekend { background: rgba(255,255,255,.02); }
|
||||||
|
|
||||||
|
.cal-day-num { font-size: .78rem; color: var(--muted); font-weight: 500; margin-bottom: 2px; }
|
||||||
|
.cal-day-num.today { background: var(--primary); color: #fff; border-radius: 50%; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; font-weight: 700; }
|
||||||
|
|
||||||
|
.cal-event-block { font-size: .7rem; padding: 2px 6px; border-radius: 4px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: opacity .15s; font-weight: 500; }
|
||||||
|
.cal-event-block:hover { opacity: .75; }
|
||||||
|
.cal-event-start { border-radius: 4px 0 0 4px; }
|
||||||
|
.cal-event-end { border-radius: 0 4px 4px 0; }
|
||||||
|
|
||||||
/* Platforms */
|
/* Platforms */
|
||||||
.platform-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: 1px solid var(--border); }
|
.platform-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: 1px solid var(--border); }
|
||||||
|
|||||||
Reference in New Issue
Block a user