需要
好的,我把 quiz-funnel.tsx 的样式按模块拆解给你:
{/* 整个测算区块 */}
<section id="quiz" className="bg-gradient-to-b from-[#eef4fa] to-[#e3ecf6] px-5 py-20 md:px-10 md:py-28">
<div className="mx-auto max-w-2xl">
{/* 标题区 */}
<div className="text-center">
<span className="text-xs font-semibold uppercase tracking-[0.3em] text-[#4a6fd4]">枕高测算</span>
<h2 className="mt-3 text-balance text-3xl font-extrabold tracking-tight text-[#15233a] md:text-4xl">
30 秒,找到适合你的枕头高度
</h2>
</div>
{/* 白色卡片容器 */}
<div className="mt-10 rounded-3xl bg-white p-6 shadow-[0_30px_70px_-40px_rgba(21,35,58,0.5)] md:p-10">
{/* 内容区域 */}
</div>
</div>
</section>{/* 开始页 - 居中布局 */}
<div className="flex flex-col items-center text-center">
{/* 说明文字 */}
<p className="max-w-md text-pretty text-sm leading-relaxed text-[#15233a]/65 md:text-base">
回答 6 个简单的小问题,我们会根据你的睡姿、肩宽和睡眠习惯,为你推荐最合适的枕面高度。无需留下任何信息。
</p>
{/* 开始按钮 - 蓝色圆角 + 深阴影 */}
<button
onClick={start}
className="mt-7 rounded-full bg-[#4a6fd4] px-10 py-4 text-base font-bold text-white shadow-[0_12px_30px_-10px_rgba(74,111,212,0.7)] transition hover:bg-[#3a5cc0]"
>
开始测算
</button>
{/* 提示文字 */}
<p className="mt-3 text-xs text-[#15233a]/40">约 30 秒 · 6 道选择题</p>
</div><div>
{/* 进度条 */}
<div className="mb-6 flex items-center gap-3">
{/* 进度槽 */}
<div className="h-1.5 flex-1 overflow-hidden rounded-full bg-slate-100">
{/* 进度填充 - 动态宽度 */}
<div
className="h-full rounded-full bg-[#4a6fd4] transition-all duration-300"
style={{ width: `${((step + 1) / total) * 100}%` }}
/>
</div>
{/* 进度数字 */}
<span className="text-xs font-semibold tabular-nums text-[#15233a]/50">
{step + 1}/{total}
</span>
</div>
{/* 问题标题 */}
<h3 className="text-xl font-bold text-[#15233a] md:text-2xl">{current.question}</h3>
{/* 选项列表 */}
<div className="mt-6 grid gap-3">
{current.options.map((opt) => (
<button
key={opt.label}
onClick={() => choose(opt)}
className="group flex items-center justify-between rounded-2xl border border-slate-200 bg-white px-5 py-4 text-left transition-all hover:border-[#4a6fd4] hover:bg-[#4a6fd4]/5"
>
{/* 左侧文字 */}
<span>
<span className="block text-base font-bold text-[#15233a]">{opt.label}</span>
{opt.sub && <span className="mt-0.5 block text-xs text-[#15233a]/50">{opt.sub}</span>}
</span>
{/* 右侧箭头圆圈 - hover变色 */}
<span className="flex h-7 w-7 flex-none items-center justify-center rounded-full border border-slate-200 text-[#4a6fd4] transition group-hover:border-[#4a6fd4] group-hover:bg-[#4a6fd4] group-hover:text-white">
→
</span>
</button>
))}
</div>
{/* 上一题按钮 */}
{step > 0 && (
<button
onClick={() => setStep(step - 1)}
className="mt-5 text-sm font-medium text-[#15233a]/40 transition hover:text-[#15233a]/70"
>
← 上一题
</button>
)}
</div><div className="flex flex-col items-center py-8 text-center">
{/* 旋转加载圈 */}
<div className="relative h-16 w-16">
{/* 底层灰圈 */}
<span className="absolute inset-0 rounded-full border-4 border-[#4a6fd4]/15" />
{/* 旋转蓝圈 */}
<span className="absolute inset-0 animate-spin rounded-full border-4 border-transparent border-t-[#4a6fd4]" />
</div>
{/* 分析文案轮播 */}
<div className="mt-6 h-6">
{ANALYZE_STEPS.map((t, i) => (
<p
key={t}
className="text-base font-semibold text-[#15233a] transition-opacity duration-300"
style={{ display: i === analyzeStep ? "block" : "none" }}
>
{t}
</p>
))}
</div>
{/* 步骤指示点 */}
<div className="mt-5 flex gap-1.5">
{ANALYZE_STEPS.map((_, i) => (
<span
key={i}
className="h-1.5 w-8 rounded-full transition-colors duration-300"
style={{ backgroundColor: i <= analyzeStep ? "#4a6fd4" : "#e2e8f0" }}
/>
))}
</div>
</div>{/* 入场动画 */}
<div className="animate-[riseIn_0.5s_ease]">
{/* 推荐标题区 */}
<div className="text-center">
<p className="text-sm font-semibold uppercase tracking-wide text-[#4a6fd4]">为你推荐</p>
{/* 推荐规格卡片 */}
<div className="mt-3 flex items-center justify-center gap-4">
{/* 左侧蓝色方块 - 高度+名称 */}
<div className="flex h-20 w-20 flex-col items-center justify-center rounded-2xl bg-[#4a6fd4] text-white">
<span className="text-2xl font-extrabold leading-none">{rec.height}</span>
<span className="mt-1 text-[10px] tracking-wide">{rec.name}</span>
</div>
{/* 右侧文字说明 */}
<div className="text-left">
<p className="text-xl font-extrabold text-[#15233a]">{rec.target}</p>
<p className="mt-1 max-w-[14rem] text-sm leading-relaxed text-[#15233a]/60">{rec.desc}</p>
</div>
</div>
</div>
{/* 推荐理由卡片 */}
<div className="mt-7 space-y-3 rounded-2xl bg-[#f6f9fc] p-5">
{reasons.map((r, i) => (
<div key={i} className="flex gap-3">
{/* 绿色勾选圆圈 */}
<span className="flex h-5 w-5 flex-none items-center justify-center rounded-full bg-[#0e9f7e] text-[11px] font-bold text-white">
✓
</span>
<p className="text-sm leading-relaxed text-[#15233a]/75">{r}</p>
</div>
))}
</div>
{/* CTA按钮组 */}
<div className="mt-7 flex flex-col gap-3 sm:flex-row">
{/* 主按钮 - 蓝色填充 */}
<button
onClick={() => scrollToId("buy")}
className="flex-1 rounded-xl bg-[#4a6fd4] py-4 text-base font-bold text-white transition hover:bg-[#3a5cc0]"
>
选择 {rec.name}({rec.height})
</button>
{/* 副按钮 - 边框样式 */}
<button
onClick={() => scrollToId("specs")}
className="rounded-xl border border-slate-200 px-6 py-4 text-base font-semibold text-[#15233a]/70 transition hover:border-[#4a6fd4]/40 hover:text-[#15233a]"
>
对比所有高度
</button>
</div>
{/* 重新测算链接 */}
<button
onClick={restart}
className="mt-4 w-full text-center text-sm font-medium text-[#15233a]/40 transition hover:text-[#15233a]/70"
>
重新测算
</button>
</div>@keyframes riseIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}样式要点总结:
| 元素 | 关键样式 |
|---|---|
| 容器背景 | 渐变 from-[#eef4fa] to-[#e3ecf6] |
| 白色卡片 | rounded-3xl + 深阴影 shadow-[0_30px_70px_-40px_rgba(21,35,58,0.5)] |
| 进度条 | h-1.5 rounded-full + 蓝色填充 |
| 选项按钮 | rounded-2xl border + hover边框变蓝 |
| 加载动画 | animate-spin border-t-[#4a6fd4] |
| 推荐卡片 | 蓝色方块 rounded-2xl bg-[#4a6fd4] |
| 理由列表 | 绿色勾选 bg-[#0e9f7e] |
产品购买区 (floating-buy.tsx)你给我样式的代码了吗
是的,我之前给了完整代码,但没有像 quiz-funnel 那样按模块拆解样式。让我把 floating-buy.tsx 的样式按模块拆解给你:
<section id="buy" className="relative w-full overflow-hidden">
{/* 顶部渐变过渡 */}
<div className="h-8 bg-gradient-to-b from-[#eef4fa] to-[#dce8f5] md:h-12" />
{/* 主内容区 - 蓝色渐变背景 */}
<div className="relative bg-gradient-to-b from-[#dce8f5] via-[#c8daf0] to-[#b8ceeb]">
{/* 环境光晕装饰 */}
<div className="pointer-events-none absolute left-1/4 top-1/4 h-[400px] w-[400px] -translate-x-1/2 rounded-full bg-white/40 blur-[100px]" />
<div className="pointer-events-none absolute bottom-1/4 right-1/4 h-[300px] w-[300px] translate-x-1/2 rounded-full bg-[#4a6fd4]/10 blur-[80px]" />
<div className="relative z-10 mx-auto max-w-6xl px-5 py-8 md:px-8 md:py-16">
{/* 内容 */}
</div>
</div>
{/* 底部渐变过渡 */}
<div className="h-8 bg-gradient-to-b from-[#b8ceeb] to-[#15233a] md:h-12" />
</section>{/* 推荐提示 - 仅在完成测算后显示 */}
{recommended && (
<div className="mb-4 flex justify-center md:mb-6 lg:justify-start">
<span className="inline-flex items-center gap-2 rounded-full bg-[#4a6fd4] px-3 py-1.5 text-xs font-medium text-white shadow-lg shadow-[#4a6fd4]/25 md:px-4 md:py-2">
<Sparkles className="h-3 w-3 md:h-3.5 md:w-3.5" />
已根据测算推荐 {specs.find((s) => s.id === recommended)?.name}
</span>
</div>
)}{/* 左侧产品区 - 占45%宽度 */}
<div className="relative flex w-[45%] items-center justify-center py-8">
<div className="relative">
{/* 底部阴影 */}
<div className="absolute bottom-0 left-1/2 h-8 w-4/5 -translate-x-1/2 translate-y-6 rounded-[100%] bg-[#15233a]/20 blur-2xl" />
{/* 产品图 */}
<img
src="/product-float.png"
alt="颈椎支撑枕"
className="relative z-10 w-full max-w-sm drop-shadow-2xl transition-transform duration-700 hover:scale-[1.03]"
/>
{/* 高度标签 */}
<div className="absolute -right-2 top-4 rounded-full bg-white px-3 py-1.5 text-sm font-bold text-[#15233a] shadow-lg">
{activeSpec.height}cm
</div>
</div>
</div>{/* 右侧选择器区 - 占55%宽度 */}
<div className="w-[55%]">
<h2 className="text-2xl font-bold tracking-tight text-[#15233a]">选择适合你的高度</h2>
<p className="mt-1.5 text-sm text-[#15233a]/60">不同身高体型,需要不同的支撑高度</p>
{/* 柱状图容器 */}
<div className="mt-8 flex items-end gap-4">
{specs.map((spec) => {
const isActive = spec.id === selected
const isRecommended = spec.id === recommended
const barHeight = (spec.height / maxHeight) * 120
return (
<button
key={spec.id}
onClick={() => setSelected(spec.id)}
className={`group relative flex flex-1 flex-col items-center rounded-2xl border-2 px-3 pb-4 pt-3 transition-all duration-300 ${
isActive
? "border-[#4a6fd4] bg-white shadow-xl shadow-[#4a6fd4]/10"
: "border-transparent bg-white/40 hover:bg-white/70"
}`}
>
{/* 推荐标签 */}
{isRecommended && (
<span className="absolute -top-2.5 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-full bg-[#4a6fd4] px-2.5 py-0.5 text-[10px] font-bold text-white shadow">
推荐
</span>
)}
{/* 柱状图区域 */}
<div className="relative mb-3 flex h-32 w-full items-end justify-center">
{/* 柱状图 - 动态高度 */}
<div
className={`w-12 rounded-t-lg transition-all duration-500 ${
isActive
? "bg-gradient-to-t from-[#4a6fd4] to-[#8fb0ff]"
: "bg-[#15233a]/10 group-hover:bg-[#15233a]/20"
}`}
style={{ height: barHeight }}
/>
{/* 选中勾选 */}
{isActive && (
<div className="absolute right-1 top-0 flex h-5 w-5 items-center justify-center rounded-full bg-[#4a6fd4]">
<Check className="h-3 w-3 text-white" strokeWidth={3} />
</div>
)}
</div>
{/* 高度数值 */}
<span className={`text-2xl font-bold transition-colors ${isActive ? "text-[#4a6fd4]" : "text-[#15233a]/60"}`}>
{spec.height}
<span className="text-sm font-normal">cm</span>
</span>
{/* 规格名称 */}
<span className={`mt-0.5 text-xs font-medium ${isActive ? "text-[#15233a]" : "text-[#15233a]/50"}`}>
{spec.name}
</span>
{/* 价格 */}
<span className={`mt-1 text-sm font-bold ${isActive ? "text-[#15233a]" : "text-[#15233a]/40"}`}>
¥{spec.price}
</span>
</button>
)
})}
</div>
</div>{/* 详情卡片 - 毛玻璃效果 */}
<div className="mt-6 rounded-2xl bg-white/70 p-5 backdrop-blur-sm">
<div className="grid grid-cols-3 gap-6">
{/* 睡姿 */}
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-[#4a6fd4]/10">
<Moon className="h-5 w-5 text-[#4a6fd4]" />
</div>
<div>
<p className="text-[10px] font-medium uppercase tracking-wider text-[#15233a]/40">适合睡姿</p>
<p className="text-sm font-semibold text-[#15233a]">{activeSpec.posture}</p>
</div>
</div>
{/* 体型 */}
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-[#4a6fd4]/10">
<User className="h-5 w-5 text-[#4a6fd4]" />
</div>
<div>
<p className="text-[10px] font-medium uppercase tracking-wider text-[#15233a]/40">适合体型</p>
<p className="text-sm font-semibold text-[#15233a]">{activeSpec.bodyType}</p>
</div>
</div>
{/* 体重 */}
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-[#4a6fd4]/10">
<Scale className="h-5 w-5 text-[#4a6fd4]" />
</div>
<div>
<p className="text-[10px] font-medium uppercase tracking-wider text-[#15233a]/40">适合体重</p>
<p className="text-sm font-semibold text-[#15233a]">{activeSpec.weight}</p>
</div>
</div>
</div>
</div><div className="mt-6 flex items-center justify-between">
{/* 左侧价格 */}
<div>
<div className="flex items-baseli
<AssistantMessageContentPart partEncoded="eyJjcmVhdGVkQXQiOjE3ODA2NTQyNjExNDQsImZpbmlzaGVkQXQiOjE3ODA2NTQyNjExNDQsImxhc3RQYXJ0U2VudEF0IjoxNzgwNjU0MjYxMTQ0LCJpZCI6InppM290cThLemd2TUZZYnkiLCJ0eXBlIjoidGFzay1zdG9wcGVkLXYxIiwicGFydHMiOlt7InR5cGUiOiJtYW51YWxseS1zdG9wcGVkLW9uLWNsaWVudCJ9XX0=" />
移动端呢