| {checkRes && !checkRes.is_valid && ( | {checkRes && !checkRes.is_valid && ( | ||||
| <div className="flex flex-col md:w-[400px]"> | <div className="flex flex-col md:w-[400px]"> | ||||
| <div className="mx-auto w-full"> | <div className="mx-auto w-full"> | ||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-gray-100 p-5 text-[40px] font-bold shadow-lg">🤷♂️</div> | |||||
| <h2 className="text-[32px] font-bold text-gray-900">{t('login.invalid')}</h2> | |||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">🤷♂️</div> | |||||
| <h2 className="text-[32px] font-bold text-text-primary">{t('login.invalid')}</h2> | |||||
| </div> | </div> | ||||
| <div className="mx-auto mt-6 w-full"> | <div className="mx-auto mt-6 w-full"> | ||||
| <Button variant='primary' className='w-full !text-sm'> | <Button variant='primary' className='w-full !text-sm'> |
| const Activate = () => { | const Activate = () => { | ||||
| return ( | return ( | ||||
| <div className={cn( | <div className={cn( | ||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex min-h-screen w-full', | 'flex min-h-screen w-full', | ||||
| 'sm:p-4 lg:p-8', | 'sm:p-4 lg:p-8', | ||||
| )}> | )}> | ||||
| <div className={ | <div className={ | ||||
| cn( | cn( | ||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-white shadow', | |||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-background-section-burn shadow', | |||||
| 'space-between', | 'space-between', | ||||
| ) | ) | ||||
| }> | }> | ||||
| <Header /> | <Header /> | ||||
| <ActivateForm /> | <ActivateForm /> | ||||
| <div className='px-8 py-6 text-sm font-normal text-gray-500'> | |||||
| <div className='px-8 py-6 text-sm font-normal text-text-tertiary'> | |||||
| © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | ||||
| </div> | </div> | ||||
| </div> | </div> |
| .logo { | |||||
| background: #fff center no-repeat url(./team-28x28.png); | |||||
| background-size: 56px; | |||||
| } |
| <div className="w-56 text-right"> | <div className="w-56 text-right"> | ||||
| <Menu as="div" className="relative inline-block text-left"> | <Menu as="div" className="relative inline-block text-left"> | ||||
| <div> | <div> | ||||
| <MenuButton className="h-[44px]justify-center inline-flex w-full items-center | |||||
| rounded-lg border border-gray-200 | |||||
| px-[10px] py-[6px] text-[13px] | |||||
| font-medium text-gray-900 | |||||
| hover:bg-gray-100"> | |||||
| <MenuButton className="h-[44px]justify-center inline-flex w-full items-center rounded-lg border border-components-button-secondary-border px-[10px] py-[6px] text-[13px] font-medium text-text-primary hover:bg-state-base-hover"> | |||||
| <GlobeAltIcon className="mr-1 h-5 w-5" aria-hidden="true" /> | <GlobeAltIcon className="mr-1 h-5 w-5" aria-hidden="true" /> | ||||
| {item?.name} | {item?.name} | ||||
| </MenuButton> | </MenuButton> | ||||
| leaveFrom="transform opacity-100 scale-100" | leaveFrom="transform opacity-100 scale-100" | ||||
| leaveTo="transform opacity-0 scale-95" | leaveTo="transform opacity-0 scale-95" | ||||
| > | > | ||||
| <MenuItems className="absolute right-0 z-10 mt-2 w-[200px] origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"> | |||||
| <MenuItems className="absolute right-0 z-10 mt-2 w-[200px] origin-top-right divide-y divide-divider-regular rounded-md bg-components-panel-bg shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"> | |||||
| <div className="px-1 py-1 "> | <div className="px-1 py-1 "> | ||||
| {items.map((item) => { | {items.map((item) => { | ||||
| return <MenuItem key={item.value}> | return <MenuItem key={item.value}> | ||||
| <button | <button | ||||
| className={'group flex w-full items-center rounded-lg px-3 py-2 text-sm text-gray-700 data-[active]:bg-gray-100'} | |||||
| className={'group flex w-full items-center rounded-lg px-3 py-2 text-sm text-text-secondary data-[active]:bg-state-base-hover'} | |||||
| onClick={(evt) => { | onClick={(evt) => { | ||||
| evt.preventDefault() | evt.preventDefault() | ||||
| onChange && onChange(item.value) | onChange && onChange(item.value) | ||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } | ||||
| export function InputSelect({ | |||||
| items, | |||||
| value, | |||||
| onChange, | |||||
| }: ISelectProps) { | |||||
| const item = items.filter(item => item.value === value)[0] | |||||
| return ( | |||||
| <div className="w-full"> | |||||
| <Menu as="div" className="w-full"> | |||||
| <div> | |||||
| <MenuButton className="block h-[38px] w-full appearance-none rounded-md border border-gray-300 px-3 py-2 text-left shadow-sm placeholder:text-gray-400 sm:text-sm"> | |||||
| {item?.name} | |||||
| </MenuButton> | |||||
| </div> | |||||
| <Transition | |||||
| as={Fragment} | |||||
| enter="transition ease-out duration-100" | |||||
| enterFrom="transform opacity-0 scale-95" | |||||
| enterTo="transform opacity-100 scale-100" | |||||
| leave="transition ease-in duration-75" | |||||
| leaveFrom="transform opacity-100 scale-100" | |||||
| leaveTo="transform opacity-0 scale-95" | |||||
| > | |||||
| <MenuItems className="absolute right-0 z-10 mt-2 w-full origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"> | |||||
| <div className="px-1 py-1 "> | |||||
| {items.map((item) => { | |||||
| return <MenuItem key={item.value}> | |||||
| <button | |||||
| className={'group flex w-full items-center rounded-md px-2 py-2 text-sm data-[active]:bg-gray-100'} | |||||
| onClick={() => { | |||||
| onChange && onChange(item.value) | |||||
| }} | |||||
| > | |||||
| {item.name} | |||||
| </button> | |||||
| </MenuItem> | |||||
| })} | |||||
| </div> | |||||
| </MenuItems> | |||||
| </Transition> | |||||
| </Menu> | |||||
| </div> | |||||
| ) | |||||
| } |
| {verifyTokenRes && !verifyTokenRes.is_valid && ( | {verifyTokenRes && !verifyTokenRes.is_valid && ( | ||||
| <div className="flex flex-col md:w-[400px]"> | <div className="flex flex-col md:w-[400px]"> | ||||
| <div className="mx-auto w-full"> | <div className="mx-auto w-full"> | ||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-gray-100 p-5 text-[40px] font-bold shadow-lg">🤷♂️</div> | |||||
| <h2 className="text-[32px] font-bold text-gray-900">{t('login.invalid')}</h2> | |||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">🤷♂️</div> | |||||
| <h2 className="text-[32px] font-bold text-text-primary">{t('login.invalid')}</h2> | |||||
| </div> | </div> | ||||
| <div className="mx-auto mt-6 w-full"> | <div className="mx-auto mt-6 w-full"> | ||||
| <Button variant='primary' className='w-full !text-sm'> | <Button variant='primary' className='w-full !text-sm'> | ||||
| {verifyTokenRes && verifyTokenRes.is_valid && !showSuccess && ( | {verifyTokenRes && verifyTokenRes.is_valid && !showSuccess && ( | ||||
| <div className='flex flex-col md:w-[400px]'> | <div className='flex flex-col md:w-[400px]'> | ||||
| <div className="mx-auto w-full"> | <div className="mx-auto w-full"> | ||||
| <h2 className="text-[32px] font-bold text-gray-900"> | |||||
| <h2 className="text-[32px] font-bold text-text-primary"> | |||||
| {t('login.changePassword')} | {t('login.changePassword')} | ||||
| </h2> | </h2> | ||||
| <p className='mt-1 text-sm text-gray-600'> | |||||
| <p className='mt-1 text-sm text-text-secondary'> | |||||
| {t('login.changePasswordTip')} | {t('login.changePasswordTip')} | ||||
| </p> | </p> | ||||
| </div> | </div> | ||||
| <div className="mx-auto mt-6 w-full"> | <div className="mx-auto mt-6 w-full"> | ||||
| <div className="bg-white"> | |||||
| <div className="relative"> | |||||
| {/* Password */} | {/* Password */} | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('common.account.newPassword')} | {t('common.account.newPassword')} | ||||
| </label> | </label> | ||||
| <Input | <Input | ||||
| </div> | </div> | ||||
| {/* Confirm Password */} | {/* Confirm Password */} | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="confirmPassword" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| <label htmlFor="confirmPassword" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('common.account.confirmPassword')} | {t('common.account.confirmPassword')} | ||||
| </label> | </label> | ||||
| <Input | <Input | ||||
| {verifyTokenRes && verifyTokenRes.is_valid && showSuccess && ( | {verifyTokenRes && verifyTokenRes.is_valid && showSuccess && ( | ||||
| <div className="flex flex-col md:w-[400px]"> | <div className="flex flex-col md:w-[400px]"> | ||||
| <div className="mx-auto w-full"> | <div className="mx-auto w-full"> | ||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-gray-100 p-5 text-[40px] font-bold shadow-lg"> | |||||
| <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg"> | |||||
| <CheckCircleIcon className='h-10 w-10 text-[#039855]' /> | <CheckCircleIcon className='h-10 w-10 text-[#039855]' /> | ||||
| </div> | </div> | ||||
| <h2 className="text-[32px] font-bold text-gray-900"> | |||||
| <h2 className="text-[32px] font-bold text-text-primary"> | |||||
| {t('login.passwordChangedTip')} | {t('login.passwordChangedTip')} | ||||
| </h2> | </h2> | ||||
| </div> | </div> |
| ? <Loading /> | ? <Loading /> | ||||
| : <> | : <> | ||||
| <div className="sm:mx-auto sm:w-full sm:max-w-md"> | <div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||||
| <h2 className="text-[32px] font-bold text-gray-900"> | |||||
| <h2 className="text-[32px] font-bold text-text-primary"> | |||||
| {isEmailSent ? t('login.resetLinkSent') : t('login.forgotPassword')} | {isEmailSent ? t('login.resetLinkSent') : t('login.forgotPassword')} | ||||
| </h2> | </h2> | ||||
| <p className='mt-1 text-sm text-gray-600'> | |||||
| <p className='mt-1 text-sm text-text-secondary'> | |||||
| {isEmailSent ? t('login.checkEmailForResetLink') : t('login.forgotPasswordDesc')} | {isEmailSent ? t('login.checkEmailForResetLink') : t('login.forgotPasswordDesc')} | ||||
| </p> | </p> | ||||
| </div> | </div> | ||||
| <div className="mt-8 grow sm:mx-auto sm:w-full sm:max-w-md"> | <div className="mt-8 grow sm:mx-auto sm:w-full sm:max-w-md"> | ||||
| <div className="bg-white "> | |||||
| <div className="relative"> | |||||
| <form> | <form> | ||||
| {!isEmailSent && ( | {!isEmailSent && ( | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="email" | <label htmlFor="email" | ||||
| className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('login.email')} | {t('login.email')} | ||||
| </label> | </label> | ||||
| <div className="mt-1"> | <div className="mt-1"> |
| return ( | return ( | ||||
| <div className={classNames( | <div className={classNames( | ||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex w-full min-h-screen', | 'flex w-full min-h-screen', | ||||
| 'p-4 lg:p-8', | 'p-4 lg:p-8', | ||||
| )}> | )}> | ||||
| <div className={ | <div className={ | ||||
| classNames( | classNames( | ||||
| 'flex w-full flex-col bg-white shadow rounded-2xl shrink-0', | |||||
| 'flex w-full flex-col bg-background-section-burn shadow rounded-2xl shrink-0', | |||||
| 'md:w-[608px] space-between', | 'md:w-[608px] space-between', | ||||
| ) | ) | ||||
| }> | }> | ||||
| <Header /> | <Header /> | ||||
| {token ? <ChangePasswordForm /> : <ForgotPasswordForm />} | {token ? <ChangePasswordForm /> : <ForgotPasswordForm />} | ||||
| <div className='px-8 py-6 text-sm font-normal text-gray-500'> | |||||
| <div className='px-8 py-6 text-sm font-normal text-text-tertiary'> | |||||
| © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | ||||
| </div> | </div> | ||||
| </div> | </div> |
| {!validated && ( | {!validated && ( | ||||
| <div className="mx-12 block min-w-28"> | <div className="mx-12 block min-w-28"> | ||||
| <div className="mb-4"> | <div className="mb-4"> | ||||
| <label htmlFor="password" className="block text-sm font-medium text-gray-700"> | |||||
| <label htmlFor="password" className="block text-sm font-medium text-text-secondary"> | |||||
| {t('login.adminInitPassword')} | {t('login.adminInitPassword')} | ||||
| </label> | </label> | ||||
| type="password" | type="password" | ||||
| value={password} | value={password} | ||||
| onChange={e => setPassword(e.target.value)} | onChange={e => setPassword(e.target.value)} | ||||
| className="block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 shadow-sm placeholder:text-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm" | |||||
| className="block w-full appearance-none rounded-md border border-divider-regular px-3 py-2 shadow-sm placeholder:text-text-quaternary focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm" | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| </div> | </div> |
| import React from 'react' | import React from 'react' | ||||
| import style from '../signin/page.module.css' | import style from '../signin/page.module.css' | ||||
| import InitPasswordPopup from './InitPasswordPopup' | import InitPasswordPopup from './InitPasswordPopup' | ||||
| import classNames from '@/utils/classnames' | |||||
| import cn from '@/utils/classnames' | |||||
| const Install = () => { | const Install = () => { | ||||
| return ( | return ( | ||||
| <div className={classNames( | |||||
| <div className={cn( | |||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex w-full min-h-screen', | |||||
| 'flex min-h-screen w-full', | |||||
| 'p-4 lg:p-8', | 'p-4 lg:p-8', | ||||
| 'gap-x-20', | 'gap-x-20', | ||||
| 'justify-center lg:justify-start', | 'justify-center lg:justify-start', | ||||
| )}> | )}> | ||||
| <div className="m-auto block w-96"> | |||||
| <InitPasswordPopup /> | |||||
| <div className={ | |||||
| cn( | |||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-background-section-burn shadow', | |||||
| 'space-between', | |||||
| ) | |||||
| }> | |||||
| <div className="m-auto block w-96"> | |||||
| <InitPasswordPopup /> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ) | ) |
| ? <Loading /> | ? <Loading /> | ||||
| : <> | : <> | ||||
| <div className="sm:mx-auto sm:w-full sm:max-w-md"> | <div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||||
| <h2 className="text-[32px] font-bold text-gray-900">{t('login.setAdminAccount')}</h2> | |||||
| <p className=' | |||||
| mt-1 text-sm text-gray-600 | |||||
| '>{t('login.setAdminAccountDesc')}</p> | |||||
| <h2 className="text-[32px] font-bold text-text-primary">{t('login.setAdminAccount')}</h2> | |||||
| <p className='mt-1 text-sm text-text-secondary'>{t('login.setAdminAccountDesc')}</p> | |||||
| </div> | </div> | ||||
| <div className="mt-8 grow sm:mx-auto sm:w-full sm:max-w-md"> | <div className="mt-8 grow sm:mx-auto sm:w-full sm:max-w-md"> | ||||
| <div className="bg-white "> | |||||
| <div className="relative"> | |||||
| <form onSubmit={handleSubmit(onSubmit)} onKeyDown={handleKeyDown}> | <form onSubmit={handleSubmit(onSubmit)} onKeyDown={handleKeyDown}> | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('login.email')} | {t('login.email')} | ||||
| </label> | </label> | ||||
| <div className="mt-1"> | |||||
| <div className="mt-1 rounded-md shadow-sm"> | |||||
| <input | <input | ||||
| {...register('email')} | {...register('email')} | ||||
| placeholder={t('login.emailPlaceholder') || ''} | placeholder={t('login.emailPlaceholder') || ''} | ||||
| className={'block w-full appearance-none rounded-lg border border-gray-200 px-3 py-2 pl-[14px] caret-primary-600 placeholder:text-gray-400 hover:border-gray-300 hover:shadow-sm focus:border-primary-500 focus:outline-none focus:ring-primary-500 sm:text-sm'} | |||||
| className={'w-full appearance-none rounded-md border border-transparent bg-components-input-bg-normal py-[7px] pl-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'} | |||||
| /> | /> | ||||
| {errors.email && <span className='text-sm text-red-400'>{t(`${errors.email?.message}`)}</span>} | {errors.email && <span className='text-sm text-red-400'>{t(`${errors.email?.message}`)}</span>} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('login.name')} | {t('login.name')} | ||||
| </label> | </label> | ||||
| <div className="relative mt-1 rounded-md shadow-sm"> | <div className="relative mt-1 rounded-md shadow-sm"> | ||||
| <input | <input | ||||
| {...register('name')} | {...register('name')} | ||||
| placeholder={t('login.namePlaceholder') || ''} | placeholder={t('login.namePlaceholder') || ''} | ||||
| className={'block w-full appearance-none rounded-lg border border-gray-200 px-3 py-2 pl-[14px] pr-10 caret-primary-600 placeholder:text-gray-400 hover:border-gray-300 hover:shadow-sm focus:border-primary-500 focus:outline-none focus:ring-primary-500 sm:text-sm'} | |||||
| className={'w-full appearance-none rounded-md border border-transparent bg-components-input-bg-normal py-[7px] pl-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'} | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| {errors.name && <span className='text-sm text-red-400'>{t(`${errors.name.message}`)}</span>} | {errors.name && <span className='text-sm text-red-400'>{t(`${errors.name.message}`)}</span>} | ||||
| </div> | </div> | ||||
| <div className='mb-5'> | <div className='mb-5'> | ||||
| <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> | |||||
| <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-text-primary"> | |||||
| {t('login.password')} | {t('login.password')} | ||||
| </label> | </label> | ||||
| <div className="relative mt-1 rounded-md shadow-sm"> | <div className="relative mt-1 rounded-md shadow-sm"> | ||||
| {...register('password')} | {...register('password')} | ||||
| type={showPassword ? 'text' : 'password'} | type={showPassword ? 'text' : 'password'} | ||||
| placeholder={t('login.passwordPlaceholder') || ''} | placeholder={t('login.passwordPlaceholder') || ''} | ||||
| className={'block w-full appearance-none rounded-lg border border-gray-200 px-3 py-2 pl-[14px] pr-10 caret-primary-600 placeholder:text-gray-400 hover:border-gray-300 hover:shadow-sm focus:border-primary-500 focus:outline-none focus:ring-primary-500 sm:text-sm'} | |||||
| className={'w-full appearance-none rounded-md border border-transparent bg-components-input-bg-normal py-[7px] pl-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'} | |||||
| /> | /> | ||||
| <div className="absolute inset-y-0 right-0 flex items-center pr-3"> | <div className="absolute inset-y-0 right-0 flex items-center pr-3"> | ||||
| <button | <button | ||||
| type="button" | type="button" | ||||
| onClick={() => setShowPassword(!showPassword)} | onClick={() => setShowPassword(!showPassword)} | ||||
| className="text-gray-400 hover:text-gray-500 focus:text-gray-500 focus:outline-none" | |||||
| className="text-text-quaternary hover:text-text-tertiary focus:text-text-tertiary focus:outline-none" | |||||
| > | > | ||||
| {showPassword ? '👀' : '😝'} | {showPassword ? '👀' : '😝'} | ||||
| </button> | </button> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className={classNames('mt-1 text-xs text-gray-500', { | |||||
| <div className={classNames('mt-1 text-xs text-text-tertiary', { | |||||
| 'text-red-400 !text-sm': errors.password, | 'text-red-400 !text-sm': errors.password, | ||||
| })}>{t('login.error.passwordInvalid')}</div> | })}>{t('login.error.passwordInvalid')}</div> | ||||
| </div> | </div> | ||||
| </Button> | </Button> | ||||
| </div> | </div> | ||||
| </form> | </form> | ||||
| <div className="mt-2 block w-full text-xs text-gray-600"> | |||||
| <div className="mt-2 block w-full text-xs text-text-tertiary"> | |||||
| {t('login.license.tip')} | {t('login.license.tip')} | ||||
| | | ||||
| <Link | <Link | ||||
| className='text-primary-600' | |||||
| className='text-text-accent' | |||||
| target='_blank' rel='noopener noreferrer' | target='_blank' rel='noopener noreferrer' | ||||
| href={'https://docs.dify.ai/user-agreement/open-source'} | href={'https://docs.dify.ai/user-agreement/open-source'} | ||||
| >{t('login.license.link')}</Link> | >{t('login.license.link')}</Link> |
| const Install = () => { | const Install = () => { | ||||
| return ( | return ( | ||||
| <div className={classNames( | <div className={classNames( | ||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex w-full min-h-screen', | 'flex w-full min-h-screen', | ||||
| 'p-4 lg:p-8', | 'p-4 lg:p-8', | ||||
| )}> | )}> | ||||
| <div className={ | <div className={ | ||||
| classNames( | classNames( | ||||
| 'flex w-full flex-col bg-white shadow rounded-2xl shrink-0', | |||||
| 'flex w-full flex-col bg-background-section-burn shadow rounded-2xl shrink-0', | |||||
| 'md:w-[608px] space-between', | 'md:w-[608px] space-between', | ||||
| ) | ) | ||||
| }> | }> | ||||
| <Header /> | <Header /> | ||||
| <InstallForm /> | <InstallForm /> | ||||
| <div className='px-8 py-6 text-sm font-normal text-gray-500'> | |||||
| <div className='px-8 py-6 text-sm font-normal text-text-tertiary'> | |||||
| © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. | ||||
| </div> | </div> | ||||
| </div> | </div> |
| export default async function SignInLayout({ children }: any) { | export default async function SignInLayout({ children }: any) { | ||||
| return <> | return <> | ||||
| <div className={cn( | <div className={cn( | ||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex min-h-screen w-full', | 'flex min-h-screen w-full', | ||||
| 'sm:p-4 lg:p-8', | 'sm:p-4 lg:p-8', | ||||
| )}> | )}> | ||||
| <div className={ | <div className={ | ||||
| cn( | cn( | ||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-white shadow', | |||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-background-section-burn shadow', | |||||
| 'space-between', | 'space-between', | ||||
| ) | ) | ||||
| }> | }> |
| export default async function SignInLayout({ children }: any) { | export default async function SignInLayout({ children }: any) { | ||||
| return <> | return <> | ||||
| <div className={cn( | <div className={cn( | ||||
| 'bg-background-body', | |||||
| style.background, | style.background, | ||||
| 'flex min-h-screen w-full', | 'flex min-h-screen w-full', | ||||
| 'sm:p-4 lg:p-8', | 'sm:p-4 lg:p-8', | ||||
| )}> | )}> | ||||
| <div className={ | <div className={ | ||||
| cn( | cn( | ||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-white shadow', | |||||
| 'flex w-full shrink-0 flex-col rounded-2xl bg-background-section-burn shadow', | |||||
| 'space-between', | 'space-between', | ||||
| ) | ) | ||||
| }> | }> |
| } | } | ||||
| if (systemFeatures.license?.status === LicenseStatus.LOST) { | if (systemFeatures.license?.status === LicenseStatus.LOST) { | ||||
| return <div className='mx-auto mt-8 w-full'> | return <div className='mx-auto mt-8 w-full'> | ||||
| <div className='bg-white'> | |||||
| <div className='relative'> | |||||
| <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | ||||
| <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | ||||
| <RiContractLine className='h-5 w-5' /> | <RiContractLine className='h-5 w-5' /> | ||||
| } | } | ||||
| if (systemFeatures.license?.status === LicenseStatus.EXPIRED) { | if (systemFeatures.license?.status === LicenseStatus.EXPIRED) { | ||||
| return <div className='mx-auto mt-8 w-full'> | return <div className='mx-auto mt-8 w-full'> | ||||
| <div className='bg-white'> | |||||
| <div className='relative'> | |||||
| <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | ||||
| <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | ||||
| <RiContractLine className='h-5 w-5' /> | <RiContractLine className='h-5 w-5' /> | ||||
| } | } | ||||
| if (systemFeatures.license?.status === LicenseStatus.INACTIVE) { | if (systemFeatures.license?.status === LicenseStatus.INACTIVE) { | ||||
| return <div className='mx-auto mt-8 w-full'> | return <div className='mx-auto mt-8 w-full'> | ||||
| <div className='bg-white'> | |||||
| <div className='relative'> | |||||
| <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | <div className="rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4"> | ||||
| <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | <div className='shadows-shadow-lg relative mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow'> | ||||
| <RiContractLine className='h-5 w-5' /> | <RiContractLine className='h-5 w-5' /> | ||||
| <h2 className="title-4xl-semi-bold text-text-primary">{t('login.pageTitle')}</h2> | <h2 className="title-4xl-semi-bold text-text-primary">{t('login.pageTitle')}</h2> | ||||
| <p className='body-md-regular mt-2 text-text-tertiary'>{t('login.welcome')}</p> | <p className='body-md-regular mt-2 text-text-tertiary'>{t('login.welcome')}</p> | ||||
| </div>} | </div>} | ||||
| <div className="bg-white"> | |||||
| <div className="relative"> | |||||
| <div className="mt-6 flex flex-col gap-3"> | <div className="mt-6 flex flex-col gap-3"> | ||||
| {systemFeatures.enable_social_oauth_login && <SocialAuth />} | {systemFeatures.enable_social_oauth_login && <SocialAuth />} | ||||
| {systemFeatures.sso_enforced_for_signin && <div className='w-full'> | {systemFeatures.sso_enforced_for_signin && <div className='w-full'> | ||||
| <div className='h-px w-full bg-gradient-to-r from-background-gradient-mask-transparent via-divider-regular to-background-gradient-mask-transparent'></div> | <div className='h-px w-full bg-gradient-to-r from-background-gradient-mask-transparent via-divider-regular to-background-gradient-mask-transparent'></div> | ||||
| </div> | </div> | ||||
| <div className="relative flex justify-center"> | <div className="relative flex justify-center"> | ||||
| <span className="system-xs-medium-uppercase bg-white px-2 text-text-tertiary">{t('login.or')}</span> | |||||
| <span className="system-xs-medium-uppercase px-2 text-text-tertiary">{t('login.or')}</span> | |||||
| </div> | </div> | ||||
| </div>} | </div>} | ||||
| { | { |
| </div> | </div> | ||||
| <div className="mx-auto mt-6 w-full"> | <div className="mx-auto mt-6 w-full"> | ||||
| <div className="bg-white"> | |||||
| <div className="relative"> | |||||
| <div className="mb-5"> | <div className="mb-5"> | ||||
| <label className="system-md-semibold my-2 flex items-center justify-between text-text-secondary"> | <label className="system-md-semibold my-2 flex items-center justify-between text-text-secondary"> | ||||
| {t('login.invitationCode')} | {t('login.invitationCode')} |