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.
- package/package.json +5 -2
- package/src/cli.js +39 -3
- package/src/commands/shop.js +59 -0
- package/src/commands/warehouse.js +73 -0
- 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 +10 -9
- 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 +5 -5
- 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-Chip/Component.tsx +14 -14
- package/templates/blocks/DD-ComparisonTable/Component.tsx +255 -256
- package/templates/blocks/DD-Contact/Component.tsx +433 -434
- package/templates/blocks/DD-Counter/Component.tsx +18 -13
- 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 +16 -40
- 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 +4 -5
- 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-IframeMedia/Component.tsx +14 -10
- 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 -547
- 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 +368 -372
- package/templates/blocks/DD-Pricing/config.ts +215 -215
- package/templates/blocks/DD-Process/Component.tsx +147 -149
- package/templates/blocks/DD-Progress/Component.tsx +156 -141
- package/templates/blocks/DD-ProjHeader/Component.tsx +93 -91
- package/templates/blocks/DD-ProjSlider/Component.tsx +1 -1
- package/templates/blocks/DD-ProjSlider/config.ts +2 -2
- 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 +237 -237
- package/templates/blocks/DD-StackCards/Component.tsx +474 -473
- 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 +161 -168
- 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 -147
- package/templates/blocks/DD-TextMarq/Component.tsx +157 -157
- package/templates/blocks/DD-Thanks/Component.tsx +501 -500
- package/templates/blocks/DD-Work/Component.tsx +315 -315
- 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 +246 -243
- package/templates/blocks/DDHG-LogoMarquee/Component.tsx +180 -93
- package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -66
- package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +225 -213
- package/templates/blocks/DDHG-ProcessSec/Component.tsx +38 -39
- package/templates/blocks/DDHG-ServiceDetails/Component.tsx +11 -11
- package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +30 -47
- package/templates/blocks/DDHG-ServiceHero/Component.tsx +10 -10
- package/templates/blocks/DDHG-ServiceOverview/Component.tsx +23 -23
- package/templates/blocks/DDHG-StatsFAQ/Component.tsx +40 -40
- package/templates/blocks/DDHG-TeamCards/Component.tsx +140 -131
- 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
|
@@ -47,21 +47,21 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
47
47
|
customClassName,
|
|
48
48
|
animate = false,
|
|
49
49
|
maxWidth,
|
|
50
|
-
padding = 'none'
|
|
50
|
+
padding = 'none',
|
|
51
51
|
}) => {
|
|
52
52
|
// Gap mappings
|
|
53
53
|
const gapClasses = {
|
|
54
54
|
none: 'gap-0',
|
|
55
55
|
small: 'gap-2',
|
|
56
56
|
medium: 'gap-3',
|
|
57
|
-
large: 'gap-4'
|
|
57
|
+
large: 'gap-4',
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Layout mappings
|
|
61
61
|
const layoutClasses = {
|
|
62
62
|
row: 'flex-row flex-nowrap overflow-x-auto',
|
|
63
63
|
column: 'flex-col',
|
|
64
|
-
'row-wrap': 'flex-row flex-wrap'
|
|
64
|
+
'row-wrap': 'flex-row flex-wrap',
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Alignment mappings
|
|
@@ -69,7 +69,7 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
69
69
|
start: 'justify-start',
|
|
70
70
|
center: 'justify-center',
|
|
71
71
|
end: 'justify-end',
|
|
72
|
-
'space-between': 'justify-between'
|
|
72
|
+
'space-between': 'justify-between',
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// Padding mappings
|
|
@@ -77,7 +77,7 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
77
77
|
none: '',
|
|
78
78
|
small: 'p-2',
|
|
79
79
|
medium: 'p-4',
|
|
80
|
-
large: 'p-6'
|
|
80
|
+
large: 'p-6',
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Helper to determine if a color is a Tailwind class or CSS color
|
|
@@ -137,9 +137,9 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
137
137
|
visible: {
|
|
138
138
|
opacity: 1,
|
|
139
139
|
transition: {
|
|
140
|
-
staggerChildren: 0.1
|
|
141
|
-
}
|
|
142
|
-
}
|
|
140
|
+
staggerChildren: 0.1,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
const chipVariants: Variants = {
|
|
@@ -149,9 +149,9 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
149
149
|
y: 0,
|
|
150
150
|
transition: {
|
|
151
151
|
duration: 0.4,
|
|
152
|
-
ease: 'easeOut'
|
|
153
|
-
}
|
|
154
|
-
}
|
|
152
|
+
ease: 'easeOut',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
const ChipElement = ({ chip, index }: { chip: Chip; index: number }): React.ReactElement => {
|
|
@@ -165,7 +165,7 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
165
165
|
<span className="relative z-10 mx-auto flex max-w-md items-center bg-gradient-to-r from-transparent via-white/80 via-50% to-transparent bg-clip-text bg-no-repeat text-neutral-400/70 [background-position:0_0] [background-size:var(--shiny-width)_100%] [--shiny-width:100px] select-none">
|
|
166
166
|
<span className="flex items-center text-white">
|
|
167
167
|
{/* {chip.icon && (
|
|
168
|
-
<span className="chip-icon mr-2 inline-flex h-3.5 w-3.5 items-center justify-center text-
|
|
168
|
+
<span className="chip-icon mr-2 inline-flex h-3.5 w-3.5 items-center justify-center text-xs leading-none">
|
|
169
169
|
{chip.icon}
|
|
170
170
|
</span>
|
|
171
171
|
)} */}
|
|
@@ -180,7 +180,7 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
180
180
|
'[&[href]]:cursor-pointer [&[href]]:no-underline',
|
|
181
181
|
hoverEffect &&
|
|
182
182
|
'hover:-translate-y-0.5 hover:shadow-[0_0_26px_rgba(186,85,211,0.35)] active:translate-y-0',
|
|
183
|
-
getChipClasses(chip)
|
|
183
|
+
getChipClasses(chip),
|
|
184
184
|
)
|
|
185
185
|
|
|
186
186
|
const chipElement = chip.link ? (
|
|
@@ -216,7 +216,7 @@ export const ChipBlockComponent: React.FC<ChipBlockProps> = ({
|
|
|
216
216
|
gapClasses[gap],
|
|
217
217
|
alignmentClasses[alignment],
|
|
218
218
|
paddingClasses[padding],
|
|
219
|
-
customClassName
|
|
219
|
+
customClassName,
|
|
220
220
|
)
|
|
221
221
|
|
|
222
222
|
if (animate) {
|
|
@@ -1,256 +1,255 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React, { Fragment, useState } from 'react'
|
|
4
|
-
import { Check, Minus, Plus } from 'lucide-react'
|
|
5
|
-
|
|
6
|
-
type TierKey = 'free' | 'pro' | 'team'
|
|
7
|
-
|
|
8
|
-
type CellValue = boolean | string
|
|
9
|
-
|
|
10
|
-
interface FeatureRow {
|
|
11
|
-
id?: string | null
|
|
12
|
-
label?: string | null
|
|
13
|
-
free?: CellValue | null
|
|
14
|
-
pro?: CellValue | null
|
|
15
|
-
team?: CellValue | null
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface FeatureGroup {
|
|
19
|
-
id?: string | null
|
|
20
|
-
group?: string | null
|
|
21
|
-
rows?: FeatureRow[] | null
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface TierHeader {
|
|
25
|
-
key: TierKey
|
|
26
|
-
label: string
|
|
27
|
-
highlight: boolean
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface StudioComparisonTableProps {
|
|
31
|
-
eyebrow?: string | null
|
|
32
|
-
heading?: string | null
|
|
33
|
-
defaultOpen?: boolean | null
|
|
34
|
-
groups?: FeatureGroup[] | null
|
|
35
|
-
sectionId?: string | null
|
|
36
|
-
customCSS?: string | null
|
|
37
|
-
[key: string]: unknown
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const DEFAULT_GROUPS: FeatureGroup[] = [
|
|
41
|
-
{
|
|
42
|
-
group: 'Components & Templates',
|
|
43
|
-
rows: [
|
|
44
|
-
{ label: 'Free components', free: true, pro: true, team: true },
|
|
45
|
-
{ label: 'Premium components', free: false, pro: '120+', team: '120+' },
|
|
46
|
-
{ label: 'Free templates', free: true, pro: true, team: true },
|
|
47
|
-
{ label: 'Premium templates', free: false, pro: '24+', team: '24+' },
|
|
48
|
-
{ label: 'Payload CMS v3 blocks', free: false, pro: true, team: true },
|
|
49
|
-
{ label: 'Figma source files', free: false, pro: true, team: true },
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
group: 'Licensing',
|
|
54
|
-
rows: [
|
|
55
|
-
{ label: 'Personal use', free: true, pro: true, team: true },
|
|
56
|
-
{
|
|
57
|
-
label: 'Commercial projects',
|
|
58
|
-
free: false,
|
|
59
|
-
pro: '1 project',
|
|
60
|
-
team: 'Unlimited',
|
|
61
|
-
},
|
|
62
|
-
{ label: 'White-label license', free: false, pro: false, team: true },
|
|
63
|
-
{ label: 'Client resale rights', free: false, pro: false, team: true },
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
group: 'Updates & Access',
|
|
68
|
-
rows: [
|
|
69
|
-
{ label: 'Lifetime updates', free: true, pro: true, team: true },
|
|
70
|
-
{
|
|
71
|
-
label: 'Early access to new releases',
|
|
72
|
-
free: false,
|
|
73
|
-
pro: true,
|
|
74
|
-
team: true,
|
|
75
|
-
},
|
|
76
|
-
{ label: 'Download source files', free: false, pro: true, team: true },
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
group: 'Support',
|
|
81
|
-
rows: [
|
|
82
|
-
{ label: 'Community Discord', free: true, pro: true, team: true },
|
|
83
|
-
{ label: 'Priority email support', free: false, pro: true, team: true },
|
|
84
|
-
{ label: 'Dedicated Slack channel', free: false, pro: false, team: true },
|
|
85
|
-
{ label: '1-on-1 onboarding call', free: false, pro: false, team: true },
|
|
86
|
-
{ label: 'SLA support guarantee', free: false, pro: false, team: true },
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
group: 'Team',
|
|
91
|
-
rows: [
|
|
92
|
-
{ label: 'Team seats', free: '1', pro: '1', team: 'Up to 10' },
|
|
93
|
-
{
|
|
94
|
-
label: 'Invoice & billing management',
|
|
95
|
-
free: false,
|
|
96
|
-
pro: false,
|
|
97
|
-
team: true,
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
label: 'Custom Payload CMS schemas',
|
|
101
|
-
free: false,
|
|
102
|
-
pro: false,
|
|
103
|
-
team: true,
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
function Cell({ value, highlight }: { value: CellValue | null | undefined; highlight: boolean }) {
|
|
110
|
-
if (typeof value === 'string') {
|
|
111
|
-
return (
|
|
112
|
-
<span
|
|
113
|
-
className={`text-sm font-medium ${highlight ? 'text-indigo-900 dark:text-lime-400' : 'text-stone-700 dark:text-stone-300'}`}
|
|
114
|
-
>
|
|
115
|
-
{value}
|
|
116
|
-
</span>
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (value === true) {
|
|
121
|
-
return (
|
|
122
|
-
<div
|
|
123
|
-
className={`mx-auto flex h-5 w-5 items-center justify-center rounded-full ${
|
|
124
|
-
highlight ? 'bg-stone-900' : 'bg-stone-800'
|
|
125
|
-
}`}
|
|
126
|
-
style={{ cornerShape: 'squircle' } as React.CSSProperties}
|
|
127
|
-
>
|
|
128
|
-
<Check className={`h-3 w-3 ${highlight ? 'text-stone-50' : 'text-stone-300'}`} />
|
|
129
|
-
</div>
|
|
130
|
-
)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<div className="mx-auto flex h-5 w-5 items-center justify-center opacity-30">
|
|
135
|
-
<Minus className="h-4 w-4 text-stone-600" />
|
|
136
|
-
</div>
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function DDComparisonTable({
|
|
141
|
-
eyebrow = 'Full breakdown',
|
|
142
|
-
heading = 'Compare all features',
|
|
143
|
-
defaultOpen = true,
|
|
144
|
-
groups,
|
|
145
|
-
sectionId,
|
|
146
|
-
}: StudioComparisonTableProps) {
|
|
147
|
-
const [open, setOpen] = useState(defaultOpen !== false)
|
|
148
|
-
const featureGroups = groups && groups.length > 0 ? groups : DEFAULT_GROUPS
|
|
149
|
-
|
|
150
|
-
const tiers: TierHeader[] = [
|
|
151
|
-
{ key: 'free', label: 'Free', highlight: false },
|
|
152
|
-
{ key: 'pro', label: 'Pro', highlight: true },
|
|
153
|
-
{ key: 'team', label: 'Team', highlight: false },
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
return (
|
|
157
|
-
<section
|
|
158
|
-
id={sectionId ?? undefined}
|
|
159
|
-
className="studio-comparison-table border-t border-stone-800 bg-transparent px-6 py-20"
|
|
160
|
-
>
|
|
161
|
-
<div className="mx-auto max-w-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
export default DDComparisonTable
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { Fragment, useState } from 'react'
|
|
4
|
+
import { Check, Minus, Plus } from 'lucide-react'
|
|
5
|
+
|
|
6
|
+
type TierKey = 'free' | 'pro' | 'team'
|
|
7
|
+
|
|
8
|
+
type CellValue = boolean | string
|
|
9
|
+
|
|
10
|
+
interface FeatureRow {
|
|
11
|
+
id?: string | null
|
|
12
|
+
label?: string | null
|
|
13
|
+
free?: CellValue | null
|
|
14
|
+
pro?: CellValue | null
|
|
15
|
+
team?: CellValue | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface FeatureGroup {
|
|
19
|
+
id?: string | null
|
|
20
|
+
group?: string | null
|
|
21
|
+
rows?: FeatureRow[] | null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TierHeader {
|
|
25
|
+
key: TierKey
|
|
26
|
+
label: string
|
|
27
|
+
highlight: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface StudioComparisonTableProps {
|
|
31
|
+
eyebrow?: string | null
|
|
32
|
+
heading?: string | null
|
|
33
|
+
defaultOpen?: boolean | null
|
|
34
|
+
groups?: FeatureGroup[] | null
|
|
35
|
+
sectionId?: string | null
|
|
36
|
+
customCSS?: string | null
|
|
37
|
+
[key: string]: unknown
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DEFAULT_GROUPS: FeatureGroup[] = [
|
|
41
|
+
{
|
|
42
|
+
group: 'Components & Templates',
|
|
43
|
+
rows: [
|
|
44
|
+
{ label: 'Free components', free: true, pro: true, team: true },
|
|
45
|
+
{ label: 'Premium components', free: false, pro: '120+', team: '120+' },
|
|
46
|
+
{ label: 'Free templates', free: true, pro: true, team: true },
|
|
47
|
+
{ label: 'Premium templates', free: false, pro: '24+', team: '24+' },
|
|
48
|
+
{ label: 'Payload CMS v3 blocks', free: false, pro: true, team: true },
|
|
49
|
+
{ label: 'Figma source files', free: false, pro: true, team: true },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
group: 'Licensing',
|
|
54
|
+
rows: [
|
|
55
|
+
{ label: 'Personal use', free: true, pro: true, team: true },
|
|
56
|
+
{
|
|
57
|
+
label: 'Commercial projects',
|
|
58
|
+
free: false,
|
|
59
|
+
pro: '1 project',
|
|
60
|
+
team: 'Unlimited',
|
|
61
|
+
},
|
|
62
|
+
{ label: 'White-label license', free: false, pro: false, team: true },
|
|
63
|
+
{ label: 'Client resale rights', free: false, pro: false, team: true },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
group: 'Updates & Access',
|
|
68
|
+
rows: [
|
|
69
|
+
{ label: 'Lifetime updates', free: true, pro: true, team: true },
|
|
70
|
+
{
|
|
71
|
+
label: 'Early access to new releases',
|
|
72
|
+
free: false,
|
|
73
|
+
pro: true,
|
|
74
|
+
team: true,
|
|
75
|
+
},
|
|
76
|
+
{ label: 'Download source files', free: false, pro: true, team: true },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
group: 'Support',
|
|
81
|
+
rows: [
|
|
82
|
+
{ label: 'Community Discord', free: true, pro: true, team: true },
|
|
83
|
+
{ label: 'Priority email support', free: false, pro: true, team: true },
|
|
84
|
+
{ label: 'Dedicated Slack channel', free: false, pro: false, team: true },
|
|
85
|
+
{ label: '1-on-1 onboarding call', free: false, pro: false, team: true },
|
|
86
|
+
{ label: 'SLA support guarantee', free: false, pro: false, team: true },
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
group: 'Team',
|
|
91
|
+
rows: [
|
|
92
|
+
{ label: 'Team seats', free: '1', pro: '1', team: 'Up to 10' },
|
|
93
|
+
{
|
|
94
|
+
label: 'Invoice & billing management',
|
|
95
|
+
free: false,
|
|
96
|
+
pro: false,
|
|
97
|
+
team: true,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: 'Custom Payload CMS schemas',
|
|
101
|
+
free: false,
|
|
102
|
+
pro: false,
|
|
103
|
+
team: true,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
function Cell({ value, highlight }: { value: CellValue | null | undefined; highlight: boolean }) {
|
|
110
|
+
if (typeof value === 'string') {
|
|
111
|
+
return (
|
|
112
|
+
<span
|
|
113
|
+
className={`text-sm font-medium ${highlight ? 'text-indigo-900 dark:text-lime-400' : 'text-stone-700 dark:text-stone-300'}`}
|
|
114
|
+
>
|
|
115
|
+
{value}
|
|
116
|
+
</span>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (value === true) {
|
|
121
|
+
return (
|
|
122
|
+
<div
|
|
123
|
+
className={`mx-auto flex h-5 w-5 items-center justify-center rounded-full ${
|
|
124
|
+
highlight ? 'bg-stone-900' : 'bg-stone-800'
|
|
125
|
+
}`}
|
|
126
|
+
style={{ cornerShape: 'squircle' } as React.CSSProperties}
|
|
127
|
+
>
|
|
128
|
+
<Check className={`h-3 w-3 ${highlight ? 'text-stone-50' : 'text-stone-300'}`} />
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className="mx-auto flex h-5 w-5 items-center justify-center opacity-30">
|
|
135
|
+
<Minus className="h-4 w-4 text-stone-600" />
|
|
136
|
+
</div>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function DDComparisonTable({
|
|
141
|
+
eyebrow = 'Full breakdown',
|
|
142
|
+
heading = 'Compare all features',
|
|
143
|
+
defaultOpen = true,
|
|
144
|
+
groups,
|
|
145
|
+
sectionId,
|
|
146
|
+
}: StudioComparisonTableProps) {
|
|
147
|
+
const [open, setOpen] = useState(defaultOpen !== false)
|
|
148
|
+
const featureGroups = groups && groups.length > 0 ? groups : DEFAULT_GROUPS
|
|
149
|
+
|
|
150
|
+
const tiers: TierHeader[] = [
|
|
151
|
+
{ key: 'free', label: 'Free', highlight: false },
|
|
152
|
+
{ key: 'pro', label: 'Pro', highlight: true },
|
|
153
|
+
{ key: 'team', label: 'Team', highlight: false },
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<section
|
|
158
|
+
id={sectionId ?? undefined}
|
|
159
|
+
className="studio-comparison-table w-full border-t border-stone-800 bg-transparent px-6 py-20"
|
|
160
|
+
>
|
|
161
|
+
<div className="mx-auto w-full max-w-7xl">
|
|
162
|
+
<button
|
|
163
|
+
type="button"
|
|
164
|
+
onClick={() => setOpen((current) => !current)}
|
|
165
|
+
className="group mb-8 flex w-full cursor-pointer items-center justify-between gap-6 text-left"
|
|
166
|
+
>
|
|
167
|
+
<div>
|
|
168
|
+
{eyebrow && (
|
|
169
|
+
<p className="mb-1 text-xs font-semibold uppercase tracking-widest text-stone-500">
|
|
170
|
+
{eyebrow}
|
|
171
|
+
</p>
|
|
172
|
+
)}
|
|
173
|
+
{heading && (
|
|
174
|
+
<h2 className="text-3xl font-semibold text-stone-900 dark:text-stone-50">
|
|
175
|
+
{heading}
|
|
176
|
+
</h2>
|
|
177
|
+
)}
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div
|
|
181
|
+
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-stone-100 bg-stone-200 dark:border-stone-700 dark:bg-stone-800 transition-colors group-hover:border-stone-300 dark:group-hover:border-stone-500"
|
|
182
|
+
style={{ cornerShape: 'squircle' } as React.CSSProperties}
|
|
183
|
+
>
|
|
184
|
+
{open ? (
|
|
185
|
+
<Minus className="h-4 w-4 text-stone-700 dark:text-stone-400 transition-transform duration-300" />
|
|
186
|
+
) : (
|
|
187
|
+
<Plus className="h-4 w-4 text-stone-700 dark:text-stone-300 transition-transform duration-300" />
|
|
188
|
+
)}
|
|
189
|
+
</div>
|
|
190
|
+
</button>
|
|
191
|
+
|
|
192
|
+
{open && (
|
|
193
|
+
<div className="overflow-x-auto">
|
|
194
|
+
<table className="w-full min-w-160">
|
|
195
|
+
<thead>
|
|
196
|
+
<tr>
|
|
197
|
+
<th className="w-1/2 pb-0 text-left" />
|
|
198
|
+
{tiers.map((tier) => (
|
|
199
|
+
<th key={tier.key} className="pb-0 text-center">
|
|
200
|
+
<span
|
|
201
|
+
className={`inline-block rounded-lg px-4 py-1.5 text-sm font-semibold ${
|
|
202
|
+
tier.highlight
|
|
203
|
+
? 'bg-stone-100 text-stone-900'
|
|
204
|
+
: 'border-stone-100 bg-stone-200 dark:border-stone-700 dark:bg-stone-800/50 transition-colors group-hover:border-stone-300 dark:group-hover:border-stone-500'
|
|
205
|
+
}`}
|
|
206
|
+
style={{ cornerShape: 'squircle' } as React.CSSProperties}
|
|
207
|
+
>
|
|
208
|
+
{tier.label}
|
|
209
|
+
</span>
|
|
210
|
+
</th>
|
|
211
|
+
))}
|
|
212
|
+
</tr>
|
|
213
|
+
</thead>
|
|
214
|
+
|
|
215
|
+
<tbody>
|
|
216
|
+
{featureGroups.map((group, groupIndex) => (
|
|
217
|
+
<Fragment key={group.id ?? group.group ?? groupIndex}>
|
|
218
|
+
<tr>
|
|
219
|
+
<td colSpan={4} className="pb-3 pt-0">
|
|
220
|
+
<span className="text-xs font-bold uppercase tracking-widest text-stone-500">
|
|
221
|
+
{group.group}
|
|
222
|
+
</span>
|
|
223
|
+
</td>
|
|
224
|
+
</tr>
|
|
225
|
+
|
|
226
|
+
{(group.rows ?? []).map((row, rowIndex) => (
|
|
227
|
+
<tr
|
|
228
|
+
key={row.id ?? row.label ?? rowIndex}
|
|
229
|
+
className={`border-t transition-colors hover:bg-stone-200/40 dark:hover:bg-stone-900/40 ${
|
|
230
|
+
rowIndex === 0 ? 'border-stone-800' : 'border-stone-800/50'
|
|
231
|
+
}`}
|
|
232
|
+
>
|
|
233
|
+
<td className="py-3.5 pr-6">
|
|
234
|
+
<span className="text-sm text-stone-400">{row.label}</span>
|
|
235
|
+
</td>
|
|
236
|
+
|
|
237
|
+
{tiers.map((tier) => (
|
|
238
|
+
<td key={tier.key} className="py-3.5 text-center">
|
|
239
|
+
<Cell value={row[tier.key]} highlight={tier.highlight} />
|
|
240
|
+
</td>
|
|
241
|
+
))}
|
|
242
|
+
</tr>
|
|
243
|
+
))}
|
|
244
|
+
</Fragment>
|
|
245
|
+
))}
|
|
246
|
+
</tbody>
|
|
247
|
+
</table>
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
250
|
+
</div>
|
|
251
|
+
</section>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default DDComparisonTable
|