| | |
| | | import { pinyin } from 'pinyin-pro' |
| | | import type { FC, RefObject } from 'react' |
| | | import type { ToolWithProvider } from '../types' |
| | | import { CollectionType } from '../../tools/types' |
| | | import classNames from '@/utils/classnames' |
| | | |
| | | export const CUSTOM_GROUP_NAME = '@@@custom@@@' |
| | | export const WORKFLOW_GROUP_NAME = '@@@workflow@@@' |
| | | export const AGENT_GROUP_NAME = '@@@agent@@@' |
| | | /* |
| | | { |
| | | A: { |
| | | 'google': [ // plugin organize name |
| | | ...tools |
| | | ], |
| | | 'custom': [ // custom tools |
| | | ...tools |
| | | ], |
| | | 'workflow': [ // workflow as tools |
| | | ...tools |
| | | ] |
| | | } |
| | | } |
| | | */ |
| | | export const groupItems = (items: ToolWithProvider[], getFirstChar: (item: ToolWithProvider) => string) => { |
| | | const groups = items.reduce((acc: Record<string, Record<string, ToolWithProvider[]>>, item) => { |
| | | export const groupItems = (items: Array<any>, getFirstChar: (item: string) => string) => { |
| | | const groups = items.reduce((acc, item) => { |
| | | const firstChar = getFirstChar(item) |
| | | if (!firstChar || firstChar.length === 0) |
| | | return acc |
| | |
| | | letter = '#' |
| | | |
| | | if (!acc[letter]) |
| | | acc[letter] = {} |
| | | acc[letter] = [] |
| | | |
| | | let groupName: string = '' |
| | | if (item.type === CollectionType.builtIn) |
| | | groupName = item.author |
| | | else if (item.type === CollectionType.custom) |
| | | groupName = CUSTOM_GROUP_NAME |
| | | else if (item.type === CollectionType.workflow) |
| | | groupName = WORKFLOW_GROUP_NAME |
| | | else |
| | | groupName = AGENT_GROUP_NAME |
| | | |
| | | if (!acc[letter][groupName]) |
| | | acc[letter][groupName] = [] |
| | | |
| | | acc[letter][groupName].push(item) |
| | | |
| | | acc[letter].push(item) |
| | | return acc |
| | | }, {}) |
| | | |
| | |
| | | type IndexBarProps = { |
| | | letters: string[] |
| | | itemRefs: RefObject<{ [key: string]: HTMLElement | null }> |
| | | className?: string |
| | | } |
| | | |
| | | const IndexBar: FC<IndexBarProps> = ({ letters, itemRefs, className }) => { |
| | | const IndexBar: FC<IndexBarProps> = ({ letters, itemRefs }) => { |
| | | const handleIndexClick = (letter: string) => { |
| | | const element = itemRefs.current?.[letter] |
| | | if (element) |
| | | element.scrollIntoView({ behavior: 'smooth' }) |
| | | } |
| | | return ( |
| | | <div className={classNames('index-bar absolute right-0 top-36 flex flex-col items-center w-6 justify-center text-xs font-medium text-text-quaternary', className)}> |
| | | <div className='absolute left-0 top-0 h-full w-px bg-[linear-gradient(270deg,rgba(255,255,255,0)_0%,rgba(16,24,40,0.08)_30%,rgba(16,24,40,0.08)_50%,rgba(16,24,40,0.08)_70.5%,rgba(255,255,255,0)_100%)]'></div> |
| | | <div className="index-bar fixed right-4 top-36 flex flex-col items-center text-xs font-medium text-text-quaternary"> |
| | | {letters.map(letter => ( |
| | | <div className="cursor-pointer hover:text-text-secondary" key={letter} onClick={() => handleIndexClick(letter)}> |
| | | <div className="hover:text-text-secondary cursor-pointer" key={letter} onClick={() => handleIndexClick(letter)}> |
| | | {letter} |
| | | </div> |
| | | ))} |