feat(ui): CTAButton 可复用组件 + P5 全站 CTA 签名切换(17 页面 27 处)
feat(ui): 抽离 CTAButton 为 src/components/ui/cta-button.tsx - 4 variant 覆盖全站 CTA 场景: * primary:品牌红填充 pill(hero 主行动 / 底部大 CTA) * secondary:描边墨色 pill(浅色 section 次行动) * dark:描边浅色 pill(深色区块 bg-dark-bg 内次行动,如 brand/team 底部 CTA) * inline:透明 + 小箭头(卡片内次行动) - 品牌箭头签名化:内置 ArrowRight + hover translate-x 微交互 - 200-300ms transition,对齐项目动效四原则 - data-testid 透传避免破坏既有测试 style(cta): P5 全站 CTA 签名切换(17 页面 27 处) - home V15 / news×3 / products×4(含 erp)/ cases / services×2 / solutions×2 - brand / methodology / team(hero 2 + L4 2 = 4 处,含 dark variant) - error / not-found(保留 onClick 功能按钮与卡片式导航 StaticLink) - 清理:StaticLink / Button / ArrowRight / ChevronRight unused import test(marketing): services/solutions lucide-react mock 补 ArrowRight - CTAButton 内部用 ArrowRight,原 mock 漏导导致渲染崩(4 测试失败已修) - 对齐 home-content-v15.test.tsx 既有 mock 范式
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowUpRight, CheckCircle2 } from 'lucide-react';
|
||||
import { StaticLink } from '@/components/ui/static-link';
|
||||
import { CTAButton } from '@/components/ui/cta-button';
|
||||
import type { Service } from '@/lib/constants/services';
|
||||
|
||||
const EASE_OUT = [0.22, 1, 0.36, 1] as const;
|
||||
@@ -126,19 +127,12 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
|
||||
transition={{ duration: 0.8, delay: 0.7, ease: EASE_OUT }}
|
||||
className="flex flex-col sm:flex-row gap-4 sm:gap-6"
|
||||
>
|
||||
<StaticLink
|
||||
href="/contact"
|
||||
className="group inline-flex items-center justify-center gap-3 px-10 py-5 font-semibold text-base bg-brand text-white rounded-full transition-all duration-300 hover:bg-brand/90 min-h-[52px] touch-manipulation"
|
||||
>
|
||||
<CTAButton href="/contact" dataTestId="services-hero-primary" className="min-h-[52px]">
|
||||
{ctaPrimary}
|
||||
<ArrowUpRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
|
||||
</StaticLink>
|
||||
<StaticLink
|
||||
href="/products"
|
||||
className="inline-flex items-center justify-center gap-3 px-10 py-5 font-semibold text-base text-ink border border-border-primary rounded-full hover:border-ink/30 transition-all duration-300 min-h-[52px] touch-manipulation"
|
||||
>
|
||||
</CTAButton>
|
||||
<CTAButton href="/products" variant="secondary" dataTestId="services-hero-secondary" className="min-h-[52px]">
|
||||
{ctaSecondary}
|
||||
</StaticLink>
|
||||
</CTAButton>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
@@ -364,19 +358,12 @@ function CTASection({ pageCopy }: { pageCopy?: PageCopy | null }) {
|
||||
))}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 sm:gap-6">
|
||||
<StaticLink
|
||||
href="/contact"
|
||||
className="group inline-flex items-center justify-center gap-3 px-10 py-5 font-semibold text-base bg-brand text-white rounded-full transition-all duration-300 hover:bg-brand/90 min-h-[52px] touch-manipulation"
|
||||
>
|
||||
<CTAButton href="/contact" dataTestId="services-bottom-primary" className="min-h-[52px]">
|
||||
预约免费咨询
|
||||
<ArrowUpRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
|
||||
</StaticLink>
|
||||
<StaticLink
|
||||
href="/team"
|
||||
className="inline-flex items-center justify-center gap-3 px-10 py-5 font-semibold text-base text-ink border border-border-primary rounded-full hover:border-ink/30 transition-all duration-300 min-h-[52px] touch-manipulation"
|
||||
>
|
||||
</CTAButton>
|
||||
<CTAButton href="/team" variant="secondary" dataTestId="services-bottom-secondary" className="min-h-[52px]">
|
||||
了解我们的团队
|
||||
</StaticLink>
|
||||
</CTAButton>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user