flotilla/src/app/components/PollOption.svelte

73 lines
2.3 KiB
Svelte
Raw Normal View History

2026-04-03 17:54:50 +00:00
<script lang="ts">
import {tweened} from "svelte/motion"
import type {TrustedEvent} from "@welshman/util"
2026-07-28 16:16:26 +00:00
import {noop, spec} from "@welshman/lib"
import {Poll} from "@welshman/domain"
2026-04-03 17:54:50 +00:00
import {stopPropagation} from "@lib/html"
2026-07-28 16:16:26 +00:00
import {reader} from "@app/core"
2026-04-03 17:54:50 +00:00
type Props = {
event: TrustedEvent
option: {id: string; label: string}
results: {voters: number; options: {id: string; votes: number}[]}
selectedIds: string[]
setSingleChoice: (id: string) => void
toggleMultipleChoice: (id: string) => void
}
const {event, option, results, selectedIds, setSingleChoice, toggleMultipleChoice}: Props =
$props()
2026-07-28 16:16:26 +00:00
const poll = reader(Poll)(event)
const pollType = poll.pollType()
const closed = poll.isClosed()
2026-04-03 17:54:50 +00:00
const selected = $derived(
pollType === "singlechoice" ? selectedIds[0] === option.id : selectedIds.includes(option.id),
)
const onselect = () =>
pollType === "singlechoice" ? setSingleChoice(option.id) : toggleMultipleChoice(option.id)
2026-07-28 16:16:26 +00:00
const votes = $derived(results.options.find(spec({id: option.id}))?.votes || 0)
2026-04-03 17:54:50 +00:00
const maxVotes = $derived(Math.max(...results.options.map(r => r.votes), 1))
const tweenedVotes = tweened(votes, {duration: 300})
const tweenedMax = tweened(maxVotes, {duration: 300})
$effect(() => {
tweenedVotes.set(votes)
})
$effect(() => {
tweenedMax.set(maxVotes)
})
</script>
<div class="flex flex-col gap-2 card card-sm">
2026-04-03 17:54:50 +00:00
<div class="flex items-center justify-between gap-2">
2026-04-07 21:53:19 +00:00
<label class="flex min-w-0 grow items-center gap-2">
2026-04-03 17:54:50 +00:00
{#if !closed}
{#if pollType === "singlechoice"}
<input
name={event.id}
type="radio"
class="radio"
2026-04-03 17:54:50 +00:00
checked={selected}
onclick={stopPropagation(noop)}
onchange={onselect} />
{:else}
<input
type="checkbox"
class="checkbox"
2026-04-03 17:54:50 +00:00
checked={selected}
onclick={stopPropagation(noop)}
onchange={onselect} />
{/if}
{/if}
<span class="truncate">{option.label}</span>
</label>
<span class="whitespace-nowrap text-xs opacity-75">{votes} vote{votes === 1 ? "" : "s"}</span>
</div>
<progress class="progress" value={$tweenedVotes} max={$tweenedMax}></progress>
2026-04-03 17:54:50 +00:00
</div>