blocks-dusted 0.1.0

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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -0
  3. package/bin/index.js +8 -0
  4. package/package.json +40 -0
  5. package/src/cli.js +79 -0
  6. package/src/commands/add.js +327 -0
  7. package/src/commands/doctor.js +21 -0
  8. package/src/commands/list.js +18 -0
  9. package/src/installers/checkRequirements.js +101 -0
  10. package/src/installers/copyTemplateFiles.js +79 -0
  11. package/src/installers/installDependencies.js +69 -0
  12. package/src/installers/patchPayloadBlocksArray.js +122 -0
  13. package/src/installers/patchRenderBlocks.js +110 -0
  14. package/src/installers/runGenerators.js +3 -0
  15. package/src/installers/writeInstalledBlockReadme.js +117 -0
  16. package/src/registry/listTemplates.js +17 -0
  17. package/src/registry/loadTemplateManifest.js +20 -0
  18. package/src/registry/validateTemplateManifest.js +69 -0
  19. package/src/utils/logger.js +8 -0
  20. package/src/utils/packageManager.js +42 -0
  21. package/src/utils/paths.js +7 -0
  22. package/src/utils/project.js +122 -0
  23. package/src/utils/strings.js +7 -0
  24. package/templates/blocks/DD-BookCall/Component.tsx +573 -0
  25. package/templates/blocks/DD-BookCall/config.ts +239 -0
  26. package/templates/blocks/DD-BookCall/manifest.json +112 -0
  27. package/templates/blocks/DD-CardTemplate01/Component.tsx +144 -0
  28. package/templates/blocks/DD-CardTemplate01/config.ts +106 -0
  29. package/templates/blocks/DD-CardTemplate01/manifest.json +84 -0
  30. package/templates/blocks/DD-Carousel-A/Component.tsx +266 -0
  31. package/templates/blocks/DD-Carousel-A/config.ts +163 -0
  32. package/templates/blocks/DD-Carousel-A/manifest.json +86 -0
  33. package/templates/blocks/DD-Carousel-B/Component.tsx +432 -0
  34. package/templates/blocks/DD-Carousel-B/config.ts +176 -0
  35. package/templates/blocks/DD-Carousel-B/manifest.json +86 -0
  36. package/templates/blocks/DD-ComparisonTable/Component.tsx +272 -0
  37. package/templates/blocks/DD-ComparisonTable/config.ts +105 -0
  38. package/templates/blocks/DD-ComparisonTable/manifest.json +78 -0
  39. package/templates/blocks/DD-Contact/Component.tsx +439 -0
  40. package/templates/blocks/DD-Contact/config.ts +217 -0
  41. package/templates/blocks/DD-Contact/manifest.json +107 -0
  42. package/templates/blocks/DD-FeatCat/Component.tsx +361 -0
  43. package/templates/blocks/DD-FeatCat/config.ts +204 -0
  44. package/templates/blocks/DD-FeatCat/manifest.json +87 -0
  45. package/templates/blocks/DD-FeatStrip/Component.tsx +615 -0
  46. package/templates/blocks/DD-FeatStrip/config.ts +134 -0
  47. package/templates/blocks/DD-FeatStrip/manifest.json +82 -0
  48. package/templates/blocks/DD-Hero/Component.tsx +317 -0
  49. package/templates/blocks/DD-Hero/config.ts +267 -0
  50. package/templates/blocks/DD-Hero/manifest.json +92 -0
  51. package/templates/blocks/DD-HorizontalScroll/Component.tsx +995 -0
  52. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -0
  53. package/templates/blocks/DD-HorizontalScroll/manifest.json +85 -0
  54. package/templates/blocks/DD-MasonaryMedia/Component.tsx +571 -0
  55. package/templates/blocks/DD-MasonaryMedia/config.ts +390 -0
  56. package/templates/blocks/DD-MasonaryMedia/manifest.json +101 -0
  57. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -0
  58. package/templates/blocks/DD-Pricing/Component.tsx +380 -0
  59. package/templates/blocks/DD-Pricing/config.ts +215 -0
  60. package/templates/blocks/DD-Pricing/manifest.json +78 -0
  61. package/templates/blocks/DD-Process/Component.tsx +155 -0
  62. package/templates/blocks/DD-Process/config.ts +150 -0
  63. package/templates/blocks/DD-Process/manifest.json +82 -0
  64. package/templates/blocks/DD-Section/Component.tsx +327 -0
  65. package/templates/blocks/DD-Section/config.ts +214 -0
  66. package/templates/blocks/DD-Section/manifest.json +85 -0
  67. package/templates/blocks/DD-Services/Component.tsx +188 -0
  68. package/templates/blocks/DD-Services/config.ts +149 -0
  69. package/templates/blocks/DD-Services/manifest.json +95 -0
  70. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +317 -0
  71. package/templates/blocks/DD-ShowcaseGrid/config.ts +197 -0
  72. package/templates/blocks/DD-ShowcaseGrid/manifest.json +80 -0
  73. package/templates/blocks/DD-Slider-A/Component.tsx +252 -0
  74. package/templates/blocks/DD-Slider-A/config.ts +118 -0
  75. package/templates/blocks/DD-Slider-A/manifest.json +86 -0
  76. package/templates/blocks/DD-StackCards/Component.tsx +496 -0
  77. package/templates/blocks/DD-StackCards/config.ts +399 -0
  78. package/templates/blocks/DD-StackCards/manifest.json +87 -0
  79. package/templates/blocks/DD-Team/Component.tsx +265 -0
  80. package/templates/blocks/DD-Team/config.ts +173 -0
  81. package/templates/blocks/DD-Team/manifest.json +82 -0
  82. package/templates/blocks/DD-TechStack/Component.tsx +189 -0
  83. package/templates/blocks/DD-TechStack/config.ts +153 -0
  84. package/templates/blocks/DD-TechStack/manifest.json +118 -0
  85. package/templates/blocks/DD-Testimonials/Component.tsx +147 -0
  86. package/templates/blocks/DD-Testimonials/config.ts +120 -0
  87. package/templates/blocks/DD-Testimonials/manifest.json +87 -0
  88. package/templates/blocks/DD-Work/Component.tsx +328 -0
  89. package/templates/blocks/DD-Work/config.ts +165 -0
  90. package/templates/blocks/DD-Work/manifest.json +87 -0
  91. package/templates/blocks/DD-Work-B/Component.tsx +320 -0
  92. package/templates/blocks/DD-Work-B/config.ts +165 -0
  93. package/templates/blocks/DD-Work-B/manifest.json +75 -0
  94. package/templates/shared/components/ui/anims/fade.tsx +83 -0
  95. package/templates/shared/components/ui/button.tsx +233 -0
  96. package/templates/shared/components/ui/input.tsx +41 -0
  97. package/templates/shared/fields/lucide-icon-picker/Cell.tsx +24 -0
  98. package/templates/shared/fields/lucide-icon-picker/README.md +160 -0
  99. package/templates/shared/fields/lucide-icon-picker/field.ts +40 -0
  100. package/templates/shared/fields/lucide-icon-picker/index.tsx +203 -0
  101. package/templates/shared/utilities/canUseDOM.ts +1 -0
  102. package/templates/shared/utilities/getURL.ts +31 -0
