your personal website on atproto - mirror blento.app
at improve-oauth-permissions 123 lines 3.8 kB view raw
1<script lang="ts"> 2 import type { Item } from '$lib/types'; 3 import { onMount } from 'svelte'; 4 import { getAdditionalUserData, getDidContext, getHandleContext } from '$lib/website/context'; 5 import { CardDefinitionsByType } from '../..'; 6 import type { SembleCollectionData } from './index'; 7 8 let { item }: { item: Item } = $props(); 9 10 const additionalData = getAdditionalUserData(); 11 let did = getDidContext(); 12 let handle = getHandleContext(); 13 14 let key = $derived(`${item.cardData.handle}/${item.cardData.collectionRkey}`); 15 16 // svelte-ignore state_referenced_locally 17 let collectionData = $state( 18 additionalData[item.cardType] != null 19 ? (additionalData[item.cardType] as Record<string, SembleCollectionData>)[key] 20 : undefined 21 ); 22 23 onMount(async () => { 24 if (!collectionData) { 25 const result = (await CardDefinitionsByType[item.cardType]?.loadData?.([item], { 26 did, 27 handle 28 })) as Record<string, SembleCollectionData>; 29 30 if (result) { 31 additionalData[item.cardType] = { 32 ...((additionalData[item.cardType] as Record<string, SembleCollectionData>) ?? {}), 33 ...result 34 }; 35 collectionData = result[key]; 36 } 37 } 38 }); 39 40 function getDisplayUrl(url: string) { 41 try { 42 const u = new URL(url); 43 return u.hostname + (u.pathname !== '/' ? u.pathname : ''); 44 } catch { 45 return url; 46 } 47 } 48 49 function truncate(text: string, max: number) { 50 if (text.length <= max) return text; 51 return text.slice(0, max) + '…'; 52 } 53</script> 54 55<div class={['flex h-full flex-col overflow-y-auto px-5 py-4', item.cardData.label ? 'pt-12' : '']}> 56 {#if collectionData} 57 <div class="mb-3 flex flex-col gap-1"> 58 <h3 class="text-base-900 dark:text-base-100 accent:text-black text-sm font-semibold"> 59 {collectionData.name} 60 </h3> 61 {#if collectionData.description} 62 <p class="text-base-500 dark:text-base-400 accent:text-black/60 text-xs"> 63 {collectionData.description} 64 </p> 65 {/if} 66 </div> 67 68 {#if collectionData.cards.length > 0} 69 <div class="flex flex-col gap-3"> 70 {#each collectionData.cards as card (card.uri)} 71 {#if card.type === 'URL' && card.url} 72 <a 73 href={card.url} 74 target="_blank" 75 rel="noopener noreferrer" 76 class="bg-base-100 dark:bg-base-800 accent:bg-black/10 hover:bg-base-200 dark:hover:bg-base-700 accent:hover:bg-black/15 flex flex-col gap-1.5 rounded-xl px-5 py-3 transition-colors" 77 > 78 {#if card.title} 79 <span 80 class="text-base-900 dark:text-base-100 accent:text-black text-sm leading-snug font-medium" 81 > 82 {truncate(card.title, 80)} 83 </span> 84 {/if} 85 {#if card.description} 86 <span 87 class="text-base-600 dark:text-base-400 accent:text-black/70 text-xs leading-snug" 88 > 89 {truncate(card.description, 120)} 90 </span> 91 {/if} 92 <span class="text-base-400 dark:text-base-500 accent:text-black/60 truncate text-xs"> 93 {getDisplayUrl(card.url)} 94 </span> 95 </a> 96 {:else if card.type === 'NOTE' && card.text} 97 <div 98 class="bg-base-100 dark:bg-base-800 accent:bg-black/10 flex flex-col gap-1.5 rounded-xl px-5 py-3" 99 > 100 <span 101 class="text-base-700 dark:text-base-300 accent:text-black/80 border-accent-500 accent:border-black/60 border-l-2 pl-3 text-sm leading-snug italic" 102 > 103 {truncate(card.text, 200)} 104 </span> 105 </div> 106 {/if} 107 {/each} 108 </div> 109 {:else} 110 <div 111 class="text-base-500 dark:text-base-400 accent:text-black/60 flex flex-1 items-center justify-center text-center text-sm" 112 > 113 No cards in this collection yet. 114 </div> 115 {/if} 116 {:else} 117 <div 118 class="text-base-500 dark:text-base-400 accent:text-black/60 flex h-full w-full items-center justify-center text-center text-sm" 119 > 120 Loading... 121 </div> 122 {/if} 123</div>