Skip to content

Commit d4c710f

Browse files
Merge pull request #322 from guillermoscript/feat/puck-vertical-template-packs
feat(puck): 5 vertical landing-page template packs
2 parents 87fc5c2 + de93b8f commit d4c710f

8 files changed

Lines changed: 1656 additions & 43 deletions

File tree

components/admin/landing-page/template-picker.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ const CATEGORY_COLORS: Record<string, string> = {
4141
creative: 'bg-violet-500/10 text-violet-600 dark:text-violet-400 border-violet-500/20',
4242
business: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20',
4343
'code-school': 'bg-sky-500/10 text-sky-600 dark:text-sky-400 border-sky-500/20',
44+
'language-school': 'bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20',
45+
fitness: 'bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20',
46+
music: 'bg-fuchsia-500/10 text-fuchsia-600 dark:text-fuchsia-400 border-fuchsia-500/20',
47+
design: 'bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20',
4448
}
4549

4650
export function TemplatePicker({ open, onClose, templates, onSelect, loading }: Props) {

lib/puck/templates/_shared.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { Data } from '@measured/puck'
2+
import { sectionSpacingDefaults } from '../utils/section-spacing'
3+
4+
export interface PuckTemplate {
5+
name: string
6+
description: string
7+
category: string
8+
puck_data: Data
9+
sort_order: number
10+
pageType: string
11+
}
12+
13+
// LMS component types that use section spacing — these get the shared
14+
// spacing defaults injected so vertical templates render with consistent
15+
// vertical rhythm without repeating the spacing props on every block.
16+
const SPACED_COMPONENTS = new Set([
17+
'FeaturesGrid', 'CourseGrid', 'TestimonialGrid', 'CtaBlock',
18+
'PricingTable', 'FaqAccordion', 'StatsCounter', 'ContactForm',
19+
'LogoCloud', 'Banner', 'TeamGrid', 'ImageGallery', 'SocialProof',
20+
])
21+
22+
// Module-level counter for stable, unique build-time IDs. Real per-instance
23+
// IDs are regenerated when a template is applied (see deepCloneWithFreshIds).
24+
let idCounter = 0
25+
26+
/** Build a Puck content node with an auto-generated id + spacing defaults. */
27+
export function c(type: string, props: Record<string, unknown>, id?: string) {
28+
const spacing = SPACED_COMPONENTS.has(type) ? sectionSpacingDefaults : {}
29+
return { type, props: { id: id || `${type}-tpl-${++idCounter}`, ...spacing, ...props } }
30+
}
31+
32+
/** Deep-clone a template's puck_data and assign fresh random IDs to all components. */
33+
export function deepCloneWithFreshIds(data: Data): Data {
34+
const cloned = JSON.parse(JSON.stringify(data)) as Data
35+
for (const item of cloned.content) {
36+
if (item.props?.id) {
37+
item.props.id = `${item.type}-${Math.random().toString(36).slice(2, 10)}`
38+
}
39+
}
40+
for (const zoneItems of Object.values(cloned.zones || {})) {
41+
for (const item of zoneItems as Array<{ type: string; props: Record<string, unknown> }>) {
42+
if (item.props?.id) {
43+
item.props.id = `${item.type}-${Math.random().toString(36).slice(2, 10)}`
44+
}
45+
}
46+
}
47+
return cloned
48+
}

lib/puck/templates/business-coaching.ts

Lines changed: 314 additions & 0 deletions
Large diffs are not rendered by default.

lib/puck/templates/design-school.ts

Lines changed: 319 additions & 0 deletions
Large diffs are not rendered by default.

lib/puck/templates/fitness-studio.ts

Lines changed: 318 additions & 0 deletions
Large diffs are not rendered by default.

lib/puck/templates/index.ts

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,14 @@
1-
import type { Data } from '@measured/puck'
2-
import { sectionSpacingDefaults } from '../utils/section-spacing'
1+
import { c, deepCloneWithFreshIds, type PuckTemplate } from './_shared'
2+
import { languageSchoolTemplates } from './language-school'
3+
import { fitnessStudioTemplates } from './fitness-studio'
4+
import { musicAcademyTemplates } from './music-academy'
5+
import { businessCoachingTemplates } from './business-coaching'
6+
import { designSchoolTemplates } from './design-school'
37

4-
export interface PuckTemplate {
5-
name: string
6-
description: string
7-
category: string
8-
puck_data: Data
9-
sort_order: number
10-
pageType: string
11-
}
12-
13-
// Counter to generate unique-per-template IDs at module level.
14-
// Fresh IDs are generated when templates are applied via deepCloneWithFreshIds().
15-
// LMS component types that use section spacing
16-
const SPACED_COMPONENTS = new Set([
17-
'FeaturesGrid', 'CourseGrid', 'TestimonialGrid', 'CtaBlock',
18-
'PricingTable', 'FaqAccordion', 'StatsCounter', 'ContactForm',
19-
'LogoCloud', 'Banner', 'TeamGrid', 'ImageGallery', 'SocialProof',
20-
])
21-
22-
let idCounter = 0
23-
function c(type: string, props: Record<string, unknown>, id?: string) {
24-
const spacing = SPACED_COMPONENTS.has(type) ? sectionSpacingDefaults : {}
25-
return { type, props: { id: id || `${type}-tpl-${++idCounter}`, ...spacing, ...props } }
26-
}
27-
28-
/** Deep-clone a template's puck_data and assign fresh random IDs to all components */
29-
export function deepCloneWithFreshIds(data: Data): Data {
30-
const cloned = JSON.parse(JSON.stringify(data)) as Data
31-
for (const item of cloned.content) {
32-
if (item.props?.id) {
33-
item.props.id = `${item.type}-${Math.random().toString(36).slice(2, 10)}`
34-
}
35-
}
36-
for (const zoneItems of Object.values(cloned.zones || {})) {
37-
for (const item of zoneItems as Array<{ type: string; props: Record<string, unknown> }>) {
38-
if (item.props?.id) {
39-
item.props.id = `${item.type}-${Math.random().toString(36).slice(2, 10)}`
40-
}
41-
}
42-
}
43-
return cloned
44-
}
8+
// Re-export shared helpers so existing importers (`@/lib/puck/templates`)
9+
// keep working unchanged.
10+
export { deepCloneWithFreshIds }
11+
export type { PuckTemplate }
4512

4613
// ─── Blank Template ──────────────────────────────────────────────────────────
4714

@@ -1136,4 +1103,10 @@ export const PUCK_TEMPLATES: PuckTemplate[] = [
11361103
codeSchoolFaqTemplate,
11371104
codeSchoolContactTemplate,
11381105
codeSchoolCatalogTemplate,
1106+
// Vertical packs (Home / About / FAQ / Contact each)
1107+
...languageSchoolTemplates,
1108+
...fitnessStudioTemplates,
1109+
...musicAcademyTemplates,
1110+
...businessCoachingTemplates,
1111+
...designSchoolTemplates,
11391112
]

0 commit comments

Comments
 (0)