Files
dalcode-website/components/Header.tsx
T
Leon-in 97db9ee8c7 feat(site): redesign with product pages, ecosystem sections and pixel reveal
Add cli/code/office/platform/pricing pages, new home sections
(Ecosystem, FeatureGrid, Faq, WorkflowSteps, BottomCta, ProductEcosystem),
ScrollReveal and PixelTextReveal animation components, brand assets,
and expanded site-content.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 14:00:18 +08:00

193 lines
8.2 KiB
TypeScript

"use client"
import { useState, useEffect, useCallback } from "react"
import Image from "next/image"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { useTranslations } from "next-intl"
import ThemeToggle from "@/components/ThemeToggle"
import LocaleSwitcher from "@/components/LocaleSwitcher"
import { NAV_GROUPS, NAV_LINKS } from "@/lib/site-content"
function ChevronIcon() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 17 17" fill="none" className="squared-icon">
<path d="M6.25391 3.45312L10.7458 8.01563L6.25391 12.5781" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square" />
</svg>
)
}
function DropdownIcon() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 20 20" fill="none">
<path d="M15.5 7.03847L10 12.9615L4.5 7.03847" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square" />
</svg>
)
}
export default function Header() {
const t = useTranslations("nav")
const [mobileOpen, setMobileOpen] = useState(false)
const [dropdownOpen, setDropdownOpen] = useState(false)
const [scrolled, setScrolled] = useState(false)
const pathname = usePathname()
const closeMenus = useCallback(() => {
setMobileOpen(false)
setDropdownOpen(false)
}, [])
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 20)
window.addEventListener("scroll", onScroll, { passive: true })
return () => window.removeEventListener("scroll", onScroll)
}, [])
const toggleMobile = useCallback(() => setMobileOpen((v) => !v), [])
return (
<div
className={`header-wrapper w-nav ${scrolled ? "header-scrolled" : ""}`}
data-animation="default"
data-easing2="ease"
data-easing="ease"
data-collapse="medium"
role="banner"
data-duration="300"
>
<div className="header-content">
<div className="header-logo-wrapper">
<div className="show-light-mode">
<Link href="/" className="logo-link w-inline-block">
<Image src="/assets/dalcode-app-icon.svg" width={54} height={54} alt="DAL Code" className="logo-icon" />
</Link>
</div>
<div className="show-dark-mode">
<Link href="/" className="logo-link w-inline-block">
<Image src="/assets/dalcode-logo-dark.svg" width={54} height={54} alt="DAL Code" className="logo-icon" />
</Link>
</div>
</div>
<div className="header-right-side">
<nav
role="navigation"
className={`nav-menu w-nav-menu ${mobileOpen ? "w--open" : ""}`}
>
<ul role="list" className="list-nav-menu w-list-unstyled">
{NAV_LINKS.map(({ href, label }) => (
<li key={href} className="link-nav-item sibling-blur-item">
<Link
href={href}
className={`link w-inline-block ${pathname === href ? "w--current" : ""}`}
onClick={closeMenus}
>
<div className="link-icon-wrapper">
<div className="link-icon">
<ChevronIcon />
</div>
</div>
<div className="link-text">{label === "首页" ? t("home") : label === "产品定位" ? t("about") : label === "洞察" ? t("blog") : t("contact")}</div>
</Link>
</li>
))}
<li className="link-nav-item sibling-blur-item">
<div
className={`header-dropdown w-dropdown ${dropdownOpen ? "w--open" : ""}`}
onMouseEnter={() => setDropdownOpen(true)}
onMouseLeave={() => setDropdownOpen(false)}
>
<button
className="dropdown-toggle w-dropdown-toggle"
onClick={() => setDropdownOpen((v) => !v)}
aria-expanded={dropdownOpen}
type="button"
>
<div>{t("explore")}</div>
<div className="dropdown-icon">
<DropdownIcon />
</div>
</button>
{dropdownOpen && (
<nav className="dropdown-content-wrapper w-dropdown-list w--open">
<div className="card header-dropdown-card">
<div className="w-layout-grid header-dropdown-grid">
{NAV_GROUPS.map((group) => (
<div key={group.title}>
<div className="dropdown-title">{group.title === "产品" ? t("groups.product") : t("groups.content")}</div>
<div className="w-layout-grid pages-column">
{group.links.map(({ href, label }) => (
<Link key={href} href={href} className="link w-inline-block" onClick={closeMenus}>
<div className="link-icon-wrapper">
<div className="link-icon"><ChevronIcon /></div>
</div>
<div className="link-text">{label === "首页" ? t("groupLinks.home") : label === "为什么是 DAL Code" ? t("groupLinks.whyDalCode") : label === "申请试用" ? t("groupLinks.applyTrial") : label === "产品洞察" ? t("groupLinks.insights") : t("groupLinks.buildingRoles")}</div>
</Link>
))}
</div>
</div>
))}
</div>
</div>
</nav>
)}
</div>
</li>
<li className="link-nav-item mbl-button">
<Link href="/contact" className="primary-button w-inline-block" onClick={closeMenus}>
<div className="button-content">
<div>{t("applyTrial")}</div>
<div className="button-icon-wrapper primary">
<ChevronIcon />
<div className="button-icon-bg" />
<div className="button-icon-bg-inside" />
</div>
</div>
</Link>
</li>
</ul>
</nav>
<div className="hidden-on-mobile-landscape">
<div className="show-light-mode">
<Link href="/contact" className="primary-button w-inline-block" onClick={closeMenus}>
<div className="button-content">
<div>{t("applyTrial")}</div>
<div className="button-icon-wrapper primary">
<ChevronIcon />
<div className="button-icon-bg" />
<div className="button-icon-bg-inside" />
</div>
</div>
</Link>
</div>
<div className="show-dark-mode">
<Link href="/contact" className="secondary-button w-inline-block" onClick={closeMenus}>
<div className="button-content">
<div>{t("applyTrial")}</div>
<div className="button-icon-wrapper secondary">
<ChevronIcon />
<div className="button-icon-bg bg-neutral-800" />
<div className="button-icon-bg-inside bg-neutral-600" />
</div>
</div>
</Link>
</div>
</div>
<ThemeToggle />
<LocaleSwitcher />
<button
className={`hamburger-menu w-nav-button ${mobileOpen ? "w--open" : ""}`}
onClick={toggleMobile}
aria-label={t("toggleMenu")}
type="button"
>
<div className="hamburger-menu-flex">
<div className="hamburger-menu-line top" />
<div className="hamburger-menu-line bottom" />
</div>
</button>
</div>
</div>
{mobileOpen && <div className="w-nav-overlay w--open" onClick={() => setMobileOpen(false)} />}
</div>
)
}