@nextsparkjs/ai-workflow 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: page-builder-blocks
|
|
3
|
+
description: |
|
|
4
|
+
Page builder block patterns for this Next.js application.
|
|
5
|
+
Covers block structure (5 files), baseBlockSchema, field definitions, and component patterns.
|
|
6
|
+
Use this skill when creating or modifying page builder blocks.
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Page Builder Blocks Skill
|
|
12
|
+
|
|
13
|
+
Patterns for creating and managing page builder blocks in this Next.js application.
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
contents/themes/{THEME}/blocks/
|
|
19
|
+
├── hero/ # Example block
|
|
20
|
+
│ ├── config.ts # Metadata (slug, name, category, icon)
|
|
21
|
+
│ ├── schema.ts # Zod validation (extends baseBlockSchema)
|
|
22
|
+
│ ├── fields.ts # Field definitions for admin UI
|
|
23
|
+
│ ├── component.tsx # React component
|
|
24
|
+
│ └── index.ts # Re-exports
|
|
25
|
+
├── features-grid/
|
|
26
|
+
├── cta-section/
|
|
27
|
+
└── ...
|
|
28
|
+
|
|
29
|
+
core/types/blocks.ts # Base schemas, types, helpers
|
|
30
|
+
core/lib/registries/block-registry.ts # Auto-generated registry
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## When to Use This Skill
|
|
34
|
+
|
|
35
|
+
- Creating new page builder blocks
|
|
36
|
+
- Modifying existing block schemas
|
|
37
|
+
- Adding fields to blocks
|
|
38
|
+
- Understanding block component patterns
|
|
39
|
+
- Working with BLOCK_SELECTORS
|
|
40
|
+
|
|
41
|
+
## Block Structure (5 Required Files)
|
|
42
|
+
|
|
43
|
+
Every block requires exactly 5 files in `contents/themes/{THEME}/blocks/{slug}/`:
|
|
44
|
+
|
|
45
|
+
### File 1: config.ts
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import type { BlockConfig, BlockCategory } from '@/core/types/blocks'
|
|
49
|
+
|
|
50
|
+
export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
|
|
51
|
+
slug: 'hero', // kebab-case, matches folder name
|
|
52
|
+
name: 'Hero Section', // User-facing display name
|
|
53
|
+
description: 'Full-width hero with title, subtitle, and CTA',
|
|
54
|
+
category: 'hero' as BlockCategory, // From 15 categories
|
|
55
|
+
icon: 'LayoutTemplate', // Lucide icon name
|
|
56
|
+
thumbnail: '/theme/blocks/hero/thumbnail.png', // Optional preview
|
|
57
|
+
scope: ['pages'], // 'pages', 'posts', or both
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### File 2: schema.ts
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { z } from 'zod'
|
|
65
|
+
import { baseBlockSchema } from '@/core/types/blocks'
|
|
66
|
+
|
|
67
|
+
// For array fields, define item schema first
|
|
68
|
+
const featureItemSchema = z.object({
|
|
69
|
+
icon: z.string().optional(),
|
|
70
|
+
title: z.string().min(1, 'Title is required'),
|
|
71
|
+
description: z.string().optional(),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// ALWAYS extend baseBlockSchema with .merge()
|
|
75
|
+
export const schema = baseBlockSchema.merge(z.object({
|
|
76
|
+
// ONLY custom fields here - base fields are inherited
|
|
77
|
+
features: z.array(featureItemSchema).min(1).max(12).optional(),
|
|
78
|
+
columns: z.enum(['2', '3', '4']).default('3'),
|
|
79
|
+
showIcons: z.boolean().default(true),
|
|
80
|
+
}))
|
|
81
|
+
|
|
82
|
+
export type HeroProps = z.infer<typeof schema>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**baseBlockSchema provides (DO NOT recreate):**
|
|
86
|
+
|
|
87
|
+
| Tab | Field | Type | Description |
|
|
88
|
+
|-----|-------|------|-------------|
|
|
89
|
+
| Content | `title` | string? | Section heading |
|
|
90
|
+
| Content | `content` | string? | Rich text description |
|
|
91
|
+
| Content | `cta` | object? | CTA button {text, link, target} |
|
|
92
|
+
| Design | `backgroundColor` | enum? | 10 preset colors |
|
|
93
|
+
| Advanced | `className` | string? | Custom CSS classes |
|
|
94
|
+
| Advanced | `id` | string? | HTML ID for anchors |
|
|
95
|
+
|
|
96
|
+
### File 3: fields.ts
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import type { FieldDefinition } from '@/core/types/blocks'
|
|
100
|
+
import {
|
|
101
|
+
baseContentFields,
|
|
102
|
+
baseDesignFields,
|
|
103
|
+
baseAdvancedFields,
|
|
104
|
+
} from '@/core/types/blocks'
|
|
105
|
+
|
|
106
|
+
// Custom content fields
|
|
107
|
+
const customContentFields: FieldDefinition[] = [
|
|
108
|
+
{
|
|
109
|
+
name: 'features',
|
|
110
|
+
label: 'Features',
|
|
111
|
+
type: 'array',
|
|
112
|
+
tab: 'content',
|
|
113
|
+
required: false,
|
|
114
|
+
minItems: 1,
|
|
115
|
+
maxItems: 12,
|
|
116
|
+
itemFields: [
|
|
117
|
+
{ name: 'icon', label: 'Icon', type: 'text', tab: 'content' },
|
|
118
|
+
{ name: 'title', label: 'Title', type: 'text', tab: 'content', required: true },
|
|
119
|
+
{ name: 'description', label: 'Description', type: 'textarea', tab: 'content' },
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
// Custom design fields
|
|
125
|
+
const customDesignFields: FieldDefinition[] = [
|
|
126
|
+
{
|
|
127
|
+
name: 'columns',
|
|
128
|
+
label: 'Grid Columns',
|
|
129
|
+
type: 'select',
|
|
130
|
+
tab: 'design',
|
|
131
|
+
default: '3',
|
|
132
|
+
options: [
|
|
133
|
+
{ label: '2 Columns', value: '2' },
|
|
134
|
+
{ label: '3 Columns', value: '3' },
|
|
135
|
+
{ label: '4 Columns', value: '4' },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'showIcons',
|
|
140
|
+
label: 'Show Icons',
|
|
141
|
+
type: 'checkbox',
|
|
142
|
+
tab: 'design',
|
|
143
|
+
default: true,
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
// CRITICAL: Export in correct order
|
|
148
|
+
// Content → Design → Advanced (baseAdvancedFields ALWAYS last)
|
|
149
|
+
export const fieldDefinitions: FieldDefinition[] = [
|
|
150
|
+
...baseContentFields,
|
|
151
|
+
...customContentFields,
|
|
152
|
+
...baseDesignFields,
|
|
153
|
+
...customDesignFields,
|
|
154
|
+
...baseAdvancedFields, // MUST be last
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
// Compatibility alias
|
|
158
|
+
export const fields = fieldDefinitions
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### File 4: component.tsx
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { buildSectionClasses } from '@/core/types/blocks'
|
|
165
|
+
import { sel } from '../../lib/selectors'
|
|
166
|
+
import type { HeroProps } from './schema'
|
|
167
|
+
|
|
168
|
+
export function HeroBlock({
|
|
169
|
+
// Base content props (from baseBlockSchema)
|
|
170
|
+
title,
|
|
171
|
+
content,
|
|
172
|
+
cta,
|
|
173
|
+
// Custom props
|
|
174
|
+
features = [],
|
|
175
|
+
columns = '3',
|
|
176
|
+
showIcons = true,
|
|
177
|
+
// Base design props
|
|
178
|
+
backgroundColor,
|
|
179
|
+
// Base advanced props
|
|
180
|
+
className,
|
|
181
|
+
id,
|
|
182
|
+
}: HeroProps) {
|
|
183
|
+
// Use buildSectionClasses helper (NEVER hardcode colors)
|
|
184
|
+
const sectionClasses = buildSectionClasses('py-16 px-4 md:py-24', {
|
|
185
|
+
backgroundColor,
|
|
186
|
+
className,
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
const gridCols = {
|
|
190
|
+
'2': 'grid-cols-1 md:grid-cols-2',
|
|
191
|
+
'3': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
|
192
|
+
'4': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
|
|
193
|
+
}[columns]
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<section
|
|
197
|
+
id={id}
|
|
198
|
+
className={sectionClasses}
|
|
199
|
+
data-cy={sel('blocks.hero.container')}
|
|
200
|
+
>
|
|
201
|
+
<div className="container mx-auto">
|
|
202
|
+
{title && (
|
|
203
|
+
<h2 className="text-3xl font-bold text-center mb-4">{title}</h2>
|
|
204
|
+
)}
|
|
205
|
+
{content && (
|
|
206
|
+
<div
|
|
207
|
+
className="text-center text-muted-foreground mb-8 max-w-2xl mx-auto"
|
|
208
|
+
dangerouslySetInnerHTML={{ __html: content }}
|
|
209
|
+
/>
|
|
210
|
+
)}
|
|
211
|
+
|
|
212
|
+
{features && features.length > 0 && (
|
|
213
|
+
<div className={`grid ${gridCols} gap-6`}>
|
|
214
|
+
{features.map((feature, index) => (
|
|
215
|
+
<div
|
|
216
|
+
key={index}
|
|
217
|
+
className="p-6 rounded-lg bg-card"
|
|
218
|
+
data-cy={sel('blocks.hero.feature', { index: String(index) })}
|
|
219
|
+
>
|
|
220
|
+
{showIcons && feature.icon && (
|
|
221
|
+
<span className="text-2xl mb-4 block">{feature.icon}</span>
|
|
222
|
+
)}
|
|
223
|
+
<h3 className="font-semibold mb-2">{feature.title}</h3>
|
|
224
|
+
{feature.description && (
|
|
225
|
+
<p className="text-muted-foreground">{feature.description}</p>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
))}
|
|
229
|
+
</div>
|
|
230
|
+
)}
|
|
231
|
+
|
|
232
|
+
{cta?.text && cta?.link && (
|
|
233
|
+
<div className="mt-8 text-center">
|
|
234
|
+
<a
|
|
235
|
+
href={cta.link}
|
|
236
|
+
target={cta.target || '_self'}
|
|
237
|
+
className="inline-flex items-center px-6 py-3 bg-primary text-primary-foreground rounded-md"
|
|
238
|
+
data-cy={sel('blocks.hero.cta')}
|
|
239
|
+
>
|
|
240
|
+
{cta.text}
|
|
241
|
+
</a>
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
</section>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### File 5: index.ts
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
export { config } from './config'
|
|
254
|
+
export { schema } from './schema'
|
|
255
|
+
export { fields, fieldDefinitions } from './fields'
|
|
256
|
+
export { HeroBlock as Component } from './component'
|
|
257
|
+
|
|
258
|
+
export type { HeroProps } from './schema'
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Field Types (16 Available)
|
|
262
|
+
|
|
263
|
+
| Type | Description | Additional Props |
|
|
264
|
+
|------|-------------|------------------|
|
|
265
|
+
| `text` | Single line text | `placeholder`, `maxLength` |
|
|
266
|
+
| `textarea` | Multi-line text | `rows`, `maxLength` |
|
|
267
|
+
| `url` | URL input | `placeholder` |
|
|
268
|
+
| `email` | Email input | `placeholder` |
|
|
269
|
+
| `number` | Numeric input | `min`, `max`, `step` |
|
|
270
|
+
| `select` | Dropdown | `options: [{label, value}]` |
|
|
271
|
+
| `checkbox` | Boolean toggle | - |
|
|
272
|
+
| `radio` | Radio group | `options: [{label, value}]` |
|
|
273
|
+
| `rich-text` | WYSIWYG editor | - |
|
|
274
|
+
| `image` | Image upload | `aspectRatio`, `maxSize` |
|
|
275
|
+
| `media-library` | Media Library modal | Opens full media browser with search, filter, tags, upload |
|
|
276
|
+
| `color` | Color picker | `presets` |
|
|
277
|
+
| `date` | Date picker | `format` |
|
|
278
|
+
| `time` | Time picker | `format` |
|
|
279
|
+
| `datetime` | DateTime picker | `format` |
|
|
280
|
+
| `array` | Repeatable items | `itemFields`, `minItems`, `maxItems` |
|
|
281
|
+
|
|
282
|
+
### media-library Field Type
|
|
283
|
+
|
|
284
|
+
The `media-library` field type opens the full Media Library modal instead of a basic file upload. Users can browse existing media, search, filter by type/tags, and upload new files.
|
|
285
|
+
|
|
286
|
+
**Usage in fields.ts:**
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
{
|
|
290
|
+
name: 'backgroundImage',
|
|
291
|
+
label: 'Background Image',
|
|
292
|
+
type: 'media-library',
|
|
293
|
+
tab: 'design',
|
|
294
|
+
required: false,
|
|
295
|
+
helpText: 'Optional background image (recommended: 1920x1080px)',
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**In array sub-fields:**
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
{
|
|
303
|
+
name: 'logos',
|
|
304
|
+
type: 'array',
|
|
305
|
+
itemFields: [
|
|
306
|
+
{
|
|
307
|
+
name: 'image',
|
|
308
|
+
label: 'Logo Image',
|
|
309
|
+
type: 'media-library', // Works inside arrays too
|
|
310
|
+
tab: 'content',
|
|
311
|
+
required: true,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Key behavior:**
|
|
318
|
+
- Stores URL string (not media ID) in block data
|
|
319
|
+
- Zero schema changes needed (blocks use `z.string().url()`)
|
|
320
|
+
- Empty state: dashed border with "Browse Media Library" prompt
|
|
321
|
+
- With value: image preview with Change/Remove hover overlay
|
|
322
|
+
- Both `dynamic-form.tsx` and `array-field.tsx` handle this type
|
|
323
|
+
|
|
324
|
+
**Migration from `'image'` to `'media-library'`:**
|
|
325
|
+
Simply change `type: 'image'` to `type: 'media-library'` in any block's `fields.ts`. No schema or component changes required.
|
|
326
|
+
|
|
327
|
+
## Block Categories (15)
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
type BlockCategory =
|
|
331
|
+
| 'hero' // Hero sections
|
|
332
|
+
| 'features' // Feature showcases
|
|
333
|
+
| 'cta' // Call to action
|
|
334
|
+
| 'content' // Text content
|
|
335
|
+
| 'testimonials' // Customer testimonials
|
|
336
|
+
| 'pricing' // Pricing tables
|
|
337
|
+
| 'faq' // FAQ sections
|
|
338
|
+
| 'stats' // Statistics/metrics
|
|
339
|
+
| 'gallery' // Image galleries
|
|
340
|
+
| 'timeline' // Timelines
|
|
341
|
+
| 'contact' // Contact forms
|
|
342
|
+
| 'newsletter' // Newsletter signup
|
|
343
|
+
| 'team' // Team members
|
|
344
|
+
| 'portfolio' // Portfolio items
|
|
345
|
+
| 'custom' // Custom/other
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Existing Blocks (Default Theme)
|
|
349
|
+
|
|
350
|
+
| Block | Category | Description |
|
|
351
|
+
|-------|----------|-------------|
|
|
352
|
+
| `benefits` | features | 3-column grid with colored borders |
|
|
353
|
+
| `cta-section` | cta | Title, description, buttons |
|
|
354
|
+
| `faq-accordion` | faq | Expandable accordion items |
|
|
355
|
+
| `features-grid` | features | Grid with icons, titles |
|
|
356
|
+
| `hero` | hero | Full-width hero section |
|
|
357
|
+
| `hero-with-form` | hero | Hero with lead capture form |
|
|
358
|
+
| `jumbotron` | hero | Large hero with fullscreen mode |
|
|
359
|
+
| `logo-cloud` | content | Partner/client logos |
|
|
360
|
+
| `post-content` | content | Blog post editorial styling |
|
|
361
|
+
| `pricing-table` | pricing | Pricing comparison |
|
|
362
|
+
| `split-content` | content | Two-column (image + text) |
|
|
363
|
+
| `stats-counter` | stats | Key metrics with numbers |
|
|
364
|
+
| `testimonials` | testimonials | Customer testimonials grid |
|
|
365
|
+
| `text-content` | content | Rich text paragraphs |
|
|
366
|
+
| `timeline` | timeline | Vertical/horizontal timeline |
|
|
367
|
+
| `video-hero` | hero | Hero with YouTube/Vimeo video |
|
|
368
|
+
|
|
369
|
+
## BLOCK_SELECTORS Pattern
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// contents/themes/{theme}/lib/selectors.ts
|
|
373
|
+
|
|
374
|
+
export const BLOCK_SELECTORS = {
|
|
375
|
+
hero: {
|
|
376
|
+
container: 'block-hero',
|
|
377
|
+
feature: 'hero-feature-{index}',
|
|
378
|
+
cta: 'hero-cta',
|
|
379
|
+
},
|
|
380
|
+
faqAccordion: {
|
|
381
|
+
container: 'block-faq-accordion',
|
|
382
|
+
item: 'faq-item-{index}',
|
|
383
|
+
question: 'faq-question-{index}',
|
|
384
|
+
answer: 'faq-answer-{index}',
|
|
385
|
+
},
|
|
386
|
+
featuresGrid: {
|
|
387
|
+
container: 'block-features-grid',
|
|
388
|
+
item: 'feature-item-{index}',
|
|
389
|
+
},
|
|
390
|
+
// ... add entry for each block
|
|
391
|
+
} as const
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Using selectors in components:**
|
|
395
|
+
```typescript
|
|
396
|
+
import { sel } from '../../lib/selectors'
|
|
397
|
+
|
|
398
|
+
// Static selector
|
|
399
|
+
<section data-cy={sel('blocks.hero.container')}>
|
|
400
|
+
|
|
401
|
+
// Dynamic selector with placeholder
|
|
402
|
+
<div data-cy={sel('blocks.hero.feature', { index: String(index) })}>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## BLOCK_REGISTRY
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
// core/lib/registries/block-registry.ts (AUTO-GENERATED)
|
|
409
|
+
|
|
410
|
+
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
|
|
411
|
+
hero: {
|
|
412
|
+
slug: 'hero',
|
|
413
|
+
name: 'Hero Section',
|
|
414
|
+
category: 'hero',
|
|
415
|
+
icon: 'LayoutTemplate',
|
|
416
|
+
fieldDefinitions: [...],
|
|
417
|
+
examples: [...],
|
|
418
|
+
},
|
|
419
|
+
// ...
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Rebuild registry after creating/modifying blocks:**
|
|
424
|
+
```bash
|
|
425
|
+
node core/scripts/build/registry.mjs
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## buildSectionClasses Helper
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { buildSectionClasses } from '@/core/types/blocks'
|
|
432
|
+
|
|
433
|
+
// Returns combined class string with background color and custom classes
|
|
434
|
+
const classes = buildSectionClasses('py-16 px-4', {
|
|
435
|
+
backgroundColor: 'gray-900', // Maps to bg-gray-900
|
|
436
|
+
className: 'custom-class',
|
|
437
|
+
})
|
|
438
|
+
// Output: "py-16 px-4 bg-gray-900 custom-class"
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Available background colors (10):**
|
|
442
|
+
```
|
|
443
|
+
white, gray-50, gray-100, gray-200, gray-300,
|
|
444
|
+
gray-800, gray-900, primary, secondary, accent
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Anti-Patterns
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// NEVER: Hardcode colors
|
|
451
|
+
<section className="bg-gray-900 text-white">
|
|
452
|
+
|
|
453
|
+
// CORRECT: Use buildSectionClasses with backgroundColor prop
|
|
454
|
+
<section className={buildSectionClasses('py-16', { backgroundColor })}>
|
|
455
|
+
|
|
456
|
+
// NEVER: Recreate base schema fields
|
|
457
|
+
export const schema = z.object({
|
|
458
|
+
title: z.string(), // Already in baseBlockSchema!
|
|
459
|
+
content: z.string(),
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
// CORRECT: Extend baseBlockSchema
|
|
463
|
+
export const schema = baseBlockSchema.merge(z.object({
|
|
464
|
+
// Only custom fields
|
|
465
|
+
customField: z.string(),
|
|
466
|
+
}))
|
|
467
|
+
|
|
468
|
+
// NEVER: Wrong field order in fieldDefinitions
|
|
469
|
+
export const fieldDefinitions = [
|
|
470
|
+
...baseAdvancedFields, // Wrong position!
|
|
471
|
+
...customContentFields,
|
|
472
|
+
...baseContentFields,
|
|
473
|
+
]
|
|
474
|
+
|
|
475
|
+
// CORRECT: content → design → advanced
|
|
476
|
+
export const fieldDefinitions = [
|
|
477
|
+
...baseContentFields,
|
|
478
|
+
...customContentFields,
|
|
479
|
+
...baseDesignFields,
|
|
480
|
+
...customDesignFields,
|
|
481
|
+
...baseAdvancedFields, // Always last
|
|
482
|
+
]
|
|
483
|
+
|
|
484
|
+
// NEVER: Missing data-cy selectors
|
|
485
|
+
<section className="block-container">
|
|
486
|
+
|
|
487
|
+
// CORRECT: Include data-cy
|
|
488
|
+
<section data-cy={sel('blocks.myBlock.container')}>
|
|
489
|
+
|
|
490
|
+
// NEVER: Forget to rebuild registry
|
|
491
|
+
// Block won't appear in admin UI without registry entry
|
|
492
|
+
|
|
493
|
+
// CORRECT: Always rebuild after changes
|
|
494
|
+
// node core/scripts/build/registry.mjs
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Checklist
|
|
498
|
+
|
|
499
|
+
Before finalizing a block:
|
|
500
|
+
|
|
501
|
+
- [ ] Folder name matches slug in config.ts
|
|
502
|
+
- [ ] Schema extends baseBlockSchema with .merge()
|
|
503
|
+
- [ ] Fields in correct order: content → design → advanced
|
|
504
|
+
- [ ] Component uses buildSectionClasses helper
|
|
505
|
+
- [ ] Component has data-cy selectors
|
|
506
|
+
- [ ] Block selectors added to BLOCK_SELECTORS
|
|
507
|
+
- [ ] index.ts exports all required items
|
|
508
|
+
- [ ] Registry rebuilt (`node core/scripts/build/registry.mjs`)
|
|
509
|
+
- [ ] Block appears in BLOCK_REGISTRY
|
|
510
|
+
- [ ] No hardcoded colors
|
|
511
|
+
- [ ] TypeScript compiles without errors
|
|
512
|
+
|
|
513
|
+
## Scripts
|
|
514
|
+
|
|
515
|
+
### scaffold-block.py
|
|
516
|
+
|
|
517
|
+
Generate a new block with all 5 files:
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
python .claude/skills/page-builder-blocks/scripts/scaffold-block.py
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Interactive prompts for: slug, name, description, category, icon, scope.
|
|
524
|
+
|
|
525
|
+
## Related Skills
|
|
526
|
+
|
|
527
|
+
- `cypress-selectors` - data-cy attribute patterns
|
|
528
|
+
- `shadcn-components` - UI component patterns
|
|
529
|
+
- `tailwind-theming` - CSS variable patterns
|
|
530
|
+
- `media-library` - Media Library system and components
|