| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  | import type { FC } from 'react' | 
					
						
							|  |  |  | import { useMemo, useState } from 'react' | 
					
						
							|  |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import { RiArrowDownSLine, RiCheckLine, RiSortAsc, RiSortDesc } from '@remixicon/react' | 
					
						
							|  |  |  | import cn from '@/utils/classnames' | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   PortalToFollowElem, | 
					
						
							|  |  |  |   PortalToFollowElemContent, | 
					
						
							|  |  |  |   PortalToFollowElemTrigger, | 
					
						
							|  |  |  | } from '@/app/components/base/portal-to-follow-elem' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type Item = { | 
					
						
							|  |  |  |   value: number | string | 
					
						
							|  |  |  |   name: string | 
					
						
							|  |  |  | } & Record<string, any> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  | type Props = { | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |   order?: string | 
					
						
							|  |  |  |   value: number | string | 
					
						
							|  |  |  |   items: Item[] | 
					
						
							|  |  |  |   onSelect: (item: any) => void | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | const Sort: FC<Props> = ({ | 
					
						
							|  |  |  |   order, | 
					
						
							|  |  |  |   value, | 
					
						
							|  |  |  |   items, | 
					
						
							|  |  |  |   onSelect, | 
					
						
							|  |  |  | }) => { | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const [open, setOpen] = useState(false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const triggerContent = useMemo(() => { | 
					
						
							|  |  |  |     return items.find(item => item.value === value)?.name || '' | 
					
						
							|  |  |  |   }, [items, value]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <div className='inline-flex items-center'> | 
					
						
							|  |  |  |       <PortalToFollowElem | 
					
						
							|  |  |  |         open={open} | 
					
						
							|  |  |  |         onOpenChange={setOpen} | 
					
						
							|  |  |  |         placement='bottom-start' | 
					
						
							|  |  |  |         offset={4} | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         <div className='relative'> | 
					
						
							|  |  |  |           <PortalToFollowElemTrigger | 
					
						
							|  |  |  |             onClick={() => setOpen(v => !v)} | 
					
						
							|  |  |  |             className='block' | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             <div className={cn( | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |               'flex cursor-pointer items-center rounded-l-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt', | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |               open && '!bg-state-base-hover-alt hover:bg-state-base-hover-alt', | 
					
						
							|  |  |  |             )}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |               <div className='flex items-center gap-0.5 p-1'> | 
					
						
							|  |  |  |                 <div className='system-sm-regular text-text-tertiary'>{t('appLog.filter.sortBy')}</div> | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |                 <div className={cn('system-sm-regular text-text-tertiary', !!value && 'text-text-secondary')}> | 
					
						
							|  |  |  |                   {triggerContent} | 
					
						
							|  |  |  |                 </div> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |               <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' /> | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           </PortalToFollowElemTrigger> | 
					
						
							|  |  |  |           <PortalToFollowElemContent className='z-[1002]'> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             <div className='relative w-[240px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'> | 
					
						
							|  |  |  |               <div className='max-h-72 overflow-auto p-1'> | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |                 {items.map(item => ( | 
					
						
							|  |  |  |                   <div | 
					
						
							|  |  |  |                     key={item.value} | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |                     className='flex cursor-pointer items-center gap-2 rounded-lg px-2 py-[6px] pl-3 hover:bg-state-base-hover' | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |                     onClick={() => { | 
					
						
							|  |  |  |                       onSelect(`${order}${item.value}`) | 
					
						
							|  |  |  |                       setOpen(false) | 
					
						
							|  |  |  |                     }} | 
					
						
							|  |  |  |                   > | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |                     <div title={item.name} className='system-sm-medium grow truncate text-text-secondary'>{item.name}</div> | 
					
						
							|  |  |  |                     {value === item.value && <RiCheckLine className='h-4 w-4 shrink-0 text-util-colors-blue-light-blue-light-600' />} | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |                   </div> | 
					
						
							|  |  |  |                 ))} | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           </PortalToFollowElemContent> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       </PortalToFollowElem> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |       <div className='ml-px cursor-pointer rounded-r-lg bg-components-button-tertiary-bg p-2 hover:bg-components-button-tertiary-bg-hover' onClick={() => onSelect(`${order ? '' : '-'}${value}`)}> | 
					
						
							|  |  |  |         {!order && <RiSortAsc className='h-4 w-4 text-components-button-tertiary-text' />} | 
					
						
							|  |  |  |         {order && <RiSortDesc className='h-4 w-4 text-components-button-tertiary-text' />} | 
					
						
							| 
									
										
										
										
											2024-08-20 17:55:44 +08:00
										 |  |  |       </div> | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default Sort |