11import { useRef , useEffect , useState , useCallback } from 'react'
2- import { motion , AnimatePresence , useScroll , useTransform , useSpring } from 'framer-motion'
2+ import { motion , AnimatePresence } from 'framer-motion'
33import { Loader2 , Sparkles } from 'lucide-react'
44import { HeroSearch , type HeroSearchHandle } from './HeroSearch'
55import { useDemoSearch , DEMO_REPOS , type DemoRepo } from '@/hooks/useDemoSearch'
@@ -24,22 +24,20 @@ const headlineVariants = {
2424 hidden : { opacity : 0 } ,
2525 visible : {
2626 opacity : 1 ,
27- transition : { staggerChildren : 0.05 , delayChildren : 0.2 }
27+ transition : { staggerChildren : 0.08 , delayChildren : 0.2 }
2828 }
2929}
3030
3131const wordVariants = {
32- hidden : { opacity : 0 , y : 20 , filter : 'blur(10px)' } ,
32+ hidden : { opacity : 0 , y : 20 } ,
3333 visible : {
3434 opacity : 1 ,
3535 y : 0 ,
36- filter : 'blur(0px)' ,
37- transition : { duration : 0.5 , ease : [ 0.25 , 0.4 , 0.25 , 1 ] }
36+ transition : { duration : 0.4 , ease : [ 0.25 , 0.4 , 0.25 , 1 ] }
3837 }
3938}
4039
4140export function Hero ( { onResultsReady } : Props ) {
42- const sectionRef = useRef < HTMLElement > ( null )
4341 const searchRef = useRef < HeroSearchHandle > ( null )
4442 const cardRef = useRef < HTMLDivElement > ( null )
4543 const { query, repo, results, loading, searchTime, setQuery, setRepo, search } = useDemoSearch ( false )
@@ -48,21 +46,6 @@ export function Hero({ onResultsReady }: Props) {
4846 const [ typingIndex , setTypingIndex ] = useState ( 0 )
4947 const typingTimeoutRef = useRef < ReturnType < typeof setTimeout > > ( )
5048
51- // Scroll-linked parallax
52- const { scrollYProgress } = useScroll ( {
53- target : sectionRef ,
54- offset : [ 'start start' , 'end start' ]
55- } )
56-
57- const smoothProgress = useSpring ( scrollYProgress , { stiffness : 100 , damping : 30 } )
58- const orb1Y = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , - 150 ] )
59- const orb2Y = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , - 100 ] )
60- const orb3Y = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , - 200 ] )
61- const orb1X = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , 50 ] )
62- const orb2X = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , - 80 ] )
63- const contentY = useTransform ( smoothProgress , [ 0 , 1 ] , [ 0 , 100 ] )
64- const contentOpacity = useTransform ( smoothProgress , [ 0 , 0.5 ] , [ 1 , 0 ] )
65-
6649 useEffect ( ( ) => {
6750 if ( results . length ) onResultsReady ?.( results , query , repo . id , searchTime )
6851 } , [ results , query , repo . id , searchTime , onResultsReady ] )
@@ -120,41 +103,33 @@ export function Hero({ onResultsReady }: Props) {
120103 const line2Words = [ 'unfamiliar' , 'codebases.' ]
121104
122105 return (
123- < section ref = { sectionRef } className = "relative min-h-[90vh] flex flex-col justify-center pt-16 pb-8 px-6 overflow-hidden" >
106+ < section className = "relative min-h-[90vh] flex flex-col justify-center pt-16 pb-8 px-6 overflow-hidden" >
124107 { /* Grid pattern background */ }
125108 < div className = "absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:64px_64px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,black_40%,transparent_100%)]" />
126109
127- { /* Parallax gradient orbs */ }
110+ { /* Floating gradient orbs */ }
128111 < div className = "absolute inset-0 overflow-hidden pointer-events-none" >
129112 < motion . div
130113 className = "absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full"
131- style = { {
132- background : 'radial-gradient(circle, rgba(79,70,229,0.2) 0%, transparent 60%)' ,
133- y : orb1Y ,
134- x : orb1X ,
135- } }
114+ style = { { background : 'radial-gradient(circle, rgba(79,70,229,0.2) 0%, transparent 60%)' } }
115+ animate = { { x : [ 0 , 30 , 0 ] , y : [ 0 , - 20 , 0 ] } }
116+ transition = { { duration : 10 , repeat : Infinity , ease : 'easeInOut' } }
136117 />
137118 < motion . div
138119 className = "absolute top-1/3 right-1/4 w-[500px] h-[500px] rounded-full"
139- style = { {
140- background : 'radial-gradient(circle, rgba(139,92,246,0.15) 0%, transparent 60%)' ,
141- y : orb2Y ,
142- x : orb2X ,
143- } }
120+ style = { { background : 'radial-gradient(circle, rgba(139,92,246,0.15) 0%, transparent 60%)' } }
121+ animate = { { x : [ 0 , - 25 , 0 ] , y : [ 0 , 25 , 0 ] } }
122+ transition = { { duration : 12 , repeat : Infinity , ease : 'easeInOut' } }
144123 />
145124 < motion . div
146125 className = "absolute bottom-1/4 left-1/3 w-[400px] h-[400px] rounded-full"
147- style = { {
148- background : 'radial-gradient(circle, rgba(34,211,238,0.1) 0%, transparent 60%)' ,
149- y : orb3Y ,
150- } }
126+ style = { { background : 'radial-gradient(circle, rgba(34,211,238,0.1) 0%, transparent 60%)' } }
127+ animate = { { x : [ 0 , 20 , 0 ] , y : [ 0 , - 15 , 0 ] } }
128+ transition = { { duration : 14 , repeat : Infinity , ease : 'easeInOut' } }
151129 />
152130 </ div >
153131
154- < motion . div
155- className = "relative max-w-3xl mx-auto w-full"
156- style = { { y : contentY , opacity : contentOpacity } }
157- >
132+ < div className = "relative max-w-3xl mx-auto w-full" >
158133 { /* Badge */ }
159134 < motion . div
160135 className = "flex justify-center mb-5"
@@ -356,7 +331,7 @@ export function Hero({ onResultsReady }: Props) {
356331 </ div >
357332 < p className = "text-xs text-muted-foreground/60" > Works with any Python repository • Self-host or cloud</ p >
358333 </ motion . div >
359- </ motion . div >
334+ </ div >
360335 </ section >
361336 )
362337}
0 commit comments