blocks-dusted 0.1.11 → 0.1.13

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 (161) hide show
  1. package/package.json +5 -2
  2. package/src/cli.js +39 -3
  3. package/src/commands/shop.js +59 -0
  4. package/src/commands/warehouse.js +73 -0
  5. package/src/installers/patchRenderBlocks.js +1 -1
  6. package/src/registry/validateTemplateManifest.js +2 -1
  7. package/templates/blocks/BannerDD790432/Component.tsx +63 -0
  8. package/templates/blocks/BannerDD790432/config.ts +54 -0
  9. package/templates/blocks/BannerDD790432/manifest.json +80 -0
  10. package/templates/blocks/Button47/Component.tsx +124 -0
  11. package/templates/blocks/Button47/config.ts +75 -0
  12. package/templates/blocks/Button47/link.ts +22 -0
  13. package/templates/blocks/Button47/manifest.json +105 -0
  14. package/templates/blocks/Button47/styles.module.scss +75 -0
  15. package/templates/blocks/DD-Accordion/Component.tsx +55 -36
  16. package/templates/blocks/DD-Accordion/config.ts +71 -59
  17. package/templates/blocks/DD-AnimText/Component.tsx +50 -32
  18. package/templates/blocks/DD-AnimText/config.ts +296 -295
  19. package/templates/blocks/DD-AsideNav/Component.tsx +323 -319
  20. package/templates/blocks/DD-Banner/Component.tsx +54 -51
  21. package/templates/blocks/DD-BookCall/Component.tsx +10 -9
  22. package/templates/blocks/DD-ButtonPop/Component.tsx +118 -117
  23. package/templates/blocks/DD-Card/Component.tsx +4 -4
  24. package/templates/blocks/DD-CardTemplate01/Component.tsx +5 -5
  25. package/templates/blocks/DD-CardsWithVariantV3/Component.tsx +472 -0
  26. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/index.tsx +203 -0
  27. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/styles.ts +87 -0
  28. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/useInjectStyle.ts +39 -0
  29. package/templates/blocks/DD-CardsWithVariantV3/config.ts +326 -0
  30. package/templates/blocks/DD-CardsWithVariantV3/manifest.json +110 -0
  31. package/templates/blocks/DD-Carousel-A/Component.tsx +251 -249
  32. package/templates/blocks/DD-Carousel-B/Component.tsx +405 -403
  33. package/templates/blocks/DD-Chip/Component.tsx +14 -14
  34. package/templates/blocks/DD-ComparisonTable/Component.tsx +255 -256
  35. package/templates/blocks/DD-Contact/Component.tsx +433 -434
  36. package/templates/blocks/DD-Counter/Component.tsx +18 -13
  37. package/templates/blocks/DD-DeliCard/Component.tsx +303 -0
  38. package/templates/blocks/DD-DeliCard/config.ts +186 -0
  39. package/templates/blocks/DD-DeliCard/manifest.json +94 -0
  40. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  41. package/templates/blocks/DD-FeatProd/CircularGallery.tsx +1179 -0
  42. package/templates/blocks/DD-FeatProd/Component.tsx +484 -0
  43. package/templates/blocks/DD-FeatProd/config.ts +173 -0
  44. package/templates/blocks/DD-FeatProd/manifest.json +93 -0
  45. package/templates/blocks/DD-FeatServ/Component.tsx +607 -0
  46. package/templates/blocks/DD-FeatServ/config.ts +213 -0
  47. package/templates/blocks/DD-FeatServ/manifest.json +113 -0
  48. package/templates/blocks/DD-FeatStrip/Component.tsx +584 -585
  49. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +627 -628
  50. package/templates/blocks/DD-FluidBtn/Component.tsx +46 -43
  51. package/templates/blocks/DD-GooeyInfo/Component.tsx +150 -149
  52. package/templates/blocks/DD-GooeyInfo/config.ts +136 -135
  53. package/templates/blocks/DD-Hero/Component.tsx +16 -40
  54. package/templates/blocks/DD-HeroPlas/Component.tsx +50 -0
  55. package/templates/blocks/DD-HeroPlas/ThreeScene.tsx +109 -0
  56. package/templates/blocks/DD-HeroPlas/config.ts +33 -0
  57. package/templates/blocks/DD-HeroPlas/manifest.json +88 -0
  58. package/templates/blocks/DD-HorizontalScroll/Component.tsx +4 -5
  59. package/templates/blocks/DD-Icon/Component.tsx +46 -81
  60. package/templates/blocks/DD-IconButton/Component.tsx +13 -20
  61. package/templates/blocks/DD-IdTag/Component.tsx +22 -21
  62. package/templates/blocks/DD-IframeMedia/Component.tsx +14 -10
  63. package/templates/blocks/DD-LineAnim/Component.tsx +42 -36
  64. package/templates/blocks/DD-LogoMarq/Component.tsx +38 -48
  65. package/templates/blocks/DD-Lottie/Component.tsx +11 -3
  66. package/templates/blocks/DD-MasonaryMedia/Component.tsx +544 -547
  67. package/templates/blocks/DD-MasonaryMedia/config.ts +389 -389
  68. package/templates/blocks/DD-Masonry/Component.tsx +654 -644
  69. package/templates/blocks/DD-Masonry/config.ts +475 -475
  70. package/templates/blocks/DD-MaterialSwatches/Component.tsx +85 -0
  71. package/templates/blocks/DD-MaterialSwatches/config.ts +232 -0
  72. package/templates/blocks/DD-MaterialSwatches/manifest.json +84 -0
  73. package/templates/blocks/DD-MaterialSwatches/material.ts +107 -0
  74. package/templates/blocks/DD-NineCanvas/Component.tsx +129 -0
  75. package/templates/blocks/DD-NineCanvas/RenderBlocks.tsx +244 -0
  76. package/templates/blocks/DD-NineCanvas/allowedCanvasBlocks.ts +6 -0
  77. package/templates/blocks/DD-NineCanvas/blockComponents.tsx +8 -0
  78. package/templates/blocks/DD-NineCanvas/canvas/CanvasGrid.tsx +316 -0
  79. package/templates/blocks/DD-NineCanvas/canvas/RadialNav.tsx +432 -0
  80. package/templates/blocks/DD-NineCanvas/canvas/canvas-panels.css +889 -0
  81. package/templates/blocks/DD-NineCanvas/canvas/icons/custom-icons.tsx +364 -0
  82. package/templates/blocks/DD-NineCanvas/config.ts +61 -0
  83. package/templates/blocks/DD-NineCanvas/manifest.json +165 -0
  84. package/templates/blocks/DD-NineCanvas/styles.scss +152 -0
  85. package/templates/blocks/DD-NineCanvas/tooltip/get-strict-context.tsx +26 -0
  86. package/templates/blocks/DD-NineCanvas/tooltip/primitives.tsx +178 -0
  87. package/templates/blocks/DD-NineCanvas/tooltip/tooltip.tsx +71 -0
  88. package/templates/blocks/DD-NineCanvas/tooltip/use-controlled-state.tsx +33 -0
  89. package/templates/blocks/DD-NineCanvas/utilities/FadeOnScroll.tsx +68 -0
  90. package/templates/blocks/DD-NineCanvas/utilities/ParallaxWrapper.tsx +157 -0
  91. package/templates/blocks/DD-NineCanvas/utilities/renderCustomCSS.ts +5 -0
  92. package/templates/blocks/DD-NineCanvas/utilities/webglCleanup.ts +27 -0
  93. package/templates/blocks/DD-PayloadAIAssistant/Component.tsx +78 -0
  94. package/templates/blocks/DD-PayloadAIAssistant/DustedBot.tsx +590 -0
  95. package/templates/blocks/DD-PayloadAIAssistant/config.ts +37 -0
  96. package/templates/blocks/DD-PayloadAIAssistant/demo.css +125 -0
  97. package/templates/blocks/DD-PayloadAIAssistant/manifest.json +93 -0
  98. package/templates/blocks/DD-PayloadAIAssistant/source-defaults.ts +17 -0
  99. package/templates/blocks/DD-PayloadAIAssistant/styles.ts +306 -0
  100. package/templates/blocks/DD-Pricing/Component.tsx +368 -372
  101. package/templates/blocks/DD-Pricing/config.ts +215 -215
  102. package/templates/blocks/DD-Process/Component.tsx +147 -149
  103. package/templates/blocks/DD-Progress/Component.tsx +156 -141
  104. package/templates/blocks/DD-ProjHeader/Component.tsx +93 -91
  105. package/templates/blocks/DD-ProjSlider/Component.tsx +1 -1
  106. package/templates/blocks/DD-ProjSlider/config.ts +2 -2
  107. package/templates/blocks/DD-Section/Component.tsx +265 -266
  108. package/templates/blocks/DD-Separator/Component.tsx +66 -66
  109. package/templates/blocks/DD-Services/Component.tsx +176 -176
  110. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +306 -307
  111. package/templates/blocks/DD-Slider-A/Component.tsx +237 -237
  112. package/templates/blocks/DD-StackCards/Component.tsx +474 -473
  113. package/templates/blocks/DD-Team/Component.tsx +247 -247
  114. package/templates/blocks/DD-TeamCards/Component.tsx +251 -251
  115. package/templates/blocks/DD-TechStack/Component.tsx +161 -168
  116. package/templates/blocks/DD-TestMarq/Component.tsx +158 -132
  117. package/templates/blocks/DD-Testim/Component.tsx +247 -247
  118. package/templates/blocks/DD-Testim2/Component.tsx +265 -256
  119. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  120. package/templates/blocks/DD-TextMarq/Component.tsx +157 -157
  121. package/templates/blocks/DD-Thanks/Component.tsx +501 -500
  122. package/templates/blocks/DD-Work/Component.tsx +315 -315
  123. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  124. package/templates/blocks/DDHG-CTASection2/Component.tsx +183 -184
  125. package/templates/blocks/DDHG-HighlightArc/Component.tsx +246 -243
  126. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +180 -93
  127. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -66
  128. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +225 -213
  129. package/templates/blocks/DDHG-ProcessSec/Component.tsx +38 -39
  130. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +11 -11
  131. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +30 -47
  132. package/templates/blocks/DDHG-ServiceHero/Component.tsx +10 -10
  133. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +23 -23
  134. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +40 -40
  135. package/templates/blocks/DDHG-TeamCards/Component.tsx +140 -131
  136. package/templates/blocks/Form/Checkbox/index.tsx +45 -0
  137. package/templates/blocks/Form/Component.tsx +163 -0
  138. package/templates/blocks/Form/Country/index.tsx +65 -0
  139. package/templates/blocks/Form/Country/options.ts +982 -0
  140. package/templates/blocks/Form/Email/index.tsx +38 -0
  141. package/templates/blocks/Form/Error/index.tsx +15 -0
  142. package/templates/blocks/Form/Message/index.tsx +13 -0
  143. package/templates/blocks/Form/Number/index.tsx +36 -0
  144. package/templates/blocks/Form/Select/index.tsx +63 -0
  145. package/templates/blocks/Form/State/index.tsx +64 -0
  146. package/templates/blocks/Form/State/options.ts +52 -0
  147. package/templates/blocks/Form/Text/index.tsx +32 -0
  148. package/templates/blocks/Form/Textarea/index.tsx +40 -0
  149. package/templates/blocks/Form/Width/index.tsx +13 -0
  150. package/templates/blocks/Form/config.ts +51 -0
  151. package/templates/blocks/Form/fields.tsx +21 -0
  152. package/templates/blocks/Form/manifest.json +168 -0
  153. package/templates/blocks/MediaBlock/Component.tsx +67 -0
  154. package/templates/blocks/MediaBlock/config.ts +14 -0
  155. package/templates/blocks/MediaBlock/manifest.json +92 -0
  156. package/templates/blocks/TransitionsDustedShowcase/Component.tsx +9 -0
  157. package/templates/blocks/TransitionsDustedShowcase/config.ts +13 -0
  158. package/templates/blocks/TransitionsDustedShowcase/manifest.json +80 -0
  159. package/templates/blocks/rawHtml/Component.tsx +25 -0
  160. package/templates/blocks/rawHtml/config.ts +56 -0
  161. package/templates/blocks/rawHtml/manifest.json +80 -0
