source: chapterx-frontend/src/pages/reading-list/CommunityListsPage.tsx@ acf690c

main
Last change on this file since acf690c was b62cefc, checked in by kikisrbinoska <srbinoskakristina07@…>, 4 months ago

Added frontend and imporoved AI Suggestions service

  • Property mode set to 100644
File size: 5.7 KB
RevLine 
[b62cefc]1import React, { useState } from 'react'
2import { useNavigate } from 'react-router-dom'
3import { Globe, BookOpen, User } from 'lucide-react'
4import { useStoryStore } from '../../store/storyStore'
5import { ReadingList } from '../../types'
6import { Modal } from '../../components/ui/Modal'
7import { GenreBadge } from '../../components/ui/Badge'
8import { Avatar } from '../../components/ui/Avatar'
9
10export const CommunityListsPage: React.FC = () => {
11 const navigate = useNavigate()
12 const { readingLists } = useStoryStore()
13 const [selectedList, setSelectedList] = useState<ReadingList | null>(null)
14
15 const publicLists = readingLists.filter(l => l.is_public)
16
17 return (
18 <div className="max-w-6xl mx-auto px-4 py-8">
19 {/* Header */}
20 <div className="mb-8">
21 <div className="flex items-center gap-2 mb-2">
22 <Globe size={20} className="text-indigo-400" />
23 <h1 className="font-serif text-3xl font-bold text-white">Community Reading Lists</h1>
24 </div>
25 <p className="text-slate-400">Discover curated lists from the ChapterX community</p>
26 </div>
27
28 {publicLists.length === 0 ? (
29 <div className="flex flex-col items-center py-20 text-slate-500">
30 <Globe size={48} className="mb-4 opacity-40" />
31 <p className="text-lg font-medium">No public lists yet</p>
32 <p className="text-sm mt-1">Be the first to share your reading list!</p>
33 </div>
34 ) : (
35 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
36 {publicLists.map(list => (
37 <div
38 key={list.list_id}
39 className="bg-slate-800 border border-slate-700 rounded-2xl overflow-hidden hover:border-indigo-500/30 transition-all cursor-pointer group"
40 onClick={() => setSelectedList(list)}
41 >
42 {/* Cover preview */}
43 <div className="h-24 bg-gradient-to-br from-indigo-900/50 via-violet-900/30 to-slate-900 p-4 flex items-end">
44 <div className="flex gap-1">
45 {Array.from({ length: Math.min(3, list.stories.length) }).map((_, i) => (
46 <div key={i} className={`w-10 h-14 rounded bg-slate-700 border border-slate-600 -ml-${i > 0 ? '2' : '0'}`} style={{ transform: `rotate(${(i - 1) * 5}deg)` }} />
47 ))}
48 </div>
49 </div>
50
51 <div className="p-5">
52 <div className="flex items-start justify-between gap-2 mb-3">
53 <h3 className="text-white font-semibold group-hover:text-indigo-300 transition-colors">
54 {list.name}
55 </h3>
56 <span className="flex items-center gap-1 text-xs text-emerald-400 flex-shrink-0">
57 <Globe size={11} /> Public
58 </span>
59 </div>
60
61 <div className="flex items-center gap-2 mb-3">
62 <Avatar name={list.username} size="sm" />
63 <span className="text-slate-400 text-sm">@{list.username}</span>
64 </div>
65
66 {list.description && (
67 <p className="text-slate-500 text-sm mb-3 line-clamp-2">{list.description}</p>
68 )}
69
70 <div className="flex items-center justify-between text-xs text-slate-500">
71 <span className="flex items-center gap-1">
72 <BookOpen size={12} />
73 {list.stories.length} stories
74 </span>
75 <button
76 className="text-indigo-400 hover:text-indigo-300 transition-colors"
77 onClick={e => { e.stopPropagation(); setSelectedList(list) }}
78 >
79 View list →
80 </button>
81 </div>
82 </div>
83 </div>
84 ))}
85 </div>
86 )}
87
88 {/* List detail modal */}
89 {selectedList && (
90 <Modal
91 isOpen={!!selectedList}
92 onClose={() => setSelectedList(null)}
93 title={selectedList.name}
94 size="lg"
95 >
96 <div>
97 <div className="flex items-center gap-2 mb-4">
98 <Avatar name={selectedList.username} size="sm" />
99 <div>
100 <p className="text-white text-sm font-medium">@{selectedList.username}</p>
101 <p className="text-slate-500 text-xs">{selectedList.stories.length} stories</p>
102 </div>
103 </div>
104 {selectedList.description && (
105 <p className="text-slate-400 text-sm mb-4">{selectedList.description}</p>
106 )}
107
108 {selectedList.stories.length === 0 ? (
109 <p className="text-slate-500 text-sm text-center py-8">This list is empty.</p>
110 ) : (
111 <div className="space-y-3">
112 {selectedList.stories.map(item => (
113 <div
114 key={item.item_id}
115 className="flex items-center gap-3 p-3 bg-slate-800 rounded-xl border border-slate-700 hover:border-indigo-500/40 cursor-pointer transition-colors"
116 onClick={() => { navigate(`/story/${item.story_id}`); setSelectedList(null) }}
117 >
118 <div className="flex-1 min-w-0">
119 <p className="text-white font-medium text-sm">{item.story_title}</p>
120 <p className="text-slate-500 text-xs">by {item.author_username}</p>
121 </div>
122 <div className="flex flex-wrap gap-1">
123 {item.genres.slice(0, 2).map(g => <GenreBadge key={g} genre={g} />)}
124 </div>
125 </div>
126 ))}
127 </div>
128 )}
129 </div>
130 </Modal>
131 )}
132 </div>
133 )
134}
Note: See TracBrowser for help on using the repository browser.