import React, { useEffect, useState } from 'react'; import { Card } from './ui/card'; interface Metadata { title?: string; description?: string; favicon?: string; image?: string; url: string; } interface LinkPreviewProps { url: string; } async function fetchMetadata(url: string): Promise { try { // Fetch the HTML content using the main process const html = await window.electron.fetchMetadata(url); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const baseUrl = new URL(url); // Extract title const title = doc.querySelector('title')?.textContent || doc.querySelector('meta[property="og:title"]')?.getAttribute('content'); // Extract description const description = doc.querySelector('meta[name="description"]')?.getAttribute('content') || doc.querySelector('meta[property="og:description"]')?.getAttribute('content'); // Extract favicon const faviconLink = doc.querySelector('link[rel="icon"]') || doc.querySelector('link[rel="shortcut icon"]') || doc.querySelector('link[rel="apple-touch-icon"]') || doc.querySelector('link[rel="apple-touch-icon-precomposed"]'); let favicon = faviconLink?.getAttribute('href'); if (favicon) { favicon = new URL(favicon, baseUrl).toString(); } else { // Fallback to /favicon.ico favicon = new URL('/favicon.ico', baseUrl).toString(); } // Extract OpenGraph image let image = doc.querySelector('meta[property="og:image"]')?.getAttribute('content'); if (image) { image = new URL(image, baseUrl).toString(); } return { title: title || url, description, favicon, image, url, }; } catch (error) { console.error('❌ Error fetching metadata:', error); return { title: url, description: undefined, favicon: undefined, image: undefined, url, }; } } export default function LinkPreview({ url }: LinkPreviewProps) { const [metadata, setMetadata] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let mounted = true; const fetchData = async () => { try { const data = await fetchMetadata(url); if (mounted) { setMetadata(data); } } catch (error) { if (mounted) { console.error('❌ Failed to fetch metadata:', error); setError(error.message || 'Failed to fetch metadata'); } } finally { if (mounted) { setLoading(false); } } }; fetchData(); return () => { mounted = false; }; }, [url]); if (loading) { return null; } if (error) { return null; } if (!metadata || !metadata.title) { return null; } return ( {metadata.favicon && ( Site favicon { e.currentTarget.style.display = 'none'; }} /> )}

{metadata.title || url}

{metadata.description && (

{metadata.description}

)}
{metadata.image && ( Preview { e.currentTarget.style.display = 'none'; }} /> )}
); }