Files
wikiplus/app/summary/[title]/page.tsx
T
2026-01-24 16:52:19 -06:00

115 lines
3.6 KiB
TypeScript

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowsRotate, faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { Button } from '@/components/ui/button';
import Image from 'next/image';
import Link from 'next/link';
import { notFound } from 'next/navigation';
import { PageTransition } from '@/components/page-transition';
interface WikipediaSummary {
title: string;
extract: string;
thumbnail?: {
source: string;
};
originalimage?: {
source: string;
};
content_urls?: {
desktop?: {
page: string;
};
};
}
async function getArticleSummary(title: string): Promise<WikipediaSummary | null> {
try {
// Wikipedia API expects underscores instead of %20 for spaces
const apiTitle = title.replace(/%20/g, '_');
const response = await fetch(
`https://en.wikipedia.org/api/rest_v1/page/summary/${apiTitle}`,
{
headers: {
'User-Agent': 'WikiPlus/1.0',
},
cache: 'no-store',
}
);
if (!response.ok) {
return null;
}
return await response.json();
} catch (error) {
console.error('Error fetching article summary:', error);
return null;
}
}
export default async function SummaryPage({
params,
}: {
params: Promise<{ title: string }>;
}) {
const { title } = await params;
const article = await getArticleSummary(title);
if (!article) {
notFound();
}
const imageUrl = article.thumbnail?.source || article.originalimage?.source;
const pageUrl = article.content_urls?.desktop?.page;
return (
<main className="min-h-screen py-10 sm:py-16 px-4 sm:px-6 overflow-hidden">
<div className="max-w-2xl mx-auto">
<header className="mb-8 sm:mb-12 animate-[slideInFromTop_0.6s_ease-out]">
<Link href="/" className="text-gray-500 hover:text-gray-300 text-sm uppercase tracking-widest mb-4 inline-block transition-colors">
Wiki<span className="text-blue-500">+</span>
</Link>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-light text-gray-100 tracking-tight">
{article.title}
</h1>
</header>
{imageUrl && (
<div className="relative w-full aspect-video mb-8 sm:mb-10 rounded-lg overflow-hidden bg-gray-800/50 animate-[fadeInScale_0.8s_ease-out_0.2s_both]">
<Image
src={imageUrl}
alt={article.title}
fill
className="object-contain"
priority
/>
</div>
)}
<article className="mb-8 sm:mb-12 animate-[slideInFromBottom_0.6s_ease-out_0.4s_both]">
<p className="text-gray-300 text-lg sm:text-xl leading-relaxed font-light">
{article.extract}
</p>
</article>
<footer className="flex flex-col-reverse sm:flex-row items-center justify-between gap-4 pt-6 sm:pt-8 border-t border-gray-800 animate-[slideInFromBottom_0.6s_ease-out_0.6s_both]">
<Link
href={`/article/${encodeURIComponent(article.title)}`}
className="text-gray-500 hover:text-gray-300 text-sm inline-flex items-center gap-2 transition-colors"
>
Full article
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="text-xs" />
</Link>
<PageTransition href="/random">
<Button variant="outline" className="gap-2 hover:scale-105 active:scale-95 transition-transform w-full sm:w-auto">
<FontAwesomeIcon icon={faArrowsRotate} />
New Article
</Button>
</PageTransition>
</footer>
</div>
</main>
);
}