dify/web/app/components/header/account-dropdown/main-nav-menu-content.tsx
Jingyi 9b74df21d0
feat(web): refine onboarding UI (#37433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: hjlarry <hjlarry@163.com>
Co-authored-by: fatelei <fatelei@gmail.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
Co-authored-by: gigglewang <gigglewang@dify.ai>
Co-authored-by: Yunlu Wen <yunlu.wen@dify.ai>
Co-authored-by: chariri <w@chariri.moe>
Co-authored-by: Evan <2869018789@qq.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
2026-06-15 08:47:15 +00:00

156 lines
6.0 KiB
TypeScript

'use client'
import type { ReactNode } from 'react'
import type { Theme } from '@/app/components/base/theme-selector'
import { Avatar } from '@langgenius/dify-ui/avatar'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLinkItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuRadioItemIndicator,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
import { useTheme } from 'next-themes'
import { useTranslation } from 'react-i18next'
import PremiumBadge from '@/app/components/base/premium-badge'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import { useAppContext } from '@/context/app-context'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import Link from '@/next/link'
import { ExternalLinkIndicator, MenuItemContent } from './menu-item-content'
const mainNavMenuGroupClassName = 'p-1'
const mainNavMenuItemClassName = 'mx-0 h-8 gap-1 px-3 py-1'
const mainNavMenuSubPopupClassName = 'w-60 max-h-[360px] bg-components-panel-bg-blur! p-1! backdrop-blur-[5px]'
type MainNavRadioItemContentProps = {
iconClassName?: string
label: ReactNode
}
function MainNavRadioItemContent({
iconClassName,
label,
}: MainNavRadioItemContentProps) {
const labelTitle = typeof label === 'string' ? label : undefined
return (
<>
{iconClassName && <span aria-hidden className={cn('size-4 shrink-0 text-text-tertiary', iconClassName)} />}
<span className="min-w-0 grow truncate px-1 system-md-regular text-text-secondary" title={labelTitle}>{label}</span>
<DropdownMenuRadioItemIndicator />
</>
)
}
function AppearanceSubmenu() {
const { t } = useTranslation()
const { theme, setTheme } = useTheme()
return (
<DropdownMenuSub>
<DropdownMenuSubTrigger className={mainNavMenuItemClassName}>
<MenuItemContent
iconClassName="i-ri-sun-line"
label={t('account.appearanceLabel', { ns: 'common' })}
/>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent
placement="right-start"
sideOffset={6}
popupClassName={mainNavMenuSubPopupClassName}
>
<DropdownMenuRadioGroup value={theme || 'system'} onValueChange={value => setTheme(value as Theme)}>
<DropdownMenuRadioItem value="light" closeOnClick className={mainNavMenuItemClassName}>
<MainNavRadioItemContent iconClassName="i-ri-sun-line" label={t('account.appearanceLight', { ns: 'common' })} />
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="dark" closeOnClick className={mainNavMenuItemClassName}>
<MainNavRadioItemContent iconClassName="i-ri-moon-line" label={t('account.appearanceDark', { ns: 'common' })} />
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="system" closeOnClick className={mainNavMenuItemClassName}>
<MainNavRadioItemContent iconClassName="i-ri-computer-line" label={t('account.appearanceSystem', { ns: 'common' })} />
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
)
}
type MainNavMenuContentProps = {
onLogout: () => Promise<void>
}
export function MainNavMenuContent({
onLogout,
}: MainNavMenuContentProps) {
const { t } = useTranslation()
const { userProfile } = useAppContext()
const { isEducationAccount } = useProviderContext()
const { setShowAccountSettingModal } = useModalContext()
return (
<>
<DropdownMenuGroup className={mainNavMenuGroupClassName}>
<div className="flex items-center gap-3 rounded-xl bg-gradient-to-b from-background-section-burn to-background-section p-3">
<div className="flex min-w-0 grow flex-col gap-1">
<div className="flex min-w-0 items-center gap-1">
<div className="min-w-0 flex-1 truncate body-md-medium text-text-primary" title={userProfile.name}>{userProfile.name}</div>
{isEducationAccount && (
<PremiumBadge size="s" color="blue" className="shrink-0 px-2!">
<span aria-hidden className="mr-1 i-ri-graduation-cap-fill h-3 w-3" />
<span className="system-2xs-medium">EDU</span>
</PremiumBadge>
)}
</div>
<div className="truncate system-xs-regular text-text-tertiary" title={userProfile.email}>{userProfile.email}</div>
</div>
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size="lg" className="shrink-0" />
</div>
</DropdownMenuGroup>
<DropdownMenuGroup className={mainNavMenuGroupClassName}>
<DropdownMenuLinkItem
className={cn('justify-between', mainNavMenuItemClassName)}
render={<Link href="/account" />}
>
<MenuItemContent
iconClassName="i-ri-account-circle-line"
label={t('account.account', { ns: 'common' })}
trailing={<ExternalLinkIndicator />}
/>
</DropdownMenuLinkItem>
<DropdownMenuItem
className={mainNavMenuItemClassName}
onClick={() => setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.LANGUAGE })}
>
<MenuItemContent
iconClassName="i-ri-equalizer-2-line"
label={t('settings.preferences', { ns: 'common' })}
/>
</DropdownMenuItem>
<AppearanceSubmenu />
</DropdownMenuGroup>
<DropdownMenuSeparator className="my-0! bg-divider-subtle" />
<DropdownMenuGroup className={mainNavMenuGroupClassName}>
<DropdownMenuItem
className={mainNavMenuItemClassName}
onClick={() => {
void onLogout()
}}
>
<MenuItemContent
iconClassName="i-ri-shut-down-line"
label={t('userProfile.logout', { ns: 'common' })}
/>
</DropdownMenuItem>
</DropdownMenuGroup>
</>
)
}