@@ -0,0 +1,432 @@
1
+ /* eslint-disable react-hooks/set-state-in-effect */
2
+ /* eslint-disable @next/next/no-html-link-for-pages */
3
+ 'use client'
4
+
5
+ import * as React from 'react'
6
+ import { createPortal } from 'react-dom'
7
+ import { motion } from 'framer-motion'
8
+ import Link from 'next/link'
9
+ import { Tooltip, TooltipTrigger, TooltipPanel } from '../tooltip/tooltip'
10
+ import { TopLogoBgElement, BottomLogoBgElement } from './icons/custom-icons'
11
+ import { ArrowLeft, Circle } from 'lucide-react'
12
+
13
+ export type RadialNavItem = {
14
+ id: number
15
+ icon: React.ComponentType<{ size?: number; className?: string }>
16
+ label: string
17
+ angle: number
18
+ canvasId: string
19
+ }
20
+
21
+ type RadialNavProps = {
22
+ items: RadialNavItem[]
23
+ activeCanvasId: string
24
+ onCanvasChange: (canvasId: string) => void
25
+ }
26
+
27
+ type RadialNavInnerProps = RadialNavProps & {
28
+ isOpen: boolean
29
+ setIsOpen: React.Dispatch<React.SetStateAction<boolean>>
30
+ }
31
+
32
+ let mountedRadialNavCount = 0
33
+
34
+ function getPolarCoordinates(angleDeg: number, radius: number) {
35
+ const rad = ((angleDeg - 90) * Math.PI) / 180
36
+
37
+ return {
38
+ x: radius * Math.cos(rad),
39
+ y: radius * Math.sin(rad),
40
+ }
41
+ }
42
+
43
+ function useIsTouchMode() {
44
+ const [isTouchMode, setIsTouchMode] = React.useState(false)
45
+
46
+ React.useEffect(() => {
47
+ const checkTouchMode = () => {
48
+ setIsTouchMode(
49
+ window.matchMedia('(hover: none), (pointer: coarse)').matches ||
50
+ navigator.maxTouchPoints > 0,
51
+ )
52
+ }
53
+
54
+ checkTouchMode()
55
+
56
+ window.addEventListener('resize', checkTouchMode)
57
+
58
+ return () => {
59
+ window.removeEventListener('resize', checkTouchMode)
60
+ }
61
+ }, [])
62
+
63
+ return isTouchMode
64
+ }
65
+
66
+ function MorphCenterIcon() {
67
+ return <Circle aria-hidden="true" size={24} />
68
+ }
69
+
70
+ function RadialNavInner({
71
+ items,
72
+ activeCanvasId,
73
+ onCanvasChange,
74
+ isOpen,
75
+ setIsOpen,
76
+ }: RadialNavInnerProps) {
77
+ const size = 200
78
+ const orbitRadius = size / 2 - 2
79
+ const activeItem = items.find((item) => item.canvasId === activeCanvasId)
80
+ const rotateAngle = activeItem?.angle ?? 0
81
+
82
+ const closeTimerRef = React.useRef<number | null>(null)
83
+ const suppressOpenUntilRef = React.useRef(0)
84
+ const isTouchMode = useIsTouchMode()
85
+
86
+ const openRadialNav = () => {
87
+ if (Date.now() < suppressOpenUntilRef.current) return
88
+
89
+ if (closeTimerRef.current) {
90
+ window.clearTimeout(closeTimerRef.current)
91
+ closeTimerRef.current = null
92
+ }
93
+
94
+ setIsOpen(true)
95
+ }
96
+
97
+ const closeRadialNav = () => {
98
+ if (closeTimerRef.current) {
99
+ window.clearTimeout(closeTimerRef.current)
100
+ }
101
+
102
+ closeTimerRef.current = window.setTimeout(() => {
103
+ setIsOpen(false)
104
+ closeTimerRef.current = null
105
+ }, 500)
106
+ }
107
+
108
+ const handleCenterClick = () => {
109
+ if (isTouchMode) {
110
+ if (!isOpen) {
111
+ openRadialNav()
112
+ return
113
+ }
114
+
115
+ onCanvasChange('canvas_05')
116
+ setIsOpen(false)
117
+ return
118
+ }
119
+
120
+ onCanvasChange('canvas_05')
121
+ }
122
+
123
+ React.useEffect(() => {
124
+ return () => {
125
+ if (closeTimerRef.current) {
126
+ window.clearTimeout(closeTimerRef.current)
127
+ }
128
+ }
129
+ }, [])
130
+
131
+ return (
132
+ <>
133
+ <motion.div
134
+ animate={{
135
+ scale: isOpen ? 0.775 : 0.65,
136
+ y: isOpen ? '-1.5rem' : '0rem',
137
+ filter: isOpen ? 'brightness(0.8)' : 'brightness(1)',
138
+ borderWidth: isOpen ? '0px' : '2px',
139
+ borderColor: isOpen ? '#ffffff00' : '#808080',
140
+ borderStyle: 'solid',
141
+ }}
142
+ className={`hzRadialRoot hzRadialRoot--portal origin-center ${isOpen ? 'hzRadialNavIsOpen' : ''}`}
143
+ onBlur={(event) => {
144
+ if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {
145
+ closeRadialNav()
146
+ }
147
+ }}
148
+ onFocus={() => {
149
+ if (!isTouchMode) {
150
+ openRadialNav()
151
+ }
152
+ }}
153
+ onMouseEnter={() => {
154
+ if (!isTouchMode) {
155
+ openRadialNav()
156
+ }
157
+ }}
158
+ onMouseLeave={() => {
159
+ if (!isTouchMode) {
160
+ closeRadialNav()
161
+ }
162
+ }}
163
+ tabIndex={0}
164
+ transition={{ type: 'spring', stiffness: 220, damping: 28 }}
165
+ >
166
+ <div className="radialNav-notification fixed left-1/2 top-1/2 mt-32 z-50 h-fit w-[min(50rem,calc(100vw-2rem))] -translate-x-1/2 translate-y-1/2 origin-center p-4 md:p-6 flex flex-col items-center justify-center rounded-2xl squircle shadow-3xl bg-7 text-md text-stone-200 border border-border">
167
+ <h4 className="tracking-wider font-semibold">NineCanvas layout demo</h4>
168
+ <p className="tracking-wider !text-[1.125rem]">
169
+ Explore all nine panels using the navigation or swipe between adjacent panels. Open the{' '}
170
+ <a
171
+ href="/backend-preview/ninecanvasblock"
172
+ className="text-underline !hover:text-accent font-semibold"
173
+ style={{ textDecoration: 'underline', textUnderlineOffset: '2px' }}
174
+ >
175
+ static configuration preview{' '}
176
+ </a>
177
+ to inspect the layout fields.
178
+ </p>
179
+ <Link
180
+ href="/nine-canvas"
181
+ aria-hidden={!isOpen}
182
+ aria-label="Return to main canvas"
183
+ className="relative w-fit flex gap-2 mt-8 items-center text-lime-500 scale-120 hover:gap-4 duration-300 hover:duration-300 hover:brightness-110"
184
+ onClick={() => {
185
+ onCanvasChange('canvas_05')
186
+ setIsOpen(false)
187
+ }}
188
+ onFocus={() => openRadialNav()}
189
+ onMouseEnter={() => {
190
+ if (!isTouchMode) {
191
+ openRadialNav()
192
+ }
193
+ }}
194
+ tabIndex={isOpen ? 0 : -1}
195
+ >
196
+ <ArrowLeft aria-hidden="true" size={18} strokeWidth={2.25} />
197
+ <span className="text-md font-semibold">Restart demo</span>
198
+ </Link>
199
+ </div>
200
+ <motion.div
201
+ animate={{
202
+ opacity: isOpen ? 0.8 : 0,
203
+ scale: isOpen ? 1.5 : 0.75,
204
+ }}
205
+ className="hzRadialBackdrop"
206
+ transition={{ type: 'spring', stiffness: 220, damping: 26 }}
207
+ />
208
+
209
+ {items.map((item) => {
210
+ const Icon = item.icon
211
+ const { x, y } = getPolarCoordinates(item.angle, orbitRadius)
212
+ const isActive = activeCanvasId === item.canvasId
213
+ const shouldShowActive = isActive || isOpen
214
+ const activeClosedOffsetY = 62
215
+ const activeClosedScale = 1.5
216
+
217
+ return (
218
+ <Tooltip key={item.id}>
219
+ <TooltipTrigger
220
+ render={
221
+ <motion.button
222
+ animate={{
223
+ left: `calc(50% + ${isOpen ? x : 0}px)`,
224
+ top: `calc(50% + ${isOpen ? y : isActive ? activeClosedOffsetY : 0}px)`,
225
+ opacity: shouldShowActive ? 1 : 0,
226
+ scale: isOpen ? 1 : isActive ? activeClosedScale : 0,
227
+ width: 42,
228
+ }}
229
+ aria-label={item.label}
230
+ className={[
231
+ 'hzRadialItem group',
232
+ `hzRadialItem--${item.canvasId}`,
233
+ `hzRadialItem--id-${item.id}`,
234
+ isActive ? 'hzRadialItem--active' : '',
235
+ !isOpen && !isActive ? 'hzRadialItem--closed' : '',
236
+ ]
237
+ .filter(Boolean)
238
+ .join(' ')}
239
+ key={item.id}
240
+ onClick={(event) => {
241
+ event.currentTarget.blur()
242
+ onCanvasChange(item.canvasId)
243
+ suppressOpenUntilRef.current = Date.now() + 700
244
+ setIsOpen(false)
245
+ }}
246
+ transition={{ type: 'spring', stiffness: 220, damping: 28 }}
247
+ type="button"
248
+ >
249
+ <Icon size={16} />
250
+ </motion.button>
251
+ }
252
+ />
253
+
254
+ <TooltipPanel className="hzTooltipPanel">
255
+ <p>{item.label}</p>
256
+ </TooltipPanel>
257
+ </Tooltip>
258
+ )
259
+ })}
260
+
261
+ <Tooltip>
262
+ <TooltipTrigger
263
+ render={
264
+ <button
265
+ aria-expanded={isOpen}
266
+ aria-label={isOpen ? 'Go to Canvas 5' : 'Open Canvas navigation'}
267
+ className={`hzRadialCenterButton ${
268
+ activeCanvasId === 'canvas_05' ? 'hzRadialCenterButton--active' : ''
269
+ }`}
270
+ onClick={handleCenterClick}
271
+ type="button"
272
+ >
273
+ <motion.div
274
+ animate={{ rotate: isOpen ? rotateAngle : 0 }}
275
+ className="hzRadialCenterButtonIcon"
276
+ transition={{ type: 'spring', stiffness: 220, damping: 26 }}
277
+ >
278
+ <MorphCenterIcon />
279
+ </motion.div>
280
+ </button>
281
+ }
282
+ />
283
+
284
+ <TooltipPanel className="hzTooltipPanel">
285
+ <p>Canvas 5</p>
286
+ </TooltipPanel>
287
+ </Tooltip>
288
+
289
+ {/* <motion.div
290
+ animate={{
291
+ opacity: isOpen ? 1 : 0,
292
+ scale: isOpen ? 1 : 0.7,
293
+ y: isOpen ? 0 : -8,
294
+ x: isOpen ? 0 : -32
295
+ }}
296
+ transition={{ type: 'spring', stiffness: 260, damping: 24 }}
297
+ >
298
+ <Link
299
+ href="/nine-canvas"
300
+ aria-hidden={!isOpen}
301
+ aria-label="Return to main canvas"
302
+ className="hzRadialReturnButton hidden md:flex"
303
+ onClick={() => {
304
+ onCanvasChange('canvas_05')
305
+ setIsOpen(false)
306
+ }}
307
+ onFocus={() => openRadialNav()}
308
+ onMouseEnter={() => {
309
+ if (!isTouchMode) {
310
+ openRadialNav()
311
+ }
312
+ }}
313
+ tabIndex={isOpen ? 0 : -1}
314
+ >
315
+ <ArrowLeft aria-hidden="true" size={18} strokeWidth={2.25} />
316
+ <span className="text-xs text-stone-200">Exit Overview-Mode</span>
317
+ </Link>
318
+ </motion.div> */}
319
+ </motion.div>
320
+ </>
321
+ )
322
+ }
323
+
324
+ export function RadialNav(props: RadialNavProps) {
325
+ const [mounted, setMounted] = React.useState(false)
326
+ const [isOpen, setIsOpen] = React.useState(false)
327
+
328
+ const lastScrollYRef = React.useRef(0)
329
+
330
+ React.useEffect(() => {
331
+ setMounted(true)
332
+ lastScrollYRef.current = window.scrollY
333
+
334
+ mountedRadialNavCount += 1
335
+ document.body.classList.add('hasRadialNav')
336
+
337
+ return () => {
338
+ mountedRadialNavCount = Math.max(0, mountedRadialNavCount - 1)
339
+
340
+ if (mountedRadialNavCount === 0) {
341
+ document.body.classList.remove('hasRadialNav')
342
+ document.body.classList.remove('hasRadialNavOpen')
343
+ }
344
+ }
345
+ }, [])
346
+
347
+ React.useEffect(() => {
348
+ if (!mounted) return
349
+
350
+ const desktopMedia = window.matchMedia('(min-width: 768px)')
351
+
352
+ const handleVerticalMotion = (deltaY: number) => {
353
+ if (!desktopMedia.matches) return
354
+
355
+ if (deltaY > 8) {
356
+ setIsOpen(true)
357
+ } else if (deltaY < -8) {
358
+ setIsOpen(false)
359
+ }
360
+ }
361
+
362
+ const handleScroll = () => {
363
+ const scrollY = window.scrollY
364
+ const deltaY = scrollY - lastScrollYRef.current
365
+
366
+ handleVerticalMotion(deltaY)
367
+
368
+ lastScrollYRef.current = Math.max(0, scrollY)
369
+ }
370
+
371
+ const handleWheel = (event: WheelEvent) => {
372
+ handleVerticalMotion(event.deltaY)
373
+ }
374
+
375
+ const handleCanvasScrollDown = () => {
376
+ if (!desktopMedia.matches) return
377
+
378
+ setIsOpen(true)
379
+ }
380
+
381
+ const handleBreakpointChange = () => {
382
+ lastScrollYRef.current = window.scrollY
383
+ }
384
+
385
+ window.addEventListener('scroll', handleScroll, { passive: true })
386
+
387
+ window.addEventListener('hz:canvas-scroll-down', handleCanvasScrollDown)
388
+
389
+ document.addEventListener('wheel', handleWheel, {
390
+ capture: true,
391
+ passive: true,
392
+ })
393
+
394
+ desktopMedia.addEventListener('change', handleBreakpointChange)
395
+
396
+ return () => {
397
+ window.removeEventListener('scroll', handleScroll)
398
+
399
+ window.removeEventListener('hz:canvas-scroll-down', handleCanvasScrollDown)
400
+
401
+ document.removeEventListener('wheel', handleWheel, {
402
+ capture: true,
403
+ })
404
+
405
+ desktopMedia.removeEventListener('change', handleBreakpointChange)
406
+ }
407
+ }, [mounted])
408
+
409
+ React.useEffect(() => {
410
+ if (isOpen) {
411
+ document.body.classList.add('hasRadialNavOpen')
412
+ } else {
413
+ document.body.classList.remove('hasRadialNavOpen')
414
+ }
415
+
416
+ return () => {
417
+ document.body.classList.remove('hasRadialNavOpen')
418
+ }
419
+ }, [isOpen])
420
+
421
+ if (!mounted) return null
422
+
423
+ return createPortal(
424
+ <>
425
+ <TopLogoBgElement />
426
+
427
+ <RadialNavInner {...props} isOpen={isOpen} setIsOpen={setIsOpen} />
428
+ <BottomLogoBgElement />
429
+ </>,
430
+ document.body,
431
+ )
432
+ }