blocks-dusted 0.1.1 → 0.1.3

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 (56) hide show
  1. package/README.md +967 -3
  2. package/package.json +2 -2
  3. package/src/commands/add.js +143 -45
  4. package/src/commands/list.js +2 -2
  5. package/src/installers/checkRequirements.js +1 -0
  6. package/src/installers/copyTemplateFiles.js +23 -2
  7. package/src/installers/patchPayloadConfigCollections.js +92 -0
  8. package/src/installers/writeInstalledBlockReadme.js +17 -4
  9. package/src/registry/listTemplates.js +16 -7
  10. package/src/registry/loadTemplateManifest.js +20 -11
  11. package/src/registry/validateTemplateManifest.js +6 -5
  12. package/src/utils/paths.js +7 -0
  13. package/templates/blocks/DD-BookCall/Component.tsx +535 -573
  14. package/templates/blocks/DD-CardTemplate01/Component.tsx +45 -49
  15. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -266
  16. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -432
  17. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -272
  18. package/templates/blocks/DD-Contact/Component.tsx +434 -439
  19. package/templates/blocks/DD-Contact/config.ts +8 -3
  20. package/templates/blocks/DD-FeatCat/Component.tsx +302 -361
  21. package/templates/blocks/DD-FeatCat/config.ts +201 -204
  22. package/templates/blocks/DD-FeatStrip/Component.tsx +171 -201
  23. package/templates/blocks/DD-Hero/Component.tsx +297 -317
  24. package/templates/blocks/DD-HorizontalScroll/Component.tsx +244 -303
  25. package/templates/blocks/DD-MasonaryMedia/Component.tsx +202 -228
  26. package/templates/blocks/DD-MasonaryMedia/config.ts +13 -14
  27. package/templates/blocks/DD-Pricing/Component.tsx +372 -380
  28. package/templates/blocks/DD-Process/Component.tsx +149 -155
  29. package/templates/blocks/DD-Section/Component.tsx +266 -327
  30. package/templates/blocks/DD-Services/Component.tsx +176 -188
  31. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -317
  32. package/templates/blocks/DD-Slider-A/Component.tsx +237 -252
  33. package/templates/blocks/DD-StackCards/Component.tsx +137 -160
  34. package/templates/blocks/DD-Team/Component.tsx +247 -265
  35. package/templates/blocks/DD-TechStack/Component.tsx +57 -72
  36. package/templates/blocks/DD-Testimonials/Component.tsx +147 -147
  37. package/templates/blocks/DD-Testimonials/config.ts +66 -66
  38. package/templates/blocks/DD-Work/Component.tsx +315 -328
  39. package/templates/blocks/DD-Work-B/Component.tsx +294 -320
  40. package/templates/collections/Testimonials/README.md +11 -0
  41. package/templates/collections/Testimonials/Testimonials.ts +161 -0
  42. package/templates/collections/Testimonials/manifest.json +55 -0
  43. package/templates/components/HeaderDD02/MobileBottomNav/index.tsx +545 -0
  44. package/templates/components/HeaderDD02/README.md +45 -0
  45. package/templates/components/HeaderDD02/RowLabel.tsx +33 -0
  46. package/templates/components/HeaderDD02/config.ts +302 -0
  47. package/templates/components/HeaderDD02/index.tsx +517 -0
  48. package/templates/components/HeaderDD02/manifest.json +123 -0
  49. package/templates/components/RichText/README.md +13 -0
  50. package/templates/components/RichText/converter/componentConverter/blocks.tsx +43 -0
  51. package/templates/components/RichText/converter/componentConverter/types.ts +11 -0
  52. package/templates/components/RichText/converter/index.tsx +18 -0
  53. package/templates/components/RichText/converter/internalLinks.tsx +45 -0
  54. package/templates/components/RichText/converter/textConverter.tsx +27 -0
  55. package/templates/components/RichText/index.tsx +35 -0
  56. package/templates/components/RichText/manifest.json +80 -0
