初始化
This commit is contained in:
82
client/src/pages/Blog.vue
Normal file
82
client/src/pages/Blog.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<section id="blog" 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">关于前端技术、交互设计以及数字艺术的深度思考。</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>
|
||||
|
||||
<!-- Error state -->
|
||||
<div v-else-if="error" class="text-center text-red-500 py-20">
|
||||
<p class="mb-4">{{ error }}</p>
|
||||
<button @click="fetchBlogPosts" class="px-4 py-2 bg-art-accent text-white rounded hover:bg-opacity-80 transition-colors">
|
||||
重试
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Blog posts list -->
|
||||
<div v-else class="space-y-12" id="blog-list-container">
|
||||
<!-- Blog posts will be rendered here -->
|
||||
<div
|
||||
v-for="post in blogPosts"
|
||||
:key="post.id"
|
||||
class="art-card rounded-2xl p-8 group cursor-pointer transition-all"
|
||||
@click="$router.push('/blog/' + post.id)"
|
||||
>
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="px-2 py-1 text-[10px] font-mono border border-white/20 rounded-full text-white backdrop-blur-sm">{{ post.category }}</span>
|
||||
<span class="text-xs font-mono text-art-muted">{{ post.date }}</span>
|
||||
</div>
|
||||
<i data-lucide="arrow-up-right" class="w-5 h-5 text-white/50 transform group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform"></i>
|
||||
</div>
|
||||
<h3 class="text-2xl md:text-3xl font-serif text-white mb-4 group-hover:text-art-accent transition-colors">{{ post.title }}</h3>
|
||||
<p class="text-art-muted leading-relaxed">{{ post.excerpt }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeMount } from 'vue'
|
||||
import { fetchPosts, Post } from '../services/api'
|
||||
import { useScrollAnimation } from '../composables/useScrollAnimation'
|
||||
|
||||
const blogPosts = ref<Post[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const fetchBlogPosts = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const posts = await fetchPosts()
|
||||
blogPosts.value = posts
|
||||
} catch (err) {
|
||||
console.error('Error fetching blog posts:', err)
|
||||
error.value = '获取博客文章失败,请稍后重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchBlogPosts()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user