11'use client' ;
22
3- import { Avatar , Block , Flexbox , Icon , Tag , Text , Tooltip , TooltipGroup } from '@lobehub/ui' ;
4- import { createStaticStyles } from 'antd-style' ;
5- import { ClockIcon , DownloadIcon , UsersIcon } from 'lucide-react' ;
3+ import {
4+ Tag as AntTag ,
5+ Avatar ,
6+ Block ,
7+ DropdownMenu ,
8+ Flexbox ,
9+ Icon ,
10+ Tag ,
11+ Text ,
12+ Tooltip ,
13+ TooltipGroup ,
14+ } from '@lobehub/ui' ;
15+ import { createStaticStyles , cx } from 'antd-style' ;
16+ import {
17+ AlertTriangle ,
18+ ClockIcon ,
19+ DownloadIcon ,
20+ Eye ,
21+ EyeOff ,
22+ MoreVerticalIcon ,
23+ Pencil ,
24+ UsersIcon ,
25+ } from 'lucide-react' ;
626import qs from 'query-string' ;
727import { memo , useCallback } from 'react' ;
828import { useTranslation } from 'react-i18next' ;
929import { Link , useNavigate } from 'react-router-dom' ;
1030import urlJoin from 'url-join' ;
1131
1232import PublishedTime from '@/components/PublishedTime' ;
13- import { type DiscoverGroupAgentItem } from '@/types/discover' ;
33+ import { type DiscoverGroupAgentItem , type GroupAgentStatus } from '@/types/discover' ;
1434import { formatIntergerNumber } from '@/utils/format' ;
1535
36+ import { useUserDetailContext } from './DetailProvider' ;
37+
38+ const getStatusTagColor = ( status ?: GroupAgentStatus ) => {
39+ switch ( status ) {
40+ case 'published' : {
41+ return 'green' ;
42+ }
43+ case 'unpublished' : {
44+ return 'orange' ;
45+ }
46+ case 'deprecated' : {
47+ return 'red' ;
48+ }
49+ case 'archived' : {
50+ return 'default' ;
51+ }
52+ default : {
53+ return 'default' ;
54+ }
55+ }
56+ } ;
57+
1658const styles = createStaticStyles ( ( { css, cssVar } ) => {
1759 return {
1860 desc : css `
@@ -25,6 +67,16 @@ const styles = createStaticStyles(({ css, cssVar }) => {
2567 border-block-start : 1px dashed ${ cssVar . colorBorder } ;
2668 background : ${ cssVar . colorBgContainer } ;
2769 ` ,
70+ moreButton : css `
71+ position : absolute;
72+ z-index : 10 ;
73+ inset-block-start : 12px ;
74+ inset-inline-end : 12px ;
75+
76+ opacity : 0 ;
77+
78+ transition : opacity 0.2s ;
79+ ` ,
2880 secondaryDesc : css `
2981 font-size : 12px ;
3082 color : ${ cssVar . colorTextDescription } ;
@@ -47,15 +99,31 @@ const styles = createStaticStyles(({ css, cssVar }) => {
4799 color : ${ cssVar . colorLink } ;
48100 }
49101 ` ,
102+ wrapper : css `
103+ & : hover .more-button {
104+ opacity : 1 ;
105+ }
106+ ` ,
50107 } ;
51108} ) ;
52109
53110type UserGroupCardProps = DiscoverGroupAgentItem ;
54111
55112const UserGroupCard = memo < UserGroupCardProps > (
56- ( { avatar, title, description, createdAt, category, installCount, identifier, memberCount } ) => {
57- const { t } = useTranslation ( [ 'discover' ] ) ;
113+ ( {
114+ avatar,
115+ title,
116+ description,
117+ createdAt,
118+ category,
119+ installCount,
120+ identifier,
121+ memberCount,
122+ status,
123+ } ) => {
124+ const { t } = useTranslation ( [ 'discover' , 'setting' ] ) ;
58125 const navigate = useNavigate ( ) ;
126+ const { isOwner, onStatusChange } = useUserDetailContext ( ) ;
59127
60128 const link = qs . stringifyUrl (
61129 {
@@ -65,12 +133,55 @@ const UserGroupCard = memo<UserGroupCardProps>(
65133 { skipNull : true } ,
66134 ) ;
67135
136+ const isPublished = status === 'published' ;
137+
68138 const handleCardClick = useCallback ( ( ) => {
69139 navigate ( link ) ;
70140 } , [ link , navigate ] ) ;
71141
142+ const handleEdit = useCallback ( ( ) => {
143+ navigate ( urlJoin ( '/group' , identifier , 'profile' ) ) ;
144+ } , [ identifier , navigate ] ) ;
145+
146+ const handleStatusAction = useCallback (
147+ ( action : 'publish' | 'unpublish' | 'deprecate' ) => {
148+ onStatusChange ?.( identifier , action , 'group' ) ;
149+ } ,
150+ [ identifier , onStatusChange ] ,
151+ ) ;
152+
153+ const menuItems = isOwner
154+ ? [
155+ {
156+ icon : < Icon icon = { Pencil } /> ,
157+ key : 'edit' ,
158+ label : t ( 'setting:myAgents.actions.edit' ) ,
159+ onClick : handleEdit ,
160+ } ,
161+ {
162+ type : 'divider' as const ,
163+ } ,
164+ {
165+ icon : < Icon icon = { isPublished ? EyeOff : Eye } /> ,
166+ key : 'togglePublish' ,
167+ label : isPublished
168+ ? t ( 'setting:myAgents.actions.unpublish' )
169+ : t ( 'setting:myAgents.actions.publish' ) ,
170+ onClick : ( ) => handleStatusAction ( isPublished ? 'unpublish' : 'publish' ) ,
171+ } ,
172+ {
173+ danger : true ,
174+ icon : < Icon icon = { AlertTriangle } /> ,
175+ key : 'deprecate' ,
176+ label : t ( 'setting:myAgents.actions.deprecate' ) ,
177+ onClick : ( ) => handleStatusAction ( 'deprecate' ) ,
178+ } ,
179+ ]
180+ : [ ] ;
181+
72182 return (
73183 < Block
184+ className = { styles . wrapper }
74185 clickable
75186 height = { '100%' }
76187 onClick = { handleCardClick }
@@ -82,6 +193,15 @@ const UserGroupCard = memo<UserGroupCardProps>(
82193 variant = { 'outlined' }
83194 width = { '100%' }
84195 >
196+ { isOwner && (
197+ < div onClick = { ( e ) => e . stopPropagation ( ) } >
198+ < DropdownMenu items = { menuItems as any } >
199+ < div className = { cx ( 'more-button' , styles . moreButton ) } >
200+ < Icon icon = { MoreVerticalIcon } size = { 16 } style = { { cursor : 'pointer' } } />
201+ </ div >
202+ </ DropdownMenu >
203+ </ div >
204+ ) }
85205 < Flexbox
86206 align = { 'flex-start' }
87207 gap = { 16 }
@@ -105,15 +225,22 @@ const UserGroupCard = memo<UserGroupCardProps>(
105225 overflow : 'hidden' ,
106226 } }
107227 >
108- < Link
109- onClick = { ( e ) => e . stopPropagation ( ) }
110- style = { { color : 'inherit' , flex : 1 , overflow : 'hidden' } }
111- to = { link }
112- >
113- < Text as = { 'h3' } className = { styles . title } ellipsis style = { { flex : 1 } } >
114- { title }
115- </ Text >
116- </ Link >
228+ < Flexbox align = { 'center' } gap = { 8 } horizontal >
229+ < Link
230+ onClick = { ( e ) => e . stopPropagation ( ) }
231+ style = { { color : 'inherit' , flex : 1 , overflow : 'hidden' } }
232+ to = { link }
233+ >
234+ < Text as = { 'h3' } className = { styles . title } ellipsis style = { { flex : 1 } } >
235+ { title }
236+ </ Text >
237+ </ Link >
238+ { isOwner && status && (
239+ < AntTag color = { getStatusTagColor ( status ) } style = { { flexShrink : 0 , margin : 0 } } >
240+ { t ( `setting:myAgents.status.${ status } ` ) }
241+ </ AntTag >
242+ ) }
243+ </ Flexbox >
117244 </ Flexbox >
118245 </ Flexbox >
119246 </ Flexbox >
0 commit comments