blocks-dusted 0.1.8 → 0.1.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blocks-dusted",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Manifest-driven CLI for installing reusable Payload CMS blocks.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,3 @@
1
- import { writeFile } from 'node:fs/promises'
2
1
  import { copySharedFiles, copyTemplateFiles, backupExistingDestination, plannedBackupPath } from '../installers/copyTemplateFiles.js'
3
2
  import { checkDependencies } from '../installers/installDependencies.js'
4
3
  import { checkRequirements } from '../installers/checkRequirements.js'
@@ -9,11 +8,7 @@ import { packageRoot } from '../utils/paths.js'
9
8
  import { fileExists, validateTargetProject } from '../utils/project.js'
10
9
 
11
10
  const SUPPORTED_HEADERS = new Set(['HeaderDD02'])
12
- const ACTIVE_HEADER_FILES = [
13
- 'src/Header/config.ts',
14
- 'src/Header/Nav/index.tsx',
15
- 'src/Header/RowLabel.tsx',
16
- ]
11
+ const ACTIVE_HEADER_DIRECTORY = 'src/Header'
17
12
 
18
13
  export async function addHeader({ headerName, targetDirectory = process.cwd(), dryRun = false }) {
19
14
  if (!headerName) throw new Error('A header name is required. Example: blocks-dusted header add HeaderDD02 --dry-run')
@@ -31,30 +26,17 @@ export async function addHeader({ headerName, targetDirectory = process.cwd(), d
31
26
  throw new Error(`Required project files are missing:\n${missingRequired.map(formatMissingRequirement).join('\n')}`)
32
27
  }
33
28
 
34
- const activeFileChecks = await Promise.all(
35
- ACTIVE_HEADER_FILES.map(async (path) => ({ path, exists: await fileExists(`${targetDirectory}/${path}`) })),
36
- )
37
- const missingActive = activeFileChecks.filter((check) => !check.exists)
38
- if (missingActive.length > 0) {
39
- throw new Error(`Active Header files are missing:\n${missingActive.map((check) => `- ${check.path}`).join('\n')}`)
40
- }
41
-
42
- const destinationBackupPath = checks.collisions.destinationExists
43
- ? await plannedBackupPath({ destinationPath: checks.collisions.destinationPath, targetDirectory })
29
+ const activeHeaderExists = await fileExists(`${targetDirectory}/${ACTIVE_HEADER_DIRECTORY}`)
30
+ const activeHeaderBackupPath = activeHeaderExists
31
+ ? await plannedBackupPath({ destinationPath: ACTIVE_HEADER_DIRECTORY, targetDirectory })
44
32
  : null
45
- const activeBackups = await Promise.all(
46
- ACTIVE_HEADER_FILES.map(async (path) => ({
47
- path,
48
- backupPath: await plannedBackupPath({ destinationPath: path, targetDirectory }),
49
- })),
50
- )
51
33
 
52
34
  heading('Header workflow')
53
35
  info(`Name: ${manifest.name}`)
54
36
  info(`Target directory: ${targetDirectory}`)
55
37
  info(`Payload config: ${project.payloadConfigPath}`)
56
38
  info(`Source template path: ${templateDirectory}`)
57
- info(`Target install path: ${checks.collisions.destinationPath}`)
39
+ info(`Active Header path: ${ACTIVE_HEADER_DIRECTORY}`)
58
40
 
59
41
  heading(dryRun ? 'Files that would be installed' : 'Files to install')
60
42
  for (const file of manifest.files) item(`${file.from} -> ${file.to}`)
@@ -73,17 +55,13 @@ export async function addHeader({ headerName, targetDirectory = process.cwd(), d
73
55
  }
74
56
  if (dependencyChecks.missing.length > 0) item(`Install command: ${installCommandText(dependencyChecks.packageManager, dependencyChecks.missing)}`)
75
57
 
76
- heading('Active Header backups')
77
- for (const backup of activeBackups) {
78
- item(dryRun ? `Would back up ${backup.path} to ${backup.backupPath}` : `Will back up ${backup.path} to ${backup.backupPath}`)
79
- }
80
- if (destinationBackupPath) {
81
- item(dryRun ? `Would back up ${checks.collisions.destinationPath} to ${destinationBackupPath}` : `Will back up ${checks.collisions.destinationPath} to ${destinationBackupPath}`)
82
- }
58
+ heading('Active Header backup')
59
+ if (activeHeaderBackupPath) item(dryRun ? `Would back up ${ACTIVE_HEADER_DIRECTORY} to ${activeHeaderBackupPath}` : `Will back up ${ACTIVE_HEADER_DIRECTORY} to ${activeHeaderBackupPath}`)
60
+ else item('No existing src/Header directory found; a new active Header will be installed.')
83
61
 
84
- heading('Activation patches')
85
- item('Patch src/Header/Nav/index.tsx to render HeaderDD02')
86
- item('Patch src/Header/config.ts to expose HeaderDD02 fields and preserve legacy navItems as hidden data')
62
+ heading('Activation')
63
+ item('Install a complete active src/Header replacement wired to HeaderDD02.')
64
+ item('The previous Header folder is preserved as src/Header.bak, src/Header.bak.1, or the next available backup path.')
87
65
 
88
66
  if (dryRun) {
89
67
  const sharedResults = await copySharedFiles({ manifest, packageRoot, targetDirectory, dryRun: true })
@@ -95,17 +73,8 @@ export async function addHeader({ headerName, targetDirectory = process.cwd(), d
95
73
  }
96
74
 
97
75
  const sharedResults = await copySharedFiles({ manifest, packageRoot, targetDirectory })
98
-
99
- if (checks.collisions.destinationExists) {
100
- await backupExistingDestination({ destinationPath: checks.collisions.destinationPath, targetDirectory })
101
- }
102
- for (const file of ACTIVE_HEADER_FILES) {
103
- await backupExistingDestination({ destinationPath: file, targetDirectory })
104
- }
105
-
76
+ if (activeHeaderExists) await backupExistingDestination({ destinationPath: ACTIVE_HEADER_DIRECTORY, targetDirectory })
106
77
  const copiedFiles = await copyTemplateFiles({ manifest, templateDirectory, targetDirectory })
107
- await writeFile(`${targetDirectory}/src/Header/Nav/index.tsx`, renderHeaderNav())
108
- await writeFile(`${targetDirectory}/src/Header/config.ts`, renderHeaderConfig())
109
78
 
110
79
  heading('Copied files')
111
80
  copiedFiles.forEach((file) => item(file))
@@ -122,14 +91,6 @@ export async function addHeader({ headerName, targetDirectory = process.cwd(), d
122
91
  info('Header workflow complete.')
123
92
  }
124
93
 
125
- function renderHeaderNav() {
126
- return `import React from 'react'\n\nimport type { Header as HeaderType } from '@/payload-types'\n\nimport HeaderDD02 from '@/Header/variants/HeaderDD02'\n\nexport const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {\n return <HeaderDD02 data={data} />\n}\n`
127
- }
128
-
129
- function renderHeaderConfig() {
130
- return `import type { GlobalConfig } from 'payload'\n\nimport { iconPicker } from '@/fields/lucide-icon-picker/field'\nimport { link } from '@/fields/link'\nimport { HeaderDD02 } from '@/Header/variants/HeaderDD02/config'\nimport { revalidateHeader } from './hooks/revalidateHeader'\n\nexport const Header: GlobalConfig = {\n slug: 'header',\n access: {\n read: () => true,\n update: () => true,\n },\n fields: [\n {\n name: 'variant',\n label: 'Variant',\n type: 'select',\n defaultValue: 'header02',\n options: [{ label: 'Header DD 02', value: 'header02' }],\n admin: {\n position: 'sidebar',\n },\n },\n {\n name: 'header02',\n type: 'group',\n fields: HeaderDD02,\n },\n {\n name: 'navItems',\n type: 'array',\n admin: {\n hidden: true,\n description: 'Legacy starter Header navItems retained so existing stored header data is not discarded.',\n },\n fields: [\n link({ appearances: false }),\n iconPicker({\n name: 'icon',\n required: false,\n description: 'Legacy optional icon to display with the navigation item',\n }),\n ],\n },\n ],\n hooks: {\n afterChange: [revalidateHeader],\n },\n}\n`
131
- }
132
-
133
94
  function formatMissingRequirement(check) {
134
95
  const resolution = check.resolution ? `\n Resolve: ${check.resolution}` : ''
135
96
  return `- ${check.path}: ${check.reason}${resolution}`
@@ -142,4 +103,4 @@ function formatDependency(dependency) {
142
103
  function installCommandText(packageManager, dependencies) {
143
104
  const command = packageManager === 'yarn' ? ['yarn', 'add'] : packageManager === 'bun' ? ['bun', 'add'] : packageManager === 'npm' ? ['npm', 'install'] : ['pnpm', 'add']
144
105
  return [...command, ...dependencies.map(formatDependency)].join(' ')
145
- }
106
+ }
@@ -0,0 +1,9 @@
1
+ 'use client'
2
+
3
+ import type { Header as HeaderType } from '@/payload-types'
4
+
5
+ import { HeaderNav } from './Nav'
6
+
7
+ export const HeaderClient: React.FC<{ data: HeaderType }> = ({ data }) => {
8
+ return <HeaderNav data={data} />
9
+ }
@@ -0,0 +1,10 @@
1
+ import type { Header as HeaderType } from '@/payload-types'
2
+ import { getCachedGlobal } from '@/utilities/getGlobals'
3
+
4
+ import { HeaderClient } from './Component.client'
5
+
6
+ export async function Header() {
7
+ const headerData = (await getCachedGlobal('header', 1)()) as HeaderType | null
8
+
9
+ return <HeaderClient data={headerData ?? ({} as HeaderType)} />
10
+ }
@@ -0,0 +1,33 @@
1
+ import type { GlobalConfig } from 'payload'
2
+
3
+ import { HeaderDD02 } from '@/Header/variants/HeaderDD02/config'
4
+
5
+ import { revalidateHeader } from './hooks/revalidateHeader'
6
+
7
+ export const Header: GlobalConfig = {
8
+ slug: 'header',
9
+ access: {
10
+ read: () => true,
11
+ update: () => true,
12
+ },
13
+ fields: [
14
+ {
15
+ name: 'variant',
16
+ label: 'Variant',
17
+ type: 'select',
18
+ defaultValue: 'header02',
19
+ options: [{ label: 'Header DD 02', value: 'header02' }],
20
+ admin: {
21
+ position: 'sidebar',
22
+ },
23
+ },
24
+ {
25
+ name: 'header02',
26
+ type: 'group',
27
+ fields: HeaderDD02,
28
+ },
29
+ ],
30
+ hooks: {
31
+ afterChange: [revalidateHeader],
32
+ },
33
+ }