重构首页,优化组件结构

This commit is contained in:
2025-12-23 17:11:46 +08:00
parent 78d605749f
commit a3588fd1be
24 changed files with 305 additions and 268 deletions

View File

@@ -2,6 +2,10 @@
购买页固定套餐
不要余额
优惠问题
### 禁止直接依赖 form
`\[(.*,)?form(,.*)?\]`

View File

@@ -74,5 +74,5 @@
"typescript": "^5.9.3",
"babel-plugin-react-compiler": "^1.0.0"
},
"packageManager": "bun@1.2.19"
}
"packageManager": "bun@1.3.2"
}

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

View File

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 142 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 540 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -0,0 +1,50 @@
import Image, {StaticImageData} from 'next/image'
import {PageSection} from './page-section'
import s4_1_main from './_assets/s4-1-main.webp'
import s4_2_main from './_assets/s4-2-main.webp'
import s4_1_1 from './_assets/s4-1-1.webp'
import s4_1_2 from './_assets/s4-1-2.webp'
import s4_1_3 from './_assets/s4-1-3.webp'
import s4_2_1 from './_assets/s4-2-1.webp'
import s4_2_2 from './_assets/s4-2-2.webp'
import s4_2_3 from './_assets/s4-2-3.webp'
export function AdvantagesSection() {
return (
<PageSection title="HTTP 产品优势">
<div className="flex gap-36">
<ul className="flex-1 flex flex-col gap-6">
<AdvantageItem icon={s4_1_1} title="安全合规" description="国内三大运营商支持"/>
<AdvantageItem icon={s4_1_2} title="稳定链接" description="IP纯净度高达99.9%"/>
<AdvantageItem icon={s4_1_3} title="超匿名性" description="稳定传输,保护隐私安全"/>
</ul>
<Image src={s4_1_main} alt="产品优势展示" className="w-0 flex-1 object-contain max-lg:hidden"/>
</div>
<div className="flex gap-36">
<Image src={s4_2_main} alt="技术优势展示" className="w-0 flex-1 object-contain max-lg:hidden"/>
<ul className="flex-1 flex flex-col gap-6">
<AdvantageItem icon={s4_2_1} title="API接口文档" description="与第三方软件轻松集成"/>
<AdvantageItem icon={s4_2_2} title="多种编程语言代码" description="C语言、GO语言、Python..."/>
<AdvantageItem icon={s4_2_3} title="双重认证方式" description="API提取+账密认证"/>
</ul>
</div>
</PageSection>
)
}
function AdvantageItem(props: {
icon: StaticImageData
title: string
description: string
}) {
return (
<li className="flex gap-8 items-center p-4 lg:p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg">
<Image src={props.icon} alt={props.title} aria-hidden className="w-24 h-24 object-contain"/>
<div className="flex flex-col gap-3">
<h3 className="text-xl">{props.title}</h3>
<p>{props.description}</p>
</div>
</li>
)
}

View File

@@ -0,0 +1,70 @@
import {ReactNode} from 'react'
import Link from 'next/link'
import {PageSection} from './page-section'
import {BookOpen, Smartphone, HelpCircle} from 'lucide-react'
export function ArticlesSection() {
return (
<PageSection title="推荐文章">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<ArticleCard
icon={<BookOpen className="w-12 h-12"/>}
title="浏览器设置代理教程"
description="快速上手5分钟学会在浏览器中配置代理服务器"
href="/docs/browser-proxy"
/>
<ArticleCard
icon={<Smartphone className="w-12 h-12"/>}
title="Windows10 代理配置"
description="详细图文教程,帮助你在 Windows 系统中设置代理"
href="/docs/windows10-proxy"
/>
<ArticleCard
icon={<HelpCircle className="w-12 h-12"/>}
title="常见问题总览"
description="解决使用过程中遇到的各类问题,快速找到答案"
href="/docs/faq-general"
/>
</div>
</PageSection>
)
}
function ArticleCard(props: {
icon: ReactNode
title: string
description: string
href: string
}) {
return (
<Link
href={props.href}
className={[
`group block p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg bg-white`,
`transition-all duration-200`,
].join(' ')}
>
<div className="flex flex-col items-center text-center gap-6">
<div className="p-4 rounded-xl bg-linear-to-br from-blue-500 to-cyan-400 text-white group-hover:scale-110 transition-transform">
{props.icon}
</div>
<div>
<h3 className="text-xl font-semibold mb-3 group-hover:text-blue-600 transition-colors">
{props.title}
</h3>
<p className="text-gray-500 text-sm leading-relaxed">
{props.description}
</p>
</div>
<div className="mt-2 text-blue-500 text-sm flex items-center gap-2 group-hover:gap-3 transition-all">
<span></span>
<span className="text-lg"></span>
</div>
</div>
</Link>
)
}

