diff --git a/public/calendar.html b/public/calendar.html index 27b542d..6998790 100644 --- a/public/calendar.html +++ b/public/calendar.html @@ -33,6 +33,10 @@
diff --git a/public/css/style.css b/public/css/style.css index 9784958..0491a03 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -513,6 +513,39 @@ h3 { font-size: 1rem; margin: 0 0 0.5rem; } .pill-link.spotify { border-color: #205934; } } +.calendar-menu { position: relative; display: inline-block; } + +.calendar-menu > summary { + list-style: none; + cursor: pointer; +} + +.calendar-menu > summary::-webkit-details-marker { display: none; } + +.calendar-menu-options { + position: absolute; + top: calc(100% + 0.3rem); + left: 0; + z-index: 20; + display: flex; + flex-direction: column; + min-width: 9rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); + overflow: hidden; +} + +.calendar-menu-options a { + padding: 0.45rem 0.75rem; + font-size: 0.85rem; + color: var(--text); + text-decoration: none; +} + +.calendar-menu-options a:hover { background: var(--surface-alt); } + /* ---------- Tags (tutorials / instruments) ---------- */ .tag-list { @@ -1482,6 +1515,22 @@ a.back-link:hover { color: var(--accent); } .vote-badge.accept { border-left: 3px solid var(--success); } .vote-badge.reject { border-left: 3px solid var(--danger); } +.rehearsal-voted-section { margin-top: 0.75rem; } + +.rehearsal-voted-section > summary { + color: var(--muted); + font-size: 0.85rem; + cursor: pointer; + list-style: none; + padding: 0.3rem 0; +} + +.rehearsal-voted-section > summary::-webkit-details-marker { display: none; } +.rehearsal-voted-section > summary::before { content: '▸ '; } +.rehearsal-voted-section[open] > summary::before { content: '▾ '; } + +.rehearsal-voted-section .panel { margin-top: 0.4rem; opacity: 0.85; } + .cell-badges { position: absolute; top: 0.3rem; diff --git a/public/js/calendar.js b/public/js/calendar.js index e69c3f4..f36b23b 100644 --- a/public/js/calendar.js +++ b/public/js/calendar.js @@ -55,9 +55,7 @@ function concertLinksHtml(concert) {

${concert.venue ? escapeHtml(concert.venue) + ' · ' : ''}${formatTime(startISO)} – ${formatTime(endISO)}

- + Google - + Outlook - + Apple / autre + ${calendarLinksMenuHtml(linkArgs, 'concert.ics')}
`; @@ -432,24 +430,14 @@ function rehearsalRowTemplate(r) {
${rehearsalVoteActionsHtml(r)} - + Google - + Outlook - + Apple / autre + ${calendarLinksMenuHtml(linkArgs, 'repetition.ics')} ${canRemove ? `` : ''}
`; } -function renderRehearsals() { - const section = document.getElementById('rehearsals-section'); - const container = document.getElementById('rehearsals-list'); - if (!state.rehearsals.length) { - section.style.display = 'none'; - return; - } - section.style.display = ''; - container.innerHTML = state.rehearsals.map(rehearsalRowTemplate).join(''); +function wireRehearsalActions(container) { container.querySelectorAll('.remove-rehearsal-btn').forEach((btn) => { btn.addEventListener('click', () => onRemoveRehearsal(parseInt(btn.dataset.rehearsalId, 10))); }); @@ -464,6 +452,40 @@ function renderRehearsals() { }); } +function renderRehearsals() { + const section = document.getElementById('rehearsals-section'); + const container = document.getElementById('rehearsals-list'); + const votedSection = document.getElementById('rehearsals-voted-section'); + const votedSummary = document.getElementById('rehearsals-voted-summary'); + const votedContainer = document.getElementById('rehearsals-voted-list'); + + if (!state.rehearsals.length) { + section.style.display = 'none'; + return; + } + section.style.display = ''; + + const pending = state.rehearsals.filter( + (r) => !me || !r.votes.some((v) => v.userId === me.id) + ); + const voted = state.rehearsals.filter( + (r) => me && r.votes.some((v) => v.userId === me.id) + ); + + container.innerHTML = pending.map(rehearsalRowTemplate).join(''); + wireRehearsalActions(container); + + if (voted.length) { + votedSection.style.display = ''; + votedSummary.textContent = `Répétitions traitées (${voted.length})`; + votedContainer.innerHTML = voted.map(rehearsalRowTemplate).join(''); + wireRehearsalActions(votedContainer); + } else { + votedSection.style.display = 'none'; + votedContainer.innerHTML = ''; + } +} + async function onProposeRehearsal() { if (!currentModalDate) return; const { slot } = currentModalDate; diff --git a/public/js/render.js b/public/js/render.js index f0b0174..0627f18 100644 --- a/public/js/render.js +++ b/public/js/render.js @@ -118,3 +118,26 @@ function icsDataUrl({ uid, title, startISO, endISO, location }) { lines.push('END:VEVENT', 'END:VCALENDAR'); return `data:text/calendar;charset=utf-8,${encodeURIComponent(lines.join('\r\n'))}`; } + +// Single "+ Calendrier" control that reveals the 3 provider links on click, +// instead of showing all 3 pills side by side. +function calendarLinksMenuHtml(linkArgs, icsFilename) { + return ` +
+ + Calendrier +
+ Google + Outlook + Apple / autre (.ics) +
+
+ `; +} + +// Close any open "+ Calendrier" menu when picking a link inside it or +// clicking anywhere else on the page. +document.addEventListener('click', (e) => { + document.querySelectorAll('details.calendar-menu[open]').forEach((menu) => { + if (!menu.contains(e.target) || e.target.closest('a')) menu.open = false; + }); +}); diff --git a/public/js/setlistEditor.js b/public/js/setlistEditor.js index 81d42f8..09c3204 100644 --- a/public/js/setlistEditor.js +++ b/public/js/setlistEditor.js @@ -54,9 +54,7 @@ function createSetlistEditor({ }; return `
- + Google - + Outlook - + Apple / autre + ${calendarLinksMenuHtml(linkArgs, 'concert.ics')}
`; }