feat: 修改文案大小
This commit is contained in:
parent
9cde4cb0a1
commit
bf8c01048c
@ -5,7 +5,7 @@
|
||||
### 熟练部署命令
|
||||
|
||||
```shell
|
||||
APP_NAME="ppanel-admin-web-dev"
|
||||
APP_NAME="ppanel-admin-web"
|
||||
tar -xzvf ${APP_NAME}.tar.gz && pm2 start ${APP_NAME} && pm2 list
|
||||
unset APP_NAME # 显式销毁变量
|
||||
```
|
||||
|
||||
@ -19,7 +19,7 @@ export function Header() {
|
||||
const items = useMemo(() => findNavByUrl(pathname), [pathname]);
|
||||
return (
|
||||
<header className='flex h-[84px] w-full items-center justify-end gap-2 px-4 pt-4 md:hidden'>
|
||||
<SidebarTrigger className={'fixed left-4'} />
|
||||
<SidebarTrigger className={'fixed left-4 z-50'} />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList className={'text-[36px] font-semibold'}>
|
||||
{items.map((item, index) => {
|
||||
|
||||
@ -51,8 +51,8 @@ export const AnnouncementDialog = ({ ref }: AnnouncementDialogProps) => {
|
||||
const response = await queryAnnouncement({
|
||||
...pagination,
|
||||
...filter,
|
||||
pinned: false,
|
||||
popup: false,
|
||||
// pinned: false,
|
||||
// popup: false,
|
||||
});
|
||||
return {
|
||||
list: response.data.data?.announcements || [],
|
||||
@ -62,7 +62,7 @@ export const AnnouncementDialog = ({ ref }: AnnouncementDialogProps) => {
|
||||
renderItem={(item) => {
|
||||
return (
|
||||
<div
|
||||
className={`${item.pinned ? 'bg-[#B5C9E2]' : 'bg-white'} flex items-center rounded-[20px] px-4 py-2 shadow-[0_0_4.5px_0_rgba(0,0,0,0.25)]`}
|
||||
className={`${item.pinned ? 'bg-[#B5C9E2]' : 'bg-white'} flex items-center rounded-[20px] px-4 py-1.5 shadow-[0_0_4.5px_0_rgba(0,0,0,0.25)]`}
|
||||
>
|
||||
<p
|
||||
className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'} line-clamp-2 flex-1 text-[10px] sm:text-sm`}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Display } from '@/components/display';
|
||||
import Renewal from '@/components/subscribe/renewal';
|
||||
import { resetUserSubscribeToken } from '@/services/user/user';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@ -14,6 +13,7 @@ import { toast } from 'sonner';
|
||||
|
||||
import SvgIcon from '@/components/SvgIcon';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
@ -62,13 +62,13 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
</p>
|
||||
|
||||
{/* 统计信息 */}
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4'>
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] py-4'>
|
||||
<div className='grid grid-cols-3 gap-4 text-center'>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-sm'>
|
||||
{t('totalTraffic')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-base'>
|
||||
<Display
|
||||
type='traffic'
|
||||
value={userSubscribeData.traffic}
|
||||
@ -77,20 +77,20 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-sm'>
|
||||
{t('nextResetDays')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-base'>
|
||||
{userSubscribeData.reset_time
|
||||
? differenceInDays(new Date(userSubscribeData.reset_time), new Date())
|
||||
: t('noReset')}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-sm'>
|
||||
{t('expirationDays')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-base'>
|
||||
{userSubscribeData.expire_time
|
||||
? differenceInDays(new Date(userSubscribeData.expire_time), new Date()) ||
|
||||
t('unknown')
|
||||
@ -123,7 +123,7 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
</Tabs>
|
||||
)}
|
||||
</div>
|
||||
<div className={'mb-3 flex items-center justify-center gap-1'}>
|
||||
<div className={'mb-3 flex items-center justify-center gap-3'}>
|
||||
<div
|
||||
className={
|
||||
'flex flex-1 items-center gap-1 rounded-full bg-[#BABABA] pl-1 sm:gap-2 sm:rounded-[16px] sm:pl-2'
|
||||
@ -133,14 +133,14 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
value={userSubscribeProtocolCurrent}
|
||||
onValueChange={setUserSubscribeProtocolCurrent}
|
||||
>
|
||||
<SelectTrigger className='h-auto w-auto flex-shrink-0 rounded-[16px] border-none bg-[#D9D9D9] px-2.5 py-0.5 text-[13px] text-sm font-medium text-white shadow-none hover:bg-[#848484] focus:ring-0 sm:h-[35px] sm:rounded-[8px] sm:p-2 [&>svg]:hidden'>
|
||||
<SelectTrigger className='h-auto w-auto flex-shrink-0 rounded-[16px] border-none bg-[#D9D9D9] px-2.5 py-0.5 text-[13px] font-medium text-[#0F2C53] shadow-none hover:bg-[#848484] focus:ring-0 sm:h-[35px] sm:rounded-[8px] sm:px-2 sm:py-1.5 [&>svg]:hidden'>
|
||||
<SelectValue>
|
||||
<div className='flex flex-col items-center justify-center text-[10px] sm:text-sm'>
|
||||
<div className='flex flex-col items-center justify-between text-[10px] sm:text-xs'>
|
||||
<div>
|
||||
{t('subscriptionUrl')}
|
||||
{userSubscribeProtocolCurrent + 1}
|
||||
</div>
|
||||
<div className='-mt-0.5 h-0 w-0 scale-50 border-l-[5px] border-r-[5px] border-t-[5px] border-l-transparent border-r-transparent border-t-white sm:scale-100'></div>
|
||||
<div className='-mt-0.5 h-0 w-0 scale-50 border-l-[3px] border-r-[3px] border-t-[3px] border-l-transparent border-r-transparent border-t-[#0F2C53] sm:scale-100'></div>
|
||||
</div>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
@ -158,8 +158,8 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<div className='flex-1 rounded-full bg-white px-3 py-1 text-[10px] leading-tight text-[#225BA9] shadow-[inset_0px_0px_7.6px_0px_rgba(0,0,0,0.25)] sm:rounded-[16px] sm:text-xs'>
|
||||
<div className={'flex items-center gap-4 py-1 text-[10px] sm:text-[16px]'}>
|
||||
<div className='flex-1 rounded-full bg-white px-3 py-2 text-[10px] leading-tight text-[#225BA9] shadow-[inset_0px_0px_7.6px_0px_rgba(0,0,0,0.25)] sm:rounded-[16px]'>
|
||||
<div className={'flex items-center gap-4 py-1'}>
|
||||
<div className={'line-clamp-2 flex-1 break-all'}>
|
||||
{userSubscribeProtocol[userSubscribeProtocolCurrent]}
|
||||
</div>
|
||||
@ -203,15 +203,9 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
<div className='flex justify-between gap-2'>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
size='sm'
|
||||
className={
|
||||
'h-fit rounded-full bg-[#E22C2E] px-3 py-1 text-[10px] text-white sm:h-9 sm:text-xs'
|
||||
}
|
||||
variant='destructive'
|
||||
>
|
||||
<AiroButton variant='danger' className={'px-2 text-xs'}>
|
||||
{t('resetSubscription')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
@ -235,7 +229,7 @@ const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<Renewal
|
||||
className='h-fit rounded-full bg-[#A8D4ED] px-3 py-1 text-[10px] text-white sm:h-9 sm:text-xs'
|
||||
className='px-2 text-xs'
|
||||
id={userSubscribeData.id}
|
||||
subscribe={userSubscribeData.subscribe}
|
||||
/>
|
||||
|
||||
@ -64,9 +64,9 @@ export default function Content() {
|
||||
queryFn: async () => {
|
||||
const { data } = await queryAnnouncement({
|
||||
page: 1,
|
||||
size: 4,
|
||||
pinned: false,
|
||||
popup: false,
|
||||
size: 5,
|
||||
// pinned: false,
|
||||
// popup: false,
|
||||
});
|
||||
return data.data?.announcements || [];
|
||||
},
|
||||
@ -96,7 +96,7 @@ export default function Content() {
|
||||
<div className={'grid grid-cols-1 gap-[10px] sm:gap-6 lg:grid-cols-2'}>
|
||||
{/* 账户概况 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='mb-1 sm:mb-4'>
|
||||
<div className='mb-1'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('accountOverview')}
|
||||
</h3>
|
||||
@ -105,8 +105,8 @@ export default function Content() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
<div className='mb-3 sm:mb-3.5'>
|
||||
<span className='text-2xl font-medium text-[#091B33]'>
|
||||
{userSubscribe?.length > 0 && userSubscribe[0]?.status === 1 && orderData
|
||||
? orderData?.quantity === 1
|
||||
? t('annualMonthPlanUser')
|
||||
@ -115,7 +115,7 @@ export default function Content() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] px-4 py-[10px]'>
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] px-5 py-2.5'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-sm font-light text-[#666666]'>{t('accountBalance')}</span>
|
||||
<Recharge
|
||||
@ -124,7 +124,7 @@ export default function Content() {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className='text-xl font-medium text-[#225BA9] sm:text-4xl'>
|
||||
<div className='text-xl font-medium text-[#225BA9] sm:text-2xl'>
|
||||
<Display type='currency' value={totalAssets} />
|
||||
</div>
|
||||
</div>
|
||||
@ -132,7 +132,7 @@ export default function Content() {
|
||||
|
||||
{/* 套餐状态 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 text-[#666666] shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='mb-4'>
|
||||
<div className=''>
|
||||
<h3 className='flex items-center justify-between text-[#666666]'>
|
||||
<div className={'flex items-center justify-between'}>
|
||||
<span className={'text-base font-medium sm:text-xl'}>{t('planStatus')}</span>
|
||||
@ -153,12 +153,12 @@ export default function Content() {
|
||||
</div>
|
||||
{userSubscribe?.length ? (
|
||||
<>
|
||||
<div className='mb-2 text-sm text-[#666666] sm:mb-[22px] sm:mt-1'>
|
||||
<div className='mt-1 text-xs text-[#666666] sm:text-sm'>
|
||||
{t('planExpirationTime')}
|
||||
{formatDate(userSubscribe?.[0]?.expire_time, false)}
|
||||
</div>
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
<div className='mb-3 sm:mb-5'>
|
||||
<span className='text-2xl font-medium text-[#091B33]'>
|
||||
{userSubscribe?.[0]?.subscribe.name}
|
||||
</span>
|
||||
</div>
|
||||
@ -226,7 +226,7 @@ export default function Content() {
|
||||
</Card>
|
||||
{/* 网站公告 Card */}
|
||||
<Card className='relative order-4 rounded-[20px] border border-[#EAEAEA] bg-gradient-to-b from-white to-[#EAEAEA] p-6 pb-0 sm:order-none'>
|
||||
<div className='mb-3 flex items-center justify-between sm:mb-4'>
|
||||
<div className='mb-3 flex items-center justify-between sm:mb-1'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('siteAnnouncements')}
|
||||
</h3>
|
||||
@ -248,7 +248,7 @@ export default function Content() {
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`${item.pinned ? 'bg-[#B5C9E2]' : 'bg-white'} flex items-center rounded-[20px] px-4 py-2`}
|
||||
className={`${item.pinned ? 'bg-[#B5C9E2]' : 'bg-white'} flex items-center rounded-[20px] px-4 py-1.5`}
|
||||
>
|
||||
<p
|
||||
className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'} line-clamp-2 flex-1 text-[10px] sm:text-sm`}
|
||||
@ -285,7 +285,7 @@ export default function Content() {
|
||||
|
||||
{/* 我的订阅 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='flex items-center justify-between sm:mb-4'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('mySubscription')}
|
||||
</h3>
|
||||
|
||||
@ -67,7 +67,7 @@ const OrderDetailDialog = forwardRef<OrderDetailDialogRef, OrderDetailDialogProp
|
||||
<div className={'sr-only'}>order detail</div>
|
||||
</DialogTitle>
|
||||
<DialogContent className='sm:w-[675px]'>
|
||||
<div className='text-4xl font-bold text-[#0F2C53] sm:mb-8 sm:text-center sm:text-4xl'>
|
||||
<div className='text-2xl font-bold text-[#0F2C53] sm:mb-8 sm:text-center'>
|
||||
{t('orderDetail')}
|
||||
</div>
|
||||
|
||||
|
||||
@ -77,7 +77,7 @@ export default function Page() {
|
||||
</AiroButton>
|
||||
</div>
|
||||
</div>
|
||||
<CardContent className='px-0 py-3 pb-0 text-sm sm:pb-6'>
|
||||
<CardContent className='px-0 py-3 pb-0 text-sm'>
|
||||
<ul className='grid grid-cols-2 gap-3 *:flex *:flex-col lg:grid-cols-4'>
|
||||
<li>
|
||||
<span className='text-[#225BA9]'>{t('name')}</span>
|
||||
|
||||
@ -29,16 +29,12 @@ export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<LoginDialogProvider>
|
||||
<div
|
||||
className={
|
||||
'hidden text-4xl font-bold text-[#0F2C53] sm:block md:mb-4 md:text-center md:text-5xl'
|
||||
}
|
||||
>
|
||||
<div className={'hidden text-4xl font-bold text-[#0F2C53] sm:block md:mb-4 md:text-center'}>
|
||||
{t('title')}
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
'mt-0 text-right text-lg font-bold text-[#666666] sm:mt-0 sm:text-center sm:font-medium'
|
||||
'mt-0 text-right text-base font-bold text-[#666666] sm:mt-0 sm:text-center sm:font-medium'
|
||||
}
|
||||
>
|
||||
{t('description')}
|
||||
|
||||
@ -27,23 +27,23 @@ const Table: React.FC<{}> = () => {
|
||||
<CardContent className='px-0 py-3 text-[10px] sm:p-3 sm:text-sm'>
|
||||
<ul className='grid grid-cols-4 gap-3 *:flex *:flex-col'>
|
||||
<li className='font-semibold'>
|
||||
<span className='text-[#225BA9]'>{t('createdAt')}</span>
|
||||
<time>{formatDate(item.created_at)}</time>
|
||||
<span className='font-normal text-[#225BA9]'>{t('createdAt')}</span>
|
||||
<time className={'text-base'}>{formatDate(item.created_at)}</time>
|
||||
</li>
|
||||
<li className='font-semibold'>
|
||||
<span className='text-[#225BA9]'>{t('type.0')}</span>
|
||||
<span>{t(`type.${item.type}`)}</span>
|
||||
<span className='font-normal text-[#225BA9]'>{t('type.0')}</span>
|
||||
<span className={'text-base'}>{t(`type.${item.type}`)}</span>
|
||||
</li>
|
||||
<li className='font-semibold'>
|
||||
<span className='text-[#225BA9]'>{t('amount')}</span>
|
||||
<span>
|
||||
<span className='font-normal text-[#225BA9]'>{t('amount')}</span>
|
||||
<span className={'text-base'}>
|
||||
<Display type='currency' value={item.amount} />
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li className='font-semibold'>
|
||||
<span className='text-[#225BA9]'>{t('balance')}</span>
|
||||
<span>
|
||||
<span className='font-normal text-[#225BA9]'>{t('balance')}</span>
|
||||
<span className={'text-base'}>
|
||||
<Display type='currency' value={item.balance} />
|
||||
</span>
|
||||
</li>
|
||||
|
||||
@ -31,7 +31,7 @@ export default function Page() {
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
<p className='text-sm font-light text-[#666]'>{t('totalAssets')}</p>
|
||||
<p className='text-2xl font-bold sm:text-[32px]'>
|
||||
<p className='text-2xl font-bold'>
|
||||
<Display type='currency' value={totalAssets} />
|
||||
</p>
|
||||
</div>
|
||||
@ -39,37 +39,33 @@ export default function Page() {
|
||||
</div>
|
||||
<div className='grid grid-cols-2 gap-2 sm:grid-cols-2 sm:gap-6 md:grid-cols-4'>
|
||||
<div className='col-span-2 rounded-[20px] bg-[#EAEAEA] p-4 shadow-sm transition-all duration-300 hover:shadow-md sm:col-span-1'>
|
||||
<p className='text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
<p className='text-sm font-light text-[#666] opacity-80 sm:mb-3'>
|
||||
{t('accountBalance')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='text-xl font-medium text-[#225BA9]'>
|
||||
<Display type='currency' value={user?.balance} />
|
||||
</p>
|
||||
</div>
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4 shadow-sm transition-all duration-300 hover:shadow-md'>
|
||||
<p className='t text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
{t('giftAmount')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='text-sm font-light text-[#666] opacity-80 sm:mb-3'>{t('giftAmount')}</p>
|
||||
<p className='text-xl font-medium text-[#225BA9]'>
|
||||
<Display type='currency' value={user?.gift_amount} />
|
||||
</p>
|
||||
</div>
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4 shadow-sm transition-all duration-300 hover:shadow-md'>
|
||||
<p className='t text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
{t('commission')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='text-sm font-light text-[#666] opacity-80 sm:mb-3'>{t('commission')}</p>
|
||||
<p className='text-xl font-medium text-[#225BA9]'>
|
||||
<Display type='currency' value={user?.commission} />
|
||||
</p>
|
||||
</div>
|
||||
<div className='col-span-2 rounded-[20px] border-2 border-[#D9D9D9] p-4 shadow-sm transition-all duration-300 hover:shadow-md sm:col-span-1'>
|
||||
<p className='mb-1 flex justify-between text-sm font-medium text-[#666] opacity-80 sm:mb-3'>
|
||||
<p className='mb-1 flex justify-between text-sm font-light text-[#666] sm:mb-3'>
|
||||
<span>{t('referralCode')}</span>
|
||||
<Link href='/affiliate' className={'text-[#225BA9]'}>
|
||||
{t('referralDetails')}
|
||||
</Link>
|
||||
</p>
|
||||
<p className='flex justify-between text-base font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='flex justify-between text-base font-medium text-[#225BA9]'>
|
||||
<span> {user?.refer_code}</span>
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/?invite=${user?.refer_code}`}
|
||||
|
||||
@ -66,7 +66,7 @@ const LoginDialog = forwardRef<LoginDialogRef>((props, ref) => {
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className='rounded-0 h-full w-full px-12 py-[4.5rem] sm:h-auto sm:w-[496px] sm:!rounded-[50px]'>
|
||||
<DialogTitle className='sr-only'>Login</DialogTitle>
|
||||
<div className='min-h-[524px]'>
|
||||
<div className=''>
|
||||
<EmailAuthForm hide={hide} isRedirect={isRedirect} />
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import {
|
||||
Form,
|
||||
@ -55,7 +56,7 @@ export default function LoginForm({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={'pb-9 pt-16 text-4xl font-bold'}>账户验证</div>
|
||||
<div className={'h-[84px] text-2xl font-bold leading-[84px]'}>账户验证</div>
|
||||
<Form {...form}>
|
||||
<form onSubmit={handleSubmit} className=''>
|
||||
<FormField
|
||||
@ -65,9 +66,7 @@ export default function LoginForm({
|
||||
<FormItem className={'mb-5'}>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Email'
|
||||
type='email'
|
||||
{...field}
|
||||
@ -84,9 +83,7 @@ export default function LoginForm({
|
||||
<FormItem className={'mb-2'}>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Password'
|
||||
type='password'
|
||||
{...field}
|
||||
@ -133,14 +130,15 @@ export default function LoginForm({
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex justify-center'>
|
||||
<Button
|
||||
<AiroButton
|
||||
type='submit'
|
||||
variant='default'
|
||||
disabled={loading}
|
||||
className='h-[64px] w-[219px] rounded-full border-[#0F2C53] bg-[#0F2C53] text-2xl font-bold hover:bg-[#225BA9] hover:text-white'
|
||||
className='h-auto min-w-[157px] py-2 text-lg font-medium'
|
||||
>
|
||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||
{t('title')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@ -93,7 +95,7 @@ export default function RegisterForm({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={'pb-9 text-4xl font-bold'}>注册账户</div>
|
||||
<div className={'h-[84px] text-2xl font-bold leading-[84px]'}>注册账户</div>
|
||||
|
||||
{auth.register.stop_register ? (
|
||||
<Markdown>{t('message')}</Markdown>
|
||||
@ -108,9 +110,7 @@ export default function RegisterForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Enter your email...'
|
||||
type='email'
|
||||
{...field}
|
||||
@ -127,9 +127,7 @@ export default function RegisterForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Enter your password...'
|
||||
type='password'
|
||||
{...field}
|
||||
@ -146,9 +144,7 @@ export default function RegisterForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
disabled={loading}
|
||||
placeholder='Enter password again...'
|
||||
type='password'
|
||||
@ -169,9 +165,7 @@ export default function RegisterForm({
|
||||
<div className='flex items-center gap-8'>
|
||||
<Input
|
||||
disabled={loading}
|
||||
className={
|
||||
'h-[60px] flex-1 rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Enter code...'
|
||||
type='text'
|
||||
{...field}
|
||||
@ -198,9 +192,7 @@ export default function RegisterForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
disabled={loading || !!localStorage.getItem('invite')}
|
||||
placeholder={t('invite')}
|
||||
{...field}
|
||||
@ -242,14 +234,14 @@ export default function RegisterForm({
|
||||
</Button>
|
||||
</div>
|
||||
<div className='mt-6 flex justify-center'>
|
||||
<Button
|
||||
<AiroButton
|
||||
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'
|
||||
className='h-auto min-w-[157px] py-2 text-lg font-medium'
|
||||
>
|
||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||
{t('title')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import {
|
||||
Form,
|
||||
@ -60,7 +61,7 @@ export default function ResetForm({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={'pb-9 pt-10 text-4xl font-bold'}>找回账户</div>
|
||||
<div className={'h-[84px] text-2xl font-bold leading-[84px]'}>找回账户</div>
|
||||
<Form {...form}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className='grid gap-5'>
|
||||
@ -71,9 +72,7 @@ export default function ResetForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Enter your email...'
|
||||
type='email'
|
||||
{...field}
|
||||
@ -91,9 +90,7 @@ export default function ResetForm({
|
||||
<FormControl>
|
||||
<div className='flex items-center gap-8'>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] flex-1 rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
disabled={loading}
|
||||
placeholder='Enter code...'
|
||||
type='text'
|
||||
@ -120,9 +117,7 @@ export default function ResetForm({
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
className={
|
||||
'h-[60px] rounded-[20px] text-xl shadow-[inset_0_0_7.6px_0_#00000040]'
|
||||
}
|
||||
className={'h-[46px] rounded-full shadow-[inset_0_0_7.6px_0_#00000040]'}
|
||||
placeholder='Enter your new password...'
|
||||
type='password'
|
||||
{...field}
|
||||
@ -162,14 +157,14 @@ export default function ResetForm({
|
||||
</Button>
|
||||
</div>
|
||||
<div className='mt-6 flex justify-center'>
|
||||
<Button
|
||||
<AiroButton
|
||||
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'
|
||||
className='h-auto min-w-[157px] py-2 text-lg font-medium'
|
||||
>
|
||||
{loading && <Icon icon='mdi:loading' className='animate-spin' />}
|
||||
{t('title')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -84,7 +84,7 @@ export default function SendCode({ type, params }: SendCodeProps) {
|
||||
<Button
|
||||
type='button'
|
||||
className={
|
||||
'h-[60px] w-[109px] rounded-full border-[#A8D4ED] bg-[#A8D4ED] text-xl hover:bg-[#225BA9] hover:text-white'
|
||||
'h-[30px] w-[109px] rounded-full border-[#A8D4ED] bg-[#A8D4ED] text-base hover:bg-[#225BA9] hover:text-white'
|
||||
}
|
||||
onClick={handleSendCode}
|
||||
disabled={disabled}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="40" height="40" rx="10" fill="#D9D9D9"/>
|
||||
<rect x="1" y="1" width="38" height="38" rx="9" stroke="#848484" stroke-opacity="0.28" stroke-width="2"/>
|
||||
<rect x="1" y="1" width="38" height="38" rx="9" stroke="#225BA9" stroke-width="2"/>
|
||||
<g clip-path="url(#clip0_795_3268)">
|
||||
<path d="M8.75 8C8.3375 8 8 8.3375 8 8.75V17.75C8 18.1625 8.3375 18.5 8.75 18.5H17.75C18.1625 18.5 18.5 18.1625 18.5 17.75V8.75C18.5 8.3375 18.1625 8 17.75 8H8.75ZM22.25 8C21.8375 8 21.5 8.3375 21.5 8.75V17.75C21.5 18.1625 21.8375 18.5 22.25 18.5H31.25C31.6625 18.5 32 18.1625 32 17.75V8.75C32 8.3375 31.6625 8 31.25 8H22.25ZM9.5 9.5H17V17H9.5V9.5ZM23 9.5H30.5V17H23V9.5ZM11 11V15.5H15.5V11H11ZM24.5 11V15.5H29V11H24.5ZM8.75 21.5C8.3375 21.5 8 21.8375 8 22.25V31.25C8 31.6625 8.3375 32 8.75 32H17.75C18.1625 32 18.5 31.6625 18.5 31.25V22.25C18.5 21.8375 18.1625 21.5 17.75 21.5H8.75ZM22.25 21.5C21.8375 21.5 21.5 21.8375 21.5 22.25V26H23V23H26V21.5H22.25ZM28.25 21.5C27.8375 21.5 27.5 21.8375 27.5 22.25V26H29V23H32V21.5H28.25ZM9.5 23H17V30.5H9.5V23ZM11 24.5V29H15.5V24.5H11ZM24.5 26V27.5H23.75C23.3375 27.5 23 27.8375 23 28.25V32H24.5V29H26V32H27.5V28.25C27.5 27.8375 27.1625 27.5 26.75 27.5H26V26H24.5ZM30.5 26V32H32V26H30.5Z" fill="#848484"/>
|
||||
<path d="M8.75 8C8.3375 8 8 8.3375 8 8.75V17.75C8 18.1625 8.3375 18.5 8.75 18.5H17.75C18.1625 18.5 18.5 18.1625 18.5 17.75V8.75C18.5 8.3375 18.1625 8 17.75 8H8.75ZM22.25 8C21.8375 8 21.5 8.3375 21.5 8.75V17.75C21.5 18.1625 21.8375 18.5 22.25 18.5H31.25C31.6625 18.5 32 18.1625 32 17.75V8.75C32 8.3375 31.6625 8 31.25 8H22.25ZM9.5 9.5H17V17H9.5V9.5ZM23 9.5H30.5V17H23V9.5ZM11 11V15.5H15.5V11H11ZM24.5 11V15.5H29V11H24.5ZM8.75 21.5C8.3375 21.5 8 21.8375 8 22.25V31.25C8 31.6625 8.3375 32 8.75 32H17.75C18.1625 32 18.5 31.6625 18.5 31.25V22.25C18.5 21.8375 18.1625 21.5 17.75 21.5H8.75ZM22.25 21.5C21.8375 21.5 21.5 21.8375 21.5 22.25V26H23V23H26V21.5H22.25ZM28.25 21.5C27.8375 21.5 27.5 21.8375 27.5 22.25V26H29V23H32V21.5H28.25ZM9.5 23H17V30.5H9.5V23ZM11 24.5V29H15.5V24.5H11ZM24.5 26V27.5H23.75C23.3375 27.5 23 27.8375 23 28.25V32H24.5V29H26V32H27.5V28.25C27.5 27.8375 27.1625 27.5 26.75 27.5H26V26H24.5ZM30.5 26V32H32V26H30.5Z" fill="#225BA9"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_795_3268">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -26,11 +26,11 @@ export default function Header() {
|
||||
<>
|
||||
<header className='fixed top-10 z-50 w-full'>
|
||||
<div className={'container'}>
|
||||
<div className='flex h-[60px] items-center justify-between rounded-[50px] bg-white pl-4 pr-1 sm:h-[73px] md:pl-7'>
|
||||
<div className='flex h-[60px] items-center justify-between rounded-[50px] bg-white pl-4 pr-3 md:pl-6'>
|
||||
<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'>
|
||||
{Logo}
|
||||
</nav>
|
||||
<div className='flex h-full flex-1 items-center justify-end gap-2 py-1'>
|
||||
<div className='flex h-full flex-1 items-center justify-end gap-2 py-2'>
|
||||
<LanguageSwitch />
|
||||
{/*<ThemeSwitch />*/}
|
||||
<UserNav />
|
||||
@ -43,7 +43,7 @@ export default function Header() {
|
||||
size: 'lg',
|
||||
variant: 'outline',
|
||||
}),
|
||||
'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-5 text-[16px] font-bold text-white transition hover:bg-[#225BA9] hover:text-white sm:px-14 sm:text-2xl',
|
||||
'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-5 text-base font-bold text-white transition hover:bg-[#225BA9] hover:text-white sm:px-10 sm:text-lg',
|
||||
)}
|
||||
>
|
||||
{t('login')}
|
||||
|
||||
@ -65,9 +65,7 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ plan }) => {
|
||||
{common?.currency?.currency_symbol}
|
||||
{plan.discount_price}
|
||||
</span>
|
||||
<span className='text-sm font-normal leading-[1.8em] text-[#4D4D4D] sm:text-[15px]'>
|
||||
{t('perYear')}
|
||||
</span>
|
||||
<span className='text-sm font-normal text-[#4D4D4D] sm:text-base'>{t('perYear')}</span>
|
||||
</div>
|
||||
<div className={'h-[15px]'}>
|
||||
{plan.origin_price && (
|
||||
@ -86,12 +84,13 @@ import Modal, { AlertDialogRef } from '@/components/Modal';
|
||||
import Purchase from '@/components/subscribe/purchase';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { queryUserSubscribe } from '@/services/user/user';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import React from 'react';
|
||||
|
||||
// 星级评分组件
|
||||
const StarRating = ({ rating, maxRating = 5 }: { rating: number; maxRating?: number }) => (
|
||||
<div className='text-right text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'>
|
||||
<div className='text-right text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
{Array.from({ length: Math.min(rating, maxRating) }, (_, i) => (
|
||||
<span key={i} className='text-black'>
|
||||
✭
|
||||
@ -103,13 +102,13 @@ const StarRating = ({ rating, maxRating = 5 }: { rating: number; maxRating?: num
|
||||
// 功能列表组件
|
||||
const FeatureList = ({ plan }: { plan: API.Subscribe }) => {
|
||||
const t = useTranslations('subscribe.detail');
|
||||
const tSubscribe = useTranslations('subscribe');
|
||||
const tOffer = useTranslations('components.offerDialog');
|
||||
const features = [{ label: tOffer('availableNodes'), value: plan?.server_count }];
|
||||
|
||||
return (
|
||||
<div className='mt-6 space-y-0 sm:mt-6'>
|
||||
<ul className='list-disc space-y-1 pl-5'>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'>
|
||||
<ul className='list-disc space-y-0 pl-5'>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className=''>{t('availableTraffic')}</span>
|
||||
<span>
|
||||
@ -117,7 +116,16 @@ const FeatureList = ({ plan }: { plan: API.Subscribe }) => {
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className=''>{tSubscribe('billing.duration')}</span>
|
||||
<span>
|
||||
{plan.origin_price ? '365' : '30'}
|
||||
{tSubscribe('Day')}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className=''>{t('connectionSpeed')}</span>
|
||||
<span>
|
||||
@ -125,7 +133,7 @@ const FeatureList = ({ plan }: { plan: API.Subscribe }) => {
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'>
|
||||
<li className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className=''>{t('connectedDevices')}</span>
|
||||
<span>
|
||||
@ -136,7 +144,7 @@ const FeatureList = ({ plan }: { plan: API.Subscribe }) => {
|
||||
{features.map((feature) => (
|
||||
<li
|
||||
key={feature.label}
|
||||
className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'
|
||||
className='py-1 text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'
|
||||
>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className=''>{feature.label}:</span>
|
||||
@ -146,7 +154,7 @@ const FeatureList = ({ plan }: { plan: API.Subscribe }) => {
|
||||
))}
|
||||
<li className='py-1'>
|
||||
<div className={'flex items-start justify-between'}>
|
||||
<span className='text-xs font-light leading-[1.8461538461538463em] text-black sm:text-[13px]'>
|
||||
<span className='text-xs font-light leading-[1.8461538461538463em] text-black sm:text-sm'>
|
||||
{tOffer('networkStabilityIndex')}
|
||||
</span>
|
||||
<StarRating rating={5} />
|
||||
@ -186,23 +194,24 @@ const PlanCard: React.FC<{
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='relative w-full min-w-[300px] cursor-pointer rounded-[20px] border border-[#D9D9D9] bg-white p-8 shadow-[0_0_52.6px_1px_rgba(15,44,83,0.05)] transition-all duration-300 sm:w-[345px] sm:p-10'>
|
||||
{/* 套餐名称 */}
|
||||
<h3 className='mb-4 text-left text-xl font-normal sm:mb-6 sm:text-base'>{plan.name}</h3>
|
||||
<div className='relative w-full min-w-[300px] cursor-pointer rounded-[20px] border border-[#D9D9D9] bg-white p-8 shadow-[0_0_52.6px_1px_rgba(15,44,83,0.05)] transition-all duration-300 sm:w-[345px]'>
|
||||
<div className={'ml-4'}>
|
||||
{/* 套餐名称 */}
|
||||
<h3 className='mb-3 text-left text-xl font-normal sm:text-base'>{plan.name}</h3>
|
||||
|
||||
{/* 价格区域 */}
|
||||
<PriceDisplay plan={plan} />
|
||||
{/* 价格区域 */}
|
||||
<PriceDisplay plan={plan} />
|
||||
</div>
|
||||
|
||||
{/* 订阅按钮 */}
|
||||
<button
|
||||
onClick={handleSubscribe}
|
||||
className='h-10 w-full rounded-full bg-[#0F2C53] text-sm font-medium text-white shadow-md transition-all duration-300 hover:bg-[#225BA9] sm:h-10 sm:text-sm md:h-[40px] md:text-[14px]'
|
||||
>
|
||||
<AiroButton onClick={handleSubscribe} className='h-10 w-full text-sm font-medium'>
|
||||
{t('subscribe')}
|
||||
</button>
|
||||
</AiroButton>
|
||||
|
||||
{/* 功能列表 */}
|
||||
<FeatureList plan={plan} />
|
||||
<div className={'mx-4'}>
|
||||
{/* 功能列表 */}
|
||||
<FeatureList plan={plan} />
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
ref={ModalRef}
|
||||
|
||||
@ -28,13 +28,13 @@ const PlanTabs: React.FC<PlanTabProps> = (props) => {
|
||||
return (
|
||||
<Tabs
|
||||
defaultValue='year'
|
||||
className={cn('mt-8 w-full text-center md:mt-16', className)}
|
||||
className={cn('mt-8 w-full text-center md:mt-8', className)}
|
||||
value={tabValue}
|
||||
onValueChange={(value) => props.setTabValue(value as 'year' | 'month')}
|
||||
>
|
||||
<TabsList className='relative mb-8 grid h-[74px] grid-cols-2 flex-wrap rounded-full bg-[#EAEAEA] p-2.5 md:mb-16'>
|
||||
<TabsList className='relative mb-8 grid h-auto grid-cols-2 flex-wrap rounded-full bg-[#EAEAEA] px-2.5 py-2'>
|
||||
{tabValue === 'year' ? (
|
||||
<span className='absolute -top-8 left-16 z-10 rounded-sm bg-[#E22C2E] px-2 py-0.5 text-[10px] font-bold leading-none text-white shadow sm:text-xs'>
|
||||
<span className='absolute -top-7 left-16 z-10 rounded-sm bg-[#E22C2E] px-3 py-0.5 text-[10px] font-bold leading-none text-white shadow sm:text-xs'>
|
||||
-{props.discount}%{/* 小三角箭头 */}
|
||||
<span
|
||||
className='absolute right-0 top-[75%] h-10 w-2 bg-[#E22C2E]'
|
||||
@ -46,7 +46,7 @@ const PlanTabs: React.FC<PlanTabProps> = (props) => {
|
||||
<TabsTrigger
|
||||
key={val.value}
|
||||
className={
|
||||
'rounded-full py-3.5 text-xl data-[state=active]:bg-[#0F2C53] data-[state=active]:text-white md:px-12'
|
||||
'rounded-full py-2 text-base text-[#0F2C53] data-[state=active]:bg-[#0F2C53] data-[state=active]:text-white md:px-12'
|
||||
}
|
||||
value={val.value}
|
||||
>
|
||||
|
||||
@ -57,11 +57,11 @@ export const AffiliateDialog = ({ ref }: AffiliateDialogProps) => {
|
||||
return (
|
||||
<div className='flex flex-wrap justify-between gap-2 rounded-[20px] bg-white px-6 py-2 text-[10px] shadow-[0_0_4.5px_0_rgba(0,0,0,0.25)] sm:text-base'>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'text-sm text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>{invite.identifier}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'text-sm text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>
|
||||
{formatDate(invite.registered_at)}
|
||||
</div>
|
||||
|
||||
@ -66,24 +66,22 @@ export default function Affiliate() {
|
||||
<div className={'text-xs font-light sm:text-[15px]'}>{t('commissionInfo')}</div>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
'mb-3 text-xl font-bold leading-tight text-[#091B33] sm:text-[32px] sm:leading-[1.5]'
|
||||
}
|
||||
className={'mb-3 text-xl font-bold leading-tight text-[#091B33] sm:mb-4 sm:text-2xl'}
|
||||
>
|
||||
{t('historicalRecommendedUsers')}
|
||||
{inviteListData?.total}
|
||||
</div>
|
||||
<div className={'grid grid-cols-2 gap-[10px] sm:grid-cols-1 sm:gap-5 lg:grid-cols-2'}>
|
||||
<div className='rounded-[20px] border-2 border-[#EAEAEA] bg-[#EAEAEA] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:py-4'>
|
||||
<p className='flex justify-between font-medium text-[#666] opacity-80 sm:mb-3 sm:text-sm'>
|
||||
<div className='rounded-[20px] border-2 border-[#EAEAEA] bg-[#EAEAEA] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:px-5 sm:pb-2 sm:pt-4'>
|
||||
<p className='flex justify-between font-light text-[#666] sm:mb-3 sm:text-sm'>
|
||||
{t('totalCommission')}
|
||||
</p>
|
||||
<p className='text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='text-xl font-semibold text-[#225BA9]'>
|
||||
<Display type='currency' value={data?.total_commission} />
|
||||
</p>
|
||||
</div>
|
||||
<div className='rounded-[20px] border-2 border-[#D9D9D9] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:py-4'>
|
||||
<p className='flex justify-between font-medium text-[#666] opacity-80 sm:mb-3 sm:text-sm'>
|
||||
<div className='rounded-[20px] border-2 border-[#D9D9D9] px-4 py-2 shadow-sm transition-all duration-300 hover:shadow-md sm:px-5 sm:pb-2 sm:pt-4'>
|
||||
<p className='flex justify-between font-light text-[#666] sm:mb-3 sm:text-sm'>
|
||||
{t('commissionInviteCode')}
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/?invite=${user?.refer_code}`}
|
||||
@ -102,7 +100,7 @@ export default function Affiliate() {
|
||||
</Button>
|
||||
</CopyToClipboard>
|
||||
</p>
|
||||
<p className='flex justify-between text-xl font-bold text-[#225BA9] sm:text-2xl'>
|
||||
<p className='flex justify-between text-xl font-bold text-[#225BA9]'>
|
||||
<span> {user?.refer_code}</span>
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/?invite=${user?.refer_code}`}
|
||||
@ -148,11 +146,11 @@ export default function Affiliate() {
|
||||
return (
|
||||
<div className='flex flex-wrap justify-between gap-2 rounded-[20px] bg-white px-6 py-2 text-[10px] sm:text-base'>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'text-sm text-[#225BA9]'}>{t('userIdentifier')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>{invite.identifier}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={'text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'text-sm text-[#225BA9]'}>{t('time')}</div>
|
||||
<div className={'font-bold text-[#091B33]'}>
|
||||
{formatDate(invite.registered_at)}
|
||||
</div>
|
||||
@ -172,7 +170,9 @@ export default function Affiliate() {
|
||||
{t('commissionCalculation')}
|
||||
</h3>
|
||||
</div>
|
||||
<div className={'mb-4 text-[10px] font-light text-[#0F2C53] sm:text-base'}>
|
||||
<div
|
||||
className={'mb-4 whitespace-pre-line text-[10px] font-light text-[#0F2C53] sm:text-sm'}
|
||||
>
|
||||
{t('commissionCalculationInfo')}
|
||||
</div>
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ export default function FooterCopyright() {
|
||||
const t = useTranslations('auth');
|
||||
|
||||
return (
|
||||
<footer className={'fixed bottom-6 z-50 w-full text-xs sm:text-lg'}>
|
||||
<footer className={'fixed bottom-6 z-[1] w-full text-xs sm:text-sm'}>
|
||||
<div className={'container relative flex items-center justify-center text-right sm:block'}>
|
||||
<Image
|
||||
src={'./logo.png'}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRef } from 'react';
|
||||
import OfferDialog, { OfferDialogRef } from './OfferDialog/index';
|
||||
import OfferDialog from './OfferDialog/index';
|
||||
|
||||
export default function HomeContent() {
|
||||
const dialogRef = useRef<OfferDialogRef>(null);
|
||||
const t = useTranslations('components.home');
|
||||
|
||||
return (
|
||||
<div className='flex min-h-[calc(100vh-73px)] flex-col items-center justify-center pt-8'>
|
||||
{/* 大标题 */}
|
||||
<h1 className='mb-6 self-start text-4xl font-bold !leading-tight text-white sm:mb-10 sm:self-center sm:text-6xl'>
|
||||
<h1 className='mb-6 self-start text-4xl font-bold !leading-tight text-white sm:mb-10 sm:self-center sm:text-6xl sm:text-[64px]'>
|
||||
{t('connect')}
|
||||
<br />
|
||||
{t('anytime')}
|
||||
@ -30,14 +27,7 @@ export default function HomeContent() {
|
||||
<p className={'mt-1 w-[255px] sm:mt-0 sm:w-full'}>{t('getSubscription')}</p>
|
||||
</div>
|
||||
{/* 按钮 */}
|
||||
<Button
|
||||
onClick={() => dialogRef.current?.show()}
|
||||
className='mb-8 h-auto rounded-full border-2 border-white bg-white/10 px-8 py-2 text-lg font-bold text-white transition hover:bg-white/25 sm:py-4 sm:text-2xl'
|
||||
>
|
||||
{t('viewSubscriptionPlans')}
|
||||
</Button>
|
||||
|
||||
<OfferDialog ref={dialogRef} />
|
||||
<OfferDialog />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
import { getSubscription } from '@/services/user/portal';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Dialog, DialogContent, DialogTitle } from '@workspace/airo-ui/components/dialog';
|
||||
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@workspace/airo-ui/components/dialog';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import TabContent from '@/components/SubscribePlan/PlanContent/index';
|
||||
import PlanTabs from '@/components/SubscribePlan/PlanTabs/PlanTabs';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export interface OfferDialogRef {
|
||||
show: () => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
const OfferDialog = () => {
|
||||
const t = useTranslations('components.offerDialog');
|
||||
const tHome = useTranslations('components.home');
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [tabValue, setTabValue] = useState<'year' | 'month'>('year');
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
@ -40,28 +43,26 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
},
|
||||
enabled: true, // 初始不执行,手动控制
|
||||
retry: 1, // 失败时重试1次
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: () => {
|
||||
refetch();
|
||||
setOpen(true);
|
||||
},
|
||||
hide: () => setOpen(false),
|
||||
}));
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button className='mb-8 h-auto rounded-full border-[3px] border-white bg-white/10 px-8 py-2 text-lg font-bold text-white transition hover:bg-white/25 sm:px-6 sm:py-1.5'>
|
||||
{tHome('viewSubscriptionPlans')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
ref={dialogRef}
|
||||
className='rounded-0 h-full gap-0 px-4 py-8 sm:max-h-[95%] sm:!rounded-[32px] sm:px-8 sm:py-12 md:max-w-[1280px]'
|
||||
>
|
||||
<DialogTitle className={'sr-only'}></DialogTitle>
|
||||
<div className={'ml-6 sm:ml-0'}>
|
||||
<div className={'text-4xl font-bold text-[#0F2C53] md:mb-4 md:text-center md:text-5xl'}>
|
||||
<div className={'text-4xl font-bold text-[#0F2C53] md:mb-1 md:text-center'}>
|
||||
{t('selectPlan')}
|
||||
</div>
|
||||
<div className={'text-lg font-medium text-[#666666] md:text-center'}>
|
||||
<div className={'text-base font-medium text-[#666666] md:text-center'}>
|
||||
{t('selectYourPlan')}
|
||||
</div>
|
||||
</div>
|
||||
@ -80,6 +81,6 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default OfferDialog;
|
||||
|
||||
@ -5,7 +5,7 @@ import PlanTabs, { TabValueType } from '@/components/SubscribePlan/PlanTabs/Plan
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { preCreateOrder, purchase } from '@/services/user/order';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@ -164,14 +164,10 @@ const Purchase = forwardRef<PurchaseDialogRef, PurchaseProps>((props, ref) => {
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-8 flex items-center justify-center'>
|
||||
<Button
|
||||
className='w-[150px] rounded-full border-[#A8D4ED] bg-[#A8D4ED] text-xl hover:bg-[#225BA9] hover:text-white'
|
||||
disabled={loading}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<AiroButton variant={'primary'} disabled={loading} onClick={handleSubmit}>
|
||||
{loading && <LoaderCircle className='mr-2 animate-spin' />}
|
||||
{t('buyNow')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@ -6,7 +6,6 @@ import useGlobalStore from '@/config/use-global';
|
||||
import { preCreateOrder, renewal } from '@/services/user/order';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { AiroButton } from '@workspace/airo-ui/components/AiroButton';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@ -103,9 +102,9 @@ export default function Renewal({ id, subscribe, className }: Readonly<RenewalPr
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size='sm' className={className}>
|
||||
<AiroButton variant={'primaryBlue'} className={'px-2 text-xs'}>
|
||||
{t('renewPlan')}
|
||||
</Button>
|
||||
</AiroButton>
|
||||
</DialogTrigger>
|
||||
<DialogContent className='flex h-full flex-col md:h-auto'>
|
||||
<DialogHeader>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"annualPackage": "Annual Package",
|
||||
"commissionCalculation": "Commission Calculation",
|
||||
"commissionCalculationInfo": "Fill in the corresponding number of invited users below to calculate the commission amount at different ratios. *This table is calculated based on the Pro Plan. The ratios for other plans remain unchanged, and the calculation is based on the actual amount.",
|
||||
"commissionCalculationInfo": "Fill in the corresponding number of invited users below to calculate the commission amount at different ratios. \n *This table is calculated based on the Pro Plan. The ratios for other plans remain unchanged, and the calculation is based on the actual amount.",
|
||||
"commissionInfo": "Commission amount, which is automatically transferred to the wallet balance after a successful invitation.",
|
||||
"commissionInviteCode": "Commission Invite Code",
|
||||
"commissionRate": "Commission Rate",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"annualPackage": "年付套餐",
|
||||
"commissionCalculation": "佣金计算",
|
||||
"commissionCalculationInfo": "在下方填入对应邀请用户数量,即可计算不同比例返佣金额 *该表以Pro Plan计算,其它套餐比例不变,以实际金额计算为准",
|
||||
"commissionCalculationInfo": "在下方填入对应邀请用户数量,即可计算不同比例返佣金额 \n *该表以Pro Plan计算,其它套餐比例不变,以实际金额计算为准",
|
||||
"commissionInfo": "佣金金额,邀请成功后自动转入钱包余额",
|
||||
"commissionInviteCode": "返佣邀请码",
|
||||
"commissionRate": "佣金比例",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
import baseConfig from '@workspace/airo-ui/tailwind.config';
|
||||
|
||||
baseConfig.theme.extend.boxShadow = {
|
||||
...baseConfig.theme.extend.boxShadow,
|
||||
...{
|
||||
input: 'inset 0 0 7.6px 0 rgba(0, 0, 0, 0.25) ',
|
||||
},
|
||||
};
|
||||
const config = {
|
||||
...baseConfig,
|
||||
darkMode: false, // 或 'media' 或 'class',根据你的需求覆盖
|
||||
|
||||
@ -13,6 +13,7 @@ const buttonVariants = cva(
|
||||
primary: 'bg-[#225BA9] text-primary-foreground shadow hover:bg-[#0F2C53] ',
|
||||
danger: 'bg-[#FF4248] text-primary-foreground shadow hover:bg-[#E22C2E]',
|
||||
dangerLink: 'text-[#E22C2E] ',
|
||||
primaryBlue: 'bg-[#A8D4ED] text-primary-foreground hover:bg-[#225BA9]',
|
||||
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
||||
|
||||
@ -5,7 +5,7 @@ import * as React from 'react';
|
||||
import { cn } from '@workspace/airo-ui/lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
@ -133,42 +133,44 @@ export function ProList<TData, TValue extends Record<string, unknown>>({
|
||||
|
||||
return (
|
||||
<div className='flex max-w-full flex-col gap-2 sm:gap-4'>
|
||||
<div className='flex flex-wrap-reverse items-center justify-between gap-4'>
|
||||
<div className={'w-full'}>
|
||||
{params ? (
|
||||
<div className='flex w-full justify-between'>
|
||||
<ColumnFilter
|
||||
table={table}
|
||||
params={params}
|
||||
filters={Object.fromEntries(columnFilters.map((item) => [item.id, item.value]))}
|
||||
/>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='h-8 w-8 rounded-full bg-[#D9D9D9] p-2 sm:hidden'
|
||||
onClick={fetchData}
|
||||
>
|
||||
<RefreshCcw className='h-4 w-4 text-[#848484]' />
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
header?.title
|
||||
)}
|
||||
{params || header ? (
|
||||
<div className='flex flex-wrap-reverse items-center justify-between gap-4'>
|
||||
<div className={'w-full'}>
|
||||
{params ? (
|
||||
<div className='flex w-full justify-between'>
|
||||
<ColumnFilter
|
||||
table={table}
|
||||
params={params}
|
||||
filters={Object.fromEntries(columnFilters.map((item) => [item.id, item.value]))}
|
||||
/>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='h-8 w-8 rounded-full bg-[#D9D9D9] p-2 sm:hidden'
|
||||
onClick={fetchData}
|
||||
>
|
||||
<RefreshCcw className='h-4 w-4 text-[#848484]' />
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
header?.title
|
||||
)}
|
||||
</div>
|
||||
<div className='flex flex-1 items-center justify-end gap-2'>
|
||||
{params && params?.length > 0 && (
|
||||
<>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='hidden h-8 w-8 rounded-full bg-[#D9D9D9] p-2 sm:block'
|
||||
onClick={fetchData}
|
||||
>
|
||||
<RefreshCcw className='h-4 w-4 text-[#848484]' />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{header?.toolbar}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-1 items-center justify-end gap-2'>
|
||||
{params && params?.length > 0 && (
|
||||
<>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='hidden h-8 w-8 rounded-full bg-[#D9D9D9] p-2 sm:block'
|
||||
onClick={fetchData}
|
||||
>
|
||||
<RefreshCcw className='h-4 w-4 text-[#848484]' />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{header?.toolbar}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{selectedCount > 0 && batchRender && (
|
||||
<Alert className='flex items-center justify-between'>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user