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决策:参与暗黑)
This commit is contained in:
@@ -14,7 +14,7 @@ function DetailHero({ service }: { service: Service }) {
|
||||
const firstBenefit = service.benefits?.[0] || '效率提升 40%';
|
||||
|
||||
return (
|
||||
<section className="relative min-h-[85vh] flex items-center overflow-hidden bg-white">
|
||||
<section className="relative min-h-[85vh] flex items-center overflow-hidden bg-bg-primary">
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10 w-full py-28 sm:py-36 md:py-44 lg:py-56">
|
||||
<div className="max-w-4xl">
|
||||
<motion.h1
|
||||
@@ -147,7 +147,7 @@ function OverviewSection({ service }: { service: Service }) {
|
||||
|
||||
function FeaturesSection({ service }: { service: Service }) {
|
||||
return (
|
||||
<section className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-white">
|
||||
<section className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-bg-primary">
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
@@ -176,7 +176,7 @@ function FeaturesSection({ service }: { service: Service }) {
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.6, delay: index * 0.06, ease: EASE_OUT }}
|
||||
className="group relative p-8 sm:p-10 transition-all duration-500 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-white"
|
||||
className="group relative p-8 sm:p-10 transition-all duration-500 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-bg-primary"
|
||||
>
|
||||
<div className="relative z-10">
|
||||
<Icon className="w-8 h-8 mb-6 text-brand" />
|
||||
@@ -230,7 +230,7 @@ function ProcessSection({ service }: { service: Service }) {
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.6, delay: index * 0.08, ease: EASE_OUT }}
|
||||
className="relative group p-6 sm:p-8 bg-white hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 transition-all duration-500"
|
||||
className="relative group p-6 sm:p-8 bg-bg-primary hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 transition-all duration-500"
|
||||
>
|
||||
<div
|
||||
className="w-2 h-2 rounded-full mb-6"
|
||||
@@ -255,7 +255,7 @@ function CaseStudiesSection({ caseStudies = [] }: { caseStudies?: CaseStudy[] })
|
||||
if (caseStudies.length === 0) return null;
|
||||
|
||||
return (
|
||||
<section id="cases" className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-white">
|
||||
<section id="cases" className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-bg-primary">
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
@@ -278,7 +278,7 @@ function CaseStudiesSection({ caseStudies = [] }: { caseStudies?: CaseStudy[] })
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.6, delay: i * 0.08, ease: EASE_OUT }}
|
||||
className="group relative block p-8 sm:p-10 transition-all duration-500 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-white border border-transparent hover:border-border-primary"
|
||||
className="group relative block p-8 sm:p-10 transition-all duration-500 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-bg-primary border border-transparent hover:border-border-primary"
|
||||
>
|
||||
|
||||
<div className="relative z-10">
|
||||
@@ -348,7 +348,7 @@ function CTASection() {
|
||||
|
||||
export default function ServiceDetailContentV4({ service }: { service: Service }) {
|
||||
return (
|
||||
<main className="min-h-screen bg-white text-ink">
|
||||
<main className="min-h-screen bg-bg-primary text-ink">
|
||||
<DetailHero service={service} />
|
||||
<OverviewSection service={service} />
|
||||
<FeaturesSection service={service} />
|
||||
|
||||
@@ -81,7 +81,7 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
|
||||
const ctaSecondary = (pageCopy?.servicesCtaSecondary as string) || '查看产品矩阵';
|
||||
|
||||
return (
|
||||
<section className="relative min-h-[85vh] flex items-center overflow-hidden bg-white">
|
||||
<section className="relative min-h-[85vh] flex items-center overflow-hidden bg-bg-primary">
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10 w-full py-28 sm:py-36 md:py-44 lg:py-56">
|
||||
<div className="max-w-4xl">
|
||||
<motion.h1
|
||||
@@ -205,7 +205,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
|
||||
key={service.id}
|
||||
data-testid={`service-card-${service.id}`}
|
||||
data-featured={i === 0 ? 'true' : 'false'}
|
||||
className={i === 0 ? 'md:col-span-2 bg-white' : 'md:col-span-1 bg-white'}
|
||||
className={i === 0 ? 'md:col-span-2 bg-bg-primary' : 'md:col-span-1 bg-bg-primary'}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
@@ -213,7 +213,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
|
||||
>
|
||||
<StaticLink
|
||||
href={`/services/${service.id}`}
|
||||
className="group relative block p-8 sm:p-10 md:p-12 transition-all duration-300 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-white border border-transparent hover:border-border-primary after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:origin-left after:scale-x-0 after:bg-brand after:transition-transform after:duration-300 group-hover:after:scale-x-100"
|
||||
className="group relative block p-8 sm:p-10 md:p-12 transition-all duration-300 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-bg-primary border border-transparent hover:border-border-primary after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:origin-left after:scale-x-0 after:bg-brand after:transition-transform after:duration-300 group-hover:after:scale-x-100"
|
||||
>
|
||||
<div className="relative z-10">
|
||||
<h3 className="text-xl sm:text-2xl font-bold text-ink group-hover:text-brand transition-colors duration-300 mb-3">
|
||||
@@ -258,7 +258,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
|
||||
|
||||
function ProcessModesSection() {
|
||||
return (
|
||||
<section className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-white">
|
||||
<section className="relative py-20 sm:py-28 md:py-36 lg:py-44 overflow-hidden bg-bg-primary">
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
|
||||
<div className="grid lg:grid-cols-12 gap-12 sm:gap-16 md:gap-20">
|
||||
{/* Process */}
|
||||
@@ -310,7 +310,7 @@ function ProcessModesSection() {
|
||||
{SERVICE_MODES.map((mode) => (
|
||||
<div
|
||||
key={mode.title}
|
||||
className="group relative p-6 sm:p-7 border border-border-primary bg-white hover:bg-bg-secondary hover:border-brand/20 hover:shadow-md transition-all duration-300"
|
||||
className="group relative p-6 sm:p-7 border border-border-primary bg-bg-primary hover:bg-bg-secondary hover:border-brand/20 hover:shadow-md transition-all duration-300"
|
||||
>
|
||||
<div className="relative z-10">
|
||||
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors duration-300">
|
||||
@@ -373,7 +373,7 @@ function CTASection({ pageCopy }: { pageCopy?: PageCopy | null }) {
|
||||
|
||||
export default function ServicesContentV3({ services, pageCopy }: { services?: Service[]; pageCopy?: PageCopy | null }) {
|
||||
return (
|
||||
<main className="bg-white text-ink">
|
||||
<main className="bg-bg-primary text-ink">
|
||||
<HeroSection pageCopy={pageCopy} />
|
||||
<ServicesGridSection services={services} pageCopy={pageCopy} />
|
||||
<ProcessModesSection />
|
||||
|
||||
@@ -15,7 +15,7 @@ interface SolutionValueSectionProps {
|
||||
|
||||
export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
|
||||
return (
|
||||
<section className="relative bg-white py-20 sm:py-28 md:py-36 overflow-hidden">
|
||||
<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 }}
|
||||
|
||||
Reference in New Issue
Block a user