From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/header/account-dropdown/index.tsx | 274 +++++++++++++++++++++++++++--------------------------- 1 files changed, 136 insertions(+), 138 deletions(-) diff --git a/app/components/header/account-dropdown/index.tsx b/app/components/header/account-dropdown/index.tsx index 4a08a4c..d9065f3 100644 --- a/app/components/header/account-dropdown/index.tsx +++ b/app/components/header/account-dropdown/index.tsx @@ -2,53 +2,43 @@ import { useTranslation } from 'react-i18next' import { Fragment, useState } from 'react' import { useRouter } from 'next/navigation' -import { useContextSelector } from 'use-context-selector' -import { - RiAccountCircleLine, - RiArrowRightUpLine, - RiBookOpenLine, - RiGithubLine, - RiGraduationCapFill, - RiInformation2Line, - RiLogoutBoxRLine, - RiMap2Line, - RiSettings3Line, - RiStarLine, - RiTShirt2Line, -} from '@remixicon/react' +import { useContext } from 'use-context-selector' +import { RiArrowDownSLine, RiLogoutBoxRLine } from '@remixicon/react' import Link from 'next/link' -import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react' +import { Menu, Transition } from '@headlessui/react' import Indicator from '../indicator' import AccountAbout from '../account-about' -import GithubStar from '../github-star' -import Support from './support' -import Compliance from './compliance' -import PremiumBadge from '@/app/components/base/premium-badge' -import { useGetDocLanguage } from '@/context/i18n' +import { mailToSupport } from '../utils/util' +import WorkplaceSelector from './workplace-selector' +import classNames from '@/utils/classnames' +import I18n from '@/context/i18n' import Avatar from '@/app/components/base/avatar' -import ThemeSwitcher from '@/app/components/base/theme-switcher' import { logout } from '@/service/common' -import AppContext, { useAppContext } from '@/context/app-context' -import { useProviderContext } from '@/context/provider-context' +import { useAppContext } from '@/context/app-context' +import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows' import { useModalContext } from '@/context/modal-context' -import { LicenseStatus } from '@/types/feature' -import { IS_CLOUD_EDITION } from '@/config' -import cn from '@/utils/classnames' +import { LanguagesSupported } from '@/i18n/language' +import { useProviderContext } from '@/context/provider-context' +import { Plan } from '@/app/components/billing/type' -export default function AppSelector() { +export type IAppSelector = { + isMobile: boolean +} + +export default function AppSelector({ isMobile }: IAppSelector) { const itemClassName = ` - flex items-center w-full h-9 pl-3 pr-2 text-text-secondary system-md-regular - rounded-lg hover:bg-state-base-hover cursor-pointer gap-1 + flex items-center w-full h-9 px-3 text-text-secondary system-md-regular + rounded-lg hover:bg-state-base-hover cursor-pointer ` const router = useRouter() const [aboutVisible, setAboutVisible] = useState(false) - const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures) + const { locale } = useContext(I18n) const { t } = useTranslation() - const { userProfile, langeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext() - const { isEducationAccount } = useProviderContext() + const { userProfile, langeniusVersionInfo } = useAppContext() const { setShowAccountSettingModal } = useModalContext() - const docLanguage = useGetDocLanguage() + const { plan } = useProviderContext() + const canEmailSupport = plan.type === Plan.professional || plan.type === Plan.team || plan.type === Plan.enterprise const handleLogout = async () => { await logout({ @@ -69,9 +59,21 @@ { ({ open }) => ( <> - <MenuButton className={cn('inline-flex items-center rounded-[20px] p-0.5 hover:bg-background-default-dodge', open && 'bg-background-default-dodge')}> - <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} /> - </MenuButton> + <Menu.Button + className={` + inline-flex items-center + rounded-[20px] py-1 pr-2.5 pl-1 text-sm + text-gray-700 hover:bg-gray-200 + mobile:px-1 + ${open && 'bg-gray-200'} + `} + > + <Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='sm:mr-2 mr-0' size={32} /> + {!isMobile && <> + {userProfile.name} + <RiArrowDownSLine className="w-3 h-3 ml-1 text-gray-700" /> + </>} + </Menu.Button> <Transition as={Fragment} enter="transition ease-out duration-100" @@ -81,135 +83,131 @@ leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - <MenuItems + <Menu.Items className=" absolute right-0 mt-1.5 w-60 max-w-80 - origin-top-right divide-y divide-divider-subtle rounded-xl bg-components-panel-bg-blur shadow-lg - backdrop-blur-sm focus:outline-none + divide-y divide-divider-subtle origin-top-right rounded-lg bg-components-panel-bg-blur + shadow-lg focus:outline-none " > - <MenuItem disabled> - <div className='flex flex-nowrap items-center py-[13px] pl-3 pr-2'> - <div className='grow'> - <div className='system-md-medium break-all text-text-primary'> - {userProfile.name} - {isEducationAccount && ( - <PremiumBadge size='s' color='blue' className='ml-1 !px-2'> - <RiGraduationCapFill className='mr-1 h-3 w-3' /> - <span className='system-2xs-medium'>EDU</span> - </PremiumBadge> - )} - </div> - <div className='system-xs-regular break-all text-text-tertiary'>{userProfile.email}</div> - </div> + <Menu.Item disabled> + <div className='flex flex-nowrap items-center px-4 py-[13px]'> <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} className='mr-3' /> + <div className='grow'> + <div className='system-md-medium text-text-primary break-all'>{userProfile.name}</div> + <div className='system-xs-regular text-text-tertiary break-all'>{userProfile.email}</div> + </div> </div> - </MenuItem> + </Menu.Item> + <div className='px-1 py-1'> + <div className='mt-2 px-3 text-xs font-medium text-text-tertiary'>{t('common.userProfile.workspace')}</div> + <WorkplaceSelector /> + </div> <div className="px-1 py-1"> - <MenuItem> - <Link - className={cn(itemClassName, 'group', - 'data-[active]:bg-state-base-hover', + <Menu.Item> + {({ active }) => <Link + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', )} href='/account' target='_self' rel='noopener noreferrer'> - <RiAccountCircleLine className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.account.account')}</div> - <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' /> - </Link> - </MenuItem> - <MenuItem> - <div className={cn(itemClassName, - 'data-[active]:bg-state-base-hover', + <div>{t('common.account.account')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </Link>} + </Menu.Item> + <Menu.Item> + {({ active }) => <div className={classNames(itemClassName, + active && 'bg-state-base-hover', )} onClick={() => setShowAccountSettingModal({ payload: 'members' })}> - <RiSettings3Line className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.settings')}</div> - </div> - </MenuItem> - </div> - <div className='p-1'> - <MenuItem> - <Link - className={cn(itemClassName, 'group justify-between', - 'data-[active]:bg-state-base-hover', + <div>{t('common.userProfile.settings')}</div> + </div>} + </Menu.Item> + {canEmailSupport && <Menu.Item> + {({ active }) => <a + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', )} - href={`https://docs.dify.ai/${docLanguage}/introduction`} + href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)} target='_blank' rel='noopener noreferrer'> - <RiBookOpenLine className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.helpCenter')}</div> - <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' /> - </Link> - </MenuItem> - <Support /> - {IS_CLOUD_EDITION && isCurrentWorkspaceOwner && <Compliance />} - </div> - <div className='p-1'> - <MenuItem> - <Link - className={cn(itemClassName, 'group justify-between', - 'data-[active]:bg-state-base-hover', + <div>{t('common.userProfile.emailSupport')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </a>} + </Menu.Item>} + <Menu.Item> + {({ active }) => <Link + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', + )} + href='https://github.com/langgenius/dify/discussions/categories/feedbacks' + target='_blank' rel='noopener noreferrer'> + <div>{t('common.userProfile.communityFeedback')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </Link>} + </Menu.Item> + <Menu.Item> + {({ active }) => <Link + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', + )} + href='https://discord.gg/5AEfbxcd9k' + target='_blank' rel='noopener noreferrer'> + <div>{t('common.userProfile.community')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </Link>} + </Menu.Item> + <Menu.Item> + {({ active }) => <Link + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', + )} + href={ + locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/' : `https://docs.dify.ai/v/${locale.toLowerCase()}/` + } + target='_blank' rel='noopener noreferrer'> + <div>{t('common.userProfile.helpCenter')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </Link>} + </Menu.Item> + <Menu.Item> + {({ active }) => <Link + className={classNames(itemClassName, 'group justify-between', + active && 'bg-state-base-hover', )} href='https://roadmap.dify.ai' target='_blank' rel='noopener noreferrer'> - <RiMap2Line className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.roadmap')}</div> - <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' /> - </Link> - </MenuItem> - {systemFeatures.license.status === LicenseStatus.NONE && <MenuItem> - <Link - className={cn(itemClassName, 'group justify-between', - 'data-[active]:bg-state-base-hover', - )} - href='https://github.com/langgenius/dify' - target='_blank' rel='noopener noreferrer'> - <RiGithubLine className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.github')}</div> - <div className='flex items-center gap-0.5 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-[5px] py-[3px]'> - <RiStarLine className='size-3 shrink-0 text-text-tertiary' /> - <GithubStar className='system-2xs-medium-uppercase text-text-tertiary' /> - </div> - </Link> - </MenuItem>} + <div>{t('common.userProfile.roadmap')}</div> + <ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' /> + </Link>} + </Menu.Item> { document?.body?.getAttribute('data-public-site-about') !== 'hide' && ( - <MenuItem> - <div className={cn(itemClassName, 'justify-between', - 'data-[active]:bg-state-base-hover', + <Menu.Item> + {({ active }) => <div className={classNames(itemClassName, 'justify-between', + active && 'bg-state-base-hover', )} onClick={() => setAboutVisible(true)}> - <RiInformation2Line className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.about')}</div> - <div className='flex shrink-0 items-center'> - <div className='system-xs-regular mr-2 text-text-tertiary'>{langeniusVersionInfo.current_version}</div> + <div>{t('common.userProfile.about')}</div> + <div className='flex items-center'> + <div className='mr-2 system-xs-regular text-text-tertiary'>{langeniusVersionInfo.current_version}</div> <Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} /> </div> - </div> - </MenuItem> + </div>} + </Menu.Item> ) } </div> - <MenuItem disabled> - <div className='p-1'> - <div className={cn(itemClassName, 'hover:bg-transparent')}> - <RiTShirt2Line className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.theme.theme')}</div> - <ThemeSwitcher/> - </div> - </div> - </MenuItem> - <MenuItem> - <div className='p-1' onClick={() => handleLogout()}> + <Menu.Item> + {({ active }) => <div className='p-1' onClick={() => handleLogout()}> <div - className={cn(itemClassName, 'group justify-between', - 'data-[active]:bg-state-base-hover', - )} + className={ + classNames('flex items-center justify-between h-9 px-3 rounded-lg cursor-pointer group hover:bg-state-base-hover', + active && 'bg-state-base-hover')} > - <RiLogoutBoxRLine className='size-4 shrink-0 text-text-tertiary' /> - <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.logout')}</div> + <div className='system-md-regular text-text-secondary'>{t('common.userProfile.logout')}</div> + <RiLogoutBoxRLine className='hidden w-4 h-4 text-text-tertiary group-hover:flex' /> </div> - </div> - </MenuItem> - </MenuItems> + </div>} + </Menu.Item> + </Menu.Items> </Transition> </> ) -- Gitblit v1.8.0