diff --git a/package.json b/package.json index 3948839..25f1b59 100644 --- a/package.json +++ b/package.json @@ -9,22 +9,23 @@ "lint": "next lint" }, "dependencies": { + "motion": "^12.5.0", + "next": "15.2.1", "react": "^19.0.0", - "react-dom": "^19.0.0", - "next": "15.2.1" + "react-dom": "^19.0.0" }, "devDependencies": { + "@eslint/eslintrc": "^3", "@next/eslint-plugin-next": "^15.2.1", - "eslint-plugin-react-hooks": "^5.2.0", - "typescript": "^5", + "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "@tailwindcss/postcss": "^4", - "tailwindcss": "^4", "eslint": "^9", "eslint-config-next": "15.2.1", - "@eslint/eslintrc": "^3" + "eslint-plugin-react-hooks": "^5.2.0", + "tailwindcss": "^4", + "typescript": "^5" }, "packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d914b3c..c918398 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + motion: + specifier: ^12.5.0 + version: 12.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: specifier: 15.2.1 version: 15.2.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -877,6 +880,20 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + framer-motion@12.5.0: + resolution: {integrity: sha512-buPlioFbH9/W7rDzYh1C09AuZHAk2D1xTA1BlounJ2Rb9aRg84OXexP0GLd+R83v0khURdMX7b5MKnGTaSg5iA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -1226,6 +1243,26 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + motion-dom@12.5.0: + resolution: {integrity: sha512-uH2PETDh7m+Hjd1UQQ56yHqwn83SAwNjimNPE/kC+Kds0t4Yh7+29rfo5wezVFpPOv57U4IuWved5d1x0kNhbQ==} + + motion-utils@12.5.0: + resolution: {integrity: sha512-+hFFzvimn0sBMP9iPxBa9OtRX35ZQ3py0UHnb8U29VD+d8lQ8zH3dTygJWqK7av2v6yhg7scj9iZuvTS0f4+SA==} + + motion@12.5.0: + resolution: {integrity: sha512-BTAYKszMmTvXSsIyeHNMPSicjWgUA4j7OmZv1xPpthm4sPub3ch66fy9U7BhJ1uXNL3YeprsIegzuvps3FkEMw==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2558,6 +2595,15 @@ snapshots: dependencies: is-callable: 1.2.7 + framer-motion@12.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + motion-dom: 12.5.0 + motion-utils: 12.5.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -2896,6 +2942,20 @@ snapshots: minimist@1.2.8: {} + motion-dom@12.5.0: + dependencies: + motion-utils: 12.5.0 + + motion-utils@12.5.0: {} + + motion@12.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + framer-motion: 12.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + tslib: 2.8.1 + optionalDependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + ms@2.1.3: {} nanoid@3.3.8: {} diff --git a/public/anno.svg b/public/anno.svg new file mode 100644 index 0000000..2f0bb4b --- /dev/null +++ b/public/anno.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/custom.svg b/public/custom.svg new file mode 100644 index 0000000..f628cf7 --- /dev/null +++ b/public/custom.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/header/down.svg b/public/header/down.svg new file mode 100644 index 0000000..895eb0c --- /dev/null +++ b/public/header/down.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/header/help/01.svg b/public/header/help/01.svg new file mode 100644 index 0000000..398e2db --- /dev/null +++ b/public/header/help/01.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/help/02.svg b/public/header/help/02.svg new file mode 100644 index 0000000..fa7e658 --- /dev/null +++ b/public/header/help/02.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/help/03.svg b/public/header/help/03.svg new file mode 100644 index 0000000..5d6c238 --- /dev/null +++ b/public/header/help/03.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/help/banner.webp b/public/header/help/banner.webp new file mode 100644 index 0000000..7c366ad Binary files /dev/null and b/public/header/help/banner.webp differ diff --git a/public/header/solution/01.svg b/public/header/solution/01.svg new file mode 100644 index 0000000..ebeca5e --- /dev/null +++ b/public/header/solution/01.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/solution/02.svg b/public/header/solution/02.svg new file mode 100644 index 0000000..a3af732 --- /dev/null +++ b/public/header/solution/02.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/solution/03.svg b/public/header/solution/03.svg new file mode 100644 index 0000000..70d1b1d --- /dev/null +++ b/public/header/solution/03.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/header/solution/04.svg b/public/header/solution/04.svg new file mode 100644 index 0000000..b0f148f --- /dev/null +++ b/public/header/solution/04.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/header/solution/05.svg b/public/header/solution/05.svg new file mode 100644 index 0000000..ddceccc --- /dev/null +++ b/public/header/solution/05.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/header/solution/06.svg b/public/header/solution/06.svg new file mode 100644 index 0000000..a088744 --- /dev/null +++ b/public/header/solution/06.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/header/solution/07.svg b/public/header/solution/07.svg new file mode 100644 index 0000000..08b40cc --- /dev/null +++ b/public/header/solution/07.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/header/solution/08.svg b/public/header/solution/08.svg new file mode 100644 index 0000000..026fc17 --- /dev/null +++ b/public/header/solution/08.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/prod.svg b/public/prod.svg new file mode 100644 index 0000000..7caad53 --- /dev/null +++ b/public/prod.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/(home)/footer.tsx b/src/app/(home)/footer.tsx index 9be9ad9..1c43ed3 100644 --- a/src/app/(home)/footer.tsx +++ b/src/app/(home)/footer.tsx @@ -14,12 +14,12 @@ export default function Footer(props: FooterProps) {

商务合作

-

大客户经理:张经理

-

电话/微信:18751847847

-

QQ号:800180559

+

大客户经理:张经理

+

电话/微信:18751847847

+

QQ号:800180559

服务保障

- - + +
{props.items.map((item, index) => (
  • - {item.name} + {item.name}
  • ))} diff --git a/src/app/(home)/header.tsx b/src/app/(home)/header.tsx index fbf296c..e41ed33 100644 --- a/src/app/(home)/header.tsx +++ b/src/app/(home)/header.tsx @@ -11,12 +11,15 @@ export default function Header(props: HeaderProps) { // 滚动条状态 // ====================== - const [scroll, setScroll] = useState(window.scrollY > 48) + 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) @@ -27,167 +30,405 @@ export default function Header(props: HeaderProps) { // 菜单状态 // ====================== - const [menu, setMenu] = useState('') + const [menu, setMenu] = useState(false) + const [page, setPage] = useState(0) + const pages = useMemo(() => [ + , + , + , + ], []) // ====================== // 覆盖状态 // ====================== const [overlay, setOverlay] = useState(false) - useEffect(() => { - setOverlay(scroll || menu !== '') + setOverlay(scroll || menu) }, [menu, scroll]) // ====================== // 渲染组件 // ====================== - return ( -
    ( +
  • + + {props.text} + +
    - -
    - {/* logo */} - - {`logo`} - +
    +
  • + ) - {/* 菜单 */} - - - {/* 登录 */} - - + {/* 菜单 */} + + + {/* 登录 */} + + + {/* 下拉菜单 */}
    + `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]}
    - {{ - 'product': , - 'solution': , - 'help': , - }[menu]} - Using a wrapper div to handle transitions
    ) } -function NavItemTop(props: { - children: ReactNode - onEnter?: () => void - onLeave?: () => void -}) { - return ( -
  • - {props.children} -
  • - ) -} - -function SvgDown() { - return ( - - - - ) -} - function ProductMenu() { - const [type, setType] = useState<'domestic' | 'oversea'>('domestic') + + // ==================== + // Tab 选项 + // ==================== + + type TabType = 'domestic' | 'oversea' + const [type, setType] = useState('domestic') + + const Tab = (props: { + type: TabType, + children: ReactNode + }) => { + return ( +
  • + +
  • + ) + } + + // ==================== + // 渲染组件 + // ==================== + return ( -
    -
      -
    • - -
    • -
    • - -
    • + +
        + 国内代理 + 海外代理
      -
      - {{ - 'domestic':
      国内代理
      , - 'oversea':
      海外代理
      , - }[type]} -
      -
    +
    + {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/(home)/page.tsx b/src/app/(home)/page.tsx index f013349..fa3caeb 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -18,7 +18,7 @@ export default function Home() {

    安全,稳定,快速,合规的代理服务器

    -

    遍布全国的代理服务器节点为用户提供智能可靠的IP代理服务

    +

    遍布全国的代理服务器节点为用户提供智能可靠的IP代理服务

    @@ -138,13 +138,13 @@ export default function Home() {

    我是标题 - 2025-03-04 + 2025-03-04

    我是内容我是内容我是内容我是内容我是内容我是容我是内容我是内容内容我是内容我是内容我是内我是内容我是内容我是内容我是内容我是内容...

    - + 更多详情 {`more`} @@ -199,7 +199,7 @@ function Sec3Item(props: {
    {props.terms.map((item, index) => { return ( -

    +

    {`check`} {item.text}

    diff --git a/src/components/animation/page-switcher.tsx b/src/components/animation/page-switcher.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dropdown/example-structure.tsx b/src/components/dropdown/example-structure.tsx new file mode 100644 index 0000000..06d7bca --- /dev/null +++ b/src/components/dropdown/example-structure.tsx @@ -0,0 +1,27 @@ +import { useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; + +export const Dropdown = () => { + const [isOpen, setIsOpen] = useState(false); + + return ( +
    + + + + {isOpen && ( + + {/* 菜单内容 */} + + )} + +
    + ); +}; diff --git a/src/components/wrap.tsx b/src/components/wrap.tsx index 513d0f3..f2e9a29 100644 --- a/src/components/wrap.tsx +++ b/src/components/wrap.tsx @@ -7,7 +7,7 @@ export type WrapProps = { export default function Wrap(props: WrapProps) { return ( -
    +
    {props.children}
    ) diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1 @@ +