@se-studio/project-build 1.0.61 → 1.0.63
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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/skills/se-marketing-sites/cms-routes-and-appshared/SKILL.md +99 -0
- package/skills/se-marketing-sites/create-collection/SKILL.md +2 -2
- package/skills/se-marketing-sites/create-component/SKILL.md +2 -2
- package/skills/se-marketing-sites/create-page/SKILL.md +86 -93
- package/skills/se-marketing-sites/lib-cms-structure/SKILL.md +67 -0
- package/skills/se-marketing-sites/register-cms-features/SKILL.md +9 -9
- package/skills/se-marketing-sites/styling-system/SKILL.md +6 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cms-routes-and-appshared
|
|
3
|
+
description: Guide for the (cms-routes) route group and appShared pattern. Use when setting up or migrating CMS-driven routing, creating new route segments, or refactoring page structure.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# CMS Routes and appShared Pattern
|
|
11
|
+
|
|
12
|
+
Reference apps: **example-se2026**, **example-brightline**.
|
|
13
|
+
|
|
14
|
+
## Route Group: (cms-routes)
|
|
15
|
+
|
|
16
|
+
All CMS-driven pages live under `src/app/(cms-routes)/`. The layout enables dynamic params:
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// layout.tsx
|
|
20
|
+
export const dynamicParams = true;
|
|
21
|
+
|
|
22
|
+
export default function CmsRoutesLayout({ children }: { children: React.ReactNode }) {
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Route Structure
|
|
28
|
+
|
|
29
|
+
| Path | File | Purpose |
|
|
30
|
+
|------|------|---------|
|
|
31
|
+
| `/` | `page.ts` | Home (slug: `index`) |
|
|
32
|
+
| `/{slug}/` | `[level1]/page.ts` | Single-level page |
|
|
33
|
+
| `/{slug1}/{slug2}/...` | `[level1]/[...slugs]/page.ts` | Multi-level pages |
|
|
34
|
+
| `/articles/` | `articles/page.ts` | Articles index (uses ARTICLES_BASE) |
|
|
35
|
+
| `/articles/{type}/` | `articles/[articleType]/page.ts` | Article type index |
|
|
36
|
+
| `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index |
|
|
37
|
+
| `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article |
|
|
38
|
+
| `/tags/`, `/tags/{tag}/` | `tags/` | Tag index (if enabled) |
|
|
39
|
+
| `/people/`, `/people/{person}/` | `people/` | People (if enabled) |
|
|
40
|
+
|
|
41
|
+
Base paths come from `@/lib/constants` (e.g. ARTICLES_BASE = `/learning-hub` or `/articles`).
|
|
42
|
+
|
|
43
|
+
## appShared Modules
|
|
44
|
+
|
|
45
|
+
Route files are thin wrappers. Logic lives in `src/appShared/`:
|
|
46
|
+
|
|
47
|
+
| Module | Exports | Used by |
|
|
48
|
+
|--------|---------|---------|
|
|
49
|
+
| `pageShared.tsx` | `generatePage`, `generatePageMetadata` | `/`, `[level1]`, `[level1]/[...slugs]` |
|
|
50
|
+
| `articleShared.tsx` | `generateArticlePage`, `generateArticleMetadata` | Article detail |
|
|
51
|
+
| `articleTypeShared.tsx` | `generateArticleTypePage`, `generateArticleTypeMetadata` | Article type index |
|
|
52
|
+
| `articleTypesIndexShared.tsx` | `generateArticleTypesIndexPage`, `generateArticleTypesIndexMetadata` | Articles index |
|
|
53
|
+
| `articleTypeTagShared.tsx` | `generateArticleTypeTagPage`, `generateArticleTypeTagMetadata` | Article type + tag index |
|
|
54
|
+
| `customTypeShared.tsx` | `generateCustomTypePage`, `generateCustomTypeMetadata` | Custom types |
|
|
55
|
+
| `personShared.tsx` | `generatePersonPage`, `generatePersonMetadata` | Person page |
|
|
56
|
+
| `tagShared.tsx` | `generateTagPage`, `generateTagMetadata` | Tag index |
|
|
57
|
+
| `tagsIndexShared.tsx` | `generateTagsIndexPage`, `generateTagsIndexMetadata` | Tags index |
|
|
58
|
+
| `teamIndexShared.tsx` | `generateTeamIndexPage`, `generateTeamIndexMetadata` | People index |
|
|
59
|
+
|
|
60
|
+
## Route Page Pattern
|
|
61
|
+
|
|
62
|
+
Each route page:
|
|
63
|
+
|
|
64
|
+
1. Exports `generateStaticParams() { return []; }` for dynamic routes
|
|
65
|
+
2. Defines `extractDetails(props)` to derive slug/path from params
|
|
66
|
+
3. Exports `generateMetadata(props, parent)` calling the shared metadata function
|
|
67
|
+
4. Exports default async function calling the shared page function
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import type { ResolvingMetadata } from 'next';
|
|
71
|
+
import { generatePage, generatePageMetadata } from '@/appShared/pageShared';
|
|
72
|
+
|
|
73
|
+
export function generateStaticParams() {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function extractDetails(props: PageProps<'/[level1]'>) {
|
|
78
|
+
const params = await props.params;
|
|
79
|
+
const { level1 } = params;
|
|
80
|
+
return { slug: level1, path: `/${level1}/` };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function generateMetadata(props: PageProps<'/[level1]'>, parent: ResolvingMetadata) {
|
|
84
|
+
const { slug, path } = await extractDetails(props);
|
|
85
|
+
return generatePageMetadata(slug, path, true, parent);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default async function (props: PageProps<'/[level1]'>) {
|
|
89
|
+
const { slug, path } = await extractDetails(props);
|
|
90
|
+
return generatePage(slug, path, true);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For article routes, use `converterContext.urlCalculators.article`, `articleType`, `articleTypeTag` from `@/lib/cms-server` to compute the path.
|
|
95
|
+
|
|
96
|
+
## See Also
|
|
97
|
+
|
|
98
|
+
- **create-page** – Creating new pages and routes
|
|
99
|
+
- **lib-cms-structure** – lib directory layout
|
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
import { SectionLinks } from '@/elements/SectionLinks';
|
|
88
88
|
import { Section } from '@/framework/Section';
|
|
89
89
|
import type { ICollection, IComponent, IContent } from '@/lib/cms';
|
|
90
|
-
import { getPreviewFieldIdProps } from '@/lib/cms';
|
|
90
|
+
import { getPreviewFieldIdProps } from '@/lib/cms-server';
|
|
91
91
|
import { getSizingInformation } from '@/lib/SizingInformation';
|
|
92
92
|
// import MyCollectionClient from './MyCollectionClient'; // If needed
|
|
93
93
|
|
|
@@ -280,4 +280,4 @@ export const MyCollectionRegistration = defineCollection({
|
|
|
280
280
|
* If a carousel/slider/filter is needed, move that logic to `[Name]Client.tsx`.
|
|
281
281
|
* Pass server-rendered cards as `children` to the client wrapper.
|
|
282
282
|
5. **Register**:
|
|
283
|
-
* Add to `
|
|
283
|
+
* Add to `collectionRegistrations` in `src/lib/registrations.ts`.
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
import { SectionLinks } from '@/elements/SectionLinks';
|
|
79
79
|
import { Section } from '@/framework/Section';
|
|
80
80
|
import type { IComponent, IContent } from '@/lib/cms';
|
|
81
|
-
import { getPreviewFieldIdProps } from '@/lib/cms';
|
|
81
|
+
import { getPreviewFieldIdProps } from '@/lib/cms-server';
|
|
82
82
|
import { getSizingInformation } from '@/lib/SizingInformation';
|
|
83
83
|
// If interactivity is needed:
|
|
84
84
|
// import MyNewComponentClient from './MyNewComponentClient';
|
|
@@ -242,4 +242,4 @@ export const MyNewRegistration = defineComponent({
|
|
|
242
242
|
* **CRITICAL**: `name` must match CMS `componentType` exactly.
|
|
243
243
|
* Provide mock data for showcase.
|
|
244
244
|
8. **Register Component**:
|
|
245
|
-
* Add to `componentRegistrations`
|
|
245
|
+
* Add to `componentRegistrations` in `src/lib/registrations.ts`.
|
|
@@ -1,134 +1,127 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-page-route
|
|
3
|
-
description: Guide for creating new Next.js App Router pages and dynamic routes in the SE Core Product framework.
|
|
3
|
+
description: Guide for creating new Next.js App Router pages and dynamic routes in the SE Core Product framework. Use when creating CMS-driven pages, adding route segments, or setting up routing.
|
|
4
4
|
license: Private
|
|
5
5
|
metadata:
|
|
6
6
|
author: se-core-product
|
|
7
|
-
version: "
|
|
7
|
+
version: "2.0.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Creating Pages and Routes
|
|
11
11
|
|
|
12
12
|
This guide explains how to create new pages and handle routing in the SE Core Product Next.js framework. The system uses Next.js App Router with Contentful-driven dynamic routing.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Reference apps: **example-se2026**, **example-brightline**.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Page Architecture
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
1. Receives the URL slug.
|
|
20
|
-
2. Fetches the page data from Contentful.
|
|
21
|
-
3. Renders the `<CmsContent>` component.
|
|
18
|
+
### 1. (cms-routes) Route Group
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
All CMS-driven pages live under `src/app/(cms-routes)/`. The layout enables dynamic params:
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
```tsx
|
|
23
|
+
// layout.tsx
|
|
24
|
+
export const dynamicParams = true;
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export async function generateStaticParams() {
|
|
31
|
-
const links = await getAllPageLinks();
|
|
32
|
-
return links
|
|
33
|
-
.filter(link => link.slug !== 'index')
|
|
34
|
-
.map(link => ({
|
|
35
|
-
slugs: link.href?.split('/').filter(Boolean)
|
|
36
|
-
}));
|
|
26
|
+
export default function CmsRoutesLayout({ children }: { children: React.ReactNode }) {
|
|
27
|
+
return children;
|
|
37
28
|
}
|
|
38
29
|
```
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
### 2. Route Structure
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
| Path | File | Purpose |
|
|
34
|
+
|------|------|---------|
|
|
35
|
+
| `/` | `page.ts` | Home (slug: `index`) |
|
|
36
|
+
| `/{slug}/` | `[level1]/page.ts` | Single-level page |
|
|
37
|
+
| `/{slug1}/{slug2}/...` | `[level1]/[...slugs]/page.ts` | Multi-level pages |
|
|
38
|
+
| `/articles/` | `articles/page.ts` | Articles index (uses ARTICLES_BASE from constants) |
|
|
39
|
+
| `/articles/{type}/` | `articles/[articleType]/page.ts` | Article type index |
|
|
40
|
+
| `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index |
|
|
41
|
+
| `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article |
|
|
42
|
+
| `/tags/`, `/tags/{tag}/` | `tags/` | Tag index (if enabled) |
|
|
43
|
+
| `/people/`, `/people/{person}/` | `people/` | People (if enabled) |
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
Base paths (e.g. `/articles` vs `/learning-hub`) come from `@/lib/constants`.
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
### 3. appShared Pattern
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
* Example: `src/app/team/[slug]/page.tsx` -> `/team/john-doe`
|
|
49
|
+
Route files are thin wrappers. Data-fetching and rendering logic lives in `src/appShared/`:
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
- `pageShared.tsx` – `generatePage`, `generatePageMetadata`
|
|
52
|
+
- `articleShared.tsx` – articles
|
|
53
|
+
- `articleTypeShared.tsx`, `articleTypesIndexShared.tsx`, `articleTypeTagShared.tsx` – article indices
|
|
54
|
+
- `customTypeShared.tsx` – custom types
|
|
55
|
+
- `personShared.tsx`, `tagShared.tsx`, `tagsIndexShared.tsx`, `teamIndexShared.tsx`
|
|
56
|
+
|
|
57
|
+
## Route Page Template
|
|
58
|
+
|
|
59
|
+
Each route page extracts params and delegates to the appropriate appShared function:
|
|
52
60
|
|
|
53
61
|
```typescript
|
|
54
|
-
import type {
|
|
55
|
-
import {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
interface PageProps {
|
|
61
|
-
params: { slug: string };
|
|
62
|
-
searchParams: { [key: string]: string | string[] | undefined };
|
|
62
|
+
import type { ResolvingMetadata } from 'next';
|
|
63
|
+
import { generatePage, generatePageMetadata } from '@/appShared/pageShared';
|
|
64
|
+
|
|
65
|
+
export function generateStaticParams() {
|
|
66
|
+
return [];
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
// 1. Fetch content
|
|
70
|
-
const response = await contentfulPageRest(
|
|
71
|
-
getContentfulConfig(isPreview),
|
|
72
|
-
slug,
|
|
73
|
-
{ preview: isPreview }
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
if (!response.data) {
|
|
77
|
-
notFound();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 2. Render content with CmsContent
|
|
81
|
-
// This automatically handles the recursive rendering of components
|
|
82
|
-
return (
|
|
83
|
-
<main>
|
|
84
|
-
<CmsContent
|
|
85
|
-
content={response.data}
|
|
86
|
-
config={projectRendererConfig}
|
|
87
|
-
contentContext={{
|
|
88
|
-
// Pass any required context
|
|
89
|
-
analyticsContext: { ... }
|
|
90
|
-
}}
|
|
91
|
-
/>
|
|
92
|
-
</main>
|
|
93
|
-
);
|
|
69
|
+
async function extractDetails(props: PageProps<'/[level1]'>) {
|
|
70
|
+
const params = await props.params;
|
|
71
|
+
const { level1 } = params;
|
|
72
|
+
return { slug: level1, path: `/${level1}/` };
|
|
94
73
|
}
|
|
95
|
-
```
|
|
96
74
|
|
|
97
|
-
|
|
75
|
+
export async function generateMetadata(props: PageProps<'/[level1]'>, parent: ResolvingMetadata) {
|
|
76
|
+
const { slug, path } = await extractDetails(props);
|
|
77
|
+
return generatePageMetadata(slug, path, true, parent);
|
|
78
|
+
}
|
|
98
79
|
|
|
99
|
-
|
|
80
|
+
export default async function (props: PageProps<'/[level1]'>) {
|
|
81
|
+
const { slug, path } = await extractDetails(props);
|
|
82
|
+
return generatePage(slug, path, true);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
100
85
|
|
|
101
|
-
|
|
102
|
-
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
|
103
|
-
const response = await contentfulPageRest(/* ... */);
|
|
104
|
-
const page = response.data;
|
|
86
|
+
For the home page (`/`), use slug `'index'` and path `'/'` directly.
|
|
105
87
|
|
|
106
|
-
|
|
88
|
+
## CmsContent Usage
|
|
107
89
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
}
|
|
90
|
+
The appShared modules render content with:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<CmsContent
|
|
94
|
+
contents={page.contents}
|
|
95
|
+
rendererConfig={projectRendererConfig}
|
|
96
|
+
pageContext={{ page }}
|
|
97
|
+
/>
|
|
114
98
|
```
|
|
115
99
|
|
|
116
|
-
|
|
100
|
+
- `contents` – array of page/article contents (not the full page object)
|
|
101
|
+
- `rendererConfig` – from `@/lib/cms-server`
|
|
102
|
+
- `pageContext` – provides page/article/customType to child components
|
|
117
103
|
|
|
118
|
-
|
|
104
|
+
## Creating a Specialized Route
|
|
119
105
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
106
|
+
For a route that behaves differently from standard CMS pages (e.g. search, dashboard):
|
|
107
|
+
|
|
108
|
+
1. Create the route under `(cms-routes)` or a separate route group.
|
|
109
|
+
2. Either create a new appShared module (if the pattern is reusable) or implement inline.
|
|
110
|
+
3. Use `getPageWithErrors`, `getArticleWithErrors`, etc. from `@/lib/cms-server`.
|
|
111
|
+
4. Use `projectRendererConfig` from `@/lib/cms-server`.
|
|
112
|
+
5. Render with `CmsContent` using `contents`, `rendererConfig`, and `pageContext`.
|
|
113
|
+
|
|
114
|
+
## Custom Layouts
|
|
115
|
+
|
|
116
|
+
If a route needs a different layout (e.g. no header/footer), create `layout.tsx` in that route directory.
|
|
129
117
|
|
|
130
118
|
## Troubleshooting
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
120
|
+
- **404 on new route**: Re-run the dev server or build after adding a dynamic route segment.
|
|
121
|
+
- **Static params missing**: Dynamic routes use `generateStaticParams() { return []; }` for on-demand rendering.
|
|
122
|
+
- **Preview mode**: Handled by `draftOnly` in `@/lib/server-config`; appShared modules use it automatically.
|
|
123
|
+
|
|
124
|
+
## See Also
|
|
125
|
+
|
|
126
|
+
- **cms-routes-and-appshared** – Full route structure and appShared pattern
|
|
127
|
+
- **lib-cms-structure** – lib directory layout and cms-server usage
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lib-cms-structure
|
|
3
|
+
description: Guide for the lib directory structure in SE Core Product CMS apps. Use when setting up lib/, migrating from contentful-config, or adding new CMS configuration.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Lib Directory Structure
|
|
11
|
+
|
|
12
|
+
Reference apps: **example-se2026**, **example-brightline**.
|
|
13
|
+
|
|
14
|
+
## File Responsibilities
|
|
15
|
+
|
|
16
|
+
| File | Client-safe? | Purpose |
|
|
17
|
+
|------|--------------|---------|
|
|
18
|
+
| `cms.ts` | Yes | Types, build maps from registrations, createConverterContext |
|
|
19
|
+
| `cms-server.ts` | No (server-only) | createAppHelpers, buildOptions, getContentfulConfig, projectRendererConfig |
|
|
20
|
+
| `client-config.ts` | Yes | isProduction, isDevelopment |
|
|
21
|
+
| `server-config.ts` | No | draftOnly, videoPrefix, baseUrl, revalidationSecret |
|
|
22
|
+
| `constants.ts` | Yes | ARTICLES_BASE, TAGS_BASE, PEOPLE_BASE, enable flags, customer name |
|
|
23
|
+
| `registrations.ts` | Yes | componentRegistrations, collectionRegistrations, externalComponentRegistrations |
|
|
24
|
+
| `SizingInformation.ts` | Yes | getSizingInformation for dynamic heading sizes |
|
|
25
|
+
|
|
26
|
+
## Server vs Client Boundary
|
|
27
|
+
|
|
28
|
+
- **cms-server.ts** has `import 'server-only'`. Never import it in `'use client'` components.
|
|
29
|
+
- **cms.ts** is client-safe: types, maps, converter context factory (no env access).
|
|
30
|
+
- **registrations.ts** imports from cms.ts and project components; keep it client-safe.
|
|
31
|
+
|
|
32
|
+
## constants.ts Shape
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
export const ARTICLES_SLUG = 'articles'; // or 'learning-hub'
|
|
36
|
+
export const TAGS_SLUG = 'tags';
|
|
37
|
+
export const PEOPLE_SLUG = 'people';
|
|
38
|
+
export const DEFAULT_TOPIC = 'other';
|
|
39
|
+
|
|
40
|
+
export const ARTICLES_BASE = `/${ARTICLES_SLUG}`;
|
|
41
|
+
export const TAGS_BASE = `/${TAGS_SLUG}`;
|
|
42
|
+
export const PEOPLE_BASE = `/${PEOPLE_SLUG}`;
|
|
43
|
+
|
|
44
|
+
export const customerName = '...';
|
|
45
|
+
export const applicationName = '...';
|
|
46
|
+
export const siteTitle = '...';
|
|
47
|
+
export const siteDescription = '...';
|
|
48
|
+
export const enablePerson = false;
|
|
49
|
+
export const enablePeopleIndex = false;
|
|
50
|
+
export const enableTag = false;
|
|
51
|
+
export const enableTagsIndex = false;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Data Flow
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
registrations.ts → cms.ts → builds maps → cms-server.ts
|
|
58
|
+
↓
|
|
59
|
+
projectRendererConfig
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Add new components/collections in `registrations.ts`. The `cms.ts` imports from it and builds the maps used by `cms-server.ts`.
|
|
63
|
+
|
|
64
|
+
## See Also
|
|
65
|
+
|
|
66
|
+
- **register-cms-features** – Adding components and collections
|
|
67
|
+
- **cms-routes-and-appshared** – Route structure and appShared
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: register-cms-features
|
|
3
|
-
description: Guide for registering new components, collections, and external integrations in the CMS configuration (src/lib/
|
|
3
|
+
description: Guide for registering new components, collections, and external integrations in the CMS configuration (src/lib/registrations.ts).
|
|
4
4
|
license: Private
|
|
5
5
|
metadata:
|
|
6
6
|
author: se-core-product
|
|
@@ -9,7 +9,7 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
# Registering CMS Features
|
|
11
11
|
|
|
12
|
-
The file `src/lib/
|
|
12
|
+
The file `src/lib/registrations.ts` is where you add new components, collections, and external components. The `cms.ts` module imports from `registrations.ts` and builds the maps used by the renderer; add new registrations in `registrations.ts`.
|
|
13
13
|
|
|
14
14
|
## How Registration Works
|
|
15
15
|
|
|
@@ -22,14 +22,14 @@ The system uses "Registration Objects" created via `defineComponent` or `defineC
|
|
|
22
22
|
## Registering a New Component
|
|
23
23
|
|
|
24
24
|
1. **Import the Registration**:
|
|
25
|
-
At the top of `src/lib/
|
|
25
|
+
At the top of `src/lib/registrations.ts`, import your component's registration export.
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
import { MyNewComponentRegistration } from '@/project/components/MyNewComponent';
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
2. **Add to `componentRegistrations`**:
|
|
32
|
-
Find the `componentRegistrations` array and add your component.
|
|
32
|
+
Find the `componentRegistrations` array in `registrations.ts` and add your component.
|
|
33
33
|
|
|
34
34
|
```typescript
|
|
35
35
|
const componentRegistrations = [
|
|
@@ -43,13 +43,13 @@ The system uses "Registration Objects" created via `defineComponent` or `defineC
|
|
|
43
43
|
|
|
44
44
|
## Registering a New Collection
|
|
45
45
|
|
|
46
|
-
1. **Import the Registration
|
|
46
|
+
1. **Import the Registration** in `src/lib/registrations.ts`:
|
|
47
47
|
|
|
48
48
|
```typescript
|
|
49
49
|
import { MyCollectionRegistration } from '@/project/collections/MyCollection';
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
2. **Add to `collectionRegistrations
|
|
52
|
+
2. **Add to `collectionRegistrations`** in `registrations.ts`:
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
55
|
const collectionRegistrations = [
|
|
@@ -61,14 +61,14 @@ The system uses "Registration Objects" created via `defineComponent` or `defineC
|
|
|
61
61
|
|
|
62
62
|
## Adding External Components
|
|
63
63
|
|
|
64
|
-
External components (like 3rd party forms or iframes) use a separate registry.
|
|
64
|
+
External components (like 3rd party forms or iframes) use a separate registry in `src/lib/registrations.ts`.
|
|
65
65
|
|
|
66
66
|
1. **Import**:
|
|
67
67
|
```typescript
|
|
68
68
|
import { MyExternalWidgetRegistration } from '@/project/externalComponents/MyExternalWidget';
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
2. **Add to `externalComponentRegistrations
|
|
71
|
+
2. **Add to `externalComponentRegistrations`** in `registrations.ts`:
|
|
72
72
|
```typescript
|
|
73
73
|
const externalComponentRegistrations = [
|
|
74
74
|
ExternalIFrameRegistration,
|
|
@@ -78,7 +78,7 @@ External components (like 3rd party forms or iframes) use a separate registry.
|
|
|
78
78
|
|
|
79
79
|
## Extending Type Definitions
|
|
80
80
|
|
|
81
|
-
If you introduce new Color names, Button variants, or other enumerations, update the type definitions in `src/lib/cms.ts
|
|
81
|
+
If you introduce new Color names, Button variants, or other enumerations, update the type definitions in `src/lib/cms.ts` (types are defined there; registrations live in `registrations.ts`):
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
84
|
export type CmsColourName = NonNullable<TypeComponentFields['backgroundColour']>['values'];
|
|
@@ -37,14 +37,18 @@ Styles are responsive and scale automatically based on the breakpoints defined i
|
|
|
37
37
|
|
|
38
38
|
### Best Practice: Dynamic Sizing
|
|
39
39
|
|
|
40
|
-
Use `getSizingInformation(index)` to dynamically assign the correct heading class based on the component's position on the page
|
|
40
|
+
Use `getSizingInformation(index)` from `@/lib/SizingInformation` to dynamically assign the correct heading class based on the component's position on the page.
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
|
+
import { getSizingInformation } from '@/lib/SizingInformation';
|
|
44
|
+
|
|
43
45
|
// Example usage in a component renderer
|
|
44
|
-
const { Element, sizingInformation } = getSizingInformation(
|
|
46
|
+
const { Element, sizingInformation } = getSizingInformation(index);
|
|
45
47
|
<Element className={sizingInformation.h1}>{title}</Element>
|
|
46
48
|
```
|
|
47
49
|
|
|
50
|
+
For embedded content (e.g. inside rich text), pass `embedded: true` as the second argument.
|
|
51
|
+
|
|
48
52
|
## Colors
|
|
49
53
|
|
|
50
54
|
Colors are defined in `colorOptions` within `tailwind.config.json`. The build system generates TypeScript helpers in `@/generated/colors` to access these colors safely.
|