feat: enhance interventions calendar UI with team color indicators, sticky column styling, and improved grid layouts

This commit is contained in:
kdeterme 2026-09-02 14:12:32 +02:00
parent fa92404ae7
commit 61a099eb4f
3 changed files with 81 additions and 31 deletions

View file

@ -828,13 +828,24 @@
.teams-daily-table th, .teams-daily-table th,
.teams-daily-table td { .teams-daily-table td {
padding: 0.75rem; padding: 0.6rem 0.75rem;
vertical-align: top; vertical-align: top;
border: 1px solid rgba(15, 23, 42, 0.08); border: 1px solid rgba(15, 23, 42, 0.12);
} }
.teams-daily-table tbody td { /* Lignes de séparation très marquées entre équipes */
border-bottom: 2px solid rgba(15, 23, 42, 0.16); .teams-daily-table tbody tr.teams-daily-team-row td {
border-bottom: 3px solid #64748b !important;
padding-top: 8px;
padding-bottom: 10px;
}
.teams-daily-table tbody tr.teams-daily-team-row:nth-child(even) td.sticky-left {
background-color: #f1f5f9 !important;
}
.teams-daily-table tbody tr.teams-daily-team-row:nth-child(even) td.teams-daily-grid-cell:not(.today-cell) {
background-color: #f8fafc;
} }
.teams-daily-table thead th { .teams-daily-table thead th {
@ -848,24 +859,37 @@
top: 0; top: 0;
z-index: 5; z-index: 5;
box-shadow: 0 1px 0 rgba(15, 23, 42, 0.08); box-shadow: 0 1px 0 rgba(15, 23, 42, 0.08);
border-bottom: 2px solid #cbd5e1;
}
.teams-daily-table thead th.day-header {
min-width: 180px;
width: 200px;
max-width: 200px;
} }
/* Left sticky team column */ /* Left sticky team column */
.teams-daily-table .sticky-left { .teams-daily-table .sticky-left {
position: sticky; position: sticky;
left: 0; left: 0;
background-color: #f8fafc !important; background-color: #ffffff;
z-index: 6; z-index: 6;
box-shadow: 2px 0 5px rgba(15, 23, 42, 0.05); box-shadow: 2px 0 5px rgba(15, 23, 42, 0.06);
border-right: 2px solid #94a3b8 !important;
min-width: 220px;
width: 220px;
max-width: 240px;
} }
.teams-daily-table thead th.sticky-left { .teams-daily-table thead th.sticky-left {
z-index: 7; z-index: 7;
background-color: #f8fafc !important;
box-shadow: 2px 2px 0 rgba(15, 23, 42, 0.08); box-shadow: 2px 2px 0 rgba(15, 23, 42, 0.08);
border-right: 2px solid #94a3b8 !important;
} }
.team-cell-title { .team-cell-title {
font-size: 0.95rem; font-size: 0.92rem;
color: #0f172a; color: #0f172a;
font-weight: 700; font-weight: 700;
} }
@ -879,30 +903,32 @@
/* Grid cells & today highlighted column */ /* Grid cells & today highlighted column */
.teams-daily-grid-cell { .teams-daily-grid-cell {
background-color: #fff; background-color: #fff;
min-width: 220px; min-width: 180px;
width: 220px; width: 200px;
transition: background-color 0.2s ease; max-width: 200px;
transition: background-color 0.15s ease;
} }
.teams-daily-grid-cell.today-cell { .teams-daily-grid-cell.today-cell {
background-color: rgba(13, 110, 253, 0.02) !important; background-color: #f3f8ff !important;
} }
.today-column-header { .today-column-header {
background: rgba(13, 110, 253, 0.08) !important; background: linear-gradient(180deg, #e7f1ff 0%, #d0e2ff 100%) !important;
color: #0d6efd !important; color: #0b5ed7 !important;
border-bottom: 2px solid #0d6efd !important; border-bottom: 2px solid #0d6efd !important;
} }
/* Team composition list */ /* Team composition list */
.team-members-list { .team-members-list {
background: #f1f5f9; background: #f8fafc;
border-radius: 0.5rem; border-radius: 0.35rem;
padding: 0.4rem 0.6rem; padding: 0.35rem 0.5rem;
color: #475569; color: #334155;
font-weight: 500; font-weight: 500;
line-height: 1.4; line-height: 1.35;
border-left: 2px solid #cbd5e1; border-left: 3px solid #cbd5e1;
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
} }
/* Stack of interventions */ /* Stack of interventions */

View file

@ -417,6 +417,14 @@ document.addEventListener('DOMContentLoaded', function () {
} }
} }
const TEAM_PALETTE = [
'#0d6efd', '#6610f2', '#6f42c1', '#d63384', '#fd7e14',
'#198754', '#20c997', '#0dcaf0', '#495057', '#e83e8c'
];
function getTeamColor(teamId) {
return TEAM_PALETTE[Math.abs(teamId || 0) % TEAM_PALETTE.length];
}
function renderTeamsDailyGrid(data) { function renderTeamsDailyGrid(data) {
const todayStr = formatDateISO(new Date()); const todayStr = formatDateISO(new Date());
const headerRow = document.getElementById('teams-daily-table-header'); const headerRow = document.getElementById('teams-daily-table-header');
@ -454,14 +462,15 @@ document.addEventListener('DOMContentLoaded', function () {
data.days.forEach(day => { data.days.forEach(day => {
const th = document.createElement('th'); const th = document.createElement('th');
th.className = 'day-header text-center align-middle'; th.className = 'day-header text-center align-middle';
th.style.minWidth = '200px'; th.style.minWidth = '180px';
th.style.width = '200px'; th.style.width = '200px';
th.style.maxWidth = '200px';
const dateObj = new Date(day.date); const dateObj = new Date(day.date);
th.textContent = dayFormatter.format(dateObj); th.textContent = dayFormatter.format(dateObj);
if (day.is_today) { if (day.is_today) {
th.classList.add('bg-primary-subtle', 'border-primary', 'text-primary', 'today-column-header'); th.classList.add('today-column-header');
} }
headerRow.appendChild(th); headerRow.appendChild(th);
}); });
@ -477,15 +486,30 @@ document.addEventListener('DOMContentLoaded', function () {
data.teams.forEach(team => { data.teams.forEach(team => {
const tr = document.createElement('tr'); const tr = document.createElement('tr');
tr.className = 'teams-daily-team-row';
const teamColor = getTeamColor(team.id);
const tdTeam = document.createElement('td'); const tdTeam = document.createElement('td');
tdTeam.className = 'sticky-left bg-light font-weight-bold align-middle'; tdTeam.className = 'sticky-left align-middle';
tdTeam.style.zIndex = '2'; tdTeam.style.zIndex = '2';
let teamHTML = `<div class="team-cell-title">${escapeHtml(team.name)}</div>`; let teamHTML = `
if (team.company) { <div class="d-flex align-items-center">
teamHTML += `<div class="team-cell-company text-muted small font-weight-normal">${escapeHtml(team.company)}</div>`; <div class="team-color-indicator" style="background-color: ${teamColor}; min-height: 38px; width: 4px; margin-right: 8px; border-radius: 2px; flex-shrink: 0;"></div>
} <div class="overflow-hidden flex-grow-1">
<div class="fw-bold text-truncate text-dark d-flex align-items-center gap-1">
<i class="bi bi-people-fill" style="color: ${teamColor}; font-size: 0.95rem;"></i>
<span class="text-truncate">${escapeHtml(team.name)}</span>
</div>
${team.company ? `
<div class="text-muted small text-truncate mt-1" style="font-size:0.75rem;">
<span class="badge bg-light text-secondary border px-1 py-0"><i class="bi bi-building me-1"></i>${escapeHtml(team.company)}</span>
</div>
` : ''}
</div>
</div>
`;
tdTeam.innerHTML = teamHTML; tdTeam.innerHTML = teamHTML;
tr.appendChild(tdTeam); tr.appendChild(tdTeam);
@ -495,7 +519,7 @@ document.addEventListener('DOMContentLoaded', function () {
tdDay.setAttribute('data-date', day.date); tdDay.setAttribute('data-date', day.date);
tdDay.setAttribute('data-team-id', team.id !== null ? team.id : ''); tdDay.setAttribute('data-team-id', team.id !== null ? team.id : '');
if (day.is_today) { if (day.is_today) {
tdDay.classList.add('bg-primary-subtle-light', 'today-cell'); tdDay.classList.add('today-cell');
} }
const dayData = team.days[day.date] || { members: [], interventions: [] }; const dayData = team.days[day.date] || { members: [], interventions: [] };
@ -513,11 +537,11 @@ document.addEventListener('DOMContentLoaded', function () {
} }
return escapeHtml(name); return escapeHtml(name);
}).join(', '); }).join(', ');
membersHTML = `<div class="team-members-list text-muted small fst-italic mb-2" title="${gettext('Composition de l’équipe')}"> membersHTML = `<div class="team-members-list text-muted small fst-italic mb-2" style="border-left: 3px solid ${teamColor};" title="${gettext('Composition de l’équipe')}">
<i class="bi bi-people-fill me-1"></i>${formattedMembers} <i class="bi bi-people-fill me-1" style="color: ${teamColor};"></i>${formattedMembers}
</div>`; </div>`;
} else if (team.id !== null) { } else if (team.id !== null) {
membersHTML = `<div class="team-members-list text-muted small fst-italic mb-2 text-opacity-50"> membersHTML = `<div class="team-members-list text-muted small fst-italic mb-2 text-opacity-50" style="border-left: 3px solid #cbd5e1;">
<i class="bi bi-people me-1"></i>(${gettext('Aucun membre')}) <i class="bi bi-people me-1"></i>(${gettext('Aucun membre')})
</div>`; </div>`;
} }

View file

@ -529,7 +529,7 @@
<table class="table table-bordered teams-daily-table mb-0"> <table class="table table-bordered teams-daily-table mb-0">
<thead> <thead>
<tr id="teams-daily-table-header"> <tr id="teams-daily-table-header">
<th class="bg-light sticky-left font-weight-bold text-center align-middle" style="min-width: 220px; width: 220px; z-index: 4;"> <th class="bg-light sticky-left font-weight-bold text-center align-middle" style="min-width: 220px; width: 220px; max-width: 240px; z-index: 8;">
{% translate "Équipes / Jours" %} {% translate "Équipes / Jours" %}
</th> </th>
</tr> </tr>