@@ -0,0 +1,203 @@
1
+ 'use client'
2
+
3
+ import { TextFieldClientProps } from 'payload'
4
+ import { useField } from '@payloadcms/ui'
5
+ import { Button } from '@/components/ui/button'
6
+ import { Input } from '@/components/ui/input'
7
+ import { icons } from 'lucide-react'
8
+ import { useState, useMemo, useRef } from 'react'
9
+ import Fuse from 'fuse.js'
10
+ import * as LucideIcons from 'lucide-react'
11
+ import { useVirtualizer } from '@tanstack/react-virtual'
12
+
13
+ export type IconName = keyof typeof icons
14
+
15
+ const iconNames = Object.keys(icons) as IconName[]
16
+
17
+ const IconPickerField: React.FC<TextFieldClientProps> = ({ field, path }) => {
18
+ const { value, setValue } = useField<string>({ path: path || field.name })
19
+ const [open, setOpen] = useState(false)
20
+ const [search, setSearch] = useState('')
21
+
22
+ const parentRef = useRef<HTMLDivElement>(null)
23
+
24
+ // Fuzzy search setup
25
+ const fuse = useMemo(() => {
26
+ return new Fuse(iconNames, {
27
+ threshold: 0.3,
28
+ keys: ['name']
29
+ })
30
+ }, [])
31
+
32
+ // Filter icons based on search
33
+ const filteredIcons = useMemo(() => {
34
+ if (!search) return iconNames
35
+ return fuse.search(search).map((result) => result.item)
36
+ }, [search, fuse])
37
+
38
+ // Virtualization
39
+ const rowVirtualizer = useVirtualizer({
40
+ count: Math.ceil(filteredIcons.length / 6),
41
+ getScrollElement: () => parentRef.current,
42
+ estimateSize: () => 50,
43
+ overscan: 5
44
+ })
45
+
46
+ const handleSelect = (iconName: string) => {
47
+ setValue(iconName)
48
+ setOpen(false)
49
+ setSearch('')
50
+ }
51
+
52
+ const handleClear = (e: React.MouseEvent) => {
53
+ e.stopPropagation()
54
+ setValue('')
55
+ setOpen(false)
56
+ }
57
+
58
+ const Icon = value && icons[value as IconName] ? LucideIcons[value as IconName] : null
59
+
60
+ return (
61
+ <div
62
+ className="w-full"
63
+ style={{
64
+ minWidth: 'calc(50% - 1rem)',
65
+ borderRadius: '0.2rem',
66
+ paddingBottom: '1rem'
67
+ }}
68
+ >
69
+ {field.admin?.description && typeof field.admin.description === 'string' && (
70
+ <div className="text-sm text-gray-500" style={{ paddingBottom: '1rem' }}>
71
+ {field.admin.description}
72
+ </div>
73
+ )}
74
+ <div className="flex items-center gap-2" style={{ padding: '0 1rem' }}>
75
+ <Button
76
+ type="button"
77
+ onClick={() => setOpen(!open)}
78
+ className="w-auto justify-between border border-gray-300 bg-white text-gray-900 hover:bg-gray-50 cursor-pointer"
79
+ style={{ cursor: 'pointer' }}
80
+ >
81
+ {value ? (
82
+ <div
83
+ className="flex items-center gap-2"
84
+ style={{ display: 'flex', alignItems: 'center', gap: '6px' }}
85
+ >
86
+ {Icon && <Icon className="h-4 w-4" />}
87
+ <span>{value}</span>
88
+ </div>
89
+ ) : (
90
+ <span>Select Icon</span>
91
+ )}
92
+ </Button>
93
+
94
+ {/* clear icon button */}
95
+ {value && (
96
+ <Button
97
+ type="button"
98
+ size="sm"
99
+ onClick={handleClear}
100
+ className="clear-icon-button cursor-pointer"
101
+ style={{
102
+ cursor: 'pointer',
103
+ padding: '0.5rem',
104
+ background: 'transparent',
105
+ border: '0',
106
+ scale: '0.8',
107
+ top: '-0.6rem'
108
+ }}
109
+ title="Clear icon"
110
+ >
111
+ <LucideIcons.X className="h-4 w-4" />
112
+ </Button>
113
+ )}
114
+ </div>
115
+
116
+ <div
117
+ className="relative flex flex-row items-center gap-2"
118
+ style={{
119
+ display: 'flex',
120
+ justifyContent: 'center',
121
+ justifyItems: 'center',
122
+ gap: '1rem',
123
+ backgroundColor: 'var(--theme-elevation-50)',
124
+ borderRadius: '0.5rem'
125
+ // border: '1px solid var(--border-color)'
126
+ }}
127
+ >
128
+ {open && (
129
+ <div className="icon-picker-dropdown">
130
+ <Input
131
+ placeholder="Search icons..."
132
+ value={search}
133
+ onChange={(e) => setSearch(e.target.value)}
134
+ className="mb-4"
135
+ style={{
136
+ margin: '1rem 0',
137
+ position: 'relative',
138
+ width: '100%',
139
+ maxWidth: '21rem',
140
+ padding: '0.5rem',
141
+ zIndex: 50
142
+ }}
143
+ />
144
+
145
+ <div
146
+ ref={parentRef}
147
+ className="dropdown-icon-container"
148
+ style={{ maxHeight: '300px', overflowY: 'auto' }}
149
+ >
150
+ <div
151
+ style={{
152
+ height: `${rowVirtualizer.getTotalSize()}px`,
153
+ width: '100%',
154
+ position: 'relative'
155
+ }}
156
+ >
157
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => {
158
+ const startIdx = virtualRow.index * 6
159
+ const rowIcons = filteredIcons.slice(startIdx, startIdx + 6)
160
+
161
+ return (
162
+ <div
163
+ key={virtualRow.index}
164
+ style={{
165
+ position: 'relative',
166
+ top: 0,
167
+ left: 0,
168
+ width: '100%',
169
+ height: `${virtualRow.size}px`,
170
+ transform: `translateY(${virtualRow.start}px)`,
171
+ display: 'flex',
172
+ gap: '8px',
173
+ marginBottom: '-40px'
174
+ }}
175
+ className="container-fluid"
176
+ >
177
+ {rowIcons.map((iconName) => {
178
+ const IconComponent = LucideIcons[iconName]
179
+ return (
180
+ <button
181
+ key={iconName}
182
+ type="button"
183
+ onClick={() => handleSelect(iconName)}
184
+ className="flex items-center justify-center p-2 rounded hover:bg-gray-100 transition-colors group"
185
+ title={iconName}
186
+ >
187
+ <IconComponent className="h-3 w-3 transition-transform duration-200 group-hover:scale-125" />
188
+ </button>
189
+ )
190
+ })}
191
+ </div>
192
+ )
193
+ })}
194
+ </div>
195
+ </div>
196
+ </div>
197
+ )}
198
+ </div>
199
+ </div>
200
+ )
201
+ }
202
+
203
+ export default IconPickerField
@@ -0,0 +1 @@
1
+ export default !!(typeof window !== 'undefined' && window.document && window.document.createElement)
@@ -0,0 +1,31 @@
1
+ import canUseDOM from './canUseDOM'
2
+
3
+ export const getServerSideURL = () => {
4
+ let url = process.env.NEXT_PUBLIC_SERVER_URL
5
+
6
+ if (!url && process.env.VERCEL_PROJECT_PRODUCTION_URL) {
7
+ return `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
8
+ }
9
+
10
+ if (!url) {
11
+ url = 'http://localhost:3000'
12
+ }
13
+
14
+ return url
15
+ }
16
+
17
+ export const getClientSideURL = () => {
18
+ if (canUseDOM) {
19
+ const protocol = window.location.protocol
20
+ const domain = window.location.hostname
21
+ const port = window.location.port
22
+
23
+ return `${protocol}//${domain}${port ? `:${port}` : ''}`
24
+ }
25
+
26
+ if (process.env.VERCEL_PROJECT_PRODUCTION_URL) {
27
+ return `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
28
+ }
29
+
30
+ return process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000'
31
+ }