| | |
| | | useState, |
| | | } from 'react' |
| | | import { useTranslation } from 'react-i18next' |
| | | import { |
| | | RiEditBoxLine, |
| | | RiExpandRightLine, |
| | | RiLayoutLeft2Line, |
| | | } from '@remixicon/react' |
| | | import { useChatWithHistoryContext } from '../context' |
| | | import List from './list' |
| | | import AppIcon from '@/app/components/base/app-icon' |
| | | import ActionButton from '@/app/components/base/action-button' |
| | | import Button from '@/app/components/base/button' |
| | | import List from '@/app/components/base/chat/chat-with-history/sidebar/list' |
| | | import MenuDropdown from '@/app/components/share/text-generation/menu-dropdown' |
| | | import { Edit05 } from '@/app/components/base/icons/src/vender/line/general' |
| | | import type { ConversationItem } from '@/models/share' |
| | | import Confirm from '@/app/components/base/confirm' |
| | | import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal' |
| | | import DifyLogo from '@/app/components/base/logo/dify-logo' |
| | | import type { ConversationItem } from '@/models/share' |
| | | import cn from '@/utils/classnames' |
| | | |
| | | type Props = { |
| | | isPanel?: boolean |
| | | } |
| | | |
| | | const Sidebar = ({ isPanel }: Props) => { |
| | | const Sidebar = () => { |
| | | const { t } = useTranslation() |
| | | const { |
| | | appData, |
| | | handleNewConversation, |
| | | pinnedConversationList, |
| | | conversationList, |
| | | handleNewConversation, |
| | | currentConversationId, |
| | | handleChangeConversation, |
| | | handlePinConversation, |
| | |
| | | conversationRenaming, |
| | | handleRenameConversation, |
| | | handleDeleteConversation, |
| | | sidebarCollapseState, |
| | | handleSidebarCollapse, |
| | | isMobile, |
| | | isResponding, |
| | | } = useChatWithHistoryContext() |
| | | const isSidebarCollapsed = sidebarCollapseState |
| | | |
| | | const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null) |
| | | const [showRename, setShowRename] = useState<ConversationItem | null>(null) |
| | | |
| | |
| | | }, [showRename, handleRenameConversation, handleCancelRename]) |
| | | |
| | | return ( |
| | | <div className={cn( |
| | | 'flex w-full grow flex-col', |
| | | isPanel && 'rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-bg shadow-lg', |
| | | )}> |
| | | <div className={cn( |
| | | 'flex shrink-0 items-center gap-3 p-3 pr-2', |
| | | )}> |
| | | <div className='shrink-0'> |
| | | <AppIcon |
| | | size='large' |
| | | iconType={appData?.site.icon_type} |
| | | icon={appData?.site.icon} |
| | | background={appData?.site.icon_background} |
| | | imageUrl={appData?.site.icon_url} |
| | | /> |
| | | </div> |
| | | <div className={cn('system-md-semibold grow truncate text-text-secondary')}>{appData?.site.title}</div> |
| | | {!isMobile && isSidebarCollapsed && ( |
| | | <ActionButton size='l' onClick={() => handleSidebarCollapse(false)}> |
| | | <RiExpandRightLine className='h-[18px] w-[18px]' /> |
| | | </ActionButton> |
| | | )} |
| | | {!isMobile && !isSidebarCollapsed && ( |
| | | <ActionButton size='l' onClick={() => handleSidebarCollapse(true)}> |
| | | <RiLayoutLeft2Line className='h-[18px] w-[18px]' /> |
| | | </ActionButton> |
| | | )} |
| | | </div> |
| | | <div className='shrink-0 px-3 py-4'> |
| | | <Button variant='secondary-accent' disabled={isResponding} className='w-full justify-center' onClick={handleNewConversation}> |
| | | <RiEditBoxLine className='mr-1 h-4 w-4' /> |
| | | <div className='shrink-0 h-full flex flex-col w-[240px] border-r border-r-gray-100'> |
| | | { |
| | | !isMobile && ( |
| | | <div className='shrink-0 flex p-4'> |
| | | <AppIcon |
| | | className='mr-3' |
| | | size='small' |
| | | iconType={appData?.site.icon_type} |
| | | icon={appData?.site.icon} |
| | | background={appData?.site.icon_background} |
| | | imageUrl={appData?.site.icon_url} |
| | | /> |
| | | <div className='py-1 text-base font-semibold text-gray-800'> |
| | | {appData?.site.title} |
| | | </div> |
| | | </div> |
| | | ) |
| | | } |
| | | <div className='shrink-0 p-4'> |
| | | <Button |
| | | variant='secondary-accent' |
| | | className='justify-start w-full' |
| | | onClick={handleNewConversation} |
| | | > |
| | | <Edit05 className='mr-2 w-4 h-4' /> |
| | | {t('share.chat.newChat')} |
| | | </Button> |
| | | </div> |
| | | <div className='h-0 grow space-y-2 overflow-y-auto px-3 pt-4'> |
| | | {/* pinned list */} |
| | | {!!pinnedConversationList.length && ( |
| | | <div className='mb-4'> |
| | | <div className='grow px-4 py-2 overflow-y-auto'> |
| | | { |
| | | !!pinnedConversationList.length && ( |
| | | <div className='mb-4'> |
| | | <List |
| | | isPin |
| | | title={t('share.chat.pinnedTitle') || ''} |
| | | list={pinnedConversationList} |
| | | onChangeConversation={handleChangeConversation} |
| | | onOperate={handleOperate} |
| | | currentConversationId={currentConversationId} |
| | | /> |
| | | </div> |
| | | ) |
| | | } |
| | | { |
| | | !!conversationList.length && ( |
| | | <List |
| | | isPin |
| | | title={t('share.chat.pinnedTitle') || ''} |
| | | list={pinnedConversationList} |
| | | title={(pinnedConversationList.length && t('share.chat.unpinnedTitle')) || ''} |
| | | list={conversationList} |
| | | onChangeConversation={handleChangeConversation} |
| | | onOperate={handleOperate} |
| | | currentConversationId={currentConversationId} |
| | | /> |
| | | </div> |
| | | )} |
| | | {!!conversationList.length && ( |
| | | <List |
| | | title={(pinnedConversationList.length && t('share.chat.unpinnedTitle')) || ''} |
| | | list={conversationList} |
| | | onChangeConversation={handleChangeConversation} |
| | | onOperate={handleOperate} |
| | | currentConversationId={currentConversationId} |
| | | /> |
| | | )} |
| | | ) |
| | | } |
| | | </div> |
| | | <div className='flex shrink-0 items-center justify-between p-3'> |
| | | <MenuDropdown placement='top-start' data={appData?.site} /> |
| | | {/* powered by */} |
| | | <div className='shrink-0'> |
| | | {!appData?.custom_config?.remove_webapp_brand && ( |
| | | <div className={cn( |
| | | 'flex shrink-0 items-center gap-1.5 px-1', |
| | | )}> |
| | | <div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div> |
| | | {appData?.custom_config?.replace_webapp_logo && ( |
| | | <img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' /> |
| | | )} |
| | | {!appData?.custom_config?.replace_webapp_logo && ( |
| | | <DifyLogo size='small' /> |
| | | )} |
| | | </div> |
| | | )} |
| | | {appData?.site.copyright && ( |
| | | <div className='px-4 pb-4 text-xs text-gray-400'> |
| | | © {(new Date()).getFullYear()} {appData?.site.copyright} |
| | | </div> |
| | | </div> |
| | | )} |
| | | {!!showConfirm && ( |
| | | <Confirm |
| | | title={t('share.chat.deleteConversation.title')} |