Thread viewer for Bluesky
at 2.0 49 lines 1.4 kB view raw
1<script lang="ts"> 2 import { getPostContext } from '../posts/PostComponent.svelte'; 3 import { isValidURL, truncateText } from '../../utils.js'; 4 import GIFPlayer from './GIFPlayer.svelte'; 5 import { InlineLinkEmbed, RawLinkEmbed } from '../../models/embeds.js'; 6 7 let { embed }: { embed: InlineLinkEmbed | RawLinkEmbed } = $props(); 8 let { post } = getPostContext(); 9 10 let showingGIF = $state(false); 11 12 let hostname = $derived(new URL(embed.url).hostname); 13 let isTenorGIF = $derived(hostname == 'media.tenor.com'); 14 let onclick = $derived(isTenorGIF ? playGIF : undefined); 15 16 function playGIF(e: Event) { 17 e.preventDefault(); 18 showingGIF = true; 19 } 20 21 function thumbnailURL() { 22 if (typeof embed.thumb == 'string') { 23 return embed.thumb; 24 } else { 25 return `https://cdn.bsky.app/img/avatar/feed_thumbnail/${post.author.did}/${embed.thumb.ref.$link}@jpeg`; 26 } 27 } 28</script> 29 30{#if showingGIF} 31 <GIFPlayer gifURL={embed.url} staticURL={thumbnailURL()} alt={embed.title} /> 32{:else} 33 {#if isValidURL(embed.url)} 34 <a class="link-card" href={embed.url} target="_blank" {onclick}> 35 <div> 36 <p class="domain">{hostname}</p> 37 <h2>{embed.title || embed.url}</h2> 38 39 {#if embed.description} 40 <p class="description">{truncateText(embed.description, 300)}</p> 41 {/if} 42 </div> 43 </a> 44 {:else} 45 <p> 46 [Link: {embed.url}] 47 </p> 48 {/if} 49{/if}