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.
Files changed (249) hide show
  1. package/README.md +35 -0
  2. package/package.json +5 -2
  3. package/src/cli.js +39 -3
  4. package/src/commands/shop.js +59 -0
  5. package/src/commands/warehouse.js +73 -0
  6. package/src/utils/paths.js +13 -13
  7. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  8. package/templates/blocks/DD-Accordion/README.md +3 -0
  9. package/templates/blocks/DD-Accordion/config.ts +73 -0
  10. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  11. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  12. package/templates/blocks/DD-AnimText/README.md +3 -0
  13. package/templates/blocks/DD-AnimText/config.ts +295 -0
  14. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  15. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  16. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  17. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  18. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  19. package/templates/blocks/DD-Banner/config.ts +57 -0
  20. package/templates/blocks/DD-Banner/manifest.json +72 -0
  21. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  22. package/templates/blocks/DD-BgLightning/README.md +3 -0
  23. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  24. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  25. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  26. package/templates/blocks/DD-BookCall/config.ts +238 -238
  27. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  28. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  29. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  30. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  31. package/templates/blocks/DD-Card/Component.tsx +251 -0
  32. package/templates/blocks/DD-Card/README.md +4 -0
  33. package/templates/blocks/DD-Card/config.ts +154 -0
  34. package/templates/blocks/DD-Card/manifest.json +82 -0
  35. package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
  36. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  37. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  38. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  39. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  40. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  41. package/templates/blocks/DD-Chip/README.md +202 -0
  42. package/templates/blocks/DD-Chip/config.ts +369 -0
  43. package/templates/blocks/DD-Chip/manifest.json +74 -0
  44. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  45. package/templates/blocks/DD-Contact/Component.tsx +435 -434
  46. package/templates/blocks/DD-Contact/config.ts +22 -22
  47. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  48. package/templates/blocks/DD-Counter/README.md +4 -0
  49. package/templates/blocks/DD-Counter/config.ts +291 -0
  50. package/templates/blocks/DD-Counter/manifest.json +74 -0
  51. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  52. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  53. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  54. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  55. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  56. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  57. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  58. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  59. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  60. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  61. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  62. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  63. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  64. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  65. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  66. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  67. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  68. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  69. package/templates/blocks/DD-Hero/Component.tsx +297 -297
  70. package/templates/blocks/DD-Hero/config.ts +267 -267
  71. package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
  72. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  73. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  74. package/templates/blocks/DD-Icon/README.md +4 -0
  75. package/templates/blocks/DD-Icon/config.ts +258 -0
  76. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  77. package/templates/blocks/DD-Icon/manifest.json +82 -0
  78. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  79. package/templates/blocks/DD-IconButton/README.md +326 -0
  80. package/templates/blocks/DD-IconButton/config.ts +239 -0
  81. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  82. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  83. package/templates/blocks/DD-IdTag/README.md +4 -0
  84. package/templates/blocks/DD-IdTag/config.ts +41 -0
  85. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  86. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  87. package/templates/blocks/DD-Iframe/README.md +4 -0
  88. package/templates/blocks/DD-Iframe/config.ts +47 -0
  89. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  90. package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
  91. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  92. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  93. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  94. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  95. package/templates/blocks/DD-LineAnim/README.md +4 -0
  96. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  97. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  98. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  99. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  100. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  101. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  102. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  103. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  104. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  105. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  106. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  107. package/templates/blocks/DD-Lottie/README.md +4 -0
  108. package/templates/blocks/DD-Lottie/config.ts +379 -0
  109. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  110. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  111. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  112. package/templates/blocks/DD-MagicBento/README.md +4 -0
  113. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  114. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  115. package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
  116. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  117. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  118. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  119. package/templates/blocks/DD-Masonry/README.md +4 -0
  120. package/templates/blocks/DD-Masonry/config.ts +475 -0
  121. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  122. package/templates/blocks/DD-Pricing/Component.tsx +2 -5
  123. package/templates/blocks/DD-Process/Component.tsx +2 -4
  124. package/templates/blocks/DD-Process/config.ts +150 -150
  125. package/templates/blocks/DD-Progress/Component.tsx +156 -0
  126. package/templates/blocks/DD-Progress/README.md +4 -0
  127. package/templates/blocks/DD-Progress/config.ts +175 -0
  128. package/templates/blocks/DD-Progress/manifest.json +74 -0
  129. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  130. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  131. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  132. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  133. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  134. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  135. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  136. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  137. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  138. package/templates/blocks/DD-ScrollText/README.md +4 -0
  139. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  140. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  141. package/templates/blocks/DD-Section/Component.tsx +266 -266
  142. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  143. package/templates/blocks/DD-Separator/README.md +4 -0
  144. package/templates/blocks/DD-Separator/config.ts +58 -0
  145. package/templates/blocks/DD-Separator/manifest.json +72 -0
  146. package/templates/blocks/DD-Services/Component.tsx +176 -176
  147. package/templates/blocks/DD-Services/config.ts +149 -149
  148. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  149. package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
  150. package/templates/blocks/DD-StackCards/Component.tsx +1 -1
  151. package/templates/blocks/DD-StackCards/config.ts +399 -399
  152. package/templates/blocks/DD-Team/Component.tsx +247 -247
  153. package/templates/blocks/DD-Team/config.ts +173 -173
  154. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  155. package/templates/blocks/DD-TeamCards/README.md +4 -0
  156. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  157. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  158. package/templates/blocks/DD-TechStack/Component.tsx +174 -174
  159. package/templates/blocks/DD-TechStack/config.ts +153 -153
  160. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  161. package/templates/blocks/DD-TestMarq/README.md +4 -0
  162. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  163. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  164. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  165. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  166. package/templates/blocks/DD-Testim/README.md +4 -0
  167. package/templates/blocks/DD-Testim/config.ts +101 -0
  168. package/templates/blocks/DD-Testim/manifest.json +75 -0
  169. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  170. package/templates/blocks/DD-Testim2/README.md +4 -0
  171. package/templates/blocks/DD-Testim2/config.ts +100 -0
  172. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  173. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  174. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  175. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  176. package/templates/blocks/DD-TextMarq/README.md +4 -0
  177. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  178. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  179. package/templates/blocks/DD-Thanks/Component.tsx +501 -0
  180. package/templates/blocks/DD-Thanks/README.md +4 -0
  181. package/templates/blocks/DD-Thanks/config.ts +224 -0
  182. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  183. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  184. package/templates/blocks/DD-VertMarq/README.md +4 -0
  185. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  186. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  187. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  188. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  189. package/templates/blocks/DD-Work/Component.tsx +318 -315
  190. package/templates/blocks/DD-Work/config.ts +165 -165
  191. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  192. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  193. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  194. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  195. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  196. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  197. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  198. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
  199. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
  200. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  201. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
  202. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  203. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  204. package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
  205. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  206. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  207. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  208. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
  209. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  210. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  211. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  212. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  213. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  214. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  215. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  216. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  217. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  218. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  219. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  220. package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
  221. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  222. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  223. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  224. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  225. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  226. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  227. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  228. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  229. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  230. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  231. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  232. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  233. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  234. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  235. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  236. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  237. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  238. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  239. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  240. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  241. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  242. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  243. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  244. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  245. package/templates/shared/src/components/ui/separator.tsx +85 -0
  246. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  247. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  248. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  249. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -0,0 +1,58 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ interface ShinyTextProps {
5
+ text: string
6
+ disabled?: boolean
7
+ speed?: number
8
+ className?: string
9
+ }
10
+
11
+ export const ShinyText: React.FC<ShinyTextProps> = ({
12
+ text,
13
+ disabled = false,
14
+ speed = 5,
15
+ className = ''
16
+ }) => {
17
+ const animationDuration = `${speed}s`
18
+
19
+ return (
20
+ <>
21
+ <div
22
+ className={`shiny-text ${disabled ? 'disabled' : ''} ${className}`}
23
+ style={{ animationDuration }}
24
+ >
25
+ {text}
26
+ </div>
27
+ <style jsx>{`
28
+ .shiny-text {
29
+ color: #b5b5b5a4; /* Adjust this color to change intensity/style */
30
+ background: linear-gradient(
31
+ 120deg,
32
+ rgba(255, 255, 255, 0) 40%,
33
+ rgba(255, 255, 255, 0.8) 50%,
34
+ rgba(255, 255, 255, 0) 60%
35
+ );
36
+ background-size: 200% 100%;
37
+ -webkit-background-clip: text;
38
+ background-clip: text;
39
+ display: inline-block;
40
+ animation: shine 5s linear infinite;
41
+ }
42
+
43
+ @keyframes shine {
44
+ 0% {
45
+ background-position: 100%;
46
+ }
47
+ 100% {
48
+ background-position: -100%;
49
+ }
50
+ }
51
+
52
+ .shiny-text.disabled {
53
+ animation: none;
54
+ }
55
+ `}</style>
56
+ </>
57
+ )
58
+ }
@@ -0,0 +1,85 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { motion, useInView } from 'framer-motion'
5
+ import { cn } from '@/utilities/ui'
6
+
7
+ interface ShuffleTextProps {
8
+ text: string | string[]
9
+ className?: string
10
+ aniTextClass?: string
11
+ duration?: number
12
+ delay?: number
13
+ }
14
+
15
+ export function ShuffleText({
16
+ text,
17
+ className = '',
18
+ aniTextClass = '',
19
+ duration = 0.8,
20
+ delay = 0
21
+ }: ShuffleTextProps) {
22
+ const ref = React.useRef(null)
23
+ const isInView = useInView(ref, { once: false })
24
+
25
+ // Convert text to array if it's a string
26
+ const textArray = Array.isArray(text) ? text : [text]
27
+ const fullText = textArray.join(' ')
28
+
29
+ const [displayText, setDisplayText] = React.useState('')
30
+ const [isShuffling, setIsShuffling] = React.useState(false)
31
+
32
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
33
+
34
+ React.useEffect(() => {
35
+ if (!isInView) return
36
+
37
+ const startShuffle = () => {
38
+ setIsShuffling(true)
39
+ let iteration = 0
40
+ const totalIterations = fullText.length
41
+
42
+ const interval = setInterval(() => {
43
+ setDisplayText((prev) => {
44
+ return fullText
45
+ .split('')
46
+ .map((char, index) => {
47
+ if (index < iteration) {
48
+ return char
49
+ }
50
+ if (char === ' ') {
51
+ return ' '
52
+ }
53
+ return characters[Math.floor(Math.random() * characters.length)]
54
+ })
55
+ .join('')
56
+ })
57
+
58
+ if (iteration >= totalIterations) {
59
+ clearInterval(interval)
60
+ setDisplayText(fullText)
61
+ setIsShuffling(false)
62
+ }
63
+
64
+ iteration += 1 / 3
65
+ }, 30)
66
+ }
67
+
68
+ const timer = setTimeout(startShuffle, delay * 1000)
69
+ return () => {
70
+ clearTimeout(timer)
71
+ }
72
+ }, [isInView, fullText, delay])
73
+
74
+ return (
75
+ <motion.span
76
+ ref={ref}
77
+ className={cn('inline-block', className, aniTextClass)}
78
+ initial={{ opacity: 0 }}
79
+ animate={isInView ? { opacity: 1 } : { opacity: 0 }}
80
+ transition={{ duration: 0.3, delay }}
81
+ >
82
+ {displayText || fullText}
83
+ </motion.span>
84
+ )
85
+ }
@@ -0,0 +1,211 @@
1
+ 'use client'
2
+
3
+ import React, { useRef, useEffect, useState } from 'react'
4
+ import { gsap } from 'gsap'
5
+ import { ScrollTrigger } from 'gsap/ScrollTrigger'
6
+ import { SplitText as GSAPSplitText } from 'gsap/SplitText'
7
+ import { useGSAP } from '@gsap/react'
8
+
9
+ gsap.registerPlugin(ScrollTrigger, GSAPSplitText, useGSAP)
10
+
11
+ export interface SplitTextProps {
12
+ text: string
13
+ className?: string
14
+ delay?: number
15
+ duration?: number
16
+ ease?: string | ((t: number) => number)
17
+ splitType?: 'chars' | 'words' | 'lines' | 'words, chars'
18
+ from?: gsap.TweenVars
19
+ to?: gsap.TweenVars
20
+ threshold?: number
21
+ rootMargin?: string
22
+ tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span'
23
+ textAlign?: React.CSSProperties['textAlign']
24
+ onLetterAnimationComplete?: () => void
25
+ }
26
+
27
+ export const SplitText: React.FC<SplitTextProps> = ({
28
+ text,
29
+ className = '',
30
+ delay = 100,
31
+ duration = 0.6,
32
+ ease = 'power3.out',
33
+ splitType = 'chars',
34
+ from = { opacity: 0, y: 40 },
35
+ to = { opacity: 1, y: 0 },
36
+ threshold = 0.1,
37
+ rootMargin = '-100px',
38
+ textAlign = 'center',
39
+ tag = 'p',
40
+ onLetterAnimationComplete
41
+ }) => {
42
+ const ref = useRef<HTMLParagraphElement>(null)
43
+ const animationCompletedRef = useRef(false)
44
+ const [fontsLoaded, setFontsLoaded] = useState<boolean>(false)
45
+
46
+ useEffect(() => {
47
+ if (document.fonts.status === 'loaded') {
48
+ setFontsLoaded(true)
49
+ } else {
50
+ document.fonts.ready.then(() => {
51
+ setFontsLoaded(true)
52
+ })
53
+ }
54
+ }, [])
55
+
56
+ useGSAP(
57
+ () => {
58
+ if (!ref.current || !text || !fontsLoaded) return
59
+
60
+ const el = ref.current as HTMLElement & {
61
+ _rbsplitInstance?: GSAPSplitText
62
+ }
63
+
64
+ if (el._rbsplitInstance) {
65
+ try {
66
+ el._rbsplitInstance.revert()
67
+ } catch (_) {}
68
+ el._rbsplitInstance = undefined
69
+ }
70
+
71
+ const startPct = (1 - threshold) * 100
72
+ const marginMatch = /^(-?\d+(?:\.\d+)?)(px|em|rem|%)?$/.exec(rootMargin)
73
+ const marginValue = marginMatch ? parseFloat(marginMatch[1] || '0') : 0
74
+ const marginUnit = marginMatch ? marginMatch[2] || 'px' : 'px'
75
+ const sign =
76
+ marginValue === 0
77
+ ? ''
78
+ : marginValue < 0
79
+ ? `-=${Math.abs(marginValue)}${marginUnit}`
80
+ : `+=${marginValue}${marginUnit}`
81
+ const start = `top ${startPct}%${sign}`
82
+ let targets: Element[] = []
83
+ const assignTargets = (self: GSAPSplitText) => {
84
+ if (splitType.includes('chars') && self.chars.length) targets = self.chars
85
+ if (!targets.length && splitType.includes('words') && self.words.length)
86
+ targets = self.words
87
+ if (!targets.length && splitType.includes('lines') && self.lines.length)
88
+ targets = self.lines
89
+ if (!targets.length) targets = self.chars || self.words || self.lines
90
+ }
91
+ const splitInstance = new GSAPSplitText(el, {
92
+ type: splitType,
93
+ smartWrap: true,
94
+ autoSplit: splitType === 'lines',
95
+ linesClass: 'split-line',
96
+ wordsClass: 'split-word',
97
+ charsClass: 'split-char',
98
+ reduceWhiteSpace: false,
99
+ onSplit: (self: GSAPSplitText) => {
100
+ assignTargets(self)
101
+ return gsap.fromTo(
102
+ targets,
103
+ { ...from },
104
+ {
105
+ ...to,
106
+ duration,
107
+ ease,
108
+ stagger: delay / 1000,
109
+ scrollTrigger: {
110
+ trigger: el,
111
+ start,
112
+ once: true,
113
+ fastScrollEnd: true,
114
+ anticipatePin: 0.4
115
+ },
116
+ onComplete: () => {
117
+ animationCompletedRef.current = true
118
+ onLetterAnimationComplete?.()
119
+ },
120
+ willChange: 'transform, opacity',
121
+ force3D: true
122
+ }
123
+ )
124
+ }
125
+ })
126
+ el._rbsplitInstance = splitInstance
127
+ return () => {
128
+ ScrollTrigger.getAll().forEach((st) => {
129
+ if (st.trigger === el) st.kill()
130
+ })
131
+ try {
132
+ splitInstance.revert()
133
+ } catch (_) {}
134
+ el._rbsplitInstance = undefined
135
+ }
136
+ },
137
+ {
138
+ dependencies: [
139
+ text,
140
+ delay,
141
+ duration,
142
+ ease,
143
+ splitType,
144
+ JSON.stringify(from),
145
+ JSON.stringify(to),
146
+ threshold,
147
+ rootMargin,
148
+ fontsLoaded,
149
+ onLetterAnimationComplete
150
+ ],
151
+ scope: ref
152
+ }
153
+ )
154
+
155
+ const renderTag = () => {
156
+ const style: React.CSSProperties = {
157
+ textAlign,
158
+ overflow: 'hidden',
159
+ display: 'inline-block',
160
+ whiteSpace: 'normal',
161
+ wordWrap: 'break-word',
162
+ willChange: 'transform, opacity'
163
+ }
164
+ const classes = `split-parent ${className}`
165
+ switch (tag) {
166
+ case 'h1':
167
+ return (
168
+ <h1 ref={ref} style={style} className={classes}>
169
+ {text}
170
+ </h1>
171
+ )
172
+ case 'h2':
173
+ return (
174
+ <h2 ref={ref} style={style} className={classes}>
175
+ {text}
176
+ </h2>
177
+ )
178
+ case 'h3':
179
+ return (
180
+ <h3 ref={ref} style={style} className={classes}>
181
+ {text}
182
+ </h3>
183
+ )
184
+ case 'h4':
185
+ return (
186
+ <h4 ref={ref} style={style} className={classes}>
187
+ {text}
188
+ </h4>
189
+ )
190
+ case 'h5':
191
+ return (
192
+ <h5 ref={ref} style={style} className={classes}>
193
+ {text}
194
+ </h5>
195
+ )
196
+ case 'h6':
197
+ return (
198
+ <h6 ref={ref} style={style} className={classes}>
199
+ {text}
200
+ </h6>
201
+ )
202
+ default:
203
+ return (
204
+ <p ref={ref} style={style} className={classes}>
205
+ {text}
206
+ </p>
207
+ )
208
+ }
209
+ }
210
+ return renderTag()
211
+ }
@@ -0,0 +1,133 @@
1
+ // 'use client'
2
+ // import { cn } from '@/utilities/ui'
3
+ // import { motion, useInView } from 'framer-motion'
4
+ // import * as React from 'react'
5
+
6
+ // type TextStaggeredFadeProps = {
7
+ // text: string
8
+ // className?: string
9
+ // aniTextClass?: string
10
+ // }
11
+
12
+ // export const StaggeredFade: React.FC<TextStaggeredFadeProps> = ({
13
+ // text,
14
+ // className = '',
15
+ // aniTextClass = ''
16
+ // }) => {
17
+ // const variants = {
18
+ // hidden: { opacity: 0 },
19
+ // show: (i: number) => ({
20
+ // y: 0,
21
+ // opacity: 1,
22
+ // transition: { delay: i * 0.07 }
23
+ // })
24
+ // }
25
+
26
+ // const letters = text.split('')
27
+ // const ref = React.useRef(null)
28
+ // const isInView = useInView(ref, { once: false })
29
+
30
+ // return (
31
+ // <span className="relative inline-block">
32
+ // {/* Underlay: full text visible at 50% opacity so it's readable before animation */}
33
+ // <span
34
+ // aria-hidden
35
+ // className={cn(
36
+ // 'absolute inset-0 opacity-40 select-none pointer-events-none',
37
+ // className,
38
+ // aniTextClass
39
+ // )}
40
+ // >
41
+ // {text}
42
+ // </span>
43
+ // {/* Animated letters on top */}
44
+ // <motion.span
45
+ // ref={ref}
46
+ // initial="hidden"
47
+ // animate={isInView ? 'show' : ''}
48
+ // variants={variants}
49
+ // viewport={{ once: false }}
50
+ // className={cn('indie-stagger-fade', className, aniTextClass)}
51
+ // >
52
+ // {letters.map((word, i) => (
53
+ // <motion.span key={`${word}-${i}`} variants={variants} custom={i}>
54
+ // {word}
55
+ // </motion.span>
56
+ // ))}
57
+ // </motion.span>
58
+ // </span>
59
+ // )
60
+ // }
61
+
62
+ // Optimised version
63
+ 'use client'
64
+
65
+ import { cn } from '@/utilities/ui'
66
+ import { motion, useInView } from 'framer-motion'
67
+ import * as React from 'react'
68
+
69
+ type TextStaggeredFadeProps = {
70
+ text: string
71
+ className?: string
72
+ aniTextClass?: string
73
+ }
74
+
75
+ export const StaggeredFade: React.FC<TextStaggeredFadeProps> = ({
76
+ text,
77
+ className = '',
78
+ aniTextClass = ''
79
+ }) => {
80
+ const ref = React.useRef<HTMLSpanElement | null>(null)
81
+ const isInView = useInView(ref, {
82
+ once: true,
83
+ margin: '0px 0px -15% 0px'
84
+ })
85
+
86
+ const letters = React.useMemo(() => text.split(''), [text])
87
+
88
+ return (
89
+ <span className="relative inline-block">
90
+ <span
91
+ aria-hidden="true"
92
+ className={cn(
93
+ 'absolute inset-0 opacity-40 select-none pointer-events-none',
94
+ className,
95
+ aniTextClass
96
+ )}
97
+ >
98
+ {text}
99
+ </span>
100
+
101
+ <motion.span
102
+ ref={ref}
103
+ initial={false}
104
+ animate={isInView ? 'show' : 'hidden'}
105
+ className={cn('indie-stagger-fade', className, aniTextClass)}
106
+ >
107
+ {letters.map((letter, i) => (
108
+ <motion.span
109
+ key={`${letter}-${i}`}
110
+ custom={i}
111
+ variants={{
112
+ hidden: {
113
+ opacity: 0,
114
+ y: 8
115
+ },
116
+ show: (index: number) => ({
117
+ opacity: 1,
118
+ y: 0,
119
+ transition: {
120
+ delay: index * 0.025,
121
+ duration: 0.35,
122
+ ease: [0.22, 1, 0.36, 1]
123
+ }
124
+ })
125
+ }}
126
+ >
127
+ {letter}
128
+ </motion.span>
129
+ ))}
130
+ </motion.span>
131
+ </span>
132
+ )
133
+ }
@@ -0,0 +1,111 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useRef, useState } from 'react'
4
+ import {
5
+ motion,
6
+ useAnimationFrame,
7
+ useMotionValue,
8
+ useScroll,
9
+ useSpring,
10
+ useTransform,
11
+ useVelocity,
12
+ } from 'framer-motion'
13
+
14
+ import { cn } from '@/utilities/ui'
15
+
16
+ interface TextScrollProps {
17
+ text: string
18
+ default_velocity?: number
19
+ className?: string
20
+ }
21
+
22
+ interface ParallaxProps {
23
+ children: string
24
+ baseVelocity: number
25
+ className?: string
26
+ }
27
+
28
+ export const wrap = (min: number, max: number, v: number) => {
29
+ const rangeSize = max - min
30
+ return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min
31
+ }
32
+
33
+ export const TextScroll: React.FC<TextScrollProps> = ({
34
+ text,
35
+ default_velocity = 5,
36
+ className,
37
+ }) => {
38
+ const ParallaxText: React.FC<ParallaxProps> = ({ children, baseVelocity = 100, className }) => {
39
+ const baseX = useMotionValue(0)
40
+ const { scrollY } = useScroll()
41
+ const scrollVelocity = useVelocity(scrollY)
42
+ const smoothVelocity = useSpring(scrollVelocity, {
43
+ damping: 50,
44
+ stiffness: 400,
45
+ })
46
+
47
+ const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {
48
+ clamp: false,
49
+ })
50
+
51
+ const [repetitions, setRepetitions] = useState(1)
52
+ const containerRef = useRef<HTMLDivElement>(null)
53
+ const textRef = useRef<HTMLSpanElement>(null)
54
+
55
+ useEffect(() => {
56
+ const calculateRepetitions = () => {
57
+ if (containerRef.current && textRef.current) {
58
+ const containerWidth = containerRef.current.offsetWidth
59
+ const textWidth = textRef.current.offsetWidth
60
+ const newRepetitions = Math.ceil(containerWidth / textWidth) + 2
61
+ setRepetitions(newRepetitions)
62
+ }
63
+ }
64
+
65
+ calculateRepetitions()
66
+
67
+ window.addEventListener('resize', calculateRepetitions)
68
+ return () => window.removeEventListener('resize', calculateRepetitions)
69
+ }, [children])
70
+
71
+ const x = useTransform(baseX, (v) => `${wrap(-100 / repetitions, 0, v)}%`)
72
+
73
+ const directionFactor = useRef<number>(1)
74
+ useAnimationFrame((t, delta) => {
75
+ let moveBy = directionFactor.current * baseVelocity * (delta / 1000)
76
+
77
+ if (velocityFactor.get() < 0) {
78
+ directionFactor.current = -1
79
+ } else if (velocityFactor.get() > 0) {
80
+ directionFactor.current = 1
81
+ }
82
+
83
+ moveBy += directionFactor.current * moveBy * velocityFactor.get()
84
+
85
+ baseX.set(baseX.get() + moveBy)
86
+ })
87
+
88
+ return (
89
+ <div className="w-full overflow-hidden whitespace-nowrap" ref={containerRef}>
90
+ <motion.div className={cn('inline-block', className)} style={{ x }}>
91
+ {Array.from({ length: repetitions }).map((_, i) => (
92
+ <span key={i} ref={i === 0 ? textRef : null}>
93
+ {children}{' '}
94
+ </span>
95
+ ))}
96
+ </motion.div>
97
+ </div>
98
+ )
99
+ }
100
+
101
+ return (
102
+ <section className="relative w-full">
103
+ <ParallaxText baseVelocity={default_velocity} className={className}>
104
+ {text}
105
+ </ParallaxText>
106
+ <ParallaxText baseVelocity={-default_velocity} className={className}>
107
+ {text}
108
+ </ParallaxText>
109
+ </section>
110
+ )
111
+ }
@@ -0,0 +1,112 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { motion, useInView } from 'framer-motion'
5
+ import { cn } from '@/utilities/ui'
6
+
7
+ export function TypingEffect({
8
+ text = 'Typing Effect',
9
+ className = '',
10
+ aniTextClass = '',
11
+ charDelayMs = 200
12
+ }: {
13
+ text: string
14
+ className?: string
15
+ aniTextClass?: string
16
+ charDelayMs?: number
17
+ }) {
18
+ const ref = React.useRef(null)
19
+ const isInView = useInView(ref, { once: true })
20
+
21
+ const [visibleChars, setVisibleChars] = React.useState(0)
22
+
23
+ const chars = React.useMemo(() => Array.from(String(text)), [text])
24
+
25
+ const prefersReducedMotion = React.useMemo(() => {
26
+ if (typeof window === 'undefined') return false
27
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches
28
+ }, [])
29
+
30
+ React.useEffect(() => {
31
+ if (!isInView) return
32
+
33
+ if (prefersReducedMotion) {
34
+ setVisibleChars(chars.length)
35
+ return
36
+ }
37
+
38
+ setVisibleChars(0)
39
+
40
+ const delay = typeof charDelayMs === 'number' && charDelayMs > 0 ? charDelayMs : 200
41
+ const id = window.setInterval(() => {
42
+ setVisibleChars((prev) => {
43
+ if (prev >= chars.length) {
44
+ window.clearInterval(id)
45
+ return prev
46
+ }
47
+ return prev + 1
48
+ })
49
+ }, delay)
50
+
51
+ return () => window.clearInterval(id)
52
+ }, [isInView, prefersReducedMotion, chars.length, charDelayMs])
53
+
54
+ return (
55
+ <>
56
+ <span
57
+ ref={ref}
58
+ className={cn('tracking-tighter', className, aniTextClass)}
59
+ // className="text-xl text-center sm:text-4xl font-bold tracking-tighter md:text-6xl md:leading-[4rem]"
60
+ >
61
+ {chars.slice(0, visibleChars).map((ch, index) => {
62
+ // Keep word-wrap behavior by not forcing inline-block per character.
63
+ // Also render spaces as-is so wrapping occurs at spaces.
64
+ const shouldAnimate = !prefersReducedMotion
65
+
66
+ return (
67
+ <motion.span
68
+ key={`typed-${index}`}
69
+ className={ch === ' ' ? undefined : 'continuous-typing-effect'}
70
+ initial={shouldAnimate ? { opacity: 0 } : undefined}
71
+ animate={shouldAnimate ? { opacity: 1 } : undefined}
72
+ transition={shouldAnimate ? { duration: 0.12 } : undefined}
73
+ >
74
+ {ch}
75
+ </motion.span>
76
+ )
77
+ })}
78
+
79
+ <span aria-hidden className="typing-effect-cursor">
80
+ ▍
81
+ </span>
82
+ </span>
83
+
84
+ <style jsx global>{`
85
+ .typing-effect-cursor {
86
+ display: inline-block;
87
+ margin-left: 0.08em;
88
+ transform: translateY(0.08em);
89
+ animation: typing-effect-blink 0.9s steps(2, start) infinite;
90
+ }
91
+
92
+ @keyframes typing-effect-blink {
93
+ 0%,
94
+ 49% {
95
+ opacity: 1;
96
+ }
97
+ 50%,
98
+ 100% {
99
+ opacity: 0;
100
+ }
101
+ }
102
+
103
+ @media (prefers-reduced-motion: reduce) {
104
+ .typing-effect-cursor {
105
+ animation: none;
106
+ opacity: 1;
107
+ }
108
+ }
109
+ `}</style>
110
+ </>
111
+ )
112
+ }