feat: add NIP-88 poll support

This commit is contained in:
Bhavishy
2026-04-03 01:09:00 +05:30
parent d1b868e7ba
commit 7a44bd1677
6 changed files with 30 additions and 12 deletions
+3 -1
View File
@@ -35,7 +35,9 @@
{/if} {/if}
</p> </p>
</div> </div>
<p class="whitespace-nowrap text-xs opacity-50">{$results.voters} voter{$results.voters === 1 ? "" : "s"}</p> <p class="whitespace-nowrap text-xs opacity-50">
{$results.voters} voter{$results.voters === 1 ? "" : "s"}
</p>
</div> </div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
+9 -2
View File
@@ -118,7 +118,11 @@
{#each options as option, index (index)} {#each options as option, index (index)}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<label class="input input-bordered flex w-full items-center gap-2"> <label class="input input-bordered flex w-full items-center gap-2">
<input bind:value={options[index]} class="grow" type="text" placeholder={`Option ${index + 1}`} /> <input
bind:value={options[index]}
class="grow"
type="text"
placeholder={`Option ${index + 1}`} />
</label> </label>
<Button class="btn btn-ghost btn-sm" onclick={() => removeOption(index)}> <Button class="btn btn-ghost btn-sm" onclick={() => removeOption(index)}>
<Icon icon={MinusCircle} size={4} /> <Icon icon={MinusCircle} size={4} />
@@ -150,7 +154,10 @@
Ends at Ends at
{/snippet} {/snippet}
{#snippet input()} {#snippet input()}
<input bind:value={endsAt} class="input input-bordered w-full max-w-xs" type="datetime-local" /> <input
bind:value={endsAt}
class="input input-bordered w-full max-w-xs"
type="datetime-local" />
{/snippet} {/snippet}
</FieldInline> </FieldInline>
</div> </div>
+3 -1
View File
@@ -18,7 +18,9 @@
const h = getTagValue("h", event.tags) const h = getTagValue("h", event.tags)
</script> </script>
<Link class="cv col-2 card2 bg-alt w-full cursor-pointer shadow-md" href={makePollPath(url, event.id)}> <Link
class="cv col-2 card2 bg-alt w-full cursor-pointer shadow-md"
href={makePollPath(url, event.id)}>
<NoteContent {event} {url} /> <NoteContent {event} {url} />
<div class="flex w-full flex-col items-end justify-between gap-2 sm:flex-row"> <div class="flex w-full flex-col items-end justify-between gap-2 sm:flex-row">
<span class="whitespace-nowrap py-1 text-sm opacity-75"> <span class="whitespace-nowrap py-1 text-sm opacity-75">
+9 -6
View File
@@ -33,10 +33,11 @@
const endsAt = getPollEndsAt(event) const endsAt = getPollEndsAt(event)
const results = $derived.by(() => getPollResults(event, $responses)) const results = $derived.by(() => getPollResults(event, $responses))
const ownResponse = $derived.by(() => const ownResponse = $derived.by(
$responses () =>
.filter(response => response.pubkey === $pubkey) $responses
.sort((left, right) => right.created_at - left.created_at)[0], .filter(response => response.pubkey === $pubkey)
.sort((left, right) => right.created_at - left.created_at)[0],
) )
const submit = async () => { const submit = async () => {
@@ -111,9 +112,11 @@
{/if} {/if}
<span class="truncate">{option.label}</span> <span class="truncate">{option.label}</span>
</label> </label>
<span class="whitespace-nowrap text-xs opacity-75">{current?.votes || 0} vote{(current?.votes || 0) === 1 ? "" : "s"}</span> <span class="whitespace-nowrap text-xs opacity-75"
>{current?.votes || 0} vote{(current?.votes || 0) === 1 ? "" : "s"}</span>
</div> </div>
<progress class="progress progress-primary" value={current?.votes || 0} max={maxVotes}></progress> <progress class="progress progress-primary" value={current?.votes || 0} max={maxVotes}
></progress>
</div> </div>
{/each} {/each}
</div> </div>
+1 -1
View File
@@ -5,7 +5,7 @@
import {page} from "$app/stores" import {page} from "$app/stores"
import {sortBy, partition, spec, pushToMapKey, max} from "@welshman/lib" import {sortBy, partition, spec, pushToMapKey, max} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {COMMENT, getTagValue} from "@welshman/util" import {getTagValue} from "@welshman/util"
import {fly} from "@lib/transition" import {fly} from "@lib/transition"
import PollIcon from "@assets/icons/revote.svg?dataurl" import PollIcon from "@assets/icons/revote.svg?dataurl"
import Add from "@assets/icons/add.svg?dataurl" import Add from "@assets/icons/add.svg?dataurl"
@@ -47,7 +47,11 @@
onMount(() => { onMount(() => {
const controller = new AbortController() const controller = new AbortController()
request({relays: [url], filters: [{kinds: [Poll], ids: [id]}, {kinds: [PollResponse], "#e": [id]}, ...filters], signal: controller.signal}) request({
relays: [url],
filters: [{kinds: [Poll], ids: [id]}, {kinds: [PollResponse], "#e": [id]}, ...filters],
signal: controller.signal,
})
return () => { return () => {
controller.abort() controller.abort()