feat: 修改文案大小

This commit is contained in:
2025-08-16 09:38:50 -07:00
parent 9cde4cb0a1
commit bf8c01048c
32 changed files with 218 additions and 243 deletions
+3 -3
View File
@@ -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>
+12 -12
View File
@@ -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'}
+3 -13
View File
@@ -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>
);
}
+20 -19
View File
@@ -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;
+3 -7
View File
@@ -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>
+2 -3
View File
@@ -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>