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,149 +1,147 @@
1
- 'use client'
2
- import React from 'react'
3
- import * as LucideIcons from 'lucide-react'
4
- import { motion, type Variants } from 'framer-motion'
5
- export type DDProcessProps = Record<string, any>
6
- type StepItem = {
7
- id?: string | null
8
- iconName?: string | null
9
- title?: string | null
10
- description?: string | null
11
- duration?: string | null
12
- }
13
-
14
- function DynamicIcon({
15
- name,
16
- size = 24,
17
- ...props
18
- }: { name?: string | null } & Omit<LucideIcons.LucideProps, 'name'>) {
19
- if (!name) return null
20
- const Icon = (LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>)[name]
21
- if (!Icon) return null
22
- return <Icon size={size} {...props} />
23
- }
24
-
25
- // Enumerate all possible classes so Tailwind doesn't purge them
26
- const gridColsMap: Record<number, string> = {
27
- 1: 'lg:grid-cols-1',
28
- 2: 'lg:grid-cols-2',
29
- 3: 'lg:grid-cols-3',
30
- 4: 'lg:grid-cols-4',
31
- 5: 'lg:grid-cols-5',
32
- 6: 'lg:grid-cols-6',
33
- }
34
-
35
- const containerVariants: Variants = {
36
- hidden: {},
37
- show: {
38
- transition: {
39
- staggerChildren: 0.1,
40
- delayChildren: 0.05,
41
- },
42
- },
43
- }
44
-
45
- const stepVariants: Variants = {
46
- hidden: { opacity: 0, y: 28 },
47
- show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: 'easeOut' } },
48
- }
49
-
50
- export const DDProcess: React.FC<DDProcessProps> = ({
51
- eyebrow,
52
- headlineMain,
53
- headlineAccent,
54
- description,
55
- steps,
56
- sectionId,
57
- customCSS,
58
- }) => {
59
- const stepItems = (steps ?? []) as StepItem[]
60
- const colCount = Math.min(stepItems.length || 4, 6)
61
- const lgCols = gridColsMap[colCount] ?? 'lg:grid-cols-4'
62
-
63
- return (
64
- <>
65
- {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
66
-
67
- <div id={sectionId ?? 'process'} className="py-24">
68
- <div className="max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6">
69
- {/* Header */}
70
- <div className="text-center max-w-2xl mx-auto mb-16">
71
- {eyebrow && (
72
- <p className="text-[11.5px] font-semibold text-stone-400 tracking-widest uppercase mb-3 top-caption">
73
- {eyebrow}
74
- </p>
75
- )}
76
- <h2 className="text-3d text-4xl md:text-5xl font-bold text-stone-900 dark:text-stone-50 leading-tight mb-5">
77
- {headlineMain}
78
- <br />
79
- <span className="text-stone-400">{headlineAccent}</span>
80
- </h2>
81
- {description && (
82
- <p className="text-stone-700 dark:text-stone-300 text-base leading-relaxed">
83
- {description}
84
- </p>
85
- )}
86
- </div>
87
- {/* Steps */}
88
- {stepItems.length > 0 && (
89
- <div className="relative steps-container mb-4">
90
- {/* Single connector line spanning icon centres */}
91
- <div
92
- className="hidden lg:block absolute top-10 h-px bg-indigo-700 z-0"
93
- style={{
94
- left: `calc(100% / ${colCount} / 2)`,
95
- right: `calc(100% / ${colCount} / 2)`,
96
- }}
97
- />
98
-
99
- <motion.div
100
- className={`grid grid-cols-2 sm:grid-cols-2 ${lgCols} gap-8 sm:gap-6 relative z-10`}
101
- variants={containerVariants}
102
- initial="hidden"
103
- whileInView="show"
104
- viewport={{ once: false, amount: 0.2 }}
105
- >
106
- {stepItems.map((step, i) => (
107
- <motion.div
108
- key={step.id ?? i}
109
- className="flex flex-col items-start md:items-center text-left md:text-center justify-start md:justify-center p-4 border-zinc-700/0 border focus:outline-none group bg-lines rounded-md hover:rounded-lg hover:border hover:bg-stone-100 dark:hover:bg-stone-950/90 hover:shadow-2xl hover:border-indigo-500 duration-300 hover:duration-300 transition-all card-bottom-lit"
110
- variants={stepVariants}
111
- >
112
- {/* Circular icon with numbered badge */}
113
- <div className="w-20 h-20 mx-auto flex items-center justify-center rounded-full bg-stone-200 dark:bg-stone-900 border-2 border-indigo-700 group-hover:border-indigo-500 -border-stone-700 mb-5 relative shrink-0">
114
- <DynamicIcon
115
- className="dark:text-indigo-400 text-indigo-700 group-hover:dark:text-lime-400 duration-300 transition-all"
116
- name={step.iconName}
117
- size={24}
118
- />
119
- <span className="absolute -top-1 -right-1 w-6 h-6 flex items-center justify-center rounded-full bg-stone-200 dark:bg-stone-900 border border-indigo-700 text-[10px] font-mono text-indigo-700 dark:text-indigo-400">
120
- {i + 1}
121
- </span>
122
- </div>
123
-
124
- {/* Duration badge */}
125
- {step.duration && (
126
- <div className="inline-flex items-center gap-1 bg-7 bg-stone-800 border border-stone-700 rounded-full px-2.5 py-0.5 mb-3 group-hover:bg-indigo-800 group-hover:border-indigo-600 dark:group-hover:border-lime-500">
127
- <LucideIcons.Clock size={10} className="text-stone-300" />
128
- <span className="text-[10px] text-stone-300 font-medium">
129
- {step.duration}
130
- </span>
131
- </div>
132
- )}
133
-
134
- <h3 className="text-lg font-semibold text-stone-900 dark:text-stone-50 mb-2">
135
- {step.title}
136
- </h3>
137
- <p className="text-sm text-stone-700 dark:text-stone-300 leading-relaxed pb-8">
138
- {step.description}
139
- </p>
140
- </motion.div>
141
- ))}
142
- </motion.div>
143
- </div>
144
- )}
145
- </div>
146
- </div>
147
- </>
148
- )
149
- }
1
+ 'use client'
2
+ import React from 'react'
3
+ import * as LucideIcons from 'lucide-react'
4
+ import { motion, type Variants } from 'framer-motion'
5
+ export type DDProcessProps = Record<string, any>
6
+ type StepItem = {
7
+ id?: string | null
8
+ iconName?: string | null
9
+ title?: string | null
10
+ description?: string | null
11
+ duration?: string | null
12
+ }
13
+
14
+ function DynamicIcon({
15
+ name,
16
+ size = 24,
17
+ ...props
18
+ }: { name?: string | null } & Omit<LucideIcons.LucideProps, 'name'>) {
19
+ if (!name) return null
20
+ const Icon = (LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>)[name]
21
+ if (!Icon) return null
22
+ return <Icon size={size} {...props} />
23
+ }
24
+
25
+ // Enumerate all possible classes so Tailwind doesn't purge them
26
+ const gridColsMap: Record<number, string> = {
27
+ 1: 'lg:grid-cols-1',
28
+ 2: 'lg:grid-cols-2',
29
+ 3: 'lg:grid-cols-3',
30
+ 4: 'lg:grid-cols-4',
31
+ 5: 'lg:grid-cols-5',
32
+ 6: 'lg:grid-cols-6',
33
+ }
34
+
35
+ const containerVariants: Variants = {
36
+ hidden: {},
37
+ show: {
38
+ transition: {
39
+ staggerChildren: 0.1,
40
+ delayChildren: 0.05,
41
+ },
42
+ },
43
+ }
44
+
45
+ const stepVariants: Variants = {
46
+ hidden: { opacity: 0, y: 28 },
47
+ show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: 'easeOut' } },
48
+ }
49
+
50
+ export const DDProcess: React.FC<DDProcessProps> = ({
51
+ eyebrow,
52
+ headlineMain,
53
+ headlineAccent,
54
+ description,
55
+ steps,
56
+ sectionId,
57
+ customCSS,
58
+ }) => {
59
+ const stepItems = (steps ?? []) as StepItem[]
60
+ const colCount = Math.min(stepItems.length || 4, 6)
61
+ const lgCols = gridColsMap[colCount] ?? 'lg:grid-cols-4'
62
+
63
+ return (
64
+ <>
65
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
66
+
67
+ <div id={sectionId ?? 'process'} className="py-4">
68
+ <div className="max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6">
69
+ {/* Header */}
70
+ <div className="text-center max-w-2xl mx-auto mb-16">
71
+ {eyebrow && (
72
+ <p className="text-[11.5px] font-semibold text-stone-400 tracking-widest uppercase mb-3 top-caption">
73
+ {eyebrow}
74
+ </p>
75
+ )}
76
+ <h2 className="text-3d text-4xl md:text-5xl font-bold text-stone-900 dark:text-stone-50 leading-tight mb-5">
77
+ {headlineMain}
78
+ <br />
79
+ <span className="text-stone-400">{headlineAccent}</span>
80
+ </h2>
81
+ {description && (
82
+ <p className="text-stone-700 dark:text-stone-300 text-base leading-relaxed">
83
+ {description}
84
+ </p>
85
+ )}
86
+ </div>
87
+ {/* Steps */}
88
+ {stepItems.length > 0 && (
89
+ <div className="relative steps-container mb-4">
90
+ {/* Single connector line spanning icon centres */}
91
+ <div
92
+ className="hidden lg:block absolute top-10 h-px bg-indigo-700 z-0"
93
+ style={{
94
+ left: `calc(100% / ${colCount} / 2)`,
95
+ right: `calc(100% / ${colCount} / 2)`,
96
+ }}
97
+ />
98
+
99
+ <motion.div
100
+ className={`grid grid-cols-2 sm:grid-cols-2 ${lgCols} gap-8 sm:gap-6 relative z-10`}
101
+ variants={containerVariants}
102
+ initial="hidden"
103
+ whileInView="show"
104
+ viewport={{ once: false, amount: 0.2 }}
105
+ >
106
+ {stepItems.map((step, i) => (
107
+ <motion.div
108
+ key={step.id ?? i}
109
+ className="flex flex-col items-start md:items-center text-left md:text-center justify-start md:justify-center p-4 border-zinc-700/0 border focus:outline-none group bg-lines rounded-md hover:rounded-lg hover:border hover:bg-stone-100 dark:hover:bg-stone-950/90 hover:shadow-2xl hover:border-indigo-500 duration-300 hover:duration-300 transition-all card-bottom-lit"
110
+ variants={stepVariants}
111
+ >
112
+ {/* Circular icon with numbered badge */}
113
+ <div className="w-20 h-20 mx-auto flex items-center justify-center rounded-full bg-stone-200 dark:bg-stone-900 border-2 border-indigo-700 group-hover:border-indigo-500 -border-stone-700 mb-5 relative shrink-0">
114
+ <DynamicIcon
115
+ className="dark:text-indigo-400 text-indigo-700 group-hover:dark:text-lime-400 duration-300 transition-all"
116
+ name={step.iconName}
117
+ size={24}
118
+ />
119
+ <span className="absolute -top-1 -right-1 w-6 h-6 flex items-center justify-center rounded-full bg-stone-200 dark:bg-stone-900 border border-indigo-700 text-xs font-mono text-indigo-700 dark:text-indigo-400">
120
+ {i + 1}
121
+ </span>
122
+ </div>
123
+
124
+ {/* Duration badge */}
125
+ {step.duration && (
126
+ <div className="inline-flex items-center gap-1 bg-7 bg-stone-800 border border-stone-700 rounded-full px-2.5 py-0.5 mb-3 group-hover:bg-indigo-800 group-hover:border-indigo-600 dark:group-hover:border-lime-500">
127
+ <LucideIcons.Clock size={10} className="text-stone-300" />
128
+ <span className="text-xs text-stone-300 font-medium">{step.duration}</span>
129
+ </div>
130
+ )}
131
+
132
+ <h3 className="text-lg font-semibold text-stone-900 dark:text-stone-50 mb-2">
133
+ {step.title}
134
+ </h3>
135
+ <p className="text-sm text-stone-700 dark:text-stone-300 leading-relaxed pb-8">
136
+ {step.description}
137
+ </p>
138
+ </motion.div>
139
+ ))}
140
+ </motion.div>
141
+ </div>
142
+ )}
143
+ </div>
144
+ </div>
145
+ </>
146
+ )
147
+ }
@@ -1,141 +1,156 @@
1
- 'use client'
2
-
3
- import React from 'react'
4
- import { motion, useInView } from 'framer-motion'
5
- import { cn } from '@/utilities/ui'
6
-
7
- export interface SkillItem {
8
- label: string
9
- percentage: number
10
- color?: string
11
- showPercentage?: boolean
12
- id?: string
13
- }
14
-
15
- export interface ProgressSkillBlockProps {
16
- skills?: SkillItem[]
17
- containerClass?: string
18
- labelClass?: string
19
- progressBarClass?: string
20
- percentageClass?: string
21
- animationDuration?: number
22
- animationDelay?: number
23
- blockType?: string
24
- }
25
-
26
- export const DDProgress: React.FC<ProgressSkillBlockProps> = ({
27
- skills = [],
28
- containerClass = '',
29
- labelClass = '',
30
- progressBarClass = '',
31
- percentageClass = '',
32
- animationDuration = 1.5,
33
- animationDelay = 0.2
34
- }) => {
35
- if (!skills || skills.length === 0) {
36
- return null
37
- }
38
-
39
- return (
40
- <div className={cn('progress-skill-block w-full space-y-6 py-8', containerClass)}>
41
- {skills.map((skill, index) => (
42
- <SkillProgressBar
43
- key={skill.id || `skill-${index}`}
44
- skill={skill}
45
- index={index}
46
- labelClass={labelClass}
47
- progressBarClass={progressBarClass}
48
- percentageClass={percentageClass}
49
- animationDuration={animationDuration}
50
- animationDelay={animationDelay}
51
- />
52
- ))}
53
- </div>
54
- )
55
- }
56
-
57
- interface SkillProgressBarProps {
58
- skill: SkillItem
59
- index: number
60
- labelClass: string
61
- progressBarClass: string
62
- percentageClass: string
63
- animationDuration: number
64
- animationDelay: number
65
- }
66
-
67
- const SkillProgressBar: React.FC<SkillProgressBarProps> = ({
68
- skill,
69
- index,
70
- labelClass,
71
- progressBarClass,
72
- percentageClass,
73
- animationDuration,
74
- animationDelay
75
- }) => {
76
- const ref = React.useRef(null)
77
- const isInView = useInView(ref, { once: false, amount: 0.3 })
78
-
79
- const progressVariants = {
80
- hidden: { width: '0%' },
81
- visible: {
82
- width: `${skill.percentage}%`,
83
- transition: {
84
- duration: animationDuration,
85
- delay: index * animationDelay,
86
- ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number]
87
- }
88
- }
89
- }
90
-
91
- const percentageVariants = {
92
- hidden: { opacity: 0 },
93
- visible: {
94
- opacity: 1,
95
- transition: {
96
- duration: 0.3,
97
- delay: index * animationDelay + animationDuration * 0.8
98
- }
99
- }
100
- }
101
-
102
- // Create unique class name from label (slugified)
103
- const uniqueClass =
104
- skill.id ||
105
- skill.label
106
- .toLowerCase()
107
- .replace(/\s+/g, '-')
108
- .replace(/[^a-z0-9-]/g, '')
109
-
110
- return (
111
- <div ref={ref} className={cn('skill-item w-full', `skill-${uniqueClass}`)}>
112
- {/* Label and Percentage Row */}
113
- <div className="flex justify-between items-center mb-1">
114
- <div className={cn('text-lg font-medium text-white', labelClass)}>{skill.label}</div>
115
- {skill.showPercentage !== false && (
116
- <motion.span
117
- className={cn('text-sm font-semibold text-white', percentageClass)}
118
- variants={percentageVariants}
119
- initial="hidden"
120
- animate={isInView ? 'visible' : 'hidden'}
121
- >
122
- {skill.percentage} %
123
- </motion.span>
124
- )}
125
- </div>
126
-
127
- {/* Progress Bar Container */}
128
- <div className="progress-bar-container relative w-full h-1.5 bg-zinc-700 overflow-hidden">
129
- <motion.div
130
- className={cn('progress-bar-fill absolute top-0 left-0 h-full', progressBarClass)}
131
- style={{
132
- backgroundColor: skill.color || '#9ACD32'
133
- }}
134
- variants={progressVariants}
135
- initial="hidden"
136
- animate={isInView ? 'visible' : 'hidden'}
137
- />
138
- </div>
139
- </div>
140
- )
141
- }
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { motion, useInView } from 'framer-motion'
5
+ import { cn } from '@/utilities/ui'
6
+
7
+ export interface SkillItem {
8
+ label: string
9
+ percentage: number
10
+ color?: string
11
+ showPercentage?: boolean
12
+ id?: string
13
+ }
14
+
15
+ export interface ProgressSkillBlockProps {
16
+ skills?: SkillItem[]
17
+ containerClass?: string
18
+ labelClass?: string
19
+ progressBarClass?: string
20
+ percentageClass?: string
21
+ animationDuration?: number
22
+ animationDelay?: number
23
+ blockType?: string
24
+ }
25
+
26
+ export const DDProgress: React.FC<ProgressSkillBlockProps> = ({
27
+ skills = [],
28
+ containerClass = '',
29
+ labelClass = '',
30
+ progressBarClass = '',
31
+ percentageClass = '',
32
+ animationDuration = 1.5,
33
+ animationDelay = 0.2,
34
+ }) => {
35
+ if (!skills || skills.length === 0) {
36
+ return null
37
+ }
38
+
39
+ return (
40
+ <div
41
+ className={cn(
42
+ 'progress-skill-block w-full space-y-6 py-8',
43
+ 'max-w-7xl mx-auto',
44
+ containerClass,
45
+ )}
46
+ >
47
+ {skills.map((skill, index) => (
48
+ <SkillProgressBar
49
+ key={skill.id || `skill-${index}`}
50
+ skill={skill}
51
+ index={index}
52
+ labelClass={labelClass}
53
+ progressBarClass={progressBarClass}
54
+ percentageClass={percentageClass}
55
+ animationDuration={animationDuration}
56
+ animationDelay={animationDelay}
57
+ />
58
+ ))}
59
+ </div>
60
+ )
61
+ }
62
+
63
+ interface SkillProgressBarProps {
64
+ skill: SkillItem
65
+ index: number
66
+ labelClass: string
67
+ progressBarClass: string
68
+ percentageClass: string
69
+ animationDuration: number
70
+ animationDelay: number
71
+ }
72
+
73
+ const SkillProgressBar: React.FC<SkillProgressBarProps> = ({
74
+ skill,
75
+ index,
76
+ labelClass,
77
+ progressBarClass,
78
+ percentageClass,
79
+ animationDuration,
80
+ animationDelay,
81
+ }) => {
82
+ const ref = React.useRef(null)
83
+ const isInView = useInView(ref, { once: false, amount: 0.3 })
84
+
85
+ const progressVariants = {
86
+ hidden: { width: '0%' },
87
+ visible: {
88
+ width: `${skill.percentage}%`,
89
+ transition: {
90
+ duration: animationDuration,
91
+ delay: index * animationDelay,
92
+ ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number],
93
+ },
94
+ },
95
+ }
96
+
97
+ const percentageVariants = {
98
+ hidden: { opacity: 0 },
99
+ visible: {
100
+ opacity: 1,
101
+ transition: {
102
+ duration: 0.3,
103
+ delay: index * animationDelay + animationDuration * 0.8,
104
+ },
105
+ },
106
+ }
107
+
108
+ // Create unique class name from label (slugified)
109
+ const uniqueClass =
110
+ skill.id ||
111
+ skill.label
112
+ .toLowerCase()
113
+ .replace(/\s+/g, '-')
114
+ .replace(/[^a-z0-9-]/g, '')
115
+
116
+ return (
117
+ <div ref={ref} className={cn('skill-item w-full', `skill-${uniqueClass}`)}>
118
+ {/* Label and Percentage Row */}
119
+ <div className="flex justify-between items-center mb-1">
120
+ <div className={cn('text-md font-medium text-stone-700 dark:text-stone-200', labelClass)}>
121
+ {skill.label}
122
+ </div>
123
+ {skill.showPercentage !== false && (
124
+ <motion.span
125
+ className={cn(
126
+ 'text-xl font-semibold text-stone-700 dark:text-stone-200',
127
+ percentageClass,
128
+ )}
129
+ variants={percentageVariants}
130
+ initial="hidden"
131
+ animate={isInView ? 'visible' : 'hidden'}
132
+ >
133
+ {skill.percentage} %
134
+ </motion.span>
135
+ )}
136
+ </div>
137
+
138
+ {/* Progress Bar Container */}
139
+ <div className="progress-bar-container relative w-full h-1.5 bg-zinc-700/50 overflow-hidden">
140
+ <motion.div
141
+ className={cn(
142
+ 'progress-bar-fill absolute top-0 left-0 h-full',
143
+ 'bg-indigo-500',
144
+ progressBarClass,
145
+ )}
146
+ style={{
147
+ backgroundColor: skill.color || '#9ACD32',
148
+ }}
149
+ variants={progressVariants}
150
+ initial="hidden"
151
+ animate={isInView ? 'visible' : 'hidden'}
152
+ />
153
+ </div>
154
+ </div>
155
+ )
156
+ }