完善页头页尾
67
src/app/(root)/@header/_client/help.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import Link from "next/link"
|
||||||
|
import Image from "next/image"
|
||||||
|
import Wrap from "@/components/wrap"
|
||||||
|
import h01 from '@/assets/header/help/01.svg'
|
||||||
|
import h02 from '@/assets/header/help/02.svg'
|
||||||
|
import h03 from '@/assets/header/help/03.svg'
|
||||||
|
import banner from '@/assets/header/help/banner.webp'
|
||||||
|
|
||||||
|
export default function HelpMenu() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrap className="w-full grid grid-cols-4 gap-4 justify-items-center">
|
||||||
|
<Column
|
||||||
|
icon={h01}
|
||||||
|
title="提取IP"
|
||||||
|
items={[
|
||||||
|
{ lead: '短效动态IP提取', href: '#' },
|
||||||
|
{ lead: '长效静态IP提取', href: '#' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
icon={h02}
|
||||||
|
title="使用教程"
|
||||||
|
items={[
|
||||||
|
{ lead: '快速入手', href: '#' },
|
||||||
|
{ lead: '代码下载', href: '#' },
|
||||||
|
{ lead: 'API文档', href: '#' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
icon={h03}
|
||||||
|
title="产品功能"
|
||||||
|
items={[
|
||||||
|
{ lead: '常见问题', href: '#' },
|
||||||
|
{ lead: '产品介绍', href: '#' },
|
||||||
|
{ lead: '行业资讯', href: '#' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Image src={banner} alt={`banner`} className={``} />
|
||||||
|
</Wrap>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Column(props: {
|
||||||
|
icon: any
|
||||||
|
title: string
|
||||||
|
items: {
|
||||||
|
lead: string
|
||||||
|
href: string
|
||||||
|
}[]
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<h3 className="font-bold flex gap-3 items-center">
|
||||||
|
<Image src={props.icon} alt={props.title} className="w-10 h-10" />
|
||||||
|
<span>{props.title}</span>
|
||||||
|
</h3>
|
||||||
|
<ul className=" text-gray-500 text-sm flex flex-col items-end gap-2">
|
||||||
|
{props.items.map((item, index) => (
|
||||||
|
<li key={index}><Link href={item.href}>{item.lead}</Link></li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
127
src/app/(root)/@header/_client/product.tsx
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, ReactNode } from "react"
|
||||||
|
import Wrap from "@/components/wrap"
|
||||||
|
import Image from "next/image"
|
||||||
|
import prod from '@/assets/header/product/prod.svg'
|
||||||
|
import custom from '@/assets/header/product/custom.svg'
|
||||||
|
import anno from '@/assets/header/product/anno.svg'
|
||||||
|
|
||||||
|
type TabType = 'domestic' | 'oversea'
|
||||||
|
|
||||||
|
export default function ProductMenu() {
|
||||||
|
|
||||||
|
const [type, setType] = useState<TabType>('domestic')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrap className="flex">
|
||||||
|
<ul role="tablist" className="w-48">
|
||||||
|
<Tab selected={type === 'domestic'} onSelect={() => setType('domestic')}>国内代理</Tab>
|
||||||
|
<Tab selected={type === 'oversea'} onSelect={() => setType('oversea')}>海外代理</Tab>
|
||||||
|
</ul>
|
||||||
|
<div className="flex-1">
|
||||||
|
{type === 'domestic'
|
||||||
|
? (
|
||||||
|
<section role="tabpanel" className="flex gap-16 mr-16">
|
||||||
|
<div className="w-64 flex flex-col gap-6">
|
||||||
|
<h3 className="font-bold mb-2 flex items-center gap-3">
|
||||||
|
<Image src={prod} alt={`产品`} className={`w-10 h-=10`} />
|
||||||
|
<span>代理产品</span>
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<p className="flex gap-2">
|
||||||
|
<span>短效动态IP</span>
|
||||||
|
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
||||||
|
折扣45%
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-400 text-sm">
|
||||||
|
全国300+城市级定位节点
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<p className="flex gap-2">
|
||||||
|
<span>长效静态IP</span>
|
||||||
|
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
||||||
|
折扣45%
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-400 text-sm">
|
||||||
|
IPI资源覆盖全国
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="flex gap-2">
|
||||||
|
<span>固定IP</span>
|
||||||
|
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
||||||
|
折扣45%
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-64 flex flex-col gap-4">
|
||||||
|
<h3 className="font-bold mb-2 flex items-center gap-3">
|
||||||
|
<Image src={custom} alt="定制" className="w-10 h-10" />
|
||||||
|
<span>业务定制</span>
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<p>优质/企业/精选IP</p>
|
||||||
|
<p className="text-gray-400 text-sm">
|
||||||
|
超 1000 家企业共同信赖之选!大客户经理全
|
||||||
|
程 1 对 1 沟通,随时为您排忧解难,提供 24
|
||||||
|
小时不间断支持
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
) : (
|
||||||
|
<section role="tabpanel">
|
||||||
|
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<aside className="w-64">
|
||||||
|
<h3 className="flex gap-3 items-center mb-4">
|
||||||
|
<Image src={anno} alt={`公告`} className={`w-10 h-10`} />
|
||||||
|
<span>网站公告</span>
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<p>官网最新上线,体验再升级!</p>
|
||||||
|
<p className="text-gray-400 text-sm">
|
||||||
|
1.新增多样使用功能,新增多样使用
|
||||||
|
新增多样使用功能
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-400 text-sm">
|
||||||
|
2.新增多样使用功能,新增多样使用
|
||||||
|
新增多样使用功能
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</Wrap>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Tab(props: {
|
||||||
|
selected: boolean
|
||||||
|
onSelect: () => void
|
||||||
|
children: ReactNode
|
||||||
|
}) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li role="tab">
|
||||||
|
<button
|
||||||
|
className={[
|
||||||
|
`p-8 text-lg cursor-pointer border-r`,
|
||||||
|
props.selected ? `bg-gradient-to-r from-transparent to-blue-200 border-blue-400` : `border-gray-200`,
|
||||||
|
].join(' ')}
|
||||||
|
onClick={props.onSelect}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
79
src/app/(root)/@header/_client/solution.tsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import Image from "next/image"
|
||||||
|
import Wrap from "@/components/wrap"
|
||||||
|
import s01 from "@/assets/header/solution/01.svg"
|
||||||
|
import s02 from "@/assets/header/solution/02.svg"
|
||||||
|
import s03 from "@/assets/header/solution/03.svg"
|
||||||
|
import s04 from "@/assets/header/solution/04.svg"
|
||||||
|
import s05 from "@/assets/header/solution/05.svg"
|
||||||
|
import s06 from "@/assets/header/solution/06.svg"
|
||||||
|
import s07 from "@/assets/header/solution/07.svg"
|
||||||
|
import s08 from "@/assets/header/solution/08.svg"
|
||||||
|
|
||||||
|
export default function SolutionMenu() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrap className="grid grid-cols-4 auto-rows-fr gap-4">
|
||||||
|
<SolutionItem
|
||||||
|
icon={s01}
|
||||||
|
title="数据抓取"
|
||||||
|
desc="高效采集和分析大量数据,助力企业获取大量情报"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s02}
|
||||||
|
title="广告验证"
|
||||||
|
desc="确保广告点击和展示数据的真实性,帮助企业,提升广告效果"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s03}
|
||||||
|
title="市场调查"
|
||||||
|
desc="收集全网行业数据,了解竞争对手动态"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s04}
|
||||||
|
title="SEO优化"
|
||||||
|
desc="收集搜索引擎情报,提高网站在搜索引擎的排名"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s05}
|
||||||
|
title="品牌保护"
|
||||||
|
desc="保护品牌商标打造,优质品牌形象,为企业获得更多用户"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s06}
|
||||||
|
title="价格监控"
|
||||||
|
desc="利用优质代理IP,实时监控行业价格信息,提高市场竞争力"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s07}
|
||||||
|
title="金融数据"
|
||||||
|
desc="快速获取金融市场实时数据,帮助投资者分析趋势,使其做出精准决策"
|
||||||
|
/>
|
||||||
|
<SolutionItem
|
||||||
|
icon={s08}
|
||||||
|
title="网站测试"
|
||||||
|
desc="在不同环境下对网站进行性能和兼容的测试,让用户有高质量体验"
|
||||||
|
/>
|
||||||
|
</Wrap>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SolutionItem(props: {
|
||||||
|
icon: any
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={[
|
||||||
|
`h-full p-4 flex gap-4 items-start rounded-md cursor-pointer`,
|
||||||
|
`transition-colors duration-200 hover:bg-blue-100`,
|
||||||
|
].join(' ')}
|
||||||
|
>
|
||||||
|
<Image src={props.icon} alt={props.title} className="w-10 h-10" />
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<h3 className="font-bold">{props.title}</h3>
|
||||||
|
<p className="text-gray-400 text-sm">{props.desc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
72
src/app/(root)/@header/_server/navs.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import Image from "next/image"
|
||||||
|
import Link from "next/link"
|
||||||
|
import down from "@/assets/header/down.svg"
|
||||||
|
|
||||||
|
export function LinkItem(props: {
|
||||||
|
text: string
|
||||||
|
href: string
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<li className={`group relative`}>
|
||||||
|
<Link
|
||||||
|
href={props.href}
|
||||||
|
className={[
|
||||||
|
`h-full px-4 flex items-center text-lg`,
|
||||||
|
`transition-colors duration-200 ease-in-out`,
|
||||||
|
`hover:text-blue-500`,
|
||||||
|
].join(' ')}
|
||||||
|
>
|
||||||
|
{props.text}
|
||||||
|
</Link>
|
||||||
|
<div className={[
|
||||||
|
`absolute bottom-0 w-full h-0.5 bg-transparent `,
|
||||||
|
`transition-colors duration-200`,
|
||||||
|
`group-hover:bg-blue-500`,
|
||||||
|
].join(' ')}>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MenuItem(props: {
|
||||||
|
text: string
|
||||||
|
active: boolean
|
||||||
|
onEnter: () => void
|
||||||
|
onLeave: () => void
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<li className={`group relative`}>
|
||||||
|
<button
|
||||||
|
onPointerEnter={props.onEnter}
|
||||||
|
onPointerLeave={props.onLeave}
|
||||||
|
className={[
|
||||||
|
`h-full px-4 flex gap-3 items-center cursor-pointer text-lg`,
|
||||||
|
`transition-colors duration-200 ease-in-out`,
|
||||||
|
props.active
|
||||||
|
? `text-blue-500`
|
||||||
|
: ``,
|
||||||
|
].join(' ')}
|
||||||
|
>
|
||||||
|
<span>{props.text}</span>
|
||||||
|
<Image
|
||||||
|
src={down}
|
||||||
|
alt={`drop_menu`}
|
||||||
|
className={[
|
||||||
|
`transition-transform duration-200 ease-in-out`,
|
||||||
|
props.active
|
||||||
|
? `rotate-180`
|
||||||
|
: ``,
|
||||||
|
].join(' ')}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className={[
|
||||||
|
`absolute bottom-0 w-full h-0.5 pointer-events-none`,
|
||||||
|
`transition-colors duration-200`,
|
||||||
|
props.active
|
||||||
|
? `bg-blue-500`
|
||||||
|
: 'bg-transparent',
|
||||||
|
].join(' ')} />
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
155
src/app/(root)/@header/page.tsx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
'use client'
|
||||||
|
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { LinkItem, MenuItem } from './_server/navs'
|
||||||
|
import SolutionMenu from './_client/solution'
|
||||||
|
import ProductMenu from './_client/product'
|
||||||
|
import HelpMenu from './_client/help'
|
||||||
|
import Wrap from '@/components/wrap'
|
||||||
|
import logo from '@/assets/logo.png'
|
||||||
|
|
||||||
|
export type HeaderProps = {}
|
||||||
|
|
||||||
|
export default function Header(props: HeaderProps) {
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// 滚动条状态
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
const [scroll, setScroll] = useState(false) // Changed to false for client-side rendering
|
||||||
|
|
||||||
|
const handleScroll = useCallback(() => {
|
||||||
|
setScroll(window.scrollY > 48)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Initialize scroll state on client
|
||||||
|
setScroll(window.scrollY > 48)
|
||||||
|
window.addEventListener('scroll', handleScroll)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', handleScroll)
|
||||||
|
}
|
||||||
|
}, [handleScroll])
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// 菜单状态
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
const [menu, setMenu] = useState(false)
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
const pages = useMemo(() => [
|
||||||
|
<ProductMenu key={`product`} />,
|
||||||
|
<SolutionMenu key={`solution`} />,
|
||||||
|
<HelpMenu key={`help`} />,
|
||||||
|
], [])
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// 渲染组件
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className={[
|
||||||
|
`fixed top-0 w-full z-10`,
|
||||||
|
].join(' ')}>
|
||||||
|
<div className={[
|
||||||
|
``,
|
||||||
|
`transition-[background, shadow] duration-200 ease-in-out`,
|
||||||
|
menu
|
||||||
|
? `bg-[#fffe] backdrop-blur-sm`
|
||||||
|
: scroll
|
||||||
|
? `bg-[#fffe] backdrop-blur-sm shadow-lg`
|
||||||
|
: `bg-transparent shadow-none`,
|
||||||
|
].join(' ')}>
|
||||||
|
<Wrap className="h-20 max-md:h-16 flex justify-between">
|
||||||
|
<div className="flex justify-between gap-8">
|
||||||
|
{/* logo */}
|
||||||
|
<Link href="/public" className={`flex items-center`}>
|
||||||
|
<Image src={logo} alt={`logo`} className={`w-16 max-md:w-12 h-16 max-md:h-12 rounded-full`} />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* 菜单 */}
|
||||||
|
<nav>
|
||||||
|
<ul className="h-full flex items-stretch max-lg:hidden">
|
||||||
|
<LinkItem text={`首页`} href={`/`} />
|
||||||
|
<MenuItem
|
||||||
|
text={`产品订购`}
|
||||||
|
active={menu && page === 0}
|
||||||
|
onEnter={() => {
|
||||||
|
setMenu(true)
|
||||||
|
setPage(0)
|
||||||
|
}}
|
||||||
|
onLeave={() => {
|
||||||
|
return setMenu(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
text={`业务场景`}
|
||||||
|
active={menu && page === 1}
|
||||||
|
onEnter={() => {
|
||||||
|
setMenu(true)
|
||||||
|
setPage(1)
|
||||||
|
}}
|
||||||
|
onLeave={() => {
|
||||||
|
return setMenu(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
text={`帮助中心`}
|
||||||
|
active={menu && page === 2}
|
||||||
|
onEnter={() => {
|
||||||
|
setMenu(true)
|
||||||
|
setPage(2)
|
||||||
|
}}
|
||||||
|
onLeave={() => {
|
||||||
|
return setMenu(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<LinkItem
|
||||||
|
text={`企业服务`} href={`#`} />
|
||||||
|
<LinkItem
|
||||||
|
text={`推广返利`} href={`#`} />
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{/* 登录 */}
|
||||||
|
<div className={`flex items-center`}>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
className={`w-24 h-12 flex items-center justify-center lg:text-lg font-medium`}
|
||||||
|
>
|
||||||
|
<span>登录</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
className={`w-20 lg:w-24 h-10 lg:h-12 bg-gradient-to-r from-blue-500 to-cyan-400 rounded-sm flex items-center justify-center lg:text-lg font-medium text-white`}
|
||||||
|
>
|
||||||
|
<span>注册</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Wrap>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 下拉菜单 */}
|
||||||
|
<div
|
||||||
|
className={[
|
||||||
|
`shadow-lg`,
|
||||||
|
`overflow-hidden bg-[#fffe] backdrop-blur-sm`,
|
||||||
|
`transition-[opacity,padding,height] transition-discrete duration-200 ease-in-out`,
|
||||||
|
menu
|
||||||
|
? `delay-[0s,0s,0s] opacity-100 py-8 h-auto`
|
||||||
|
: `delay-[0s,0s,0.2s] opacity-0 py-0 h-0`,
|
||||||
|
].join(' ')}
|
||||||
|
onPointerEnter={() => setMenu(true)}
|
||||||
|
onPointerLeave={() => setMenu(false)}
|
||||||
|
>
|
||||||
|
{pages[page]}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import {ReactNode, useCallback, useEffect, useMemo, useState} from 'react'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import Wrap from '@/components/wrap'
|
|
||||||
|
|
||||||
export type HeaderProps = {}
|
|
||||||
|
|
||||||
export default function Header(props: HeaderProps) {
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// 滚动条状态
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
const [scroll, setScroll] = useState(false) // Changed to false for client-side rendering
|
|
||||||
|
|
||||||
const handleScroll = useCallback(() => {
|
|
||||||
setScroll(window.scrollY > 48)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Initialize scroll state on client
|
|
||||||
setScroll(window.scrollY > 48)
|
|
||||||
window.addEventListener('scroll', handleScroll)
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('scroll', handleScroll)
|
|
||||||
}
|
|
||||||
}, [handleScroll])
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// 菜单状态
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
const [menu, setMenu] = useState(false)
|
|
||||||
const [page, setPage] = useState(0)
|
|
||||||
const pages = useMemo(() => [
|
|
||||||
<ProductMenu key={`product`}/>,
|
|
||||||
<SolutionMenu key={`solution`}/>,
|
|
||||||
<HelpMenu key={`help`}/>,
|
|
||||||
], [])
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// 覆盖状态
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
const [overlay, setOverlay] = useState(false)
|
|
||||||
useEffect(() => {
|
|
||||||
setOverlay(scroll || menu)
|
|
||||||
}, [menu, scroll])
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// 渲染组件
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
const LinkItem = (props: {
|
|
||||||
text: string
|
|
||||||
href: string
|
|
||||||
}) => (
|
|
||||||
<li className={`group relative`}>
|
|
||||||
<Link
|
|
||||||
href={props.href}
|
|
||||||
className={[
|
|
||||||
`h-full px-4 flex items-center text-lg`,
|
|
||||||
`transition-colors duration-200 ease-in-out`,
|
|
||||||
`hover:text-blue-500`,
|
|
||||||
].join(' ')}
|
|
||||||
>
|
|
||||||
{props.text}
|
|
||||||
</Link>
|
|
||||||
<div className={[
|
|
||||||
`absolute bottom-0 w-full h-0.5 bg-transparent `,
|
|
||||||
`transition-colors duration-200`,
|
|
||||||
`group-hover:bg-blue-500`,
|
|
||||||
].join(' ')}>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
|
|
||||||
const MenuItem = (props: {
|
|
||||||
text: string
|
|
||||||
page: number
|
|
||||||
}) => (
|
|
||||||
<li className={`group relative`}>
|
|
||||||
<button
|
|
||||||
onPointerEnter={() => {
|
|
||||||
setMenu(true)
|
|
||||||
setPage(props.page)
|
|
||||||
}}
|
|
||||||
onPointerLeave={() => {
|
|
||||||
setMenu(false)
|
|
||||||
}}
|
|
||||||
className={[
|
|
||||||
`h-full px-4 flex gap-3 items-center cursor-pointer text-lg`,
|
|
||||||
`transition-colors duration-200 ease-in-out`,
|
|
||||||
menu && page === props.page
|
|
||||||
? `text-blue-500`
|
|
||||||
: ``,
|
|
||||||
].join(' ')}
|
|
||||||
>
|
|
||||||
<span>{props.text}</span>
|
|
||||||
<img
|
|
||||||
src={`/header/down.svg`}
|
|
||||||
alt={`drop_menu`}
|
|
||||||
className={[
|
|
||||||
`transition-transform duration-200 ease-in-out`,
|
|
||||||
menu && page === props.page
|
|
||||||
? `rotate-180`
|
|
||||||
: ``,
|
|
||||||
].join(' ')}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<div className={[
|
|
||||||
`absolute bottom-0 w-full h-0.5 bg-transparent pointer-events-none`,
|
|
||||||
`transition-colors duration-200`,
|
|
||||||
menu && page === props.page ? `bg-blue-500` : '',
|
|
||||||
].join(' ')}>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className={[
|
|
||||||
`fixed top-0 w-full z-10`,
|
|
||||||
].join(' ')}>
|
|
||||||
<div className={[
|
|
||||||
``,
|
|
||||||
`transition-[background, shadow] duration-200 ease-in-out`,
|
|
||||||
menu
|
|
||||||
? `bg-[#fffe] backdrop-blur-sm`
|
|
||||||
: scroll
|
|
||||||
? `bg-[#fffe] backdrop-blur-sm shadow-lg`
|
|
||||||
: `bg-transparent shadow-none`,
|
|
||||||
].join(' ')}>
|
|
||||||
<Wrap className="h-20 max-md:h-16 flex justify-between">
|
|
||||||
<div className="flex justify-between gap-8">
|
|
||||||
{/* logo */}
|
|
||||||
<Link href="/public" className={`flex items-center`}>
|
|
||||||
<img src={`/logo.svg`} alt={`logo`} className={`w-16 max-md:w-12 h-16 max-md:h-12 rounded-full bg-gray-100`}/>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{/* 菜单 */}
|
|
||||||
<nav>
|
|
||||||
<ul className="h-full flex items-stretch max-lg:hidden">
|
|
||||||
<LinkItem text={`首页`} href={`/`}/>
|
|
||||||
<MenuItem text={`产品订购`} page={0}/>
|
|
||||||
<MenuItem text={`业务场景`} page={1}/>
|
|
||||||
<MenuItem text={`帮助中心`} page={2}/>
|
|
||||||
<LinkItem text={`企业服务`} href={`#`}/>
|
|
||||||
<LinkItem text={`推广返利`} href={`#`}/>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
{/* 登录 */}
|
|
||||||
<div className={`flex items-center`}>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className={`w-24 h-12 flex items-center justify-center lg:text-lg font-medium`}
|
|
||||||
>
|
|
||||||
<span>登录</span>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className={`w-20 lg:w-24 h-10 lg:h-12 bg-gradient-to-r from-blue-500 to-cyan-400 rounded-sm flex items-center justify-center lg:text-lg font-medium text-white`}
|
|
||||||
>
|
|
||||||
<span>注册</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Wrap>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 下拉菜单 */}
|
|
||||||
<div
|
|
||||||
className={[
|
|
||||||
`shadow-lg`,
|
|
||||||
`overflow-hidden bg-[#fffe] backdrop-blur-sm`,
|
|
||||||
`transition-[opacity,padding,height] transition-discrete duration-200 ease-in-out`,
|
|
||||||
menu
|
|
||||||
? `delay-[0s,0s,0s] opacity-100 py-8 h-auto`
|
|
||||||
: `delay-[0s,0s,0.2s] opacity-0 py-0 h-0`,
|
|
||||||
].join(' ')}
|
|
||||||
onPointerEnter={() => setMenu(true)}
|
|
||||||
onPointerLeave={() => setMenu(false)}
|
|
||||||
>
|
|
||||||
{pages[page]}
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProductMenu() {
|
|
||||||
|
|
||||||
// ====================
|
|
||||||
// Tab 选项
|
|
||||||
// ====================
|
|
||||||
|
|
||||||
type TabType = 'domestic' | 'oversea'
|
|
||||||
const [type, setType] = useState<TabType>('domestic')
|
|
||||||
|
|
||||||
const Tab = (props: {
|
|
||||||
type: TabType,
|
|
||||||
children: ReactNode
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<li role="tab">
|
|
||||||
<button
|
|
||||||
className={[
|
|
||||||
`p-8 text-lg cursor-pointer border-r`,
|
|
||||||
type === props.type ? `bg-gradient-to-r from-transparent to-blue-200 border-blue-400` : `border-gray-200`,
|
|
||||||
].join(' ')}
|
|
||||||
onClick={() => setType(props.type)}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================
|
|
||||||
// 渲染组件
|
|
||||||
// ====================
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Wrap className="flex">
|
|
||||||
<ul role="tablist" className="w-48">
|
|
||||||
<Tab type="domestic">国内代理</Tab>
|
|
||||||
<Tab type="oversea">海外代理</Tab>
|
|
||||||
</ul>
|
|
||||||
<div className="flex-1">
|
|
||||||
{type === 'domestic'
|
|
||||||
? (
|
|
||||||
<section role="tabpanel" className="flex gap-16 mr-16">
|
|
||||||
<div className="w-64 flex flex-col gap-6">
|
|
||||||
<h3 className="font-bold mb-2 flex items-center gap-3">
|
|
||||||
<img src={`/prod.svg`} alt={`产品`} className={`w-10 h-=10`}/>
|
|
||||||
<span>代理产品</span>
|
|
||||||
</h3>
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<p className="flex gap-2">
|
|
||||||
<span>短效动态IP</span>
|
|
||||||
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
|
||||||
折扣45%
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-400 text-sm">
|
|
||||||
全国300+城市级定位节点
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<p className="flex gap-2">
|
|
||||||
<span>长效静态IP</span>
|
|
||||||
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
|
||||||
折扣45%
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-400 text-sm">
|
|
||||||
IPI资源覆盖全国
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="flex gap-2">
|
|
||||||
<span>固定IP</span>
|
|
||||||
<span className="text-orange-500 text-xs text-light px-2 py-1 bg-orange-50 rounded-full">
|
|
||||||
折扣45%
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-64 flex flex-col gap-4">
|
|
||||||
<h3 className="font-bold mb-2 flex items-center gap-3">
|
|
||||||
<img src="/custom.svg" alt="定制" className="w-10 h-10"/>
|
|
||||||
<span>业务定制</span>
|
|
||||||
</h3>
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<p>优质/企业/精选IP</p>
|
|
||||||
<p className="text-gray-400 text-sm">
|
|
||||||
超 1000 家企业共同信赖之选!大客户经理全
|
|
||||||
程 1 对 1 沟通,随时为您排忧解难,提供 24
|
|
||||||
小时不间断支持
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
) : (
|
|
||||||
<section role="tabpanel">
|
|
||||||
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<aside className="w-64">
|
|
||||||
<h3 className="flex gap-3 items-center mb-4">
|
|
||||||
<img src={`/anno.svg`} alt={`公告`} className={`w-10 h-10`}/>
|
|
||||||
<span>网站公告</span>
|
|
||||||
</h3>
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<p>官网最新上线,体验再升级!</p>
|
|
||||||
<p className="text-gray-400 text-sm">
|
|
||||||
1.新增多样使用功能,新增多样使用
|
|
||||||
新增多样使用功能
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-400 text-sm">
|
|
||||||
2.新增多样使用功能,新增多样使用
|
|
||||||
新增多样使用功能
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
</Wrap>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function SolutionMenu() {
|
|
||||||
|
|
||||||
const SolutionItem = (props: {
|
|
||||||
icon: string
|
|
||||||
title: string
|
|
||||||
desc: string
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={[
|
|
||||||
`h-full p-4 flex gap-4 items-start rounded-md cursor-pointer`,
|
|
||||||
`transition-colors duration-200 hover:bg-blue-100`,
|
|
||||||
].join(' ')}
|
|
||||||
>
|
|
||||||
<img src={`/header/solution/${props.icon}.svg`} alt={props.title} className="w-10 h-10"/>
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<h3 className="font-bold">{props.title}</h3>
|
|
||||||
<p className="text-gray-400 text-sm">{props.desc}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Wrap className="grid grid-cols-4 auto-rows-fr gap-4">
|
|
||||||
<SolutionItem
|
|
||||||
icon="01"
|
|
||||||
title="数据抓取"
|
|
||||||
desc="高效采集和分析大量数据,助力企业获取大量情报"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="02"
|
|
||||||
title="广告验证"
|
|
||||||
desc="确保广告点击和展示数据的真实性,帮助企业,提升广告效果"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="03"
|
|
||||||
title="市场调查"
|
|
||||||
desc="收集全网行业数据,了解竞争对手动态"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="04"
|
|
||||||
title="SEO优化"
|
|
||||||
desc="收集搜索引擎情报,提高网站在搜索引擎的排名"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="05"
|
|
||||||
title="品牌保护"
|
|
||||||
desc="保护品牌商标打造,优质品牌形象,为企业获得更多用户"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="06"
|
|
||||||
title="价格监控"
|
|
||||||
desc="利用优质代理IP,实时监控行业价格信息,提高市场竞争力"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="07"
|
|
||||||
title="金融数据"
|
|
||||||
desc="快速获取金融市场实时数据,帮助投资者分析趋势,使其做出精准决策"
|
|
||||||
/>
|
|
||||||
<SolutionItem
|
|
||||||
icon="08"
|
|
||||||
title="网站测试"
|
|
||||||
desc="在不同环境下对网站进行性能和兼容的测试,让用户有高质量体验"
|
|
||||||
/>
|
|
||||||
</Wrap>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function HelpMenu() {
|
|
||||||
|
|
||||||
const Column = (props: {
|
|
||||||
icon: string,
|
|
||||||
title: string,
|
|
||||||
items: {
|
|
||||||
lead: string
|
|
||||||
href: string
|
|
||||||
}[]
|
|
||||||
}) => (
|
|
||||||
<div className="flex flex-col gap-4">
|
|
||||||
<h3 className="font-bold flex gap-3 items-center">
|
|
||||||
<img src={`/header/help/${props.icon}.svg`} alt={props.title} className="w-10 h-10"/>
|
|
||||||
<span>{props.title}</span>
|
|
||||||
</h3>
|
|
||||||
<ul className=" text-gray-500 text-sm flex flex-col items-end gap-2">
|
|
||||||
{props.items.map((item, index) => (
|
|
||||||
<li key={index}><Link href={item.href}>{item.lead}</Link></li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Wrap className="w-full grid grid-cols-4 gap-4 justify-items-center">
|
|
||||||
<Column
|
|
||||||
icon="01"
|
|
||||||
title="提取IP"
|
|
||||||
items={[
|
|
||||||
{lead: '短效动态IP提取', href: '#'},
|
|
||||||
{lead: '长效静态IP提取', href: '#'},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<Column
|
|
||||||
icon="02"
|
|
||||||
title="使用教程"
|
|
||||||
items={[
|
|
||||||
{lead: '快速入手', href: '#'},
|
|
||||||
{lead: '代码下载', href: '#'},
|
|
||||||
{lead: 'API文档', href: '#'},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<Column
|
|
||||||
icon="03"
|
|
||||||
title="产品功能"
|
|
||||||
items={[
|
|
||||||
{lead: '常见问题', href: '#'},
|
|
||||||
{lead: '产品介绍', href: '#'},
|
|
||||||
{lead: '行业资讯', href: '#'},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<img src={`/header/help/banner.webp`} alt={`banner`} className={``}/>
|
|
||||||
</Wrap>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import Header from '@/app/(root)/header'
|
import Header from '@/app/(root)/@header/page'
|
||||||
import Footer from '@/app/(root)/footer'
|
import Footer from '@/app/(root)/@footer/page'
|
||||||
import {ReactNode} from 'react'
|
import {ReactNode} from 'react'
|
||||||
|
|
||||||
export type RootLayoutProps = {
|
export type RootLayoutProps = {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 652 B After Width: | Height: | Size: 652 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |