153 lines
5.5 KiB
TypeScript
153 lines
5.5 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useParams, Link } from 'react-router-dom';
|
|
import { ArrowLeft, Clock, Share2, Bookmark } from 'lucide-react';
|
|
import { Header } from '../components/Header';
|
|
import { ReactionButtons } from '../components/ReactionButtons';
|
|
import { PhotoGallery } from '../components/PhotoGallery';
|
|
import { articles } from '../data/mock';
|
|
import { Article } from '../types';
|
|
|
|
export function ArticlePage() {
|
|
const { id } = useParams();
|
|
const [articleData, setArticleData] = useState<Article | undefined>(
|
|
articles.find(a => a.id === id)
|
|
);
|
|
|
|
useEffect(() => {
|
|
window.scrollTo(0, 0);
|
|
}, [id]);
|
|
|
|
if (!articleData) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<div className="text-center">
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">Article not found</h2>
|
|
<Link to="/" className="text-blue-600 hover:text-blue-800">
|
|
Return to homepage
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const handleReaction = (reaction: 'like' | 'dislike') => {
|
|
setArticleData(prev => {
|
|
if (!prev) return prev;
|
|
|
|
const newArticle = { ...prev };
|
|
|
|
if (prev.userReaction === 'like') newArticle.likes--;
|
|
if (prev.userReaction === 'dislike') newArticle.dislikes--;
|
|
|
|
if (prev.userReaction !== reaction) {
|
|
if (reaction === 'like') newArticle.likes++;
|
|
if (reaction === 'dislike') newArticle.dislikes++;
|
|
newArticle.userReaction = reaction;
|
|
} else {
|
|
newArticle.userReaction = null;
|
|
}
|
|
|
|
return newArticle;
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
<Header />
|
|
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
<Link
|
|
to="/"
|
|
className="inline-flex items-center text-gray-600 hover:text-gray-900 mb-8"
|
|
>
|
|
<ArrowLeft size={20} className="mr-2" />
|
|
Back to articles
|
|
</Link>
|
|
|
|
<article>
|
|
{/* Article Header */}
|
|
<div className="mb-8">
|
|
<div className="flex items-center gap-4 mb-6">
|
|
<img
|
|
src={articleData.author.avatar}
|
|
alt={articleData.author.name}
|
|
className="w-12 h-12 rounded-full"
|
|
/>
|
|
<div>
|
|
<p className="font-medium text-gray-900">{articleData.author.name}</p>
|
|
<div className="flex items-center text-sm text-gray-500">
|
|
<Clock size={14} className="mr-1" />
|
|
{articleData.readTime} min read ·{' '}
|
|
{new Date(articleData.publishedAt).toLocaleDateString('en-US', {
|
|
month: 'long',
|
|
day: 'numeric',
|
|
year: 'numeric',
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">{articleData.title}</h1>
|
|
<p className="text-xl text-gray-600 mb-6">{articleData.excerpt}</p>
|
|
|
|
<div className="flex items-center gap-4 mb-8">
|
|
<span className="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm font-medium">
|
|
{articleData.category}
|
|
</span>
|
|
<div className="flex-1" />
|
|
<button className="p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100">
|
|
<Share2 size={20} />
|
|
</button>
|
|
<button className="p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100">
|
|
<Bookmark size={20} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Cover Image */}
|
|
<img
|
|
src={articleData.coverImage}
|
|
alt={articleData.title}
|
|
className="w-full h-[28rem] object-cover rounded-xl mb-8"
|
|
/>
|
|
|
|
{/* Article Content */}
|
|
<div className="prose prose-lg max-w-none mb-8">
|
|
<div className="text-gray-800 leading-relaxed">
|
|
{articleData.content}
|
|
</div>
|
|
|
|
<p className="text-gray-800 leading-relaxed mt-6">
|
|
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
|
</p>
|
|
|
|
<blockquote className="border-l-4 border-blue-500 pl-4 my-8 italic text-gray-700">
|
|
"Art is not what you see, but what you make others see." - Edgar Degas
|
|
</blockquote>
|
|
|
|
<p className="text-gray-800 leading-relaxed">
|
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Photo Gallery */}
|
|
{articleData.gallery && articleData.gallery.length > 0 && (
|
|
<div className="mb-8">
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">Photo Gallery</h2>
|
|
<PhotoGallery images={articleData.gallery} />
|
|
</div>
|
|
)}
|
|
|
|
{/* Article Footer */}
|
|
<div className="border-t pt-8">
|
|
<ReactionButtons
|
|
likes={articleData.likes}
|
|
dislikes={articleData.dislikes}
|
|
userReaction={articleData.userReaction}
|
|
onReact={handleReaction}
|
|
/>
|
|
</div>
|
|
</article>
|
|
</main>
|
|
</div>
|
|
);
|
|
} |