@@ -0,0 +1,43 @@
1
+ import type React from 'react'
2
+ import type { SerializedBlockNode } from '@payloadcms/richtext-lexical'
3
+
4
+ import { BannerBlock } from '@/blocks/Banner/Component'
5
+ import { CodeBlock } from '@/blocks/Code/Component'
6
+ import { MediaBlock } from '@/blocks/MediaBlock/Component'
7
+ import type { CodeBlockProps } from '@/blocks/Code/Component'
8
+ import type {
9
+ BannerBlock as BannerBlockProps,
10
+ MediaBlock as MediaBlockProps,
11
+ } from '@/payload-types'
12
+
13
+ type BlockConverter<T> = (props: { node?: SerializedBlockNode<T> }) => React.ReactNode
14
+
15
+ const banner: BlockConverter<BannerBlockProps> = ({ node }) => {
16
+ if (!node?.fields) return null
17
+ return <BannerBlock className="col-start-2 mb-4" {...node.fields} />
18
+ }
19
+
20
+ const mediaBlock: BlockConverter<MediaBlockProps> = ({ node }) => {
21
+ if (!node?.fields) return null
22
+ return (
23
+ <MediaBlock
24
+ className="col-start-1 col-span-3"
25
+ imgClassName="m-0"
26
+ {...node.fields}
27
+ captionClassName="mx-auto max-w-[48rem]"
28
+ enableGutter={false}
29
+ disableInnerContainer={true}
30
+ />
31
+ )
32
+ }
33
+
34
+ const code: BlockConverter<CodeBlockProps> = ({ node }) => {
35
+ if (!node?.fields) return null
36
+ return <CodeBlock className="col-start-2" {...node.fields} />
37
+ }
38
+
39
+ export const blockConverters = {
40
+ banner,
41
+ mediaBlock,
42
+ code,
43
+ }
@@ -0,0 +1,11 @@
1
+ import type { DefaultNodeTypes, SerializedBlockNode } from '@payloadcms/richtext-lexical'
2
+
3
+ import type { CodeBlockProps } from '@/blocks/Code/Component'
4
+ import type {
5
+ BannerBlock as BannerBlockProps,
6
+ MediaBlock as MediaBlockProps,
7
+ } from '@/payload-types'
8
+
9
+ export type RichTextEmbeddedBlock = BannerBlockProps | MediaBlockProps | CodeBlockProps
10
+
11
+ export type NodeTypes = DefaultNodeTypes | SerializedBlockNode<RichTextEmbeddedBlock>
@@ -0,0 +1,18 @@
1
+ import {
2
+ JSXConvertersFunction,
3
+ LinkJSXConverter,
4
+ } from '@payloadcms/richtext-lexical/react'
5
+
6
+ import { internalDocToHref } from '@/components/RichText/converter/internalLinks'
7
+ import { textConverter } from '@/components/RichText/converter/textConverter'
8
+ import { blockConverters } from '@/components/RichText/converter/componentConverter/blocks'
9
+ import type { NodeTypes } from '@/components/RichText/converter/componentConverter/types'
10
+
11
+ export type { NodeTypes } from '@/components/RichText/converter/componentConverter/types'
12
+
13
+ export const jsxConverters: JSXConvertersFunction<NodeTypes> = ({ defaultConverters }) => ({
14
+ ...defaultConverters,
15
+ ...LinkJSXConverter({ internalDocToHref }),
16
+ ...textConverter,
17
+ blocks: blockConverters,
18
+ })
@@ -0,0 +1,45 @@
1
+ import type { SerializedLinkNode } from '@payloadcms/richtext-lexical'
2
+
3
+ type LinkedDocument = {
4
+ slug?: string | null
5
+ breadcrumbs?: Array<{
6
+ slug?: string | null
7
+ url?: string | null
8
+ }> | null
9
+ }
10
+
11
+ const pagePathFromDoc = (value: LinkedDocument): string => {
12
+ const crumbs = Array.isArray(value.breadcrumbs) ? value.breadcrumbs : []
13
+ const lastCrumb = crumbs[crumbs.length - 1]
14
+
15
+ if (typeof lastCrumb?.url === 'string' && lastCrumb.url) return lastCrumb.url
16
+
17
+ const segments = crumbs
18
+ .map((crumb) => (typeof crumb?.slug === 'string' ? crumb.slug : ''))
19
+ .filter(Boolean)
20
+
21
+ if (segments.length > 0) return `/${segments.join('/')}`
22
+
23
+ const slug = typeof value.slug === 'string' ? value.slug : ''
24
+ if (!slug || slug === 'home') return '/'
25
+ return `/${slug.replace(/^\/+/, '')}`
26
+ }
27
+
28
+ export const internalDocToHref = ({ linkNode }: { linkNode: SerializedLinkNode }) => {
29
+ const doc = linkNode.fields.doc
30
+ const relationTo = doc?.relationTo
31
+ const value = doc?.value
32
+
33
+ if (!relationTo || typeof value !== 'object' || value === null) return '#'
34
+
35
+ switch (relationTo) {
36
+ case 'pages':
37
+ return pagePathFromDoc(value as LinkedDocument)
38
+ case 'posts': {
39
+ const slug = (value as LinkedDocument).slug
40
+ return typeof slug === 'string' && slug ? `/posts/${slug}` : '#'
41
+ }
42
+ default:
43
+ return '#'
44
+ }
45
+ }
@@ -0,0 +1,27 @@
1
+ import type React from 'react'
2
+ import type { SerializedTextNode } from '@payloadcms/richtext-lexical'
3
+ import type { JSXConverters } from '@payloadcms/richtext-lexical/react'
4
+
5
+ const IS_BOLD = 1
6
+ const IS_ITALIC = 2
7
+ const IS_STRIKETHROUGH = 4
8
+ const IS_UNDERLINE = 8
9
+ const IS_CODE = 16
10
+ const IS_SUBSCRIPT = 32
11
+ const IS_SUPERSCRIPT = 64
12
+
13
+ export const textConverter: JSXConverters<SerializedTextNode> = {
14
+ text: ({ node }) => {
15
+ let output: React.ReactNode = node.text
16
+
17
+ if (node.format & IS_BOLD) output = <strong>{output}</strong>
18
+ if (node.format & IS_ITALIC) output = <em>{output}</em>
19
+ if (node.format & IS_STRIKETHROUGH) output = <s>{output}</s>
20
+ if (node.format & IS_UNDERLINE) output = <u>{output}</u>
21
+ if (node.format & IS_CODE) output = <code>{output}</code>
22
+ if (node.format & IS_SUBSCRIPT) output = <sub>{output}</sub>
23
+ if (node.format & IS_SUPERSCRIPT) output = <sup>{output}</sup>
24
+
25
+ return output
26
+ },
27
+ }
@@ -0,0 +1,35 @@
1
+ import type React from 'react'
2
+ import { type DefaultTypedEditorState } from '@payloadcms/richtext-lexical'
3
+ import { RichText as ConvertRichText } from '@payloadcms/richtext-lexical/react'
4
+
5
+ import { jsxConverters } from '@/components/RichText/converter'
6
+ import { cn } from '@/utilities/ui'
7
+
8
+ type Props = {
9
+ data?: DefaultTypedEditorState | null
10
+ enableGutter?: boolean
11
+ enableProse?: boolean
12
+ } & React.HTMLAttributes<HTMLDivElement>
13
+
14
+ export default function RichText(props: Props) {
15
+ const { className, enableProse = true, enableGutter = true, data, ...rest } = props
16
+
17
+ if (!data) return null
18
+
19
+ return (
20
+ <ConvertRichText
21
+ converters={jsxConverters}
22
+ data={data}
23
+ className={cn(
24
+ 'payload-richtext',
25
+ {
26
+ container: enableGutter,
27
+ 'max-w-none': !enableGutter,
28
+ 'mx-auto prose md:prose-md dark:prose-invert': enableProse,
29
+ },
30
+ className,
31
+ )}
32
+ {...rest}
33
+ />
34
+ )
35
+ }
@@ -0,0 +1,80 @@
1
+ {
2
+ "type": "component",
3
+ "name": "RichText",
4
+ "label": "Payload RichText Dusted Standard",
5
+ "slug": "RichText",
6
+ "version": "0.0.1",
7
+ "source": {
8
+ "defaultPath": "src/components/RichText/index.tsx",
9
+ "referencePath": "Raw Dusted Blocks/dusted-src (to add into CLI)/src/components/RichText"
10
+ },
11
+ "files": [
12
+ {
13
+ "from": "index.tsx",
14
+ "to": "src/components/RichText/index.tsx"
15
+ },
16
+ {
17
+ "from": "converter/index.tsx",
18
+ "to": "src/components/RichText/converter/index.tsx"
19
+ },
20
+ {
21
+ "from": "converter/internalLinks.tsx",
22
+ "to": "src/components/RichText/converter/internalLinks.tsx"
23
+ },
24
+ {
25
+ "from": "converter/textConverter.tsx",
26
+ "to": "src/components/RichText/converter/textConverter.tsx"
27
+ },
28
+ {
29
+ "from": "converter/componentConverter/blocks.tsx",
30
+ "to": "src/components/RichText/converter/componentConverter/blocks.tsx"
31
+ },
32
+ {
33
+ "from": "converter/componentConverter/types.ts",
34
+ "to": "src/components/RichText/converter/componentConverter/types.ts"
35
+ }
36
+ ],
37
+ "dependencies": [
38
+ {
39
+ "name": "@payloadcms/richtext-lexical"
40
+ }
41
+ ],
42
+ "requiredProjectFiles": [
43
+ {
44
+ "path": "src/utilities/ui.ts",
45
+ "reason": "RichText uses cn from @/utilities/ui."
46
+ },
47
+ {
48
+ "path": "src/blocks/Banner/Component.tsx",
49
+ "reason": "Default Payload RichText embedded block mapping for banner."
50
+ },
51
+ {
52
+ "path": "src/blocks/Code/Component.tsx",
53
+ "reason": "Default Payload RichText embedded block mapping for code."
54
+ },
55
+ {
56
+ "path": "src/blocks/MediaBlock/Component.tsx",
57
+ "reason": "Default Payload RichText embedded block mapping for mediaBlock."
58
+ }
59
+ ],
60
+ "optionalProjectFiles": [
61
+ {
62
+ "path": "src/collections/Posts/index.ts",
63
+ "reason": "Inspect RichText editor features and embedded BlocksFeature configuration before installing."
64
+ }
65
+ ],
66
+ "manual": [
67
+ "The existing src/components/RichText folder is backed up before installation; review the backup and copy any project-specific behaviour missing from the newly installed RichText structure.",
68
+ "Install this component only after inspecting the target project\u0027s RichText editor configuration.",
69
+ "This default template maps only the Payload starter embedded RichText blocks: banner, code, and mediaBlock.",
70
+ "Add cta or other block mappings only if the target RichText field\u0027s BlocksFeature actually enables those blocks.",
71
+ "Keep internal link routes aligned with the target project\u0027s real pages/posts routes.",
72
+ "Run the target project\u0027s Payload type-generation command if generated types are stale.",
73
+ "Run formatter, linter, TypeScript, and build checks after installation."
74
+ ],
75
+ "notes": [
76
+ "This is a Layer 2 reusable core component template, not a Payload block template.",
77
+ "Do not copy reference-project preview-link-card, custom media, custom color state, or non-starter block mappings into default Payload installs."
78
+ ],
79
+ "backupExistingDestination": true
80
+ }