feat: add NIP-88 poll support
This commit is contained in:
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user