Spaces:
Running
Running
Pulastya B
feat: Initial commit - Data Science Agent with React frontend and FastAPI backend
226ac39
| 'use client'; | |
| import React, { useRef, useId, useEffect, CSSProperties } from 'react'; | |
| import { animate, useMotionValue, AnimationPlaybackControls, motion } from 'framer-motion'; | |
| import { cn } from '../lib/utils'; | |
| // Type definitions | |
| interface ResponsiveImage { | |
| src: string; | |
| alt?: string; | |
| srcSet?: string; | |
| } | |
| interface AnimationConfig { | |
| preview?: boolean; | |
| scale: number; | |
| speed: number; | |
| } | |
| interface NoiseConfig { | |
| opacity: number; | |
| scale: number; | |
| } | |
| interface ShadowOverlayProps { | |
| type?: 'preset' | 'custom'; | |
| presetIndex?: number; | |
| customImage?: ResponsiveImage; | |
| sizing?: 'fill' | 'stretch'; | |
| color?: string; | |
| animation?: AnimationConfig; | |
| noise?: NoiseConfig; | |
| style?: CSSProperties; | |
| className?: string; | |
| title?: string; | |
| description?: string; | |
| } | |
| function mapRange( | |
| value: number, | |
| fromLow: number, | |
| fromHigh: number, | |
| toLow: number, | |
| toHigh: number | |
| ): number { | |
| if (fromLow === fromHigh) { | |
| return toLow; | |
| } | |
| const percentage = (value - fromLow) / (fromHigh - fromLow); | |
| return toLow + percentage * (toHigh - toLow); | |
| } | |
| const useInstanceId = (): string => { | |
| const id = useId(); | |
| const cleanId = id.replace(/:/g, ""); | |
| const instanceId = `shadowoverlay-${cleanId}`; | |
| return instanceId; | |
| }; | |
| export function ShadowSection({ | |
| sizing = 'fill', | |
| color = 'rgba(99, 102, 241, 0.6)', | |
| animation = { scale: 50, speed: 15 }, | |
| noise = { opacity: 0.1, scale: 0.5 }, | |
| style, | |
| className, | |
| title = "Cognitive Core", | |
| description = "The unseen intelligence powering your most critical decisions." | |
| }: ShadowOverlayProps) { | |
| const id = useInstanceId(); | |
| const animationEnabled = animation && animation.scale > 0; | |
| const feColorMatrixRef = useRef<SVGFEColorMatrixElement>(null); | |
| const hueRotateMotionValue = useMotionValue(180); | |
| const hueRotateAnimation = useRef<AnimationPlaybackControls | null>(null); | |
| const displacementScale = animation ? mapRange(animation.scale, 1, 100, 20, 100) : 0; | |
| const animationDuration = animation ? mapRange(animation.speed, 1, 100, 1000, 50) : 1; | |
| useEffect(() => { | |
| if (feColorMatrixRef.current && animationEnabled) { | |
| if (hueRotateAnimation.current) { | |
| hueRotateAnimation.current.stop(); | |
| } | |
| hueRotateMotionValue.set(0); | |
| hueRotateAnimation.current = animate(hueRotateMotionValue, 360, { | |
| duration: animationDuration / 25, | |
| repeat: Infinity, | |
| repeatType: "loop", | |
| repeatDelay: 0, | |
| ease: "linear", | |
| delay: 0, | |
| onUpdate: (value: number) => { | |
| if (feColorMatrixRef.current) { | |
| feColorMatrixRef.current.setAttribute("values", String(value)); | |
| } | |
| } | |
| }); | |
| return () => { | |
| if (hueRotateAnimation.current) { | |
| hueRotateAnimation.current.stop(); | |
| } | |
| }; | |
| } | |
| }, [animationEnabled, animationDuration, hueRotateMotionValue]); | |
| return ( | |
| <section | |
| className={cn("relative w-full h-[70vh] min-h-[500px] overflow-hidden bg-[#030303]", className)} | |
| style={style} | |
| > | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: -displacementScale, | |
| filter: animationEnabled ? `url(#${id}) blur(8px)` : "none" | |
| }} | |
| > | |
| {animationEnabled && ( | |
| <svg style={{ position: "absolute", width: 0, height: 0 }}> | |
| <defs> | |
| <filter id={id}> | |
| <feTurbulence | |
| result="undulation" | |
| numOctaves="2" | |
| baseFrequency={`${mapRange(animation.scale, 0, 100, 0.001, 0.0005)},${mapRange(animation.scale, 0, 100, 0.004, 0.002)}`} | |
| seed="0" | |
| type="turbulence" | |
| /> | |
| <feColorMatrix | |
| ref={feColorMatrixRef} | |
| in="undulation" | |
| type="hueRotate" | |
| values="180" | |
| /> | |
| <feColorMatrix | |
| in="dist" | |
| result="circulation" | |
| type="matrix" | |
| values="4 0 0 0 1 4 0 0 0 1 4 0 0 0 1 1 0 0 0 0" | |
| /> | |
| <feDisplacementMap | |
| in="SourceGraphic" | |
| in2="circulation" | |
| scale={displacementScale} | |
| result="dist" | |
| /> | |
| <feDisplacementMap | |
| in="dist" | |
| in2="undulation" | |
| scale={displacementScale} | |
| result="output" | |
| /> | |
| </filter> | |
| </defs> | |
| </svg> | |
| )} | |
| <div | |
| style={{ | |
| backgroundColor: color, | |
| maskImage: `url('https://framerusercontent.com/images/ceBGguIpUU8luwByxuQz79t7To.png')`, | |
| maskSize: sizing === "stretch" ? "100% 100%" : "cover", | |
| maskRepeat: "no-repeat", | |
| maskPosition: "center", | |
| width: "100%", | |
| height: "100%" | |
| }} | |
| /> | |
| </div> | |
| <div | |
| style={{ | |
| position: "absolute", | |
| top: "50%", | |
| left: "50%", | |
| transform: "translate(-50%, -50%)", | |
| textAlign: "center", | |
| zIndex: 20, | |
| width: '100%', | |
| padding: '0 2rem' | |
| }} | |
| > | |
| <motion.h2 | |
| initial={{ opacity: 0, y: 20 }} | |
| whileInView={{ opacity: 1, y: 0 }} | |
| viewport={{ once: true }} | |
| className="md:text-7xl text-5xl lg:text-8xl font-heading font-bold text-center text-white relative z-20 tracking-tighter mb-4" | |
| > | |
| {title} | |
| </motion.h2> | |
| <motion.p | |
| initial={{ opacity: 0, y: 20 }} | |
| whileInView={{ opacity: 1, y: 0 }} | |
| viewport={{ once: true }} | |
| transition={{ delay: 0.2 }} | |
| className="text-white/60 text-lg md:text-xl font-sans max-w-xl mx-auto" | |
| > | |
| {description} | |
| </motion.p> | |
| </div> | |
| {noise && noise.opacity > 0 && ( | |
| <div | |
| style={{ | |
| position: "absolute", | |
| inset: 0, | |
| backgroundImage: `url("https://framerusercontent.com/images/g0QcWrxr87K0ufOxIUFBakwYA8.png")`, | |
| backgroundSize: noise.scale * 200, | |
| backgroundRepeat: "repeat", | |
| opacity: noise.opacity / 2, | |
| zIndex: 15 | |
| }} | |
| /> | |
| )} | |
| {/* Bottom Vignette */} | |
| <div className="absolute inset-x-0 bottom-0 h-40 bg-gradient-to-t from-[#030303] to-transparent z-30" /> | |
| <div className="absolute inset-x-0 top-0 h-40 bg-gradient-to-b from-[#030303] to-transparent z-30" /> | |
| </section> | |
| ); | |
| } | |