@catalystsoftware/ui 1.0.5 → 1.0.6
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/dist/data/data.tsx +29 -29
- package/dist/data/tailwind.config.js +3821 -261
- package/dist/data.tsx +29 -29
- package/package.json +4 -3
- package/components/catalyst-ui/buttons/burger.tsx +0 -207
- package/components/catalyst-ui/core/data-display/timeline.tsx +0 -210
- package/components/catalyst-ui/core/feedback/alert.tsx +0 -491
- package/components/catalyst-ui/core/feedback/spinner-1.tsx +0 -65
- package/components/catalyst-ui/core/feedback/toast.tsx +0 -1857
- package/components/catalyst-ui/core/navigation/menu.tsx +0 -164
- package/components/catalyst-ui/forms/toggle-class.tsx +0 -176
- package/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +0 -419
- package/components/catalyst-ui/hooks/use-counter.tsx +0 -13
- package/components/catalyst-ui/hooks/use-event-listener.tsx +0 -23
- package/components/catalyst-ui/hooks/use-export-markdown.tsx +0 -47
- package/components/catalyst-ui/hooks/use-focus.tsx +0 -17
- package/components/catalyst-ui/hooks/use-interval.tsx +0 -23
- package/components/catalyst-ui/hooks/use-is-client.tsx +0 -16
- package/components/catalyst-ui/hooks/use-media-query.tsx +0 -19
- package/components/catalyst-ui/hooks/use-mobile.tsx +0 -19
- package/components/catalyst-ui/hooks/use-resize-observer.tsx +0 -81
- package/components/catalyst-ui/hooks/use-timeout.tsx +0 -21
- package/components/catalyst-ui/hooks/use-timer.tsx +0 -209
- package/components/catalyst-ui/hooks/use-toggle.tsx +0 -12
- package/components/catalyst-ui/media/image.tsx +0 -13
- package/components/catalyst-ui/overlays/dual-sidebar.tsx +0 -4142
- package/components/catalyst-ui/overlays/sidebar-original.tsx +0 -726
- package/components/catalyst-ui/primitives/accordion.tsx +0 -250
- package/components/catalyst-ui/primitives/alert-dialog.tsx +0 -126
- package/components/catalyst-ui/primitives/aspect-ratio.tsx +0 -9
- package/components/catalyst-ui/primitives/avatar.tsx +0 -296
- package/components/catalyst-ui/primitives/badge.tsx +0 -57
- package/components/catalyst-ui/primitives/breadcrumb.tsx +0 -101
- package/components/catalyst-ui/primitives/button.tsx +0 -265
- package/components/catalyst-ui/primitives/calendar-v4.tsx +0 -208
- package/components/catalyst-ui/primitives/calendar.tsx +0 -295
- package/components/catalyst-ui/primitives/card.tsx +0 -618
- package/components/catalyst-ui/primitives/carousel.tsx +0 -238
- package/components/catalyst-ui/primitives/chart.tsx +0 -347
- package/components/catalyst-ui/primitives/checkbox.tsx +0 -225
- package/components/catalyst-ui/primitives/collapsible.tsx +0 -212
- package/components/catalyst-ui/primitives/command.tsx +0 -393
- package/components/catalyst-ui/primitives/context-menu.tsx +0 -236
- package/components/catalyst-ui/primitives/dialog.tsx +0 -471
- package/components/catalyst-ui/primitives/drawer.tsx +0 -761
- package/components/catalyst-ui/primitives/dropdown-menu.tsx +0 -290
- package/components/catalyst-ui/primitives/empty.tsx +0 -104
- package/components/catalyst-ui/primitives/field.tsx +0 -244
- package/components/catalyst-ui/primitives/hover-card.tsx +0 -124
- package/components/catalyst-ui/primitives/input-otp.tsx +0 -76
- package/components/catalyst-ui/primitives/input.tsx +0 -64
- package/components/catalyst-ui/primitives/item.tsx +0 -196
- package/components/catalyst-ui/primitives/kbd.tsx +0 -75
- package/components/catalyst-ui/primitives/label.tsx +0 -24
- package/components/catalyst-ui/primitives/navigation-menu.tsx +0 -150
- package/components/catalyst-ui/primitives/pagination.tsx +0 -198
- package/components/catalyst-ui/primitives/popover.tsx +0 -232
- package/components/catalyst-ui/primitives/progress.tsx +0 -34
- package/components/catalyst-ui/primitives/radio-group.tsx +0 -43
- package/components/catalyst-ui/primitives/resizable.tsx +0 -56
- package/components/catalyst-ui/primitives/select.tsx +0 -155
- package/components/catalyst-ui/primitives/separator.tsx +0 -74
- package/components/catalyst-ui/primitives/sheet.tsx +0 -126
- package/components/catalyst-ui/primitives/skeleton.tsx +0 -15
- package/components/catalyst-ui/primitives/slider.tsx +0 -27
- package/components/catalyst-ui/primitives/switch.tsx +0 -187
- package/components/catalyst-ui/primitives/tabs.tsx +0 -335
- package/components/catalyst-ui/primitives/textarea.tsx +0 -24
- package/components/catalyst-ui/primitives/toggle-group.tsx +0 -55
- package/components/catalyst-ui/primitives/toggle.tsx +0 -42
- package/components/catalyst-ui/primitives/tooltip.tsx +0 -116
- package/components/catalyst-ui/utils/basic-auth.tsx +0 -40
- package/components/catalyst-ui/utils/context-storage.tsx +0 -19
- package/components/catalyst-ui/utils/cors-middleware.tsx +0 -71
- package/components/catalyst-ui/utils/deferred-content.tsx +0 -595
- package/components/catalyst-ui/utils/honeypot-middleware.tsx +0 -38
- package/components/catalyst-ui/utils/incId.tsx +0 -75
- package/components/catalyst-ui/utils/jwk-auth.tsx +0 -36
- package/components/catalyst-ui/utils/request-id.tsx +0 -14
- package/components/catalyst-ui/utils/secure-headers.tsx +0 -37
- package/components/catalyst-ui/utils/server-timing.tsx +0 -23
- package/components/catalyst-ui/utils/utils.ts +0 -43
- package/components/catalyst-ui/utils/with-cookie.tsx +0 -43
- package/components/catalyst-ui/x/accordian-x.tsx +0 -428
- package/components/catalyst-ui/x/alert-x.tsx +0 -413
- package/components/catalyst-ui/x/animated-text-x.tsx +0 -2242
- package/components/catalyst-ui/x/avatar-x.tsx +0 -515
- package/components/catalyst-ui/x/badge-x.tsx +0 -670
- package/components/catalyst-ui/x/button-X.tsx +0 -2857
- package/components/catalyst-ui/x/button-group-x.tsx +0 -847
- package/components/catalyst-ui/x/calendar-x.tsx +0 -1910
- package/components/catalyst-ui/x/card-x.tsx +0 -2597
- package/components/catalyst-ui/x/checkbox-x.tsx +0 -656
- package/components/catalyst-ui/x/collapsible-x.tsx +0 -1360
- package/components/catalyst-ui/x/combobox-x.tsx +0 -911
- package/components/catalyst-ui/x/data-table-x.tsx +0 -1753
- package/components/catalyst-ui/x/date-picker-x.tsx +0 -648
- package/components/catalyst-ui/x/dialog-x.tsx +0 -659
- package/components/catalyst-ui/x/dropdown-menu-x.tsx +0 -612
- package/components/catalyst-ui/x/hover-card-x.tsx +0 -375
- package/components/catalyst-ui/x/icon-x.tsx +0 -840
- package/components/catalyst-ui/x/input-mask-x.tsx +0 -981
- package/components/catalyst-ui/x/input-otp-x.tsx +0 -659
- package/components/catalyst-ui/x/loader-x.tsx +0 -1757
- package/components/catalyst-ui/x/pagination-x.tsx +0 -622
- package/components/catalyst-ui/x/popover-x.tsx +0 -744
- package/components/catalyst-ui/x/radio-group-x.tsx +0 -499
- package/components/catalyst-ui/x/select-x.tsx +0 -1127
- package/components/catalyst-ui/x/sheet-x.tsx +0 -668
- package/components/catalyst-ui/x/switch-x.tsx +0 -681
- package/components/catalyst-ui/x/table-x.tsx +0 -574
- package/components/catalyst-ui/x/tabs-x.tsx +0 -839
- package/components/catalyst-ui/x/textarea-x.tsx +0 -1263
- package/components/catalyst-ui/x/tooltip-x.tsx +0 -396
- package/components/catalyst-ui/x/tracker-x.tsx +0 -560
- package/data/bg-data.tsx +0 -901
- package/data/buttons-data.tsx +0 -2327
- package/data/charts-data.tsx +0 -102
- package/data/chat-data.tsx +0 -83
- package/data/code-data.tsx +0 -1040
- package/data/comboboxes-data.tsx +0 -1843
- package/data/command-data.tsx +0 -1381
- package/data/core-data.tsx +0 -15953
- package/data/crm-data.tsx +0 -47
- package/data/data.tsx +0 -159
- package/data/date-and-time-data.tsx +0 -554
- package/data/dependencies.tsx +0 -7
- package/data/ecommerce-data.tsx +0 -1387
- package/data/forms-data.tsx +0 -7890
- package/data/hooks-data.tsx +0 -5487
- package/data/index.ts +0 -34
- package/data/inputs-data.tsx +0 -557
- package/data/interactive-data.tsx +0 -5394
- package/data/lofi-data.tsx +0 -18295
- package/data/marketing-data.tsx +0 -2546
- package/data/media-data.tsx +0 -1510
- package/data/motion-data.tsx +0 -5801
- package/data/overlay-data.tsx +0 -4136
- package/data/pdf-data.tsx +0 -124
- package/data/pos-data.tsx +0 -213
- package/data/postcss.config.js +0 -6
- package/data/primitive-data.tsx +0 -5170
- package/data/prompt-data.tsx +0 -1226
- package/data/requiredLibs.ts +0 -4
- package/data/sandbox-data.tsx +0 -1
- package/data/sidebars-data.tsx +0 -5421
- package/data/stacks-data.tsx +0 -32
- package/data/table-data.tsx +0 -706
- package/data/tailwind.config.js +0 -270
- package/data/tailwind.config.ngin.js +0 -3830
- package/data/tailwind.css +0 -431
- package/data/tools-data.tsx +0 -6910
- package/data/typography-data.tsx +0 -2050
- package/data/utils-data.tsx +0 -6500
- package/data/x-data.tsx +0 -1171
|
@@ -1,2242 +0,0 @@
|
|
|
1
|
-
import React, { FC, useEffect, useRef, CSSProperties, useState, useId, useMemo, ComponentPropsWithoutRef, ReactNode, useCallback, } from "react"
|
|
2
|
-
import { cn } from "~/components/catalyst-ui"
|
|
3
|
-
import { HTMLMotionProps, motion, useAnimation, useInView, AnimatePresence, MotionProps, Transition, Variants, MotionValue, useScroll, useTransform, animate, useMotionValue, } from "motion/react"
|
|
4
|
-
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
-
|
|
6
|
-
type AnimationVariant = | "Rotate" | "ExpandableTypewriter" | "TypingAnimation" | "Typewriter" | "Rewind" | "Reveal" | "Morph" | "Swoosh" | "Sliced" | "Shimmer" | "Matrix" | "Hyper" | "Glitch" | "Encrypted" | "Comic" | "AnimatedGlitch" | "default";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* type AnimationVariant = | "Rotate" | "ExpandableTypewriter" | "TypingAnimation" | "Typewriter" | "Rewind" | "Reveal" | "Morph" | "Swoosh" | "Sliced" | "Shimmer" | "Matrix" | "Hyper" | "Glitch" | "Encrypted" | "Comic" | "AnimatedGlitch" | "default";
|
|
10
|
-
* ============================ DEFAULT (AnimateText) ============================
|
|
11
|
-
* text: string (default: "Welcome to the Matrix, Neo.!") - any variant that uses text as a prop will default to this
|
|
12
|
-
* type?: "fadeIn" | "fadeInUp" | "popIn" | "shiftInUp" | "rollIn" | "whipIn" | "whipInUp" | "calmInUp" | "blurIn" | "blurInUp" | "blurInDown" | "slideUp" | "slideDown" | "slideLeft" | "slideRight" | "scaleUp" | "scaleDown"
|
|
13
|
-
* className?: string
|
|
14
|
-
* example: <AnimateText text="Roll In" type="rollIn" />
|
|
15
|
-
* note: this being the default, theres no need to call the function with the variant prop in order to use, granting acces to 18 different text animations alone.
|
|
16
|
-
*
|
|
17
|
-
* ============================ AnimatedGlitch ==================================
|
|
18
|
-
* text: string
|
|
19
|
-
* as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span"
|
|
20
|
-
* textClassName?: string
|
|
21
|
-
* containerClassName?: string
|
|
22
|
-
* colors?: { red: string, green: string, blue: string }
|
|
23
|
-
* example: <AnimateText variant='AnimatedGlitch' text="GLITCH" colors={{ red: "#ff0000", green: "#00ff00", blue: "#0000ff" }} />
|
|
24
|
-
*
|
|
25
|
-
* ============================ Rotate ==========================================
|
|
26
|
-
* words: string[] - Array of words to rotate through
|
|
27
|
-
* duration?: number (default: 2500) - Time in ms between word changes
|
|
28
|
-
* motionProps?: MotionProps - Custom motion properties
|
|
29
|
-
* className?: string
|
|
30
|
-
* example: <AnimateText variant='Rotate' words={["First", "Second", "Third"]} duration={2000} />
|
|
31
|
-
*
|
|
32
|
-
* ============================ ExpandableTypewriter ============================
|
|
33
|
-
* delay: number - Initial delay before animation starts
|
|
34
|
-
* texts: string[] - Array of texts to cycle through
|
|
35
|
-
* baseText?: string - Initial base text to type out
|
|
36
|
-
* example: <AnimateText variant='ExpandableTypewriter' delay={0.5} texts={["Hello", "World"]} baseText="Welcome: " />
|
|
37
|
-
*
|
|
38
|
-
* ============================ TypingAnimation =================================
|
|
39
|
-
* children?: string - Single text to type
|
|
40
|
-
* words?: string[] - Multiple words to cycle through
|
|
41
|
-
* className?: string
|
|
42
|
-
* duration?: number (default: 100) - Speed per character
|
|
43
|
-
* typeSpeed?: number - Override duration for typing
|
|
44
|
-
* deleteSpeed?: number - Speed for deleting (default: typeSpeed/2)
|
|
45
|
-
* delay?: number (default: 0)
|
|
46
|
-
* pauseDelay?: number (default: 1000)
|
|
47
|
-
* loop?: boolean (default: false)
|
|
48
|
-
* as?: React.ElementType (default: "span")
|
|
49
|
-
* startOnView?: boolean (default: true)
|
|
50
|
-
* showCursor?: boolean (default: true)
|
|
51
|
-
* blinkCursor?: boolean (default: true)
|
|
52
|
-
* cursorStyle?: "line" | "block" | "underscore"
|
|
53
|
-
* example: <AnimateText variant='TypingAnimation' words={["TypeScript", "React", "Next.js"]} loop showCursor />
|
|
54
|
-
*
|
|
55
|
-
* ============================ Typewriter ======================================
|
|
56
|
-
* sequences?: TypewriterSequence[] - Array of { text: string, deleteAfter?: boolean, pauseAfter?: number }
|
|
57
|
-
* typingSpeed?: number (default: 50)
|
|
58
|
-
* startDelay?: number (default: 500)
|
|
59
|
-
* autoLoop?: boolean (default: true)
|
|
60
|
-
* loopDelay?: number (default: 2000)
|
|
61
|
-
* size?: "sm" | "md" | "lg"
|
|
62
|
-
* className?: string
|
|
63
|
-
* containerClassName?: string
|
|
64
|
-
* example: <AnimateText variant='Typewriter' sequences={[{ text: "Hello", deleteAfter: true }]} size="md" />
|
|
65
|
-
*
|
|
66
|
-
* ============================ Rewind ==========================================
|
|
67
|
-
* text?: string
|
|
68
|
-
* className?: string
|
|
69
|
-
* shadowColors?: { first?: string, second?: string, third?: string, fourth?: string, glow?: string }
|
|
70
|
-
* example: <AnimateText variant='Rewind' text="HOVER ME" shadowColors={{ first: "#07bccc", glow: "#f40468" }} />
|
|
71
|
-
*
|
|
72
|
-
* ============================ Swoosh ==========================================
|
|
73
|
-
* text?: string
|
|
74
|
-
* shadowColors?: { first?: string, second?: string, third?: string, fourth?: string, glow?: string }
|
|
75
|
-
* size?: "sm" | "md" | "lg" | "xl"
|
|
76
|
-
* className?: string
|
|
77
|
-
* disabled?: boolean
|
|
78
|
-
* example: <AnimateText variant='Swoosh' text="SWOOSH" size="lg" />
|
|
79
|
-
*
|
|
80
|
-
* ============================ Sliced ==========================================
|
|
81
|
-
* text: string
|
|
82
|
-
* splitSpacing?: number (default: 2)
|
|
83
|
-
* size?: "sm" | "md" | "lg" | "xl"
|
|
84
|
-
* className?: string
|
|
85
|
-
* containerClassName?: string
|
|
86
|
-
* disabled?: boolean
|
|
87
|
-
* example: <AnimateText variant='Sliced' text="SLICE" splitSpacing={4} size="lg" />
|
|
88
|
-
*
|
|
89
|
-
* ============================ Shimmer =========================================
|
|
90
|
-
* text: string
|
|
91
|
-
* duration?: number (default: 2.5)
|
|
92
|
-
* variant?: "default" | "primary" | "secondary" | "accent"
|
|
93
|
-
* size?: "sm" | "md" | "lg" | "xl"
|
|
94
|
-
* className?: string
|
|
95
|
-
* containerClassName?: string
|
|
96
|
-
* disabled?: boolean
|
|
97
|
-
* example: <AnimateText variant='Shimmer' text="Shimmer" duration={3} variant="primary" />
|
|
98
|
-
*
|
|
99
|
-
* ============================ Matrix ==========================================
|
|
100
|
-
* text?: string (default: "Welcome to the Matrix, Neo.!")
|
|
101
|
-
* initialDelay?: number (default: 200)
|
|
102
|
-
* letterAnimationDuration?: number (default: 500)
|
|
103
|
-
* letterInterval?: number (default: 100)
|
|
104
|
-
* matrixColor?: string (default: "#00ff00")
|
|
105
|
-
* loop?: boolean (default: false)
|
|
106
|
-
* size?: "sm" | "md" | "lg"
|
|
107
|
-
* alignment?: "left" | "center" | "right"
|
|
108
|
-
* className?: string
|
|
109
|
-
* example: <AnimateText variant='Matrix' text="MATRIX" matrixColor="#00ff00" loop />
|
|
110
|
-
*
|
|
111
|
-
* ============================ Glitch ==========================================
|
|
112
|
-
* text: string
|
|
113
|
-
* className?: string
|
|
114
|
-
* intensity?: "low" | "medium" | "high"
|
|
115
|
-
* duration?: number (default: 2000)
|
|
116
|
-
* enabled?: boolean (default: true)
|
|
117
|
-
* fontSize?: "sm" | "md" | "lg" | "xl" | "2xl"
|
|
118
|
-
* example: <AnimateText variant='Glitch' text="GLITCH" intensity="high" fontSize="xl" />
|
|
119
|
-
*
|
|
120
|
-
* ============================ Encrypted =======================================
|
|
121
|
-
* text: string
|
|
122
|
-
* className?: string
|
|
123
|
-
* revealDelayMs?: number (default: 50) - Time between revealing each character
|
|
124
|
-
* charset?: string - Custom character set for encryption
|
|
125
|
-
* flipDelayMs?: number (default: 50) - Time between gibberish flips
|
|
126
|
-
* encryptedClassName?: string
|
|
127
|
-
* revealedClassName?: string
|
|
128
|
-
* example: <AnimateText variant='Encrypted' text="SECRET" revealDelayMs={100} />
|
|
129
|
-
*
|
|
130
|
-
* ============================ Hyper ===========================================
|
|
131
|
-
* children: string
|
|
132
|
-
* className?: string
|
|
133
|
-
* duration?: number (default: 800)
|
|
134
|
-
* delay?: number (default: 0)
|
|
135
|
-
* as?: React.ElementType (default: "div")
|
|
136
|
-
* startOnView?: boolean (default: false)
|
|
137
|
-
* animateOnHover?: boolean (default: true)
|
|
138
|
-
* characterSet?: string[] (default: A-Z)
|
|
139
|
-
* example: <AnimateText variant='Hyper' duration={1000} animateOnHover>HYPERTEXT</AnimateText>
|
|
140
|
-
*
|
|
141
|
-
* ============================ Comic ===========================================
|
|
142
|
-
* children: string - The text to display in comic style
|
|
143
|
-
* className?: string
|
|
144
|
-
* style?: CSSProperties
|
|
145
|
-
* fontSize?: number (default: 5)
|
|
146
|
-
* example: <AnimateText variant='Comic' fontSize={4}>POW!</AnimateText>
|
|
147
|
-
*
|
|
148
|
-
* ============================ Reveal ==========================================
|
|
149
|
-
* children: string - Text to reveal on scroll
|
|
150
|
-
* className?: string
|
|
151
|
-
* example: <AnimateText variant='Reveal'>This text reveals as you scroll down the page</AnimateText>
|
|
152
|
-
*
|
|
153
|
-
* ============================ Morph ===========================================
|
|
154
|
-
* children: string - Text that morphs between changes
|
|
155
|
-
* as?: React.ElementType (default: "p")
|
|
156
|
-
* className?: string
|
|
157
|
-
* style?: React.CSSProperties
|
|
158
|
-
* variants?: Variants - Custom Framer Motion variants
|
|
159
|
-
* transition?: Transition - Custom Framer Motion transition
|
|
160
|
-
* example: <AnimateText variant='Morph'>Morphing Text</AnimateText>
|
|
161
|
-
*
|
|
162
|
-
*/
|
|
163
|
-
|
|
164
|
-
function AnimatedTextX({
|
|
165
|
-
text = "Welcome to the Matrix, Neo.",
|
|
166
|
-
variant = 'default' | AnimationVariant,
|
|
167
|
-
useCustomVariants = false,
|
|
168
|
-
useBouncy = false,
|
|
169
|
-
children,
|
|
170
|
-
...props }) {
|
|
171
|
-
|
|
172
|
-
switch (variant) {
|
|
173
|
-
case 'Rotate':
|
|
174
|
-
return <WordRotate {...props} />;
|
|
175
|
-
case 'ExpandableTypewriter':
|
|
176
|
-
return <ExpandableTypewriter {...props} />;
|
|
177
|
-
case 'TypingAnimation':
|
|
178
|
-
return <TypingAnimation {...props} />;
|
|
179
|
-
case 'Typewriter':
|
|
180
|
-
return <Typewriter {...props} />;
|
|
181
|
-
case 'Rewind':
|
|
182
|
-
return <TextRewind text={text} {...props} />;
|
|
183
|
-
case 'Swoosh':
|
|
184
|
-
return <SwooshText text={text} {...props} />;
|
|
185
|
-
case 'Sliced':
|
|
186
|
-
return <SlicedText text={text} {...props} />;
|
|
187
|
-
case 'Shimmer':
|
|
188
|
-
return <ShimmerText text={text} {...props} />;
|
|
189
|
-
case 'Matrix':
|
|
190
|
-
return <MatrixText text={text} {...props} />;
|
|
191
|
-
case 'AnimatedGlitch':
|
|
192
|
-
return <AnimatedGlitchText text={text} {...props} />;
|
|
193
|
-
case 'Glitch':
|
|
194
|
-
return <GlitchText text={text} {...props} />;
|
|
195
|
-
case 'Encrypted':
|
|
196
|
-
return <EncryptedText text={text} {...props} />;
|
|
197
|
-
case 'Reveal':
|
|
198
|
-
return <TextReveal {...props}>{children}</TextReveal>;
|
|
199
|
-
case 'Morph':
|
|
200
|
-
return <TextMorph {...props} variants={useCustomVariants ? customVariants : undefined} transition={useBouncy ? bouncyTransition : smoothTransition}>{children}</TextMorph>;
|
|
201
|
-
case 'Comic':
|
|
202
|
-
return <ComicText {...props}>{children}</ComicText>;
|
|
203
|
-
case 'Hyper':
|
|
204
|
-
return <HyperText {...props}>{children}</HyperText>;
|
|
205
|
-
case 'default':
|
|
206
|
-
default:
|
|
207
|
-
return <AnimateText text={text} {...props} />;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
AnimatedTextX.displayName = "AnimatedTextX"
|
|
211
|
-
|
|
212
|
-
interface WordRotateProps {
|
|
213
|
-
words: string[]
|
|
214
|
-
duration?: number
|
|
215
|
-
motionProps?: MotionProps
|
|
216
|
-
className?: string
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function WordRotate({
|
|
220
|
-
words,
|
|
221
|
-
duration = 2500,
|
|
222
|
-
motionProps = {
|
|
223
|
-
initial: { opacity: 0, y: -50 },
|
|
224
|
-
animate: { opacity: 1, y: 0 },
|
|
225
|
-
exit: { opacity: 0, y: 50 },
|
|
226
|
-
transition: { duration: 0.25, ease: "easeOut" },
|
|
227
|
-
},
|
|
228
|
-
className,
|
|
229
|
-
}: WordRotateProps) {
|
|
230
|
-
const [index, setIndex] = useState(0)
|
|
231
|
-
|
|
232
|
-
useEffect(() => {
|
|
233
|
-
const interval = setInterval(() => {
|
|
234
|
-
setIndex((prevIndex) => (prevIndex + 1) % words.length)
|
|
235
|
-
}, duration)
|
|
236
|
-
|
|
237
|
-
return () => clearInterval(interval)
|
|
238
|
-
}, [words, duration])
|
|
239
|
-
|
|
240
|
-
return (
|
|
241
|
-
<div className="overflow-hidden py-2">
|
|
242
|
-
<AnimatePresence mode="wait">
|
|
243
|
-
<motion.h1
|
|
244
|
-
key={words[index]}
|
|
245
|
-
className={cn(className)}
|
|
246
|
-
{...motionProps}
|
|
247
|
-
>
|
|
248
|
-
{words[index]}
|
|
249
|
-
</motion.h1>
|
|
250
|
-
</AnimatePresence>
|
|
251
|
-
</div>
|
|
252
|
-
)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
interface ITypewriterProps {
|
|
256
|
-
delay: number
|
|
257
|
-
texts: string[]
|
|
258
|
-
baseText?: string
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function ExpandableTypewriter({ delay, texts, baseText = "" }: ITypewriterProps) {
|
|
262
|
-
const [animationComplete, setAnimationComplete] = useState(false)
|
|
263
|
-
const count = useMotionValue(0)
|
|
264
|
-
const rounded = useTransform(count, (latest) => Math.round(latest))
|
|
265
|
-
const displayText = useTransform(rounded, (latest) =>
|
|
266
|
-
baseText.slice(0, latest)
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
useEffect(() => {
|
|
270
|
-
const controls = animate(count, baseText.length, {
|
|
271
|
-
type: "tween",
|
|
272
|
-
delay,
|
|
273
|
-
duration: 1,
|
|
274
|
-
ease: [0.42, 0, 0.58, 1] as const,
|
|
275
|
-
onComplete: () => setAnimationComplete(true),
|
|
276
|
-
})
|
|
277
|
-
return () => {
|
|
278
|
-
controls.stop && controls.stop()
|
|
279
|
-
}
|
|
280
|
-
}, [count, baseText.length, delay])
|
|
281
|
-
|
|
282
|
-
return (
|
|
283
|
-
<span>
|
|
284
|
-
<motion.span>{displayText}</motion.span>
|
|
285
|
-
{animationComplete && (
|
|
286
|
-
<RepeatedTextAnimation texts={texts} delay={delay + 1} />
|
|
287
|
-
)}
|
|
288
|
-
<BlinkingCursor />
|
|
289
|
-
</span>
|
|
290
|
-
)
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
interface IRepeatedTextAnimationProps {
|
|
294
|
-
delay: number
|
|
295
|
-
texts: string[]
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const defaultTexts = [
|
|
299
|
-
"quiz page with questions and answers",
|
|
300
|
-
"blog Article Details Page Layout",
|
|
301
|
-
"ecommerce dashboard with a sidebar",
|
|
302
|
-
"ui like platform.openai.com....",
|
|
303
|
-
"buttttton",
|
|
304
|
-
"aop that tracks non-standard split sleep cycles",
|
|
305
|
-
"transparent card to showcase achievements of a user",
|
|
306
|
-
]
|
|
307
|
-
function RepeatedTextAnimation({
|
|
308
|
-
delay,
|
|
309
|
-
texts = defaultTexts,
|
|
310
|
-
}: IRepeatedTextAnimationProps) {
|
|
311
|
-
const textIndex = useMotionValue(0)
|
|
312
|
-
|
|
313
|
-
const baseText = useTransform(textIndex, (latest) => texts[latest] || "")
|
|
314
|
-
const count = useMotionValue(0)
|
|
315
|
-
const rounded = useTransform(count, (latest) => Math.round(latest))
|
|
316
|
-
const displayText = useTransform(rounded, (latest) =>
|
|
317
|
-
baseText.get().slice(0, latest)
|
|
318
|
-
)
|
|
319
|
-
const updatedThisRound = useMotionValue(true)
|
|
320
|
-
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
const animation = animate(count, 60, {
|
|
323
|
-
type: "tween",
|
|
324
|
-
delay,
|
|
325
|
-
duration: 1,
|
|
326
|
-
ease: [0.42, 0, 1, 1] as const,
|
|
327
|
-
repeat: Infinity,
|
|
328
|
-
repeatType: "reverse",
|
|
329
|
-
repeatDelay: 1,
|
|
330
|
-
onUpdate(latest) {
|
|
331
|
-
if (updatedThisRound.get() && latest > 0) {
|
|
332
|
-
updatedThisRound.set(false)
|
|
333
|
-
} else if (!updatedThisRound.get() && latest === 0) {
|
|
334
|
-
textIndex.set((textIndex.get() + 1) % texts.length)
|
|
335
|
-
updatedThisRound.set(true)
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
})
|
|
339
|
-
return () => {
|
|
340
|
-
animation.stop && animation.stop()
|
|
341
|
-
}
|
|
342
|
-
}, [count, delay, textIndex, texts, updatedThisRound])
|
|
343
|
-
|
|
344
|
-
return <motion.span className="inline">{displayText}</motion.span>
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const cursorVariants = {
|
|
348
|
-
blinking: {
|
|
349
|
-
opacity: [0, 0, 1, 1],
|
|
350
|
-
transition: {
|
|
351
|
-
duration: 1,
|
|
352
|
-
repeat: Infinity,
|
|
353
|
-
repeatDelay: 0,
|
|
354
|
-
ease: [0, 0, 1, 1] as const,
|
|
355
|
-
times: [0, 0.5, 0.5, 1],
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function BlinkingCursor() {
|
|
361
|
-
return (
|
|
362
|
-
<motion.div
|
|
363
|
-
variants={cursorVariants}
|
|
364
|
-
animate="blinking"
|
|
365
|
-
className="inline-block h-5 w-[1px] translate-y-1 bg-neutral-900"
|
|
366
|
-
/>
|
|
367
|
-
)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
interface TypingAnimationProps extends MotionProps {
|
|
371
|
-
children?: string
|
|
372
|
-
words?: string[]
|
|
373
|
-
className?: string
|
|
374
|
-
duration?: number
|
|
375
|
-
typeSpeed?: number
|
|
376
|
-
deleteSpeed?: number
|
|
377
|
-
delay?: number
|
|
378
|
-
pauseDelay?: number
|
|
379
|
-
loop?: boolean
|
|
380
|
-
as?: React.ElementType
|
|
381
|
-
startOnView?: boolean
|
|
382
|
-
showCursor?: boolean
|
|
383
|
-
blinkCursor?: boolean
|
|
384
|
-
cursorStyle?: "line" | "block" | "underscore"
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function TypingAnimation({
|
|
388
|
-
children,
|
|
389
|
-
words,
|
|
390
|
-
className,
|
|
391
|
-
duration = 100,
|
|
392
|
-
typeSpeed,
|
|
393
|
-
deleteSpeed,
|
|
394
|
-
delay = 0,
|
|
395
|
-
pauseDelay = 1000,
|
|
396
|
-
loop = false,
|
|
397
|
-
as: Component = "span",
|
|
398
|
-
startOnView = true,
|
|
399
|
-
showCursor = true,
|
|
400
|
-
blinkCursor = true,
|
|
401
|
-
cursorStyle = "line",
|
|
402
|
-
...props
|
|
403
|
-
}: TypingAnimationProps) {
|
|
404
|
-
const MotionComponent = motion.create(Component, {
|
|
405
|
-
forwardMotionProps: true,
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
const [displayedText, setDisplayedText] = useState<string>("")
|
|
409
|
-
const [currentWordIndex, setCurrentWordIndex] = useState(0)
|
|
410
|
-
const [currentCharIndex, setCurrentCharIndex] = useState(0)
|
|
411
|
-
const [phase, setPhase] = useState<"typing" | "pause" | "deleting">("typing")
|
|
412
|
-
const elementRef = useRef<HTMLElement | null>(null)
|
|
413
|
-
const isInView = useInView(elementRef as React.RefObject<Element>, {
|
|
414
|
-
amount: 0.3,
|
|
415
|
-
once: true,
|
|
416
|
-
})
|
|
417
|
-
|
|
418
|
-
const wordsToAnimate = useMemo(
|
|
419
|
-
() => words || (children ? [children] : []),
|
|
420
|
-
[words, children]
|
|
421
|
-
)
|
|
422
|
-
const hasMultipleWords = wordsToAnimate.length > 1
|
|
423
|
-
|
|
424
|
-
const typingSpeed = typeSpeed || duration
|
|
425
|
-
const deletingSpeed = deleteSpeed || typingSpeed / 2
|
|
426
|
-
|
|
427
|
-
const shouldStart = startOnView ? isInView : true
|
|
428
|
-
|
|
429
|
-
useEffect(() => {
|
|
430
|
-
if (!shouldStart || wordsToAnimate.length === 0) return
|
|
431
|
-
|
|
432
|
-
const timeoutDelay =
|
|
433
|
-
delay > 0 && displayedText === ""
|
|
434
|
-
? delay
|
|
435
|
-
: phase === "typing"
|
|
436
|
-
? typingSpeed
|
|
437
|
-
: phase === "deleting"
|
|
438
|
-
? deletingSpeed
|
|
439
|
-
: pauseDelay
|
|
440
|
-
|
|
441
|
-
const timeout = setTimeout(() => {
|
|
442
|
-
const currentWord = wordsToAnimate[currentWordIndex] || ""
|
|
443
|
-
const graphemes = Array.from(currentWord)
|
|
444
|
-
|
|
445
|
-
switch (phase) {
|
|
446
|
-
case "typing":
|
|
447
|
-
if (currentCharIndex < graphemes.length) {
|
|
448
|
-
setDisplayedText(graphemes.slice(0, currentCharIndex + 1).join(""))
|
|
449
|
-
setCurrentCharIndex(currentCharIndex + 1)
|
|
450
|
-
} else {
|
|
451
|
-
if (hasMultipleWords || loop) {
|
|
452
|
-
const isLastWord = currentWordIndex === wordsToAnimate.length - 1
|
|
453
|
-
if (!isLastWord || loop) {
|
|
454
|
-
setPhase("pause")
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
break
|
|
459
|
-
|
|
460
|
-
case "pause":
|
|
461
|
-
setPhase("deleting")
|
|
462
|
-
break
|
|
463
|
-
|
|
464
|
-
case "deleting":
|
|
465
|
-
if (currentCharIndex > 0) {
|
|
466
|
-
setDisplayedText(graphemes.slice(0, currentCharIndex - 1).join(""))
|
|
467
|
-
setCurrentCharIndex(currentCharIndex - 1)
|
|
468
|
-
} else {
|
|
469
|
-
const nextIndex = (currentWordIndex + 1) % wordsToAnimate.length
|
|
470
|
-
setCurrentWordIndex(nextIndex)
|
|
471
|
-
setPhase("typing")
|
|
472
|
-
}
|
|
473
|
-
break
|
|
474
|
-
}
|
|
475
|
-
}, timeoutDelay)
|
|
476
|
-
|
|
477
|
-
return () => clearTimeout(timeout)
|
|
478
|
-
}, [
|
|
479
|
-
shouldStart,
|
|
480
|
-
phase,
|
|
481
|
-
currentCharIndex,
|
|
482
|
-
currentWordIndex,
|
|
483
|
-
displayedText,
|
|
484
|
-
wordsToAnimate,
|
|
485
|
-
hasMultipleWords,
|
|
486
|
-
loop,
|
|
487
|
-
typingSpeed,
|
|
488
|
-
deletingSpeed,
|
|
489
|
-
pauseDelay,
|
|
490
|
-
delay,
|
|
491
|
-
])
|
|
492
|
-
|
|
493
|
-
const currentWordGraphemes = Array.from(
|
|
494
|
-
wordsToAnimate[currentWordIndex] || ""
|
|
495
|
-
)
|
|
496
|
-
const isComplete =
|
|
497
|
-
!loop &&
|
|
498
|
-
currentWordIndex === wordsToAnimate.length - 1 &&
|
|
499
|
-
currentCharIndex >= currentWordGraphemes.length &&
|
|
500
|
-
phase !== "deleting"
|
|
501
|
-
|
|
502
|
-
const shouldShowCursor =
|
|
503
|
-
showCursor &&
|
|
504
|
-
!isComplete &&
|
|
505
|
-
(hasMultipleWords || loop || currentCharIndex < currentWordGraphemes.length)
|
|
506
|
-
|
|
507
|
-
const getCursorChar = () => {
|
|
508
|
-
switch (cursorStyle) {
|
|
509
|
-
case "block":
|
|
510
|
-
return "▌"
|
|
511
|
-
case "underscore":
|
|
512
|
-
return "_"
|
|
513
|
-
case "line":
|
|
514
|
-
default:
|
|
515
|
-
return "|"
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
return (
|
|
520
|
-
<MotionComponent
|
|
521
|
-
ref={elementRef}
|
|
522
|
-
className={cn("leading-[5rem] tracking-[-0.02em]", className)}
|
|
523
|
-
{...props}
|
|
524
|
-
>
|
|
525
|
-
{displayedText}
|
|
526
|
-
{shouldShowCursor && (
|
|
527
|
-
<span
|
|
528
|
-
className={cn("inline-block", blinkCursor && "animate-blink-cursor")}
|
|
529
|
-
>
|
|
530
|
-
{getCursorChar()}
|
|
531
|
-
</span>
|
|
532
|
-
)}
|
|
533
|
-
</MotionComponent>
|
|
534
|
-
)
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const typewriterVariants = cva(
|
|
538
|
-
"inline-block animate-cursor border-foreground border-r-2 pr-1 font-mono tracking-tight",
|
|
539
|
-
{
|
|
540
|
-
variants: {
|
|
541
|
-
size: {
|
|
542
|
-
sm: "text-2xl md:text-3xl",
|
|
543
|
-
md: "text-4xl md:text-6xl",
|
|
544
|
-
lg: "text-6xl md:text-8xl",
|
|
545
|
-
},
|
|
546
|
-
},
|
|
547
|
-
defaultVariants: {
|
|
548
|
-
size: "md",
|
|
549
|
-
},
|
|
550
|
-
}
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
interface TypewriterSequence {
|
|
554
|
-
text: string
|
|
555
|
-
deleteAfter?: boolean
|
|
556
|
-
pauseAfter?: number
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
interface TypewriterProps extends VariantProps<typeof typewriterVariants> {
|
|
560
|
-
sequences?: TypewriterSequence[]
|
|
561
|
-
typingSpeed?: number
|
|
562
|
-
startDelay?: number
|
|
563
|
-
autoLoop?: boolean
|
|
564
|
-
loopDelay?: number
|
|
565
|
-
className?: string
|
|
566
|
-
containerClassName?: string
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
function Typewriter({
|
|
570
|
-
sequences = [
|
|
571
|
-
{ text: "Typewriter", deleteAfter: true },
|
|
572
|
-
{ text: "Multiple Words", deleteAfter: true },
|
|
573
|
-
{ text: "Auto Loop", deleteAfter: false },
|
|
574
|
-
],
|
|
575
|
-
typingSpeed = 50,
|
|
576
|
-
startDelay = 500,
|
|
577
|
-
autoLoop = true,
|
|
578
|
-
loopDelay = 2000,
|
|
579
|
-
size,
|
|
580
|
-
className,
|
|
581
|
-
containerClassName,
|
|
582
|
-
}: TypewriterProps) {
|
|
583
|
-
const textRef = useRef<HTMLSpanElement>(null)
|
|
584
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
|
585
|
-
|
|
586
|
-
useEffect(() => {
|
|
587
|
-
let isActive = true
|
|
588
|
-
|
|
589
|
-
const typeText = async () => {
|
|
590
|
-
const titleElement = textRef.current
|
|
591
|
-
if (!titleElement) return
|
|
592
|
-
|
|
593
|
-
while (isActive) {
|
|
594
|
-
titleElement.textContent = ""
|
|
595
|
-
|
|
596
|
-
await new Promise((resolve) => setTimeout(resolve, startDelay))
|
|
597
|
-
|
|
598
|
-
for (const sequence of sequences) {
|
|
599
|
-
if (!isActive) break
|
|
600
|
-
|
|
601
|
-
for (let i = 0; i < sequence.text.length; i++) {
|
|
602
|
-
if (!isActive) break
|
|
603
|
-
titleElement.textContent = sequence.text.slice(0, i + 1)
|
|
604
|
-
await new Promise((resolve) => setTimeout(resolve, typingSpeed))
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (sequence.pauseAfter) {
|
|
608
|
-
await new Promise((resolve) =>
|
|
609
|
-
setTimeout(resolve, sequence.pauseAfter)
|
|
610
|
-
)
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (sequence.deleteAfter) {
|
|
614
|
-
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
615
|
-
for (let i = sequence.text.length; i > 0; i--) {
|
|
616
|
-
if (!isActive) break
|
|
617
|
-
titleElement.textContent = sequence.text.slice(0, i)
|
|
618
|
-
await new Promise((resolve) =>
|
|
619
|
-
setTimeout(resolve, typingSpeed / 2)
|
|
620
|
-
)
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (!(autoLoop && isActive)) break
|
|
626
|
-
|
|
627
|
-
await new Promise((resolve) => setTimeout(resolve, loopDelay))
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
typeText()
|
|
632
|
-
|
|
633
|
-
return () => {
|
|
634
|
-
isActive = false
|
|
635
|
-
}
|
|
636
|
-
}, [sequences, typingSpeed, startDelay, autoLoop, loopDelay])
|
|
637
|
-
|
|
638
|
-
return (
|
|
639
|
-
<div className={cn("relative mx-auto w-full max-w-4xl py-24", containerClassName)}>
|
|
640
|
-
<div
|
|
641
|
-
className="relative z-10 flex flex-col items-center justify-center text-center"
|
|
642
|
-
ref={containerRef}
|
|
643
|
-
>
|
|
644
|
-
<div className="flex items-center gap-2">
|
|
645
|
-
<span
|
|
646
|
-
ref={textRef}
|
|
647
|
-
className={cn(typewriterVariants({ size }), "text-foreground", className)}
|
|
648
|
-
>
|
|
649
|
-
{sequences[0].text}
|
|
650
|
-
</span>
|
|
651
|
-
</div>
|
|
652
|
-
</div>
|
|
653
|
-
</div>
|
|
654
|
-
)
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
interface AnimatedTextProps {
|
|
658
|
-
text?: string;
|
|
659
|
-
className?: string;
|
|
660
|
-
shadowColors?: {
|
|
661
|
-
first?: string;
|
|
662
|
-
second?: string;
|
|
663
|
-
third?: string;
|
|
664
|
-
fourth?: string;
|
|
665
|
-
glow?: string;
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
function TextRewind({
|
|
670
|
-
text = "LINE",
|
|
671
|
-
className = "",
|
|
672
|
-
shadowColors = {
|
|
673
|
-
first: "#07bccc",
|
|
674
|
-
second: "#e601c0",
|
|
675
|
-
third: "#e9019a",
|
|
676
|
-
fourth: "#f40468",
|
|
677
|
-
glow: "#f40468",
|
|
678
|
-
},
|
|
679
|
-
}: AnimatedTextProps) {
|
|
680
|
-
const textShadowStyle = {
|
|
681
|
-
textShadow: `10px 10px 0px ${shadowColors.first},
|
|
682
|
-
15px 15px 0px ${shadowColors.second},
|
|
683
|
-
20px 20px 0px ${shadowColors.third},
|
|
684
|
-
25px 25px 0px ${shadowColors.fourth},
|
|
685
|
-
45px 45px 10px ${shadowColors.glow}`,
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
const noShadowStyle = {
|
|
689
|
-
textShadow: "none",
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
return (
|
|
693
|
-
<div className="w-full text-center">
|
|
694
|
-
<motion.div
|
|
695
|
-
className={cn(
|
|
696
|
-
"w-full text-center cursor-pointer text-3xl font-bold",
|
|
697
|
-
"transition-all duration-200 ease-in-out tracking-widest",
|
|
698
|
-
"text-black dark:text-white italic",
|
|
699
|
-
"stroke-[#d6f4f4]",
|
|
700
|
-
className
|
|
701
|
-
)}
|
|
702
|
-
style={textShadowStyle}
|
|
703
|
-
whileHover={noShadowStyle}
|
|
704
|
-
>
|
|
705
|
-
{text}
|
|
706
|
-
</motion.div>
|
|
707
|
-
</div>
|
|
708
|
-
);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
interface TextRevealProps extends ComponentPropsWithoutRef<"div"> {
|
|
712
|
-
children: string
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
function TextReveal({ children, className }: TextRevealProps) {
|
|
716
|
-
const targetRef = useRef<HTMLDivElement | null>(null)
|
|
717
|
-
const { scrollYProgress } = useScroll({
|
|
718
|
-
target: targetRef,
|
|
719
|
-
})
|
|
720
|
-
|
|
721
|
-
if (typeof children !== "string") {
|
|
722
|
-
throw new Error("TextReveal: children must be a string")
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const words = children.split(" ")
|
|
726
|
-
|
|
727
|
-
return (
|
|
728
|
-
<div ref={targetRef} className={cn("relative z-0 h-[200vh]", className)}>
|
|
729
|
-
<div
|
|
730
|
-
className={
|
|
731
|
-
"sticky top-0 mx-auto flex h-[50%] max-w-4xl items-center bg-transparent px-[1rem] py-[5rem]"
|
|
732
|
-
}
|
|
733
|
-
>
|
|
734
|
-
<span
|
|
735
|
-
ref={targetRef}
|
|
736
|
-
className={
|
|
737
|
-
"flex flex-wrap p-5 text-2xl font-bold text-black/20 md:p-8 md:text-3xl lg:p-10 lg:text-4xl xl:text-5xl dark:text-white/20"
|
|
738
|
-
}
|
|
739
|
-
>
|
|
740
|
-
{words.map((word, i) => {
|
|
741
|
-
const start = i / words.length
|
|
742
|
-
const end = start + 1 / words.length
|
|
743
|
-
return (
|
|
744
|
-
<Word key={i} progress={scrollYProgress} range={[start, end]}>
|
|
745
|
-
{word}
|
|
746
|
-
</Word>
|
|
747
|
-
)
|
|
748
|
-
})}
|
|
749
|
-
</span>
|
|
750
|
-
</div>
|
|
751
|
-
</div>
|
|
752
|
-
)
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
interface WordProps {
|
|
756
|
-
children: ReactNode
|
|
757
|
-
progress: MotionValue<number>
|
|
758
|
-
range: [number, number]
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
const Word: FC<WordProps> = ({ children, progress, range }) => {
|
|
762
|
-
const opacity = useTransform(progress, range, [0, 1])
|
|
763
|
-
return (
|
|
764
|
-
<span className="xl:lg-3 relative mx-1 lg:mx-1.5">
|
|
765
|
-
<span className="absolute opacity-30">{children}</span>
|
|
766
|
-
<motion.span
|
|
767
|
-
style={{ opacity: opacity }}
|
|
768
|
-
className={"text-black dark:text-white"}
|
|
769
|
-
>
|
|
770
|
-
{children}
|
|
771
|
-
</motion.span>
|
|
772
|
-
</span>
|
|
773
|
-
)
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
type TextMorphProps = {
|
|
777
|
-
children: string
|
|
778
|
-
as?: React.ElementType
|
|
779
|
-
className?: string
|
|
780
|
-
style?: React.CSSProperties
|
|
781
|
-
variants?: Variants
|
|
782
|
-
transition?: Transition
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
function TextMorph({
|
|
786
|
-
children,
|
|
787
|
-
as: Component = "p",
|
|
788
|
-
className,
|
|
789
|
-
style,
|
|
790
|
-
variants,
|
|
791
|
-
transition,
|
|
792
|
-
}: TextMorphProps) {
|
|
793
|
-
const uniqueId = useId()
|
|
794
|
-
|
|
795
|
-
const characters = useMemo(() => {
|
|
796
|
-
const charCounts: Record<string, number> = {}
|
|
797
|
-
|
|
798
|
-
return children.split("").map((char, index) => {
|
|
799
|
-
const lowerChar = char.toLowerCase()
|
|
800
|
-
charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1
|
|
801
|
-
|
|
802
|
-
return {
|
|
803
|
-
id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,
|
|
804
|
-
label:
|
|
805
|
-
char === " "
|
|
806
|
-
? "\u00A0"
|
|
807
|
-
: index === 0
|
|
808
|
-
? char.toUpperCase()
|
|
809
|
-
: lowerChar,
|
|
810
|
-
}
|
|
811
|
-
})
|
|
812
|
-
}, [children, uniqueId])
|
|
813
|
-
|
|
814
|
-
const defaultVariants: Variants = {
|
|
815
|
-
initial: { opacity: 0 },
|
|
816
|
-
animate: { opacity: 1 },
|
|
817
|
-
exit: { opacity: 0 },
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
const defaultTransition: Transition = {
|
|
821
|
-
type: "spring",
|
|
822
|
-
stiffness: 280,
|
|
823
|
-
damping: 18,
|
|
824
|
-
mass: 0.3,
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
return (
|
|
828
|
-
<Component className={cn(className)} aria-label={children} style={style}>
|
|
829
|
-
<AnimatePresence mode="popLayout" initial={false}>
|
|
830
|
-
{characters.map((character) => (
|
|
831
|
-
<motion.span
|
|
832
|
-
key={character.id}
|
|
833
|
-
layoutId={character.id}
|
|
834
|
-
className="inline-block"
|
|
835
|
-
aria-hidden="true"
|
|
836
|
-
initial="initial"
|
|
837
|
-
animate="animate"
|
|
838
|
-
exit="exit"
|
|
839
|
-
variants={variants || defaultVariants}
|
|
840
|
-
transition={transition || defaultTransition}
|
|
841
|
-
>
|
|
842
|
-
{character.label}
|
|
843
|
-
</motion.span>
|
|
844
|
-
))}
|
|
845
|
-
</AnimatePresence>
|
|
846
|
-
</Component>
|
|
847
|
-
)
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
const swooshTextVariants = cva(
|
|
851
|
-
"w-full text-center cursor-pointer font-bold transition-all duration-200 ease-in-out tracking-widest text-foreground italic",
|
|
852
|
-
{
|
|
853
|
-
variants: {
|
|
854
|
-
size: {
|
|
855
|
-
sm: "text-xl",
|
|
856
|
-
md: "text-3xl",
|
|
857
|
-
lg: "text-5xl",
|
|
858
|
-
xl: "text-7xl",
|
|
859
|
-
},
|
|
860
|
-
},
|
|
861
|
-
defaultVariants: {
|
|
862
|
-
size: "md",
|
|
863
|
-
},
|
|
864
|
-
}
|
|
865
|
-
)
|
|
866
|
-
|
|
867
|
-
interface ShadowColors {
|
|
868
|
-
first?: string
|
|
869
|
-
second?: string
|
|
870
|
-
third?: string
|
|
871
|
-
fourth?: string
|
|
872
|
-
glow?: string
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
interface SwooshTextProps extends VariantProps<typeof swooshTextVariants> {
|
|
876
|
-
text?: string
|
|
877
|
-
shadowColors?: ShadowColors
|
|
878
|
-
className?: string
|
|
879
|
-
disabled?: boolean
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
function SwooshText({
|
|
883
|
-
text = "Hover Me",
|
|
884
|
-
shadowColors = {
|
|
885
|
-
first: "#07bccc",
|
|
886
|
-
second: "#e601c0",
|
|
887
|
-
third: "#e9019a",
|
|
888
|
-
fourth: "#f40468",
|
|
889
|
-
glow: "#f40468",
|
|
890
|
-
},
|
|
891
|
-
size,
|
|
892
|
-
className,
|
|
893
|
-
disabled = false,
|
|
894
|
-
}: SwooshTextProps) {
|
|
895
|
-
const [isHovered, setIsHovered] = React.useState(false)
|
|
896
|
-
|
|
897
|
-
const textShadowStyle = {
|
|
898
|
-
textShadow: `10px 10px 0px ${shadowColors.first},
|
|
899
|
-
15px 15px 0px ${shadowColors.second},
|
|
900
|
-
20px 20px 0px ${shadowColors.third},
|
|
901
|
-
25px 25px 0px ${shadowColors.fourth},
|
|
902
|
-
45px 45px 10px ${shadowColors.glow}`,
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
const noShadowStyle = {
|
|
906
|
-
textShadow: "none",
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
return (
|
|
910
|
-
<div className="w-full text-center">
|
|
911
|
-
<div
|
|
912
|
-
className={cn(
|
|
913
|
-
swooshTextVariants({ size }),
|
|
914
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
915
|
-
className
|
|
916
|
-
)}
|
|
917
|
-
style={isHovered && !disabled ? noShadowStyle : textShadowStyle}
|
|
918
|
-
onMouseEnter={() => !disabled && setIsHovered(true)}
|
|
919
|
-
onMouseLeave={() => !disabled && setIsHovered(false)}
|
|
920
|
-
>
|
|
921
|
-
{text}
|
|
922
|
-
</div>
|
|
923
|
-
</div>
|
|
924
|
-
)
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
const slicedTextVariants = cva(
|
|
928
|
-
"text-foreground",
|
|
929
|
-
{
|
|
930
|
-
variants: {
|
|
931
|
-
size: {
|
|
932
|
-
sm: "text-2xl",
|
|
933
|
-
md: "text-4xl",
|
|
934
|
-
lg: "text-6xl",
|
|
935
|
-
xl: "text-8xl",
|
|
936
|
-
},
|
|
937
|
-
},
|
|
938
|
-
defaultVariants: {
|
|
939
|
-
size: "md",
|
|
940
|
-
},
|
|
941
|
-
}
|
|
942
|
-
)
|
|
943
|
-
|
|
944
|
-
interface SlicedTextProps extends VariantProps<typeof slicedTextVariants> {
|
|
945
|
-
text: string
|
|
946
|
-
splitSpacing?: number
|
|
947
|
-
className?: string
|
|
948
|
-
containerClassName?: string
|
|
949
|
-
disabled?: boolean
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
function SlicedText({
|
|
953
|
-
text = "Sliced Text",
|
|
954
|
-
splitSpacing = 2,
|
|
955
|
-
size,
|
|
956
|
-
className,
|
|
957
|
-
containerClassName,
|
|
958
|
-
disabled = false,
|
|
959
|
-
}: SlicedTextProps) {
|
|
960
|
-
const [isHovered, setIsHovered] = useState(false)
|
|
961
|
-
|
|
962
|
-
const topVariants = {
|
|
963
|
-
default: {
|
|
964
|
-
clipPath: "inset(0 0 50% 0)",
|
|
965
|
-
transform: `translateY(${-splitSpacing / 2}px)`,
|
|
966
|
-
opacity: 1,
|
|
967
|
-
},
|
|
968
|
-
hover: {
|
|
969
|
-
clipPath: "inset(0 0 0 0)",
|
|
970
|
-
transform: "translateY(0px)",
|
|
971
|
-
opacity: 0,
|
|
972
|
-
},
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
const bottomVariants = {
|
|
976
|
-
default: {
|
|
977
|
-
clipPath: "inset(50% 0 0 0)",
|
|
978
|
-
transform: `translateY(${splitSpacing / 2}px)`,
|
|
979
|
-
opacity: 1,
|
|
980
|
-
},
|
|
981
|
-
hover: {
|
|
982
|
-
clipPath: "inset(0 0 0 0)",
|
|
983
|
-
transform: "translateY(0px)",
|
|
984
|
-
opacity: 1,
|
|
985
|
-
},
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
const currentTopStyle = isHovered && !disabled ? topVariants.hover : topVariants.default
|
|
989
|
-
const currentBottomStyle = isHovered && !disabled ? bottomVariants.hover : bottomVariants.default
|
|
990
|
-
|
|
991
|
-
return (
|
|
992
|
-
<div
|
|
993
|
-
className={cn("w-full text-center relative inline-block", containerClassName)}
|
|
994
|
-
onMouseEnter={() => !disabled && setIsHovered(true)}
|
|
995
|
-
onMouseLeave={() => !disabled && setIsHovered(false)}
|
|
996
|
-
>
|
|
997
|
-
<div
|
|
998
|
-
className={cn(
|
|
999
|
-
"absolute w-full -ml-0.5 transition-all duration-100",
|
|
1000
|
-
slicedTextVariants({ size }),
|
|
1001
|
-
className
|
|
1002
|
-
)}
|
|
1003
|
-
style={{
|
|
1004
|
-
clipPath: currentTopStyle.clipPath,
|
|
1005
|
-
transform: currentTopStyle.transform,
|
|
1006
|
-
opacity: currentTopStyle.opacity,
|
|
1007
|
-
}}
|
|
1008
|
-
>
|
|
1009
|
-
{text}
|
|
1010
|
-
</div>
|
|
1011
|
-
<div
|
|
1012
|
-
className={cn(
|
|
1013
|
-
"absolute w-full transition-all duration-100",
|
|
1014
|
-
slicedTextVariants({ size }),
|
|
1015
|
-
className
|
|
1016
|
-
)}
|
|
1017
|
-
style={{
|
|
1018
|
-
clipPath: currentBottomStyle.clipPath,
|
|
1019
|
-
transform: currentBottomStyle.transform,
|
|
1020
|
-
opacity: currentBottomStyle.opacity,
|
|
1021
|
-
}}
|
|
1022
|
-
>
|
|
1023
|
-
{text}
|
|
1024
|
-
</div>
|
|
1025
|
-
<div className={cn("invisible", slicedTextVariants({ size }), className)}>
|
|
1026
|
-
{text}
|
|
1027
|
-
</div>
|
|
1028
|
-
</div>
|
|
1029
|
-
)
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
const shimmerTextVariants = cva(
|
|
1033
|
-
"font-bold bg-gradient-to-r bg-[length:200%_100%] bg-clip-text text-transparent",
|
|
1034
|
-
{
|
|
1035
|
-
variants: {
|
|
1036
|
-
variant: {
|
|
1037
|
-
default: "from-neutral-950 via-neutral-400 to-neutral-950 dark:from-white dark:via-neutral-600 dark:to-white",
|
|
1038
|
-
primary: "from-primary via-primary/50 to-primary",
|
|
1039
|
-
secondary: "from-secondary via-secondary/50 to-secondary",
|
|
1040
|
-
accent: "from-accent via-accent/50 to-accent",
|
|
1041
|
-
},
|
|
1042
|
-
size: {
|
|
1043
|
-
sm: "text-xl",
|
|
1044
|
-
md: "text-3xl",
|
|
1045
|
-
lg: "text-5xl",
|
|
1046
|
-
xl: "text-7xl",
|
|
1047
|
-
},
|
|
1048
|
-
},
|
|
1049
|
-
defaultVariants: {
|
|
1050
|
-
variant: "default",
|
|
1051
|
-
size: "md",
|
|
1052
|
-
},
|
|
1053
|
-
}
|
|
1054
|
-
)
|
|
1055
|
-
|
|
1056
|
-
interface ShimmerTextProps extends VariantProps<typeof shimmerTextVariants> {
|
|
1057
|
-
text: string
|
|
1058
|
-
duration?: number
|
|
1059
|
-
className?: string
|
|
1060
|
-
containerClassName?: string
|
|
1061
|
-
disabled?: boolean
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
function ShimmerText({
|
|
1065
|
-
text = "Text Shimmer",
|
|
1066
|
-
duration = 2.5,
|
|
1067
|
-
variant,
|
|
1068
|
-
size,
|
|
1069
|
-
className,
|
|
1070
|
-
containerClassName,
|
|
1071
|
-
disabled = false,
|
|
1072
|
-
}: ShimmerTextProps) {
|
|
1073
|
-
const [position, setPosition] = React.useState("200% center")
|
|
1074
|
-
|
|
1075
|
-
React.useEffect(() => {
|
|
1076
|
-
if (disabled) return
|
|
1077
|
-
|
|
1078
|
-
const startTime = Date.now()
|
|
1079
|
-
let animationFrame: number
|
|
1080
|
-
|
|
1081
|
-
const animate = () => {
|
|
1082
|
-
const elapsed = Date.now() - startTime
|
|
1083
|
-
const progress = (elapsed % (duration * 1000)) / (duration * 1000)
|
|
1084
|
-
const xPosition = 200 - (progress * 400)
|
|
1085
|
-
setPosition(`${xPosition}% center`)
|
|
1086
|
-
animationFrame = requestAnimationFrame(animate)
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
animationFrame = requestAnimationFrame(animate)
|
|
1090
|
-
return () => cancelAnimationFrame(animationFrame)
|
|
1091
|
-
}, [duration, disabled])
|
|
1092
|
-
|
|
1093
|
-
return (
|
|
1094
|
-
<div className={cn("flex items-center justify-center p-8", containerClassName)}>
|
|
1095
|
-
<div className="relative px-4 py-2 overflow-hidden">
|
|
1096
|
-
<h1
|
|
1097
|
-
className={cn(shimmerTextVariants({ variant, size }), className)}
|
|
1098
|
-
style={{
|
|
1099
|
-
backgroundPosition: disabled ? "200% center" : position,
|
|
1100
|
-
}}
|
|
1101
|
-
>
|
|
1102
|
-
{text}
|
|
1103
|
-
</h1>
|
|
1104
|
-
</div>
|
|
1105
|
-
</div>
|
|
1106
|
-
)
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
const matrixTextVariants = cva(
|
|
1110
|
-
"flex items-center justify-center text-foreground",
|
|
1111
|
-
{
|
|
1112
|
-
variants: {
|
|
1113
|
-
size: {
|
|
1114
|
-
sm: "text-2xl md:text-3xl",
|
|
1115
|
-
md: "text-4xl md:text-6xl",
|
|
1116
|
-
lg: "text-6xl md:text-8xl",
|
|
1117
|
-
},
|
|
1118
|
-
alignment: {
|
|
1119
|
-
left: "justify-start",
|
|
1120
|
-
center: "justify-center",
|
|
1121
|
-
right: "justify-end",
|
|
1122
|
-
},
|
|
1123
|
-
},
|
|
1124
|
-
defaultVariants: {
|
|
1125
|
-
size: "md",
|
|
1126
|
-
alignment: "center",
|
|
1127
|
-
},
|
|
1128
|
-
}
|
|
1129
|
-
)
|
|
1130
|
-
|
|
1131
|
-
interface LetterState {
|
|
1132
|
-
char: string
|
|
1133
|
-
isMatrix: boolean
|
|
1134
|
-
isSpace: boolean
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
interface MatrixTextProps extends VariantProps<typeof matrixTextVariants> {
|
|
1138
|
-
text?: string
|
|
1139
|
-
initialDelay?: number
|
|
1140
|
-
letterAnimationDuration?: number
|
|
1141
|
-
letterInterval?: number
|
|
1142
|
-
matrixColor?: string
|
|
1143
|
-
loop?: boolean
|
|
1144
|
-
className?: string
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
function MatrixText({
|
|
1148
|
-
text = "HelloWorld!",
|
|
1149
|
-
initialDelay = 200,
|
|
1150
|
-
letterAnimationDuration = 500,
|
|
1151
|
-
letterInterval = 100,
|
|
1152
|
-
matrixColor = "#00ff00",
|
|
1153
|
-
loop = false,
|
|
1154
|
-
size,
|
|
1155
|
-
alignment,
|
|
1156
|
-
className,
|
|
1157
|
-
}: MatrixTextProps) {
|
|
1158
|
-
const [letters, setLetters] = useState<LetterState[]>(() =>
|
|
1159
|
-
text.split("").map((char) => ({
|
|
1160
|
-
char,
|
|
1161
|
-
isMatrix: false,
|
|
1162
|
-
isSpace: char === " ",
|
|
1163
|
-
}))
|
|
1164
|
-
)
|
|
1165
|
-
const [isAnimating, setIsAnimating] = useState(false)
|
|
1166
|
-
const [isHovering, setIsHovering] = useState(false)
|
|
1167
|
-
|
|
1168
|
-
const getRandomChar = useCallback(
|
|
1169
|
-
() => (Math.random() > 0.5 ? "1" : "0"),
|
|
1170
|
-
[]
|
|
1171
|
-
)
|
|
1172
|
-
|
|
1173
|
-
const animateLetter = useCallback(
|
|
1174
|
-
(index: number) => {
|
|
1175
|
-
if (index >= text.length) return
|
|
1176
|
-
|
|
1177
|
-
requestAnimationFrame(() => {
|
|
1178
|
-
setLetters((prev) => {
|
|
1179
|
-
const newLetters = [...prev]
|
|
1180
|
-
if (!newLetters[index].isSpace) {
|
|
1181
|
-
newLetters[index] = {
|
|
1182
|
-
...newLetters[index],
|
|
1183
|
-
char: getRandomChar(),
|
|
1184
|
-
isMatrix: true,
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
return newLetters
|
|
1188
|
-
})
|
|
1189
|
-
|
|
1190
|
-
setTimeout(() => {
|
|
1191
|
-
setLetters((prev) => {
|
|
1192
|
-
const newLetters = [...prev]
|
|
1193
|
-
newLetters[index] = {
|
|
1194
|
-
...newLetters[index],
|
|
1195
|
-
char: text[index],
|
|
1196
|
-
isMatrix: false,
|
|
1197
|
-
}
|
|
1198
|
-
return newLetters
|
|
1199
|
-
})
|
|
1200
|
-
}, letterAnimationDuration)
|
|
1201
|
-
})
|
|
1202
|
-
},
|
|
1203
|
-
[getRandomChar, text, letterAnimationDuration]
|
|
1204
|
-
)
|
|
1205
|
-
|
|
1206
|
-
const startAnimation = useCallback(() => {
|
|
1207
|
-
if (isAnimating) return
|
|
1208
|
-
|
|
1209
|
-
setIsAnimating(true)
|
|
1210
|
-
let currentIndex = 0
|
|
1211
|
-
|
|
1212
|
-
const animate = () => {
|
|
1213
|
-
if (currentIndex >= text.length) {
|
|
1214
|
-
setIsAnimating(false)
|
|
1215
|
-
return
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
animateLetter(currentIndex)
|
|
1219
|
-
currentIndex++
|
|
1220
|
-
setTimeout(animate, letterInterval)
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
animate()
|
|
1224
|
-
}, [animateLetter, text, isAnimating, letterInterval])
|
|
1225
|
-
|
|
1226
|
-
useEffect(() => {
|
|
1227
|
-
const timer = setTimeout(startAnimation, initialDelay)
|
|
1228
|
-
return () => clearTimeout(timer)
|
|
1229
|
-
}, [])
|
|
1230
|
-
|
|
1231
|
-
useEffect(() => {
|
|
1232
|
-
if (!loop || isAnimating) return
|
|
1233
|
-
|
|
1234
|
-
const loopTimer = setInterval(() => {
|
|
1235
|
-
startAnimation()
|
|
1236
|
-
}, text.length * letterInterval + letterAnimationDuration + 2000)
|
|
1237
|
-
|
|
1238
|
-
return () => clearInterval(loopTimer)
|
|
1239
|
-
}, [loop, isAnimating, startAnimation, text.length, letterInterval, letterAnimationDuration])
|
|
1240
|
-
|
|
1241
|
-
const handleMouseEnter = () => {
|
|
1242
|
-
setIsHovering(true)
|
|
1243
|
-
startAnimation()
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
const handleMouseLeave = () => {
|
|
1247
|
-
setIsHovering(false)
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
return (
|
|
1251
|
-
<div
|
|
1252
|
-
className={cn(matrixTextVariants({ size, alignment }), className)}
|
|
1253
|
-
aria-label="Matrix text animation"
|
|
1254
|
-
onMouseEnter={handleMouseEnter}
|
|
1255
|
-
onMouseLeave={handleMouseLeave}
|
|
1256
|
-
>
|
|
1257
|
-
<div className="h-24 flex items-center justify-center">
|
|
1258
|
-
<div className="flex flex-wrap items-center justify-center">
|
|
1259
|
-
{letters.map((letter, index) => (
|
|
1260
|
-
<div
|
|
1261
|
-
key={`${index}-${letter.char}`}
|
|
1262
|
-
className="font-mono w-[1ch] text-center overflow-hidden transition-all duration-100"
|
|
1263
|
-
style={{
|
|
1264
|
-
display: "inline-block",
|
|
1265
|
-
fontVariantNumeric: "tabular-nums",
|
|
1266
|
-
color: letter.isMatrix ? matrixColor : "currentColor",
|
|
1267
|
-
textShadow: letter.isMatrix ? `0 2px 4px ${matrixColor}80` : "none",
|
|
1268
|
-
}}
|
|
1269
|
-
>
|
|
1270
|
-
{letter.isSpace ? "\u00A0" : letter.char}
|
|
1271
|
-
</div>
|
|
1272
|
-
))}
|
|
1273
|
-
</div>
|
|
1274
|
-
</div>
|
|
1275
|
-
</div>
|
|
1276
|
-
)
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
type CharacterSet = string[] | readonly string[]
|
|
1280
|
-
|
|
1281
|
-
interface HyperTextProps extends MotionProps {
|
|
1282
|
-
children: string
|
|
1283
|
-
className?: string
|
|
1284
|
-
duration?: number
|
|
1285
|
-
delay?: number
|
|
1286
|
-
as?: React.ElementType
|
|
1287
|
-
startOnView?: boolean
|
|
1288
|
-
animateOnHover?: boolean
|
|
1289
|
-
characterSet?: CharacterSet
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
const DEFAULT_CHARACTER_SET = Object.freeze(
|
|
1293
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
|
|
1294
|
-
) as readonly string[]
|
|
1295
|
-
|
|
1296
|
-
const getRandomInt = (max: number): number => Math.floor(Math.random() * max)
|
|
1297
|
-
|
|
1298
|
-
function HyperText({
|
|
1299
|
-
children,
|
|
1300
|
-
className,
|
|
1301
|
-
duration = 800,
|
|
1302
|
-
delay = 0,
|
|
1303
|
-
as: Component = "div",
|
|
1304
|
-
startOnView = false,
|
|
1305
|
-
animateOnHover = true,
|
|
1306
|
-
characterSet = DEFAULT_CHARACTER_SET,
|
|
1307
|
-
...props
|
|
1308
|
-
}: HyperTextProps) {
|
|
1309
|
-
const MotionComponent = motion.create(Component, {
|
|
1310
|
-
forwardMotionProps: true,
|
|
1311
|
-
})
|
|
1312
|
-
|
|
1313
|
-
const [displayText, setDisplayText] = useState<string[]>(() =>
|
|
1314
|
-
children.split("")
|
|
1315
|
-
)
|
|
1316
|
-
const [isAnimating, setIsAnimating] = useState(false)
|
|
1317
|
-
const iterationCount = useRef(0)
|
|
1318
|
-
const elementRef = useRef<HTMLElement>(null)
|
|
1319
|
-
|
|
1320
|
-
const handleAnimationTrigger = () => {
|
|
1321
|
-
if (animateOnHover && !isAnimating) {
|
|
1322
|
-
iterationCount.current = 0
|
|
1323
|
-
setIsAnimating(true)
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
useEffect(() => {
|
|
1328
|
-
if (!startOnView) {
|
|
1329
|
-
const startTimeout = setTimeout(() => {
|
|
1330
|
-
setIsAnimating(true)
|
|
1331
|
-
}, delay)
|
|
1332
|
-
return () => clearTimeout(startTimeout)
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
const observer = new IntersectionObserver(
|
|
1336
|
-
([entry]) => {
|
|
1337
|
-
if (entry.isIntersecting) {
|
|
1338
|
-
setTimeout(() => {
|
|
1339
|
-
setIsAnimating(true)
|
|
1340
|
-
}, delay)
|
|
1341
|
-
observer.disconnect()
|
|
1342
|
-
}
|
|
1343
|
-
},
|
|
1344
|
-
{ threshold: 0.1, rootMargin: "-30% 0px -30% 0px" }
|
|
1345
|
-
)
|
|
1346
|
-
|
|
1347
|
-
if (elementRef.current) {
|
|
1348
|
-
observer.observe(elementRef.current)
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
return () => observer.disconnect()
|
|
1352
|
-
}, [delay, startOnView])
|
|
1353
|
-
|
|
1354
|
-
useEffect(() => {
|
|
1355
|
-
if (!isAnimating) return
|
|
1356
|
-
|
|
1357
|
-
const maxIterations = children.length
|
|
1358
|
-
const startTime = performance.now()
|
|
1359
|
-
let animationFrameId: number
|
|
1360
|
-
|
|
1361
|
-
const animate = (currentTime: number) => {
|
|
1362
|
-
const elapsed = currentTime - startTime
|
|
1363
|
-
const progress = Math.min(elapsed / duration, 1)
|
|
1364
|
-
|
|
1365
|
-
iterationCount.current = progress * maxIterations
|
|
1366
|
-
|
|
1367
|
-
setDisplayText((currentText) =>
|
|
1368
|
-
currentText.map((letter, index) =>
|
|
1369
|
-
letter === " "
|
|
1370
|
-
? letter
|
|
1371
|
-
: index <= iterationCount.current
|
|
1372
|
-
? children[index]
|
|
1373
|
-
: characterSet[getRandomInt(characterSet.length)]
|
|
1374
|
-
)
|
|
1375
|
-
)
|
|
1376
|
-
|
|
1377
|
-
if (progress < 1) {
|
|
1378
|
-
animationFrameId = requestAnimationFrame(animate)
|
|
1379
|
-
} else {
|
|
1380
|
-
setIsAnimating(false)
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
|
-
animationFrameId = requestAnimationFrame(animate)
|
|
1385
|
-
|
|
1386
|
-
return () => cancelAnimationFrame(animationFrameId)
|
|
1387
|
-
}, [children, duration, isAnimating, characterSet])
|
|
1388
|
-
|
|
1389
|
-
return (
|
|
1390
|
-
<MotionComponent
|
|
1391
|
-
ref={elementRef}
|
|
1392
|
-
className={cn("overflow-hidden py-2 text-4xl font-bold", className)}
|
|
1393
|
-
onMouseEnter={handleAnimationTrigger}
|
|
1394
|
-
{...props}
|
|
1395
|
-
>
|
|
1396
|
-
<AnimatePresence>
|
|
1397
|
-
{displayText.map((letter, index) => (
|
|
1398
|
-
<motion.span
|
|
1399
|
-
key={index}
|
|
1400
|
-
className={cn("font-mono", letter === " " ? "w-3" : "")}
|
|
1401
|
-
>
|
|
1402
|
-
{letter.toUpperCase()}
|
|
1403
|
-
</motion.span>
|
|
1404
|
-
))}
|
|
1405
|
-
</AnimatePresence>
|
|
1406
|
-
</MotionComponent>
|
|
1407
|
-
)
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
interface GlitchTextProps {
|
|
1411
|
-
text: string;
|
|
1412
|
-
className?: string;
|
|
1413
|
-
intensity?: 'low' | 'medium' | 'high';
|
|
1414
|
-
duration?: number;
|
|
1415
|
-
enabled?: boolean;
|
|
1416
|
-
fontSize?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
function GlitchText({
|
|
1420
|
-
text,
|
|
1421
|
-
className,
|
|
1422
|
-
intensity = 'medium',
|
|
1423
|
-
duration = 2000,
|
|
1424
|
-
enabled = true,
|
|
1425
|
-
fontSize = 'md'
|
|
1426
|
-
}: GlitchTextProps) {
|
|
1427
|
-
const [isGlitching, setIsGlitching] = useState(false);
|
|
1428
|
-
const [glitchText, setGlitchText] = useState(text);
|
|
1429
|
-
|
|
1430
|
-
const fontSizeClasses = {
|
|
1431
|
-
sm: 'text-sm',
|
|
1432
|
-
md: 'text-base',
|
|
1433
|
-
lg: 'text-lg',
|
|
1434
|
-
xl: 'text-xl',
|
|
1435
|
-
'2xl': 'text-2xl'
|
|
1436
|
-
};
|
|
1437
|
-
|
|
1438
|
-
const intensityValues = {
|
|
1439
|
-
low: { interval: 3000, glitchDuration: 300, changeCount: 3 },
|
|
1440
|
-
medium: { interval: 2000, glitchDuration: 500, changeCount: 5 },
|
|
1441
|
-
high: { interval: 1000, glitchDuration: 800, changeCount: 8 }
|
|
1442
|
-
};
|
|
1443
|
-
|
|
1444
|
-
const characters = '!@#$%^&*()_+-=[]{}|;:,.<>?~';
|
|
1445
|
-
|
|
1446
|
-
const generateGlitchText = (originalText: string) => {
|
|
1447
|
-
const textArray = originalText.split('');
|
|
1448
|
-
const glitchCount = intensityValues[intensity].changeCount;
|
|
1449
|
-
|
|
1450
|
-
for (let i = 0; i < glitchCount; i++) {
|
|
1451
|
-
const randomIndex = Math.floor(Math.random() * textArray.length);
|
|
1452
|
-
if (textArray[randomIndex] !== ' ') {
|
|
1453
|
-
textArray[randomIndex] = characters[Math.floor(Math.random() * characters.length)];
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
return textArray.join('');
|
|
1458
|
-
};
|
|
1459
|
-
|
|
1460
|
-
useEffect(() => {
|
|
1461
|
-
if (!enabled) return;
|
|
1462
|
-
|
|
1463
|
-
const glitchInterval = setInterval(() => {
|
|
1464
|
-
setIsGlitching(true);
|
|
1465
|
-
setGlitchText(generateGlitchText(text));
|
|
1466
|
-
|
|
1467
|
-
setTimeout(() => {
|
|
1468
|
-
setIsGlitching(false);
|
|
1469
|
-
setGlitchText(text);
|
|
1470
|
-
}, intensityValues[intensity].glitchDuration);
|
|
1471
|
-
}, intensityValues[intensity].interval);
|
|
1472
|
-
|
|
1473
|
-
return () => clearInterval(glitchInterval);
|
|
1474
|
-
}, [text, intensity, enabled]);
|
|
1475
|
-
|
|
1476
|
-
return (
|
|
1477
|
-
<span className={cn(
|
|
1478
|
-
'inline-block relative',
|
|
1479
|
-
fontSizeClasses[fontSize],
|
|
1480
|
-
isGlitching && 'text-red-400',
|
|
1481
|
-
className
|
|
1482
|
-
)}>
|
|
1483
|
-
{glitchText}
|
|
1484
|
-
{isGlitching && (
|
|
1485
|
-
<>
|
|
1486
|
-
<span className="absolute top-0 left-1 text-blue-400 opacity-70 mix-blend-screen">
|
|
1487
|
-
{glitchText}
|
|
1488
|
-
</span>
|
|
1489
|
-
<span className="absolute top-0 left-[-1px] text-green-400 opacity-50 mix-blend-screen">
|
|
1490
|
-
{glitchText}
|
|
1491
|
-
</span>
|
|
1492
|
-
</>
|
|
1493
|
-
)}
|
|
1494
|
-
</span>
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
type EncryptedTextProps = {
|
|
1499
|
-
text: string;
|
|
1500
|
-
className?: string;
|
|
1501
|
-
/**
|
|
1502
|
-
* Time in milliseconds between revealing each subsequent real character.
|
|
1503
|
-
* Lower is faster. Defaults to 50ms per character.
|
|
1504
|
-
*/
|
|
1505
|
-
revealDelayMs?: number;
|
|
1506
|
-
/** Optional custom character set to use for the gibberish effect. */
|
|
1507
|
-
charset?: string;
|
|
1508
|
-
/**
|
|
1509
|
-
* Time in milliseconds between gibberish flips for unrevealed characters.
|
|
1510
|
-
* Lower is more jittery. Defaults to 50ms.
|
|
1511
|
-
*/
|
|
1512
|
-
flipDelayMs?: number;
|
|
1513
|
-
/** CSS class for styling the encrypted/scrambled characters */
|
|
1514
|
-
encryptedClassName?: string;
|
|
1515
|
-
/** CSS class for styling the revealed characters */
|
|
1516
|
-
revealedClassName?: string;
|
|
1517
|
-
};
|
|
1518
|
-
|
|
1519
|
-
const DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?";
|
|
1520
|
-
|
|
1521
|
-
function generateRandomCharacter(charset: string): string {
|
|
1522
|
-
const index = Math.floor(Math.random() * charset.length);
|
|
1523
|
-
return charset.charAt(index);
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
function generateGibberishPreservingSpaces(
|
|
1527
|
-
original: string,
|
|
1528
|
-
charset: string,
|
|
1529
|
-
): string {
|
|
1530
|
-
if (!original) return "";
|
|
1531
|
-
let result = "";
|
|
1532
|
-
for (let i = 0; i < original.length; i += 1) {
|
|
1533
|
-
const ch = original[i];
|
|
1534
|
-
result += ch === " " ? " " : generateRandomCharacter(charset);
|
|
1535
|
-
}
|
|
1536
|
-
return result;
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
const EncryptedText: React.FC<EncryptedTextProps> = ({
|
|
1540
|
-
text,
|
|
1541
|
-
className,
|
|
1542
|
-
revealDelayMs = 50,
|
|
1543
|
-
charset = DEFAULT_CHARSET,
|
|
1544
|
-
flipDelayMs = 50,
|
|
1545
|
-
encryptedClassName,
|
|
1546
|
-
revealedClassName,
|
|
1547
|
-
}) => {
|
|
1548
|
-
const ref = useRef<HTMLSpanElement>(null);
|
|
1549
|
-
const isInView = useInView(ref, { once: true });
|
|
1550
|
-
|
|
1551
|
-
const [revealCount, setRevealCount] = useState<number>(0);
|
|
1552
|
-
const animationFrameRef = useRef<number | null>(null);
|
|
1553
|
-
const startTimeRef = useRef<number>(0);
|
|
1554
|
-
const lastFlipTimeRef = useRef<number>(0);
|
|
1555
|
-
const scrambleCharsRef = useRef<string[]>(
|
|
1556
|
-
text ? generateGibberishPreservingSpaces(text, charset).split("") : [],
|
|
1557
|
-
);
|
|
1558
|
-
|
|
1559
|
-
useEffect(() => {
|
|
1560
|
-
if (!isInView) return;
|
|
1561
|
-
|
|
1562
|
-
// Reset state for a fresh animation whenever dependencies change
|
|
1563
|
-
const initial = text
|
|
1564
|
-
? generateGibberishPreservingSpaces(text, charset)
|
|
1565
|
-
: "";
|
|
1566
|
-
scrambleCharsRef.current = initial.split("");
|
|
1567
|
-
startTimeRef.current = performance.now();
|
|
1568
|
-
lastFlipTimeRef.current = startTimeRef.current;
|
|
1569
|
-
setRevealCount(0);
|
|
1570
|
-
|
|
1571
|
-
let isCancelled = false;
|
|
1572
|
-
|
|
1573
|
-
const update = (now: number) => {
|
|
1574
|
-
if (isCancelled) return;
|
|
1575
|
-
|
|
1576
|
-
const elapsedMs = now - startTimeRef.current;
|
|
1577
|
-
const totalLength = text.length;
|
|
1578
|
-
const currentRevealCount = Math.min(
|
|
1579
|
-
totalLength,
|
|
1580
|
-
Math.floor(elapsedMs / Math.max(1, revealDelayMs)),
|
|
1581
|
-
);
|
|
1582
|
-
|
|
1583
|
-
setRevealCount(currentRevealCount);
|
|
1584
|
-
|
|
1585
|
-
if (currentRevealCount >= totalLength) {
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
// Re-randomize unrevealed scramble characters on an interval
|
|
1590
|
-
const timeSinceLastFlip = now - lastFlipTimeRef.current;
|
|
1591
|
-
if (timeSinceLastFlip >= Math.max(0, flipDelayMs)) {
|
|
1592
|
-
for (let index = 0; index < totalLength; index += 1) {
|
|
1593
|
-
if (index >= currentRevealCount) {
|
|
1594
|
-
if (text[index] !== " ") {
|
|
1595
|
-
scrambleCharsRef.current[index] =
|
|
1596
|
-
generateRandomCharacter(charset);
|
|
1597
|
-
} else {
|
|
1598
|
-
scrambleCharsRef.current[index] = " ";
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
lastFlipTimeRef.current = now;
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
animationFrameRef.current = requestAnimationFrame(update);
|
|
1606
|
-
};
|
|
1607
|
-
|
|
1608
|
-
animationFrameRef.current = requestAnimationFrame(update);
|
|
1609
|
-
|
|
1610
|
-
return () => {
|
|
1611
|
-
isCancelled = true;
|
|
1612
|
-
if (animationFrameRef.current !== null) {
|
|
1613
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
1614
|
-
}
|
|
1615
|
-
};
|
|
1616
|
-
}, [isInView, text, revealDelayMs, charset, flipDelayMs]);
|
|
1617
|
-
|
|
1618
|
-
if (!text) return null;
|
|
1619
|
-
|
|
1620
|
-
return (
|
|
1621
|
-
<motion.span
|
|
1622
|
-
ref={ref}
|
|
1623
|
-
className={cn(className)}
|
|
1624
|
-
aria-label={text}
|
|
1625
|
-
role="text"
|
|
1626
|
-
>
|
|
1627
|
-
{text.split("").map((char, index) => {
|
|
1628
|
-
const isRevealed = index < revealCount;
|
|
1629
|
-
const displayChar = isRevealed
|
|
1630
|
-
? char
|
|
1631
|
-
: char === " "
|
|
1632
|
-
? " "
|
|
1633
|
-
: (scrambleCharsRef.current[index] ??
|
|
1634
|
-
generateRandomCharacter(charset));
|
|
1635
|
-
|
|
1636
|
-
return (
|
|
1637
|
-
<span
|
|
1638
|
-
key={index}
|
|
1639
|
-
className={cn(isRevealed ? revealedClassName : encryptedClassName)}
|
|
1640
|
-
>
|
|
1641
|
-
{displayChar}
|
|
1642
|
-
</span>
|
|
1643
|
-
);
|
|
1644
|
-
})}
|
|
1645
|
-
</motion.span>
|
|
1646
|
-
);
|
|
1647
|
-
};
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
type ComicTextProps = {
|
|
1651
|
-
children: string
|
|
1652
|
-
className?: string
|
|
1653
|
-
style?: CSSProperties
|
|
1654
|
-
fontSize?: number
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
function ComicText({
|
|
1658
|
-
children,
|
|
1659
|
-
className,
|
|
1660
|
-
style,
|
|
1661
|
-
fontSize = 5,
|
|
1662
|
-
}: ComicTextProps) {
|
|
1663
|
-
if (typeof children !== "string") {
|
|
1664
|
-
throw new Error("children must be a string")
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
const dotColor = "#EF4444"
|
|
1668
|
-
const backgroundColor = "#FACC15"
|
|
1669
|
-
|
|
1670
|
-
return (
|
|
1671
|
-
<motion.div
|
|
1672
|
-
className={cn("text-center select-none", className)}
|
|
1673
|
-
style={{
|
|
1674
|
-
fontSize: `${fontSize}rem`,
|
|
1675
|
-
fontFamily: "'Bangers', 'Comic Sans MS', 'Impact', sans-serif",
|
|
1676
|
-
fontWeight: "900",
|
|
1677
|
-
WebkitTextStroke: `${fontSize * 0.35}px #000000`, // Thick black outline
|
|
1678
|
-
transform: "skewX(-10deg)",
|
|
1679
|
-
textTransform: "uppercase",
|
|
1680
|
-
filter: `
|
|
1681
|
-
drop-shadow(5px 5px 0px #000000)
|
|
1682
|
-
drop-shadow(3px 3px 0px ${dotColor})
|
|
1683
|
-
`,
|
|
1684
|
-
backgroundColor: backgroundColor,
|
|
1685
|
-
backgroundImage: `radial-gradient(circle at 1px 1px, ${dotColor} 1px, transparent 0)`,
|
|
1686
|
-
backgroundSize: "8px 8px",
|
|
1687
|
-
backgroundClip: "text",
|
|
1688
|
-
WebkitBackgroundClip: "text",
|
|
1689
|
-
WebkitTextFillColor: "transparent",
|
|
1690
|
-
...style,
|
|
1691
|
-
}}
|
|
1692
|
-
initial={{ opacity: 0, scale: 0.8, rotate: -2 }}
|
|
1693
|
-
animate={{ opacity: 1, scale: 1, rotate: 0 }}
|
|
1694
|
-
transition={{
|
|
1695
|
-
duration: 0.6,
|
|
1696
|
-
ease: [0.175, 0.885, 0.32, 1.275],
|
|
1697
|
-
type: "spring",
|
|
1698
|
-
}}
|
|
1699
|
-
>
|
|
1700
|
-
{children}
|
|
1701
|
-
</motion.div>
|
|
1702
|
-
)
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
type AnimationType = | "fadeIn" | "fadeInUp" | "popIn" | "shiftInUp" | "rollIn" | "whipIn" | "whipInUp" | "calmInUp" | "blurIn" | "blurInUp" | "blurInDown" | "slideUp" | "slideDown" | "slideLeft" | "slideRight" | "scaleUp" | "scaleDown";
|
|
1706
|
-
|
|
1707
|
-
interface Props extends HTMLMotionProps<"div"> {
|
|
1708
|
-
text: string
|
|
1709
|
-
type?: AnimationType
|
|
1710
|
-
delay?: number
|
|
1711
|
-
duration?: number
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
const animationVariants = {
|
|
1715
|
-
fadeIn: {
|
|
1716
|
-
container: {
|
|
1717
|
-
hidden: { opacity: 0 },
|
|
1718
|
-
visible: (i: number = 1) => ({
|
|
1719
|
-
opacity: 1,
|
|
1720
|
-
transition: { staggerChildren: 0.05, delayChildren: i * 0.3 },
|
|
1721
|
-
}),
|
|
1722
|
-
},
|
|
1723
|
-
child: {
|
|
1724
|
-
visible: {
|
|
1725
|
-
opacity: 1,
|
|
1726
|
-
y: 0,
|
|
1727
|
-
transition: {
|
|
1728
|
-
type: "spring" as const,
|
|
1729
|
-
damping: 12,
|
|
1730
|
-
stiffness: 100,
|
|
1731
|
-
},
|
|
1732
|
-
},
|
|
1733
|
-
hidden: { opacity: 0, y: 10 },
|
|
1734
|
-
},
|
|
1735
|
-
},
|
|
1736
|
-
fadeInUp: {
|
|
1737
|
-
container: {
|
|
1738
|
-
hidden: { opacity: 0 },
|
|
1739
|
-
visible: {
|
|
1740
|
-
opacity: 1,
|
|
1741
|
-
transition: { staggerChildren: 0.1, delayChildren: 0.2 },
|
|
1742
|
-
},
|
|
1743
|
-
},
|
|
1744
|
-
child: {
|
|
1745
|
-
visible: { opacity: 1, y: 0, transition: { duration: 0.5 } },
|
|
1746
|
-
hidden: { opacity: 0, y: 20 },
|
|
1747
|
-
},
|
|
1748
|
-
},
|
|
1749
|
-
popIn: {
|
|
1750
|
-
container: {
|
|
1751
|
-
hidden: { scale: 0 },
|
|
1752
|
-
visible: {
|
|
1753
|
-
scale: 1,
|
|
1754
|
-
transition: { staggerChildren: 0.05, delayChildren: 0.2 },
|
|
1755
|
-
},
|
|
1756
|
-
},
|
|
1757
|
-
child: {
|
|
1758
|
-
visible: {
|
|
1759
|
-
opacity: 1,
|
|
1760
|
-
scale: 1.1,
|
|
1761
|
-
transition: { type: "spring" as const, damping: 15, stiffness: 400 },
|
|
1762
|
-
},
|
|
1763
|
-
hidden: { opacity: 0, scale: 0 },
|
|
1764
|
-
},
|
|
1765
|
-
},
|
|
1766
|
-
calmInUp: {
|
|
1767
|
-
container: {
|
|
1768
|
-
hidden: {},
|
|
1769
|
-
visible: (i: number = 1) => ({
|
|
1770
|
-
transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },
|
|
1771
|
-
}),
|
|
1772
|
-
},
|
|
1773
|
-
child: {
|
|
1774
|
-
hidden: {
|
|
1775
|
-
y: "200%",
|
|
1776
|
-
transition: {
|
|
1777
|
-
ease: [0.455, 0.03, 0.515, 0.955] as const,
|
|
1778
|
-
duration: 0.85,
|
|
1779
|
-
},
|
|
1780
|
-
},
|
|
1781
|
-
visible: {
|
|
1782
|
-
y: 0,
|
|
1783
|
-
transition: {
|
|
1784
|
-
ease: [0.125, 0.92, 0.69, 0.975] as const, // Drawing attention to dynamic content or interactive elements, where the animation needs to be engaging but not abrupt
|
|
1785
|
-
duration: 0.75,
|
|
1786
|
-
// ease: [0.455, 0.03, 0.515, 0.955], // smooth and gradual acceleration followed by a steady deceleration towards the end of the animation
|
|
1787
|
-
// ease: [0.115, 0.955, 0.655, 0.939], // smooth and gradual acceleration followed by a steady deceleration towards the end of the animation
|
|
1788
|
-
// ease: [0.09, 0.88, 0.68, 0.98], // Very Gentle Onset, Swift Mid-Section, Soft Landing
|
|
1789
|
-
// ease: [0.11, 0.97, 0.64, 0.945], // Minimal Start, Energetic Acceleration, Smooth Closure
|
|
1790
|
-
},
|
|
1791
|
-
},
|
|
1792
|
-
},
|
|
1793
|
-
},
|
|
1794
|
-
shiftInUp: {
|
|
1795
|
-
container: {
|
|
1796
|
-
hidden: {},
|
|
1797
|
-
visible: (i: number = 1) => ({
|
|
1798
|
-
transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },
|
|
1799
|
-
}),
|
|
1800
|
-
},
|
|
1801
|
-
child: {
|
|
1802
|
-
hidden: {
|
|
1803
|
-
y: "100%", // Starting from below but not too far to ensure a dramatic but manageable shift.
|
|
1804
|
-
transition: {
|
|
1805
|
-
ease: [0.75, 0, 0.25, 1] as const, // Starting quickly
|
|
1806
|
-
duration: 0.6, // Shortened duration for a more dramatic start
|
|
1807
|
-
},
|
|
1808
|
-
},
|
|
1809
|
-
visible: {
|
|
1810
|
-
y: 0,
|
|
1811
|
-
transition: {
|
|
1812
|
-
duration: 0.8, // Slightly longer to accommodate the slow middle and swift end
|
|
1813
|
-
ease: [0.22, 1, 0.36, 1] as const, // This easing function starts quickly (dramatic shift), slows down (slow middle), and ends quickly (clean swift end)
|
|
1814
|
-
},
|
|
1815
|
-
},
|
|
1816
|
-
},
|
|
1817
|
-
},
|
|
1818
|
-
whipInUp: {
|
|
1819
|
-
container: {
|
|
1820
|
-
hidden: {},
|
|
1821
|
-
visible: (i: number = 1) => ({
|
|
1822
|
-
transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },
|
|
1823
|
-
}),
|
|
1824
|
-
},
|
|
1825
|
-
child: {
|
|
1826
|
-
hidden: {
|
|
1827
|
-
y: "200%",
|
|
1828
|
-
transition: {
|
|
1829
|
-
ease: [0.455, 0.03, 0.515, 0.955] as const,
|
|
1830
|
-
duration: 0.45,
|
|
1831
|
-
},
|
|
1832
|
-
},
|
|
1833
|
-
visible: {
|
|
1834
|
-
y: 0,
|
|
1835
|
-
transition: {
|
|
1836
|
-
ease: [0.5, -0.15, 0.25, 1.05] as const,
|
|
1837
|
-
duration: 0.75,
|
|
1838
|
-
},
|
|
1839
|
-
},
|
|
1840
|
-
},
|
|
1841
|
-
},
|
|
1842
|
-
rollIn: {
|
|
1843
|
-
container: {
|
|
1844
|
-
hidden: {},
|
|
1845
|
-
visible: {},
|
|
1846
|
-
},
|
|
1847
|
-
child: {
|
|
1848
|
-
hidden: {
|
|
1849
|
-
opacity: 0,
|
|
1850
|
-
y: `0.25em`,
|
|
1851
|
-
},
|
|
1852
|
-
visible: {
|
|
1853
|
-
opacity: 1,
|
|
1854
|
-
y: `0em`,
|
|
1855
|
-
transition: {
|
|
1856
|
-
duration: 0.65,
|
|
1857
|
-
ease: [0.65, 0, 0.75, 1] as const, // Great! Swift Beginning, Prolonged Ease, Quick Finish
|
|
1858
|
-
// ease: [0.75, 0.05, 0.85, 1], // Quick Start, Smooth Middle, Sharp End
|
|
1859
|
-
// ease: [0.7, -0.25, 0.9, 1.25], // Fast Acceleration, Gentle Slowdown, Sudden Snap
|
|
1860
|
-
// ease: [0.7, -0.5, 0.85, 1.5], // Quick Leap, Soft Glide, Snappy Closure
|
|
1861
|
-
},
|
|
1862
|
-
},
|
|
1863
|
-
},
|
|
1864
|
-
},
|
|
1865
|
-
whipIn: {
|
|
1866
|
-
container: {
|
|
1867
|
-
hidden: {},
|
|
1868
|
-
visible: {},
|
|
1869
|
-
},
|
|
1870
|
-
child: {
|
|
1871
|
-
hidden: {
|
|
1872
|
-
opacity: 0,
|
|
1873
|
-
y: `0.35em`,
|
|
1874
|
-
},
|
|
1875
|
-
visible: {
|
|
1876
|
-
opacity: 1,
|
|
1877
|
-
y: `0em`,
|
|
1878
|
-
transition: {
|
|
1879
|
-
duration: 0.45,
|
|
1880
|
-
// ease: [0.75, 0.05, 0.85, 1], // Quick Start, Smooth Middle, Sharp End
|
|
1881
|
-
// ease: [0.7, -0.25, 0.9, 1.25], // Fast Acceleration, Gentle Slowdown, Sudden Snap
|
|
1882
|
-
// ease: [0.65, 0, 0.75, 1], // Great! Swift Beginning, Prolonged Ease, Quick Finish
|
|
1883
|
-
ease: [0.85, 0.1, 0.9, 1.2] as const, // Rapid Initiation, Subtle Slow, Sharp Conclusion
|
|
1884
|
-
},
|
|
1885
|
-
},
|
|
1886
|
-
},
|
|
1887
|
-
},
|
|
1888
|
-
blurIn: {
|
|
1889
|
-
container: {
|
|
1890
|
-
hidden: { opacity: 0 },
|
|
1891
|
-
visible: {
|
|
1892
|
-
opacity: 1,
|
|
1893
|
-
transition: { staggerChildren: 0.03, delayChildren: 0.2 },
|
|
1894
|
-
},
|
|
1895
|
-
},
|
|
1896
|
-
child: {
|
|
1897
|
-
visible: {
|
|
1898
|
-
opacity: 1,
|
|
1899
|
-
filter: "blur(0px)",
|
|
1900
|
-
transition: { duration: 0.6 },
|
|
1901
|
-
},
|
|
1902
|
-
hidden: { opacity: 0, filter: "blur(10px)" },
|
|
1903
|
-
},
|
|
1904
|
-
},
|
|
1905
|
-
blurInUp: {
|
|
1906
|
-
container: {
|
|
1907
|
-
hidden: { opacity: 0 },
|
|
1908
|
-
visible: {
|
|
1909
|
-
opacity: 1,
|
|
1910
|
-
transition: { staggerChildren: 0.04, delayChildren: 0.2 },
|
|
1911
|
-
},
|
|
1912
|
-
},
|
|
1913
|
-
child: {
|
|
1914
|
-
visible: {
|
|
1915
|
-
opacity: 1,
|
|
1916
|
-
y: 0,
|
|
1917
|
-
filter: "blur(0px)",
|
|
1918
|
-
transition: { duration: 0.7 },
|
|
1919
|
-
},
|
|
1920
|
-
hidden: { opacity: 0, y: 20, filter: "blur(8px)" },
|
|
1921
|
-
},
|
|
1922
|
-
},
|
|
1923
|
-
blurInDown: {
|
|
1924
|
-
container: {
|
|
1925
|
-
hidden: { opacity: 0 },
|
|
1926
|
-
visible: {
|
|
1927
|
-
opacity: 1,
|
|
1928
|
-
transition: { staggerChildren: 0.04, delayChildren: 0.2 },
|
|
1929
|
-
},
|
|
1930
|
-
},
|
|
1931
|
-
child: {
|
|
1932
|
-
visible: {
|
|
1933
|
-
opacity: 1,
|
|
1934
|
-
y: 0,
|
|
1935
|
-
filter: "blur(0px)",
|
|
1936
|
-
transition: { duration: 0.7 },
|
|
1937
|
-
},
|
|
1938
|
-
hidden: { opacity: 0, y: -20, filter: "blur(8px)" },
|
|
1939
|
-
},
|
|
1940
|
-
},
|
|
1941
|
-
slideUp: {
|
|
1942
|
-
container: {
|
|
1943
|
-
hidden: {},
|
|
1944
|
-
visible: {
|
|
1945
|
-
transition: { staggerChildren: 0.03, delayChildren: 0.2 },
|
|
1946
|
-
},
|
|
1947
|
-
},
|
|
1948
|
-
child: {
|
|
1949
|
-
visible: {
|
|
1950
|
-
y: 0,
|
|
1951
|
-
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as const },
|
|
1952
|
-
},
|
|
1953
|
-
hidden: { y: 30 },
|
|
1954
|
-
},
|
|
1955
|
-
},
|
|
1956
|
-
slideDown: {
|
|
1957
|
-
container: {
|
|
1958
|
-
hidden: {},
|
|
1959
|
-
visible: {
|
|
1960
|
-
transition: { staggerChildren: 0.03, delayChildren: 0.2 },
|
|
1961
|
-
},
|
|
1962
|
-
},
|
|
1963
|
-
child: {
|
|
1964
|
-
visible: {
|
|
1965
|
-
y: 0,
|
|
1966
|
-
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as const },
|
|
1967
|
-
},
|
|
1968
|
-
hidden: { y: -30 },
|
|
1969
|
-
},
|
|
1970
|
-
},
|
|
1971
|
-
slideLeft: {
|
|
1972
|
-
container: {
|
|
1973
|
-
hidden: {},
|
|
1974
|
-
visible: {
|
|
1975
|
-
transition: { staggerChildren: 0.03, delayChildren: 0.2 },
|
|
1976
|
-
},
|
|
1977
|
-
},
|
|
1978
|
-
child: {
|
|
1979
|
-
visible: {
|
|
1980
|
-
x: 0,
|
|
1981
|
-
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as const },
|
|
1982
|
-
},
|
|
1983
|
-
hidden: { x: 30 },
|
|
1984
|
-
},
|
|
1985
|
-
},
|
|
1986
|
-
slideRight: {
|
|
1987
|
-
container: {
|
|
1988
|
-
hidden: {},
|
|
1989
|
-
visible: {
|
|
1990
|
-
transition: { staggerChildren: 0.03, delayChildren: 0.2 },
|
|
1991
|
-
},
|
|
1992
|
-
},
|
|
1993
|
-
child: {
|
|
1994
|
-
visible: {
|
|
1995
|
-
x: 0,
|
|
1996
|
-
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as const },
|
|
1997
|
-
},
|
|
1998
|
-
hidden: { x: -30 },
|
|
1999
|
-
},
|
|
2000
|
-
},
|
|
2001
|
-
scaleUp: {
|
|
2002
|
-
container: {
|
|
2003
|
-
hidden: {},
|
|
2004
|
-
visible: {
|
|
2005
|
-
transition: { staggerChildren: 0.04, delayChildren: 0.2 },
|
|
2006
|
-
},
|
|
2007
|
-
},
|
|
2008
|
-
child: {
|
|
2009
|
-
visible: {
|
|
2010
|
-
scale: 1,
|
|
2011
|
-
opacity: 1,
|
|
2012
|
-
transition: {
|
|
2013
|
-
duration: 0.5,
|
|
2014
|
-
ease: [0.34, 1.56, 0.64, 1] as const,
|
|
2015
|
-
},
|
|
2016
|
-
},
|
|
2017
|
-
hidden: { scale: 0.5, opacity: 0 },
|
|
2018
|
-
},
|
|
2019
|
-
},
|
|
2020
|
-
scaleDown: {
|
|
2021
|
-
container: {
|
|
2022
|
-
hidden: {},
|
|
2023
|
-
visible: {
|
|
2024
|
-
transition: { staggerChildren: 0.04, delayChildren: 0.2 },
|
|
2025
|
-
},
|
|
2026
|
-
},
|
|
2027
|
-
child: {
|
|
2028
|
-
visible: {
|
|
2029
|
-
scale: 1,
|
|
2030
|
-
opacity: 1,
|
|
2031
|
-
transition: {
|
|
2032
|
-
duration: 0.5,
|
|
2033
|
-
ease: [0.34, 1.56, 0.64, 1] as const,
|
|
2034
|
-
},
|
|
2035
|
-
},
|
|
2036
|
-
hidden: { scale: 1.5, opacity: 0 },
|
|
2037
|
-
},
|
|
2038
|
-
},
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
const AnimateText: FC<Props> = ({
|
|
2042
|
-
text,
|
|
2043
|
-
type = "whipInUp",
|
|
2044
|
-
variant = 'default',
|
|
2045
|
-
...props
|
|
2046
|
-
}: Props) => {
|
|
2047
|
-
// const { ref, inView } = useInView({
|
|
2048
|
-
// threshold: 0.5,
|
|
2049
|
-
// triggerOnce: true,
|
|
2050
|
-
// });
|
|
2051
|
-
|
|
2052
|
-
const ref = useRef(null)
|
|
2053
|
-
const isInView = useInView(ref, { once: true })
|
|
2054
|
-
|
|
2055
|
-
const letters = Array.from(text)
|
|
2056
|
-
const { container, child } = animationVariants[type]
|
|
2057
|
-
|
|
2058
|
-
const ctrls = useAnimation()
|
|
2059
|
-
|
|
2060
|
-
// useEffect(() => {
|
|
2061
|
-
// if (isInView) {
|
|
2062
|
-
// ctrls.start("visible");
|
|
2063
|
-
// }
|
|
2064
|
-
// if (!isInView) {
|
|
2065
|
-
// ctrls.start("hidden");
|
|
2066
|
-
// }
|
|
2067
|
-
// }, [ctrls, isInView]);
|
|
2068
|
-
|
|
2069
|
-
if (type === "rollIn" || type === "whipIn") {
|
|
2070
|
-
return (
|
|
2071
|
-
<h2 className="mt-10 text-3xl font-black text-black dark:text-neutral-100 py-5 pb-8 px-8 md:text-5xl">
|
|
2072
|
-
{text.split(" ").map((word, index) => {
|
|
2073
|
-
return (
|
|
2074
|
-
<motion.span
|
|
2075
|
-
ref={ref}
|
|
2076
|
-
className="inline-block mr-[0.25em] whitespace-nowrap"
|
|
2077
|
-
aria-hidden="true"
|
|
2078
|
-
key={index}
|
|
2079
|
-
initial="hidden"
|
|
2080
|
-
animate="visible"
|
|
2081
|
-
variants={container}
|
|
2082
|
-
transition={{
|
|
2083
|
-
delayChildren: index * 0.13,
|
|
2084
|
-
// delayChildren: index * 0.35,
|
|
2085
|
-
staggerChildren: 0.025,
|
|
2086
|
-
// staggerChildren: 0.05,
|
|
2087
|
-
}}
|
|
2088
|
-
>
|
|
2089
|
-
{word.split("").map((character, index) => {
|
|
2090
|
-
return (
|
|
2091
|
-
<motion.span
|
|
2092
|
-
aria-hidden="true"
|
|
2093
|
-
key={index}
|
|
2094
|
-
variants={child}
|
|
2095
|
-
className="inline-block -mr-[0.01em]"
|
|
2096
|
-
>
|
|
2097
|
-
{character}
|
|
2098
|
-
</motion.span>
|
|
2099
|
-
)
|
|
2100
|
-
})}
|
|
2101
|
-
</motion.span>
|
|
2102
|
-
)
|
|
2103
|
-
})}
|
|
2104
|
-
</h2>
|
|
2105
|
-
)
|
|
2106
|
-
}
|
|
2107
|
-
|
|
2108
|
-
return (
|
|
2109
|
-
<motion.h2
|
|
2110
|
-
style={{ display: "flex", overflow: "hidden" }}
|
|
2111
|
-
role="heading"
|
|
2112
|
-
variants={container}
|
|
2113
|
-
initial="hidden"
|
|
2114
|
-
animate="visible"
|
|
2115
|
-
className="mt-10 text-4xl font-black text-black dark:text-neutral-100 py-5 pb-8 px-8 md:text-5xl"
|
|
2116
|
-
{...props}
|
|
2117
|
-
>
|
|
2118
|
-
{letters.map((letter, index) => (
|
|
2119
|
-
<motion.span key={index} variants={child}>
|
|
2120
|
-
{letter === " " ? "\u00A0" : letter}
|
|
2121
|
-
</motion.span>
|
|
2122
|
-
))}
|
|
2123
|
-
</motion.h2>
|
|
2124
|
-
)
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
interface GlitchTextProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2128
|
-
text: string
|
|
2129
|
-
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span"
|
|
2130
|
-
textClassName?: string
|
|
2131
|
-
containerClassName?: string
|
|
2132
|
-
colors?: {
|
|
2133
|
-
red: string
|
|
2134
|
-
green: string
|
|
2135
|
-
blue: string
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
const AnimatedGlitchText = React.forwardRef<HTMLDivElement, GlitchTextProps>(
|
|
2140
|
-
({
|
|
2141
|
-
text,
|
|
2142
|
-
as: Component = "h1",
|
|
2143
|
-
className,
|
|
2144
|
-
textClassName,
|
|
2145
|
-
containerClassName,
|
|
2146
|
-
colors = {
|
|
2147
|
-
red: "#ff0000",
|
|
2148
|
-
green: "#00ff00",
|
|
2149
|
-
blue: "#0000ff"
|
|
2150
|
-
},
|
|
2151
|
-
...props
|
|
2152
|
-
}, ref) => {
|
|
2153
|
-
return (
|
|
2154
|
-
<div
|
|
2155
|
-
ref={ref}
|
|
2156
|
-
className={cn(
|
|
2157
|
-
"flex items-center justify-center p-4",
|
|
2158
|
-
"min-h-[200px]",
|
|
2159
|
-
className
|
|
2160
|
-
)}
|
|
2161
|
-
{...props}
|
|
2162
|
-
>
|
|
2163
|
-
<div className={cn(
|
|
2164
|
-
"relative",
|
|
2165
|
-
containerClassName
|
|
2166
|
-
)}>
|
|
2167
|
-
<motion.div
|
|
2168
|
-
className={cn(
|
|
2169
|
-
"text-6xl font-bold absolute",
|
|
2170
|
-
"mix-blend-multiply dark:mix-blend-screen",
|
|
2171
|
-
textClassName
|
|
2172
|
-
)}
|
|
2173
|
-
animate={{
|
|
2174
|
-
x: [-2, 2, -2],
|
|
2175
|
-
y: [0, -1, 1],
|
|
2176
|
-
skew: [0, -2, 2],
|
|
2177
|
-
opacity: [1, 0.8, 0.9],
|
|
2178
|
-
color: [colors.red, colors.red, colors.red]
|
|
2179
|
-
}}
|
|
2180
|
-
transition={{
|
|
2181
|
-
duration: 0.15,
|
|
2182
|
-
repeat: Infinity,
|
|
2183
|
-
repeatType: "mirror",
|
|
2184
|
-
ease: "anticipate"
|
|
2185
|
-
}}
|
|
2186
|
-
>
|
|
2187
|
-
{text}
|
|
2188
|
-
</motion.div>
|
|
2189
|
-
<motion.div
|
|
2190
|
-
className={cn(
|
|
2191
|
-
"text-6xl font-bold absolute",
|
|
2192
|
-
"mix-blend-multiply dark:mix-blend-screen",
|
|
2193
|
-
textClassName
|
|
2194
|
-
)}
|
|
2195
|
-
animate={{
|
|
2196
|
-
x: [2, -2, 2],
|
|
2197
|
-
y: [1, -1, 0],
|
|
2198
|
-
skew: [-2, 2, 0],
|
|
2199
|
-
opacity: [0.9, 1, 0.8],
|
|
2200
|
-
color: [colors.green, colors.green, colors.green]
|
|
2201
|
-
}}
|
|
2202
|
-
transition={{
|
|
2203
|
-
duration: 0.13,
|
|
2204
|
-
repeat: Infinity,
|
|
2205
|
-
repeatType: "mirror",
|
|
2206
|
-
ease: "anticipate"
|
|
2207
|
-
}}
|
|
2208
|
-
>
|
|
2209
|
-
{text}
|
|
2210
|
-
</motion.div>
|
|
2211
|
-
<motion.div
|
|
2212
|
-
className={cn(
|
|
2213
|
-
"text-6xl font-bold",
|
|
2214
|
-
"mix-blend-multiply dark:mix-blend-screen",
|
|
2215
|
-
textClassName
|
|
2216
|
-
)}
|
|
2217
|
-
animate={{
|
|
2218
|
-
x: [-1, 1, -1],
|
|
2219
|
-
y: [-1, 1, 0],
|
|
2220
|
-
skew: [2, -2, 0],
|
|
2221
|
-
opacity: [0.8, 0.9, 1],
|
|
2222
|
-
color: [colors.blue, colors.blue, colors.blue]
|
|
2223
|
-
}}
|
|
2224
|
-
transition={{
|
|
2225
|
-
duration: 0.11,
|
|
2226
|
-
repeat: Infinity,
|
|
2227
|
-
repeatType: "mirror",
|
|
2228
|
-
ease: "anticipate"
|
|
2229
|
-
}}
|
|
2230
|
-
>
|
|
2231
|
-
{text}
|
|
2232
|
-
</motion.div>
|
|
2233
|
-
</div>
|
|
2234
|
-
</div>
|
|
2235
|
-
)
|
|
2236
|
-
}
|
|
2237
|
-
)
|
|
2238
|
-
AnimatedGlitchText.displayName = "AnimatedGlitchText"
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
export { AnimatedTextX }
|