b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 1 | <script lang="ts"> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 2 | import { messageMediaUrl } from './api'; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 3 | import type { LinkPreview } from './types'; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 4 | import type { UrlPreview } from './urls'; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 5 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 6 | export let link: UrlPreview; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 7 | export let preview: LinkPreview | null = null; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 8 | export let imageUrl: (mediaId: string) => string = (mediaId) => messageMediaUrl(mediaId, 'Thumbnail'); |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 9 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 10 | const BANNER_MIN_WIDTH = 320; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 11 | const BANNER_MIN_ASPECT = 1.3; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 12 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 13 | let imageFailed = false; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 14 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 15 | $: image = preview?.image && !imageFailed ? preview.image : null; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 16 | $: imageSrc = image ? imageUrl(image.media_id) : null; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 17 | $: banner = |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 18 | image !== null && |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 19 | image.width !== null && |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 20 | image.height !== null && |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 21 | image.width >= BANNER_MIN_WIDTH && |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 22 | image.width / image.height >= BANNER_MIN_ASPECT; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 23 | $: rich = Boolean(preview && (preview.title || preview.description)); |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 24 | $: if (preview) imageFailed = false; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 25 | </script> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 26 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 27 | <a class="link-card" class:rich class:banner href={link.href} target="_blank" rel="noopener noreferrer"> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 28 | {#if rich && preview} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 29 | <span class="body"> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 30 | <span class="link-host">{preview.site_name ?? link.hostname}</span> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 31 | {#if preview.title}<span class="link-title">{preview.title}</span>{/if} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 32 | {#if preview.description}<span class="link-desc">{preview.description}</span>{/if} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 33 | </span> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 34 | {:else} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 35 | <span class="body"> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 36 | <span class="link-host">{link.hostname}</span> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 37 | {#if link.path}<span class="link-path">{link.path}</span>{/if} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 38 | <span class="link-url">{link.display}</span> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 39 | </span> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 40 | {/if} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 41 | {#if imageSrc} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 42 | <img class="link-image" src={imageSrc} alt="" loading="lazy" on:error={() => (imageFailed = true)} /> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 43 | {/if} |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 44 | </a> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 45 | |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 46 | <style> |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 47 | .link-card { |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 48 | display: flex; gap: 10px; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 49 | border: 1px solid var(--border); border-radius: 8px; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 50 | background: var(--bg-soft); padding: 8px 10px; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 51 | text-decoration: none; color: var(--text); |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 52 | overflow: hidden; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 53 | } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 54 | .link-card.rich { border-left: 3px solid var(--accent); } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 55 | .link-card.banner { flex-direction: column; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 56 | .link-card:hover { border-color: var(--accent); } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 57 | .body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 58 | .link-host { font-size: 12.5px; font-weight: 650; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 59 | .rich .link-host { font-size: 11.5px; font-weight: 600; color: var(--muted); } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 60 | .link-title { font-size: 14px; font-weight: 650; color: var(--accent); overflow-wrap: anywhere; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 61 | .link-desc { |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 62 | font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 63 | display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 64 | } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 65 | .link-path { font-size: 12px; color: var(--muted); overflow-wrap: anywhere; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 66 | .link-url { font-size: 11.5px; color: var(--accent); overflow-wrap: anywhere; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 67 | .link-image { flex: none; width: 72px; height: 72px; object-fit: cover; border-radius: 6px; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 68 | .banner .link-image { width: 100%; height: auto; max-height: 220px; } |
b8ab00377c20 | atagen | 2026-10-22 05:13 UTC | 69 | </style> |