@se-studio/skills 1.0.1
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 +7 -0
- package/package.json +25 -0
- package/skills/contentful-cms-alt-text-audit/SKILL.md +60 -0
- package/skills/contentful-cms-cms-guidelines/README.md +166 -0
- package/skills/contentful-cms-cms-guidelines/colour-hint-prompt.md +77 -0
- package/skills/contentful-cms-cms-guidelines/evaluation-prompt.md +84 -0
- package/skills/contentful-cms-cms-guidelines/generate-component-guidelines.md +126 -0
- package/skills/contentful-cms-cms-guidelines/generation-prompt.md +231 -0
- package/skills/contentful-cms-cms-guidelines/html-component-authoring.md +401 -0
- package/skills/contentful-cms-cms-guidelines/validation-prompt.md +170 -0
- package/skills/contentful-cms-cms-guidelines/variant-loop.md +189 -0
- package/skills/contentful-cms-cms-guidelines/variant-proposal-prompt.md +131 -0
- package/skills/contentful-cms-core/SKILL.md +793 -0
- package/skills/contentful-cms-generate-all-guidelines/SKILL.md +313 -0
- package/skills/contentful-cms-generate-cms-guidelines/SKILL.md +313 -0
- package/skills/contentful-cms-image-guide/SKILL.md +240 -0
- package/skills/contentful-cms-navigation/SKILL.md +23 -0
- package/skills/contentful-cms-rich-text/SKILL.md +96 -0
- package/skills/contentful-cms-schema-org/SKILL.md +74 -0
- package/skills/contentful-cms-screenshots/SKILL.md +46 -0
- package/skills/contentful-cms-seo-descriptions/SKILL.md +54 -0
- package/skills/contentful-cms-templates/SKILL.md +21 -0
- package/skills/contentful-cms-update-cms-guidelines/SKILL.md +348 -0
- package/skills/performance-audit/SKILL.md +344 -0
- package/skills/se-marketing-sites-cms-routes-and-appshared/SKILL.md +99 -0
- package/skills/se-marketing-sites-create-collection/SKILL.md +295 -0
- package/skills/se-marketing-sites-create-component/SKILL.md +250 -0
- package/skills/se-marketing-sites-create-page/SKILL.md +183 -0
- package/skills/se-marketing-sites-curate-showcase-mocks/SKILL.md +344 -0
- package/skills/se-marketing-sites-handling-media/SKILL.md +195 -0
- package/skills/se-marketing-sites-lib-cms-structure/SKILL.md +83 -0
- package/skills/se-marketing-sites-register-cms-features/SKILL.md +95 -0
- package/skills/se-marketing-sites-styling-system/SKILL.md +122 -0
- package/skills/site-workflows-brand-context-builder/SKILL.md +98 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handling-media
|
|
3
|
+
description: Guide for using images, videos, and animations in marketing sites using the ResponsiveVisual and VisualComponent systems.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Handling Media
|
|
11
|
+
|
|
12
|
+
This project uses a unified media system to handle images, videos, and animations efficiently.
|
|
13
|
+
|
|
14
|
+
## Core Components
|
|
15
|
+
|
|
16
|
+
### 1. `ResponsiveVisual` (or `VisualComponent`)
|
|
17
|
+
|
|
18
|
+
This is the main component for rendering media from Contentful. It handles:
|
|
19
|
+
* Responsive image sources (desktop/mobile).
|
|
20
|
+
* Format optimization (WebP/AVIF).
|
|
21
|
+
* Video auto-play/looping.
|
|
22
|
+
* Lottie animations.
|
|
23
|
+
* Lazy loading & Priority hints.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import VisualComponent from '@/framework/VisualComponent';
|
|
27
|
+
// or
|
|
28
|
+
import { Visual } from '@se-studio/core-ui';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage Pattern
|
|
32
|
+
|
|
33
|
+
### Basic Usage
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
<VisualComponent
|
|
37
|
+
visual={field.visual}
|
|
38
|
+
className="w-full h-auto"
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Responsive Sizing (`visualSizes`)
|
|
43
|
+
|
|
44
|
+
You **MUST** provide `visualSizes` to ensure the browser loads the correct image size. This uses the `sizes` attribute.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { calculateVisualSizes } from '@se-studio/core-ui';
|
|
48
|
+
|
|
49
|
+
// Example: Full width on mobile, 50% width on laptop
|
|
50
|
+
const sizes = calculateVisualSizes(1, { laptop: 0.5 });
|
|
51
|
+
|
|
52
|
+
<VisualComponent
|
|
53
|
+
visual={visual}
|
|
54
|
+
visualSizes={sizes}
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
* `1`: 100vw (Mobile default)
|
|
59
|
+
* `laptop: 0.5`: 50vw (Laptop breakpoint)
|
|
60
|
+
|
|
61
|
+
### visualSizes Must Mirror Col-Span
|
|
62
|
+
|
|
63
|
+
`visualSizes` **must** match the visual's layout (col-span, container width). The browser uses these values to pick the right image size.
|
|
64
|
+
|
|
65
|
+
* **Rule**: `col-span-N` in a 12-col grid → use `N/12` (e.g. 6 cols → 0.5, 5 cols → 5/12).
|
|
66
|
+
* **Full width** (`col-span-full`) → use `1`.
|
|
67
|
+
* **First arg** = mobile/default; breakpoint keys (`laptop`, `tablet`, `desktop`) = that breakpoint.
|
|
68
|
+
* **Common mistake**: Reversing mobile vs laptop. If mobile is full width and laptop is smaller, use `(1, { laptop: 0.5 })`, **not** `(0.5, { laptop: 1 })`.
|
|
69
|
+
* **Fixed-size icons** (~96–128px): use small ratios like `0.2`–`0.25`; **never** use values > 1 (e.g. `(100)` is invalid and causes massive over-fetch).
|
|
70
|
+
* **Example table**:
|
|
71
|
+
|
|
72
|
+
| Layout | visualSizes |
|
|
73
|
+
|--------|-------------|
|
|
74
|
+
| Full width | `(1)` |
|
|
75
|
+
| 6 cols on laptop, full on mobile | `(1, { laptop: 0.5 })` |
|
|
76
|
+
| 5 cols on laptop, full on mobile | `(1, { laptop: 5/12 })` |
|
|
77
|
+
| 2 cols in 12 on laptop, half on mobile | `(0.5, { laptop: 2/12 })` |
|
|
78
|
+
| Small icon (~96px) | `(0.25)` |
|
|
79
|
+
|
|
80
|
+
### CMS Width & Position (`widthPercent`, `horizontalPosition`)
|
|
81
|
+
|
|
82
|
+
Visuals in Contentful can have a `widthPercent` (e.g. 50%) and `horizontalPosition` (Left / Middle / Right). These control how wide the visual renders on laptop+ and where it aligns within its container. **How these fields are applied depends on the component rendering the visual.**
|
|
83
|
+
|
|
84
|
+
**Key principle**: The `Visual` component is a "fill my container" renderer — it does **not** apply width constraints itself. Width and position are always the responsibility of the wrapping component.
|
|
85
|
+
|
|
86
|
+
#### Which components handle it automatically
|
|
87
|
+
|
|
88
|
+
* **`VisualComponent`** (framework, `@/framework/VisualComponent`): Handles `widthPercent` and `horizontalPosition` in both embedded and non-embedded modes. Also adjusts `visualSizes` so the browser fetches an appropriately sized image.
|
|
89
|
+
* **`ResponsiveVisual`** (core-ui): Wraps the `Visual` in a div that applies `--image-width` and horizontal positioning. Components using `ResponsiveVisual` get this for free.
|
|
90
|
+
|
|
91
|
+
#### Custom components using `Visual` directly
|
|
92
|
+
|
|
93
|
+
If your component renders `Visual` directly and the visual may have a `widthPercent`, you must handle it yourself:
|
|
94
|
+
|
|
95
|
+
1. **Wrap in a positioning div** using helpers from `core-ui`:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { getVisualWidthPercent } from '@se-studio/core-data-types';
|
|
99
|
+
import {
|
|
100
|
+
calculateHorizontalPositionClassName,
|
|
101
|
+
calculateImageWidthStyleVariable,
|
|
102
|
+
calculateVisualSizes,
|
|
103
|
+
Visual,
|
|
104
|
+
cn,
|
|
105
|
+
} from '@se-studio/core-ui';
|
|
106
|
+
|
|
107
|
+
const imageWidthStyle = calculateImageWidthStyleVariable(visual);
|
|
108
|
+
const imageHorizontalPosition = imageWidthStyle
|
|
109
|
+
? calculateHorizontalPositionClassName(visual)
|
|
110
|
+
: undefined;
|
|
111
|
+
|
|
112
|
+
<div
|
|
113
|
+
className={cn(
|
|
114
|
+
'w-full',
|
|
115
|
+
imageHorizontalPosition,
|
|
116
|
+
imageWidthStyle && 'laptop:w-(--image-width)',
|
|
117
|
+
)}
|
|
118
|
+
style={imageWidthStyle}
|
|
119
|
+
>
|
|
120
|
+
<Visual visual={visual} visualSizes={visualSizes} />
|
|
121
|
+
</div>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
2. **Factor width into `visualSizes`** so the browser doesn't over-fetch:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const widthPercent = getVisualWidthPercent(visual);
|
|
128
|
+
const laptopRatio = widthPercent ? widthPercent / 100 : undefined;
|
|
129
|
+
const visualSizes = laptopRatio
|
|
130
|
+
? calculateVisualSizes(1, { laptop: laptopRatio })
|
|
131
|
+
: calculateVisualSizes(1);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Collections with multiple visuals
|
|
135
|
+
|
|
136
|
+
Collections like `SeparatedVisualsCollection` may interpret `widthPercent` differently — as relative proportions between visuals rather than absolute percentages. The collection controls the layout and passes the computed slot width to `visualSizes`. Don't apply the standard wrapper pattern blindly in collections; match `visualSizes` to the actual rendered slot width.
|
|
137
|
+
|
|
138
|
+
### LCP Optimization (`calculateImagePriority`)
|
|
139
|
+
|
|
140
|
+
For the Hero component (or whatever is at the top of the page), you must prioritize the image load to improve LCP (Largest Contentful Paint).
|
|
141
|
+
|
|
142
|
+
Use `calculateImagePriority(index)` where `index` is the component's position on the page.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { calculateImagePriority } from '@se-studio/core-ui';
|
|
146
|
+
|
|
147
|
+
<VisualComponent
|
|
148
|
+
visual={visual}
|
|
149
|
+
{...calculateImagePriority(index)}
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
If `index` is `0`, this sets `priority={true}` (or `fetchPriority="high"`). If `index > 0`, it defaults to lazy loading.
|
|
154
|
+
|
|
155
|
+
### Analytics Tracking
|
|
156
|
+
|
|
157
|
+
Pass `componentLabel` (usually `cmsLabel`) and `analyticsContext` to enable click tracking on media elements (if they are linked).
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
<VisualComponent
|
|
161
|
+
visual={visual}
|
|
162
|
+
componentLabel={cmsLabel}
|
|
163
|
+
analyticsContext={contentContext.analyticsContext}
|
|
164
|
+
/>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Media Types
|
|
168
|
+
|
|
169
|
+
The `IResponsiveVisual` type (from `@se-studio/core-data-types`) supports:
|
|
170
|
+
|
|
171
|
+
1. **Image**: Standard Contentful image asset.
|
|
172
|
+
2. **Video**: Hosted video file (mp4/webm). The component handles `<video>` tag rendering with autoplay/loop/muted attributes suitable for background videos.
|
|
173
|
+
3. **Animation**: Lottie JSON file. Renders using a Lottie player.
|
|
174
|
+
|
|
175
|
+
The component automatically detects the type and renders the appropriate element.
|
|
176
|
+
|
|
177
|
+
## Mobile Specific Visuals
|
|
178
|
+
|
|
179
|
+
Contentful models often support a separate `mobileVisual` field. The `VisualComponent` handles switching between them using `<picture>` tags or CSS media queries internally.
|
|
180
|
+
|
|
181
|
+
You typically pass the combined object or handle it via props if the component exposes both:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// If your component merges them into one responsive object before rendering:
|
|
185
|
+
<VisualComponent visual={combinedVisual} />
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Or if using raw fields:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
<VisualComponent
|
|
192
|
+
visual={visual}
|
|
193
|
+
mobileVisual={mobileVisual}
|
|
194
|
+
/>
|
|
195
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
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**, **example-om1**.
|
|
13
|
+
|
|
14
|
+
## File Responsibilities
|
|
15
|
+
|
|
16
|
+
| File | Client-safe? | Purpose |
|
|
17
|
+
|------|--------------|---------|
|
|
18
|
+
| `cms.ts` | Yes | Types, buildComponentRecord / buildCollectionRecord / buildExternalRecord (array → Record), then build*Maps from those Records, createConverterContext |
|
|
19
|
+
| `cms-server.ts` | No (server-only) | createAppHelpers, buildOptions, getContentfulConfig, projectRendererConfig |
|
|
20
|
+
| `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 | componentRegistrationsList, collectionRegistrationsList, externalComponentRegistrationsList (arrays) |
|
|
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 (*RegistrationsList arrays)
|
|
58
|
+
→ cms.ts (build*Record from arrays, then build*Maps)
|
|
59
|
+
→ builds maps → cms-server.ts
|
|
60
|
+
↓
|
|
61
|
+
projectRendererConfig
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Add new components/collections to the appropriate *RegistrationsList array in `registrations.ts`. The `cms.ts` imports those arrays, builds Records via `buildComponentRecord` / `buildCollectionRecord` / `buildExternalRecord` (which enforce that every CMS type has a registration), then builds the maps used by `cms-server.ts`.
|
|
65
|
+
|
|
66
|
+
## Circular Dependency: Do Not Import cms-server in Components/Collections
|
|
67
|
+
|
|
68
|
+
Components and collections in the registration chain (imported by `registrations.ts`) must **not** import from `cms-server` directly. Doing so creates a circular dependency (cms-server → cms → registrations → components → cms-server) that causes TDZ errors during RSC serialization.
|
|
69
|
+
|
|
70
|
+
**Instead**, use the helpers from `@se-studio/core-ui`:
|
|
71
|
+
|
|
72
|
+
- `getPreviewFieldProps(rendererConfig, id, fieldId)` – for field preview props
|
|
73
|
+
- `getPreviewResponsiveVisualFieldProps(rendererConfig, id, visualFieldId, mobileVisualFieldId)` – for responsive visuals
|
|
74
|
+
- `rendererConfig.previewHelpers?.getPreviewParentProps?.(information)`
|
|
75
|
+
- `rendererConfig.fetchHelpers?.getAllArticleLinks?.()`
|
|
76
|
+
- `rendererConfig.fetchHelpers?.getRelatedArticles?.(information, contentContext, count)`
|
|
77
|
+
|
|
78
|
+
These are passed via `projectRendererConfig` in `cms-server.ts`. `Section` and `SectionLinks` accept `previewHelpers` / `rendererConfig` props. See `docs/SERVER_CLIENT_BOUNDARIES.md`.
|
|
79
|
+
|
|
80
|
+
## See Also
|
|
81
|
+
|
|
82
|
+
- **register-cms-features** – Adding components and collections
|
|
83
|
+
- **cms-routes-and-appshared** – Route structure and appShared
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: register-cms-features
|
|
3
|
+
description: Guide for registering new components, collections, and external integrations in the CMS configuration (src/lib/registrations.ts).
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Registering CMS Features
|
|
11
|
+
|
|
12
|
+
The file `src/lib/registrations.ts` is where you add new components, collections, and external components. It exports three **arrays** (not Records): `componentRegistrationsList`, `collectionRegistrationsList`, `externalComponentRegistrationsList`. The **name is defined only in each registration** (in the `defineComponent` / `defineCollection` / `defineExternalComponent` call). The `cms.ts` module imports these arrays, uses `buildComponentRecord` / `buildCollectionRecord` / `buildExternalRecord` to build Records keyed by `name` (with exhaustiveness checks), then passes those Records to the core-ui build*Maps helpers. Add new registrations to the appropriate *List array in `registrations.ts`.
|
|
13
|
+
|
|
14
|
+
## How Registration Works
|
|
15
|
+
|
|
16
|
+
The system uses registration objects created via `defineComponent`, `defineCollection`, or `defineExternalComponent` (from `@/lib/define-cms`). Each object contains:
|
|
17
|
+
1. **Name**: Matches the Contentful content type ID exactly. Defined **once** in the registration (not as a Record key).
|
|
18
|
+
2. **Renderer**: The React component to render.
|
|
19
|
+
3. **Used Fields**: Which fields from the content model are used.
|
|
20
|
+
4. **Mock Data**: Sample data for the styleguide/showcase.
|
|
21
|
+
|
|
22
|
+
## Registering a New Component
|
|
23
|
+
|
|
24
|
+
1. **Import the Registration**:
|
|
25
|
+
At the top of `src/lib/registrations.ts`, import your component's registration export.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { MyNewComponentRegistration } from '@/project/components/MyNewComponent';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. **Add to `componentRegistrationsList`**:
|
|
32
|
+
Find the `componentRegistrationsList` array in `registrations.ts` and add your component.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
export const componentRegistrationsList = [
|
|
36
|
+
HeroRegistration,
|
|
37
|
+
// ...
|
|
38
|
+
MyNewComponentRegistration, // Add this
|
|
39
|
+
] as const;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
*Order does not matter for functionality, but logical grouping is helpful. Missing a CMS type causes a type error in `cms.ts` when `buildComponentRecord(componentRegistrationsList)` is called.*
|
|
43
|
+
|
|
44
|
+
## Registering a New Collection
|
|
45
|
+
|
|
46
|
+
1. **Import the Registration** in `src/lib/registrations.ts`:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { MyCollectionRegistration } from '@/project/collections/MyCollection';
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. **Add to `collectionRegistrationsList`** in `registrations.ts`:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
export const collectionRegistrationsList = [
|
|
56
|
+
CardGridRegistration,
|
|
57
|
+
// ...
|
|
58
|
+
MyCollectionRegistration, // Add this
|
|
59
|
+
] as const;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Adding External Components
|
|
63
|
+
|
|
64
|
+
External components (like 3rd party forms or iframes) use a separate list in `src/lib/registrations.ts`.
|
|
65
|
+
|
|
66
|
+
1. **Import**:
|
|
67
|
+
```typescript
|
|
68
|
+
import { MyExternalWidgetRegistration } from '@/project/externalComponents/MyExternalWidget';
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
2. **Add to `externalComponentRegistrationsList`** in `registrations.ts`:
|
|
72
|
+
```typescript
|
|
73
|
+
export const externalComponentRegistrationsList = [
|
|
74
|
+
ExternalIFrameRegistration,
|
|
75
|
+
MyExternalWidgetRegistration,
|
|
76
|
+
] as const;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Extending Type Definitions
|
|
80
|
+
|
|
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
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
export type CmsColourName = NonNullable<TypeComponentFields['backgroundColour']>['values'];
|
|
85
|
+
// Add or modify if types are not automatically generated from Contentful
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Note**: Most types are generated automatically into `@/generated/types` by the `type-gen` script. You typically don't need to manually edit types unless you are defining project-specific overrides.
|
|
89
|
+
|
|
90
|
+
## The Showcase
|
|
91
|
+
|
|
92
|
+
Registering a component automatically adds it to the CMS Showcase (usually available at `/cms/showcase` in development). This allows you to view the component in isolation using its mock data.
|
|
93
|
+
|
|
94
|
+
* Ensure your `mock` object in the registration is complete and realistic.
|
|
95
|
+
* The showcase helps verify that `usedFields` and `UnusedChecker` are working correctly.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: styling-system
|
|
3
|
+
description: Reference guide for the marketing site styling system, including typography, colors, grids, and RTF classes.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Styling System
|
|
11
|
+
|
|
12
|
+
This project uses a customized Tailwind CSS setup where the configuration is driven by `tailwind.config.json` in each app. This JSON file acts as the source of truth for design tokens, including colors, typography, spacing, and breakpoints.
|
|
13
|
+
|
|
14
|
+
## Configuration Source
|
|
15
|
+
|
|
16
|
+
The `tailwind.config.json` file in your app's root directory defines the following:
|
|
17
|
+
|
|
18
|
+
* **`colorOptions`**: Defines the project's color palette.
|
|
19
|
+
* **`fontTable`**: Defines typography styles, responsive scaling, and font families.
|
|
20
|
+
* **`sizes`**: Defines breakpoints, grid columns, gaps, and margins.
|
|
21
|
+
|
|
22
|
+
These configurations are processed by the build system to generate utility classes and TypeScript helpers.
|
|
23
|
+
|
|
24
|
+
## Typography
|
|
25
|
+
|
|
26
|
+
Typography utility classes (e.g., `h1`, `h2`, `p1`, `p2`) are automatically generated from the `fontTable` in `tailwind.config.json`.
|
|
27
|
+
|
|
28
|
+
### generated Utilities
|
|
29
|
+
|
|
30
|
+
Classes are generated for each key in `fontTable.styles`. Common keys include:
|
|
31
|
+
|
|
32
|
+
* **Headings**: `h1`, `h2`, `h3`, `h4`, `h5`, `h6`
|
|
33
|
+
* **Body**: `p1`, `p2`, `p3`, `p4`
|
|
34
|
+
* **Special**: `quote`, `button`, `nav`, etc. (varies by project)
|
|
35
|
+
|
|
36
|
+
Styles are responsive and scale automatically based on the breakpoints defined in the config (e.g., `laptop`, `desktop`).
|
|
37
|
+
|
|
38
|
+
### Best Practice: Dynamic Sizing
|
|
39
|
+
|
|
40
|
+
Use `getSizingInformation(index)` from `@/lib/SizingInformation` to get **Element** (or **ChildElement** for items inside a collection) and typography classes. Use **Element** for the single main heading of the block; apply a class from `sizingInformation` (e.g. `sizingInformation.h1`). **preHeading** and **postHeading** must be rendered as **<p>** with typography classes (e.g. `sizingInformation.p`), not as heading elements.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { getSizingInformation } from '@/lib/SizingInformation';
|
|
44
|
+
|
|
45
|
+
// Example usage in a component renderer
|
|
46
|
+
const { Element, sizingInformation } = getSizingInformation(index);
|
|
47
|
+
<Element className={sizingInformation.h1}>{title}</Element>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For embedded content (e.g. inside rich text), pass `embedded: true` as the second argument.
|
|
51
|
+
|
|
52
|
+
## Colors
|
|
53
|
+
|
|
54
|
+
Colors are defined in `colorOptions` within `tailwind.config.json`. The build system generates TypeScript helpers in `@/generated/colors` to access these colors safely.
|
|
55
|
+
|
|
56
|
+
### Helper Functions
|
|
57
|
+
|
|
58
|
+
1. **`lookupColourString(colorName, property)`**:
|
|
59
|
+
Get a single class for a specific property.
|
|
60
|
+
```typescript
|
|
61
|
+
// Returns "text-primary-blue" (if 'Primary Blue' exists in config)
|
|
62
|
+
lookupColourString('Primary Blue', 'text')
|
|
63
|
+
// Returns "bg-light-gray" (if 'Light Gray' exists in config)
|
|
64
|
+
lookupColourString('Light Gray', 'bg')
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. **`lookupColourClassNames(bgColor, textColor)`**:
|
|
68
|
+
Get background AND text classes, handling automatic contrast if text color is omitted (based on `colorOpposites` in config).
|
|
69
|
+
```typescript
|
|
70
|
+
// Returns "bg-primary-blue text-white" (if White is opposite of Primary Blue)
|
|
71
|
+
lookupColourClassNames('Primary Blue')
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Grid System
|
|
75
|
+
|
|
76
|
+
The grid system is defined in the `sizes` object of `tailwind.config.json`. It specifies the number of columns, margins, and gaps for each breakpoint.
|
|
77
|
+
|
|
78
|
+
### Standard Breakpoints
|
|
79
|
+
|
|
80
|
+
While configurable, most projects use:
|
|
81
|
+
* `mobile`: Default (0px+)
|
|
82
|
+
* `tablet`: ~768px+
|
|
83
|
+
* `laptop`: ~1024px+
|
|
84
|
+
* `desktop`: ~1440px+
|
|
85
|
+
|
|
86
|
+
### Layout Helpers
|
|
87
|
+
|
|
88
|
+
Common layout patterns using Tailwind grid utilities:
|
|
89
|
+
|
|
90
|
+
* **Full Width**: `col-span-full`
|
|
91
|
+
* **Centered Content**: `col-span-full laptop:col-start-2 laptop:col-span-10` (assuming 12 columns on laptop)
|
|
92
|
+
* **Split 50/50**:
|
|
93
|
+
* Left: `col-span-full laptop:col-span-6`
|
|
94
|
+
* Right: `col-span-full laptop:col-span-6`
|
|
95
|
+
|
|
96
|
+
## Rich Text (RTF) Classes
|
|
97
|
+
|
|
98
|
+
Rich text styling is handled via custom utility classes defined in `src/app/globals.css`. These classes map raw HTML elements (from the CMS rich text field) to the project's typography utilities.
|
|
99
|
+
|
|
100
|
+
Common conventions for RTF classes (check your specific `globals.css`):
|
|
101
|
+
|
|
102
|
+
* **`.rtf-standard` / `.content-rich-text`**: Default styling for body content.
|
|
103
|
+
* **`.rtf-legal`**: Styling for terms and conditions (often smaller text, decimal lists).
|
|
104
|
+
* **`.rtf-article`**: Editorial styling (often larger text, specific spacing).
|
|
105
|
+
* **`.rtf-core`**: Minimal styling reset.
|
|
106
|
+
|
|
107
|
+
**Usage**:
|
|
108
|
+
Wrap the `RtfOrString` component with the appropriate class:
|
|
109
|
+
```tsx
|
|
110
|
+
<div className="rtf-standard">
|
|
111
|
+
<RtfOrString data={richTextData} />
|
|
112
|
+
</div>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Global Styles
|
|
116
|
+
|
|
117
|
+
Project-specific global styles, animations, and custom utility classes are located in `src/app/globals.css`. This file imports the generated Tailwind CSS and defines:
|
|
118
|
+
|
|
119
|
+
* Root variables (if any)
|
|
120
|
+
* Animation keyframes
|
|
121
|
+
* Custom component classes (e.g., `.btn-primary`)
|
|
122
|
+
* Rich Text Formatting classes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Brand Context Builder"
|
|
3
|
+
description: "Interactively create or update a brand context skill for a customer's site by analysing their content and asking refinement questions."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Brand Context Builder
|
|
7
|
+
|
|
8
|
+
Create a brand context skill for a customer's website. This skill guides you through analysing the site, proposing a brand context, and refining it with the user.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- User wants to set up brand context for a new customer
|
|
13
|
+
- User says "create brand context for [site]" or "set up [customer] brand context"
|
|
14
|
+
- User wants to update an existing brand context
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
### Step 1: Gather Information
|
|
19
|
+
|
|
20
|
+
Ask the user for:
|
|
21
|
+
- **Site URL** (required) — e.g., "https://www.hopskipdrive.com"
|
|
22
|
+
- **Customer name** (optional) — e.g., "HopSkipDrive" (can be inferred)
|
|
23
|
+
|
|
24
|
+
### Step 2: Analyse the Site
|
|
25
|
+
|
|
26
|
+
Call the `build_brand_context` tool with the site URL and customer name. This fetches the homepage and common pages via markdown routes and returns the content for analysis.
|
|
27
|
+
|
|
28
|
+
If the tool returns no content, the site may not have markdown routes enabled. Ask the user if they can provide the site URL with markdown routes, or proceed with what they can tell you about the brand.
|
|
29
|
+
|
|
30
|
+
### Step 3: Propose Brand Context
|
|
31
|
+
|
|
32
|
+
Based on the site content returned by the tool, propose a complete brand context covering:
|
|
33
|
+
|
|
34
|
+
1. **Customer name** — the brand name as they write it
|
|
35
|
+
2. **Brand voice** — analyse the writing style (formal? casual? technical? warm?)
|
|
36
|
+
3. **Target audience** — who is the site for? What are their needs?
|
|
37
|
+
4. **Terminology** — brand-specific terms that should be used instead of generic words
|
|
38
|
+
5. **Tone** — one-line description
|
|
39
|
+
6. **SEO focus** — primary topics and keywords
|
|
40
|
+
7. **Image context** — brand colours, common visual subjects and what they represent
|
|
41
|
+
|
|
42
|
+
Present the proposed context as JSON to the user.
|
|
43
|
+
|
|
44
|
+
### Step 4: Refine
|
|
45
|
+
|
|
46
|
+
Ask the user these questions to refine the context:
|
|
47
|
+
|
|
48
|
+
1. "Is the brand voice description accurate? Any adjustments?"
|
|
49
|
+
2. "Are there brand-specific terms I missed? For example, do you have special names for your products, roles, or services?"
|
|
50
|
+
3. "Are there visual elements in your imagery I should know about? (e.g., 'people in orange shirts are CareDrivers')"
|
|
51
|
+
4. "Is the target audience description correct?"
|
|
52
|
+
5. "Any SEO keywords or topics to add?"
|
|
53
|
+
|
|
54
|
+
Incorporate their feedback into the context.
|
|
55
|
+
|
|
56
|
+
### Step 5: Generate the Brand Context Skill
|
|
57
|
+
|
|
58
|
+
Once the user is happy with the context, generate a brand context skill file:
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
---
|
|
62
|
+
name: "[CustomerName] Brand Context"
|
|
63
|
+
description: "Brand voice, terminology, audience, and visual guidelines for [CustomerName] ([siteUrl])."
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# Brand Context: [CustomerName]
|
|
67
|
+
**Site:** [siteUrl]
|
|
68
|
+
**Brand voice:** [brandVoice]
|
|
69
|
+
**Target audience:** [targetAudience]
|
|
70
|
+
**Tone:** [tone]
|
|
71
|
+
**SEO focus:** [seoFocus]
|
|
72
|
+
|
|
73
|
+
## Terminology
|
|
74
|
+
Use these brand-specific terms instead of generic alternatives:
|
|
75
|
+
- **[term]**: [meaning]
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
## Image Interpretation
|
|
79
|
+
**Brand colours:** [colours]
|
|
80
|
+
**When you see → interpret as:**
|
|
81
|
+
- "[visual]" → [meaning]
|
|
82
|
+
...
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Step 6: Save
|
|
86
|
+
|
|
87
|
+
Tell the user:
|
|
88
|
+
|
|
89
|
+
1. **For Claude Desktop:** Save the skill content as `Skill.md` in a folder named `[customer-name]-brand-context/`, ZIP it, and upload via Customize > Skills
|
|
90
|
+
2. **For the project:** Save the JSON as `.site-context.json` in the project root, then run `generate-skills` to create the skill automatically
|
|
91
|
+
3. **To update later:** Edit `.site-context.json` and re-run `generate-skills`, or use this skill again to rebuild from scratch
|
|
92
|
+
|
|
93
|
+
## Tips
|
|
94
|
+
|
|
95
|
+
- If the site has a blog, look at article content for more terminology and voice clues
|
|
96
|
+
- Company about pages are great for understanding target audience
|
|
97
|
+
- Service/product pages reveal the key terms and benefits language
|
|
98
|
+
- Look for consistent phrases that appear across multiple pages — those are likely intentional brand language
|