|
| 1 | +import { useState, useEffect } from 'react' |
| 2 | +import { Box, Typography, Paper } from '@mui/material' |
| 3 | +import { styled, keyframes } from '@mui/material/styles' |
| 4 | +import MusicNoteIcon from '@mui/icons-material/MusicNote' |
| 5 | +import SmartToyIcon from '@mui/icons-material/SmartToy' |
| 6 | +import CheckCircleIcon from '@mui/icons-material/CheckCircle' |
| 7 | +import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh' |
| 8 | +import PianoIcon from '@mui/icons-material/Piano' |
| 9 | + |
| 10 | +// Animation keyframes |
| 11 | +const pulse = keyframes` |
| 12 | + 0%, 100% { transform: scale(1); opacity: 1; } |
| 13 | + 50% { transform: scale(1.05); opacity: 0.8; } |
| 14 | +` |
| 15 | + |
| 16 | +const flow = keyframes` |
| 17 | + 0% { transform: translateX(-100%); } |
| 18 | + 100% { transform: translateX(100%); } |
| 19 | +` |
| 20 | + |
| 21 | +const glow = keyframes` |
| 22 | + 0%, 100% { box-shadow: 0 0 5px #D35400, 0 0 10px #D35400; } |
| 23 | + 50% { box-shadow: 0 0 20px #D35400, 0 0 30px #F1C40F; } |
| 24 | +` |
| 25 | + |
| 26 | +const float = keyframes` |
| 27 | + 0%, 100% { transform: translateY(0); } |
| 28 | + 50% { transform: translateY(-10px); } |
| 29 | +` |
| 30 | + |
| 31 | +const dataFlow = keyframes` |
| 32 | + 0% { stroke-dashoffset: 100; } |
| 33 | + 100% { stroke-dashoffset: 0; } |
| 34 | +` |
| 35 | + |
| 36 | +const AnimatedBox = styled(Box)(({ theme, delay = 0 }) => ({ |
| 37 | + animation: `${pulse} 2s ease-in-out ${delay}s infinite`, |
| 38 | +})) |
| 39 | + |
| 40 | +const FlowingLine = styled(Box)({ |
| 41 | + position: 'absolute', |
| 42 | + height: '4px', |
| 43 | + background: 'linear-gradient(90deg, transparent, #F1C40F, transparent)', |
| 44 | + animation: `${flow} 2s linear infinite`, |
| 45 | +}) |
| 46 | + |
| 47 | +const StepCard = styled(Paper)(({ theme, active }) => ({ |
| 48 | + padding: '16px', |
| 49 | + textAlign: 'center', |
| 50 | + background: active |
| 51 | + ? 'linear-gradient(135deg, #FFF8E1 0%, #FFECB3 100%)' |
| 52 | + : 'linear-gradient(135deg, #ffffff 0%, #f5f5f5 100%)', |
| 53 | + border: active ? '2px solid #D35400' : '1px solid #e0e0e0', |
| 54 | + borderRadius: '12px', |
| 55 | + transition: 'all 0.3s ease', |
| 56 | + animation: active ? `${glow} 2s ease-in-out infinite` : 'none', |
| 57 | + '&:hover': { |
| 58 | + transform: 'translateY(-5px)', |
| 59 | + boxShadow: '0 8px 25px rgba(211, 84, 0, 0.2)', |
| 60 | + }, |
| 61 | +})) |
| 62 | + |
| 63 | +const steps = [ |
| 64 | + { |
| 65 | + icon: MusicNoteIcon, |
| 66 | + label: 'MIDI Input', |
| 67 | + description: 'Raw musical data', |
| 68 | + color: '#1976d2' |
| 69 | + }, |
| 70 | + { |
| 71 | + icon: AutoFixHighIcon, |
| 72 | + label: 'Preprocessing', |
| 73 | + description: 'NoteSequences', |
| 74 | + color: '#388e3c' |
| 75 | + }, |
| 76 | + { |
| 77 | + icon: SmartToyIcon, |
| 78 | + label: 'LSTM Training', |
| 79 | + description: 'Neural Network', |
| 80 | + color: '#d32f2f' |
| 81 | + }, |
| 82 | + { |
| 83 | + icon: CheckCircleIcon, |
| 84 | + label: 'Validation', |
| 85 | + description: 'Raga Grammar', |
| 86 | + color: '#7b1fa2' |
| 87 | + }, |
| 88 | + { |
| 89 | + icon: PianoIcon, |
| 90 | + label: 'Generation', |
| 91 | + description: 'Real-time Output', |
| 92 | + color: '#D35400' |
| 93 | + }, |
| 94 | +] |
| 95 | + |
| 96 | +function AnimatedWorkflow() { |
| 97 | + const [activeStep, setActiveStep] = useState(0) |
| 98 | + |
| 99 | + useEffect(() => { |
| 100 | + const interval = setInterval(() => { |
| 101 | + setActiveStep((prev) => (prev + 1) % steps.length) |
| 102 | + }, 2000) |
| 103 | + return () => clearInterval(interval) |
| 104 | + }, []) |
| 105 | + |
| 106 | + return ( |
| 107 | + <Box sx={{ width: '100%', py: 3 }}> |
| 108 | + {/* Title */} |
| 109 | + <Typography |
| 110 | + variant="h6" |
| 111 | + sx={{ |
| 112 | + textAlign: 'center', |
| 113 | + mb: 4, |
| 114 | + color: '#D35400', |
| 115 | + fontWeight: 600, |
| 116 | + animation: `${float} 3s ease-in-out infinite`, |
| 117 | + }} |
| 118 | + > |
| 119 | + 🎵 DeepRaaga AI Pipeline in Action |
| 120 | + </Typography> |
| 121 | + |
| 122 | + {/* Workflow Steps */} |
| 123 | + <Box |
| 124 | + sx={{ |
| 125 | + display: 'flex', |
| 126 | + justifyContent: 'space-between', |
| 127 | + alignItems: 'center', |
| 128 | + gap: 2, |
| 129 | + flexWrap: 'wrap', |
| 130 | + position: 'relative', |
| 131 | + }} |
| 132 | + > |
| 133 | + {/* Connection Lines */} |
| 134 | + <svg |
| 135 | + style={{ |
| 136 | + position: 'absolute', |
| 137 | + top: '50%', |
| 138 | + left: '10%', |
| 139 | + width: '80%', |
| 140 | + height: '4px', |
| 141 | + zIndex: 0, |
| 142 | + pointerEvents: 'none', |
| 143 | + }} |
| 144 | + > |
| 145 | + <defs> |
| 146 | + <linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%"> |
| 147 | + <stop offset="0%" stopColor="#D35400" stopOpacity="0.3" /> |
| 148 | + <stop offset="50%" stopColor="#F1C40F" stopOpacity="1" /> |
| 149 | + <stop offset="100%" stopColor="#D35400" stopOpacity="0.3" /> |
| 150 | + </linearGradient> |
| 151 | + </defs> |
| 152 | + <line |
| 153 | + x1="0" |
| 154 | + y1="2" |
| 155 | + x2="100%" |
| 156 | + y2="2" |
| 157 | + stroke="url(#lineGradient)" |
| 158 | + strokeWidth="4" |
| 159 | + strokeDasharray="10,5" |
| 160 | + style={{ |
| 161 | + animation: `${dataFlow} 2s linear infinite`, |
| 162 | + }} |
| 163 | + /> |
| 164 | + </svg> |
| 165 | + |
| 166 | + {steps.map((step, index) => { |
| 167 | + const Icon = step.icon |
| 168 | + const isActive = index === activeStep |
| 169 | + const isPast = index < activeStep |
| 170 | + |
| 171 | + return ( |
| 172 | + <AnimatedBox |
| 173 | + key={index} |
| 174 | + delay={index * 0.2} |
| 175 | + sx={{ |
| 176 | + flex: '1 1 150px', |
| 177 | + maxWidth: '180px', |
| 178 | + zIndex: 1, |
| 179 | + }} |
| 180 | + > |
| 181 | + <StepCard active={isActive}> |
| 182 | + <Box sx={{ |
| 183 | + display: 'flex', |
| 184 | + justifyContent: 'center', |
| 185 | + mb: 1, |
| 186 | + animation: isActive ? `${pulse} 1s ease-in-out infinite` : 'none', |
| 187 | + }}> |
| 188 | + <Icon |
| 189 | + sx={{ |
| 190 | + fontSize: 40, |
| 191 | + color: isActive || isPast ? step.color : '#9e9e9e', |
| 192 | + transition: 'color 0.3s ease', |
| 193 | + }} |
| 194 | + /> |
| 195 | + </Box> |
| 196 | + <Typography |
| 197 | + variant="subtitle2" |
| 198 | + sx={{ |
| 199 | + fontWeight: 'bold', |
| 200 | + color: isActive ? '#D35400' : (isPast ? '#333' : '#666'), |
| 201 | + mb: 0.5, |
| 202 | + }} |
| 203 | + > |
| 204 | + {step.label} |
| 205 | + </Typography> |
| 206 | + <Typography |
| 207 | + variant="caption" |
| 208 | + sx={{ |
| 209 | + color: isActive ? '#666' : '#999', |
| 210 | + display: 'block', |
| 211 | + }} |
| 212 | + > |
| 213 | + {step.description} |
| 214 | + </Typography> |
| 215 | + {isActive && ( |
| 216 | + <Box |
| 217 | + sx={{ |
| 218 | + mt: 1, |
| 219 | + py: 0.5, |
| 220 | + px: 1, |
| 221 | + bgcolor: '#D35400', |
| 222 | + color: 'white', |
| 223 | + borderRadius: '12px', |
| 224 | + fontSize: '0.7rem', |
| 225 | + fontWeight: 'bold', |
| 226 | + display: 'inline-block', |
| 227 | + animation: `${pulse} 1s ease-in-out infinite`, |
| 228 | + }} |
| 229 | + > |
| 230 | + ACTIVE |
| 231 | + </Box> |
| 232 | + )} |
| 233 | + </StepCard> |
| 234 | + </AnimatedBox> |
| 235 | + ) |
| 236 | + })} |
| 237 | + </Box> |
| 238 | + |
| 239 | + {/* Status Bar */} |
| 240 | + <Box sx={{ mt: 4, textAlign: 'center' }}> |
| 241 | + <Paper |
| 242 | + elevation={2} |
| 243 | + sx={{ |
| 244 | + display: 'inline-flex', |
| 245 | + alignItems: 'center', |
| 246 | + gap: 2, |
| 247 | + px: 3, |
| 248 | + py: 1.5, |
| 249 | + borderRadius: '25px', |
| 250 | + bgcolor: '#FFF8E1', |
| 251 | + border: '1px solid #F1C40F', |
| 252 | + }} |
| 253 | + > |
| 254 | + <Box |
| 255 | + sx={{ |
| 256 | + width: 12, |
| 257 | + height: 12, |
| 258 | + borderRadius: '50%', |
| 259 | + bgcolor: '#4caf50', |
| 260 | + animation: `${pulse} 1s ease-in-out infinite`, |
| 261 | + }} |
| 262 | + /> |
| 263 | + <Typography variant="body2" sx={{ color: '#5D4037', fontWeight: 500 }}> |
| 264 | + Step {activeStep + 1} of {steps.length}: {steps[activeStep].label} |
| 265 | + </Typography> |
| 266 | + <Typography variant="caption" sx={{ color: '#8D6E63', ml: 1 }}> |
| 267 | + (Auto-cycling every 2 seconds) |
| 268 | + </Typography> |
| 269 | + </Paper> |
| 270 | + </Box> |
| 271 | + |
| 272 | + {/* Data Flow Animation */} |
| 273 | + <Box sx={{ mt: 4, position: 'relative', height: '30px', overflow: 'hidden' }}> |
| 274 | + <Typography |
| 275 | + variant="caption" |
| 276 | + sx={{ |
| 277 | + position: 'absolute', |
| 278 | + left: '50%', |
| 279 | + transform: 'translateX(-50%)', |
| 280 | + color: '#D35400', |
| 281 | + fontStyle: 'italic', |
| 282 | + animation: `${float} 2s ease-in-out infinite`, |
| 283 | + }} |
| 284 | + > |
| 285 | + ◀ AI processing raga: Mayamalavagowla ▶ |
| 286 | + </Typography> |
| 287 | + <Box |
| 288 | + sx={{ |
| 289 | + position: 'absolute', |
| 290 | + bottom: 0, |
| 291 | + left: 0, |
| 292 | + right: 0, |
| 293 | + height: '3px', |
| 294 | + background: 'linear-gradient(90deg, transparent 0%, #D35400 50%, transparent 100%)', |
| 295 | + animation: `${flow} 3s linear infinite`, |
| 296 | + }} |
| 297 | + /> |
| 298 | + </Box> |
| 299 | + </Box> |
| 300 | + ) |
| 301 | +} |
| 302 | + |
| 303 | +export default AnimatedWorkflow |
0 commit comments