my website at ewancroft.uk
at main 2.1 kB view raw
1<script lang="ts"> 2 import { ExternalLink, Tag } from '@lucide/svelte'; 3 import type { BlogPost } from '$lib/services/atproto'; 4 import { InternalCard } from '$lib/components/ui'; 5 import { getPostBadges, getBadgeClasses } from '$lib/helper/badges'; 6 import { formatLocalizedDate } from '$lib/utils/locale'; 7 8 interface Props { 9 post: BlogPost; 10 locale?: string; 11 } 12 13 let { post, locale }: Props = $props(); 14 15 const badges = $derived(getPostBadges(post)); 16</script> 17 18<InternalCard href={post.url}> 19 {#snippet children()} 20 <div class="relative min-w-0 flex-1 space-y-2"> 21 <!-- Badges: Platform and Publication --> 22 {#if badges.length > 0} 23 <div class="flex flex-wrap items-center gap-2"> 24 {#each badges as badge} 25 <span class={getBadgeClasses(badge)}> 26 {badge.text} 27 </span> 28 {/each} 29 </div> 30 {/if} 31 32 <!-- Title --> 33 <h4 34 class="overflow-wrap-anywhere font-semibold wrap-break-word text-ink-900 dark:text-ink-50" 35 > 36 {post.title} 37 </h4> 38 39 <!-- Description --> 40 {#if post.description} 41 <p 42 class="overflow-wrap-anywhere line-clamp-2 text-sm wrap-break-word text-ink-700 dark:text-ink-200" 43 > 44 {post.description} 45 </p> 46 {/if} 47 48 <!-- Timestamp --> 49 <div class="pt-1"> 50 <p class="text-xs font-medium text-ink-800 dark:text-ink-100"> 51 {formatLocalizedDate(post.createdAt, locale)} 52 </p> 53 </div> 54 </div> 55 56 <!-- Right column: External Link Icon and Tags --> 57 <div class="flex shrink-0 flex-col items-end justify-between gap-2 self-stretch"> 58 <!-- External Link Icon --> 59 <ExternalLink 60 class="h-4 w-4 text-ink-700 transition-colors dark:text-ink-200" 61 aria-hidden="true" 62 /> 63 64 <!-- Tags --> 65 {#if post.tags && post.tags.length > 0} 66 <div class="flex items-center gap-1.5 rounded bg-ink-100 px-2 py-0.5 dark:bg-ink-800"> 67 <Tag class="h-3 w-3 text-ink-700 dark:text-ink-200" aria-hidden="true" /> 68 <span class="text-xs font-medium text-ink-800 dark:text-ink-100"> 69 {post.tags.length} 70 </span> 71 </div> 72 {/if} 73 </div> 74 {/snippet} 75</InternalCard>