import { useState } from "react"; import { getGameTitle } from "../utils.ts"; import { useSearchParams } from "react-router-dom"; export interface NewsData { date: string; identifier: string; type: string | null; timestamp: number; headline: string | null; content: string; url: string | null; images: Array<{ image: string; link: string | null; }>; en_headline: string | null; en_content: string | null; } interface NewsFeedProps { newsItems: NewsData[]; } export const NewsFeed: React.FC = ({ newsItems }) => { const [showEnglish, setShowEnglish] = useState>({}); const [expanded, setExpanded] = useState>({}); const [currentImageIndex, setCurrentImageIndex] = useState>({}); const [loadingImages, setLoadingImages] = useState>({}); const [searchParams] = useSearchParams(); const isMoe = searchParams.has("moe"); const toggleLanguage = (id: string) => setShowEnglish((prev) => ({ ...prev, [id]: !prev[id] })); const toggleExpand = (id: string) => setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); const changeImage = (id: string, i: number) => { setCurrentImageIndex((p) => ({ ...p, [id]: i })); setLoadingImages((p) => ({ ...p, [id]: true })); }; const handleImageLoad = (id: string) => setLoadingImages((p) => ({ ...p, [id]: false })); const PREVIEW_CHAR_LIMIT = 600; return (
{newsItems.map((news) => { const date = new Date(news.timestamp * 1000).toLocaleDateString("ja-JP", { year: "numeric", month: "2-digit", day: "2-digit" }); const contentHash = news.content.split('').reduce((hash, char) => ((hash << 5) + hash) + char.charCodeAt(0), 5381) >>> 0; const newsId = `${news.identifier}-${news.timestamp}-${contentHash.toString(16)}-${news.headline}`; const isEnglish = !!showEnglish[newsId]; const hasTranslation = news.en_headline || news.en_content; const displayHeadline = isEnglish && news.en_headline ? news.en_headline : news.headline; const displayContent = isEnglish && news.en_content ? news.en_content : news.content; const isLong = displayContent.length > PREVIEW_CHAR_LIMIT; const isExpanded = !!expanded[newsId]; const contentToShow = isLong && !isExpanded ? displayContent.slice(0, PREVIEW_CHAR_LIMIT) + "…" : displayContent; return (
{news.identifier.charAt(0)}
{getGameTitle(news.identifier)} {date} {news.type && {news.type}}
{hasTranslation && ( )}
{displayHeadline &&

{displayHeadline}

}

{contentToShow.split(/(\[.*?\]\(.*?\)|https?:\/\/[^\s]+)/g).map((part, idx) => { const m = part.match(/\[(.*?)\]\((.*?)\)/); const u = part.match(/https?:\/\/[^\s]+/); if (m) return {m[1]}; if (u) return {u[0]}; return part; })}

{isLong && ( )}
{/* Images */} {news.images.length > 0 && (
{(() => { const idx = currentImageIndex[newsId] || 0; const img = news.images[idx]; return (
{loadingImages[newsId] && (
)} news visual handleImageLoad(newsId)} />
); })()} {news.images.length > 1 && (
{news.images.map((_, idx) => ( ))}
)}
)} {news.url && ( )}
); })}
); };