View File

@@ -0,0 +1,37 @@
import Image from 'next/image'
import Wrap from '@/components/wrap'
import FreeTrial from '@/components/free-trial'
import banner from '../_assets/banner.webp'
import check_main from '@/assets/check-main.svg'
export function HeroSection() {
return (
<section className="w-full relative">
<Image src={banner} alt="banner" className="absolute inset-0 h-full object-cover"/>
<Wrap className="relative pt-64 pb-48 max-md:pt-32 max-md:pb-24">
<h1 className="text-4xl"></h1>
<p className="mt-10 text-gray-500">IP代理服务</p>
<div className="mt-24 max-md:mt-14 flex gap-8 max-md:flex-col">
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">200+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">300+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">&</span>
</p>
</div>
<FreeTrial className={[
`mt-32 max-md:mt-20 w-96 max-md:w-full h-16 md:h-24 rounded-lg shadow-lg`,
`bg-linear-to-r from-blue-500 to-cyan-400 text-white text-xl lg:text-4xl`,
].join(' ')}/>
</Wrap>
</section>
)
}

View File

@@ -0,0 +1,15 @@
import {ReactNode} from 'react'
export function PageSection(props: {
title: string
children: ReactNode
}) {
return (
<section>
<div className="max-w-[1232px] mx-auto px-4 flex flex-col items-stretch">
<h2 className="text-center text-3xl mb-8 lg:mb-24">{props.title}</h2>
{props.children}
</div>
</section>
)
}

View File

@@ -0,0 +1,17 @@
import {HeroSection} from './hero-section'
import {StatsSection} from './stats-section'
import {ProductTypesSection} from './product-types-section'
import {AdvantagesSection} from './advantages-section'
import {ArticlesSection} from './articles-section'
export default function Home() {
return (
<main className="flex flex-col gap-16 lg:gap-32 pb-16 lg:pb-32 bg-white">
<HeroSection/>
<StatsSection/>
<ProductTypesSection/>
<AdvantagesSection/>
<ArticlesSection/>
</main>
)
}

View File

@@ -0,0 +1,78 @@
import Image, {StaticImageData} from 'next/image'
import {PageSection} from './page-section'
import s1_1 from './_assets/s1-1.webp'
import s1_2 from './_assets/s1-2.webp'
import s1_3 from './_assets/s1-3.webp'
import s1_4 from './_assets/s1-4.webp'
import s1_check from './_assets/s1-check.svg'
export function ProductTypesSection() {
return (
<PageSection title="HTTP安全合规的代理IP资源池">
<ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<ProductTypeCard
icon={s1_1}
title="短期动态IP池"
features={[
{icon: s1_check, text: 'IP时效3-30分钟(可定制)'},
{icon: s1_check, text: '支持高并发提取'},
]}
/>
<ProductTypeCard
icon={s1_2}
title="长期静态IP池"
features={[
{icon: s1_check, text: 'IP覆盖全国各地'},
{icon: s1_check, text: '平均响应时长0.03s'},
]}
/>
<ProductTypeCard
icon={s1_3}
title="固定IP池"
features={[
{icon: s1_check, text: '稳定长输不掉线'},
{icon: s1_check, text: '全国热门静态IP线路'},
]}
/>
<ProductTypeCard
icon={s1_4}
title="企业级定制池"
features={[
{icon: s1_check, text: '可视化监控设计'},
{icon: s1_check, text: '技术团队现场支持'},
]}
/>
</ul>
</PageSection>
)
}
function ProductTypeCard(props: {
icon: StaticImageData
title: string
features: {
icon: StaticImageData
text: string
}[]
}) {
return (
<li
className={[
`p-8 flex flex-col gap-5 shadow-[4px_4px_20px_4px] shadow-blue-50 bg-white rounded-lg`,
`max-md:items-center`,
].join(' ')}>
<Image src={props.icon} alt={props.title} aria-hidden className="self-center w-44 h-44 object-cover"/>
<h3 className="text-xl">{props.title}</h3>
<div className="flex flex-col gap-3">
{props.features.map((item, index) => {
return (
<p key={index} className="text-sm text-gray-500 flex gap-3 items-center">
<Image src={item.icon} alt="check" aria-hidden className="w-5 h-5"/>
<span>{item.text}</span>
</p>
)
})}
</div>
</li>
)
}

