2025-07-07 22:28:36 +00:00
|
|
|
<script lang="ts">
|
2026-09-21 20:25:01 +00:00
|
|
|
import cx from "classnames"
|
|
|
|
|
import type {Readable} from "svelte/store"
|
2026-07-28 16:16:26 +00:00
|
|
|
import type {TrustedEvent} from "@welshman/util"
|
2025-09-10 22:26:39 +00:00
|
|
|
import Bolt from "@assets/icons/bolt.svg?dataurl"
|
2025-07-07 22:28:36 +00:00
|
|
|
import Icon from "@lib/components/Icon.svelte"
|
2026-09-21 20:25:01 +00:00
|
|
|
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
2025-07-07 22:28:36 +00:00
|
|
|
import ZapButton from "@app/components/ZapButton.svelte"
|
2026-09-21 20:25:01 +00:00
|
|
|
import GoalMeter from "@app/components/GoalMeter.svelte"
|
|
|
|
|
import GoalStatus from "@app/components/GoalStatus.svelte"
|
|
|
|
|
import {ENABLE_ZAPS} from "@app/env"
|
|
|
|
|
import {deriveGoalProgress} from "@app/goals"
|
|
|
|
|
import type {GoalProgress} from "@app/goals"
|
2025-07-07 22:28:36 +00:00
|
|
|
|
|
|
|
|
type Props = {
|
2025-10-06 18:23:19 +00:00
|
|
|
url?: string
|
2025-07-07 22:28:36 +00:00
|
|
|
event: TrustedEvent
|
2026-09-21 20:25:01 +00:00
|
|
|
progress?: Readable<GoalProgress>
|
2025-10-06 18:23:19 +00:00
|
|
|
class?: string
|
2025-07-07 22:28:36 +00:00
|
|
|
}
|
|
|
|
|
|
2026-09-21 20:25:01 +00:00
|
|
|
const {url, event, progress: providedProgress, ...props}: Props = $props()
|
2025-07-07 22:28:36 +00:00
|
|
|
|
2026-09-21 20:25:01 +00:00
|
|
|
// The list page already has a store per goal; reuse it instead of resubscribing.
|
|
|
|
|
const progress = providedProgress ?? deriveGoalProgress(event, url)
|
2026-07-28 16:16:26 +00:00
|
|
|
|
2026-09-21 20:25:01 +00:00
|
|
|
const backers = $derived($progress.backers.length)
|
2025-07-07 22:28:36 +00:00
|
|
|
</script>
|
|
|
|
|
|
2026-09-21 20:25:01 +00:00
|
|
|
<div class={cx("flex flex-col gap-3", props.class)}>
|
|
|
|
|
<GoalMeter progress={$progress} />
|
|
|
|
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
|
|
|
<div class="flex min-w-0 items-center gap-2">
|
|
|
|
|
{#if backers > 0}
|
|
|
|
|
<ProfileCircles pubkeys={$progress.backers} size={6} limit={5} />
|
|
|
|
|
{/if}
|
|
|
|
|
<span class="truncate text-sm text-content-muted">
|
|
|
|
|
{#if backers === 0}
|
|
|
|
|
No contributions yet
|
|
|
|
|
{:else}
|
|
|
|
|
{backers}
|
|
|
|
|
{backers === 1 ? "backer" : "backers"}
|
|
|
|
|
{/if}
|
|
|
|
|
</span>
|
2025-07-07 22:28:36 +00:00
|
|
|
</div>
|
2026-09-21 20:25:01 +00:00
|
|
|
<GoalStatus progress={$progress} />
|
2025-07-07 22:28:36 +00:00
|
|
|
</div>
|
2026-09-21 20:25:01 +00:00
|
|
|
{#if ENABLE_ZAPS && !$progress.isEnded}
|
|
|
|
|
<ZapButton {url} {event} class="button button-primary button-block">
|
|
|
|
|
<Icon icon={Bolt} />
|
|
|
|
|
{$progress.isFunded ? "Chip in anyway" : "Contribute"}
|
|
|
|
|
</ZapButton>
|
|
|
|
|
{/if}
|
2025-07-07 22:28:36 +00:00
|
|
|
</div>
|