Files
iiEasy/components/BlogPostDetail.tsx

178 lines
7.1 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useRef, useState } from 'react';
import { CurrentView, Post } from '../types';
import { SECTION_IDS, BLOG_POST_DETAIL_CONTENT, UI_TEXTS } from '../constants'; // Removed mockPosts
import Button from './Button';
import { ArrowUturnLeftIcon, PlayIcon, PauseIcon, ChevronRightIcon } from './icons';
import ItemDetailNavigation from './ItemDetailNavigation';
import PostCard from './PostCard';
import GalleryComponent from './GalleryComponent'; // Import GalleryComponent
interface BlogPostDetailProps {
itemId: string;
allPosts: Post[];
setCurrentView: (view: CurrentView) => void;
setSelectedItemId: (id: string | null) => void;
}
const BlogPostDetail: React.FC<BlogPostDetailProps> = ({ itemId, allPosts, setCurrentView, setSelectedItemId }) => {
const post = allPosts.find(p => p.id === itemId);
const videoRef = useRef<HTMLVideoElement>(null);
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
const handleBackClick = () => {
setCurrentView('storiesAll');
setSelectedItemId(null);
};
const handleNavigateItem = (newItemId: string) => {
setSelectedItemId(newItemId);
};
const handleShowAllKeepReading = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
setCurrentView('storiesAll');
setSelectedItemId(null);
};
if (!post) {
return (
<section id={SECTION_IDS.blogPostDetailPage} className="py-16 md:py-24 min-h-screen flex items-center justify-center">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-2xl font-semibold text-slate-700">{BLOG_POST_DETAIL_CONTENT.notFoundTitle}</h1>
<Button onClick={handleBackClick} leftIcon={<ArrowUturnLeftIcon />} className="mt-8">
{BLOG_POST_DETAIL_CONTENT.backButtonText}
</Button>
</div>
</section>
);
}
const currentIndex = allPosts.findIndex(p => p.id === itemId);
const previousPost = currentIndex > 0 ? allPosts[currentIndex - 1] : undefined;
const nextPost = currentIndex < allPosts.length - 1 ? allPosts[currentIndex + 1] : undefined;
const relatedPosts = allPosts
.filter(p => p.id !== itemId)
.slice(0, 3);
const toggleVideoPlay = (e: React.MouseEvent) => {
e.stopPropagation();
if (videoRef.current) {
if (videoRef.current.paused) {
videoRef.current.play();
setIsVideoPlaying(true);
} else {
videoRef.current.pause();
setIsVideoPlaying(false);
}
}
};
return (
<section
id={SECTION_IDS.blogPostDetailPage}
className="py-16 md:py-24 bg-white min-h-screen"
>
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<Button
variant="outline"
size="sm"
onClick={handleBackClick}
leftIcon={<ArrowUturnLeftIcon />}
className="mb-6"
>
{BLOG_POST_DETAIL_CONTENT.backButtonText}
</Button>
{post.videoUrl ? (
<div className="mb-8 rounded-lg overflow-hidden relative aspect-video">
<video
ref={videoRef}
controls
className="w-full h-full object-cover"
poster={post.imageUrl}
onPlay={() => setIsVideoPlaying(true)}
onPause={() => setIsVideoPlaying(false)}
>
<source src={post.videoUrl} type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
) : post.imageUrl && (
<div className="mb-8 rounded-lg overflow-hidden">
<img src={post.imageUrl} alt={post.title} className="w-full h-auto object-cover max-h-[60vh]" />
</div>
)}
<div className="max-w-3xl mx-auto">
<header className="mb-8 md:mb-12">
<h1 className="font-quicksand text-3xl sm:text-4xl md:text-5xl font-bold text-slate-800 mb-3">
{post.title}
</h1>
<div className="font-inter text-sm text-slate-500">
<span className="font-semibold text-slate-600">{post.category}</span>
{(post.date || post.readTime) && <span className="mx-1.5"></span>}
{post.date && <span>{post.date}</span>}
{post.date && post.readTime && <span className="mx-1.5"></span>}
{post.readTime && <span>{post.readTime}</span>}
</div>
</header>
<article className="prose prose-lg max-w-none font-inter text-slate-700">
{typeof post.fullContent === 'string' ? (
<div dangerouslySetInnerHTML={{ __html: post.fullContent }} />
) : (
post.fullContent
)}
</article>
{post.gallery && post.gallery.length > 0 && (
<GalleryComponent items={post.gallery} title={BLOG_POST_DETAIL_CONTENT.galleryTitle} />
)}
<ItemDetailNavigation
previousItem={previousPost ? { id: previousPost.id, title: previousPost.title } : undefined}
nextItem={nextPost ? { id: nextPost.id, title: nextPost.title } : undefined}
onNavigate={handleNavigateItem}
previousItemButtonLabel={BLOG_POST_DETAIL_CONTENT.previousItemButtonLabel || `Предыдущий ${BLOG_POST_DETAIL_CONTENT.itemTypeSingular}`}
nextItemButtonLabel={BLOG_POST_DETAIL_CONTENT.nextItemButtonLabel || `Следующий ${BLOG_POST_DETAIL_CONTENT.itemTypeSingular}`}
noPreviousItemText={BLOG_POST_DETAIL_CONTENT.noPreviousItemText || `Это первая история`}
noNextItemText={BLOG_POST_DETAIL_CONTENT.noNextItemText || `Это последняя история`}
themeColorClass="slate"
/>
</div>
{relatedPosts.length > 0 && (
<div className="mt-12 md:mt-16">
<div className="flex justify-between items-baseline mb-8">
<h2 className="font-quicksand text-3xl font-bold text-slate-800">
{BLOG_POST_DETAIL_CONTENT.keepReadingTitle || "Читайте также"}
</h2>
<a
href={`#${SECTION_IDS.storiesAllPage}`}
onClick={handleShowAllKeepReading}
className="group inline-flex items-center text-base font-medium text-slate-700 hover:text-black transition-colors whitespace-nowrap"
aria-label={`Посмотреть все ${BLOG_POST_DETAIL_CONTENT.itemTypePlural}`}
>
{BLOG_POST_DETAIL_CONTENT.viewAllButtonText || `Все ${BLOG_POST_DETAIL_CONTENT.itemTypePlural}`}
<ChevronRightIcon className="ml-1 w-5 h-5 transform group-hover:translate-x-1 transition-transform duration-200" />
</a>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
{relatedPosts.map(relatedPost => (
<PostCard
key={relatedPost.id}
post={relatedPost}
setCurrentView={setCurrentView}
setSelectedItemId={setSelectedItemId}
/>
))}
</div>
</div>
)}
</div>
</section>
);
};
export default BlogPostDetail;