Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101<script lang="ts"> import Button from '$lib/components/ui/Button.svelte'; import UserRoundPlus from '$icon/user-round-plus'; import UserRoundMinus from '$icon/user-round-minus'; import { getAuth } from '$lib/auth.svelte'; import { createFollow, deleteFollow } from '$lib/api/graph'; import { getProfileCounts } from './counts.svelte'; import type { FollowChange } from './types'; import { createOptimisticRelation } from '$lib/optimistic.svelte';
interface Props { profileDid: string; initialRkey?: string | null; size?: 'sm' | 'md'; onCommit?: (change: FollowChange) => void; }
let { profileDid, initialRkey, size = 'sm', onCommit }: Props = $props();
const auth = getAuth(); const profileCounts = getProfileCounts(); const signedIn = $derived(Boolean(auth.currentDid)); const isSelf = $derived(auth.currentDid === profileDid); const relation = createOptimisticRelation({ key: () => `${auth.currentDid ?? ''}:${profileDid}`, loadedRkey: () => initialRkey });
let busy = $state(false); const following = $derived(relation.active);
const commit = (change: FollowChange) => { profileCounts?.adjust(change.subjectDid, 'followers', change.delta); profileCounts?.adjust(change.viewerDid, 'following', change.delta); onCommit?.(change); };
const toggle = async () => { const agent = auth.agent; if (!agent || busy || !relation.known) return; busy = true; relation.resetFailure(); try { if (relation.active && relation.rkey) { await deleteFollow(agent, relation.rkey); relation.deleted(); commit({ viewerDid: agent.sub, subjectDid: profileDid, following: false, rkey: null, delta: -1 }); } else { const rkey = await createFollow(agent, profileDid); relation.created(rkey); commit({ viewerDid: agent.sub, subjectDid: profileDid, following: true, rkey, delta: 1 }); } } catch { relation.fail(); } finally { busy = false; } };</script>
{#if !isSelf} {#if !signedIn} <Button href="/login" variant="default" {size} class="w-full gap-2"> <UserRoundPlus class="size-4" aria-hidden="true" /><span>Follow</span> </Button> {:else} <div class="w-full"> <Button variant="default" {size} class="w-full gap-2" loading={busy} disabled={!relation.known} onclick={toggle} > {#if following} <UserRoundMinus class="size-4" aria-hidden="true" /> {:else} <UserRoundPlus class="size-4" aria-hidden="true" /> {/if} <span>{following ? 'Unfollow' : 'Follow'}</span> </Button> {#if relation.failed} <p class="mt-1 text-xs text-danger">Something went wrong. Try again.</p> {/if} </div> {/if}{/if}