Files
novalon-website/src/components/detail/solution-value.tsx
T
zhangxiang 80e3c48c5d feat(theme): 暗黑模式 Phase 2 批次 2 — services/service-detail/solution-value token 化
将 services-content-v3(7 处)、service-detail-content-v4(7 处)、
solution-value(1 处)的浅色 bg-white 全部迁移到 bg-bg-primary。
浅色下值完全等价(#FFFFFF)→ 浅色视觉零差异;dark 下随 token 自动
反色为 #0A0E14,section 间 bg-bg-secondary 层次交替保留。

【变更】
- services-content-v3.tsx(7 处):Hero + section + 卡片×3 + main wrapper
  (含卡片条件 className 中两个 bg-white 分支)
- service-detail-content-v4.tsx(7 处):Hero + FeaturesSection + 卡片×3 +
  CasesSection + main wrapper
- solution-value.tsx(1 处):共享 section 组件

【验证】
- type-check 0 / lint 0 errors(127 warnings 既有)
- jest 128 suites / 1623 passed
- 视觉回归 22 passed(含 /services 与 /services/software 浅色快照零 diff)
- computed-style 一次性脚本验证(已删除):
  dark: /services 与 /services/software 的 html/body/header → #0A0E14
  section 层次 [primary, secondary, primary, secondary] 自动反色正确
  light: 零深色残留

【Phase 2 剩余批次】
- 批次 3:product-detail-content-v3 + products/standalone + detail-hero 共享组件
- 批次 4:admin 全量(user决策:参与暗黑)
2026-08-31 18:31:08 +08:00

232 lines
9.3 KiB
TypeScript

'use client';
import { motion } from 'framer-motion';
import {
CheckCircle2,
Lightbulb,
Target,
TrendingUp,
} from 'lucide-react';
import type { Solution } from '@/lib/constants/solutions';
interface SolutionValueSectionProps {
solution: Solution;
}
export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
return (
<section className="relative bg-bg-primary py-20 sm:py-28 md:py-36 overflow-hidden">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative">
<motion.div
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-120px' }}
transition={{ duration: 0.8, ease: [0.22, 1, 0.36, 1] }}
className="mb-16 sm:mb-20"
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
行业方案
</span>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[0.95] max-w-3xl">
<span className="text-brand">{solution.industry}</span>量身定制
</h2>
<p className="text-lg text-text-secondary max-w-2xl mt-6 leading-relaxed">
{solution.description}
</p>
</motion.div>
{/* 痛点 + 方案:不对称布局 */}
<div className="asymmetric-wide-narrow mb-16">
{/* 行业痛点 */}
<motion.div
initial={{ opacity: 0, x: -30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.7, ease: [0.22, 1, 0.36, 1] }}
>
<div className="bain-card p-8">
<h3 className="text-xl font-bold text-ink mb-6 flex items-center gap-3">
<span className="w-10 h-10 flex items-center justify-center bg-brand text-white">
<Target className="w-5 h-5" />
</span>
行业痛点挑战
</h3>
<ul className="space-y-4">
{solution.challenges.map((challenge, index) => (
<motion.li
key={index}
initial={{ opacity: 0, y: 15 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
delay: index * 0.08,
duration: 0.45,
ease: [0.22, 1, 0.36, 1],
}}
className="flex items-start gap-3 text-text-secondary"
>
<span className="w-1.5 h-1.5 rounded-full bg-brand mt-2 shrink-0" />
<span className="text-sm leading-relaxed">{challenge}</span>
</motion.li>
))}
</ul>
</div>
</motion.div>
{/* 解决方案 */}
<motion.div
initial={{ opacity: 0, x: 30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.7, delay: 0.15, ease: [0.22, 1, 0.36, 1] }}
>
<div className="bain-card p-8">
<h3 className="text-xl font-bold text-ink mb-6 flex items-center gap-3">
<span className="w-10 h-10 flex items-center justify-center bg-accent-blue text-white">
<Lightbulb className="w-5 h-5" />
</span>
睿新致远解决方案
</h3>
<ul className="space-y-4">
{solution.solutions.map((solutionItem, index) => (
<motion.li
key={index}
initial={{ opacity: 0, y: 15 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
delay: 0.25 + index * 0.08,
duration: 0.45,
ease: [0.22, 1, 0.36, 1],
}}
className="flex items-start gap-3 text-text-secondary"
>
<CheckCircle2 className="w-4 h-4 text-accent-blue mt-0.5 shrink-0" />
<span className="text-sm leading-relaxed">{solutionItem}</span>
</motion.li>
))}
</ul>
</div>
</motion.div>
</div>
{/* 价值主张 */}
{solution.valueProposition && (
<motion.div
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.75, delay: 0.3 }}
>
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
价值主张
</span>
</div>
<h3 className="text-2xl sm:text-3xl md:text-4xl font-black text-ink tracking-tight leading-[0.95]">
{solution.valueProposition.headline}
</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{solution.valueProposition.points.map((point, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
delay: index * 0.08,
duration: 0.5,
ease: [0.22, 1, 0.36, 1],
}}
className="bain-card p-7"
>
<div className="w-12 h-12 flex items-center justify-center bg-accent-blue text-white mb-5">
<TrendingUp className="w-6 h-6" />
</div>
<h4 className="text-lg font-bold text-ink mb-2">{point.title}</h4>
<p className="text-sm text-text-secondary leading-relaxed">{point.description}</p>
</motion.div>
))}
</div>
</motion.div>
)}
{/* 产品组合 */}
{solution.suiteCombination && (
<motion.div
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.75, delay: 0.4 }}
className="mt-20"
>
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
产品组合
</span>
</div>
<h3 className="text-2xl sm:text-3xl font-black text-ink tracking-tight leading-[0.95]">
推荐搭配方案
</h3>
</div>
<div className="bain-card p-8 sm:p-10">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10">
<div>
<h4 className="text-sm font-bold text-ink mb-5 flex items-center gap-2.5">
<span className="w-8 h-8 flex items-center justify-center bg-brand text-white text-xs font-bold">
</span>
核心产品组合
</h4>
<div className="flex flex-wrap gap-3">
{solution.suiteCombination.primaryProducts.map((product) => (
<span
key={product}
className="px-4 py-2 bg-brand-soft/50 text-brand text-sm font-semibold border border-brand/20"
>
{product}
</span>
))}
</div>
</div>
<div>
<h4 className="text-sm font-bold text-ink mb-5 flex items-center gap-2.5">
<span className="w-8 h-8 flex items-center justify-center bg-accent-blue text-white text-xs font-bold">
</span>
配套专业服务
</h4>
<div className="flex flex-wrap gap-3">
{solution.suiteCombination.complementaryServices.map((service) => (
<span
key={service}
className="px-4 py-2 bg-blue-50 text-blue-700 text-sm font-semibold border border-blue-200"
>
{service}
</span>
))}
</div>
</div>
</div>
<p className="mt-8 p-5 bg-bg-secondary text-sm text-text-secondary leading-relaxed">
<strong className="text-ink">组合逻辑:</strong>{solution.suiteCombination.rationale}
</p>
</div>
</motion.div>
)}
</div>
</section>
);
}