Read-it-later social network

init PublicationCard w docs + subs stats, filter empty pubs

+58 -3
+44
src/lib/components/PublicationCard.svelte
··· 1 + <script lang="ts"> 2 + import type { PublicationNode } from "$lib/utils"; 3 + import { createQuery } from "@tanstack/svelte-query"; 4 + 5 + let { publication, showEmpty = false }: { publication: PublicationNode, showEmpty?: boolean } = $props(); 6 + 7 + const countQuery = createQuery(() => ({ 8 + queryKey: ["publication", publication.uri], 9 + queryFn: async () => { 10 + const constellationUrl = new URL("https://constellation.microcosm.blue/links/all"); 11 + constellationUrl.searchParams.set("target", publication.uri); 12 + const response = await fetch(constellationUrl, { 13 + headers: { 14 + "Accept": "application/json" 15 + } 16 + }); 17 + 18 + 19 + const json = await response.json() as { links: Record<string, any> }; 20 + return json; 21 + }, 22 + staleTime: 30 * 60 * 1000, 23 + select: (data) => { 24 + const documents = Number(data.links["site.standard.document"]?.[".site"]?.records) || 0; 25 + const subscribers = Number(data.links["site.standard.graph.subscription"]?.[".publication"]?.records) || 0; 26 + return { documents, subscribers } 27 + } 28 + })); 29 + </script> 30 + 31 + {#if countQuery.isFetching} 32 + <p>Fetching...</p> 33 + {:else if countQuery.isSuccess} 34 + {#if countQuery.data.documents > 0 || showEmpty} 35 + <li class="flex flex-col gap-4 border p-4"> 36 + <a href={publication.value.url} class="w-fit">{publication.value.name}</a> 37 + <a href={`https://pdsls.dev/${publication.uri}`} target="_blank" class="w-fit border">Go to Record</a> 38 + <div class="flex gap-4"> 39 + <p>{countQuery.data.documents} Documents</p> 40 + <p>{countQuery.data.subscribers} Subscribers</p> 41 + </div> 42 + </li> 43 + {/if} 44 + {/if}
+5
src/lib/utils.ts
··· 27 27 url: string; 28 28 name: string; 29 29 description: string; 30 + icon?: string; 31 + preferences?: { 32 + showInDiscover?: boolean; 33 + hideProfile?: boolean; 34 + } 30 35 }} 31 36 32 37 export type DocumentNode = Node & { value: {
+9 -3
src/routes/+page.svelte
··· 1 1 <script lang="ts"> 2 + import PublicationCard from '$lib/components/PublicationCard.svelte'; 2 3 import type { PublicationNode } from '$lib/utils'; 3 - import { createInfiniteQuery, createQuery } from '@tanstack/svelte-query'; 4 + import { createInfiniteQuery } from '@tanstack/svelte-query'; 4 5 5 6 let { data } = $props(); 6 7 let { atclient, user } = data; ··· 43 44 })); 44 45 45 46 let currentPage = $derived(publicationsQuery.data?.slice(page*20, (page*20) + 20)); 47 + let showEmpty = $state(true); 46 48 </script> 47 49 48 50 <menu> 51 + <label for="showEmpty"> 52 + <input name="showEmpty" type="checkbox" bind:checked={showEmpty}> 53 + Show empty publication 54 + </label> 49 55 <button 50 56 onclick={() => { 51 57 if (page > 0) { ··· 71 77 </button> 72 78 {/if} 73 79 </menu> 80 + 74 81 {#if publicationsQuery.isFetching} 75 82 <p>Fetching...</p> 76 83 {:else if publicationsQuery.isError} 77 84 <p>Error</p> 78 85 {:else} 79 86 {#each currentPage as publication (publication.uri)} 80 - <a href={publication.value.url}>{publication.value.url}</a> 87 + <PublicationCard {publication} {showEmpty} /> 81 88 {/each} 82 89 {/if} 83 -