57 lines
2.1 KiB
Vue
57 lines
2.1 KiB
Vue
<template>
|
|
<section class="page-section block animate-slide-down">
|
|
<div class="max-w-4xl mx-auto pt-32 px-6 pb-20">
|
|
<div class="mb-16 text-center">
|
|
<h2 class="font-serif text-5xl italic text-white mb-6">分类</h2>
|
|
<p class="text-art-muted max-w-lg mx-auto mb-8">按照主题浏览文章。</p>
|
|
</div>
|
|
|
|
<!-- Loading state -->
|
|
<div v-if="loading" class="flex justify-center items-center h-64">
|
|
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-art-accent"></div>
|
|
</div>
|
|
|
|
<!-- Categories Grid -->
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<div
|
|
v-for="category in categories"
|
|
:key="category.id"
|
|
class="group p-6 rounded-lg border border-white/5 bg-white/5 hover:bg-white/10 hover:border-art-accent/30 transition-all cursor-pointer"
|
|
@click="router.push(`/blog?category=${category.id}`)"
|
|
>
|
|
<div class="flex items-start justify-between mb-4">
|
|
<span class="text-3xl">📂</span>
|
|
<span class="font-mono text-xs text-art-muted group-hover:text-art-accent transition-colors">#{{ category.slug }}</span>
|
|
</div>
|
|
<h3 class="text-xl font-serif text-white mb-2 group-hover:text-art-accent transition-colors">{{ category.name }}</h3>
|
|
<p class="text-sm text-art-muted leading-relaxed line-clamp-3">{{ category.description || '暂无描述' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="!loading && categories.length === 0" class="text-center py-20 text-art-muted">
|
|
暂无分类
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { fetchCategories, Category } from '../services/api'
|
|
|
|
const router = useRouter()
|
|
const categories = ref<Category[]>([])
|
|
const loading = ref(true)
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
categories.value = await fetchCategories()
|
|
} catch (error) {
|
|
console.error('Failed to fetch categories:', error)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
})
|
|
</script>
|