diff --git a/src/app/(root)/footer.tsx b/src/app/(root)/@footer/page.tsx similarity index 100% rename from src/app/(root)/footer.tsx rename to src/app/(root)/@footer/page.tsx diff --git a/src/app/(root)/@header/_client/help.tsx b/src/app/(root)/@header/_client/help.tsx new file mode 100644 index 0000000..cf5c79a --- /dev/null +++ b/src/app/(root)/@header/_client/help.tsx @@ -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 ( + + + + + {`banner`} + + ) +} + +function Column(props: { + icon: any + title: string + items: { + lead: string + href: string + }[] +}) { + return ( +
+

+ {props.title} + {props.title} +

+ +
+ ) +} \ No newline at end of file diff --git a/src/app/(root)/@header/_client/product.tsx b/src/app/(root)/@header/_client/product.tsx new file mode 100644 index 0000000..472bc91 --- /dev/null +++ b/src/app/(root)/@header/_client/product.tsx @@ -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('domestic') + + return ( + + +
+ {type === 'domestic' + ? ( +
+
+

+ {`产品`} + 代理产品 +

+
+

+ 短效动态IP + + 折扣45% + +

+

+ 全国300+城市级定位节点 +

+
+
+

+ 长效静态IP + + 折扣45% + +

+

+ IPI资源覆盖全国 +

+
+
+

+ 固定IP + + 折扣45% + +

+
+
+
+

+ 定制 + 业务定制 +

+
+

优质/企业/精选IP

+

+ 超 1000 家企业共同信赖之选!大客户经理全 + 程 1 对 1 沟通,随时为您排忧解难,提供 24 + 小时不间断支持 +

+
+
+
+ ) : ( +
+ +
+ ) + } +
+ +
+ ) +} + + + + +function Tab(props: { + selected: boolean + onSelect: () => void + children: ReactNode +}) { + + return ( +
  • + +
  • + ) +} \ No newline at end of file diff --git a/src/app/(root)/@header/_client/solution.tsx b/src/app/(root)/@header/_client/solution.tsx new file mode 100644 index 0000000..cfc09de --- /dev/null +++ b/src/app/(root)/@header/_client/solution.tsx @@ -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 ( + + + + + + + + + + + ) +} + +function SolutionItem(props: { + icon: any + title: string + desc: string +}) { + return ( +
    + {props.title} +
    +

    {props.title}

    +

    {props.desc}

    +
    +
    + ) +} \ No newline at end of file diff --git a/src/app/(root)/@header/_server/navs.tsx b/src/app/(root)/@header/_server/navs.tsx new file mode 100644 index 0000000..95c4273 --- /dev/null +++ b/src/app/(root)/@header/_server/navs.tsx @@ -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 ( +
  • + + {props.text} + +
    +
    +
  • + ) +} + +export function MenuItem(props: { + text: string + active: boolean + onEnter: () => void + onLeave: () => void +}) { + return ( +
  • + +
    +
  • + ) +} \ No newline at end of file diff --git a/src/app/(root)/@header/page.tsx b/src/app/(root)/@header/page.tsx new file mode 100644 index 0000000..27fa6f0 --- /dev/null +++ b/src/app/(root)/@header/page.tsx @@ -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(() => [ + , + , + , + ], []) + + // ====================== + // 渲染组件 + // ====================== + + return ( +
    +
    + +
    + {/* logo */} + + {`logo`} + + + {/* 菜单 */} + +
    + {/* 登录 */} + +
    +
    + + {/* 下拉菜单 */} +
    setMenu(true)} + onPointerLeave={() => setMenu(false)} + > + {pages[page]} +
    +
    + ) +} + + + + + diff --git a/src/app/(root)/header.tsx b/src/app/(root)/header.tsx deleted file mode 100644 index 5bd68c7..0000000 --- a/src/app/(root)/header.tsx +++ /dev/null @@ -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(() => [ - , - , - , - ], []) - - // ====================== - // 覆盖状态 - // ====================== - - const [overlay, setOverlay] = useState(false) - useEffect(() => { - setOverlay(scroll || menu) - }, [menu, scroll]) - - // ====================== - // 渲染组件 - // ====================== - - const LinkItem = (props: { - text: string - href: string - }) => ( -
  • - - {props.text} - -
    -
    -
  • - ) - - const MenuItem = (props: { - text: string - page: number - }) => ( -
  • - -
    -
    -
  • - - ) - - return ( -
    -
    - -
    - {/* logo */} - - {`logo`} - - - {/* 菜单 */} - -
    - {/* 登录 */} - -
    -
    - - {/* 下拉菜单 */} -
    setMenu(true)} - onPointerLeave={() => setMenu(false)} - > - {pages[page]} -
    -
    - ) -} - -function ProductMenu() { - - // ==================== - // Tab 选项 - // ==================== - - type TabType = 'domestic' | 'oversea' - const [type, setType] = useState('domestic') - - const Tab = (props: { - type: TabType, - children: ReactNode - }) => { - return ( -
  • - -
  • - ) - } - - // ==================== - // 渲染组件 - // ==================== - - return ( - -
      - 国内代理 - 海外代理 -
    -
    - {type === 'domestic' - ? ( -
    -
    -

    - {`产品`} - 代理产品 -

    -
    -

    - 短效动态IP - - 折扣45% - -

    -

    - 全国300+城市级定位节点 -

    -
    -
    -

    - 长效静态IP - - 折扣45% - -

    -

    - IPI资源覆盖全国 -

    -
    -
    -

    - 固定IP - - 折扣45% - -

    -
    -
    -
    -

    - 定制 - 业务定制 -

    -
    -

    优质/企业/精选IP

    -

    - 超 1000 家企业共同信赖之选!大客户经理全 - 程 1 对 1 沟通,随时为您排忧解难,提供 24 - 小时不间断支持 -

    -
    -
    -
    - ) : ( -
    - -
    - ) - } -
    - -
    - ) -} - -function SolutionMenu() { - - const SolutionItem = (props: { - icon: string - title: string - desc: string - }) => { - return ( -
    - {props.title} -
    -

    {props.title}

    -

    {props.desc}

    -
    -
    - ) - } - - return ( - - - - - - - - - - - ) -} - -function HelpMenu() { - - const Column = (props: { - icon: string, - title: string, - items: { - lead: string - href: string - }[] - }) => ( -
    -

    - {props.title} - {props.title} -

    -
      - {props.items.map((item, index) => ( -
    • {item.lead}
    • - ))} -
    -
    - ) - - return ( - - - - - {`banner`} - - ) -} diff --git a/src/app/(root)/layout.tsx b/src/app/(root)/layout.tsx index 6d69514..82c28d2 100644 --- a/src/app/(root)/layout.tsx +++ b/src/app/(root)/layout.tsx @@ -1,5 +1,5 @@ -import Header from '@/app/(root)/header' -import Footer from '@/app/(root)/footer' +import Header from '@/app/(root)/@header/page' +import Footer from '@/app/(root)/@footer/page' import {ReactNode} from 'react' export type RootLayoutProps = { diff --git a/public/header/down.svg b/src/assets/header/down.svg similarity index 100% rename from public/header/down.svg rename to src/assets/header/down.svg diff --git a/public/header/help/01.svg b/src/assets/header/help/01.svg similarity index 100% rename from public/header/help/01.svg rename to src/assets/header/help/01.svg diff --git a/public/header/help/02.svg b/src/assets/header/help/02.svg similarity index 100% rename from public/header/help/02.svg rename to src/assets/header/help/02.svg diff --git a/public/header/help/03.svg b/src/assets/header/help/03.svg similarity index 100% rename from public/header/help/03.svg rename to src/assets/header/help/03.svg diff --git a/public/header/help/banner.webp b/src/assets/header/help/banner.webp similarity index 100% rename from public/header/help/banner.webp rename to src/assets/header/help/banner.webp diff --git a/public/anno.svg b/src/assets/header/product/anno.svg similarity index 100% rename from public/anno.svg rename to src/assets/header/product/anno.svg diff --git a/public/custom.svg b/src/assets/header/product/custom.svg similarity index 100% rename from public/custom.svg rename to src/assets/header/product/custom.svg diff --git a/public/prod.svg b/src/assets/header/product/prod.svg similarity index 100% rename from public/prod.svg rename to src/assets/header/product/prod.svg diff --git a/public/header/solution/01.svg b/src/assets/header/solution/01.svg similarity index 100% rename from public/header/solution/01.svg rename to src/assets/header/solution/01.svg diff --git a/public/header/solution/02.svg b/src/assets/header/solution/02.svg similarity index 100% rename from public/header/solution/02.svg rename to src/assets/header/solution/02.svg diff --git a/public/header/solution/03.svg b/src/assets/header/solution/03.svg similarity index 100% rename from public/header/solution/03.svg rename to src/assets/header/solution/03.svg diff --git a/public/header/solution/04.svg b/src/assets/header/solution/04.svg similarity index 100% rename from public/header/solution/04.svg rename to src/assets/header/solution/04.svg diff --git a/public/header/solution/05.svg b/src/assets/header/solution/05.svg similarity index 100% rename from public/header/solution/05.svg rename to src/assets/header/solution/05.svg diff --git a/public/header/solution/06.svg b/src/assets/header/solution/06.svg similarity index 100% rename from public/header/solution/06.svg rename to src/assets/header/solution/06.svg diff --git a/public/header/solution/07.svg b/src/assets/header/solution/07.svg similarity index 100% rename from public/header/solution/07.svg rename to src/assets/header/solution/07.svg diff --git a/public/header/solution/08.svg b/src/assets/header/solution/08.svg similarity index 100% rename from public/header/solution/08.svg rename to src/assets/header/solution/08.svg diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..be7c2c6 Binary files /dev/null and b/src/assets/logo.png differ