my website at ewancroft.uk
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>