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
@@ -1,213 +1,225 @@
1
- 'use client'
2
-
3
- import Image from 'next/image'
4
- import Link from 'next/link'
5
- import * as LucideIcons from 'lucide-react'
6
- import React from 'react'
7
-
8
- import { getMediaUrl } from '@/utilities/getMediaUrl'
9
- import { cn } from '@/utilities/ui'
10
-
11
- type PortableDoc = {
12
- slug?: string | null
13
- breadcrumbs?: Array<{ url?: string | null }> | null
14
- [key: string]: unknown
15
- }
16
-
17
- type Media = {
18
- url?: string | null
19
- alt?: string | null
20
- [key: string]: unknown
21
- }
22
-
23
- type LinkReference =
24
- | { relationTo: 'pages'; value: number | PortableDoc }
25
- | { relationTo: 'posts'; value: number | PortableDoc }
26
- | { relationTo: 'projects'; value: number | PortableDoc }
27
- | { relationTo: 'thoughts'; value: number | PortableDoc }
28
-
29
- type NavCodeGridLink = {
30
- type?: 'reference' | 'custom' | null
31
- reference?: LinkReference | null
32
- url?: string | null
33
- label?: string | null
34
- newTab?: boolean | null
35
- icon?: string | null
36
- iconPosition?: 'before' | 'after' | null
37
- customIcon?: number | Media | null
38
- } | null
39
-
40
- export type DDHGNavCodeGridItem = {
41
- id?: string | null
42
- code?: string | null
43
- link?: NavCodeGridLink
44
- }
45
-
46
- export type DDHGNavCodeGridProps = {
47
- items?: DDHGNavCodeGridItem[] | null
48
- defaultHref?: string | null
49
- containerClassName?: string | null
50
- gridClassName?: string | null
51
- cellClassName?: string | null
52
- showIcons?: boolean | null
53
- }
54
-
55
- const getPageURLFromDoc = (doc: PortableDoc | number): string | null => {
56
- if (typeof doc === 'number') return null
57
- const crumbs = Array.isArray(doc?.breadcrumbs) ? doc.breadcrumbs : []
58
- if (crumbs.length) {
59
- const last = crumbs[crumbs.length - 1]
60
- if (typeof last?.url === 'string' && last.url) return last.url
61
- }
62
- const slug = doc?.slug
63
- if (!slug || slug === 'home') return '/'
64
- return slug.startsWith('/') ? slug : `/${slug}`
65
- }
66
-
67
- const getDocumentSlug = (doc: PortableDoc | number): string | null => {
68
- if (typeof doc === 'number') return null
69
- return doc?.slug || null
70
- }
71
-
72
- const getCollectionPath = (relationTo: LinkReference['relationTo']): string => {
73
- if (relationTo === 'posts') return 'internal-docs'
74
- if (relationTo === 'thoughts') return 'thoughts'
75
- if (relationTo === 'projects') return 'archives'
76
- return ''
77
- }
78
-
79
- const isExternalUrl = (href: string): boolean =>
80
- href.startsWith('http://') ||
81
- href.startsWith('https://') ||
82
- href.startsWith('mailto:') ||
83
- href.startsWith('tel:')
84
-
85
- const resolveHref = (link: NavCodeGridLink, defaultHref = '/archive'): string => {
86
- if (!link) return defaultHref
87
- if (link.type === 'custom' && link.url) return link.url
88
- if (link.type === 'reference' && link.reference?.value) {
89
- const { relationTo, value } = link.reference
90
- if (relationTo === 'pages') return getPageURLFromDoc(value) || defaultHref
91
- const slug = getDocumentSlug(value)
92
- if (!slug) return defaultHref
93
- const basePath = getCollectionPath(relationTo)
94
- return basePath ? `/${basePath}/${slug}` : `/${slug}`
95
- }
96
- return defaultHref
97
- }
98
-
99
- const renderIcon = (link: NavCodeGridLink, showIcons = true) => {
100
- if (!showIcons || !link) return null
101
-
102
- if (link.customIcon && typeof link.customIcon === 'object') {
103
- const iconUrl = getMediaUrl(link.customIcon.url)
104
- if (iconUrl) {
105
- return (
106
- <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center overflow-hidden">
107
- <Image
108
- src={iconUrl}
109
- alt={link.customIcon.alt || ''}
110
- width={14}
111
- height={14}
112
- className="m-0 block h-full w-full object-contain"
113
- />
114
- </span>
115
- )
116
- }
117
- }
118
-
119
- if (link.icon) {
120
- const LucideIcon = LucideIcons[link.icon as keyof typeof LucideIcons] as
121
- | React.ComponentType<{ className?: string }>
122
- | undefined
123
- if (LucideIcon) {
124
- return (
125
- <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center">
126
- <LucideIcon className="h-3.5 w-3.5" />
127
- </span>
128
- )
129
- }
130
- }
131
-
132
- return null
133
- }
134
-
135
- const getDelayClass = (index: number) => {
136
- const delay = Math.min(index * 40, 320)
137
- return `[transition-delay:${delay}ms]`
138
- }
139
-
140
- export const DDHGNavCodeGrid: React.FC<DDHGNavCodeGridProps> = ({
141
- items,
142
- defaultHref = '/archive',
143
- containerClassName,
144
- gridClassName,
145
- cellClassName,
146
- showIcons = true,
147
- }) => {
148
- if (!Array.isArray(items) || items.length === 0) return null
149
-
150
- return (
151
- <div className={cn('w-full', containerClassName)}>
152
- <div className={cn('grid grid-cols-2 border border-border sm:grid-cols-4 !gap-0', gridClassName)}>
153
- {items.map((item, index) => {
154
- const link = item.link || null
155
- const href = resolveHref(link, defaultHref || '/archive')
156
- const label = link?.label || item.code || 'Archive'
157
- const icon = renderIcon(link, Boolean(showIcons))
158
- const iconPosition = link?.iconPosition || 'before'
159
- const target = link?.newTab ? '_blank' : undefined
160
- const rel = link?.newTab ? 'noopener noreferrer' : undefined
161
- const className = cn(
162
- 'menu-cell-hover group bg-transparent backdrop-blur-2xl border border-[var(--hg-50)] [border-style:outset] [text-shadow:0px_2px_4px_#ffffff45] relative flex items-center justify-center gap-2 py-2.5 text-[10px] font-normal uppercase tracking-[0.1em] text-[#6b6860] transition-all duration-200 hover:text-stone-700 dark:text-stone-200 sm:py-3 sm:text-[10px] md:py-4',
163
- '--border-r --border-b --border-border',
164
- (index + 1) % 4 === 0 ? '--sm:border-r-0' : '--border-border ',
165
- index >= 4 ? '--sm:border-b-0' : '',
166
- (index + 1) % 2 === 0 ? '--border-r-0' : '--border-r',
167
- index >= 6 ? '--border-b-0' : '--border-b',
168
- getDelayClass(index),
169
- cellClassName,
170
- )
171
-
172
- const content = (
173
- <>
174
- {icon && iconPosition === 'before' && icon}
175
- <span className="relative z-10">{label}</span>
176
- {icon && iconPosition === 'after' && icon}
177
- </>
178
- )
179
-
180
- if (isExternalUrl(href)) {
181
- return (
182
- <a
183
- key={item.id || `${label}-${index}`}
184
- href={href}
185
- target={target}
186
- rel={rel}
187
- className={className}
188
- style={{ fontFamily: "'Space Grotesk', sans-serif", fontWeight: 400, position: 'relative', textDecoration: 'none' }}
189
- >
190
- {content}
191
- </a>
192
- )
193
- }
194
-
195
- return (
196
- <Link
197
- key={item.id || `${label}-${index}`}
198
- href={href}
199
- target={target}
200
- rel={rel}
201
- className={className}
202
- style={{ fontFamily: "'Space Grotesk', sans-serif", fontWeight: 400, position: 'relative', textDecoration: 'none' }}
203
- >
204
- {content}
205
- </Link>
206
- )
207
- })}
208
- </div>
209
- </div>
210
- )
211
- }
212
-
213
- export default DDHGNavCodeGrid
1
+ 'use client'
2
+
3
+ import Image from 'next/image'
4
+ import Link from 'next/link'
5
+ import * as LucideIcons from 'lucide-react'
6
+ import React from 'react'
7
+
8
+ import { getMediaUrl } from '@/utilities/getMediaUrl'
9
+ import { cn } from '@/utilities/ui'
10
+
11
+ type PortableDoc = {
12
+ slug?: string | null
13
+ breadcrumbs?: Array<{ url?: string | null }> | null
14
+ [key: string]: unknown
15
+ }
16
+
17
+ type Media = {
18
+ url?: string | null
19
+ alt?: string | null
20
+ [key: string]: unknown
21
+ }
22
+
23
+ type LinkReference =
24
+ | { relationTo: 'pages'; value: number | PortableDoc }
25
+ | { relationTo: 'projects'; value: number | PortableDoc }
26
+ | { relationTo: 'thoughts'; value: number | PortableDoc }
27
+
28
+ type NavCodeGridLink = {
29
+ type?: 'reference' | 'custom' | null
30
+ reference?: LinkReference | null
31
+ url?: string | null
32
+ label?: string | null
33
+ newTab?: boolean | null
34
+ icon?: string | null
35
+ iconPosition?: 'before' | 'after' | null
36
+ customIcon?: number | Media | null
37
+ } | null
38
+
39
+ export type DDHGNavCodeGridItem = {
40
+ id?: string | null
41
+ code?: string | null
42
+ link?: NavCodeGridLink
43
+ }
44
+
45
+ export type DDHGNavCodeGridProps = {
46
+ items?: DDHGNavCodeGridItem[] | null
47
+ defaultHref?: string | null
48
+ containerClassName?: string | null
49
+ gridClassName?: string | null
50
+ cellClassName?: string | null
51
+ showIcons?: boolean | null
52
+ }
53
+
54
+ const getPageURLFromDoc = (doc: PortableDoc | number): string | null => {
55
+ if (typeof doc === 'number') return null
56
+ const crumbs = Array.isArray(doc?.breadcrumbs) ? doc.breadcrumbs : []
57
+ if (crumbs.length) {
58
+ const last = crumbs[crumbs.length - 1]
59
+ if (typeof last?.url === 'string' && last.url) return last.url
60
+ }
61
+ const slug = doc?.slug
62
+ if (!slug || slug === 'home') return '/'
63
+ return slug.startsWith('/') ? slug : `/${slug}`
64
+ }
65
+
66
+ const getDocumentSlug = (doc: PortableDoc | number): string | null => {
67
+ if (typeof doc === 'number') return null
68
+ return doc?.slug || null
69
+ }
70
+
71
+ const getCollectionPath = (relationTo: LinkReference['relationTo']): string => {
72
+ if (relationTo === 'thoughts') return 'thoughts'
73
+ if (relationTo === 'projects') return 'archives'
74
+ return ''
75
+ }
76
+
77
+ const isExternalUrl = (href: string): boolean =>
78
+ href.startsWith('http://') ||
79
+ href.startsWith('https://') ||
80
+ href.startsWith('mailto:') ||
81
+ href.startsWith('tel:')
82
+
83
+ const resolveHref = (link: NavCodeGridLink, defaultHref = '/archive'): string => {
84
+ if (!link) return defaultHref
85
+ if (link.type === 'custom' && link.url) return link.url
86
+ if (link.type === 'reference' && link.reference?.value) {
87
+ const { relationTo, value } = link.reference
88
+ if (relationTo === 'pages') return getPageURLFromDoc(value) || defaultHref
89
+ const slug = getDocumentSlug(value)
90
+ if (!slug) return defaultHref
91
+ const basePath = getCollectionPath(relationTo)
92
+ return basePath ? `/${basePath}/${slug}` : `/${slug}`
93
+ }
94
+ return defaultHref
95
+ }
96
+
97
+ const renderIcon = (link: NavCodeGridLink, showIcons = true) => {
98
+ if (!showIcons || !link) return null
99
+
100
+ if (link.customIcon && typeof link.customIcon === 'object') {
101
+ const iconUrl = getMediaUrl(link.customIcon.url)
102
+ if (iconUrl) {
103
+ return (
104
+ <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center overflow-hidden">
105
+ <Image
106
+ src={iconUrl}
107
+ alt={link.customIcon.alt || ''}
108
+ width={14}
109
+ height={14}
110
+ className="m-0 block h-full w-full object-contain"
111
+ />
112
+ </span>
113
+ )
114
+ }
115
+ }
116
+
117
+ if (link.icon) {
118
+ const LucideIcon = LucideIcons[link.icon as keyof typeof LucideIcons] as
119
+ React.ComponentType<{ className?: string }> | undefined
120
+ if (LucideIcon) {
121
+ return (
122
+ <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center">
123
+ <LucideIcon className="h-3.5 w-3.5" />
124
+ </span>
125
+ )
126
+ }
127
+ }
128
+
129
+ return null
130
+ }
131
+
132
+ const getDelayClass = (index: number) => {
133
+ const delay = Math.min(index * 40, 320)
134
+ return `[transition-delay:${delay}ms]`
135
+ }
136
+
137
+ export const DDHGNavCodeGrid: React.FC<DDHGNavCodeGridProps> = ({
138
+ items,
139
+ defaultHref = '/archive',
140
+ containerClassName,
141
+ gridClassName,
142
+ cellClassName,
143
+ showIcons = true,
144
+ }) => {
145
+ if (!Array.isArray(items) || items.length === 0) return null
146
+
147
+ return (
148
+ <div className={cn('w-full max-w-7xl mx-auto', containerClassName, 'pt-24')}>
149
+ <div
150
+ className={cn(
151
+ 'grid grid-cols-2 overflow-hidden bg-stone-100/50 dark:bg-stone-900/50 sm:grid-cols-4 !gap-0 shadow-lg',
152
+ gridClassName,
153
+ )}
154
+ >
155
+ {items.map((item, index) => {
156
+ const link = item.link || null
157
+ const href = resolveHref(link, defaultHref || '/archive')
158
+ const label = link?.label || item.code || 'Archive'
159
+ const icon = renderIcon(link, Boolean(showIcons))
160
+ const iconPosition = link?.iconPosition || 'before'
161
+ const target = link?.newTab ? '_blank' : undefined
162
+ const rel = link?.newTab ? 'noopener noreferrer' : undefined
163
+ const className = cn(
164
+ 'menu-cell-hover group relative flex items-center justify-center gap-2 bg-stone-200/50 py-2.5 text-xs font-normal uppercase tracking-[0.1em] text-sm !text-stone-900 [text-shadow:0px_2px_4px_#ffffff45] backdrop-blur-2xl transition-all duration-300 hover:-translate-y-0.5 hover:bg-stone-200/80 hover:!text-stone-700 dark:bg-stone-900/50 dark:!text-stone-100 dark:hover:bg-stone-800/70 dark:hover:!text-white sm:py-3 sm:text-xs md:py-4 hover:shadow-2xl',
165
+ 'border-r border-b border-border',
166
+ (index + 1) % 4 === 0 ? 'sm:border-r-0' : ' ',
167
+ index >= 4 ? 'sm:border-b-0' : '',
168
+ (index + 1) % 2 === 0 ? 'border-r-0' : 'border-r',
169
+ index >= 6 ? 'border-b-0' : 'border-b',
170
+ getDelayClass(index),
171
+ cellClassName,
172
+ )
173
+
174
+ const content = (
175
+ <>
176
+ {icon && iconPosition === 'before' && icon}
177
+ <span className="relative z-10">{label}</span>
178
+ {icon && iconPosition === 'after' && icon}
179
+ </>
180
+ )
181
+
182
+ if (isExternalUrl(href)) {
183
+ return (
184
+ <a
185
+ key={item.id || `${label}-${index}`}
186
+ href={href}
187
+ target={target}
188
+ rel={rel}
189
+ className={className}
190
+ style={{
191
+ fontFamily: "'Space Grotesk', sans-serif",
192
+ fontWeight: 400,
193
+ position: 'relative',
194
+ textDecoration: 'none',
195
+ }}
196
+ >
197
+ {content}
198
+ </a>
199
+ )
200
+ }
201
+
202
+ return (
203
+ <Link
204
+ key={item.id || `${label}-${index}`}
205
+ href={href}
206
+ target={target}
207
+ rel={rel}
208
+ className={className}
209
+ style={{
210
+ fontFamily: "'Space Grotesk', sans-serif",
211
+ fontWeight: 400,
212
+ position: 'relative',
213
+ textDecoration: 'none',
214
+ }}
215
+ >
216
+ {content}
217
+ </Link>
218
+ )
219
+ })}
220
+ </div>
221
+ </div>
222
+ )
223
+ }
224
+
225
+ export default DDHGNavCodeGrid