@sudajs/cli 0.20.0 → 0.21.0
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/dist/index.d.ts +14 -1
- package/dist/index.js +74 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/theme/AGENTS.md +13 -318
- package/templates/theme/CLAUDE.md +3 -1
- package/templates/theme/README.md +13 -0
- package/templates/theme/docs/agent-guides/component-authoring.md +35 -0
- package/templates/theme-skill/SKILL.md +63 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudajs/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"suda": "./bin/suda.js"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"react": "^19.2.7",
|
|
34
34
|
"react-dom": "^19.2.7",
|
|
35
35
|
"zod": "^3.24.1",
|
|
36
|
-
"@sudajs/theme-engine": "6.
|
|
36
|
+
"@sudajs/theme-engine": "6.9.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@tailwindcss/postcss": "^4.3.0",
|
|
@@ -1,326 +1,21 @@
|
|
|
1
|
-
# Suda Theme
|
|
1
|
+
# Suda Theme Project Rules
|
|
2
2
|
|
|
3
3
|
This repository is a standalone Vite + React + Tailwind Suda theme generated by
|
|
4
|
-
`suda theme init`.
|
|
5
|
-
sections, realistic templates, scoped styling, assets, and AI metadata.
|
|
4
|
+
`suda theme init`.
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
Install the reusable Suda theme development skill at the repository or
|
|
7
|
+
monorepo root before implementing theme work:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
background:
|
|
12
|
-
|
|
13
|
-
| Task | Required guide |
|
|
14
|
-
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
15
|
-
| Sections, fields, defaults, menus, icons, AI metadata, or block slots | `docs/agent-guides/component-authoring.md` |
|
|
16
|
-
| CMS, posts, starter pages, page data, or locales | `docs/agent-guides/templates-and-locales.md` |
|
|
17
|
-
| Header, Footer, PageOutlet, sticky/fixed UI, transparent navigation, carousel, editor CSS, or client behavior | `docs/agent-guides/editor-compatibility.md` |
|
|
18
|
-
| Theme contract, layout, design tokens, CSS, assets, or contact forms | `docs/agent-guides/design-and-runtime.md` |
|
|
19
|
-
|
|
20
|
-
Read every guide that applies when a change crosses concerns. Follow the
|
|
21
|
-
generated types and installed package APIs when they are more specific than an
|
|
22
|
-
example. Do not guess contracts from memory.
|
|
23
|
-
|
|
24
|
-
## Non-negotiable rules
|
|
25
|
-
|
|
26
|
-
- Keep `renderMode: "ssr"` and export a complete `ThemeModule` from
|
|
27
|
-
`src/index.tsx`: `manifest`, `pageConfig`, `layoutConfig`, `defaultLayout`,
|
|
28
|
-
`starterPages`, and `cmsTemplates`.
|
|
29
|
-
- Keep page sections in `pageConfig` and shared chrome in `layoutConfig`.
|
|
30
|
-
Header and Footer render exactly once from the layout, with `PageOutlet`
|
|
31
|
-
between them.
|
|
32
|
-
- Create theme-specific sections. Do not register `createEngineComponents()`,
|
|
33
|
-
`createBaseBlocks()`, or `createContainers()` as the theme's page sections.
|
|
34
|
-
Suda adds its generic content blocks separately.
|
|
35
|
-
- Keep persisted props JSON-serializable. Never store functions, React nodes,
|
|
36
|
-
class instances, media database ids, or absolute local filesystem paths.
|
|
37
|
-
- All normal field and prop defaults belong only in component `defaultProps`.
|
|
38
|
-
Never invent display defaults inside render code with `||`, `??`, a ternary,
|
|
39
|
-
a default function parameter, or a destructuring default.
|
|
40
|
-
- Every editor-facing label must use `t(...)` and exist in
|
|
41
|
-
`src/locales/en.json`. Public content and `defaultProps` must not use the
|
|
42
|
-
editor translation helper.
|
|
43
|
-
- Every page and layout component must declare useful `ai.instructions`.
|
|
44
|
-
- Top-level page data types must be public keys from `pageConfig.components`,
|
|
45
|
-
and every top-level item must have a stable `props.id`.
|
|
46
|
-
- Block-slot items use short local kinds such as `"button"`; never author
|
|
47
|
-
`__suda_local_block__/...` types or local-block ids.
|
|
48
|
-
- Theme assets use `themeAsset("assets/...")` in authored data and
|
|
49
|
-
`resolveAsset(...)` when rendering editable media. Never hand-write published
|
|
50
|
-
theme asset URLs.
|
|
51
|
-
- Keep theme CSS scoped. Do not use global resets or vendor edits that can
|
|
52
|
-
damage the Puck editor.
|
|
53
|
-
- Do not edit `dist/`; regenerate it through the build.
|
|
54
|
-
|
|
55
|
-
## Project structure
|
|
56
|
-
|
|
57
|
-
Keep every page section in its own `.tsx` file. Do not collect multiple section
|
|
58
|
-
configs and render implementations in a single `sections.tsx`, `config.tsx`, or
|
|
59
|
-
other large module. Use kebab-case names and a small `src/sections/index.ts` to
|
|
60
|
-
export configs or assemble the registry.
|
|
61
|
-
|
|
62
|
-
```txt
|
|
63
|
-
src/
|
|
64
|
-
sections/
|
|
65
|
-
hero.tsx
|
|
66
|
-
booking.tsx
|
|
67
|
-
values.tsx
|
|
68
|
-
faq-directory.tsx
|
|
69
|
-
review-marquee.tsx
|
|
70
|
-
index.ts
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Keep section-specific prop types and tightly coupled helpers with their section.
|
|
74
|
-
Extract shared code only when multiple sections genuinely reuse it.
|
|
75
|
-
|
|
76
|
-
## Component fundamentals
|
|
77
|
-
|
|
78
|
-
- Name public component keys with concise PascalCase visitor-facing patterns,
|
|
79
|
-
such as `HeroImage`, `FeatureCards`, or `TestimonialsCarousel`. Avoid theme
|
|
80
|
-
names and filler suffixes such as `Section`, `Component`, `New`, or `Custom`.
|
|
81
|
-
- Prefer semantic variant names. Use numbered variants only when the variants
|
|
82
|
-
truly share a purpose and no concise name describes the difference.
|
|
83
|
-
- Every page section must declare `section.motion`. Use `"reveal"` for ordinary
|
|
84
|
-
sections that use the shared viewport entrance animation. Use `"custom"` when
|
|
85
|
-
the section owns its own client animation (timeline, carousel, marquee, or
|
|
86
|
-
scroll-scrub), and use `"none"` when it must remain static. TypeScript will
|
|
87
|
-
report an error when the motion declaration is missing.
|
|
88
|
-
- Keep `fields`, TypeScript props, `defaultProps`, and `render` aligned. Every
|
|
89
|
-
normal field needs a sensible serializable default.
|
|
90
|
-
- Use the most specific field: `url`, `image`, `video`, `media`, `icon`,
|
|
91
|
-
`color`, `range`, `spacing`, `posts`, `select`, `radio`, `array`, or `object`.
|
|
92
|
-
Do not model structured or semantic values as generic text.
|
|
93
|
-
- Use `visibleIf` for synchronous sibling-dependent visibility. Use
|
|
94
|
-
`resolveFields` only when `visibleIf` cannot express the behavior.
|
|
95
|
-
- Expose a `columns` prop for multi-column grids and lists.
|
|
96
|
-
- Use ordinary fields for scalar and structured props. Use `blockSlots` only
|
|
97
|
-
for controlled nested items editors and AI may add, remove, or reorder.
|
|
98
|
-
- Native Puck slots are reserved for layout/container primitives. Page sections
|
|
99
|
-
must not declare native `slot` fields, legacy DropZones, or `zones`.
|
|
100
|
-
|
|
101
|
-
Default ownership is strict:
|
|
102
|
-
|
|
103
|
-
```tsx
|
|
104
|
-
// Wrong: render invents content.
|
|
105
|
-
<div>{val || "defaultValue"}</div>;
|
|
106
|
-
|
|
107
|
-
// Correct: defaultProps owns the default.
|
|
108
|
-
export const Example: SudaSectionConfig<ExampleProps> = {
|
|
109
|
-
section: { category: "features", variant: "example", motion: "reveal" },
|
|
110
|
-
fields: { val: { type: "text", label: t("sections.example.fields.val") } },
|
|
111
|
-
defaultProps: { val: "defaultValue" },
|
|
112
|
-
render: ({ val }) => <div>{val}</div>,
|
|
113
|
-
};
|
|
9
|
+
```bash
|
|
10
|
+
suda theme skill add
|
|
114
11
|
```
|
|
115
12
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
## Icons
|
|
120
|
-
|
|
121
|
-
- Fixed icons are acceptable for interaction and UI-state semantics such as
|
|
122
|
-
menu, close, previous/next, expand/collapse, and loading controls.
|
|
123
|
-
- Content icons such as feature, service, contact-method, and social-brand
|
|
124
|
-
icons are props. Expose `{ type: "icon" }`, type values as `SudaIconName`,
|
|
125
|
-
set initial selections in `defaultProps`, and render them with `SudaIcon` from
|
|
126
|
-
`@sudajs/theme-engine/icons`. Do not hardcode content icons in `render`.
|
|
127
|
-
- Use canonical Lucide names such as `"rocket"` and namespaced Simple Icons
|
|
128
|
-
names such as `"simple-icons:github"`. The theme engine supports both; do not
|
|
129
|
-
add another icon library unless neither can represent a required icon.
|
|
130
|
-
|
|
131
|
-
## Page data fundamentals
|
|
132
|
-
|
|
133
|
-
- Wrap hand-authored page data with `defineSudaPageData(pageConfig, data)` when
|
|
134
|
-
practical so TypeScript checks public component keys and block-slot kinds.
|
|
135
|
-
- Starter pages live in `src/templates.ts`, use `root: { props: {} }`, contain
|
|
136
|
-
realistic content, and include one home page with `isHome: true`.
|
|
137
|
-
- Provide exactly the four CMS templates `posts`, `post`, `tags`, and `tag` as
|
|
138
|
-
`{ title, data }` entries. Do not invent CMS template variants.
|
|
139
|
-
- CMS-only main sections read `getCmsContent(puck?.metadata)`. Ordinary page
|
|
140
|
-
post sections use one top-level `posts` field and `getPostResource(...)`.
|
|
141
|
-
- Starter page slugs preview at root-like routes such as `/index` and
|
|
142
|
-
`/contact-us`; never use `/pages/...` as a preview prefix.
|
|
143
|
-
|
|
144
|
-
## Editor and runtime fundamentals
|
|
145
|
-
|
|
146
|
-
- Components return one stable semantic real DOM root when positioning,
|
|
147
|
-
selection, spacing, or background matters. Do not rely on a Fragment or
|
|
148
|
-
`display: contents` for such roots.
|
|
149
|
-
- Derive editor state from `puck?.metadata?.isEditor === true`, expose a stable
|
|
150
|
-
theme-root marker, and scope editor fixes below it.
|
|
151
|
-
- Puck may place `data-puck-component` and inline `position: relative` on the
|
|
152
|
-
component's actual root. Account for that before implementing sticky, fixed,
|
|
153
|
-
absolute, overlap, or transparent navigation behavior.
|
|
154
|
-
- Do not restore pointer events globally in edit mode. Test interactions in
|
|
155
|
-
editor preview and on the public site.
|
|
156
|
-
- Browser setup belongs in an optional `clientHooks` export from
|
|
157
|
-
`src/client.ts`. Do not create `src/runtime.client.ts(x)`; the CLI owns the
|
|
158
|
-
generated runtime.
|
|
159
|
-
|
|
160
|
-
## Design and assets
|
|
161
|
-
|
|
162
|
-
- Define one editable design system in `sourceManifest.designSystem`, expose it
|
|
163
|
-
at the layout root, resolve it once there, and render components through the
|
|
164
|
-
resulting unprefixed CSS variables. Do not add or consume `--suda-*` aliases.
|
|
165
|
-
- Set `tokens.layout.contentWidth` in every preset in `src/manifest.ts`. Choose only
|
|
166
|
-
`"1024px"`, `"1200px"`, `"1280px"`, or `"1440px"`:
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
tokens: {
|
|
170
|
-
colors: { /* ... */ },
|
|
171
|
-
radius: { /* ... */ },
|
|
172
|
-
layout: { contentWidth: "1280px" },
|
|
173
|
-
}
|
|
174
|
-
```
|
|
13
|
+
The installed `sudacloud-theme` skill contains the section, collection, CMS,
|
|
14
|
+
design system, editor compatibility, localization, and verification guidance.
|
|
175
15
|
|
|
176
|
-
|
|
177
|
-
display names:
|
|
178
|
-
|
|
179
|
-
```ts
|
|
180
|
-
typography: {
|
|
181
|
-
heading: "inter",
|
|
182
|
-
body: "noto-sans-sc",
|
|
183
|
-
mono: "jetbrains-mono",
|
|
184
|
-
},
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
Read available IDs from `SUDA_THEME_FONT_FAMILIES`. System fonts such as
|
|
188
|
-
`system-sans`, `microsoft-yahei`, and `songti-sc` do not make network requests.
|
|
189
|
-
|
|
190
|
-
- Connect the design system field in the layout root's `fields` and
|
|
191
|
-
`defaultProps`:
|
|
192
|
-
|
|
193
|
-
```tsx
|
|
194
|
-
fields: {
|
|
195
|
-
designSystem: designSystemField(t("layout.root.fields.designSystem"), sourceManifest.designSystem),
|
|
196
|
-
},
|
|
197
|
-
defaultProps: {
|
|
198
|
-
designSystem: createThemeDesignDefault(sourceManifest.designSystem),
|
|
199
|
-
},
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
- Use the resolved CSS variables for theme typography:
|
|
203
|
-
|
|
204
|
-
```css
|
|
205
|
-
.my-theme-root {
|
|
206
|
-
font-family: var(--font-sans);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.my-theme-root h1,
|
|
210
|
-
.my-theme-root h2,
|
|
211
|
-
.my-theme-root h3,
|
|
212
|
-
.my-theme-root h4,
|
|
213
|
-
.my-theme-root h5,
|
|
214
|
-
.my-theme-root h6 {
|
|
215
|
-
font-family: var(--font-heading);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.my-theme-root code,
|
|
219
|
-
.my-theme-root pre {
|
|
220
|
-
font-family: var(--font-mono);
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
- In the layout root, resolve the selected preset and apply its CSS variables
|
|
225
|
-
to the element that wraps `children`. Use this exact pattern:
|
|
226
|
-
|
|
227
|
-
```tsx
|
|
228
|
-
render: ({ children, designSystem }) => {
|
|
229
|
-
const tokens = resolveThemeDesignTokens(sourceManifest.designSystem, designSystem);
|
|
230
|
-
return (
|
|
231
|
-
<div
|
|
232
|
-
className="my-theme-root"
|
|
233
|
-
style={createThemeDesignCssVariables(tokens)}
|
|
234
|
-
>
|
|
235
|
-
{children}
|
|
236
|
-
</div>
|
|
237
|
-
);
|
|
238
|
-
},
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
- Do not set `max-width` on the layout root or `PageOutlet`; doing so prevents
|
|
242
|
-
full-width sections. Apply `--content-max-width` only to inner content
|
|
243
|
-
containers. Wrap Header and Footer contents in that same container when they
|
|
244
|
-
must align with page sections.
|
|
245
|
-
|
|
246
|
-
- Every page section root must include `w-full`. Put the section background,
|
|
247
|
-
border, and full-bleed media on this root. Do not set `max-width` on it.
|
|
248
|
-
- Put normal section content inside one shared container class and define that
|
|
249
|
-
class once in `src/styles.css`:
|
|
250
|
-
|
|
251
|
-
```css
|
|
252
|
-
.my-theme-container {
|
|
253
|
-
width: min(var(--content-max-width), 100%);
|
|
254
|
-
margin-inline: auto;
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
- Use the same container inside full-width Hero and band sections when their
|
|
259
|
-
text, buttons, cards, or navigation must align with ordinary sections. Omit
|
|
260
|
-
the inner container only when the section content itself must be edge to
|
|
261
|
-
edge. Do not repeat `1024px`, `1200px`, `1280px`, or `1440px` in section CSS.
|
|
262
|
-
- `--background` / `--foreground`: default page surface and readable default
|
|
263
|
-
content. `--primary` / `--primary-foreground`: main brand and action surface
|
|
264
|
-
plus readable content on it. `--secondary` / `--secondary-foreground`:
|
|
265
|
-
supporting surface plus its content; it is not assumed light or dark.
|
|
266
|
-
- `--accent` / `--accent-foreground`: high-attention emphasis, selection, or
|
|
267
|
-
decorative surface plus its content, not a default CTA substitute.
|
|
268
|
-
`--muted` / `--muted-foreground`: subdued surface and secondary text/icons.
|
|
269
|
-
Always pair a chosen surface with its corresponding foreground token.
|
|
270
|
-
- `--radius` is the generic fallback; use `--radius-card`,
|
|
271
|
-
`--radius-button`, and `--radius-input` for cards, command buttons, and form
|
|
272
|
-
controls. Tailwind token mappings use `@theme inline`; hand-written CSS may
|
|
273
|
-
consume these variables directly.
|
|
274
|
-
- The theme decides which semantic surface each of its components uses. Do not
|
|
275
|
-
alter built-in section styling to accommodate a single theme palette, and do
|
|
276
|
-
not hardcode replacement colors in individual sections.
|
|
277
|
-
- Keep typography, spacing, containers, buttons, cards, forms, and media frames
|
|
278
|
-
consistent across ordinary sections, CMS sections, and starter pages.
|
|
279
|
-
- Theme-local assets live under top-level `assets/`. Required preview images are
|
|
280
|
-
`assets/preview/desktop.png`, `tablet.png`, and `mobile.png`.
|
|
281
|
-
- Contact sections render host-provided `metadata.contactForm`; the platform
|
|
282
|
-
owns configuration, validation, submission, notifications, and limits.
|
|
283
|
-
|
|
284
|
-
## Workflow
|
|
285
|
-
|
|
286
|
-
Before editing:
|
|
287
|
-
|
|
288
|
-
1. Read the required focused guide(s).
|
|
289
|
-
2. Inspect the existing source, generated types, and established theme helpers.
|
|
290
|
-
3. Identify every affected contract: fields/defaults/render, locales, page data,
|
|
291
|
-
assets, editor behavior, and templates.
|
|
292
|
-
|
|
293
|
-
When adding or changing a section:
|
|
294
|
-
|
|
295
|
-
1. Define serializable props in its dedicated `.tsx` file.
|
|
296
|
-
2. Add `section` metadata with `category`, semantic `variant`, and an explicit
|
|
297
|
-
`motion` mode (`reveal`, `custom`, or `none`).
|
|
298
|
-
3. Add `label`, useful `ai.instructions`, typed `fields`, optional
|
|
299
|
-
`blockSlots`, `defaultProps`, and `render`.
|
|
300
|
-
4. Add all editor label keys to `src/locales/en.json`.
|
|
301
|
-
5. Register it in `pageConfig` and the appropriate translated category.
|
|
302
|
-
6. Add realistic usage to starter pages or CMS templates where appropriate.
|
|
303
|
-
7. Verify public rendering plus editor desktop, tablet, and mobile behavior.
|
|
304
|
-
|
|
305
|
-
Before handoff:
|
|
306
|
-
|
|
307
|
-
```bash
|
|
308
|
-
pnpm lint
|
|
309
|
-
pnpm typecheck
|
|
310
|
-
pnpm build
|
|
311
|
-
pnpm validate
|
|
312
|
-
suda theme check
|
|
313
|
-
suda theme visual-check
|
|
314
|
-
```
|
|
16
|
+
## Always required
|
|
315
17
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
`
|
|
319
|
-
|
|
320
|
-
`.suda-build/visual-check/`, and fails on token contrast, semantic surface,
|
|
321
|
-
or page-overflow errors. Fixed-header overlap is reported as a layout warning;
|
|
322
|
-
solve it in the theme layout. Platform built-in sections are covered by
|
|
323
|
-
theme-engine tests, not repeated for every theme. Run `suda theme capture` when
|
|
324
|
-
publish-preview visuals change.
|
|
325
|
-
Do not use removed skip flags or bypass build, validation, AI metadata, locale,
|
|
326
|
-
visual, or screenshot checks.
|
|
18
|
+
- Keep `renderMode: "ssr"` and export the complete `ThemeModule` contract.
|
|
19
|
+
- Keep persisted props JSON-serializable and put normal field defaults only in
|
|
20
|
+
component `defaultProps`.
|
|
21
|
+
- Do not edit generated files in `dist/`; regenerate them through the build.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
# Claude Code
|
|
2
2
|
|
|
3
|
-
Read `AGENTS.md` first.
|
|
3
|
+
Read `AGENTS.md` first. Then use the installed `sudacloud-theme` skill for
|
|
4
|
+
theme development guidance. If it is missing, run `suda theme skill add` from
|
|
5
|
+
the repository or monorepo root.
|
|
@@ -8,6 +8,19 @@ A standalone Vite + React + Tailwind Suda theme scaffolded with `suda theme init
|
|
|
8
8
|
pnpm install
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Theme development skill
|
|
12
|
+
|
|
13
|
+
Install the shared Suda theme development guidance once at the repository or
|
|
14
|
+
monorepo root:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
suda theme skill add
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The generated `AGENTS.md` keeps only project rules that must always apply. The
|
|
21
|
+
installed `sudacloud-theme` skill provides the detailed section, collection,
|
|
22
|
+
CMS, design system, editor, and localization guidance.
|
|
23
|
+
|
|
11
24
|
## Develop
|
|
12
25
|
|
|
13
26
|
```bash
|
|
@@ -65,6 +65,9 @@ Use the most specific supported field:
|
|
|
65
65
|
- `select`, `radio`: stable serializable choices.
|
|
66
66
|
- `object`, `array`: grouped and repeatable structured values.
|
|
67
67
|
- `posts`: one dynamic post query on an ordinary page section.
|
|
68
|
+
- `collection`: a project-scoped dynamic collection binding with semantic role
|
|
69
|
+
mappings. The current contract resolves a published list and `limit`; do not
|
|
70
|
+
invent manual selection, filter/sort, or detail-route fields in PageData.
|
|
68
71
|
|
|
69
72
|
Rules:
|
|
70
73
|
|
|
@@ -126,6 +129,38 @@ defaultProps: {
|
|
|
126
129
|
},
|
|
127
130
|
```
|
|
128
131
|
|
|
132
|
+
## Collection-backed sections
|
|
133
|
+
|
|
134
|
+
The theme engine includes three platform-owned section families:
|
|
135
|
+
|
|
136
|
+
- `SudaCollectionGrid` for multi-column cards;
|
|
137
|
+
- `SudaCollectionList` for compact directories;
|
|
138
|
+
- `SudaCollectionSpotlight` for one prominent entry and optional supporting entries.
|
|
139
|
+
|
|
140
|
+
When a theme owns a custom collection layout, declare semantic roles instead of
|
|
141
|
+
assuming every Collection has fields named `title`, `image`, or `featured`:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
source: {
|
|
145
|
+
type: "collection",
|
|
146
|
+
roles: {
|
|
147
|
+
title: { types: ["text", "textarea"], required: true },
|
|
148
|
+
description: { types: ["text", "textarea", "richText"] },
|
|
149
|
+
image: { types: ["media"] },
|
|
150
|
+
href: { types: ["url"] },
|
|
151
|
+
},
|
|
152
|
+
defaultLimit: 6,
|
|
153
|
+
maxLimit: 12,
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Read resolved entries with `getCollectionResource(props.puck?.metadata, {
|
|
158
|
+
componentId: props.id, fieldKey: "source" })` from
|
|
159
|
+
`@sudajs/theme-engine/runtime`. The host runtime supplies published entries for
|
|
160
|
+
the current locale and resolves media URLs. A theme must not access Prisma or
|
|
161
|
+
filter project data in the browser. The platform documentation describes the
|
|
162
|
+
complete contract and planned query/detail extensions.
|
|
163
|
+
|
|
129
164
|
## Navigation and footer menus
|
|
130
165
|
|
|
131
166
|
Navigation and footer menus are typed arrays. Do not use a legacy menu field,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sudacloud-theme
|
|
3
|
+
description: Use when building, editing, reviewing, validating, or publishing a SudaCloud Vite theme, including sections, collection bindings, CMS templates, design tokens, Puck editor compatibility, starter pages, and theme localization.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SudaCloud Theme Development
|
|
7
|
+
|
|
8
|
+
Use this skill for a standalone Suda theme created by `suda theme init`.
|
|
9
|
+
It supplies the reusable development contract that should be installed once at
|
|
10
|
+
the repository or monorepo root with `suda theme skill add`.
|
|
11
|
+
|
|
12
|
+
## Read first
|
|
13
|
+
|
|
14
|
+
Read the references that match the task before editing. Read more than one when
|
|
15
|
+
a change crosses concerns.
|
|
16
|
+
|
|
17
|
+
| Task | Required reference |
|
|
18
|
+
| ---------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
19
|
+
| Sections, fields, defaults, menus, icons, AI metadata, block slots, or collections | `references/component-authoring.md` |
|
|
20
|
+
| CMS templates, posts, starter pages, PageData, or locales | `references/templates-and-locales.md` |
|
|
21
|
+
| Header, Footer, PageOutlet, sticky or fixed UI, carousel, editor CSS, or client behavior | `references/editor-compatibility.md` |
|
|
22
|
+
| Theme contract, manifest, design tokens, CSS, assets, contact forms, or runtime metadata | `references/design-and-runtime.md` |
|
|
23
|
+
|
|
24
|
+
Use generated TypeScript types and installed package APIs as the source of truth
|
|
25
|
+
when they are more specific than these references. Do not guess contracts.
|
|
26
|
+
|
|
27
|
+
## Non-negotiable requirements
|
|
28
|
+
|
|
29
|
+
- Keep `renderMode: "ssr"` and export a complete `ThemeModule` with `manifest`,
|
|
30
|
+
`pageConfig`, `layoutConfig`, `defaultLayout`, `starterPages`, and
|
|
31
|
+
`cmsTemplates`.
|
|
32
|
+
- Keep page sections in `pageConfig`; render shared chrome once from the layout
|
|
33
|
+
with `PageOutlet` between Header and Footer.
|
|
34
|
+
- Persist only JSON-serializable props. Use `defaultProps` as the sole owner of
|
|
35
|
+
normal field defaults; render code must not invent fallback content.
|
|
36
|
+
- Every editor-facing label uses `t(...)` and has an `en.json` entry. Public
|
|
37
|
+
content and `defaultProps` do not use the editor translation helper.
|
|
38
|
+
- Authored PageData uses public component keys with stable top-level `props.id`.
|
|
39
|
+
Block slots use their short local kinds, never internal generated types.
|
|
40
|
+
- Resolve theme assets with `themeAsset(...)` in authored data and
|
|
41
|
+
`resolveAsset(...)` for editable rendered media.
|
|
42
|
+
- Keep CSS scoped to the theme root and preserve Puck editor compatibility.
|
|
43
|
+
- Do not edit `dist/`; regenerate it with the theme build.
|
|
44
|
+
|
|
45
|
+
## Collection sections
|
|
46
|
+
|
|
47
|
+
Prefer the platform-owned `SudaCollectionGrid`, `SudaCollectionList`, and
|
|
48
|
+
`SudaCollectionSpotlight` for standard collection displays. For a custom
|
|
49
|
+
collection layout, declare semantic collection roles and read the published
|
|
50
|
+
project-scoped resource through `getCollectionResource(...)`; do not query
|
|
51
|
+
database data or implement client-side project filtering.
|
|
52
|
+
|
|
53
|
+
## Verification
|
|
54
|
+
|
|
55
|
+
Run the relevant theme checks before publishing:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm lint:fix
|
|
59
|
+
pnpm typecheck
|
|
60
|
+
suda theme visual-check
|
|
61
|
+
suda theme capture
|
|
62
|
+
pnpm build
|
|
63
|
+
```
|