@@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom';
1010import { motion } from 'framer-motion' ;
1111import { Timer , FileText , Layers , Lightbulb } from 'lucide-react' ;
1212import { cn } from '@/lib/utils' ;
13+ import { SPRING , fadeInUp } from '@/lib/animation/springConfig' ;
1314import { useReducedMotion } from '@/hooks/useReducedMotion' ;
1415import ModuleRitualHeader from '@/components/ui/ModuleRitualHeader' ;
1516import { DashboardCard } from '../DashboardCard' ;
@@ -25,6 +26,16 @@ const accentText: Record<string, string> = {
2526 flashcard : 'text-flashcard' , feynman : 'text-feynman' ,
2627} ;
2728
29+ const staggerContainer = {
30+ hidden : { } ,
31+ visible : { transition : { staggerChildren : 0.08 , delayChildren : 0.1 } } ,
32+ } ;
33+
34+ const heroStatVariant = {
35+ hidden : { opacity : 0 , y : 20 , scale : 0.95 } ,
36+ visible : { opacity : 1 , y : 0 , scale : 1 , transition : SPRING . gentle } ,
37+ } ;
38+
2839const quickActions = [
2940 { label : '专注' , icon : Timer , path : '/pomodoro' , accent : 'pomodoro' as const } ,
3041 { label : '笔记' , icon : FileText , path : '/notes' , accent : 'note' as const } ,
@@ -65,10 +76,12 @@ export function TodayView({
6576 ] ;
6677
6778 return (
68- < div className = "stagger-fade-in" >
79+ < div >
6980 { /* ════ 今日航线:行动导向主角 ════ */ }
7081 < section className = "relative max-w-[1100px] mx-auto px-6 pt-rhythm-md" >
71- < PlannerPanel />
82+ < motion . div { ...fadeInUp } >
83+ < PlannerPanel />
84+ </ motion . div >
7285 </ section >
7386
7487 { /* ════ 今日待办:未完成显性化(蔡格尼克效应) ════ */ }
@@ -115,7 +128,7 @@ export function TodayView({
115128
116129 { /* ════ 快捷操作 ════ */ }
117130 < section className = "relative max-w-[1100px] mx-auto px-6 mt-rhythm-md" >
118- < div className = "flex gap-3" >
131+ < motion . div className = "flex gap-3" variants = { staggerContainer } >
119132 { quickActions . map ( ( action ) => {
120133 const Icon = action . icon ;
121134 return (
@@ -129,27 +142,31 @@ export function TodayView({
129142 'text-b3 font-medium text-text-secondary hover:text-text-primary' ,
130143 'transition-all duration-beat-x2' ,
131144 ) }
145+ variants = { heroStatVariant }
132146 whileHover = { { y : - 2 } }
133147 whileTap = { { scale : 0.96 } }
148+ transition = { SPRING . default }
134149 >
135150 < Icon className = { cn ( 'w-4 h-4' , accentText [ action . accent ] ) } strokeWidth = { 1.5 } />
136151 { action . label }
137152 </ motion . button >
138153 ) ;
139154 } ) }
140- </ div >
155+ </ motion . div >
141156 </ section >
142157
143158 { /* ════ 今日统计:状态反馈 ════ */ }
144159 < section className = "relative max-w-[1100px] mx-auto px-6 mt-rhythm-md" >
145- < div className = "grid grid-cols-2 lg:grid-cols-4 gap-rhythm-sm" >
160+ < motion . div className = "grid grid-cols-2 lg:grid-cols-4 gap-rhythm-sm" variants = { staggerContainer } >
146161 { heroStats . map ( ( stat ) => {
147162 const Icon = stat . icon ;
148163 return (
149164 < motion . div
150165 key = { stat . label }
166+ variants = { heroStatVariant }
151167 whileHover = { { y : - 2 , scale : 1.02 } }
152168 whileTap = { { scale : 0.97 } }
169+ transition = { SPRING . default }
153170 >
154171 < DashboardCard
155172 accent = { stat . accent }
@@ -178,7 +195,7 @@ export function TodayView({
178195 </ motion . div >
179196 ) ;
180197 } ) }
181- </ div >
198+ </ motion . div >
182199 </ section >
183200
184201 { /* 🎯 目标进度(目标梯度效应,紧邻计划区) */ }
@@ -195,15 +212,15 @@ export function TodayView({
195212
196213 { /* ════ 知识预览:回到学习现场 ════ */ }
197214 < section className = "relative max-w-[1100px] mx-auto px-6 mt-rhythm-lg pb-rhythm-xl" >
198- < div className = "mb-rhythm-sm" >
215+ < motion . div className = "mb-rhythm-sm" { ... fadeInUp } >
199216 < ModuleRitualHeader
200217 title = "知识预览"
201218 note = "最近的学习足迹"
202219 sealChar = "星"
203220 sealColor = "#40AB92"
204221 compact
205222 />
206- </ div >
223+ </ motion . div >
207224
208225 { isLoading ? (
209226 < div className = "grid grid-cols-2 lg:grid-cols-3 gap-rhythm-sm" >
@@ -216,11 +233,18 @@ export function TodayView({
216233 ) ) }
217234 </ div >
218235 ) : knowledgeCards . length > 0 ? (
219- < div className = "grid grid-cols-2 lg:grid-cols-3 gap-rhythm-sm" >
236+ < motion . div
237+ className = "grid grid-cols-2 lg:grid-cols-3 gap-rhythm-sm"
238+ variants = { staggerContainer }
239+ initial = "hidden"
240+ animate = "visible"
241+ >
220242 { knowledgeCards . map ( ( card , i ) => (
221- < KnowledgePreviewCard key = { card . id } card = { card } index = { i } />
243+ < motion . div key = { card . id } variants = { heroStatVariant } >
244+ < KnowledgePreviewCard card = { card } index = { i } />
245+ </ motion . div >
222246 ) ) }
223- </ div >
247+ </ motion . div >
224248 ) : (
225249 < div className = "text-center py-rhythm-xl" >
226250 < p className = "text-b2 text-text-tertiary" >
0 commit comments