From f0a8c32ea2f2e5602fd857866a913a625dae991b Mon Sep 17 00:00:00 2001 From: Mikhail Kiselev Date: Tue, 10 Feb 2026 18:15:18 +0300 Subject: [PATCH] feat: show spent time in participant list, fix timer sounds --- frontend/src/App.svelte | 8 ++- .../src/components/ParticipantList.svelte | 57 ++++++++++++++++--- internal/models/types.go | 1 + internal/timer/timer.go | 16 +++++- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index c83f3c3..1aa4847 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -162,7 +162,13 @@ } } - function playSound(name) { + async function playSound(name) { + // Ensure AudioContext is running (may be suspended after inactivity) + const ctx = getAudioContext() + if (ctx.state === 'suspended') { + await ctx.resume() + } + switch (name) { case 'warning': playBeep(880, 0.15) diff --git a/frontend/src/components/ParticipantList.svelte b/frontend/src/components/ParticipantList.svelte index 48f48cf..bc75458 100644 --- a/frontend/src/components/ParticipantList.svelte +++ b/frontend/src/components/ParticipantList.svelte @@ -8,10 +8,17 @@ $: allSpeakers = timerState?.allSpeakers || [] $: currentSpeakerId = timerState?.currentSpeakerId || 0 + $: currentElapsed = timerState?.speakerElapsed || 0 function handleSkip(speakerId) { dispatch('skip', { speakerId }) } + + function formatTime(seconds) { + const mins = Math.floor(seconds / 60) + const secs = seconds % 60 + return `${mins}:${secs.toString().padStart(2, '0')}` + }
@@ -23,7 +30,23 @@
  • {speaker.order} {speaker.name} - {Math.floor(speaker.timeLimit / 60)}:{(speaker.timeLimit % 60).toString().padStart(2, '0')} + + {#if speaker.status === 'done'} + speaker.timeLimit}> + {formatTime(speaker.timeSpent)} + + / + {formatTime(speaker.timeLimit)} + {:else if speaker.status === 'speaking'} + speaker.timeLimit}> + {formatTime(currentElapsed)} + + / + {formatTime(speaker.timeLimit)} + {:else} + {formatTime(speaker.timeLimit)} + {/if} + {#if speaker.status === 'pending' || speaker.status === 'skipped'}