11<template >
2- <div >
3- <!-- 导航栏 -->
2+ <div class =" min-h-screen bg-gray-50 dark:bg-[#0a0a0a] transition-colors duration-300" >
43 <Navbar />
54
6- <!-- 内容区域 -->
7- <div class =" container mx-auto px-4 py-8" >
8- <div class =" flex flex-col md:flex-row" >
9- <!-- 左侧主内容区 -->
10- <div class =" w-full md:w-2/3 md:pr-6" >
11- <!-- 页面标题和写文章按钮 -->
12- <div class =" flex justify-between items-center mb-6" >
13- <h1 class =" text-3xl font-bold text-gray-800" >最新文章</h1 >
14-
15- <!-- 管理员显示写文章按钮 -->
5+ <main class =" container mx-auto px-4 py-12 max-w-6xl" >
6+ <section class =" grid grid-cols-1 md:grid-cols-3 gap-4 mb-16 animate-fade-in-up" >
7+
8+ <div class =" md:col-span-2 bg-white dark:bg-[#111] border border-gray-200 dark:border-gray-800 rounded-2xl p-8 flex flex-col justify-center relative overflow-hidden group" >
9+ <div class =" relative z-10" >
10+ <h1 class =" text-4xl md:text-5xl font-extrabold text-gray-900 dark:text-white mb-4 tracking-tight" >
11+ Hello, I'm <span class =" text-blue-600 dark:text-blue-500" >Myshkin</span >.
12+ </h1 >
13+ <p class =" text-lg text-gray-600 dark:text-gray-400 font-mono mb-6 max-w-lg" >
14+ > Backend Developer<br >
15+ > History Enthusiast<br >
16+ > Building AI Agents...
17+ </p >
1618 <router-link
1719 v-if =" isAdmin"
1820 to =" /write"
19- class =" flex items-center bg-blue-600 hover :bg-blue-700 text-white px-4 py-2 rounded-md "
21+ class =" inline- flex items-center px-5 py-2.5 bg-gray-900 dark :bg-white text-white dark:text-black font-medium rounded-lg hover:opacity-90 transition-opacity "
2022 >
21- <svg xmlns =" http://www.w3.org/2000/svg" class =" h-5 w-5 mr-1 " fill =" none" viewBox =" 0 0 24 24" stroke =" currentColor" >
22- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z " />
23+ <svg xmlns =" http://www.w3.org/2000/svg" class =" h-4 w-4 mr-2 " fill =" none" viewBox =" 0 0 24 24" stroke =" currentColor" >
24+ <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M12 4v16m8-8H4 " />
2325 </svg >
24- 写文章
26+ New Post
2527 </router-link >
2628 </div >
27-
28- <!-- 加载状态 -->
29- <div v-if =" loading" class =" flex justify-center items-center py-12" >
30- <div class =" animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500" ></div >
29+ <div class =" absolute right-0 top-0 w-64 h-64 bg-blue-500/10 rounded-full blur-3xl -mr-16 -mt-16 pointer-events-none" ></div >
30+ </div >
31+
32+ <div class =" bg-white dark:bg-[#111] border border-gray-200 dark:border-gray-800 rounded-2xl p-6 hover:border-blue-500/50 transition-colors" >
33+ <h3 class =" text-sm font-mono font-bold text-gray-500 uppercase mb-4" >Explore Topics</h3 >
34+ <div class =" flex flex-wrap gap-2" >
35+ <router-link
36+ v-for =" cat in categories.slice(0, 5)"
37+ :key =" cat.id"
38+ :to =" `/categories/${cat.slug || cat.id}`"
39+ class =" px-3 py-1 text-xs font-medium rounded-full bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-blue-100 dark:hover:bg-blue-900/30 transition-colors"
40+ >
41+ {{ cat.name }}
42+ </router-link >
3143 </div >
32-
33- <!-- 没有文章时显示 -->
34- <div v-else-if =" posts.length === 0" class =" bg-gray-50 rounded-lg p-8 text-center" >
35- <p class =" text-gray-600" >暂无文章发布</p >
44+ </div >
45+
46+ <a href =" https://github.com/your-github-id" target =" _blank" class =" bg-gray-900 dark:bg-blue-600 rounded-2xl p-6 text-white flex flex-col justify-between hover:scale-[1.02] transition-transform" >
47+ <div class =" flex justify-between items-start" >
48+ <svg class =" w-8 h-8 opacity-80" fill =" currentColor" viewBox =" 0 0 24 24" ><path d =" M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" /></svg >
49+ <svg class =" w-5 h-5 opacity-50" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" ><path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M17 8l4 4m0 0l-4 4m4-4H3" ></path ></svg >
3650 </div >
37-
38- <!-- 文章列表 -->
39- <div v-else class =" space-y-6" >
40- <ArticleCardV2
41- v-for =" post in posts"
42- :key =" post.id"
43- :article =" post"
44- />
51+ <div >
52+ <p class =" font-bold text-lg" >GitHub</p >
53+ <p class =" text-sm opacity-70" >View my projects</p >
4554 </div >
46-
47- <!-- 分页 -->
55+ </a >
56+ </section >
57+
58+ <section >
59+ <div class =" flex items-center justify-between mb-8" >
60+ <h2 class =" text-2xl font-bold text-gray-900 dark:text-white flex items-center" >
61+ <span class =" w-2 h-8 bg-blue-600 rounded-sm mr-3" ></span >
62+ Latest Writings
63+ </h2 >
64+ <div v-if =" totalPages > 1" class =" font-mono text-sm text-gray-500" >
65+ Page {{ currentPage }} / {{ totalPages }}
66+ </div >
67+ </div >
68+
69+ <div v-if =" loading" class =" grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
70+ <div v-for =" n in 6" :key =" n" class =" h-64 bg-gray-100 dark:bg-gray-800 rounded-xl animate-pulse" ></div >
71+ </div >
72+
73+ <div v-else-if =" posts.length === 0" class =" py-20 text-center text-gray-500" >
74+ <p class =" text-xl" >Nothing here yet.</p >
75+ </div >
76+
77+ <div v-else class =" grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
78+ <ArticleCardV2
79+ v-for =" post in posts"
80+ :key =" post.id"
81+ :article =" post"
82+ />
83+ </div >
84+
85+ <div class =" mt-16 flex justify-center" >
4886 <Pagination
4987 v-if =" posts.length > 0"
5088 :current-page =" currentPage"
5189 :total-pages =" totalPages"
5290 @page-change =" handlePageChange"
5391 />
5492 </div >
55-
56- <!-- 右侧侧边栏 -->
57- <!-- 在右侧边栏中使用这些组件 -->
58- <div class =" w-full md:w-1/3 mt-8 md:mt-0" >
59- <!-- 分类列表 -->
60- <div class =" mb-6" >
61- <CategoryList
62- :categories =" categories"
63- :loading =" loadingCategories"
64- title =" 文章分类"
65- />
66- </div >
67-
68- <!-- 标签云 -->
69- <div >
70- <TagCloud
71- :tags =" tags"
72- :loading =" loadingTags"
73- title =" 标签云"
74- />
75- </div >
76- </div >
77- </div >
78- </div >
79-
80- <!-- 页脚 -->
93+ </section >
94+ </main >
95+
8196 <Footer />
8297 </div >
8398</template >
8499
85100<script setup>
86101import { ref , onMounted } from ' vue' ;
87102import Navbar from ' ../components/Navbar.vue' ;
88- // import ArticleCard from '../components/ArticleCard.vue';
89- import ArticleCardV2 from ' ../components/ArticleCardV2.vue' ; // 引入新的
103+ import ArticleCardV2 from ' ../components/ArticleCardV2.vue' ; // 使用新卡片
90104import Pagination from ' ../components/Pagination.vue' ;
91105import Footer from ' ../components/Footer.vue' ;
92- import CategoryList from ' ../components/CategoryList.vue' ;
93- import TagCloud from ' ../components/TagCloud.vue' ;
94106import api from ' ../api' ;
95107
96108// 状态
97109const posts = ref ([]);
98110const loading = ref (true );
99111const currentPage = ref (1 );
100112const totalPages = ref (1 );
101- const categories = ref ([]);
102- const tags = ref ([]);
103- const loadingCategories = ref (true );
104- const loadingTags = ref (true );
105- const isAdmin = ref (false ); // 添加管理员状态检查
113+ const categories = ref ([]); // 只需要分类,用于 Bento Grid
114+ const isAdmin = ref (false );
106115
107116// 检查是否为管理员
108117const checkAdminStatus = () => {
@@ -121,40 +130,19 @@ const checkAdminStatus = () => {
121130const fetchPosts = async (page = 1 ) => {
122131 try {
123132 loading .value = true ;
124- const response = await api .getPosts ({
125- page,
126- limit: 10
127- });
128-
129- console .log (' 文章API响应:' , response);
133+ const response = await api .getPosts ({ page, limit: 9 }); // Grid 布局每页 9 个比较好看
130134
131- // 适应不同的API响应格式
135+ // 数据处理逻辑保持不变...
132136 if (Array .isArray (response)) {
133- // 如果直接返回数组
134137 posts .value = response;
135- currentPage .value = 1 ;
136- totalPages .value = 1 ;
137138 } else if (response .posts ) {
138- // 如果返回带有posts字段的对象
139139 posts .value = response .posts ;
140140 currentPage .value = response .pagination ? .currentPage || 1 ;
141141 totalPages .value = response .pagination ? .totalPages || 1 ;
142142 } else if (response .data ) {
143- // 如果返回的是 { data: [...] } 格式
144143 posts .value = response .data ;
145- currentPage .value = 1 ;
146- totalPages .value = 1 ;
147144 } else {
148- // 其他可能的格式
149145 posts .value = response || [];
150- currentPage .value = 1 ;
151- totalPages .value = 1 ;
152- }
153-
154- console .log (' 处理后的文章数据:' , posts .value );
155-
156- if (posts .value .length === 0 ) {
157- console .warn (' 文章列表为空,可能是API返回格式不符合预期或没有文章' );
158146 }
159147 } catch (error) {
160148 console .error (' 获取文章失败:' , error);
@@ -164,46 +152,34 @@ const fetchPosts = async (page = 1) => {
164152 }
165153};
166154
167- // 获取分类列表
155+ // 获取分类 (用于 Bento Grid)
168156const fetchCategories = async () => {
169157 try {
170- loadingCategories .value = true ;
171158 categories .value = await api .getCategories ();
172- console .log (' 获取到的分类数据:' , categories .value );
173159 } catch (error) {
174160 console .error (' 获取分类失败:' , error);
175- categories .value = [];
176- } finally {
177- loadingCategories .value = false ;
178161 }
179162};
180163
181- // 获取标签列表
182- const fetchTags = async () => {
183- try {
184- loadingTags .value = true ;
185- tags .value = await api .getTags ();
186- console .log (' 获取到的标签数据:' , tags .value );
187- } catch (error) {
188- console .error (' 获取标签失败:' , error);
189- tags .value = [];
190- } finally {
191- loadingTags .value = false ;
192- }
193- };
194-
195- // 分页处理
196164const handlePageChange = (page ) => {
197165 fetchPosts (page);
198- // 回到顶部
199- window .scrollTo (0 , 0 );
166+ window .scrollTo ({ top: 0 , behavior: ' smooth' });
200167};
201168
202- // 组件挂载时获取数据
203169onMounted (() => {
204170 fetchPosts ();
205171 fetchCategories ();
206- fetchTags ();
207- checkAdminStatus (); // 检查管理员状态
172+ checkAdminStatus ();
208173});
209- < / script>
174+ < / script>
175+
176+ < style scoped>
177+ /* 简单的淡入动画 */
178+ @keyframes fadeInUp {
179+ from { opacity: 0 ; transform: translateY (20px ); }
180+ to { opacity: 1 ; transform: translateY (0 ); }
181+ }
182+ .animate - fade- in - up {
183+ animation: fadeInUp 0 .6s ease- out forwards;
184+ }
185+ < / style>
0 commit comments