This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / components / repo / StarButton.svelte
2.6 kB 96 lines
1<script lang="ts"> 2 import Star from "$icon/star"; 3 import { getAuth } from "$lib/auth.svelte"; 4 import { createStar, deleteStar } from "$lib/api/graph"; 5 import Button from "$lib/components/ui/Button.svelte"; 6 import ButtonGroup from "$lib/components/ui/ButtonGroup.svelte"; 7 import { getProfileCounts } from "$lib/components/profile/counts.svelte"; 8 import { createOptimisticRelation, createOptimisticCount } from "$lib/optimistic.svelte"; 9 10 interface Props { 11 repoDid: string; 12 repoOwnerHandle: string; 13 repoName: string; 14 initialCount?: number; 15 initialRkey?: string | null; 16 } 17 18 let { repoDid, repoOwnerHandle, repoName, initialCount, initialRkey }: Props = $props(); 19 20 const auth = getAuth(); 21 const profileCounts = getProfileCounts(); 22 const signedIn = $derived(Boolean(auth.currentDid)); 23 const relation = createOptimisticRelation({ 24 key: () => `${auth.currentDid ?? ""}:${repoDid}`, 25 loadedRkey: () => initialRkey 26 }); 27 const starCount = createOptimisticCount({ 28 key: () => repoDid, 29 loaded: () => initialCount 30 }); 31 32 let busy = $state(false); 33 const starred = $derived(relation.active); 34 const failed = $derived(relation.failed || starCount.failed); 35 36 const toggle = async () => { 37 const agent = auth.agent; 38 if (!agent || busy || !relation.known || !repoDid) return; 39 busy = true; 40 relation.resetFailure(); 41 starCount.resetFailure(); 42 try { 43 if (relation.active && relation.rkey) { 44 await deleteStar(agent, relation.rkey); 45 relation.deleted(); 46 starCount.adjust(-1); 47 profileCounts?.adjust(agent.sub, "stars", -1); 48 } else { 49 const rkey = await createStar(agent, repoDid); 50 relation.created(rkey); 51 starCount.adjust(1); 52 profileCounts?.adjust(agent.sub, "stars", 1); 53 } 54 } catch { 55 relation.fail(); 56 starCount.fail(); 57 } finally { 58 busy = false; 59 } 60 }; 61</script> 62 63{#if signedIn && repoDid} 64 <div class="flex flex-col items-end"> 65 <ButtonGroup> 66 <Button 67 variant="default" 68 size="sm" 69 insetShadow={true} 70 class="flex-1" 71 loading={busy} 72 disabled={!relation.known} 73 onclick={toggle} 74 > 75 <Star 76 class={`size-4 shrink-0 ${starred ? "[&_path]:fill-[currentColor]" : ""}`} 77 aria-hidden="true" 78 /> 79 <span>{starred ? "Unstar" : "Star"}</span> 80 </Button> 81 <Button 82 href={`/${repoOwnerHandle}/${repoName}/stars`} 83 variant="ghost" 84 size="sm" 85 title="Starred by" 86 > 87 {starCount.value} 88 </Button> 89 </ButtonGroup> 90 {#if failed} 91 <p class="mt-1 typography-paragraph-small text-foreground-danger"> 92 Something went wrong. Try again. 93 </p> 94 {/if} 95 </div> 96{/if}