Chore: frontend infrastructure upgrade (#16420)

Co-authored-by: NFish <douxc512@gmail.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: jZonG <jzongcode@gmail.com>
This commit is contained in:
Joel 2025-03-21 17:41:03 +08:00 • committed by GitHub
commit 7709d9df20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1435 changed files with 13372 additions and 11612 deletions

View file

@ -83,13 +83,13 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
return (
<>
<div>
<div className="relative group">
<div className="group relative">
<Avatar {...props} />
<div
onClick={() => { setIsShowAvatarPicker(true) }}
className="absolute inset-0 bg-black bg-opacity-50 rounded-full opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer flex items-center justify-center"
className="absolute inset-0 flex cursor-pointer items-center justify-center rounded-full bg-black bg-opacity-50 opacity-0 transition-opacity group-hover:opacity-100"
>
<span className="text-white text-xs">
<span className="text-xs text-white">
<RiPencilLine />
</span>
</div>
@ -105,7 +105,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
<ImageInput onImageInput={handleImageInput} cropShape='round' />
<Divider className='m-0' />
<div className='w-full flex items-center justify-center p-3 gap-2'>
<div className='flex w-full items-center justify-center gap-2 p-3'>
<Button className='w-full' onClick={() => setIsShowAvatarPicker(false)}>
{t('app.iconPicker.cancel')}
</Button>

View file

@ -122,17 +122,17 @@ export default function AccountPage() {
<div className='mr-3'>
<AppIcon size='tiny' />
</div>
<div className='mt-[3px] system-sm-medium text-text-secondary'>{item.name}</div>
<div className='system-sm-medium mt-[3px] text-text-secondary'>{item.name}</div>
</div>
)
}
return (
<>
<div className='pt-2 pb-3'>
<div className='pb-3 pt-2'>
<h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4>
</div>
<div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'>
<div className='mb-8 flex items-center rounded-xl bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-6'>
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={ mutateUserProfile } size={64} />
<div className='ml-4'>
<p className='system-xl-semibold text-text-primary'>{userProfile.name}</p>
@ -141,19 +141,19 @@ export default function AccountPage() {
</div>
<div className='mb-8'>
<div className={titleClassName}>{t('common.account.name')}</div>
<div className='flex items-center justify-between gap-2 w-full mt-2'>
<div className='flex-1 bg-components-input-bg-normal rounded-lg p-2 system-sm-regular text-components-input-text-filled '>
<div className='mt-2 flex w-full items-center justify-between gap-2'>
<div className='system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled '>
<span className='pl-1'>{userProfile.name}</span>
</div>
<div className='bg-components-button-tertiary-bg rounded-lg py-2 px-3 cursor-pointer system-sm-medium text-components-button-tertiary-text' onClick={handleEditName}>
<div className='system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text' onClick={handleEditName}>
{t('common.operation.edit')}
</div>
</div>
</div>
<div className='mb-8'>
<div className={titleClassName}>{t('common.account.email')}</div>
<div className='flex items-center justify-between gap-2 w-full mt-2'>
<div className='flex-1 bg-components-input-bg-normal rounded-lg p-2 system-sm-regular text-components-input-text-filled '>
<div className='mt-2 flex w-full items-center justify-between gap-2'>
<div className='system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled '>
<span className='pl-1'>{userProfile.email}</span>
</div>
</div>
@ -162,8 +162,8 @@ export default function AccountPage() {
systemFeatures.enable_email_password_login && (
<div className='mb-8 flex justify-between gap-2'>
<div>
<div className='mb-1 system-sm-semibold text-text-secondary'>{t('common.account.password')}</div>
<div className='mb-2 body-xs-regular text-text-tertiary'>{t('common.account.passwordTip')}</div>
<div className='system-sm-semibold mb-1 text-text-secondary'>{t('common.account.password')}</div>
<div className='body-xs-regular mb-2 text-text-tertiary'>{t('common.account.passwordTip')}</div>
</div>
<Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</Button>
</div>
@ -190,13 +190,13 @@ export default function AccountPage() {
onClose={() => setEditNameModalVisible(false)}
className={s.modal}
>
<div className='mb-6 title-2xl-semi-bold text-text-primary'>{t('common.account.editName')}</div>
<div className='title-2xl-semi-bold mb-6 text-text-primary'>{t('common.account.editName')}</div>
<div className={titleClassName}>{t('common.account.name')}</div>
<Input className='mt-2'
value={editName}
onChange={e => setEditName(e.target.value)}
/>
<div className='flex justify-end mt-10'>
<div className='mt-10 flex justify-end'>
<Button className='mr-2' onClick={() => setEditNameModalVisible(false)}>{t('common.operation.cancel')}</Button>
<Button
disabled={editing || !editName}
@ -219,7 +219,7 @@ export default function AccountPage() {
}}
className={s.modal}
>
<div className='mb-6 title-2xl-semi-bold text-text-primary'>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div>
<div className='title-2xl-semi-bold mb-6 text-text-primary'>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div>
{userProfile.is_password_set && (
<>
<div className={titleClassName}>{t('common.account.currentPassword')}</div>
@ -242,7 +242,7 @@ export default function AccountPage() {
</div>
</>
)}
<div className='mt-8 system-sm-semibold text-text-secondary'>
<div className='system-sm-semibold mt-8 text-text-secondary'>
{userProfile.is_password_set ? t('common.account.newPassword') : t('common.account.password')}
</div>
<div className='relative mt-2'>
@ -261,7 +261,7 @@ export default function AccountPage() {
</Button>
</div>
</div>
<div className='mt-8 system-sm-semibold text-text-secondary'>{t('common.account.confirmPassword')}</div>
<div className='system-sm-semibold mt-8 text-text-secondary'>{t('common.account.confirmPassword')}</div>
<div className='relative mt-2'>
<Input
type={showConfirmPassword ? 'text' : 'password'}
@ -278,7 +278,7 @@ export default function AccountPage() {
</Button>
</div>
</div>
<div className='flex justify-end mt-10'>
<div className='mt-10 flex justify-end'>
<Button className='mr-2' onClick={() => {
setEditPasswordModalVisible(false)
resetPasswordForm()

View file

@ -2,13 +2,13 @@
import { useTranslation } from 'react-i18next'
import { Fragment } from 'react'
import { useRouter } from 'next/navigation'
import { Menu, Transition } from '@headlessui/react'
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
import Avatar from '@/app/components/base/avatar'
import { logout } from '@/service/common'
import { useAppContext } from '@/context/app-context'
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
export interface IAppSelector {
export type IAppSelector = {
isMobile: boolean
}
@ -36,17 +36,17 @@ export default function AppSelector() {
({ open }) => (
<>
<div>
<Menu.Button
<MenuButton
className={`
inline-flex items-center
rounded-[20px] p-1x text-sm
p-1x inline-flex
items-center rounded-[20px] text-sm
text-text-primary
mobile:px-1
${open && 'bg-components-panel-bg-blur'}
`}
>
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
</Menu.Button>
</MenuButton>
</div>
<Transition
as={Fragment}
@ -57,35 +57,35 @@ export default function AppSelector() {
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
<MenuItems
className="
absolute -right-2 -top-1 w-60 max-w-80
divide-y divide-divider-subtle origin-top-right rounded-lg bg-components-panel-bg-blur
origin-top-right divide-y divide-divider-subtle rounded-lg bg-components-panel-bg-blur
shadow-lg
"
>
<Menu.Item>
<MenuItem>
<div className='p-1'>
<div className='flex flex-nowrap items-center px-3 py-2'>
<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 className='system-md-medium break-all text-text-primary'>{userProfile.name}</div>
<div className='system-xs-regular break-all text-text-tertiary'>{userProfile.email}</div>
</div>
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
</div>
</div>
</Menu.Item>
<Menu.Item>
</MenuItem>
<MenuItem>
<div className='p-1' onClick={() => handleLogout()}>
<div
className='flex items-center justify-start h-9 px-3 rounded-lg cursor-pointer group hover:bg-state-base-hover'
className='group flex h-9 cursor-pointer items-center justify-start rounded-lg px-3 hover:bg-state-base-hover'
>
<LogOut01 className='w-4 h-4 text-text-tertiary flex mr-1' />
<div className='font-normal text-[14px] text-text-secondary'>{t('common.userProfile.logout')}</div>
<LogOut01 className='mr-1 flex h-4 w-4 text-text-tertiary' />
<div className='text-[14px] font-normal text-text-secondary'>{t('common.userProfile.logout')}</div>
</div>
</div>
</Menu.Item>
</Menu.Items>
</MenuItem>
</MenuItems>
</Transition>
</>
)

View file

@ -29,18 +29,18 @@ export default function CheckEmail(props: DeleteAccountProps) {
}, [getDeleteEmailVerifyCode, props])
return <>
<div className='py-1 text-text-destructive body-md-medium'>
<div className='body-md-medium py-1 text-text-destructive'>
{t('common.account.deleteTip')}
</div>
<div className='pt-1 pb-2 text-text-secondary body-md-regular'>
<div className='body-md-regular pb-2 pt-1 text-text-secondary'>
{t('common.account.deletePrivacyLinkTip')}
<Link href='https://dify.ai/privacy' className='text-text-accent'>{t('common.account.deletePrivacyLink')}</Link>
</div>
<label className='mt-3 mb-1 h-6 flex items-center system-sm-semibold text-text-secondary'>{t('common.account.deleteLabel')}</label>
<label className='system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary'>{t('common.account.deleteLabel')}</label>
<Input placeholder={t('common.account.deletePlaceholder') as string} onChange={(e) => {
setUserInputEmail(e.target.value)
}} />
<div className='w-full flex flex-col mt-3 gap-2'>
<div className='mt-3 flex w-full flex-col gap-2'>
<Button className='w-full' disabled={userInputEmail !== userProfile.email || isSendingEmail} loading={isSendingEmail} variant='primary' onClick={handleConfirm}>{t('common.account.sendVerificationButton')}</Button>
<Button className='w-full' onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
</div>

View file

@ -56,11 +56,11 @@ export default function FeedBack(props: DeleteAccountProps) {
className="max-w-[480px]"
footer={false}
>
<label className='mt-3 mb-1 flex items-center system-sm-semibold text-text-secondary'>{t('common.account.feedbackLabel')}</label>
<label className='system-sm-semibold mb-1 mt-3 flex items-center text-text-secondary'>{t('common.account.feedbackLabel')}</label>
<Textarea rows={6} value={userFeedback} placeholder={t('common.account.feedbackPlaceholder') as string} onChange={(e) => {
setUserFeedback(e.target.value)
}} />
<div className='w-full flex flex-col mt-3 gap-2'>
<div className='mt-3 flex w-full flex-col gap-2'>
<Button className='w-full' loading={isPending} variant='primary' onClick={handleSubmit}>{t('common.operation.submit')}</Button>
<Button className='w-full' onClick={handleSkip}>{t('common.operation.skip')}</Button>
</div>

View file

@ -35,18 +35,18 @@ export default function VerifyEmail(props: DeleteAccountProps) {
catch (error) { console.error(error) }
}, [emailToken, verificationCode, confirmDeleteAccount, props])
return <>
<div className='pt-1 text-text-destructive body-md-medium'>
<div className='body-md-medium pt-1 text-text-destructive'>
{t('common.account.deleteTip')}
</div>
<div className='pt-1 pb-2 text-text-secondary body-md-regular'>
<div className='body-md-regular pb-2 pt-1 text-text-secondary'>
{t('common.account.deletePrivacyLinkTip')}
<Link href='https://dify.ai/privacy' className='text-text-accent'>{t('common.account.deletePrivacyLink')}</Link>
</div>
<label className='mt-3 mb-1 h-6 flex items-center system-sm-semibold text-text-secondary'>{t('common.account.verificationLabel')}</label>
<label className='system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary'>{t('common.account.verificationLabel')}</label>
<Input minLength={6} maxLength={6} placeholder={t('common.account.verificationPlaceholder') as string} onChange={(e) => {
setVerificationCode(e.target.value)
}} />
<div className='w-full flex flex-col mt-3 gap-2'>
<div className='mt-3 flex w-full flex-col gap-2'>
<Button className='w-full' disabled={shouldButtonDisabled} loading={isDeleting} variant='warning' onClick={handleConfirm}>{t('common.account.permanentlyDeleteButton')}</Button>
<Button className='w-full' onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
<Countdown onResend={sendEmail} />

View file

@ -16,19 +16,19 @@ const Header = () => {
return (
<div className='flex flex-1 items-center justify-between px-4'>
<div className='flex items-center gap-3'>
<div className='flex items-center cursor-pointer' onClick={back}>
<div className='flex cursor-pointer items-center' onClick={back}>
<LogoSite className='object-contain' />
</div>
<div className='w-[1px] h-4 bg-divider-regular' />
<p className='text-text-primary title-3xl-semi-bold'>{t('common.account.account')}</p>
<div className='h-4 w-[1px] bg-divider-regular' />
<p className='title-3xl-semi-bold text-text-primary'>{t('common.account.account')}</p>
</div>
<div className='flex items-center flex-shrink-0 gap-3'>
<Button className='gap-2 py-2 px-3 system-sm-medium' onClick={back}>
<RiRobot2Line className='w-4 h-4' />
<div className='flex shrink-0 items-center gap-3'>
<Button className='system-sm-medium gap-2 px-3 py-2' onClick={back}>
<RiRobot2Line className='h-4 w-4' />
<p>{t('common.account.studio')}</p>
<RiArrowRightUpLine className='w-4 h-4' />
<RiArrowRightUpLine className='h-4 w-4' />
</Button>
<div className='w-[1px] h-4 bg-divider-regular' />
<div className='h-4 w-[1px] bg-divider-regular' />
<Avatar />
</div>
</div>

View file

@ -21,7 +21,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
<HeaderWrapper>
<Header />
</HeaderWrapper>
<div className='relative flex flex-col overflow-y-auto bg-components-panel-bg shrink-0 h-0 grow'>
<div className='relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-components-panel-bg'>
{children}
</div>
</ModalContextProvider>

View file

@ -1,7 +1,7 @@
import AccountPage from './account-page'
export default function Account() {
return <div className='max-w-[640px] w-full mx-auto pt-12 px-6'>
return <div className='mx-auto w-full max-w-[640px] px-6 pt-12'>
<AccountPage />
</div>
}