1- "use client"
1+ import { SectionLinkButton } from "@/components/ui/SectionLinkButton"
2+ import { SectionMotion , type SectionAnimation } from "@/components/ui/SectionMotion"
3+ import { cn } from "@/lib/utils"
4+ import { createElement , type ReactNode } from "react"
25
3- import { LinkButton } from "@/components/ui/LinkButton"
4- import { getLocaleFromPath , localizeHref } from "@/lib/i18n"
5- import { ANIMATION_PRESETS , cn , type AnimationPreset } from "@/lib/utils"
6- import { m as motion , type Variants } from "motion/react"
7- import { usePathname } from "next/navigation"
8- import { createElement , ReactNode , useEffect , useRef } from "react"
9-
10- interface SectionLinkButton {
6+ interface SectionLink {
117 label ?: string | null
128 url ?: string | null
139}
@@ -49,41 +45,12 @@ interface SectionProps {
4945 className ?: string
5046 heading ?: string | null
5147 description ?: string | null
52- linkButton ?: SectionLinkButton | null
48+ linkButton ?: SectionLink | null
5349 showFunnel ?: boolean
5450 showLinkButton ?: boolean
5551 fullHeight ?: boolean
5652 headingLevel ?: 1 | 2 | 3 | 4 | 5 | 6
57- animation ?: {
58- preset ?: AnimationPreset
59- delay ?: number
60- duration ?: number
61- once ?: boolean
62- viewportAmount ?: number
63- viewportMargin ?: string
64- }
65- }
66-
67- const DEFAULT_SECTION_ANIMATION : NonNullable < SectionProps [ "animation" ] > = { }
68- const staggerContainer : Variants = {
69- hidden : { } ,
70- show : {
71- transition : {
72- staggerChildren : 0.1 ,
73- delayChildren : 0.04 ,
74- } ,
75- } ,
76- }
77- const staggerItem : Variants = {
78- hidden : { opacity : 0 , y : 16 } ,
79- show : {
80- opacity : 1 ,
81- y : 0 ,
82- transition : {
83- duration : 0.4 ,
84- ease : [ 0.22 , 1 , 0.36 , 1 ] ,
85- } ,
86- } ,
53+ animation ?: SectionAnimation
8754}
8855
8956export function Section ( {
@@ -96,94 +63,37 @@ export function Section({
9663 showFunnel = true ,
9764 showLinkButton = true ,
9865 fullHeight = false ,
99- animation = DEFAULT_SECTION_ANIMATION ,
66+ animation,
10067 headingLevel = 2 ,
10168} : SectionProps ) {
102- const { preset = "fade-up" , delay = 0 , duration, once = true , viewportAmount = 0.2 , viewportMargin } = animation
103- const sectionRef = useRef < HTMLElement | null > ( null )
104- const pathname = usePathname ( )
105- const locale = getLocaleFromPath ( pathname )
10669 const rawLinkUrl = linkButton ?. url ?. trim ( )
107- const linkUrl = rawLinkUrl ? localizeHref ( rawLinkUrl , locale ) : undefined
108- const shouldShowFunnel = showFunnel && Boolean ( heading || description || ( showLinkButton && linkUrl && linkButton ?. label ) )
109- const animationConfig = preset === "none" ? null : ANIMATION_PRESETS [ preset ]
70+ const shouldShowFunnel = showFunnel && Boolean ( heading || description || ( showLinkButton && rawLinkUrl && linkButton ?. label ) )
11071 const headingTag = `h${ headingLevel } ` as const
111- const headingClassName = cn ( "text-4xl font-semibold" , hasHighlightedHeading ( heading ) ? "text-secondary" : "text-white" )
112-
113- useEffect ( ( ) => {
114- const currentRef = sectionRef . current
115- if ( ! currentRef ) return
116-
117- const observer = new IntersectionObserver (
118- ( [ entry ] ) => {
119- if ( entry ?. isIntersecting ) {
120- currentRef . dataset . inView = "true"
121- observer . unobserve ( currentRef )
122- }
123- } ,
124- { rootMargin : "100px" }
125- )
126-
127- observer . observe ( currentRef )
128-
129- return ( ) => observer . disconnect ( )
130- } , [ ] )
72+ const headingClassName = cn ( "section-stagger-item text-4xl font-semibold" , hasHighlightedHeading ( heading ) ? "text-secondary" : "text-white" )
73+ const funnelClassName = funnelType === "center" ? "section-funnel flex flex-col gap-4 items-center justify-center text-center" : "section-funnel flex flex-col gap-4 text-left"
74+ const descriptionClassName = cn (
75+ "section-stagger-item relative z-10 max-w-[90vw] text-xl font-medium text-secondary lg:w-1/2" ,
76+ funnelType === "center" && "text-center"
77+ )
13178
13279 return (
133- < motion . section
134- ref = { sectionRef }
135- data-in-view = "false"
136- className = { cn ( "group/section relative overflow-hidden flex flex-col gap-16" , fullHeight && "h-[200dvh] md:h-[min(100dvh,1080px)]" , className ) }
137- initial = { animationConfig ?. initial }
138- whileInView = { animationConfig ?. whileInView }
139- viewport = { animationConfig ? { once, amount : viewportAmount , margin : viewportMargin } : undefined }
140- transition = {
141- animationConfig
142- ? {
143- ...animationConfig . transition ,
144- delay : delay ,
145- duration : duration ?? animationConfig . transition . duration ,
146- }
147- : undefined
148- }
149- >
150- { shouldShowFunnel &&
151- ( funnelType === "center" ? (
152- < motion . div
153- className = { "flex flex-col gap-4 items-center justify-center text-center" }
154- variants = { staggerContainer }
155- initial = "hidden"
156- whileInView = "show"
157- viewport = { { once, amount : 0.3 } }
158- >
159- { createElement ( motion [ headingTag ] , { variants : staggerItem , className : headingClassName } , heading ? < FormattedText text = { heading } /> : null ) }
160- { description && (
161- < motion . p variants = { staggerItem } className = "relative z-10 max-w-[90vw] text-center text-xl font-medium text-secondary lg:w-1/2" >
162- < FormattedText text = { description } />
163- </ motion . p >
164- ) }
165- { showLinkButton && linkUrl && (
166- < motion . div variants = { staggerItem } >
167- < LinkButton href = { linkUrl } > { linkButton ?. label } </ LinkButton >
168- </ motion . div >
169- ) }
170- </ motion . div >
171- ) : (
172- < motion . div className = { "flex flex-col gap-4 text-left" } variants = { staggerContainer } initial = "hidden" whileInView = "show" viewport = { { once, amount : 0.3 } } >
173- { createElement ( motion [ headingTag ] , { variants : staggerItem , className : headingClassName } , heading ? < FormattedText text = { heading } /> : null ) }
174- { description && (
175- < motion . p variants = { staggerItem } className = "relative z-10 max-w-[90vw] text-xl font-medium text-secondary lg:w-1/2" >
176- < FormattedText text = { description } />
177- </ motion . p >
178- ) }
179- { showLinkButton && linkUrl && (
180- < motion . div variants = { staggerItem } >
181- < LinkButton href = { linkUrl } > { linkButton ?. label } </ LinkButton >
182- </ motion . div >
183- ) }
184- </ motion . div >
185- ) ) }
80+ < SectionMotion animation = { animation } className = { className } fullHeight = { fullHeight } >
81+ { shouldShowFunnel && (
82+ < div className = { funnelClassName } >
83+ { createElement ( headingTag , { className : headingClassName } , heading ? < FormattedText text = { heading } /> : null ) }
84+ { description && (
85+ < p className = { descriptionClassName } >
86+ < FormattedText text = { description } />
87+ </ p >
88+ ) }
89+ { showLinkButton && rawLinkUrl && (
90+ < div className = "section-stagger-item" >
91+ < SectionLinkButton label = { linkButton ?. label } url = { rawLinkUrl } />
92+ </ div >
93+ ) }
94+ </ div >
95+ ) }
18696 { children }
187- </ motion . section >
97+ </ SectionMotion >
18898 )
18999}
0 commit comments