Files
a42cacc9-7e1b-4f64-b679-38f…/src/pages/Categories.tsx
2026-01-22 11:48:48 +08:00

121 lines
4.3 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.
import React, { useEffect, useState } from 'react'
import { Header } from '../components/Header'
import { Footer } from '../components/Footer'
import { Categories } from '../clientsdk/sdk.gen'
import { createClient } from '../clientsdk/client'
import { customQuerySerializer } from '../clientsdk/querySerializer'
import { TENANT_SLUG, TENANT_API_KEY, API_URL } from '../config'
import { usePageTitle } from '../hooks/usePageTitle'
const client = createClient({
baseUrl: API_URL,
querySerializer: customQuerySerializer,
headers: {
'X-Tenant-Slug': TENANT_SLUG,
'X-API-Key': TENANT_API_KEY,
},
})
export const CategoriesPage: React.FC = () => {
usePageTitle('文章分类')
const [categories, setCategories] = useState<any[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const fetchCategories = async () => {
try {
setLoading(true)
setError(null)
const response = await Categories.listCategories({
client,
query: {
limit: 100,
},
})
setCategories((response as any)?.data?.docs || [])
} catch (err) {
setError(err instanceof Error ? err.message : '加载失败')
console.error('获取分类失败:', err)
} finally {
setLoading(false)
}
}
fetchCategories()
}, [])
return (
<div className="min-h-screen bg-gray-50">
<Header />
<main className="container mx-auto px-4 py-8">
<section className="mb-12">
<h2 className="text-3xl font-bold text-gray-900 mb-2"></h2>
<p className="text-gray-600"></p>
</section>
{error && (
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6">
<strong></strong> {error}
</div>
)}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{loading
? Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="bg-white rounded-lg shadow-sm overflow-hidden animate-pulse">
<div className="aspect-[16/9] bg-gray-200"></div>
<div className="p-6">
<div className="h-6 bg-gray-200 rounded w-3/4 mb-2"></div>
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
</div>
))
: categories.map((category) => (
<a
key={category.id}
href={`/categories/${category.slug}`}
className="bg-white rounded-lg shadow-sm overflow-hidden hover:shadow-md transition-shadow group"
>
<div className="aspect-[16/9] overflow-hidden bg-gradient-to-br from-primary/10 to-primary-light/10">
<img
src={`/images/category-${category.slug}.jpg`}
alt={category.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
onError={(e) => {
const target = e.target as HTMLImageElement;
target.style.display = 'none';
target.nextElementSibling?.classList.remove('hidden');
}}
/>
<div className="w-full h-full flex items-center justify-center hidden">
<div className="text-center text-primary">
<div className="text-4xl mb-2">Category</div>
<p className="text-sm font-medium">{category.title}</p>
</div>
</div>
</div>
<div className="p-6">
<h3 className="text-xl font-semibold text-gray-900 mb-2">{category.title}</h3>
<p className="text-sm text-gray-600"></p>
</div>
</a>
))}
</div>
{!loading && categories.length === 0 && !error && (
<div className="text-center py-12">
<p className="text-gray-500 text-lg"></p>
</div>
)}
</main>
<Footer />
</div>
)
}