TechCorp/components/NewsDetailPage.tsx
2025-09-16 17:40:37 +08:00

650 lines
30 KiB
TypeScript
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.

'use client';
import { useState, useCallback, useEffect } from 'react';
import { useTranslation } from '../lib/i18n/useTranslation';
import { languages } from '../lib/i18n/config';
import { getNewsById, getAllNews, parseMarkdownContent, type NewsItem } from '../lib/news';
interface NewsDetailPageProps {
initialLanguage?: string;
newsId: string;
}
// 只保留元信息,正文内容已迁移到 md 文件
interface NewsArticleMeta {
id: number;
category: string;
date: string;
readTime: string;
image: string;
}
// 仅示例,实际内容请从 md 文件读取
const newsArticles: NewsArticleMeta[] = [
{
id: 1,
category: 'product',
date: '2024-01-15',
readTime: '5 min',
image: 'https://images.unsplash.com/photo-1504711434969-e33886168f5c?w=800&h=600&fit=crop',
},
{
id: 2,
category: 'industry',
date: '2024-01-12',
readTime: '8 min',
image: 'https://images.unsplash.com/photo-1586953208448-b95a79798f07?w=800&h=600&fit=crop',
},
{
id: 3,
category: 'company',
date: '2024-01-10',
readTime: '3 min',
image: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=800&h=600&fit=crop',
},
];
// 分类图标映射
const categoryIcons = {
company: '🏢',
product: '📦',
industry: '🏭',
technology: '💻',
};
export default function NewsDetailPage({ initialLanguage, newsId }: NewsDetailPageProps) {
const { language, t, changeLanguage, getLocalizedPath, isInitialized } =
useTranslation(initialLanguage);
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [showScrollTop, setShowScrollTop] = useState(false);
const handleLanguageChange = useCallback(
(newLanguage: string) => {
changeLanguage(newLanguage as any);
},
[changeLanguage],
);
// 获取新闻元信息
const article = newsArticles.find((article) => article.id.toString() === newsId);
// 滚动到顶部功能
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// 监听滚动事件
useEffect(() => {
const handleScroll = () => {
setShowScrollTop(window.scrollY > 300);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// 格式化日期
const formatDate = (dateString: string) => {
const date = new Date(dateString);
if (language === 'en') {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
} else {
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
};
// 在语言初始化完成前显示加载状态
if (!isInitialized) {
return (
<div
className="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 flex items-center justify-center"
data-oid="0ta7hzw"
>
<div className="text-center" data-oid="08wl8cy">
<div
className="w-12 h-12 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"
data-oid="vl74wbo"
></div>
<p className="text-gray-600" data-oid="gfr0.6-">
Loading...
</p>
</div>
</div>
);
}
// 如果找不到文章显示404页面
if (!article) {
return (
<div
className="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 flex items-center justify-center"
data-oid="dv3f8p5"
>
<div className="text-center" data-oid="oea:fzl">
<div className="text-8xl mb-4" data-oid="s2xkcxo">
📰
</div>
<h1 className="text-4xl font-bold text-gray-900 mb-4" data-oid="ef93e0s">
{language === 'en'
? 'Article Not Found'
: language === 'zh-CN'
? '文章未找到'
: '文章未找到'}
</h1>
<p className="text-lg text-gray-600 mb-8" data-oid="2irbjo7">
{language === 'en'
? 'The article you are looking for does not exist or has been moved.'
: language === 'zh-CN'
? '您查找的文章不存在或已被移动。'
: '您查找的文章不存在或已被移動。'}
</p>
<a
href={getLocalizedPath('/news')}
className="bg-gradient-to-r from-blue-600 to-purple-600 text-white px-8 py-3 rounded-full font-semibold hover:from-blue-700 hover:to-purple-700 transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-xl"
data-oid="w.k9kpi"
>
{language === 'en'
? 'Back to News'
: language === 'zh-CN'
? '返回新闻'
: '返回新聞'}
</a>
</div>
</div>
);
}
// Navigation items
const navItems = [
{ key: 'home', label: t.nav.home, href: getLocalizedPath('/') },
{ key: 'products', label: t.nav.products, href: getLocalizedPath('/products') },
{ key: 'news', label: t.nav.news, href: getLocalizedPath('/news') },
{ key: 'support', label: t.nav.support, href: getLocalizedPath('/support') },
{ key: 'about', label: t.nav.about, href: getLocalizedPath('/about') },
];
return (
<div
className="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50"
data-oid="pzoby69"
>
{/* Navigation */}
<nav
className="fixed top-0 left-0 w-full z-50 bg-white/80 backdrop-blur-md border-b border-white/20 shadow-sm"
data-oid="q6axiuz"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" data-oid="6.7qdqy">
<div className="flex justify-between items-center h-16" data-oid="wwgkjio">
{/* Logo */}
<div className="flex items-center" data-oid="or0niw4">
<div className="flex-shrink-0" data-oid="xb9n7.m">
<div
className="w-10 h-10 bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg flex items-center justify-center"
data-oid=":ps6kar"
>
<span
className="text-white font-bold text-lg"
data-oid="3.i-xlz"
>
T
</span>
</div>
</div>
<div className="ml-3" data-oid="mo0ialc">
<span
className="text-xl font-semibold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"
data-oid="6zwerlx"
>
TechCorp
</span>
</div>
</div>
{/* Desktop Navigation */}
<div className="hidden md:block" data-oid="u5chrs:">
<div className="ml-10 flex items-baseline space-x-8" data-oid="8lji8:h">
{navItems.map((item) => (
<a
key={item.key}
href={item.href}
className={`px-3 py-2 text-sm font-medium transition-colors duration-200 rounded-md ${
item.key === 'news'
? 'text-blue-600 bg-blue-50'
: 'text-gray-700 hover:text-blue-600 hover:bg-blue-50'
}`}
data-oid="xdfk9k7"
>
{item.label}
</a>
))}
</div>
</div>
{/* Language Selector & Mobile Menu */}
<div className="flex items-center space-x-4" data-oid="jes62r1">
{/* Language Selector */}
<div className="relative" data-oid="6xi2mpu">
<select
value={language}
onChange={(e) => handleLanguageChange(e.target.value)}
className="appearance-none bg-white/80 border border-gray-200 rounded-md px-3 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
data-oid="28q4bda"
>
{languages.map((lang) => (
<option
key={lang.code}
value={lang.code}
data-oid="3qqkghq"
>
{lang.flag} {lang.label}
</option>
))}
</select>
</div>
{/* Mobile menu button */}
<div className="md:hidden" data-oid="vei0onh">
<button
onClick={() => setIsMenuOpen(!isMenuOpen)}
className="text-gray-700 hover:text-blue-600 p-2"
data-oid="l_mhpyq"
>
<svg
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
data-oid=".ma02zl"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
data-oid="zrh6s9r"
/>
</svg>
</button>
</div>
</div>
</div>
{/* Mobile Navigation */}
{isMenuOpen && (
<div className="md:hidden" data-oid="ve3l6d_">
<div
className="px-2 pt-2 pb-3 space-y-1 bg-white/90 backdrop-blur-md rounded-lg mt-2"
data-oid="ii7_x3z"
>
{navItems.map((item) => (
<a
key={item.key}
href={item.href}
className={`block px-3 py-2 text-base font-medium transition-colors duration-200 ${
item.key === 'news'
? 'text-blue-600 bg-blue-50'
: 'text-gray-700 hover:text-blue-600'
}`}
data-oid="86wr5.a"
>
{item.label}
</a>
))}
</div>
</div>
)}
</div>
</nav>
{/* Breadcrumb */}
<section className="pt-20 pb-4 px-4 sm:px-6 lg:px-8" data-oid="8un-lq5">
<div className="max-w-4xl mx-auto" data-oid="zv4e73a">
<nav className="flex" data-oid="e3wvxn5">
<ol className="flex items-center space-x-2" data-oid="6wbmmil">
<li data-oid="e.aqwn.">
<a
href={getLocalizedPath('/')}
className="text-gray-500 hover:text-blue-600 transition-colors"
data-oid="pq4wa-o"
>
{t.nav.home}
</a>
</li>
<li data-oid="kdh1f8_">
<span className="text-gray-400" data-oid="86.6cka">
/
</span>
</li>
<li data-oid="2qz7txu">
<a
href={getLocalizedPath('/news')}
className="text-gray-500 hover:text-blue-600 transition-colors"
data-oid="ebn1xz1"
>
{t.nav.news}
</a>
</li>
<li data-oid="nd.e71w">
<span className="text-gray-400" data-oid="vjkez4f">
/
</span>
</li>
<li data-oid="3aru9ik">
<span className="text-gray-900 font-medium" data-oid="3th0wam">
{article.category.charAt(0).toUpperCase() +
article.category.slice(1)}
</span>
</li>
</ol>
</nav>
</div>
</section>
{/* Article Header */}
<section className="pb-8 px-4 sm:px-6 lg:px-8" data-oid="r21fm2p">
<div className="max-w-4xl mx-auto" data-oid="x8knt6x">
{/* Category Badge */}
<div className="mb-6" data-oid="5ku0o66">
<span
className="bg-gradient-to-r from-blue-600 to-purple-600 text-white px-4 py-2 rounded-full text-sm font-bold flex items-center gap-2 w-fit"
data-oid="6ih0cbm"
>
<span data-oid="6yhe.t9">
{categoryIcons[article.category as keyof typeof categoryIcons]}
</span>
{language === 'en'
? article.category.charAt(0).toUpperCase() +
article.category.slice(1)
: article.category === 'company'
? language === 'zh-CN'
? '公司'
: '公司'
: article.category === 'product'
? language === 'zh-CN'
? '产品'
: '產品'
: article.category === 'industry'
? language === 'zh-CN'
? '行业'
: '行業'
: article.category === 'technology'
? language === 'zh-CN'
? '技术'
: '技術'
: article.category}
</span>
</div>
{/* Title */}
<h1
className="text-4xl md:text-5xl font-bold text-gray-900 mb-6 leading-tight"
data-oid="x7.cek."
>
{article.category.charAt(0).toUpperCase() + article.category.slice(1)}
</h1>
{/* Meta Information */}
<div
className="flex flex-wrap items-center gap-6 text-gray-500 mb-8"
data-oid="jq69m::"
>
<div className="flex items-center gap-2" data-oid="ai7go_s">
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
data-oid="6:hpmxn"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
data-oid="p.4qqp."
/>
</svg>
<span data-oid="el170nw">{formatDate(article.date)}</span>
</div>
<div className="flex items-center gap-2" data-oid=":o1248:">
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
data-oid="365g9tj"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
data-oid="2tabb-7"
/>
</svg>
<span data-oid="rlt9gvp">{article.readTime}</span>
</div>
</div>
</div>
</section>
{/* Featured Image */}
<section className="pb-12 px-4 sm:px-6 lg:px-8" data-oid="1ocsoa4">
<div className="max-w-4xl mx-auto" data-oid="28vuu78">
<div
className="relative h-64 md:h-96 rounded-2xl overflow-hidden shadow-2xl"
data-oid="ml734h9"
>
<img
src={article.image}
alt={
article.category.charAt(0).toUpperCase() + article.category.slice(1)
}
className="w-full h-full object-cover"
data-oid="-rq1me-"
/>
<div
className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent"
data-oid="q_a28lv"
></div>
</div>
</div>
</section>
{/* CTA Section */}
<section
className="py-20 px-4 sm:px-6 lg:px-8 bg-gradient-to-r from-blue-600 to-purple-600"
data-oid="0knjf6d"
>
<div className="max-w-4xl mx-auto text-center text-white" data-oid="vodcka5">
<h2 className="text-3xl md:text-4xl font-bold mb-6" data-oid="egkl-38">
{language === 'en'
? 'Stay Updated'
: language === 'zh-CN'
? '保持更新'
: '保持更新'}
</h2>
<p className="text-xl mb-8 opacity-90" data-oid="p2emj--">
{language === 'en'
? 'Subscribe to our newsletter and never miss important updates and insights.'
: language === 'zh-CN'
? '订阅我们的新闻通讯,不要错过重要的更新和见解。'
: '訂閱我們的新聞通訊,不要錯過重要的更新和見解。'}
</p>
<div
className="flex flex-col sm:flex-row gap-4 justify-center"
data-oid="w6xf7ts"
>
<button
className="bg-white text-blue-600 px-8 py-3 rounded-full font-semibold hover:bg-gray-100 transition-all duration-300 transform hover:scale-105"
data-oid="olut2he"
>
{language === 'en'
? 'Subscribe Newsletter'
: language === 'zh-CN'
? '订阅新闻'
: '訂閱新聞'}
</button>
<a
href={getLocalizedPath('/news')}
className="border-2 border-white text-white px-8 py-3 rounded-full font-semibold hover:bg-white hover:text-blue-600 transition-all duration-300 transform hover:scale-105"
data-oid="6031.q."
>
{language === 'en'
? 'View All News'
: language === 'zh-CN'
? '查看所有新闻'
: '查看所有新聞'}
</a>
</div>
</div>
</section>
{/* 回到顶部按钮 */}
{showScrollTop && (
<button
onClick={scrollToTop}
className="fixed bottom-8 right-8 bg-gradient-to-r from-blue-600 to-purple-600 text-white p-3 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-110 z-40"
data-oid=".40.c6-"
>
<svg
className="w-6 h-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
data-oid="4jvjf0_"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 10l7-7m0 0l7 7m-7-7v18"
data-oid="1sjnnat"
/>
</svg>
</button>
)}
{/* Footer */}
<footer
className="bg-gray-900 text-white py-12 px-4 sm:px-6 lg:px-8"
data-oid="aih53pj"
>
<div className="max-w-7xl mx-auto" data-oid="_3wnlza">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8" data-oid="semd9fj">
<div data-oid="w2ea2vq">
<div className="flex items-center mb-4" data-oid="5r3e-.m">
<div
className="w-8 h-8 bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg flex items-center justify-center mr-3"
data-oid="y61zy4v"
>
<span className="text-white font-bold" data-oid="gzv54a4">
T
</span>
</div>
<span className="text-xl font-semibold" data-oid="mdz4l:t">
TechCorp
</span>
</div>
<p className="text-gray-400" data-oid="k_hh1je">
{t.footer.description}
</p>
</div>
<div data-oid="hnn:udv">
<h3 className="text-lg font-semibold mb-4" data-oid="v:lbw9d">
{t.footer.sections.products.title}
</h3>
<ul className="space-y-2 text-gray-400" data-oid="j2l0lrl">
{t.footer.sections.products.items.map((item, index) => (
<li key={index} data-oid="ao37a-1">
<a
href={getLocalizedPath(item.href)}
className="hover:text-white transition-colors"
data-oid="hgpri.7"
>
{item.label}
</a>
</li>
))}
</ul>
</div>
<div data-oid="sn.6b00">
<h3 className="text-lg font-semibold mb-4" data-oid="iq1::4w">
{t.footer.sections.support.title}
</h3>
<ul className="space-y-2 text-gray-400" data-oid="71if07s">
{t.footer.sections.support.items.map((item, index) => (
<li key={index} data-oid="1wgkl5.">
<a
href={getLocalizedPath(item.href)}
className="hover:text-white transition-colors"
data-oid="66z6wpf"
>
{item.label}
</a>
</li>
))}
</ul>
</div>
<div data-oid="mynso0l">
<h3 className="text-lg font-semibold mb-4" data-oid="4i0ne5n">
{t.footer.sections.social.title}
</h3>
<div className="flex space-x-4" data-oid="uiklr52">
<a
href="#"
className="text-gray-400 hover:text-white transition-colors"
data-oid="ybqhlhb"
>
<span className="sr-only" data-oid="lzigd2.">
</span>
💬
</a>
<a
href="#"
className="text-gray-400 hover:text-white transition-colors"
data-oid=".8.:jx6"
>
<span className="sr-only" data-oid="y-1a.hk">
</span>
📱
</a>
<a
href="#"
className="text-gray-400 hover:text-white transition-colors"
data-oid="a45p3p6"
>
<span className="sr-only" data-oid="rai9kgq">
</span>
📧
</a>
</div>
</div>
</div>
<div
className="border-t border-gray-800 mt-8 pt-8 text-center text-gray-400"
data-oid="n9w-8pe"
>
<p data-oid="8g0j82x">&copy; 2024 TechCorp. {t.footer.copyright}</p>
</div>
</div>
</footer>
</div>
);
}