blocks-dusted 0.1.12 → 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.
- package/package.json +1 -1
- package/src/installers/patchRenderBlocks.js +1 -1
- package/src/registry/validateTemplateManifest.js +2 -1
- package/templates/blocks/BannerDD790432/Component.tsx +63 -0
- package/templates/blocks/BannerDD790432/config.ts +54 -0
- package/templates/blocks/BannerDD790432/manifest.json +80 -0
- package/templates/blocks/Button47/Component.tsx +124 -0
- package/templates/blocks/Button47/config.ts +75 -0
- package/templates/blocks/Button47/link.ts +22 -0
- package/templates/blocks/Button47/manifest.json +105 -0
- package/templates/blocks/Button47/styles.module.scss +75 -0
- package/templates/blocks/DD-Accordion/Component.tsx +55 -36
- package/templates/blocks/DD-Accordion/config.ts +71 -59
- package/templates/blocks/DD-AnimText/Component.tsx +50 -32
- package/templates/blocks/DD-AnimText/config.ts +296 -295
- package/templates/blocks/DD-AsideNav/Component.tsx +323 -319
- package/templates/blocks/DD-Banner/Component.tsx +54 -51
- package/templates/blocks/DD-BookCall/Component.tsx +535 -535
- package/templates/blocks/DD-ButtonPop/Component.tsx +118 -117
- package/templates/blocks/DD-Card/Component.tsx +4 -4
- package/templates/blocks/DD-CardTemplate01/Component.tsx +139 -140
- package/templates/blocks/DD-CardsWithVariantV3/Component.tsx +472 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/index.tsx +203 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/styles.ts +87 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/useInjectStyle.ts +39 -0
- package/templates/blocks/DD-CardsWithVariantV3/config.ts +326 -0
- package/templates/blocks/DD-CardsWithVariantV3/manifest.json +110 -0
- package/templates/blocks/DD-Carousel-A/Component.tsx +251 -249
- package/templates/blocks/DD-Carousel-B/Component.tsx +405 -403
- package/templates/blocks/DD-ComparisonTable/Component.tsx +255 -256
- package/templates/blocks/DD-Contact/Component.tsx +433 -435
- package/templates/blocks/DD-Counter/Component.tsx +11 -6
- package/templates/blocks/DD-DeliCard/Component.tsx +303 -0
- package/templates/blocks/DD-DeliCard/config.ts +186 -0
- package/templates/blocks/DD-DeliCard/manifest.json +94 -0
- package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
- package/templates/blocks/DD-FeatProd/CircularGallery.tsx +1179 -0
- package/templates/blocks/DD-FeatProd/Component.tsx +484 -0
- package/templates/blocks/DD-FeatProd/config.ts +173 -0
- package/templates/blocks/DD-FeatProd/manifest.json +93 -0
- package/templates/blocks/DD-FeatServ/Component.tsx +607 -0
- package/templates/blocks/DD-FeatServ/config.ts +213 -0
- package/templates/blocks/DD-FeatServ/manifest.json +113 -0
- package/templates/blocks/DD-FeatStrip/Component.tsx +584 -585
- package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +627 -628
- package/templates/blocks/DD-FluidBtn/Component.tsx +46 -43
- package/templates/blocks/DD-GooeyInfo/Component.tsx +150 -149
- package/templates/blocks/DD-GooeyInfo/config.ts +136 -135
- package/templates/blocks/DD-Hero/Component.tsx +296 -297
- package/templates/blocks/DD-HeroPlas/Component.tsx +50 -0
- package/templates/blocks/DD-HeroPlas/ThreeScene.tsx +109 -0
- package/templates/blocks/DD-HeroPlas/config.ts +33 -0
- package/templates/blocks/DD-HeroPlas/manifest.json +88 -0
- package/templates/blocks/DD-HorizontalScroll/Component.tsx +937 -936
- package/templates/blocks/DD-Icon/Component.tsx +46 -81
- package/templates/blocks/DD-IconButton/Component.tsx +13 -20
- package/templates/blocks/DD-IdTag/Component.tsx +22 -21
- package/templates/blocks/DD-LineAnim/Component.tsx +42 -36
- package/templates/blocks/DD-LogoMarq/Component.tsx +38 -48
- package/templates/blocks/DD-Lottie/Component.tsx +11 -3
- package/templates/blocks/DD-MasonaryMedia/Component.tsx +544 -545
- package/templates/blocks/DD-MasonaryMedia/config.ts +389 -389
- package/templates/blocks/DD-Masonry/Component.tsx +654 -644
- package/templates/blocks/DD-Masonry/config.ts +475 -475
- package/templates/blocks/DD-MaterialSwatches/Component.tsx +85 -0
- package/templates/blocks/DD-MaterialSwatches/config.ts +232 -0
- package/templates/blocks/DD-MaterialSwatches/manifest.json +84 -0
- package/templates/blocks/DD-MaterialSwatches/material.ts +107 -0
- package/templates/blocks/DD-NineCanvas/Component.tsx +129 -0
- package/templates/blocks/DD-NineCanvas/RenderBlocks.tsx +244 -0
- package/templates/blocks/DD-NineCanvas/allowedCanvasBlocks.ts +6 -0
- package/templates/blocks/DD-NineCanvas/blockComponents.tsx +8 -0
- package/templates/blocks/DD-NineCanvas/canvas/CanvasGrid.tsx +316 -0
- package/templates/blocks/DD-NineCanvas/canvas/RadialNav.tsx +432 -0
- package/templates/blocks/DD-NineCanvas/canvas/canvas-panels.css +889 -0
- package/templates/blocks/DD-NineCanvas/canvas/icons/custom-icons.tsx +364 -0
- package/templates/blocks/DD-NineCanvas/config.ts +61 -0
- package/templates/blocks/DD-NineCanvas/manifest.json +165 -0
- package/templates/blocks/DD-NineCanvas/styles.scss +152 -0
- package/templates/blocks/DD-NineCanvas/tooltip/get-strict-context.tsx +26 -0
- package/templates/blocks/DD-NineCanvas/tooltip/primitives.tsx +178 -0
- package/templates/blocks/DD-NineCanvas/tooltip/tooltip.tsx +71 -0
- package/templates/blocks/DD-NineCanvas/tooltip/use-controlled-state.tsx +33 -0
- package/templates/blocks/DD-NineCanvas/utilities/FadeOnScroll.tsx +68 -0
- package/templates/blocks/DD-NineCanvas/utilities/ParallaxWrapper.tsx +157 -0
- package/templates/blocks/DD-NineCanvas/utilities/renderCustomCSS.ts +5 -0
- package/templates/blocks/DD-NineCanvas/utilities/webglCleanup.ts +27 -0
- package/templates/blocks/DD-PayloadAIAssistant/Component.tsx +78 -0
- package/templates/blocks/DD-PayloadAIAssistant/DustedBot.tsx +590 -0
- package/templates/blocks/DD-PayloadAIAssistant/config.ts +37 -0
- package/templates/blocks/DD-PayloadAIAssistant/demo.css +125 -0
- package/templates/blocks/DD-PayloadAIAssistant/manifest.json +93 -0
- package/templates/blocks/DD-PayloadAIAssistant/source-defaults.ts +17 -0
- package/templates/blocks/DD-PayloadAIAssistant/styles.ts +306 -0
- package/templates/blocks/DD-Pricing/Component.tsx +2 -3
- package/templates/blocks/DD-Pricing/config.ts +215 -215
- package/templates/blocks/DD-Process/Component.tsx +2 -2
- package/templates/blocks/DD-ProjHeader/Component.tsx +93 -91
- package/templates/blocks/DD-ProjSlider/Component.tsx +1 -1
- package/templates/blocks/DD-Section/Component.tsx +265 -266
- package/templates/blocks/DD-Separator/Component.tsx +66 -66
- package/templates/blocks/DD-Services/Component.tsx +176 -176
- package/templates/blocks/DD-ShowcaseGrid/Component.tsx +306 -307
- package/templates/blocks/DD-Slider-A/Component.tsx +2 -2
- package/templates/blocks/DD-StackCards/Component.tsx +172 -171
- package/templates/blocks/DD-Team/Component.tsx +247 -247
- package/templates/blocks/DD-TeamCards/Component.tsx +251 -251
- package/templates/blocks/DD-TechStack/Component.tsx +173 -174
- package/templates/blocks/DD-TestMarq/Component.tsx +158 -132
- package/templates/blocks/DD-Testim/Component.tsx +247 -247
- package/templates/blocks/DD-Testim2/Component.tsx +265 -256
- package/templates/blocks/DD-Testimonials/Component.tsx +139 -139
- package/templates/blocks/DD-Thanks/Component.tsx +1 -1
- package/templates/blocks/DD-Work/Component.tsx +318 -318
- package/templates/blocks/DD-Work-B/Component.tsx +294 -294
- package/templates/blocks/DDHG-CTASection2/Component.tsx +183 -184
- package/templates/blocks/DDHG-HighlightArc/Component.tsx +6 -3
- package/templates/blocks/DDHG-LogoMarquee/Component.tsx +45 -8
- package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +1 -3
- package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +9 -22
- package/templates/blocks/DDHG-ServiceHero/Component.tsx +10 -10
- package/templates/blocks/DDHG-TeamCards/Component.tsx +6 -35
- package/templates/blocks/Form/Checkbox/index.tsx +45 -0
- package/templates/blocks/Form/Component.tsx +163 -0
- package/templates/blocks/Form/Country/index.tsx +65 -0
- package/templates/blocks/Form/Country/options.ts +982 -0
- package/templates/blocks/Form/Email/index.tsx +38 -0
- package/templates/blocks/Form/Error/index.tsx +15 -0
- package/templates/blocks/Form/Message/index.tsx +13 -0
- package/templates/blocks/Form/Number/index.tsx +36 -0
- package/templates/blocks/Form/Select/index.tsx +63 -0
- package/templates/blocks/Form/State/index.tsx +64 -0
- package/templates/blocks/Form/State/options.ts +52 -0
- package/templates/blocks/Form/Text/index.tsx +32 -0
- package/templates/blocks/Form/Textarea/index.tsx +40 -0
- package/templates/blocks/Form/Width/index.tsx +13 -0
- package/templates/blocks/Form/config.ts +51 -0
- package/templates/blocks/Form/fields.tsx +21 -0
- package/templates/blocks/Form/manifest.json +168 -0
- package/templates/blocks/MediaBlock/Component.tsx +67 -0
- package/templates/blocks/MediaBlock/config.ts +14 -0
- package/templates/blocks/MediaBlock/manifest.json +92 -0
- package/templates/blocks/TransitionsDustedShowcase/Component.tsx +9 -0
- package/templates/blocks/TransitionsDustedShowcase/config.ts +13 -0
- package/templates/blocks/TransitionsDustedShowcase/manifest.json +80 -0
- package/templates/blocks/rawHtml/Component.tsx +25 -0
- package/templates/blocks/rawHtml/config.ts +56 -0
- package/templates/blocks/rawHtml/manifest.json +80 -0
|
@@ -1,185 +1,184 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { motion } from 'framer-motion'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { cn } from '@/utilities/ui'
|
|
7
|
-
|
|
8
|
-
type PortableDoc = {
|
|
9
|
-
slug?: string | null
|
|
10
|
-
breadcrumbs?: Array<{ url?: string | null }> | null
|
|
11
|
-
[key: string]: unknown
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type LinkReference =
|
|
15
|
-
| { relationTo: 'pages'; value: number | PortableDoc }
|
|
16
|
-
| { relationTo: '
|
|
17
|
-
| { relationTo: '
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (relationTo === '
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
id={
|
|
125
|
-
data-
|
|
126
|
-
data-scroll={scrollSpeed ?
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
{headingLineOne}
|
|
152
|
-
{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
{...revealMotion}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<CTAButton link={
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { motion } from 'framer-motion'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/utilities/ui'
|
|
7
|
+
|
|
8
|
+
type PortableDoc = {
|
|
9
|
+
slug?: string | null
|
|
10
|
+
breadcrumbs?: Array<{ url?: string | null }> | null
|
|
11
|
+
[key: string]: unknown
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type LinkReference =
|
|
15
|
+
| { relationTo: 'pages'; value: number | PortableDoc }
|
|
16
|
+
| { relationTo: 'projects'; value: number | PortableDoc }
|
|
17
|
+
| { relationTo: 'thoughts'; value: number | PortableDoc }
|
|
18
|
+
|
|
19
|
+
type BlockLinkField = {
|
|
20
|
+
type?: 'reference' | 'custom' | null
|
|
21
|
+
reference?: LinkReference | null
|
|
22
|
+
url?: string | null
|
|
23
|
+
label?: string | null
|
|
24
|
+
newTab?: boolean | null
|
|
25
|
+
} | null
|
|
26
|
+
|
|
27
|
+
export type DDHGCTASection2Props = {
|
|
28
|
+
sectionId?: string | null
|
|
29
|
+
customClassName?: string | null
|
|
30
|
+
customCSS?: string | null
|
|
31
|
+
blockId?: string | null
|
|
32
|
+
scrollSpeed?: string | number | null
|
|
33
|
+
eyebrowPrefix?: string | null
|
|
34
|
+
eyebrowEmphasis?: string | null
|
|
35
|
+
headingLineOne?: string | null
|
|
36
|
+
headingLineTwo?: string | null
|
|
37
|
+
description?: string | null
|
|
38
|
+
showDivider?: boolean | null
|
|
39
|
+
primaryLink?: BlockLinkField
|
|
40
|
+
secondaryLink?: BlockLinkField
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getHref(link?: BlockLinkField): string | null {
|
|
44
|
+
if (!link) return null
|
|
45
|
+
|
|
46
|
+
if (link.type === 'custom' && link.url) return link.url
|
|
47
|
+
|
|
48
|
+
if (link.type === 'reference' && link.reference?.value) {
|
|
49
|
+
const { relationTo, value } = link.reference
|
|
50
|
+
if (typeof value === 'number') return null
|
|
51
|
+
|
|
52
|
+
if (relationTo === 'pages') {
|
|
53
|
+
const crumbs = Array.isArray(value.breadcrumbs) ? value.breadcrumbs : []
|
|
54
|
+
const last = crumbs[crumbs.length - 1]
|
|
55
|
+
if (last?.url) return last.url
|
|
56
|
+
|
|
57
|
+
const slug = value.slug
|
|
58
|
+
if (!slug || slug === 'home') return '/'
|
|
59
|
+
return slug.startsWith('/') ? slug : `/${slug}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const slug = value.slug
|
|
63
|
+
if (!slug) return null
|
|
64
|
+
|
|
65
|
+
if (relationTo === 'projects') return `/archives/${slug}`
|
|
66
|
+
if (relationTo === 'thoughts') return `/thoughts/${slug}`
|
|
67
|
+
return `/${slug}`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function CTAButton({ link, variant }: { link?: BlockLinkField; variant: 'primary' | 'secondary' }) {
|
|
74
|
+
const href = getHref(link)
|
|
75
|
+
if (!href) return null
|
|
76
|
+
|
|
77
|
+
const target = link?.newTab ? '_blank' : undefined
|
|
78
|
+
const rel = link?.newTab ? 'noopener noreferrer' : undefined
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<a
|
|
82
|
+
href={href}
|
|
83
|
+
target={target}
|
|
84
|
+
rel={rel}
|
|
85
|
+
className={cn(
|
|
86
|
+
'inline-flex min-h-10 items-center justify-center rounded-md squircle px-5 py-2.5 text-sm font-medium transition-all duration-300 0 hover:shadow-xl hover:-translate-y-0.5 hover:transition-all hover:duration-300',
|
|
87
|
+
variant === 'primary'
|
|
88
|
+
? 'bg-stone-800 text-white hover:bg-stone-700'
|
|
89
|
+
: 'border border-stone-400 text-stone-700 dark:text-stone-200 hover:bg-stone-100 dark:hover:text-stone-700',
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{link?.label || 'Learn More'}
|
|
93
|
+
</a>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const revealMotion = {
|
|
98
|
+
initial: { opacity: 0, y: 18 },
|
|
99
|
+
whileInView: { opacity: 1, y: 0 },
|
|
100
|
+
viewport: { once: true, amount: 0.25 },
|
|
101
|
+
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const DDHGCTASection2: React.FC<DDHGCTASection2Props> = ({
|
|
105
|
+
sectionId,
|
|
106
|
+
customClassName,
|
|
107
|
+
customCSS,
|
|
108
|
+
blockId,
|
|
109
|
+
scrollSpeed,
|
|
110
|
+
eyebrowPrefix = 'ready to',
|
|
111
|
+
eyebrowEmphasis = 'begin?',
|
|
112
|
+
headingLineOne = "LET'S BUILD YOUR",
|
|
113
|
+
headingLineTwo = 'NEXT SPACE',
|
|
114
|
+
description = 'Every great space begins with a conversation. Share your vision, and we will map the path from where you are to where you want to be.',
|
|
115
|
+
showDivider = true,
|
|
116
|
+
primaryLink,
|
|
117
|
+
secondaryLink,
|
|
118
|
+
}) => {
|
|
119
|
+
const hasButtons = Boolean(getHref(primaryLink) || getHref(secondaryLink))
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div
|
|
123
|
+
id={sectionId ?? undefined}
|
|
124
|
+
data-block-id={blockId ?? undefined}
|
|
125
|
+
data-scroll={scrollSpeed ? true : undefined}
|
|
126
|
+
data-scroll-speed={scrollSpeed ? String(scrollSpeed) : undefined}
|
|
127
|
+
className={cn('mb-10 px-5 py-20 md:px-8', customClassName)}
|
|
128
|
+
>
|
|
129
|
+
{customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
|
|
130
|
+
|
|
131
|
+
<div className="mx-auto max-w-7xl">
|
|
132
|
+
<motion.div
|
|
133
|
+
className="z-plane-2 relative overflow-hidden rounded-md squircle border border-stone-300/10 bg-stone-100/50 transition-all duration-300 dark:border-stone-700/10 dark:bg-stone-900/50 shadow-xl"
|
|
134
|
+
initial={{ opacity: 0, y: 20 }}
|
|
135
|
+
whileInView={{ opacity: 1, y: 0 }}
|
|
136
|
+
viewport={{ once: true, amount: 0.25 }}
|
|
137
|
+
transition={{ duration: 0.9, ease: [0.22, 1, 0.36, 1] }}
|
|
138
|
+
>
|
|
139
|
+
<div className="relative p-8 text-center md:p-12 lg:p-16">
|
|
140
|
+
{(eyebrowPrefix || eyebrowEmphasis) && (
|
|
141
|
+
<p className="mb-4 text-xs uppercase tracking-[0.2em] text-stone-600 dark:text-stone-300">
|
|
142
|
+
{eyebrowPrefix && <span className="font-light">{eyebrowPrefix} </span>}
|
|
143
|
+
{eyebrowEmphasis && <span className="font-medium">{eyebrowEmphasis}</span>}
|
|
144
|
+
</p>
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
<motion.div className="heading" {...revealMotion}>
|
|
148
|
+
{(headingLineOne || headingLineTwo) && (
|
|
149
|
+
<h2 className="mb-4 text-3xl font-medium leading-none tracking-tight text-purple-700 dark:text-purple-500 md:text-5xl">
|
|
150
|
+
{headingLineOne}
|
|
151
|
+
{headingLineOne && headingLineTwo && <br />}
|
|
152
|
+
<span className="font-bold">{headingLineTwo}</span>
|
|
153
|
+
</h2>
|
|
154
|
+
)}
|
|
155
|
+
</motion.div>
|
|
156
|
+
|
|
157
|
+
{showDivider && <div className="mx-auto mb-6 h-px w-12 bg-stone-500" />}
|
|
158
|
+
|
|
159
|
+
<motion.div
|
|
160
|
+
className="description"
|
|
161
|
+
{...revealMotion}
|
|
162
|
+
transition={{ ...revealMotion.transition, delay: 0.08 }}
|
|
163
|
+
>
|
|
164
|
+
{description && (
|
|
165
|
+
<p className="mx-auto mb-8 max-w-lg text-[14px] font-light leading-relaxed text-stone-700 dark:text-stone-200">
|
|
166
|
+
{description}
|
|
167
|
+
</p>
|
|
168
|
+
)}
|
|
169
|
+
</motion.div>
|
|
170
|
+
|
|
171
|
+
{hasButtons && (
|
|
172
|
+
<div className="flex flex-wrap items-center justify-center gap-3">
|
|
173
|
+
<CTAButton link={primaryLink} variant="primary" />
|
|
174
|
+
<CTAButton link={secondaryLink} variant="secondary" />
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
</div>
|
|
178
|
+
</motion.div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
185
184
|
export default DDHGCTASection2
|
|
@@ -21,7 +21,6 @@ type Media = {
|
|
|
21
21
|
|
|
22
22
|
type LinkReference =
|
|
23
23
|
| { relationTo: 'pages'; value: number | PortableDoc }
|
|
24
|
-
| { relationTo: 'posts'; value: number | PortableDoc }
|
|
25
24
|
| { relationTo: 'projects'; value: number | PortableDoc }
|
|
26
25
|
| { relationTo: 'thoughts'; value: number | PortableDoc }
|
|
27
26
|
|
|
@@ -82,7 +81,6 @@ const getDocumentSlug = (doc: PortableDoc | number): string | null => {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
const getCollectionPath = (relationTo: LinkReference['relationTo']): string => {
|
|
85
|
-
if (relationTo === 'posts') return 'thoughts'
|
|
86
84
|
if (relationTo === 'thoughts') return 'thoughts'
|
|
87
85
|
if (relationTo === 'projects') return 'archives'
|
|
88
86
|
return ''
|
|
@@ -120,7 +118,12 @@ export const DDHGHighlightArc: React.FC<DDHGHighlightArcProps> = ({
|
|
|
120
118
|
if (!Array.isArray(highlights) || highlights.length === 0) return null
|
|
121
119
|
|
|
122
120
|
return (
|
|
123
|
-
<div
|
|
121
|
+
<div
|
|
122
|
+
className={cn(
|
|
123
|
+
'mx-auto grid w-full max-w-7xl origin-top scale-100 gap-0!',
|
|
124
|
+
getGridClassName(gridColumns),
|
|
125
|
+
)}
|
|
126
|
+
>
|
|
124
127
|
{highlights.map((h, i) => {
|
|
125
128
|
const isHovered = hoveredIdx === i
|
|
126
129
|
const bgImage = typeof h.bgImage === 'object' && h.bgImage !== null ? h.bgImage : null
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import React, { useState } from 'react'
|
|
4
4
|
import { motion } from 'framer-motion'
|
|
5
5
|
import Image from 'next/image'
|
|
6
|
+
import * as LucideIcons from 'lucide-react'
|
|
6
7
|
import { cn } from '@/utilities/ui'
|
|
7
8
|
// DDHG TODO: Re-enable after reviewing the project-specific separator/custom CSS bundle.
|
|
8
9
|
// import { Separator } from '@/components/ui/separator'
|
|
@@ -19,8 +20,21 @@ type LogoItem = {
|
|
|
19
20
|
imageClass?: string | null
|
|
20
21
|
imageStyle?: React.CSSProperties
|
|
21
22
|
imageAltClass?: string | null
|
|
23
|
+
icon?: string | null
|
|
24
|
+
label?: string | null
|
|
25
|
+
showLabel?: boolean | null
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
function DynamicIcon({
|
|
29
|
+
name,
|
|
30
|
+
size = 36,
|
|
31
|
+
...props
|
|
32
|
+
}: { name?: string | null } & Omit<LucideIcons.LucideProps, 'name'>) {
|
|
33
|
+
if (!name) return null
|
|
34
|
+
const Icon = (LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>)[name]
|
|
35
|
+
if (!Icon) return null
|
|
36
|
+
return <Icon size={size} {...props} />
|
|
37
|
+
}
|
|
24
38
|
export type DDHGLogoMarqueeProps = {
|
|
25
39
|
sectionId?: string | null
|
|
26
40
|
logos?: LogoItem[] | null
|
|
@@ -79,6 +93,8 @@ export const DDHGLogoMarquee: React.FC<DDHGLogoMarqueeProps> = ({
|
|
|
79
93
|
const validLogos = Array.isArray(logos) ? logos : []
|
|
80
94
|
if (validLogos.length === 0) return null
|
|
81
95
|
const calculatedItemWidth = itemWidth || 100
|
|
96
|
+
const defaultIcons = ['Code2', 'Database', 'PanelsTopLeft', 'Braces', 'Workflow', 'GitBranch']
|
|
97
|
+
const defaultLabels = ['Interface', 'Data', 'Layout', 'Types', 'Workflow', 'Collaboration']
|
|
82
98
|
const totalWidth = validLogos.length * (calculatedItemWidth + (spacing || 0))
|
|
83
99
|
|
|
84
100
|
// DDHG TODO: Re-enable with extractCustomCSS when that bundle is reviewed.
|
|
@@ -105,14 +121,35 @@ export const DDHGLogoMarquee: React.FC<DDHGLogoMarqueeProps> = ({
|
|
|
105
121
|
: { minWidth: `${calculatedItemWidth}px` }),
|
|
106
122
|
}}
|
|
107
123
|
>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
{true ? (
|
|
125
|
+
<>
|
|
126
|
+
<div className="flex h-20 w-20 items-center justify-center rounded-2xl border border-[#2A2A30] bg-linear-to-b from-[#1a1a1f] to-[#0f0f12] p-4 invert-[1] transition-all duration-300 hover:scale-105 hover:shadow-[0_0_30px_rgba(140,138,132,0.15)] dark:invert-[0]">
|
|
127
|
+
<DynamicIcon
|
|
128
|
+
className="text-[#9A9790]"
|
|
129
|
+
name={logo.icon || defaultIcons[index % defaultIcons.length]}
|
|
130
|
+
size={36}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
{logo.showLabel !== false && (
|
|
134
|
+
<span className="mt-2 block whitespace-nowrap text-center text-sm text-[#9A9790]">
|
|
135
|
+
{logo.label || defaultLabels[index % defaultLabels.length]}
|
|
136
|
+
</span>
|
|
137
|
+
)}
|
|
138
|
+
</>
|
|
139
|
+
) : (
|
|
140
|
+
<>
|
|
141
|
+
<LogoImage
|
|
142
|
+
src={logo.image?.url || placeholderBlur}
|
|
143
|
+
alt={logo.image?.alt}
|
|
144
|
+
customClass={logo.imageClass}
|
|
145
|
+
imageStyle={logo.imageStyle}
|
|
146
|
+
priority={Boolean(priority)}
|
|
147
|
+
/>
|
|
148
|
+
<p className={cn('text-center text-base', logo.imageAltClass)}>
|
|
149
|
+
{logo.label || logo.image?.alt || null}
|
|
150
|
+
</p>
|
|
151
|
+
</>
|
|
152
|
+
)}
|
|
116
153
|
</div>
|
|
117
154
|
))
|
|
118
155
|
|
|
@@ -22,7 +22,6 @@ type Media = {
|
|
|
22
22
|
|
|
23
23
|
type LinkReference =
|
|
24
24
|
| { relationTo: 'pages'; value: number | PortableDoc }
|
|
25
|
-
| { relationTo: 'posts'; value: number | PortableDoc }
|
|
26
25
|
| { relationTo: 'projects'; value: number | PortableDoc }
|
|
27
26
|
| { relationTo: 'thoughts'; value: number | PortableDoc }
|
|
28
27
|
|
|
@@ -70,7 +69,6 @@ const getDocumentSlug = (doc: PortableDoc | number): string | null => {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
const getCollectionPath = (relationTo: LinkReference['relationTo']): string => {
|
|
73
|
-
if (relationTo === 'posts') return 'internal-docs'
|
|
74
72
|
if (relationTo === 'thoughts') return 'thoughts'
|
|
75
73
|
if (relationTo === 'projects') return 'archives'
|
|
76
74
|
return ''
|
|
@@ -163,7 +161,7 @@ export const DDHGNavCodeGrid: React.FC<DDHGNavCodeGridProps> = ({
|
|
|
163
161
|
const target = link?.newTab ? '_blank' : undefined
|
|
164
162
|
const rel = link?.newTab ? 'noopener noreferrer' : undefined
|
|
165
163
|
const className = cn(
|
|
166
|
-
'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-shadow:0px_2px_4px_#ffffff45] backdrop-blur-2xl transition-all duration-300 hover:-translate-y-0.5 hover:bg-stone-200/80 hover
|
|
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',
|
|
167
165
|
'border-r border-b border-border',
|
|
168
166
|
(index + 1) % 4 === 0 ? 'sm:border-r-0' : ' ',
|
|
169
167
|
index >= 4 ? 'sm:border-b-0' : '',
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { AnimatePresence, motion } from 'framer-motion'
|
|
4
4
|
import { ChevronDown, ChevronUp, CircleDot } from 'lucide-react'
|
|
5
|
+
import Image from 'next/image'
|
|
5
6
|
import React from 'react'
|
|
6
|
-
import RichText from '@/components/RichText/index'
|
|
7
7
|
import { cn } from '@/utilities/ui'
|
|
8
8
|
|
|
9
9
|
export type ServiceDetailLayout = 'left' | 'right' | 'center' | 'split' | 'asym' | 'bleed'
|
|
@@ -161,12 +161,6 @@ type ServiceDetailCardProps = {
|
|
|
161
161
|
onToggle: () => void
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
function hasRichTextContent(value: unknown): boolean {
|
|
165
|
-
if (!value || typeof value !== 'object') return false
|
|
166
|
-
const root = (value as any)?.root
|
|
167
|
-
return Array.isArray(root?.children) && root.children.length > 0
|
|
168
|
-
}
|
|
169
|
-
|
|
170
164
|
function getDescription(service: ServiceDetailItem) {
|
|
171
165
|
return service.description || service.desc || ''
|
|
172
166
|
}
|
|
@@ -180,22 +174,15 @@ function getPoints(service: ServiceDetailItem) {
|
|
|
180
174
|
}
|
|
181
175
|
|
|
182
176
|
function VisualContent({ service }: { service: ServiceDetailItem }) {
|
|
183
|
-
const content = service.visualContent || service.mediaContent || null
|
|
184
|
-
if (hasRichTextContent(content)) {
|
|
185
|
-
return (
|
|
186
|
-
<div className="relative h-full min-h-75 w-full overflow-hidden rounded-md squircle border border-stone-300/10 bg-stone-100/50 p-4 dark:border-stone-700/10 dark:bg-stone-900/50 hover:shadow-xl transition-all duration-300">
|
|
187
|
-
<RichText
|
|
188
|
-
data={content}
|
|
189
|
-
enableGutter={false}
|
|
190
|
-
enableProse={false}
|
|
191
|
-
className="h-full min-h-75 w-full *:m-0 [&_.media-block]:m-0 [&_img]:m-0"
|
|
192
|
-
/>
|
|
193
|
-
</div>
|
|
194
|
-
)
|
|
195
|
-
}
|
|
196
177
|
return (
|
|
197
|
-
<div className="min-h-75 w-full rounded-md squircle bg-
|
|
198
|
-
<
|
|
178
|
+
<div className="relative h-full min-h-75 w-full overflow-hidden rounded-md squircle border border-stone-300/10 bg-stone-100/50 dark:border-stone-700/10 dark:bg-stone-900/50 hover:shadow-xl transition-all duration-300">
|
|
179
|
+
<Image
|
|
180
|
+
src="/media/placeholder-2-1920x1080.webp"
|
|
181
|
+
alt={`${service.title || 'Service detail'} visual`}
|
|
182
|
+
fill
|
|
183
|
+
className="object-cover"
|
|
184
|
+
sizes="(max-width: 768px) 100vw, 50vw"
|
|
185
|
+
/>
|
|
199
186
|
</div>
|
|
200
187
|
)
|
|
201
188
|
}
|
|
@@ -24,7 +24,7 @@ const minHeightClassMap: Record<NonNullable<DDHGServiceHeroProps['minHeight']>,
|
|
|
24
24
|
screen: 'min-h-screen',
|
|
25
25
|
large: 'min-h-[70vh]',
|
|
26
26
|
medium: 'min-h-[56vh]',
|
|
27
|
-
compact: 'min-h-[42vh]'
|
|
27
|
+
compact: 'min-h-[42vh]',
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
let globalInstanceCounter = 0
|
|
@@ -32,7 +32,7 @@ let globalInstanceCounter = 0
|
|
|
32
32
|
function FadeUpOnInView({
|
|
33
33
|
children,
|
|
34
34
|
className = '',
|
|
35
|
-
delay = 0
|
|
35
|
+
delay = 0,
|
|
36
36
|
}: {
|
|
37
37
|
children: React.ReactNode
|
|
38
38
|
className?: string
|
|
@@ -54,7 +54,7 @@ function FadeUpOnInView({
|
|
|
54
54
|
node.style.transitionDelay = '0s'
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
|
-
{ threshold: 0.25 }
|
|
57
|
+
{ threshold: 0.25 },
|
|
58
58
|
)
|
|
59
59
|
observer.observe(node)
|
|
60
60
|
return () => observer.disconnect()
|
|
@@ -67,7 +67,7 @@ function FadeUpOnInView({
|
|
|
67
67
|
display: 'inline-block',
|
|
68
68
|
opacity: 0,
|
|
69
69
|
transform: 'translateY(24px)',
|
|
70
|
-
transition: 'opacity 700ms ease, transform 700ms ease'
|
|
70
|
+
transition: 'opacity 700ms ease, transform 700ms ease',
|
|
71
71
|
}}
|
|
72
72
|
>
|
|
73
73
|
{children}
|
|
@@ -78,7 +78,7 @@ function FadeUpOnInView({
|
|
|
78
78
|
function RevealText({
|
|
79
79
|
text,
|
|
80
80
|
className = '',
|
|
81
|
-
instanceIndex
|
|
81
|
+
instanceIndex,
|
|
82
82
|
}: {
|
|
83
83
|
text: string[]
|
|
84
84
|
className?: string
|
|
@@ -101,7 +101,7 @@ function RevealText({
|
|
|
101
101
|
setAnimationKey((key) => key + 1)
|
|
102
102
|
} else setIsVisible(false)
|
|
103
103
|
},
|
|
104
|
-
{ threshold: 0.3 }
|
|
104
|
+
{ threshold: 0.3 },
|
|
105
105
|
)
|
|
106
106
|
observer.observe(node)
|
|
107
107
|
return () => observer.disconnect()
|
|
@@ -117,7 +117,7 @@ function RevealText({
|
|
|
117
117
|
ref={textRef}
|
|
118
118
|
className={cn(
|
|
119
119
|
'inline-block h-auto bg-transparent text-left font-bold uppercase leading-none tracking-[1px]',
|
|
120
|
-
className
|
|
120
|
+
className,
|
|
121
121
|
)}
|
|
122
122
|
>
|
|
123
123
|
{words.map((word, wordIndex) => {
|
|
@@ -140,7 +140,7 @@ function RevealText({
|
|
|
140
140
|
animationName: isVisible ? 'ddhgServiceHeroReveal' : 'none',
|
|
141
141
|
animationDuration: '1s',
|
|
142
142
|
animationFillMode: 'forwards',
|
|
143
|
-
animationDelay: `${baseDelay + index * 0.05}s
|
|
143
|
+
animationDelay: `${baseDelay + index * 0.05}s`,
|
|
144
144
|
}}
|
|
145
145
|
>
|
|
146
146
|
{char}
|
|
@@ -169,7 +169,7 @@ export const DDHGServiceHero: React.FC<DDHGServiceHeroProps> = ({
|
|
|
169
169
|
description = 'From initial vision to final handover, our services span the full spectrum of interior architecture. Each engagement is shaped by the same principle: spaces should serve the people inside them.',
|
|
170
170
|
minHeight = 'large',
|
|
171
171
|
showDivider = true,
|
|
172
|
-
showScrollIndicator = true
|
|
172
|
+
showScrollIndicator = true,
|
|
173
173
|
}) => {
|
|
174
174
|
const minHeightClass = minHeightClassMap[minHeight || 'large']
|
|
175
175
|
return (
|
|
@@ -182,7 +182,7 @@ export const DDHGServiceHero: React.FC<DDHGServiceHeroProps> = ({
|
|
|
182
182
|
>
|
|
183
183
|
{customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
|
|
184
184
|
<motion.div
|
|
185
|
-
className="ServiceHeroCard relative z-10 mx-auto max-w-
|
|
185
|
+
className="ServiceHeroCard relative z-10 mx-auto w-full max-w-7xl overflow-clip rounded-md squircle bg-stone-100/50 p-6 dark:bg-stone-900/50 md:p-8"
|
|
186
186
|
initial={{ opacity: 0, y: 20 }}
|
|
187
187
|
whileInView={{ opacity: 1, y: 0 }}
|
|
188
188
|
viewport={{ once: true, amount: 0.35 }}
|