blocks-dusted 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/package.json +5 -2
- package/src/cli.js +39 -3
- package/src/commands/shop.js +59 -0
- package/src/commands/warehouse.js +73 -0
- package/src/utils/paths.js +13 -13
- package/templates/blocks/DD-Accordion/Component.tsx +229 -0
- package/templates/blocks/DD-Accordion/README.md +3 -0
- package/templates/blocks/DD-Accordion/config.ts +73 -0
- package/templates/blocks/DD-Accordion/manifest.json +75 -0
- package/templates/blocks/DD-AnimText/Component.tsx +788 -0
- package/templates/blocks/DD-AnimText/README.md +3 -0
- package/templates/blocks/DD-AnimText/config.ts +295 -0
- package/templates/blocks/DD-AnimText/manifest.json +85 -0
- package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
- package/templates/blocks/DD-AsideNav/config.ts +204 -0
- package/templates/blocks/DD-AsideNav/manifest.json +80 -0
- package/templates/blocks/DD-Banner/Component.tsx +51 -0
- package/templates/blocks/DD-Banner/config.ts +57 -0
- package/templates/blocks/DD-Banner/manifest.json +72 -0
- package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
- package/templates/blocks/DD-BgLightning/README.md +3 -0
- package/templates/blocks/DD-BgLightning/config.ts +97 -0
- package/templates/blocks/DD-BgLightning/manifest.json +79 -0
- package/templates/blocks/DD-BookCall/Component.tsx +535 -535
- package/templates/blocks/DD-BookCall/config.ts +238 -238
- package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
- package/templates/blocks/DD-ButtonPop/config.ts +105 -0
- package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
- package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
- package/templates/blocks/DD-Card/Component.tsx +251 -0
- package/templates/blocks/DD-Card/README.md +4 -0
- package/templates/blocks/DD-Card/config.ts +154 -0
- package/templates/blocks/DD-Card/manifest.json +82 -0
- package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
- package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
- package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
- package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
- package/templates/blocks/DD-Chip/Component.tsx +250 -0
- package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
- package/templates/blocks/DD-Chip/README.md +202 -0
- package/templates/blocks/DD-Chip/config.ts +369 -0
- package/templates/blocks/DD-Chip/manifest.json +74 -0
- package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
- package/templates/blocks/DD-Contact/Component.tsx +435 -434
- package/templates/blocks/DD-Contact/config.ts +22 -22
- package/templates/blocks/DD-Counter/Component.tsx +190 -0
- package/templates/blocks/DD-Counter/README.md +4 -0
- package/templates/blocks/DD-Counter/config.ts +291 -0
- package/templates/blocks/DD-Counter/manifest.json +74 -0
- package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
- package/templates/blocks/DD-CustomCSS/README.md +4 -0
- package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
- package/templates/blocks/DD-CustomCSS/config.ts +22 -0
- package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
- package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
- package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
- package/templates/blocks/DD-FeatCat/config.ts +201 -201
- package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
- package/templates/blocks/DD-FeatStrip/config.ts +134 -134
- package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
- package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
- package/templates/blocks/DD-FluidBtn/README.md +6 -0
- package/templates/blocks/DD-FluidBtn/config.ts +102 -0
- package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
- package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
- package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
- package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
- package/templates/blocks/DD-Hero/Component.tsx +297 -297
- package/templates/blocks/DD-Hero/config.ts +267 -267
- package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
- package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
- package/templates/blocks/DD-Icon/Component.tsx +287 -0
- package/templates/blocks/DD-Icon/README.md +4 -0
- package/templates/blocks/DD-Icon/config.ts +258 -0
- package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
- package/templates/blocks/DD-Icon/manifest.json +82 -0
- package/templates/blocks/DD-IconButton/Component.tsx +455 -0
- package/templates/blocks/DD-IconButton/README.md +326 -0
- package/templates/blocks/DD-IconButton/config.ts +239 -0
- package/templates/blocks/DD-IconButton/manifest.json +85 -0
- package/templates/blocks/DD-IdTag/Component.tsx +21 -0
- package/templates/blocks/DD-IdTag/README.md +4 -0
- package/templates/blocks/DD-IdTag/config.ts +41 -0
- package/templates/blocks/DD-IdTag/manifest.json +72 -0
- package/templates/blocks/DD-Iframe/Component.tsx +45 -0
- package/templates/blocks/DD-Iframe/README.md +4 -0
- package/templates/blocks/DD-Iframe/config.ts +47 -0
- package/templates/blocks/DD-Iframe/manifest.json +72 -0
- package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
- package/templates/blocks/DD-IframeMedia/README.md +4 -0
- package/templates/blocks/DD-IframeMedia/config.ts +79 -0
- package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
- package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
- package/templates/blocks/DD-LineAnim/README.md +4 -0
- package/templates/blocks/DD-LineAnim/config.ts +90 -0
- package/templates/blocks/DD-LineAnim/manifest.json +80 -0
- package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
- package/templates/blocks/DD-LinkGrid/README.md +4 -0
- package/templates/blocks/DD-LinkGrid/config.ts +51 -0
- package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
- package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
- package/templates/blocks/DD-LogoMarq/README.md +4 -0
- package/templates/blocks/DD-LogoMarq/config.ts +264 -0
- package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
- package/templates/blocks/DD-Lottie/Component.tsx +459 -0
- package/templates/blocks/DD-Lottie/README.md +4 -0
- package/templates/blocks/DD-Lottie/config.ts +379 -0
- package/templates/blocks/DD-Lottie/index.tsx +28 -0
- package/templates/blocks/DD-Lottie/manifest.json +83 -0
- package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
- package/templates/blocks/DD-MagicBento/README.md +4 -0
- package/templates/blocks/DD-MagicBento/config.ts +264 -0
- package/templates/blocks/DD-MagicBento/manifest.json +74 -0
- package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
- package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
- package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
- package/templates/blocks/DD-Masonry/Component.tsx +645 -0
- package/templates/blocks/DD-Masonry/README.md +4 -0
- package/templates/blocks/DD-Masonry/config.ts +475 -0
- package/templates/blocks/DD-Masonry/manifest.json +82 -0
- package/templates/blocks/DD-Pricing/Component.tsx +2 -5
- package/templates/blocks/DD-Process/Component.tsx +2 -4
- package/templates/blocks/DD-Process/config.ts +150 -150
- package/templates/blocks/DD-Progress/Component.tsx +156 -0
- package/templates/blocks/DD-Progress/README.md +4 -0
- package/templates/blocks/DD-Progress/config.ts +175 -0
- package/templates/blocks/DD-Progress/manifest.json +74 -0
- package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
- package/templates/blocks/DD-ProjHeader/README.md +4 -0
- package/templates/blocks/DD-ProjHeader/config.ts +96 -0
- package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
- package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
- package/templates/blocks/DD-ProjSlider/README.md +4 -0
- package/templates/blocks/DD-ProjSlider/config.ts +64 -0
- package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
- package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
- package/templates/blocks/DD-ScrollText/README.md +4 -0
- package/templates/blocks/DD-ScrollText/config.ts +58 -0
- package/templates/blocks/DD-ScrollText/manifest.json +72 -0
- package/templates/blocks/DD-Section/Component.tsx +266 -266
- package/templates/blocks/DD-Separator/Component.tsx +66 -0
- package/templates/blocks/DD-Separator/README.md +4 -0
- package/templates/blocks/DD-Separator/config.ts +58 -0
- package/templates/blocks/DD-Separator/manifest.json +72 -0
- package/templates/blocks/DD-Services/Component.tsx +176 -176
- package/templates/blocks/DD-Services/config.ts +149 -149
- package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
- package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
- package/templates/blocks/DD-StackCards/Component.tsx +1 -1
- package/templates/blocks/DD-StackCards/config.ts +399 -399
- package/templates/blocks/DD-Team/Component.tsx +247 -247
- package/templates/blocks/DD-Team/config.ts +173 -173
- package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
- package/templates/blocks/DD-TeamCards/README.md +4 -0
- package/templates/blocks/DD-TeamCards/config.ts +302 -0
- package/templates/blocks/DD-TeamCards/manifest.json +74 -0
- package/templates/blocks/DD-TechStack/Component.tsx +174 -174
- package/templates/blocks/DD-TechStack/config.ts +153 -153
- package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
- package/templates/blocks/DD-TestMarq/README.md +4 -0
- package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
- package/templates/blocks/DD-TestMarq/config.ts +88 -0
- package/templates/blocks/DD-TestMarq/manifest.json +72 -0
- package/templates/blocks/DD-Testim/Component.tsx +247 -0
- package/templates/blocks/DD-Testim/README.md +4 -0
- package/templates/blocks/DD-Testim/config.ts +101 -0
- package/templates/blocks/DD-Testim/manifest.json +75 -0
- package/templates/blocks/DD-Testim2/Component.tsx +256 -0
- package/templates/blocks/DD-Testim2/README.md +4 -0
- package/templates/blocks/DD-Testim2/config.ts +100 -0
- package/templates/blocks/DD-Testim2/manifest.json +74 -0
- package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
- package/templates/blocks/DD-Testimonials/config.ts +120 -120
- package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
- package/templates/blocks/DD-TextMarq/README.md +4 -0
- package/templates/blocks/DD-TextMarq/config.ts +237 -0
- package/templates/blocks/DD-TextMarq/manifest.json +82 -0
- package/templates/blocks/DD-Thanks/Component.tsx +501 -0
- package/templates/blocks/DD-Thanks/README.md +4 -0
- package/templates/blocks/DD-Thanks/config.ts +224 -0
- package/templates/blocks/DD-Thanks/manifest.json +72 -0
- package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
- package/templates/blocks/DD-VertMarq/README.md +4 -0
- package/templates/blocks/DD-VertMarq/config.ts +236 -0
- package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
- package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
- package/templates/blocks/DD-VertMarq/manifest.json +74 -0
- package/templates/blocks/DD-Work/Component.tsx +318 -315
- package/templates/blocks/DD-Work/config.ts +165 -165
- package/templates/blocks/DD-Work-B/Component.tsx +294 -294
- package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
- package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
- package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
- package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
- package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
- package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
- package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
- package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
- package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
- package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
- package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
- package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
- package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
- package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
- package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
- package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
- package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
- package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
- package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
- package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
- package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
- package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
- package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
- package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
- package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
- package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
- package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
- package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
- package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
- package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
- package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
- package/templates/shared/src/components/BgLightning/index.tsx +242 -0
- package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
- package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
- package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
- package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
- package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
- package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
- package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
- package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
- package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
- package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
- package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
- package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
- package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
- package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
- package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
- package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
- package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
- package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
- package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
- package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
- package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
- package/templates/shared/src/components/ui/separator.tsx +85 -0
- package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
- package/templates/shared/src/hooks/useClickOutside.ts +28 -0
- package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
- package/templates/shared/src/utilities/smoothScroll.ts +65 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
2
|
+
'use client'
|
|
3
|
+
import React, { useRef } from 'react'
|
|
4
|
+
|
|
5
|
+
interface GlareHoverProps {
|
|
6
|
+
width?: string
|
|
7
|
+
height?: string
|
|
8
|
+
background?: string
|
|
9
|
+
borderRadius?: string
|
|
10
|
+
borderColor?: string
|
|
11
|
+
children?: React.ReactNode
|
|
12
|
+
glareColor?: string
|
|
13
|
+
glareOpacity?: number
|
|
14
|
+
glareAngle?: number
|
|
15
|
+
glareSize?: number
|
|
16
|
+
transitionDuration?: number
|
|
17
|
+
playOnce?: boolean
|
|
18
|
+
className?: string
|
|
19
|
+
style?: React.CSSProperties
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const GlareHover: React.FC<GlareHoverProps> = ({
|
|
23
|
+
width = 'auto',
|
|
24
|
+
height = 'auto',
|
|
25
|
+
background = 'transparent',
|
|
26
|
+
borderRadius = '0',
|
|
27
|
+
borderColor = 'transparent',
|
|
28
|
+
children,
|
|
29
|
+
glareColor = '#ffffff69',
|
|
30
|
+
glareOpacity = 0.5,
|
|
31
|
+
glareAngle = -45,
|
|
32
|
+
glareSize = 250,
|
|
33
|
+
transitionDuration = 650,
|
|
34
|
+
playOnce = false,
|
|
35
|
+
className = '',
|
|
36
|
+
style = {},
|
|
37
|
+
}) => {
|
|
38
|
+
const hex = glareColor.replace('#', '')
|
|
39
|
+
let rgba = glareColor
|
|
40
|
+
if (/^[\dA-Fa-f]{6}$/.test(hex)) {
|
|
41
|
+
const r = parseInt(hex.slice(0, 2), 16)
|
|
42
|
+
const g = parseInt(hex.slice(2, 4), 16)
|
|
43
|
+
const b = parseInt(hex.slice(4, 6), 16)
|
|
44
|
+
rgba = `rgba(${r}, ${g}, ${b}, ${glareOpacity})`
|
|
45
|
+
} else if (/^[\dA-Fa-f]{3}$/.test(hex) && hex.length === 3) {
|
|
46
|
+
const r = parseInt(hex[0]! + hex[0]!, 16)
|
|
47
|
+
const g = parseInt(hex[1]! + hex[1]!, 16)
|
|
48
|
+
const b = parseInt(hex[2]! + hex[2]!, 16)
|
|
49
|
+
rgba = `rgba(${r}, ${g}, ${b}, ${glareOpacity})`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const overlayRef = useRef<HTMLDivElement | null>(null)
|
|
53
|
+
|
|
54
|
+
const animateIn = () => {
|
|
55
|
+
const el = overlayRef.current
|
|
56
|
+
if (!el) return
|
|
57
|
+
|
|
58
|
+
el.style.transition = 'none'
|
|
59
|
+
el.style.backgroundPosition = '-100% -100%, 0 0'
|
|
60
|
+
el.offsetHeight
|
|
61
|
+
el.style.transition = `${transitionDuration}ms ease`
|
|
62
|
+
el.style.backgroundPosition = '100% 100%, 0 0'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const animateOut = () => {
|
|
66
|
+
const el = overlayRef.current
|
|
67
|
+
if (!el) return
|
|
68
|
+
|
|
69
|
+
if (playOnce) {
|
|
70
|
+
el.style.transition = 'none'
|
|
71
|
+
el.style.backgroundPosition = '-100% -100%, 0 0'
|
|
72
|
+
} else {
|
|
73
|
+
el.style.transition = `${transitionDuration}ms ease`
|
|
74
|
+
el.style.backgroundPosition = '-100% -100%, 0 0'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const overlayStyle: React.CSSProperties = {
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
inset: 0,
|
|
81
|
+
background: `linear-gradient(${glareAngle}deg,
|
|
82
|
+
hsla(0,0%,0%,0) 60%,
|
|
83
|
+
${rgba} 70%,
|
|
84
|
+
hsla(0,0%,0%,0) 100%)`,
|
|
85
|
+
backgroundSize: `${glareSize}% ${glareSize}%, 100% 100%`,
|
|
86
|
+
backgroundRepeat: 'no-repeat',
|
|
87
|
+
backgroundPosition: '-100% -100%, 0 0',
|
|
88
|
+
pointerEvents: 'none',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
className={`relative grid place-items-center overflow-hidden border cursor-pointer ${className}`}
|
|
94
|
+
style={{
|
|
95
|
+
width,
|
|
96
|
+
height,
|
|
97
|
+
background,
|
|
98
|
+
borderRadius,
|
|
99
|
+
borderColor,
|
|
100
|
+
...style,
|
|
101
|
+
}}
|
|
102
|
+
onMouseEnter={animateIn}
|
|
103
|
+
onMouseLeave={animateOut}
|
|
104
|
+
>
|
|
105
|
+
<div ref={overlayRef} style={overlayStyle} />
|
|
106
|
+
{children}
|
|
107
|
+
</div>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default GlareHover
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React, { useEffect, useRef } from 'react'
|
|
3
|
+
import { gsap } from 'gsap'
|
|
4
|
+
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
|
5
|
+
|
|
6
|
+
gsap.registerPlugin(ScrollTrigger)
|
|
7
|
+
|
|
8
|
+
interface LineAnimProps {
|
|
9
|
+
direction: 'left-to-right' | 'right-to-left' | 'top-to-bottom' | 'bottom-to-top'
|
|
10
|
+
className?: string
|
|
11
|
+
trigger?: 'scroll' | 'immediate'
|
|
12
|
+
duration?: number
|
|
13
|
+
delay?: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const LineAnim: React.FC<LineAnimProps> = ({
|
|
17
|
+
direction,
|
|
18
|
+
className = '',
|
|
19
|
+
trigger = 'scroll',
|
|
20
|
+
duration = 1,
|
|
21
|
+
delay = 0
|
|
22
|
+
}) => {
|
|
23
|
+
const lineRef = useRef<HTMLDivElement>(null)
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!lineRef.current) return
|
|
27
|
+
|
|
28
|
+
const isVertical = direction.includes('top') || direction.includes('bottom')
|
|
29
|
+
const scale = isVertical ? 'scaleY' : 'scaleX'
|
|
30
|
+
|
|
31
|
+
const animation = gsap.fromTo(
|
|
32
|
+
lineRef.current,
|
|
33
|
+
{ [scale]: 0, opacity: 1 },
|
|
34
|
+
{
|
|
35
|
+
[scale]: 1,
|
|
36
|
+
opacity: 1,
|
|
37
|
+
duration,
|
|
38
|
+
delay,
|
|
39
|
+
ease: 'power2.out',
|
|
40
|
+
...(trigger === 'scroll' && {
|
|
41
|
+
scrollTrigger: {
|
|
42
|
+
trigger: lineRef.current,
|
|
43
|
+
start: 'top 100%'
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
animation.kill()
|
|
51
|
+
ScrollTrigger.getAll().forEach((trigger) => trigger.kill())
|
|
52
|
+
}
|
|
53
|
+
}, [direction, trigger, duration, delay])
|
|
54
|
+
|
|
55
|
+
const getLineClasses = () => {
|
|
56
|
+
const baseClasses = 'bg-transparent opacity-0'
|
|
57
|
+
|
|
58
|
+
switch (direction) {
|
|
59
|
+
case 'left-to-right':
|
|
60
|
+
return `h-[1px] w-screen origin-left ${baseClasses}`
|
|
61
|
+
case 'right-to-left':
|
|
62
|
+
return `h-[1px] w-screen origin-right ${baseClasses}`
|
|
63
|
+
case 'top-to-bottom':
|
|
64
|
+
return `w-[1px] h-screen origin-top ${baseClasses}`
|
|
65
|
+
case 'bottom-to-top':
|
|
66
|
+
return `w-[1px] h-screen origin-bottom ${baseClasses}`
|
|
67
|
+
default:
|
|
68
|
+
return baseClasses
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
ref={lineRef}
|
|
75
|
+
className={`${getLineClasses()} ${className}`}
|
|
76
|
+
style={{ transition: 'all 0.3s' }}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default LineAnim
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React, { useEffect, useRef, ReactNode } from 'react'
|
|
2
|
+
import { motion } from 'framer-motion'
|
|
3
|
+
|
|
4
|
+
interface TitleAnims01Props {
|
|
5
|
+
children: ReactNode
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const TitleAnims01: React.FC<TitleAnims01Props> = ({ children }) => {
|
|
9
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const spanText = (text: HTMLElement) => {
|
|
13
|
+
const string = text.innerText
|
|
14
|
+
let spaned = ''
|
|
15
|
+
for (let i = 0; i < string.length; i++) {
|
|
16
|
+
if (string.substring(i, i + 1) === ' ') spaned += string.substring(i, i + 1)
|
|
17
|
+
else spaned += '<span>' + string.substring(i, i + 1) + '</span>'
|
|
18
|
+
}
|
|
19
|
+
text.innerHTML = spaned
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const headline = ref.current
|
|
23
|
+
if (!headline) return
|
|
24
|
+
spanText(headline)
|
|
25
|
+
|
|
26
|
+
const animations = headline.querySelectorAll('.animation')
|
|
27
|
+
|
|
28
|
+
animations.forEach((animation) => {
|
|
29
|
+
const letters = animation.querySelectorAll('span')
|
|
30
|
+
letters.forEach((letter, i) => {
|
|
31
|
+
;(letter as HTMLElement).style.animationDelay = i * 0.1 + 's'
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
}, [])
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<motion.div
|
|
38
|
+
ref={ref}
|
|
39
|
+
initial={{ opacity: 0, y: 50 }}
|
|
40
|
+
animate={{
|
|
41
|
+
opacity: 1,
|
|
42
|
+
y: 0,
|
|
43
|
+
}}
|
|
44
|
+
transition={{
|
|
45
|
+
duration: 0.3,
|
|
46
|
+
delay: 0.2,
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</motion.div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default TitleAnims01
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { FaPlay } from 'react-icons/fa'
|
|
6
|
+
import { cn } from '@/utilities/ui'
|
|
7
|
+
|
|
8
|
+
export const AnimationContainer = ({
|
|
9
|
+
children,
|
|
10
|
+
className = ''
|
|
11
|
+
}: {
|
|
12
|
+
children: React.ReactNode
|
|
13
|
+
className?: string
|
|
14
|
+
}) => {
|
|
15
|
+
const [key, setKey] = React.useState(0)
|
|
16
|
+
const onClick = () => {
|
|
17
|
+
setKey((prv) => prv + 1)
|
|
18
|
+
}
|
|
19
|
+
return (
|
|
20
|
+
<div className={cn('pb-12 pt-4 border-b dark:border-stone-900', className)}>
|
|
21
|
+
<div className="flex-row-end w-full mb-2">
|
|
22
|
+
<Button onClick={onClick} size="icon" className="rounded-md size-9" variant="outline">
|
|
23
|
+
<FaPlay className="size-3" />
|
|
24
|
+
</Button>
|
|
25
|
+
</div>
|
|
26
|
+
<div key={key}>{children}</div>
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { motion, useInView } from 'framer-motion'
|
|
3
|
+
import { cn } from '@/utilities/ui'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
export const BlurIn = ({
|
|
7
|
+
children,
|
|
8
|
+
className
|
|
9
|
+
}: {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
className?: string
|
|
12
|
+
}) => {
|
|
13
|
+
const ref = React.useRef(null)
|
|
14
|
+
const isInView = useInView(ref, { once: false })
|
|
15
|
+
return (
|
|
16
|
+
<motion.div
|
|
17
|
+
ref={ref}
|
|
18
|
+
initial={{ filter: 'blur(40px)', opacity: 0 }}
|
|
19
|
+
animate={isInView ? { filter: 'none', opacity: 1 } : {}}
|
|
20
|
+
transition={{ duration: 0.9, delay: 0, ease: 'easeInOut' }}
|
|
21
|
+
className={cn(className, 'blurin-ani')}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</motion.div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { KeyframeOptions, animate, useInView, useIsomorphicLayoutEffect } from 'framer-motion'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
type AnimatedCounterProps = {
|
|
7
|
+
from: number
|
|
8
|
+
to: number
|
|
9
|
+
animationOptions?: KeyframeOptions & { duration?: number }
|
|
10
|
+
className?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Counter = ({
|
|
14
|
+
from = 0,
|
|
15
|
+
to,
|
|
16
|
+
animationOptions,
|
|
17
|
+
className = 'text-xl font-extrabold sm:text-2xl md:text-3xl',
|
|
18
|
+
}: AnimatedCounterProps) => {
|
|
19
|
+
const ref = React.useRef<HTMLSpanElement>(null)
|
|
20
|
+
const inView = useInView(ref, { once: true })
|
|
21
|
+
|
|
22
|
+
useIsomorphicLayoutEffect(() => {
|
|
23
|
+
const element = ref.current
|
|
24
|
+
|
|
25
|
+
if (!element) return
|
|
26
|
+
if (!inView) return
|
|
27
|
+
|
|
28
|
+
// Set initial value
|
|
29
|
+
element.textContent = String(from)
|
|
30
|
+
|
|
31
|
+
// If reduced motion is enabled in system's preferences
|
|
32
|
+
if (window.matchMedia('(prefers-reduced-motion)').matches) {
|
|
33
|
+
element.textContent = String(to)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const controls = animate(from, to, {
|
|
38
|
+
duration: 10,
|
|
39
|
+
ease: 'easeOut',
|
|
40
|
+
...animationOptions,
|
|
41
|
+
onUpdate(value) {
|
|
42
|
+
element.textContent = value.toFixed(0)
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// Cancel on unmount
|
|
47
|
+
return () => {
|
|
48
|
+
controls.stop()
|
|
49
|
+
}
|
|
50
|
+
}, [ref, inView, from, to])
|
|
51
|
+
|
|
52
|
+
return <span ref={ref} className={className} />
|
|
53
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { motion, useInView } from 'framer-motion'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
export function TextFade({
|
|
6
|
+
direction,
|
|
7
|
+
children,
|
|
8
|
+
className = '',
|
|
9
|
+
stagger = 0.1,
|
|
10
|
+
delay = 0.3
|
|
11
|
+
}: {
|
|
12
|
+
direction: 'up' | 'down' | 'left' | 'right'
|
|
13
|
+
children: React.ReactNode
|
|
14
|
+
className?: string
|
|
15
|
+
stagger?: number
|
|
16
|
+
delay?: number
|
|
17
|
+
}) {
|
|
18
|
+
const getVariant = () => {
|
|
19
|
+
const baseTransition = {
|
|
20
|
+
type: 'spring' as const,
|
|
21
|
+
duration: 0.9,
|
|
22
|
+
delay
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
switch (direction) {
|
|
26
|
+
case 'down':
|
|
27
|
+
return {
|
|
28
|
+
show: { opacity: 1, y: 0, transition: baseTransition },
|
|
29
|
+
hidden: { opacity: 0, y: -20 }
|
|
30
|
+
}
|
|
31
|
+
case 'up':
|
|
32
|
+
return {
|
|
33
|
+
show: { opacity: 1, y: 0, transition: baseTransition },
|
|
34
|
+
hidden: { opacity: 0, y: 20 }
|
|
35
|
+
}
|
|
36
|
+
case 'left':
|
|
37
|
+
return {
|
|
38
|
+
show: { opacity: 1, x: 0, transition: baseTransition },
|
|
39
|
+
hidden: { opacity: 0, x: 20 }
|
|
40
|
+
}
|
|
41
|
+
case 'right':
|
|
42
|
+
return {
|
|
43
|
+
show: { opacity: 1, x: 0, transition: baseTransition },
|
|
44
|
+
hidden: { opacity: 0, x: -20 }
|
|
45
|
+
}
|
|
46
|
+
default:
|
|
47
|
+
return {
|
|
48
|
+
show: { opacity: 1, y: 0, transition: baseTransition },
|
|
49
|
+
hidden: { opacity: 0, y: 20 }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const FADE_VARIANT = getVariant()
|
|
55
|
+
const ref = React.useRef(null)
|
|
56
|
+
const isInView = useInView(ref, { once: false })
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<motion.div
|
|
60
|
+
ref={ref}
|
|
61
|
+
initial="hidden"
|
|
62
|
+
animate={isInView ? 'show' : ''}
|
|
63
|
+
viewport={{ once: false, amount: 0.5 }}
|
|
64
|
+
variants={{
|
|
65
|
+
hidden: {},
|
|
66
|
+
show: {
|
|
67
|
+
transition: {
|
|
68
|
+
staggerChildren: stagger
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
className={className}
|
|
73
|
+
>
|
|
74
|
+
{React.Children.map(children, (child) =>
|
|
75
|
+
React.isValidElement(child) ? (
|
|
76
|
+
<motion.div variants={FADE_VARIANT}>{child}</motion.div>
|
|
77
|
+
) : (
|
|
78
|
+
child
|
|
79
|
+
)
|
|
80
|
+
)}
|
|
81
|
+
</motion.div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { AnimatePresence, motion, useInView } from 'framer-motion'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
import { cn } from '@/utilities/ui'
|
|
6
|
+
|
|
7
|
+
export function GradualSpacing({
|
|
8
|
+
text = 'Gradual Spacing',
|
|
9
|
+
className = '',
|
|
10
|
+
aniTextClass = ''
|
|
11
|
+
}: {
|
|
12
|
+
text: string
|
|
13
|
+
className?: string
|
|
14
|
+
aniTextClass?: string
|
|
15
|
+
}) {
|
|
16
|
+
const ref = React.useRef(null)
|
|
17
|
+
const isInView = useInView(ref, { once: false })
|
|
18
|
+
return (
|
|
19
|
+
<div className={cn('flex space-x-1 gradual-spacing-text', {})}>
|
|
20
|
+
<AnimatePresence>
|
|
21
|
+
{text.split('').map((char, i) => (
|
|
22
|
+
<motion.span
|
|
23
|
+
ref={ref}
|
|
24
|
+
key={i}
|
|
25
|
+
initial={{ opacity: 0, x: -18 }}
|
|
26
|
+
animate={isInView ? { opacity: 1, x: 0 } : {}}
|
|
27
|
+
exit="hidden"
|
|
28
|
+
transition={{ duration: 0.5, delay: i * 0.1 }}
|
|
29
|
+
className={cn('tracking-tighter md:leading-[4rem]', className, aniTextClass)}
|
|
30
|
+
|
|
31
|
+
// className="text-xl text-center sm:text-4xl font-bold tracking-tighter md:text-6xl md:leading-[4rem]"
|
|
32
|
+
>
|
|
33
|
+
{char === ' ' ? <span> </span> : char}
|
|
34
|
+
</motion.span>
|
|
35
|
+
))}
|
|
36
|
+
</AnimatePresence>
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { cn } from '@/utilities/ui'
|
|
3
|
+
import { motion, useInView } from 'framer-motion'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
export function LettersPullUp({
|
|
7
|
+
text,
|
|
8
|
+
className = '',
|
|
9
|
+
aniTextClass = '',
|
|
10
|
+
}: {
|
|
11
|
+
text: string
|
|
12
|
+
className?: string
|
|
13
|
+
aniTextClass?: string
|
|
14
|
+
}) {
|
|
15
|
+
const splittedText = text.split('')
|
|
16
|
+
|
|
17
|
+
const pullupVariant = {
|
|
18
|
+
initial: { y: 100, opacity: 0 },
|
|
19
|
+
animate: (i: number) => ({
|
|
20
|
+
y: 0,
|
|
21
|
+
opacity: 1,
|
|
22
|
+
transition: {
|
|
23
|
+
delay: i * 0.15,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
}
|
|
27
|
+
const ref = React.useRef<HTMLDivElement>(null)
|
|
28
|
+
const isInView = useInView(ref, { once: false })
|
|
29
|
+
return (
|
|
30
|
+
<div className="flex indie-pull-up-justify">
|
|
31
|
+
{splittedText.map((current, i) => (
|
|
32
|
+
<motion.div
|
|
33
|
+
key={i}
|
|
34
|
+
ref={ref}
|
|
35
|
+
variants={pullupVariant}
|
|
36
|
+
initial="initial"
|
|
37
|
+
animate={isInView ? 'animate' : ''}
|
|
38
|
+
custom={i}
|
|
39
|
+
className={cn('indie-pull-up', className, aniTextClass)}
|
|
40
|
+
>
|
|
41
|
+
{current === ' ' ? <span className="indie-pull-up-space"> </span> : current}
|
|
42
|
+
</motion.div>
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function WordsPullUp({
|
|
49
|
+
text,
|
|
50
|
+
className = '',
|
|
51
|
+
aniTextClass = '',
|
|
52
|
+
}: {
|
|
53
|
+
text: string
|
|
54
|
+
className?: string
|
|
55
|
+
aniTextClass?: string
|
|
56
|
+
}) {
|
|
57
|
+
const splittedText = text.split(' ')
|
|
58
|
+
|
|
59
|
+
const pullupVariant = {
|
|
60
|
+
initial: { y: 100, opacity: 0 },
|
|
61
|
+
animate: (i: number) => ({
|
|
62
|
+
y: 0,
|
|
63
|
+
opacity: 1,
|
|
64
|
+
transition: {
|
|
65
|
+
delay: i * 0.15,
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
}
|
|
69
|
+
const ref = React.useRef(null)
|
|
70
|
+
const isInView = useInView(ref, { once: false })
|
|
71
|
+
return (
|
|
72
|
+
<div className="flex indie-pull-up-justify">
|
|
73
|
+
{splittedText.map((current, i) => (
|
|
74
|
+
<motion.div
|
|
75
|
+
key={i}
|
|
76
|
+
ref={ref}
|
|
77
|
+
variants={pullupVariant}
|
|
78
|
+
initial="initial"
|
|
79
|
+
animate={isInView ? 'animate' : ''}
|
|
80
|
+
custom={i}
|
|
81
|
+
className={cn(
|
|
82
|
+
'indie-pull-up',
|
|
83
|
+
'pr-2', // class to separate words
|
|
84
|
+
className,
|
|
85
|
+
aniTextClass,
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
{current === '' ? <span className="indie-pull-up-space"> </span> : current}
|
|
89
|
+
</motion.div>
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useId } from 'react'
|
|
4
|
+
import { AnimatePresence } from 'framer-motion'
|
|
5
|
+
import FadeUpOnInView from './FadeUpOnInView'
|
|
6
|
+
|
|
7
|
+
interface RevealTextProps {
|
|
8
|
+
text: string[]
|
|
9
|
+
className?: string
|
|
10
|
+
aniTextClass?: string
|
|
11
|
+
instanceIndex?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Global counter to ensure unique instances
|
|
15
|
+
let globalInstanceCounter = 0
|
|
16
|
+
|
|
17
|
+
export const RevealText: React.FC<RevealTextProps> = ({
|
|
18
|
+
text,
|
|
19
|
+
className,
|
|
20
|
+
aniTextClass,
|
|
21
|
+
instanceIndex
|
|
22
|
+
}) => {
|
|
23
|
+
const uniqueId = useId()
|
|
24
|
+
// Create a unique instance ID that persists across renders
|
|
25
|
+
const uniqueInstanceId = useRef<number | undefined>(undefined)
|
|
26
|
+
|
|
27
|
+
// Initialize unique instance ID only once
|
|
28
|
+
if (uniqueInstanceId.current === undefined) {
|
|
29
|
+
uniqueInstanceId.current = instanceIndex ?? globalInstanceCounter++
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const textRef = useRef<HTMLSpanElement>(null)
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const threshold = 0.3
|
|
36
|
+
const observer = new IntersectionObserver(
|
|
37
|
+
([entry]) => {
|
|
38
|
+
if (entry && entry.isIntersecting && textRef.current && text[0]) {
|
|
39
|
+
const element = textRef.current
|
|
40
|
+
const string = text[0]
|
|
41
|
+
let spaned = ''
|
|
42
|
+
for (let i = 0; i < string.length; i++) {
|
|
43
|
+
spaned += string[i] === ' ' ? ' ' : `<span>${string[i]}</span>`
|
|
44
|
+
}
|
|
45
|
+
element.innerHTML = spaned
|
|
46
|
+
const letters = element.querySelectorAll('span')
|
|
47
|
+
|
|
48
|
+
// Use the unique instance ID for staggering
|
|
49
|
+
const baseDelay = (uniqueInstanceId.current ?? 0) * 0.05
|
|
50
|
+
letters.forEach((letter, i) => {
|
|
51
|
+
letter.setAttribute('style', `animation-delay: ${baseDelay + i * 0.05}s;`)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{ threshold }
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if (textRef.current) observer.observe(textRef.current)
|
|
59
|
+
|
|
60
|
+
return () => observer.disconnect()
|
|
61
|
+
}, [text, uniqueId])
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<AnimatePresence mode="wait">
|
|
65
|
+
<FadeUpOnInView delay={0 + (uniqueInstanceId.current ?? 0) * 0.1} className="fadeup">
|
|
66
|
+
<span
|
|
67
|
+
ref={textRef}
|
|
68
|
+
className={`reveal-text animation ${className || ''} ${aniTextClass || ''}`}
|
|
69
|
+
style={{ fontWeight: '700' }}
|
|
70
|
+
dangerouslySetInnerHTML={{ __html: text[0] || '' }}
|
|
71
|
+
/>
|
|
72
|
+
</FadeUpOnInView>
|
|
73
|
+
</AnimatePresence>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
export default RevealText
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { cn } from '@/utilities/ui'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { AnimatePresence, motion } from 'framer-motion'
|
|
5
|
+
|
|
6
|
+
export function RotateWords({
|
|
7
|
+
text = 'Rotate',
|
|
8
|
+
words = ['Word 1', 'Word 2', 'Word 3'],
|
|
9
|
+
className = '',
|
|
10
|
+
aniTextClass = '',
|
|
11
|
+
}: {
|
|
12
|
+
text: string
|
|
13
|
+
words: string[]
|
|
14
|
+
className?: string
|
|
15
|
+
aniTextClass?: string
|
|
16
|
+
}) {
|
|
17
|
+
const [index, setIndex] = React.useState(0)
|
|
18
|
+
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
const interval = setInterval(() => {
|
|
21
|
+
setIndex((prevIndex) => (prevIndex + 1) % words.length)
|
|
22
|
+
}, 5000)
|
|
23
|
+
// Clean up interval on unmount
|
|
24
|
+
return () => clearInterval(interval)
|
|
25
|
+
}, [words.length])
|
|
26
|
+
return (
|
|
27
|
+
<div className={cn('tracking-tighter md:leading-[4rem] flex gap-1.5', className, aniTextClass)}>
|
|
28
|
+
{/* <div className="text-xl text-center sm:text-4xl font-bold tracking-tighter md:text-6xl md:leading-[4rem] w-fit flex items-center jusitfy-center mx-auto gap-1.5"> */}
|
|
29
|
+
{text}{' '}
|
|
30
|
+
<AnimatePresence mode="wait">
|
|
31
|
+
<motion.span
|
|
32
|
+
key={words[index]}
|
|
33
|
+
initial={{ opacity: 0, y: -40 }}
|
|
34
|
+
animate={{ opacity: 1, y: 0 }}
|
|
35
|
+
exit={{ opacity: 0, y: 40 }}
|
|
36
|
+
transition={{ duration: 0.5, delay: 0.3 }}
|
|
37
|
+
>
|
|
38
|
+
{words[index]}
|
|
39
|
+
</motion.span>
|
|
40
|
+
</AnimatePresence>
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
}
|