From e4e555cac32d6c6c7ddd9e9cf6dd520246b74cbe Mon Sep 17 00:00:00 2001 From: Daniel Legt Date: Sat, 7 Mar 2026 01:12:36 +0200 Subject: [PATCH] Update --- static/css/layout.css | 16 +++++++-- static/js/room.js | 81 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/static/css/layout.css b/static/css/layout.css index 127e0fc..f21d23e 100644 --- a/static/css/layout.css +++ b/static/css/layout.css @@ -362,6 +362,17 @@ body.is-dragging-window .ui-tool-title-bar { min-width: 0; } +.side-panel-window { + display: flex; + flex-direction: column; + min-width: 0; +} + +.side-panel-window > .window-content { + flex: 1; + min-height: 0; +} + .participants-window { min-height: 24rem; } @@ -421,12 +432,13 @@ body.is-dragging-window .ui-tool-title-bar { display: flex; flex-direction: column; gap: 0.55rem; - height: 100%; + flex: 1; + min-height: 0; } .participants-scroll { flex: 1; - min-height: 13rem; + min-height: 0; overflow-y: auto; } diff --git a/static/js/room.js b/static/js/room.js index de9de1c..bcbd662 100644 --- a/static/js/room.js +++ b/static/js/room.js @@ -203,7 +203,9 @@ function parseNumericVote(value) { function calculateSummary(state) { const rows = new Map(); - const numericVotes = []; + const scoreVotes = []; + const cardIndexByValue = new Map(state.cards.map((cardValue, index) => [cardValue, index])); + let hasNumericVote = false; state.participants.forEach((participant) => { if (!participant.connected) { @@ -221,26 +223,42 @@ function calculateSummary(state) { const numeric = parseNumericVote(participant.voteValue); if (numeric !== null) { - numericVotes.push(numeric); + hasNumericVote = true; + scoreVotes.push(numeric); + return; + } + + if (cardIndexByValue.has(participant.voteValue)) { + scoreVotes.push(cardIndexByValue.get(participant.voteValue)); } }); let average = null; - if (numericVotes.length > 0) { - average = numericVotes.reduce((acc, value) => acc + value, 0) / numericVotes.length; + if (scoreVotes.length > 0) { + average = scoreVotes.reduce((acc, value) => acc + value, 0) / scoreVotes.length; } - const deckNumeric = state.cards - .map(parseNumericVote) - .filter((value) => value !== null) - .sort((a, b) => a - b); - + let averageCard = null; let recommended = null; - if (average !== null && deckNumeric.length > 0) { - recommended = deckNumeric.find((value) => value >= average) ?? deckNumeric[deckNumeric.length - 1]; + if (!hasNumericVote && average !== null && state.cards.length > 0) { + const roundedIndex = Math.min( + state.cards.length - 1, + Math.max(0, Math.round(average)), + ); + averageCard = state.cards[roundedIndex]; + recommended = state.cards[roundedIndex]; + } else { + const deckNumeric = state.cards + .map(parseNumericVote) + .filter((value) => value !== null) + .sort((a, b) => a - b); + + if (average !== null && deckNumeric.length > 0) { + recommended = deckNumeric.find((value) => value >= average) ?? deckNumeric[deckNumeric.length - 1]; + } } - return { rows, average, recommended }; + return { rows, average, recommended, averageCard }; } function renderSummary(state) { @@ -251,7 +269,7 @@ function renderSummary(state) { return; } - const { rows, average, recommended } = calculateSummary(state); + const { rows, average, recommended, averageCard } = calculateSummary(state); summaryBody.innerHTML = ''; if (rows.size === 0) { @@ -274,7 +292,11 @@ function renderSummary(state) { }); } - summaryAverage.textContent = average === null ? 'Average: -' : `Average: ${average.toFixed(2)}`; + if (averageCard !== null) { + summaryAverage.textContent = `Average: ${averageCard}`; + } else { + summaryAverage.textContent = average === null ? 'Average: -' : `Average: ${average.toFixed(2)}`; + } summaryRecommended.textContent = recommended === null ? 'Recommended: -' : `Recommended: ${recommended}`; } @@ -400,6 +422,34 @@ function updateShareLink() { shareLinkInput.value = raw ? `${window.location.origin}${raw}` : ''; } +function fallbackCopyFromShareInput() { + shareLinkInput.focus(); + shareLinkInput.select(); + shareLinkInput.setSelectionRange(0, shareLinkInput.value.length); + document.execCommand('copy'); +} + +async function selectAndCopyShareLink() { + if (!shareLinkInput.value) { + return; + } + + shareLinkInput.focus(); + shareLinkInput.select(); + shareLinkInput.setSelectionRange(0, shareLinkInput.value.length); + + if (!navigator.clipboard || !window.isSecureContext) { + fallbackCopyFromShareInput(); + return; + } + + try { + await navigator.clipboard.writeText(shareLinkInput.value); + } catch (_err) { + fallbackCopyFromShareInput(); + } +} + function connectSSE() { if (eventSource) { eventSource.close(); @@ -502,6 +552,9 @@ async function changeName() { revealBtn.addEventListener('click', () => adminAction('reveal')); resetBtn.addEventListener('click', () => adminAction('reset')); shareAdminToggle.addEventListener('change', updateShareLink); +shareLinkInput.addEventListener('click', () => { + void selectAndCopyShareLink(); +}); changeNameBtn.addEventListener('click', () => { void changeName(); });