refactor(motion): 收敛末批 P1 入场时长与变量递增 stagger 步进
动效合规专项(Task #16)收尾。
改动:
- page-transition.tsx:入场 duration 0.4/0.5 → 0.3(末处真 P1,由 client-layout 消费)
- 17 文件 21 处子元素 stagger 步进 80/100ms → 60ms
(CONTEXT.md 原则4「子元素 stagger 30-60ms」;属已批准决策 04e91e3 的漏网,
因当时审计脚本看不见 delay: i * N 的乘法写法)
- 审计脚本补盲区:新增变量递增 stagger 识别 + 明细表(此前漏掉全站 33 处)
- 审计脚本新增 NON_ENTRANCE 排除:flip-clock 机械翻转、design-system 死代码令牌
- delay 判据自我纠正:硬禁令约束的是 duration(动效时长),
delay 属调度而非动效本身,一律判 P2(偏离指引),不得判 P0
门禁(全绿):
- tsc 0 error
- eslint 0 error(50 warnings 均为既有)
- jest 130/130 套件,1573 通过 / 2 跳过 / 0 失败
- 运行时冒烟 16/16 PASS(8 路由 × 浅深双版,0 控制台报错)
- 审计:P0=0 · P1=0 · stagger 步进 P2=0
This commit is contained in:
@@ -134,7 +134,7 @@ function MetricsStrip({ data }: { data: AboutData }) {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: i * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: i * 0.06, ease: EASE_OUT }}
|
||||
className="text-center lg:text-left"
|
||||
>
|
||||
<div className={`text-3xl sm:text-4xl md:text-5xl font-black tracking-tight mb-2 ${i === 0 ? 'text-brand' : 'text-ink'}`}>
|
||||
@@ -264,7 +264,7 @@ function MilestonesSection({ data }: { data: AboutData }) {
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.06, ease: EASE_OUT }}
|
||||
className="relative pl-8 sm:pl-12 md:pl-16 pb-10 sm:pb-12 md:pb-14 last:pb-0"
|
||||
>
|
||||
<div className="absolute left-0 top-2 bottom-0 w-px bg-border-primary last:hidden" />
|
||||
|
||||
@@ -207,7 +207,7 @@ export default function CasesContentV3({
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: i * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: i * 0.06, ease: EASE_OUT }}
|
||||
className="text-center lg:text-left"
|
||||
>
|
||||
<div className={`text-3xl sm:text-4xl md:text-5xl font-black tracking-tight mb-2 ${
|
||||
|
||||
@@ -23,7 +23,7 @@ function NewsCard({ newsItem, index }: { newsItem: NewsItem; index: number }) {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
>
|
||||
<StaticLink
|
||||
href={`/news/${newsItem.id}`}
|
||||
|
||||
@@ -15,7 +15,7 @@ function RelatedNewsCard({ news, index }: { news: NewsItem; index: number }) {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.1, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
>
|
||||
<a
|
||||
href={`/news/${news.id}`}
|
||||
|
||||
@@ -96,7 +96,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06 }}
|
||||
className="rounded-lg border border-border-primary bg-bg-secondary p-4"
|
||||
>
|
||||
<div className="mb-2 flex h-8 w-8 items-center justify-center rounded-lg bg-bg-primary text-text-muted">
|
||||
|
||||
@@ -227,7 +227,7 @@ function ProcessSection({ service }: { service: Service }) {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
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-150"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -209,7 +209,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: i * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: i * 0.06, ease: EASE_OUT }}
|
||||
>
|
||||
<StaticLink
|
||||
href={`/services/${service.id}`}
|
||||
|
||||
@@ -129,7 +129,7 @@ function SolutionCard({ solution, index, products, featured = false }: { solutio
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
>
|
||||
<StaticLink
|
||||
href={`/solutions/${solution.id}`}
|
||||
|
||||
@@ -69,7 +69,7 @@ function StrengthCard({ strength, index }: { strength: StrengthData; index: numb
|
||||
initial={shouldReduceMotion ? {} : { opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
whileHover={{ y: -6 }}
|
||||
>
|
||||
<div className="absolute top-0 left-0 bottom-0 w-1 bg-brand scale-y-0 group-hover:scale-y-100 transition-transform duration-150 origin-top" />
|
||||
@@ -104,7 +104,7 @@ function CultureCard({ culture, index }: { culture: CultureData; index: number }
|
||||
initial={shouldReduceMotion ? {} : { opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-80px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.1, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
whileHover={{ y: -8 }}
|
||||
>
|
||||
<div className="absolute top-0 left-0 right-0 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
|
||||
|
||||
@@ -49,7 +49,7 @@ export function MethodologyFramework({
|
||||
initial={{ opacity: 0, x: -30 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: '-50px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.08, ease: EASE_OUT }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06, ease: EASE_OUT }}
|
||||
>
|
||||
<div className="flex gap-6 lg:gap-10">
|
||||
<div className="flex flex-col items-center pt-2">
|
||||
|
||||
@@ -14,7 +14,7 @@ export function CaseStudyCard({ study, index }: CaseStudyCardProps) {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-50px' }}
|
||||
transition={{ duration: 0.3, delay: index * 0.1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.06 }}
|
||||
className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md"
|
||||
>
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
|
||||
@@ -103,7 +103,7 @@ export function DetailTrustSection({
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
delay: index * 0.08,
|
||||
delay: index * 0.06,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
className="bain-card p-8 sm:p-10"
|
||||
@@ -140,7 +140,7 @@ export function DetailTrustSection({
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
delay: index * 0.08,
|
||||
delay: index * 0.06,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -134,7 +134,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{
|
||||
delay: index * 0.08,
|
||||
delay: index * 0.06,
|
||||
duration: 0.3,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{
|
||||
delay: index * 0.08,
|
||||
delay: index * 0.06,
|
||||
duration: 0.3,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
@@ -141,7 +141,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{
|
||||
delay: index * 0.08,
|
||||
delay: index * 0.06,
|
||||
duration: 0.3,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
|
||||
@@ -67,7 +67,7 @@ export function SocialProofSection() {
|
||||
initial={shouldReduceMotion ? {} : { opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.1, ease: [0.16, 1, 0.3, 1] }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.06, ease: [0.16, 1, 0.3, 1] }}
|
||||
className="text-center group"
|
||||
>
|
||||
<div className="w-12 h-12 rounded-full bg-[var(--color-brand)]/5 flex items-center justify-center mx-auto mb-4 group-hover:bg-[var(--color-brand)]/10 transition-colors duration-300">
|
||||
|
||||
@@ -83,7 +83,7 @@ export function WhyUsSection() {
|
||||
initial={shouldReduceMotion ? {} : { opacity: 0, y: 24, scale: 0.96 }}
|
||||
whileInView={{ opacity: 1, y: 0, scale: 1 }}
|
||||
viewport={{ once: true, margin: '-60px' }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.08, ease: [0.16, 1, 0.3, 1] }}
|
||||
transition={{ duration: 0.3, delay: idx * 0.06, ease: [0.16, 1, 0.3, 1] }}
|
||||
className="relative group p-6 md:p-8 rounded-2xl bg-[var(--color-bg-primary)] border border-[var(--color-border-primary)] hover:border-[rgba(var(--color-brand-rgb),0.25)] transition-all duration-300"
|
||||
>
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
|
||||
@@ -16,7 +16,7 @@ const pageVariants = {
|
||||
y: 0,
|
||||
scale: 1,
|
||||
transition: {
|
||||
duration: 0.4,
|
||||
duration: 0.3,
|
||||
ease: [0.25, 1, 0.5, 1] as const,
|
||||
staggerChildren: 0.05,
|
||||
},
|
||||
@@ -71,8 +71,8 @@ const sectionVariants = {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: i * 0.08,
|
||||
duration: 0.5,
|
||||
delay: i * 0.06,
|
||||
duration: 0.3,
|
||||
ease: [0.25, 1, 0.5, 1] as const,
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user