Tie break timer and main block timer together

- Starting break now pauses the main block timer (frontend optimistic +
  backend implicit pause event recorded before break_start)
- Resuming/starting the main block while break is active pauses the
  break timer and exits break mode on all clients including TV
- Timer display counts negative past zero so overtime is visible while
  label stays "Done!"
- Fixed WS start handler incorrectly skipping break-mode clear when
  restarting the same block; resume handler now also clears break mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 14:24:50 -08:00
parent c565c94a23
commit a8e1b322f1
4 changed files with 73 additions and 16 deletions

View File

@@ -58,10 +58,12 @@ const elapsed = computed(() => {
const remaining = computed(() => Math.max(0, blockDuration.value - elapsed.value))
const display = computed(() => {
const s = remaining.value
const m = Math.floor(s / 60)
const sec = s % 60
return `${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`
const s = blockDuration.value - elapsed.value
if (s < 0) {
const abs = Math.abs(s)
return `-${String(Math.floor(abs / 60)).padStart(2, '0')}:${String(abs % 60).padStart(2, '0')}`
}
return `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`
})
const label = computed(() => {
@@ -72,7 +74,7 @@ const label = computed(() => {
const CIRCUMFERENCE = 2 * Math.PI * 88
const dashOffset = computed(() => {
if (!blockDuration.value) return CIRCUMFERENCE
const pct = remaining.value / blockDuration.value
const pct = Math.max(0, remaining.value / blockDuration.value)
return CIRCUMFERENCE * (1 - pct)
})