@@ -5,9 +5,18 @@ import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
55import { Button } from "./ui/button" ;
66import { Skeleton } from "./ui/skeleton" ;
77import { Avatar , AvatarFallback , AvatarImage } from "./ui/avatar" ;
8+ import {
9+ Item ,
10+ ItemContent ,
11+ ItemDescription ,
12+ ItemGroup ,
13+ ItemMedia ,
14+ ItemTitle ,
15+ } from "./ui/item" ;
816import { TimeAgo } from "./TimeAgo" ;
917import { getAvatarFallback , getAvatarUrl , getTabLabel } from "~/lib/brand" ;
1018import { ArrowUpRight , Handshake , MessageCircle , Trophy } from "lucide-react" ;
19+ import { TopicTabInfoCard } from "./TopicTabInfo" ;
1120
1221type SidebarData = {
1322 latest_replies : Array < {
@@ -24,7 +33,13 @@ type SidebarData = {
2433 resources : Array < { name : string ; url : string } > ;
2534} ;
2635
27- export function Sidebar ( ) {
36+ export function Sidebar ( {
37+ tab = "all" ,
38+ tabs = [ ] ,
39+ } : {
40+ tab ?: string ;
41+ tabs ?: Array < { key : string ; label : string } > ;
42+ } ) {
2843 const [ data , setData ] = useState < SidebarData | null > ( null ) ;
2944
3045 useEffect ( ( ) => {
@@ -35,25 +50,7 @@ export function Sidebar() {
3550
3651 return (
3752 < aside className = "flex flex-col gap-5 md:gap-6" >
38- < Card size = "sm" >
39- < CardHeader >
40- < CardTitle > 社区合作</ CardTitle >
41- </ CardHeader >
42- < CardContent className = "flex flex-col gap-3" >
43- < p className = "text-sm text-muted-foreground" >
44- 面向开源项目、开发者工具与 Node.js 技术活动的社区展示位。
45- </ p >
46- < Button
47- render = { < Link to = "/about#cooperation" /> }
48- variant = "secondary"
49- className = "w-full"
50- size = "sm"
51- >
52- < Handshake />
53- 了解合作方式
54- </ Button >
55- </ CardContent >
56- </ Card >
53+ < SidebarContextCard tab = { tab } label = { tabs . find ( ( item ) => item . key === tab ) ?. label } />
5754
5855 { data ? < LatestReplies replies = { data . latest_replies } /> : < SidebarSkeleton /> }
5956 { data ? < Leaderboard users = { data . top_users } /> : < SidebarSkeleton /> }
@@ -67,6 +64,33 @@ export function Sidebar() {
6764 ) ;
6865}
6966
67+ function SidebarContextCard ( { tab, label } : { tab : string ; label ?: string } ) {
68+ if ( tab !== "all" && tab !== "good" ) {
69+ return < TopicTabInfoCard tab = { tab } label = { label } /> ;
70+ }
71+ return (
72+ < Card size = "sm" >
73+ < CardHeader >
74+ < CardTitle > 社区合作</ CardTitle >
75+ </ CardHeader >
76+ < CardContent className = "flex flex-col gap-3" >
77+ < p className = "text-sm text-muted-foreground" >
78+ 面向开源项目、开发者工具与 Node.js 技术活动的社区展示位。
79+ </ p >
80+ < Button
81+ render = { < Link to = "/about#cooperation" /> }
82+ variant = "secondary"
83+ className = "w-full"
84+ size = "sm"
85+ >
86+ < Handshake />
87+ 了解合作方式
88+ </ Button >
89+ </ CardContent >
90+ </ Card >
91+ ) ;
92+ }
93+
7094function SidebarSkeleton ( ) {
7195 return (
7296 < Card size = "sm" >
@@ -86,34 +110,37 @@ function LatestReplies({ replies }: { replies: SidebarData["latest_replies"] })
86110 < CardHeader >
87111 < CardTitle > 最新回复</ CardTitle >
88112 </ CardHeader >
89- < CardContent className = "flex flex-col gap-3" >
113+ < CardContent >
114+ < ItemGroup >
90115 { replies . map ( ( reply ) => {
91116 const author = reply . author ;
92117 return (
93- < Link
118+ < Item
94119 key = { reply . id }
95- to = { `/topic/${ reply . topic_id } #${ reply . id } ` }
96- className = "group flex gap-3"
120+ render = { < Link to = { `/topic/${ reply . topic_id } #${ reply . id } ` } /> }
121+ variant = "muted"
122+ size = "xs"
97123 >
98- < Avatar className = "mt-0.5 size-8" >
99- < AvatarImage
100- src = { getAvatarUrl ( author ?. avatar_url , 32 ) }
101- alt = { author ?. loginname || "CNode" }
102- />
103- < AvatarFallback > { getAvatarFallback ( author ?. loginname ) } </ AvatarFallback >
104- </ Avatar >
105- < span className = "min-w-0 flex-1 text-xs" >
106- < span className = "block truncate font-medium text-foreground group-hover:text-primary" >
107- { reply . topic_title }
108- </ span >
109- < span className = "mt-0.5 block truncate text-muted-foreground" >
124+ < ItemMedia >
125+ < Avatar className = "size-8" >
126+ < AvatarImage
127+ src = { getAvatarUrl ( author ?. avatar_url , 32 ) }
128+ alt = { author ?. loginname || "CNode" }
129+ / >
130+ < AvatarFallback > { getAvatarFallback ( author ?. loginname ) } </ AvatarFallback >
131+ </ Avatar >
132+ </ ItemMedia >
133+ < ItemContent >
134+ < ItemTitle className = "line-clamp-2 w-full text-xs" > { reply . topic_title } </ ItemTitle >
135+ < ItemDescription >
110136 { author ?. loginname || "社区成员" } ·{ " " }
111137 { reply . create_at ? < TimeAgo date = { reply . create_at } /> : null }
112- </ span >
113- </ span >
114- </ Link >
138+ </ ItemDescription >
139+ </ ItemContent >
140+ </ Item >
115141 ) ;
116142 } ) }
143+ </ ItemGroup >
117144 </ CardContent >
118145 </ Card >
119146 ) ;
@@ -128,22 +155,22 @@ function NoReplyTopics({ topics }: { topics: SidebarData["no_reply_topics"] }) {
128155 < CardTitle > 无人回复的话题</ CardTitle >
129156 </ CardHeader >
130157 < CardContent >
131- < ul className = "flex flex-col gap-2 text-xs" >
158+ < ItemGroup >
132159 { topics . map ( ( t ) => (
133- < li key = { t . id } >
134- < Link
135- to = { `/topic/${ t . id } ` }
136- className = "block truncate font-medium text-foreground hover:text-primary"
137- >
138- { t . title }
139- </ Link >
140- < div className = "mt-0.5 flex items-center gap-2 text-muted-foreground" >
160+ < Item key = { t . id } render = { < Link to = { `/topic/${ t . id } ` } /> } variant = "muted" size = "xs" >
161+ < ItemMedia variant = "icon" >
162+ < MessageCircle />
163+ </ ItemMedia >
164+ < ItemContent >
165+ < ItemTitle className = "line-clamp-2 w-full text-xs" > { t . title } </ ItemTitle >
166+ < ItemDescription >
141167 < span > { getTabLabel ( t . tab ) } </ span >
142- { t . create_at && < TimeAgo date = { t . create_at } /> }
143- </ div >
144- </ li >
168+ { t . create_at ? < > · < TimeAgo date = { t . create_at } /> </ > : null }
169+ </ ItemDescription >
170+ </ ItemContent >
171+ </ Item >
145172 ) ) }
146- </ ul >
173+ </ ItemGroup >
147174 </ CardContent >
148175 </ Card >
149176 ) ;
0 commit comments