View File

@@ -0,0 +1,32 @@
import Image from 'next/image'
import {PageSection} from './page-section'
import map from '../_assets/map.webp'
export function StatsSection() {
return (
<PageSection title="覆盖全国的IP资源及超大的带宽线路">
<ul className="shadow-[0_0_20px_4px] shadow-blue-50 p-8 flex max-lg:flex-col">
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">线</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">350+</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">IP数量</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">1,350,129</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl"></p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">26,578</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center">
<p className="text-xl">IP可用率</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">99%</p>
</li>
</ul>
<Image src={map} alt="map" className="w-[1200px]"/>
</PageSection>
)
}

View File

@@ -1,266 +0,0 @@
import {ReactNode} from 'react'
import Wrap from '@/components/wrap'
import Image, {StaticImageData} from 'next/image'
import Link from 'next/link'
import check_main from '@/assets/check-main.svg'
import banner from './_assets/banner.webp'
import map from './_assets/map.webp'
import s1_1 from './_assets/s1-1.webp'
import s1_2 from './_assets/s1-2.webp'
import s1_3 from './_assets/s1-3.webp'
import s1_4 from './_assets/s1-4.webp'
import s1_check from './_assets/s1-check.svg'
import s4_1_main from './_assets/s4-1-main.webp'
import s4_2_main from './_assets/s4-2-main.webp'
import s4_1_1 from './_assets/s4-1-1.webp'
import s4_1_2 from './_assets/s4-1-2.webp'
import s4_1_3 from './_assets/s4-1-3.webp'
import s4_2_1 from './_assets/s4-2-1.webp'
import s4_2_2 from './_assets/s4-2-2.webp'
import s4_2_3 from './_assets/s4-2-3.webp'
import FreeTrial from '@/components/free-trial'
import {BookOpen, Smartphone, Settings, HelpCircle, Newspaper, FileText} from 'lucide-react'
export default function Home() {
return (
<main className="flex flex-col gap-16 lg:gap-32 pb-16 lg:pb-32 bg-white">
{/* banner */}
<section className="w-full relative">
<Image src={banner} alt="banner" className="absolute inset-0 h-full object-cover"/>
<Wrap className="relative pt-64 pb-48 max-md:pt-32 max-md:pb-24">
<h1 className="text-4xl"></h1>
<p className="mt-10 text-gray-500">IP代理服务</p>
<div className="mt-24 max-md:mt-14 flex gap-8 max-md:flex-col">
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>200+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>300+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>&</span>
</p>
</div>
<FreeTrial className={[
`mt-32 max-md:mt-20 w-96 max-md:w-full h-16 md:h-24 rounded-lg shadow-lg`,
`bg-linear-to-r from-blue-500 to-cyan-400 text-white text-xl lg:text-4xl`,
].join(' ')}/>
</Wrap>
</section>
{/* 数据展示 */}
<Section title="覆盖全国的IP资源及超大的带宽线路">
<ul className="shadow-[0_0_20px_4px] shadow-blue-50 p-8 flex max-lg:flex-col">
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">线</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">350+</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">IP数量</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">1,350,129</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl"></p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">26,578</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center">
<p className="text-xl">IP可用率</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">99%</p>
</li>
</ul>
<Image src={map} alt="map" className="w-[1200px]"/>
</Section>
{/* 优势 1 */}
<Section title="HTTP安全合规的代理IP资源池">
<ul
className={[
`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8`,
].join(' ')}>
<Sec3Item
icon={s1_1}
title="短期动态IP池"
terms={[
{icon: s1_check, text: `IP时效3-30分钟(可定制)`},
{icon: s1_check, text: `支持高并发提取`},
]}/>
<Sec3Item
icon={s1_2}
title="长期静态IP池"
terms={[
{icon: s1_check, text: `IP覆盖全国各地`},
{icon: s1_check, text: `平均响应时长0.03s`},
]}/>
<Sec3Item
icon={s1_3}
title="固定IP池"
terms={[
{icon: s1_check, text: `稳定长输不掉线`},
{icon: s1_check, text: `全国热门静态IP线路`},
]}/>
<Sec3Item
icon={s1_4}
title="企业级定制池"
terms={[
{icon: s1_check, text: `可视化监控设计`},
{icon: s1_check, text: `技术团队现场支持`},
]}/>
</ul>
</Section>
{/* 优势 2 */}
<Section title="HTTP 产品优势">
<div className="flex gap-36">
<ul className="flex-1 flex flex-col gap-6">
<Sec4Item icon={s4_1_1} title="安全合规" description="国内三大运营商支持"/>
<Sec4Item icon={s4_1_2} title="稳定链接" description="IP纯净度高达99.9%"/>
<Sec4Item icon={s4_1_3} title="超匿名性" description="稳定传输,保护隐私安全"/>
</ul>
<Image src={s4_1_main} alt="s2-1-main" className="w-0 flex-1 object-contain max-lg:hidden"/>
</div>
<div className="flex gap-36">
<Image src={s4_2_main} alt="s2-1-main" className="w-0 flex-1 object-contain max-lg:hidden"/>
<ul className="flex-1 flex flex-col gap-6">
<Sec4Item icon={s4_2_1} title="API接口文档" description="与第三方软件轻松集成"/>
<Sec4Item icon={s4_2_2} title="多种编程语言代码" description="C语言、GO语言、Python..."/>
<Sec4Item icon={s4_2_3} title="双重认证方式" description="API提取+账密认证"/>
</ul>
</div>
</Section>
{/* 推荐文章 */}
<Section title="推荐文章">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<ArticleCard
icon={<BookOpen className="w-12 h-12"/>}
title="浏览器设置代理教程"
description="快速上手5分钟学会在浏览器中配置代理服务器"
href="/docs/browser-proxy"
/>
<ArticleCard
icon={<Smartphone className="w-12 h-12"/>}
title="Windows10 代理配置"
description="详细图文教程,帮助你在 Windows 系统中设置代理"
href="/docs/windows10-proxy"
/>
<ArticleCard
icon={<HelpCircle className="w-12 h-12"/>}
title="常见问题总览"
description="解决使用过程中遇到的各类问题,快速找到答案"
href="/docs/faq-general"
/>
</div>
</Section>
</main>
)
}
function Section(props: {
title: string
children: ReactNode
}) {
return (
<section>
<div className="max-w-[1232px] mx-auto px-4 flex flex-col items-stretch">
<h2 className="text-center text-3xl mb-8 lg:mb-24">{props.title}</h2>
{props.children}
</div>
</section>
)
}
function Sec3Item(props: {
icon: StaticImageData
title: string
terms: {
icon: StaticImageData
text: string
}[]
}) {
return (
<li
className={[
`p-8 flex flex-col gap-5 shadow-[4px_4px_20px_4px] shadow-blue-50 bg-white rounded-lg`,
`max-md:items-center`,
].join(' ')}>
<Image src={props.icon} alt="s1-1" aria-hidden className="self-center w-44 h-44 object-cover"/>
<h3 className="text-xl">{props.title}</h3>
<div className="flex flex-col gap-3">
{props.terms.map((item, index) => {
return (
<p key={index} className="text-sm text-gray-500 flex gap-3 items-center">
<Image src={item.icon} alt="check" aria-hidden className="w-5 h-5"/>
<span>{item.text}</span>
</p>
)
})}
</div>
</li>
)
}
function ArticleCard(props: {
icon: ReactNode
title: string
description: string
href: string
}) {
return (
<Link
href={props.href}
className={[
`group block p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg bg-white`,
`transition-all duration-200`,
].join(' ')}
>
<div className="flex flex-col items-center text-center gap-6">
<div className="p-4 rounded-xl bg-linear-to-br from-blue-500 to-cyan-400 text-white group-hover:scale-110 transition-transform">
{props.icon}
</div>
<div>
<h3 className="text-xl font-semibold mb-3 group-hover:text-blue-600 transition-colors">
{props.title}
</h3>
<p className="text-gray-500 text-sm leading-relaxed">
{props.description}
</p>
</div>
<div className="mt-2 text-blue-500 text-sm flex items-center gap-2 group-hover:gap-3 transition-all">
<span></span>
<span className="text-lg"></span>
</div>
</div>
</Link>
)
}
function Sec4Item(props: {
icon: StaticImageData
title: string
description: string
}) {
return (
<li className="flex gap-8 items-center p-4 lg:p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg">
<Image src={props.icon} alt="s2-1-1" aria-hidden className="w-24 h-24 object-contain"/>
<div className="flex flex-col gap-3">
<h3 className="text-xl">{props.title}</h3>
<p>{props.description}</p>
</div>
</li>
)
}