blob: 382c9422aa4a08e1aaf1f60637d7c1ade92f9585 [file] [log] [blame]
wua80b90d2025-06-15 10:36:02 +08001// src/components/HomeFeed.jsx
wueb6e6ca2025-06-15 10:35:32 +08002
wua80b90d2025-06-15 10:36:02 +08003import React, { useState, useEffect } from 'react'
4import { ThumbsUp } from 'lucide-react'
5import { fetchPosts, fetchPost } from '../api/posts'
6import '../style/HomeFeed.css'
wueb6e6ca2025-06-15 10:35:32 +08007
8const categories = [
9 '推荐','穿搭','美食','彩妆','影视',
10 '职场','情感','家居','游戏','旅行','健身'
11]
12
13export default function HomeFeed() {
14 const [activeCat, setActiveCat] = useState('推荐')
wua80b90d2025-06-15 10:36:02 +080015 const [items, setItems] = useState([])
16 const [loading, setLoading] = useState(true)
17 const [error, setError] = useState(null)
18
19 useEffect(() => {
20 async function loadPosts() {
21 try {
22 const list = await fetchPosts() // [{id, title, heat, created_at}, …]
TRM-coding4f9260c2025-06-20 19:01:39 +080023
24 // 第一轮:立即展示基础信息
25 const basicItems = list.map(p => ({
26 id: p.id,
27 title: p.title,
28 author: `作者 ${p.user_id || 'unknown'}`,
29 avatar: `https://i.pravatar.cc/40?img=${p.user_id || 1}`,
30 img: '', // 暂时为空
31 likes: p.heat || 0,
32 loading: true // 标记图片正在加载
33 }))
34
35 setItems(basicItems)
36 setLoading(false) // 基础内容已加载完成
37
38 // 第二轮:异步加载详情和图片
39 basicItems.forEach(async (item, index) => {
40 try {
41 const detail = await fetchPost(item.id)
42 setItems(prevItems =>
43 prevItems.map(prevItem =>
44 prevItem.id === item.id
45 ? {
46 ...prevItem,
47 img: detail.media_urls?.[0] || '',
48 loading: false
49 }
50 : prevItem
51 )
52 )
53 } catch (e) {
54 // 单个图片加载失败不影响其他
55 setItems(prevItems =>
56 prevItems.map(prevItem =>
57 prevItem.id === item.id
58 ? { ...prevItem, loading: false }
59 : prevItem
60 )
61 )
62 }
63 })
64
wua80b90d2025-06-15 10:36:02 +080065 } catch (e) {
66 setError(e.message)
wua80b90d2025-06-15 10:36:02 +080067 setLoading(false)
68 }
69 }
70 loadPosts()
71 }, [])
wueb6e6ca2025-06-15 10:35:32 +080072
73 return (
74 <div className="home-feed">
75 {/* 顶部分类 */}
76 <nav className="feed-tabs">
77 {categories.map(cat => (
78 <button
79 key={cat}
80 className={cat === activeCat ? 'tab active' : 'tab'}
81 onClick={() => setActiveCat(cat)}
82 >
83 {cat}
84 </button>
85 ))}
86 </nav>
87
wua80b90d2025-06-15 10:36:02 +080088 {/* 状态提示 */}
89 {loading ? (
90 <div className="loading">加载中…</div>
91 ) : error ? (
92 <div className="error">加载失败:{error}</div>
93 ) : (
94 /* 瀑布流卡片区 */
95 <div className="feed-grid">
96 {items.map(item => (
97 <div key={item.id} className="feed-card">
TRM-coding4f9260c2025-06-20 19:01:39 +080098 {item.loading ? (
99 <div className="card-img-placeholder">图片加载中...</div>
100 ) : (
101 <img className="card-img" src={item.img} alt={item.title} />
102 )}
wua80b90d2025-06-15 10:36:02 +0800103 <h3 className="card-title">{item.title}</h3>
104 <div className="card-footer">
105 <div className="card-author">
106 <img className="avatar" src={item.avatar} alt={item.author} />
107 <span className="username">{item.author}</span>
108 </div>
109 <div className="card-likes">
110 <ThumbsUp size={16} />
111 <span className="likes-count">{item.likes}</span>
112 </div>
wueb6e6ca2025-06-15 10:35:32 +0800113 </div>
114 </div>
wua80b90d2025-06-15 10:36:02 +0800115 ))}
116 </div>
117 )}
wueb6e6ca2025-06-15 10:35:32 +0800118 </div>
119 )
wua80b90d2025-06-15 10:36:02 +0800120}