Files
novalon-website/src/components/sections/hero-section-v2.tsx
T
张翔 415a103a24 style(theme): 更新网站主题色彩方案与字体配置
- 调整主色调从 #1C1C1C 至 #1A1A1A,优化视觉层次
- 更新背景色系为暖白色调 (#FAFAF7, #F5F4F0 等)
- 配置中文字体栈,添加 serif 字体支持
- 优化文本颜色梯度,提升可读性
- 调整边框颜色,统一水墨风格
- 添加 Google Search Console 验证码配置项
- 新增桌面应用架构专家代理配置文件
- 重构 E2E 测试等待策略,提升稳定性
- 添加回归测试脚本,增强质量保障
2026-06-17 11:37:25 +08:00

204 lines
9.2 KiB
TypeScript

'use client';
import { useCallback, useRef, useState } from 'react';
import { motion } from 'framer-motion';
import { StaticLink } from '@/components/ui/static-link';
import { Button } from '@/components/ui/button';
import { HeroInkBackground } from '@/components/ui/hero-ink-background';
import { COMPANY_INFO } from '@/lib/constants';
import { ArrowRight, MessageSquare, Search, Rocket, Handshake } from 'lucide-react';
import { useReducedMotion } from '@/hooks/use-reduced-motion';
const EASE = [0.16, 1, 0.3, 1] as const;
const CAPABILITIES = [
{ icon: MessageSquare, label: '需求沟通' },
{ icon: Search, label: '方案诊断' },
{ icon: Rocket, label: '敏捷交付' },
{ icon: Handshake, label: '长期陪跑' },
];
const JOURNEY_STEPS = [
{ icon: MessageSquare, label: '需求沟通', desc: '深入理解您的业务痛点' },
{ icon: Search, label: '方案诊断', desc: '量身定制技术路径' },
{ icon: Rocket, label: '敏捷交付', desc: '快速迭代持续验证' },
{ icon: Handshake, label: '长期陪跑', desc: '持续优化保障落地' },
];
export function HeroSectionV2() {
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
const [isCardHovered, setIsCardHovered] = useState(false);
const cardRef = useRef<HTMLDivElement>(null);
const shouldReduceMotion = useReducedMotion();
const handleCardMouseMove = useCallback((e: React.MouseEvent) => {
if (!cardRef.current) { return; }
const rect = cardRef.current.getBoundingClientRect();
setMousePos({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
});
}, []);
const fadeUp = (delay: number) => ({
initial: shouldReduceMotion ? {} : { opacity: 0, y: 24 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.5, delay, ease: EASE },
});
return (
<section
id="home"
aria-labelledby="hero-heading"
className="relative min-h-screen flex flex-col justify-center overflow-hidden bg-[var(--color-bg-primary)]"
>
<HeroInkBackground />
<div className="container-wide py-16 md:py-24 lg:py-32 relative z-10 flex-1 flex items-center">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10 lg:gap-16 items-center w-full">
<div>
<motion.div
{...fadeUp(0)}
className="mb-6"
>
<span className="inline-flex items-center gap-2 px-3 py-1.5 sm:px-4 sm:py-2 rounded-full bg-[var(--color-brand-primary-bg)] text-[var(--color-brand-primary)] text-xs sm:text-sm font-medium border border-[var(--color-brand-primary)]/10">
{COMPANY_INFO.slogan}
</span>
</motion.div>
<motion.p
{...fadeUp(0.1)}
className="text-lg sm:text-xl lg:text-2xl text-[var(--color-text-primary)] mb-3"
>
<span className="font-semibold text-[var(--color-brand-primary)] font-calligraphy">
企业数字化转型服务商
</span>
</motion.p>
<motion.h1
id="hero-heading"
{...fadeUp(0.15)}
className="text-5xl sm:text-6xl lg:text-7xl tracking-tight mb-5 font-brand leading-[1.1]"
style={{ fontWeight: 'normal' }}
>
{COMPANY_INFO.shortName}
</motion.h1>
<motion.p
{...fadeUp(0.25)}
className="text-base sm:text-lg text-[var(--color-text-muted)] max-w-lg leading-relaxed mb-8"
>
{COMPANY_INFO.description}
</motion.p>
<motion.div
{...fadeUp(0.35)}
className="flex flex-col sm:flex-row items-start gap-4 mb-10"
>
<Button size="lg" asChild className="min-h-[52px] px-8 text-base font-semibold shadow-lg shadow-[var(--color-brand-primary)]/20">
<StaticLink href="/contact">
免费获取定制方案
<ArrowRight className="w-4 h-4 ml-2" />
</StaticLink>
</Button>
<Button size="lg" variant="ghost" asChild className="text-[var(--color-text-muted)]">
<StaticLink href="/products">探索产品</StaticLink>
</Button>
</motion.div>
</div>
<motion.div
initial={shouldReduceMotion ? {} : { opacity: 0, y: 32 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.5, ease: EASE }}
>
<div
ref={cardRef}
className="relative ink-glow-border rounded-2xl lg:opacity-95"
style={
{
'--glow-start': 'var(--color-brand-primary)',
'--glow-end': 'var(--color-warning)',
} as React.CSSProperties
}
onMouseMove={handleCardMouseMove}
onMouseEnter={() => setIsCardHovered(true)}
onMouseLeave={() => setIsCardHovered(false)}
>
<div
className="absolute inset-0 rounded-2xl pointer-events-none transition-opacity duration-500"
style={{
opacity: isCardHovered ? 1 : 0,
background: `radial-gradient(400px circle at ${mousePos.x}px ${mousePos.y}px, rgba(var(--color-brand-primary-rgb), 0.06), transparent 40%)`,
}}
/>
<div className="relative rounded-2xl bg-[var(--color-bg-primary)]/80 backdrop-blur-sm p-6 sm:p-8 lg:p-10">
<div className="w-12 h-12 lg:w-14 lg:h-14 rounded-xl bg-[var(--color-brand-primary-bg)] flex items-center justify-center mb-5 lg:mb-6">
<Handshake className="w-5 h-5 lg:w-6 lg:h-6 text-[var(--color-brand-primary)]" strokeWidth={1.8} />
</div>
<h3 className="text-lg lg:text-xl font-semibold text-[var(--color-text-primary)] mb-2">
从沟通到落地,全程陪伴
</h3>
<p className="text-sm text-[var(--color-text-muted)] leading-relaxed mb-6 lg:mb-8">
四步合作流程,确保每个项目科学推进、高效交付
</p>
<div className="grid grid-cols-2 gap-3 lg:gap-4 lg:block lg:space-y-4">
{JOURNEY_STEPS.map((step, idx) => {
const Icon = step.icon;
return (
<div
key={step.label}
className="flex items-center gap-3 lg:gap-4 p-2.5 lg:p-3 rounded-lg bg-[var(--color-bg-section)]/60"
>
<div className="w-8 h-8 lg:w-9 lg:h-9 rounded-lg bg-[var(--color-brand-primary-bg)] flex items-center justify-center shrink-0">
<Icon className="w-3.5 h-3.5 lg:w-4 lg:h-4 text-[var(--color-brand-primary)]" strokeWidth={2.2} />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-1.5 lg:gap-2">
<span className="text-[10px] lg:text-xs font-bold text-[var(--color-brand-primary)]">0{idx + 1}</span>
<span className="text-xs lg:text-sm font-medium text-[var(--color-text-primary)]">{step.label}</span>
</div>
<p className="text-[10px] lg:text-xs text-[var(--color-text-muted)] mt-0.5 hidden sm:block">{step.desc}</p>
</div>
</div>
);
})}
</div>
{/* Integrated capabilities */}
<div className="mt-4 pt-4 border-t border-[var(--color-border-primary)]/50">
<div className="flex flex-wrap gap-1.5">
{CAPABILITIES.map((cap, idx) => {
const Icon = cap.icon;
return (
<div
key={cap.label}
className="flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors duration-200"
style={{
backgroundColor: idx === 0 ? 'var(--color-brand-primary-bg)' : idx === 1 ? 'rgba(var(--color-accent-blue-rgb), 0.06)' : idx === 2 ? 'rgba(var(--color-accent-purple-rgb), 0.06)' : 'rgba(var(--color-accent-cyan-rgb), 0.06)',
borderColor: idx === 0 ? 'rgba(var(--color-brand-primary-rgb), 0.15)' : 'var(--color-border-primary)',
}}
>
<Icon
className="w-4 h-4"
style={{ color: idx === 0 ? 'var(--color-brand-primary)' : idx === 1 ? 'var(--color-accent-blue)' : idx === 2 ? 'var(--color-accent-purple)' : 'var(--color-accent-cyan)' }}
strokeWidth={2.2}
/>
<span className="text-xs font-medium text-[var(--color-text-primary)]">{cap.label}</span>
</div>
);
})}
</div>
</div>
</div>
</div>
</motion.div>
</div>
</div>
</section>
);
}