import { FaMastodon } from 'react-icons/fa'; import { FiArrowRight } from 'react-icons/fi'; import { siteConfig } from '@/lib/config'; import { parseMastodonUrl, stripHtml, truncateText, formatRelativeTime, type MastodonStatus } from '@/lib/mastodon'; /** * Fetch user's Mastodon account ID from username with ISR */ async function fetchAccountId(instance: string, username: string): Promise { try { const response = await fetch( `https://${instance}/api/v1/accounts/lookup?acct=${username}`, { next: { revalidate: 1800 } // Revalidate every 30 minutes } ); if (!response.ok) return null; const account = await response.json(); return account.id; } catch (error) { console.error('Error fetching Mastodon account:', error); return null; } } /** * Fetch user's recent statuses from Mastodon with ISR */ async function fetchStatuses( instance: string, accountId: string, limit: number = 5 ): Promise { try { const response = await fetch( `https://${instance}/api/v1/accounts/${accountId}/statuses?limit=${limit}&exclude_replies=true`, { next: { revalidate: 1800 } // Revalidate every 30 minutes } ); if (!response.ok) return []; const statuses = await response.json(); return statuses; } catch (error) { console.error('Error fetching Mastodon statuses:', error); return []; } } /** * Server Component for Mastodon feed with ISR */ export async function MastodonFeed() { const mastodonUrl = siteConfig.social.mastodon; // Don't render if no Mastodon URL is configured if (!mastodonUrl) { return null; } let statuses: MastodonStatus[] = []; try { // Parse the Mastodon URL const parsed = parseMastodonUrl(mastodonUrl); if (!parsed) { return null; } const { instance, username } = parsed; // Fetch account ID const accountId = await fetchAccountId(instance, username); if (!accountId) { return null; } // Fetch statuses (5 posts, exclude replies, include boosts) statuses = await fetchStatuses(instance, accountId, 5); } catch (err) { console.error('Error loading Mastodon feed:', err); // Fail silently - don't render component on error return null; } // Don't render if no statuses if (statuses.length === 0) { return null; } return (
{/* Header */}
微網誌
{/* Content */}
{statuses.map((status) => { // Handle boosts (reblogs) const displayStatus = status.reblog || status; const content = stripHtml(displayStatus.content); const truncated = truncateText(content, 180); const relativeTime = formatRelativeTime(status.created_at); const hasMedia = displayStatus.media_attachments.length > 0; return ( ); })}
{/* Footer link */} 查看更多
); }