fix: 首页出版效果
This commit is contained in:
parent
a9108fd392
commit
f534c101dd
@ -10,7 +10,6 @@ import { redirect } from 'next/navigation';
|
|||||||
import FooterCopyright from '@/components/main/FooterCopyright';
|
import FooterCopyright from '@/components/main/FooterCopyright';
|
||||||
import FullScreenVideoBackground from '@/components/main/FullScreenVideoBackground';
|
import FullScreenVideoBackground from '@/components/main/FullScreenVideoBackground';
|
||||||
import HomeContent from '@/components/main/HomeContent';
|
import HomeContent from '@/components/main/HomeContent';
|
||||||
import Image from 'next/image';
|
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const Authorization = (await cookies()).get('Authorization')?.value;
|
const Authorization = (await cookies()).get('Authorization')?.value;
|
||||||
@ -39,14 +38,6 @@ export default async function Home() {
|
|||||||
<HomeContent />
|
<HomeContent />
|
||||||
</main>
|
</main>
|
||||||
<FooterCopyright />
|
<FooterCopyright />
|
||||||
<Image
|
|
||||||
src={'./logo.png'}
|
|
||||||
height={37}
|
|
||||||
width={28}
|
|
||||||
className={'fixed bottom-8 left-1/2 -translate-x-1/2'}
|
|
||||||
alt='logo'
|
|
||||||
unoptimized
|
|
||||||
></Image>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
40
apps/user/app/auth/EmailAuthDialog/EmailAuthDialog.tsx
Normal file
40
apps/user/app/auth/EmailAuthDialog/EmailAuthDialog.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import EmailAuthForm from '@/app/auth/email/auth-form';
|
||||||
|
import CloseSvg from '@/components/CustomIcon/icons/close.svg';
|
||||||
|
import { Dialog, DialogContent, DialogTitle } from '@workspace/ui/components/dialog';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
|
||||||
|
export interface EmailAuthDialogRef {
|
||||||
|
show: () => void;
|
||||||
|
hide: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmailAuthDialog = forwardRef<EmailAuthDialogRef>((props, ref) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
show: () => setOpen(true),
|
||||||
|
hide: () => setOpen(false),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
|
<DialogContent
|
||||||
|
className={
|
||||||
|
'rounded-0 h-full w-full px-12 py-[4.5rem] md:h-auto md:w-[496px] md:!rounded-[50px]'
|
||||||
|
}
|
||||||
|
closeIcon={<Image src={CloseSvg} alt={'close'} />}
|
||||||
|
closeClassName={
|
||||||
|
'right-[40px] top-[30px] font-bold text-black opacity-100 focus:ring-0 focus:ring-offset-0'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DialogTitle className={'sr-only'}>title</DialogTitle>
|
||||||
|
<div className={'min-h-[524px]'}>
|
||||||
|
<EmailAuthForm />
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default EmailAuthDialog;
|
||||||
@ -49,15 +49,21 @@ export default function LoginForm({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className={'pb-9 pt-16 text-4xl font-bold'}>账户验证</div>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={handleSubmit} className='grid gap-6'>
|
<form onSubmit={handleSubmit} className=''>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='email'
|
name='email'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className={'mb-5'}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder='Enter your email...' type='email' {...field} />
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
placeholder='Email'
|
||||||
|
type='email'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -67,9 +73,14 @@ export default function LoginForm({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name='password'
|
name='password'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className={'mb-2'}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder='Enter your password...' type='password' {...field} />
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
placeholder='password'
|
||||||
|
type='password'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -80,7 +91,7 @@ export default function LoginForm({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name='cf_token'
|
name='cf_token'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className={'last:mb-0'}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<CloudFlareTurnstile id='login' {...field} ref={turnstile} />
|
<CloudFlareTurnstile id='login' {...field} ref={turnstile} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@ -89,27 +100,39 @@ export default function LoginForm({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Button type='submit' disabled={loading}>
|
<div className='flex w-full justify-between text-sm'>
|
||||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
<Button
|
||||||
{t('title')}
|
variant='link'
|
||||||
</Button>
|
type='button'
|
||||||
|
className='p-0'
|
||||||
|
onClick={() => onSwitchForm('reset')}
|
||||||
|
>
|
||||||
|
{t('forgotPassword')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant='link'
|
||||||
|
className='p-0'
|
||||||
|
onClick={() => {
|
||||||
|
setInitialValues(undefined);
|
||||||
|
onSwitchForm('register');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('registerAccount')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-6 flex justify-center'>
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
disabled={loading}
|
||||||
|
className='h-[64px] w-[219px] rounded-full border-[#0F2C53] bg-[#0F2C53] text-2xl font-bold hover:bg-[#225BA9] hover:text-white'
|
||||||
|
>
|
||||||
|
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||||
|
{t('title')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
<div className='mt-4 flex w-full justify-between text-sm'>
|
|
||||||
<Button variant='link' type='button' className='p-0' onClick={() => onSwitchForm('reset')}>
|
|
||||||
{t('forgotPassword')}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant='link'
|
|
||||||
className='p-0'
|
|
||||||
onClick={() => {
|
|
||||||
setInitialValues(undefined);
|
|
||||||
onSwitchForm('register');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('registerAccount')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,132 +87,156 @@ export default function RegisterForm({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className={'pb-9 text-4xl font-bold'}>注册账户</div>
|
||||||
|
|
||||||
{auth.register.stop_register ? (
|
{auth.register.stop_register ? (
|
||||||
<Markdown>{t('message')}</Markdown>
|
<Markdown>{t('message')}</Markdown>
|
||||||
) : (
|
) : (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={handleSubmit} className='grid gap-6'>
|
<form onSubmit={handleSubmit}>
|
||||||
<FormField
|
<div className='grid gap-5'>
|
||||||
control={form.control}
|
|
||||||
name='email'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder='Enter your email...' type='email' {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='password'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder='Enter your password...' type='password' {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='repeat_password'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
disabled={loading}
|
|
||||||
placeholder='Enter password again...'
|
|
||||||
type='password'
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{auth.email.enable_verify && (
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='code'
|
name='email'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className='flex items-center gap-2'>
|
<Input
|
||||||
<Input
|
className={'h-[60px] text-xl'}
|
||||||
disabled={loading}
|
placeholder='Enter your email...'
|
||||||
placeholder='Enter code...'
|
type='email'
|
||||||
type='text'
|
{...field}
|
||||||
{...field}
|
/>
|
||||||
value={field.value as string}
|
|
||||||
/>
|
|
||||||
<SendCode
|
|
||||||
type='email'
|
|
||||||
params={{
|
|
||||||
...form.getValues(),
|
|
||||||
type: 1,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='invite'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
disabled={loading || !!localStorage.getItem('invite')}
|
|
||||||
placeholder={t('invite')}
|
|
||||||
{...field}
|
|
||||||
value={field.value || ''}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{verify.enable_register_verify && (
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='cf_token'
|
name='password'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<CloudFlareTurnstile id='register' {...field} ref={turnstile} />
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
placeholder='Enter your password...'
|
||||||
|
type='password'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
<FormField
|
||||||
<Button type='submit' disabled={loading}>
|
control={form.control}
|
||||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
name='repeat_password'
|
||||||
{t('title')}
|
render={({ field }) => (
|
||||||
</Button>
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
disabled={loading}
|
||||||
|
placeholder='Enter password again...'
|
||||||
|
type='password'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{auth.email.enable_verify && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name='code'
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<div className='flex items-center gap-8'>
|
||||||
|
<Input
|
||||||
|
disabled={loading}
|
||||||
|
className={'h-[60px] flex-1 text-xl'}
|
||||||
|
placeholder='Enter code...'
|
||||||
|
type='text'
|
||||||
|
{...field}
|
||||||
|
value={field.value as string}
|
||||||
|
/>
|
||||||
|
<SendCode
|
||||||
|
type='email'
|
||||||
|
params={{
|
||||||
|
...form.getValues(),
|
||||||
|
type: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name='invite'
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
disabled={loading || !!localStorage.getItem('invite')}
|
||||||
|
placeholder={t('invite')}
|
||||||
|
{...field}
|
||||||
|
value={field.value || ''}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{verify.enable_register_verify && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name='cf_token'
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<CloudFlareTurnstile id='register' {...field} ref={turnstile} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='text-right text-sm'>
|
||||||
|
{t('existingAccount')}
|
||||||
|
<Button
|
||||||
|
variant='link'
|
||||||
|
className='p-0'
|
||||||
|
onClick={() => {
|
||||||
|
setInitialValues(undefined);
|
||||||
|
onSwitchForm('login');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('switchToLogin')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className='mt-6 flex justify-center'>
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
disabled={loading}
|
||||||
|
className='h-[64px] w-[219px] rounded-full border-[#0F2C53] bg-[#0F2C53] text-2xl font-bold hover:bg-[#225BA9] hover:text-white'
|
||||||
|
>
|
||||||
|
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||||
|
{t('title')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
<div className='mt-4 text-right text-sm'>
|
|
||||||
{t('existingAccount')}
|
|
||||||
<Button
|
|
||||||
variant='link'
|
|
||||||
className='p-0'
|
|
||||||
onClick={() => {
|
|
||||||
setInitialValues(undefined);
|
|
||||||
onSwitchForm('login');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('switchToLogin')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,92 +54,112 @@ export default function ResetForm({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className={'pb-9 pt-10 text-4xl font-bold'}>找回账户</div>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={handleSubmit} className='grid gap-6'>
|
<form onSubmit={handleSubmit}>
|
||||||
<FormField
|
<div className='grid gap-5'>
|
||||||
control={form.control}
|
|
||||||
name='email'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder='Enter your email...' type='email' {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='code'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<Input
|
|
||||||
disabled={loading}
|
|
||||||
placeholder='Enter code...'
|
|
||||||
type='text'
|
|
||||||
{...field}
|
|
||||||
value={field.value as string}
|
|
||||||
/>
|
|
||||||
<SendCode
|
|
||||||
type='email'
|
|
||||||
params={{
|
|
||||||
...form.getValues(),
|
|
||||||
type: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='password'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder='Enter your new password...' type='password' {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{verify.enable_reset_password_verify && (
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='cf_token'
|
name='email'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<CloudFlareTurnstile id='reset' {...field} ref={turnstile} />
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
placeholder='Enter your email...'
|
||||||
|
type='email'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
<FormField
|
||||||
<Button type='submit' disabled={loading}>
|
control={form.control}
|
||||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
name='code'
|
||||||
{t('title')}
|
render={({ field }) => (
|
||||||
</Button>
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<div className='flex items-center gap-8'>
|
||||||
|
<Input
|
||||||
|
className={'h-[60px] flex-1 text-xl'}
|
||||||
|
disabled={loading}
|
||||||
|
placeholder='Enter code...'
|
||||||
|
type='text'
|
||||||
|
{...field}
|
||||||
|
value={field.value as string}
|
||||||
|
/>
|
||||||
|
<SendCode
|
||||||
|
type='email'
|
||||||
|
params={{
|
||||||
|
...form.getValues(),
|
||||||
|
type: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name='password'
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className={'h-[60px] text-xl'}
|
||||||
|
placeholder='Enter your new password...'
|
||||||
|
type='password'
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{verify.enable_reset_password_verify && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name='cf_token'
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<CloudFlareTurnstile id='reset' {...field} ref={turnstile} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='text-right text-sm'>
|
||||||
|
{t('existingAccount')}
|
||||||
|
<Button
|
||||||
|
variant='link'
|
||||||
|
className='p-0'
|
||||||
|
onClick={() => {
|
||||||
|
setInitialValues(undefined);
|
||||||
|
onSwitchForm('login');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('switchToLogin')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className='mt-6 flex justify-center'>
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
disabled={loading}
|
||||||
|
className='h-[64px] w-[219px] rounded-full border-[#0F2C53] bg-[#0F2C53] text-2xl font-bold hover:bg-[#225BA9] hover:text-white'
|
||||||
|
>
|
||||||
|
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||||
|
{t('title')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
<div className='mt-4 text-right text-sm'>
|
|
||||||
{t('existingAccount')}
|
|
||||||
<Button
|
|
||||||
variant='link'
|
|
||||||
className='p-0'
|
|
||||||
onClick={() => {
|
|
||||||
setInitialValues(undefined);
|
|
||||||
onSwitchForm('login');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('switchToLogin')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,14 @@ export default function SendCode({ type, params }: SendCodeProps) {
|
|||||||
(type === 'email' ? !params.email : !params.telephone || !params.telephone_area_code);
|
(type === 'email' ? !params.email : !params.telephone || !params.telephone_area_code);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type='button' onClick={handleSendCode} disabled={disabled}>
|
<Button
|
||||||
|
type='button'
|
||||||
|
className={
|
||||||
|
'h-[60px] w-[109px] rounded-full border-[#A8D4ED] bg-[#A8D4ED] text-xl hover:bg-[#225BA9] hover:text-white'
|
||||||
|
}
|
||||||
|
onClick={handleSendCode}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
{seconds > 0 ? `${seconds}s` : t('get')}
|
{seconds > 0 ? `${seconds}s` : t('get')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export default function Certification({ platform, children }: CertificationProps
|
|||||||
router.refresh();
|
router.refresh();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
router.replace('/auth');
|
router.replace('/');
|
||||||
});
|
});
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export default function Certification({ platform, children }: CertificationProps
|
|||||||
router.refresh();
|
router.refresh();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
router.replace('/auth');
|
router.replace('/');
|
||||||
});
|
});
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
|
|||||||
3
apps/user/components/CustomIcon/icons/close.svg
Normal file
3
apps/user/components/CustomIcon/icons/close.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20.7312 7.88871L23.124 10.2816L17.9056 15.5L23.124 20.7185L20.7312 23.1113L15.5127 17.8929L10.2688 23.1368L7.87598 20.7439L13.1199 15.5L7.87598 10.2561L10.2688 7.86325L15.5127 13.1072L20.7312 7.88871Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 330 B |
@ -8,44 +8,56 @@ import Image from 'next/legacy/image';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import LanguageSwitch from '../language-switch';
|
import LanguageSwitch from '../language-switch';
|
||||||
// import ThemeSwitch from '../theme-switch';
|
// import ThemeSwitch from '../theme-switch';
|
||||||
|
import EmailAuthDialog, { EmailAuthDialogRef } from '@/app/auth/EmailAuthDialog/EmailAuthDialog';
|
||||||
|
import { useRef } from 'react';
|
||||||
import { UserNav } from '../user-nav';
|
import { UserNav } from '../user-nav';
|
||||||
import ImageLogo from './image.png';
|
import ImageLogo from './image.png';
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header(props) {
|
||||||
const t = useTranslations('common');
|
const t = useTranslations('common');
|
||||||
|
|
||||||
const { user } = useGlobalStore();
|
const { user } = useGlobalStore();
|
||||||
const Logo = (
|
const Logo = (
|
||||||
<Link href='/' className='flex items-center gap-2 text-lg font-bold'>
|
<Link href='/' className='-mt-2.5 flex items-center gap-2 font-bold'>
|
||||||
<Image src={ImageLogo} width={172} height={49} alt='logo' unoptimized />
|
<Image src={ImageLogo} width={102} height={49} alt='logo' unoptimized />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const dialogRef = useRef<EmailAuthDialogRef>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className='fixed top-10 z-50 w-full'>
|
<>
|
||||||
<div className='container flex h-[73px] items-center justify-between rounded-[50px] bg-white pl-7 pr-1'>
|
<header className='fixed top-10 z-50 w-full'>
|
||||||
<nav className='flex-col gap-6 text-lg font-medium md:flex md:flex-row md:items-center md:gap-5 md:text-sm lg:gap-6'>
|
<div className={'container'}>
|
||||||
{Logo}
|
<div className='flex h-[73px] items-center justify-between rounded-[50px] bg-white pl-4 pr-1 md:pl-7'>
|
||||||
</nav>
|
<nav className='flex-col gap-6 font-medium md:flex md:flex-row md:items-center md:gap-5 md:text-sm lg:gap-6'>
|
||||||
<div className='flex h-full flex-1 items-center justify-end gap-2 py-1'>
|
{Logo}
|
||||||
<LanguageSwitch />
|
</nav>
|
||||||
{/*<ThemeSwitch />*/}
|
<div className='flex h-full flex-1 items-center justify-end gap-2 py-1'>
|
||||||
<UserNav />
|
<LanguageSwitch />
|
||||||
{!user && (
|
{/*<ThemeSwitch />*/}
|
||||||
<Link
|
<UserNav />
|
||||||
href='/auth'
|
{!user && (
|
||||||
className={cn(
|
<Link
|
||||||
buttonVariants({
|
href='#'
|
||||||
size: 'lg',
|
onClick={() => dialogRef.current?.show()}
|
||||||
variant: 'outline',
|
className={cn(
|
||||||
}),
|
buttonVariants({
|
||||||
'h-full rounded-[50px] border-2 border-[#0F2C53] bg-[#0F2C53] px-14 text-2xl font-bold text-white transition hover:bg-white hover:text-[#0F2C53]',
|
size: 'lg',
|
||||||
|
variant: 'outline',
|
||||||
|
}),
|
||||||
|
'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-5 text-xl font-bold text-white transition hover:bg-[#225BA9] hover:text-white md:px-14 md:text-2xl',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{t('login')}
|
||||||
|
</Link>
|
||||||
)}
|
)}
|
||||||
>
|
</div>
|
||||||
{t('login')}
|
</div>
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</header>
|
{/* 登录注册弹窗 */}
|
||||||
|
<EmailAuthDialog ref={dialogRef} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export default function Header() {
|
|||||||
<UserNav />
|
<UserNav />
|
||||||
{!user && (
|
{!user && (
|
||||||
<Link
|
<Link
|
||||||
href='/auth'
|
href='/'
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
})}
|
})}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 3.9 KiB |
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import useGlobalStore from '@/config/use-global';
|
import useGlobalStore from '@/config/use-global';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function FooterCopyright() {
|
export default function FooterCopyright() {
|
||||||
@ -11,15 +12,25 @@ export default function FooterCopyright() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={'fixed bottom-6 z-50 w-full'}>
|
<footer className={'fixed bottom-6 z-50 w-full'}>
|
||||||
<div className={'container pr-0 text-right'}>
|
<div className={'container relative flex justify-center text-right md:block'}>
|
||||||
<strong className='text-foreground'>{site.site_name}</strong> © All rights reserved.
|
<Image
|
||||||
<div>
|
src={'./logo.png'}
|
||||||
<Link href='/tos' className='underline'>
|
height={37}
|
||||||
{t('tos')}
|
width={28}
|
||||||
</Link>
|
className={`h-[37px] w-[28px] flex-shrink-0 object-contain md:absolute md:left-1/2 md:-translate-x-1/2`}
|
||||||
<Link href='/privacy-policy' className='ml-2 underline'>
|
alt='logo'
|
||||||
{t('privacyPolicy')}
|
unoptimized
|
||||||
</Link>
|
></Image>
|
||||||
|
<div className={'ml-2.5'}>
|
||||||
|
<strong className='text-foreground'>{site.site_name}</strong> © All rights reserved.
|
||||||
|
<div>
|
||||||
|
<Link href='/tos' className='underline'>
|
||||||
|
{t('tos')}
|
||||||
|
</Link>
|
||||||
|
<Link href='/privacy-policy' className='ml-2 underline'>
|
||||||
|
{t('privacyPolicy')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import { Button } from '@workspace/ui/components/button';
|
import { Button } from '@workspace/ui/components/button';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import OfferDialog, { OfferDialogRef } from './OfferDialog/index';
|
||||||
|
|
||||||
export default function HomeContent() {
|
export default function HomeContent() {
|
||||||
|
const dialogRef = useRef<OfferDialogRef>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex min-h-[calc(100vh-73px)] flex-col items-center justify-center pt-8'>
|
<div className='flex min-h-[calc(100vh-73px)] flex-col items-center justify-center pt-8'>
|
||||||
{/* 大标题 */}
|
{/* 大标题 */}
|
||||||
<h1 className='mb-10 text-6xl font-extrabold leading-tight text-white'>
|
<h1 className='mb-10 text-5xl font-bold !leading-tight text-white md:text-6xl'>
|
||||||
连接
|
连接
|
||||||
<br />
|
<br />
|
||||||
任何时间
|
任何时间
|
||||||
@ -12,19 +18,24 @@ export default function HomeContent() {
|
|||||||
任何地点
|
任何地点
|
||||||
</h1>
|
</h1>
|
||||||
{/* 副标题 */}
|
{/* 副标题 */}
|
||||||
<div className='mb-16 text-center text-sm font-bold leading-6 text-white'>
|
<div className='mb-16 text-left text-[17px] leading-normal text-white md:text-center md:font-bold'>
|
||||||
<p>
|
<p className={'w-[255px] md:w-full'}>
|
||||||
<span className='mr-2 text-xs text-white'>
|
<span className='mr-2 text-white'>
|
||||||
Airo<sup className='text-[8px]'>™</sup>Port
|
Airo<sup className='text-[8px]'>™</sup>Port
|
||||||
</span>
|
</span>
|
||||||
<span>提供极稳,极简,极速的网络服务</span>
|
<span>提供极稳,极简,极速的网络服务</span>
|
||||||
</p>
|
</p>
|
||||||
<p>获取订阅地址,开始顶级的私密网络体验</p>
|
<p className={'mt-1 w-[255px] md:mt-0 md:w-full'}>获取订阅地址,开始顶级的私密网络体验</p>
|
||||||
</div>
|
</div>
|
||||||
{/* 按钮 */}
|
{/* 按钮 */}
|
||||||
<Button className='mb-8 h-[64px] w-[219px] rounded-full border-2 border-white bg-white/10 text-2xl font-bold text-white transition hover:bg-white/20'>
|
<Button
|
||||||
|
onClick={() => dialogRef.current?.show()}
|
||||||
|
className='mb-8 h-[64px] w-[219px] rounded-full border-2 border-white bg-white/10 text-2xl font-bold text-white transition hover:bg-white/20'
|
||||||
|
>
|
||||||
查看订阅套餐
|
查看订阅套餐
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<OfferDialog ref={dialogRef} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
39
apps/user/components/main/OfferDialog/index.tsx
Normal file
39
apps/user/components/main/OfferDialog/index.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import CloseSvg from '@/components/CustomIcon/icons/close.svg';
|
||||||
|
import { Dialog, DialogContent, DialogTitle } from '@workspace/ui/components/dialog';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
|
||||||
|
export interface OfferDialogRef {
|
||||||
|
show: () => void;
|
||||||
|
hide: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
show: () => setOpen(true),
|
||||||
|
hide: () => setOpen(false),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
|
<DialogContent
|
||||||
|
className={
|
||||||
|
'rounded-0 !container h-full w-full px-12 py-[4.5rem] md:h-auto md:w-[496px] md:!rounded-[50px]'
|
||||||
|
}
|
||||||
|
closeIcon={<Image src={CloseSvg} alt={'close'} />}
|
||||||
|
closeClassName={
|
||||||
|
'right-[40px] top-[30px] font-bold text-black opacity-100 focus:ring-0 focus:ring-offset-0'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DialogTitle className={'text-center text-5xl font-bold text-[#0F2C53]'}>
|
||||||
|
选择套餐
|
||||||
|
</DialogTitle>
|
||||||
|
<div className={'min-h-[524px]'}>套餐内容</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default OfferDialog;
|
||||||
@ -38,7 +38,7 @@ export function Hero() {
|
|||||||
className='*:text-muted-foreground mb-8 max-w-xl'
|
className='*:text-muted-foreground mb-8 max-w-xl'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Link href={user ? '/dashboard' : '/auth'}>
|
<Link href={user ? '/dashboard' : '/'}>
|
||||||
<HoverBorderGradient
|
<HoverBorderGradient
|
||||||
containerClassName='rounded-full'
|
containerClassName='rounded-full'
|
||||||
as='button'
|
as='button'
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
"message": "#### 尊敬的用户,您好!\n\n感谢您对我们的关注和支持。由于站点运营策略的调整,我们已关闭新用户注册功能。在此期间,现有用户的使用不会受到任何影响。\n\n我们致力于为您提供更好的服务和体验,因此将在关闭注册期间进行全面的系统优化和功能升级。未来,我们将以更优质的内容和服务迎接您的到来。\n\n请关注我们的网站和社交媒体平台,获取最新的动态和通知。感谢您的理解与支持。\n\n如有任何疑问或需要帮助,请随时联系我们的客服团队。\n\n**再次感谢您的支持与理解。**",
|
"message": "#### 尊敬的用户,您好!\n\n感谢您对我们的关注和支持。由于站点运营策略的调整,我们已关闭新用户注册功能。在此期间,现有用户的使用不会受到任何影响。\n\n我们致力于为您提供更好的服务和体验,因此将在关闭注册期间进行全面的系统优化和功能升级。未来,我们将以更优质的内容和服务迎接您的到来。\n\n请关注我们的网站和社交媒体平台,获取最新的动态和通知。感谢您的理解与支持。\n\n如有任何疑问或需要帮助,请随时联系我们的客服团队。\n\n**再次感谢您的支持与理解。**",
|
||||||
"passwordMismatch": "两次密码输入不一致",
|
"passwordMismatch": "两次密码输入不一致",
|
||||||
"success": "注册成功,已自动登录!",
|
"success": "注册成功,已自动登录!",
|
||||||
"switchToLogin": "登录/重置邮箱",
|
"switchToLogin": "登录",
|
||||||
"title": "注册",
|
"title": "注册",
|
||||||
"whitelist": "电子邮件域名不在允许的白名单中。"
|
"whitelist": "电子邮件域名不在允许的白名单中。"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export function Logout() {
|
|||||||
!pathname.startsWith('/oauth/')
|
!pathname.startsWith('/oauth/')
|
||||||
) {
|
) {
|
||||||
setRedirectUrl(location.pathname);
|
setRedirectUrl(location.pathname);
|
||||||
location.href = `/auth`;
|
location.href = `/`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||||
>(({ className, children, ...props }, ref) => (
|
>(({ className, closeClassName, closeIcon, children, ...props }, ref) => (
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay />
|
<DialogOverlay />
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
@ -44,8 +44,13 @@ const DialogContent = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<DialogPrimitive.Close className='ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none'>
|
<DialogPrimitive.Close
|
||||||
<X className='h-4 w-4' />
|
className={cn(
|
||||||
|
'ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none',
|
||||||
|
closeClassName,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{closeIcon || <X className='h-4 w-4' />}
|
||||||
<span className='sr-only'>Close</span>
|
<span className='sr-only'>Close</span>
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user