LinkOpenGraphCard

2 variants. Open one in isolation: use the link on each card.


src/ui/2_organisms/LinkOpenGraphCard.astro
---
import type { LinkOpenGraphPreview } from '../../lib/link-open-graph'
import '../../styles/link-open-graph-preview.css'
interface Props {
href: string
openGraphPreview: LinkOpenGraphPreview | null
}
const { href, openGraphPreview } = Astro.props
const domain = (() => {
try {
return new URL(href).hostname
} catch {
return href
}
})()
const previewTitle = openGraphPreview?.title?.trim() || null
const previewDescription = openGraphPreview?.description?.trim() || null
const previewImage = openGraphPreview?.imageUrl ?? null
const previewSite = openGraphPreview?.siteName?.trim() || null
const showRichPreview =
Boolean(previewImage) || Boolean(previewDescription) || Boolean(previewSite) || Boolean(previewTitle)
const ariaSourceName = previewTitle || domain
---
<a
href={href}
target="_blank"
rel="noopener noreferrer"
class:list={['source-card', 'meta', showRichPreview ? 'link-preview-rich' : 'link-preview-compact']}
style="border: 1px solid var(--border); text-decoration: none;"
aria-label={`Visit source: ${ariaSourceName} at ${domain}`}
>
{
showRichPreview ? (
<div class="link-preview-rich-inner" {...(previewImage ? { 'data-og-preview': 'true' } : {})}>
{previewImage ? (
<div class="link-preview-image-wrap">
<img
src={previewImage}
alt=""
width={320}
height={180}
loading="lazy"
decoding="async"
referrerpolicy="no-referrer"
class="link-preview-image"
/>
</div>
) : null}
<div class="link-preview-body">
<div class="link-preview-body-header">
<div class="link-preview-source-col">
<div class="link-preview-source-label">Source</div>
<div class="link-preview-source-site">{previewSite ?? domain}</div>
</div>
<span class="link-preview-visit-badge">Visit ↗</span>
</div>
{(previewTitle || previewDescription) && (
<div class="link-preview-title-block">
{previewTitle ? <div class="link-preview-title-text">{previewTitle}</div> : null}
{previewDescription ? <p class="link-preview-desc-text">{previewDescription}</p> : null}
</div>
)}
</div>
</div>
) : (
<>
<div class="link-preview-compact-leading">
<div class="link-preview-source-label">Source</div>
<div class="link-preview-source-site">{domain}</div>
</div>
<span class="link-preview-visit-badge link-preview-visit-badge--compact">Visit ↗</span>
</>
)
}
</a>