CloudPro/app/news/page.tsx
2025-09-16 16:15:57 +08:00

343 lines
15 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { Navigation } from '../../components/Navigation';
import { Footer } from '../../components/Footer';
import { Head } from '../../components/Head';
import { Calendar, User, Tag, ArrowRight, Clock } from 'lucide-react';
import Link from 'next/link';
interface NewsArticle {
id: string;
category: string;
title: string;
excerpt: string;
author: string;
date: string;
readTime: number;
image?: string;
}
export default function NewsPage() {
const [currentLang, setCurrentLang] = useState<'zh' | 'zh-tw' | 'en'>('zh');
const [selectedCategory, setSelectedCategory] = useState('all');
const [articles, setArticles] = useState<NewsArticle[]>([]);
const [loading, setLoading] = useState(true);
const translations = {
zh: {
title: '资讯中心 - CloudPro 云服务器代理商',
description:
'获取最新的云计算资讯、技术文章、产品更新和行业动态,了解云服务器和云计算的最新发展趋势。',
keywords: '云计算资讯,技术文章,产品更新,行业动态,云服务器新闻',
nav: {
home: '首页',
products: '产品',
solutions: '解决方案',
support: '支持',
news: '资讯',
contact: '联系我们',
},
hero: {
title: '资讯中心',
subtitle: '了解云计算最新动态',
description: '获取最新的技术资讯、产品更新和行业洞察',
},
categories: {
all: '全部',
tech: '技术文章',
product: '产品更新',
industry: '行业动态',
tutorial: '教程指南',
},
readMore: '阅读更多',
readTime: '阅读时间',
minutes: '分钟',
loading: '加载中...',
noArticles: '暂无文章',
},
'zh-tw': {
title: '資訊中心 - CloudPro 雲伺服器代理商',
description:
'獲取最新的雲端運算資訊、技術文章、產品更新和行業動態,了解雲伺服器和雲端運算的最新發展趨勢。',
keywords: '雲端運算資訊,技術文章,產品更新,行業動態,雲伺服器新聞',
nav: {
home: '首頁',
products: '產品',
solutions: '解決方案',
support: '支援',
news: '資訊',
contact: '聯絡我們',
},
hero: {
title: '資訊中心',
subtitle: '了解雲端運算最新動態',
description: '獲取最新的技術資訊、產品更新和行業洞察',
},
categories: {
all: '全部',
tech: '技術文章',
product: '產品更新',
industry: '行業動態',
tutorial: '教學指南',
},
readMore: '閱讀更多',
readTime: '閱讀時間',
minutes: '分鐘',
loading: '載入中...',
noArticles: '暫無文章',
},
en: {
title: 'News Center - CloudPro Cloud Server Reseller',
description:
'Get the latest cloud computing news, technical articles, product updates and industry insights about cloud servers and cloud computing trends.',
keywords:
'cloud computing news,technical articles,product updates,industry insights,cloud server news',
nav: {
home: 'Home',
products: 'Products',
solutions: 'Solutions',
support: 'Support',
news: 'News',
contact: 'Contact',
},
hero: {
title: 'News Center',
subtitle: 'Stay Updated with Cloud Computing',
description: 'Get the latest technical insights, product updates and industry news',
},
categories: {
all: 'All',
tech: 'Technical Articles',
product: 'Product Updates',
industry: 'Industry News',
tutorial: 'Tutorials',
},
readMore: 'Read More',
readTime: 'Read Time',
minutes: 'min',
loading: 'Loading...',
noArticles: 'No articles found',
},
};
const t = translations[currentLang];
useEffect(() => {
const browserLang = navigator.language.toLowerCase();
if (browserLang.includes('en')) {
setCurrentLang('en');
} else if (browserLang.includes('zh-tw') || browserLang.includes('zh-hk')) {
setCurrentLang('zh-tw');
}
}, []);
useEffect(() => {
const loadArticles = async () => {
try {
setLoading(true);
// 获取所有文章目录
const response = await fetch('/api/articles');
if (response.ok) {
const articlesData = await response.json();
setArticles(articlesData);
} else {
console.error('Failed to load articles');
setArticles([]);
}
} catch (error) {
console.error('Error loading articles:', error);
setArticles([]);
} finally {
setLoading(false);
}
};
loadArticles();
}, []);
const filteredArticles =
selectedCategory === 'all'
? articles
: articles.filter((article) => article.category === selectedCategory);
const getCategoryColor = (category: string) => {
const colors = {
tech: 'bg-blue-100 text-blue-800',
product: 'bg-green-100 text-green-800',
industry: 'bg-purple-100 text-purple-800',
tutorial: 'bg-orange-100 text-orange-800',
};
return colors[category as keyof typeof colors] || 'bg-gray-100 text-gray-800';
};
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-amber-50 to-yellow-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-amber-600 mx-auto mb-4"></div>
<p className="text-amber-700">{t.loading}</p>
</div>
</div>
);
}
return (
<div
className="min-h-screen bg-gradient-to-br from-amber-50 to-yellow-50"
data-oid="boqb.7r"
>
<Head
title={t.title}
description={t.description}
keywords={t.keywords}
currentLang={currentLang}
data-oid="bfx9fff"
/>
<Navigation
currentLang={currentLang}
onLanguageChange={setCurrentLang}
translations={translations}
data-oid="hg2jxud"
/>
{/* Hero Section */}
<section
className="bg-gradient-to-r from-amber-900 to-yellow-800 text-white py-20"
data-oid="2hx59ni"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" data-oid="_qad75g">
<div className="text-center" data-oid="25h11wr">
<h1 className="text-4xl md:text-5xl font-bold mb-6" data-oid="sm1glbj">
{t.hero.title}
</h1>
<p className="text-xl md:text-2xl text-yellow-100 mb-8" data-oid="302vwh6">
{t.hero.subtitle}
</p>
<p className="text-lg text-yellow-200 max-w-2xl mx-auto" data-oid="og47v15">
{t.hero.description}
</p>
</div>
</div>
</section>
{/* Category Filter */}
<section className="py-8 bg-white border-b border-amber-200" data-oid="tz-k6ln">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" data-oid="9bs7jyn">
<div className="flex flex-wrap justify-center gap-4" data-oid="vh_g87_">
{Object.entries(t.categories).map(([key, label]) => (
<button
key={key}
onClick={() => setSelectedCategory(key)}
className={`px-6 py-3 rounded-full font-medium transition-all duration-200 ${
selectedCategory === key
? 'bg-gradient-to-r from-amber-500 to-yellow-500 text-white shadow-lg'
: 'bg-amber-100 text-amber-700 hover:bg-amber-200'
}`}
data-oid="0eygd-d"
>
{label}
</button>
))}
</div>
</div>
</section>
{/* News Grid */}
<section className="py-20" data-oid="xw94g35">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" data-oid="wwtx4ho">
{filteredArticles.length === 0 ? (
<div className="text-center py-12">
<p className="text-amber-700 text-lg">{t.noArticles}</p>
</div>
) : (
<div
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
data-oid="4xt-f7q"
>
{filteredArticles.map((article) => (
<article
key={article.id}
className="bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden border border-amber-200 group"
data-oid="jciu2kd"
>
<div
className="aspect-video bg-gradient-to-br from-amber-100 to-yellow-100 flex items-center justify-center"
data-oid="x7t1wke"
>
<div className="text-amber-600 text-6xl" data-oid="zve:qud">
📰
</div>
</div>
<div className="p-6" data-oid="_yz_608">
<div
className="flex items-center justify-between mb-4"
data-oid="ybf-qhj"
>
<span
className={`px-3 py-1 rounded-full text-xs font-medium ${getCategoryColor(article.category)}`}
data-oid="or3hmoo"
>
{t.categories[article.category as keyof typeof t.categories] || article.category}
</span>
<div
className="flex items-center text-amber-600 text-sm"
data-oid="220a3nu"
>
<Clock className="w-4 h-4 mr-1" data-oid="kizescv" />
{article.readTime} {t.minutes}
</div>
</div>
<h2
className="text-xl font-bold text-amber-900 mb-3 group-hover:text-amber-700 transition-colors"
data-oid="4ulljgk"
>
{article.title}
</h2>
<p
className="text-amber-700 mb-4 leading-relaxed"
data-oid="8y50obt"
>
{article.excerpt}
</p>
<div
className="flex items-center justify-between text-sm text-amber-600 mb-4"
data-oid="71yedyp"
>
<div className="flex items-center" data-oid="azrio3x">
<User className="w-4 h-4 mr-1" data-oid="ymx:c55" />
{article.author}
</div>
<div className="flex items-center" data-oid="dkyta:_">
<Calendar className="w-4 h-4 mr-1" data-oid="kb8.f0-" />
{article.date}
</div>
</div>
<Link
href={`/news/${article.id}`}
className="inline-flex items-center text-amber-600 hover:text-amber-700 font-medium group-hover:translate-x-1 transition-all duration-200"
data-oid="7_fsq:6"
>
{t.readMore}
<ArrowRight className="w-4 h-4 ml-2" data-oid="hmhay_i" />
</Link>
</div>
</article>
))}
</div>
)}
</div>
</section>
<Footer currentLang={currentLang} translations={translations} data-oid="ot09pr8" />
</div>
);
}