@sudajs/cli 0.18.9 → 0.18.10
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 +4 -2
- package/dist/index.js +100 -62
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/theme/AGENTS.md +183 -1182
- package/templates/theme/docs/agent-guides/component-authoring.md +270 -0
- package/templates/theme/docs/agent-guides/design-and-runtime.md +170 -0
- package/templates/theme/docs/agent-guides/editor-compatibility.md +231 -0
- package/templates/theme/docs/agent-guides/templates-and-locales.md +206 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Templates and Locales
|
|
2
|
+
|
|
3
|
+
Read this guide before changing CMS templates, post resources, starter pages,
|
|
4
|
+
authored page data, editor locales, preview content locales, or language links.
|
|
5
|
+
The root `AGENTS.md` rules still apply.
|
|
6
|
+
|
|
7
|
+
## Authored page data
|
|
8
|
+
|
|
9
|
+
- Wrap hand-authored data with `defineSudaPageData(pageConfig, data)` when
|
|
10
|
+
practical.
|
|
11
|
+
- Every page uses `root: { props: {} }` and a `content` array.
|
|
12
|
+
- Every top-level `content[].type` must exactly match a public key in
|
|
13
|
+
`pageConfig.components`.
|
|
14
|
+
- Every top-level item needs a stable `props.id`.
|
|
15
|
+
- Do not put `id` in component `defaultProps`, local block `defaultProps`,
|
|
16
|
+
`defaultBlocks`, or block-slot nested items.
|
|
17
|
+
- Nested block-slot items use the short kind from
|
|
18
|
+
`blockSlots.<slotName>.blocks`, such as `"button"`, `"copy"`, or `"cards"`.
|
|
19
|
+
Never author `__suda_local_block__/...`.
|
|
20
|
+
- Use public authored props exactly as typed. Do not guess alternate field
|
|
21
|
+
names or add compatibility fallbacks.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
defineSudaPageData(pageConfig, {
|
|
25
|
+
root: { props: {} },
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "Hero",
|
|
29
|
+
props: {
|
|
30
|
+
id: "Hero-1",
|
|
31
|
+
title: "Welcome",
|
|
32
|
+
actions: [{ type: "button", props: { label: "Contact us", href: "/contact" } }],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## CMS contract
|
|
40
|
+
|
|
41
|
+
Suda CMS is a fixed post system. Themes provide exactly four entries through
|
|
42
|
+
`cmsTemplates`:
|
|
43
|
+
|
|
44
|
+
- `posts`: list at `/posts`.
|
|
45
|
+
- `post`: detail at `/posts/:slug`.
|
|
46
|
+
- `tags`: tag/category list at `/tags`.
|
|
47
|
+
- `tag`: posts for one tag at `/tags/:slug`.
|
|
48
|
+
|
|
49
|
+
Each entry is `{ title: string; data: PageData }`, not raw `PageData`:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
export const cmsTemplates: ThemeCmsTemplates = {
|
|
53
|
+
posts: { title: "Posts", data: postIndexTemplate },
|
|
54
|
+
post: { title: "Post", data: postDetailTemplate },
|
|
55
|
+
tags: { title: "Tags", data: tagIndexTemplate },
|
|
56
|
+
tag: { title: "Tag", data: tagDetailTemplate },
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Do not bypass the contract with intersection casts. Do not create variants such
|
|
61
|
+
as `post.default`, `post.modern`, or `posts.magazine`, arbitrary collection
|
|
62
|
+
types, or manual data-source binding contracts.
|
|
63
|
+
|
|
64
|
+
CMS-only main sections:
|
|
65
|
+
|
|
66
|
+
- `MainPosts`: `placement: { cmsTemplates: ["posts", "tag"] }` when shared;
|
|
67
|
+
render `cms.posts`, `cms.pagination`, and optional `cms.currentTag`.
|
|
68
|
+
- `MainPost`: only `post`; render when `cms.type === "post"`.
|
|
69
|
+
- `MainTags`: only `tags`; render when `cms.type === "tags"`.
|
|
70
|
+
- A separate `MainTagPosts` is valid when clearer than sharing `MainPosts`.
|
|
71
|
+
|
|
72
|
+
Read CMS data through `getCmsContent(puck?.metadata)`. CMS main sections must
|
|
73
|
+
not declare a `posts` field.
|
|
74
|
+
|
|
75
|
+
For pagination, use the exact platform fields:
|
|
76
|
+
|
|
77
|
+
- `cms.pagination.page`
|
|
78
|
+
- `cms.pagination.totalPages`
|
|
79
|
+
- `cms.pagination.hasPreviousPage`
|
|
80
|
+
- `cms.pagination.hasNextPage`
|
|
81
|
+
- `cms.pagination.previousUrl`
|
|
82
|
+
- `cms.pagination.nextUrl`
|
|
83
|
+
|
|
84
|
+
Use `cmsPaginationUrl(cms.pagination, targetPage)` for numbered links so current
|
|
85
|
+
filter/search parameters survive. Do not hand-build query strings.
|
|
86
|
+
|
|
87
|
+
## Ordinary page post sections
|
|
88
|
+
|
|
89
|
+
Provide at least one reusable ordinary-page post section such as
|
|
90
|
+
`FeaturedPosts`, `LatestPosts`, or `TopicPosts`. It has exactly one top-level
|
|
91
|
+
`posts` field and a default query on the same prop:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
fields: {
|
|
95
|
+
postList: { type: "posts", label: t("sections.featuredPosts.fields.posts") },
|
|
96
|
+
},
|
|
97
|
+
defaultProps: {
|
|
98
|
+
postList: { strategy: "featured", limit: 3 },
|
|
99
|
+
},
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Supported strategies are `latest`, `featured`, `by_tag`, and `manual`. Manual
|
|
103
|
+
queries contain only `items` and must not contain `limit`.
|
|
104
|
+
|
|
105
|
+
Resolve data with the exact component id and field key:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const posts = getPostResource(puck?.metadata, {
|
|
109
|
+
componentId: props.id,
|
|
110
|
+
fieldKey: "postList",
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The platform keys resources from both values. Do not import Prisma, call
|
|
115
|
+
platform APIs, or query a database from theme code. Do not add
|
|
116
|
+
`resourceQuery`, `resource_query`, assume the field is named `query`, nest a
|
|
117
|
+
posts field, or declare more than one posts field on a section.
|
|
118
|
+
|
|
119
|
+
For returned posts, prefer `post.url`. If missing, derive only from `post.slug`
|
|
120
|
+
as `/posts/${encodeURIComponent(post.slug)}`; if neither exists, use `#`. Do not
|
|
121
|
+
probe guessed fields such as `href`, `path`, `permalink`, `postUrl`, or
|
|
122
|
+
`canonicalUrl`.
|
|
123
|
+
|
|
124
|
+
## Starter pages
|
|
125
|
+
|
|
126
|
+
- Define realistic starter pages in `src/templates.ts`; do not ship placeholder
|
|
127
|
+
pages or a mechanical list of every component.
|
|
128
|
+
- Include one home/index page with `isHome: true`.
|
|
129
|
+
- A strong theme usually includes several purposeful pages such as `index`,
|
|
130
|
+
`about-us`, `contact-us`, `services`, and `team`, but only the home page is a
|
|
131
|
+
hard requirement.
|
|
132
|
+
- Reuse conversion sections when they support the visitor journey, but vary
|
|
133
|
+
page purpose, copy, proof, media, and ordering so pages are not interchangeable.
|
|
134
|
+
- Use only registered public component keys, stable top-level ids, and short
|
|
135
|
+
block-slot kinds.
|
|
136
|
+
- Use `themeAsset("assets/...")` for bundled media.
|
|
137
|
+
- Starter slugs preview at root-like paths: `index` is `/index`, `contact-us`
|
|
138
|
+
is `/contact-us`. Never use `/pages/...`.
|
|
139
|
+
|
|
140
|
+
## Editor labels
|
|
141
|
+
|
|
142
|
+
The host localizes editor configuration through `src/i18n.ts`.
|
|
143
|
+
|
|
144
|
+
- Use `t("stable.dot.path")` for component, category, field, nested field,
|
|
145
|
+
local-block, and option labels.
|
|
146
|
+
- Add every key to `src/locales/en.json`, the required reference locale.
|
|
147
|
+
- Locale JSON must be nested objects with string leaves. Arrays, numbers,
|
|
148
|
+
booleans, and null are invalid.
|
|
149
|
+
- Every additional `src/locales/<locale>.json` must have exactly the same leaf
|
|
150
|
+
keys as `en.json`; missing or extra keys fail validation and publishing.
|
|
151
|
+
- The CLI copies locale files into `dist/locales/`. Never edit dist copies.
|
|
152
|
+
- Do not use editor `t(...)` in public content, starter copy, default prop
|
|
153
|
+
values, or public-site text.
|
|
154
|
+
|
|
155
|
+
Installed legacy themes may show translation keys when locale files are absent;
|
|
156
|
+
new themes must still pass locale validation.
|
|
157
|
+
|
|
158
|
+
## Starter preview content locales
|
|
159
|
+
|
|
160
|
+
Use the separate `src/preview-i18n.ts` helper only in starter page templates for
|
|
161
|
+
visitor-visible titles, headings, descriptions, list copy, and button labels.
|
|
162
|
+
|
|
163
|
+
- Keep URLs, slugs, ids, component types, and asset paths as direct strings.
|
|
164
|
+
- Do not use preview translations in component labels, fields, `defaultProps`,
|
|
165
|
+
layout configuration, or CMS templates.
|
|
166
|
+
- When `manifest.previewLocales` exists, it must include `en`, and
|
|
167
|
+
`src/locales/en.content.json` is required.
|
|
168
|
+
- Every declared preview locale needs a matching
|
|
169
|
+
`src/locales/<locale>.content.json` with exactly the same string leaf keys as
|
|
170
|
+
`en.content.json`.
|
|
171
|
+
- Undeclared, missing, extra, or partial content locale files fail validation
|
|
172
|
+
and publishing.
|
|
173
|
+
|
|
174
|
+
Files named `<locale>.json` are editor messages. Files named
|
|
175
|
+
`<locale>.content.json` are starter preview content. Keep the two namespaces
|
|
176
|
+
separate.
|
|
177
|
+
|
|
178
|
+
## Public language links
|
|
179
|
+
|
|
180
|
+
Read language targets with `getSiteLocale(puck?.metadata)` from
|
|
181
|
+
`@sudajs/theme-engine/runtime`. Render the host-provided `label` and `href`.
|
|
182
|
+
Do not derive language names or construct locale URLs in theme code.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
const siteLocale = getSiteLocale(puck?.metadata);
|
|
186
|
+
|
|
187
|
+
return siteLocale?.locales.map((item) => (
|
|
188
|
+
<a key={item.locale} href={item.href} lang={item.locale}>
|
|
189
|
+
{item.label}
|
|
190
|
+
</a>
|
|
191
|
+
));
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Verification
|
|
195
|
+
|
|
196
|
+
After changing templates or locales, run:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
pnpm typecheck
|
|
200
|
+
pnpm build
|
|
201
|
+
pnpm validate
|
|
202
|
+
suda theme check
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Open every starter and CMS preview route and verify content, links, empty states,
|
|
206
|
+
pagination, and locale variants.
|