interface LinkCardProps {
title?: string
description?: string
url: string
image?: string
}
async function fetchOGMetadata(url: string) {
try {
const response = await fetch(url, {
next: { revalidate: 86400 }, // Cache for 24 hours
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; Standard.site/1.0; +https://standard.site)'
}
})
if (!response.ok) {
console.warn(`Failed to fetch ${url}: ${response.status}`)
return null
}
const html = await response.text()
const urlObj = new URL(url)
// Extract OG metadata - try both property and name attributes
let ogImage =
html.match(/]*property=["']og:image["'][^>]*content=["']([^"']*)["']/i)?.[1] ||
html.match(/]*content=["']([^"']*)["'][^>]*property=["']og:image["']/i)?.[1]
const ogTitle =
html.match(/]*property=["']og:title["'][^>]*content=["']([^"']*)["']/i)?.[1] ||
html.match(/]*content=["']([^"']*)["'][^>]*property=["']og:title["']/i)?.[1]
const ogDescription =
html.match(/]*property=["']og:description["'][^>]*content=["']([^"']*)["']/i)?.[1] ||
html.match(/]*content=["']([^"']*)["'][^>]*property=["']og:description["']/i)?.[1]
// Resolve relative image URLs to absolute
if (ogImage && !ogImage.startsWith('http')) {
if (ogImage.startsWith('//')) {
ogImage = `${urlObj.protocol}${ogImage}`
} else if (ogImage.startsWith('/')) {
ogImage = `${urlObj.protocol}//${urlObj.host}${ogImage}`
} else {
ogImage = `${urlObj.protocol}//${urlObj.host}/${ogImage}`
}
}
return {
image: ogImage || null,
title: ogTitle || null,
description: ogDescription || null
}
} catch (error) {
console.error('Failed to fetch OG metadata from', url, error)
return null
}
}
export async function LinkCard({ title, description, url, image }: LinkCardProps) {
const urlObj = new URL(url)
const hostname = urlObj.hostname.replace('www.', '')
// Fetch OG metadata if not provided
const metadata = await fetchOGMetadata(url)
const finalTitle = title || metadata?.title || hostname
const finalDescription = description || metadata?.description || ''
const finalImage = image || metadata?.image
urlObj.searchParams.set('utm_source', 'standard.site')
urlObj.searchParams.set('utm_medium', 'docs')
urlObj.searchParams.set('utm_campaign', 'implementations')
return (
{finalTitle}
{finalDescription && (
{finalDescription}
)}
{hostname}
{finalImage && (
)}
)
}