@sudajs/cli 0.11.0 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudajs/cli",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "suda": "./bin/suda.js"
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@modelcontextprotocol/sdk": "^1.29.0",
28
- "@puckeditor/core": "^0.21.3",
28
+ "@puckeditor/core": "^0.22.0",
29
29
  "commander": "^12.1.0",
30
30
  "esbuild": "^0.25.12",
31
31
  "lucide-react": "^1.17.0",
@@ -34,7 +34,7 @@
34
34
  "react": "^19.2.7",
35
35
  "react-dom": "^19.2.7",
36
36
  "zod": "^3.24.1",
37
- "@sudajs/theme-engine": "3.0.0"
37
+ "@sudajs/theme-engine": "4.0.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@tailwindcss/postcss": "^4.3.0",
@@ -49,8 +49,8 @@
49
49
  "typescript": "^5.7.2",
50
50
  "vite": "^7.3.3",
51
51
  "vitest": "^3.2.4",
52
- "@suda/eslint-config": "0.0.0",
53
52
  "@suda/build-config": "0.0.0",
53
+ "@suda/eslint-config": "0.0.0",
54
54
  "@suda/tsconfig": "0.0.0"
55
55
  },
56
56
  "scripts": {
@@ -308,8 +308,8 @@ example `FeaturedPosts`, `LatestPosts`, or `TopicPosts`. Use it for homepage
308
308
  insights, featured articles, case studies, news teasers, or tag-filtered post
309
309
  groups on ordinary pages.
310
310
 
311
- Define that section with exactly one top-level `type: "posts"` field and a
312
- default query on the same prop:
311
+ Define that section with one or more top-level `type: "posts"` fields and a
312
+ default query on each matching prop:
313
313
 
314
314
  ```tsx
315
315
  fields: {
@@ -320,10 +320,13 @@ defaultProps: {
320
320
  },
321
321
  ```
322
322
 
323
- Supported strategies are `latest`, `featured`, `by_tag`, and `manual`. In the
324
- section render function, call `getPostResource(puck?.metadata, id)` to get the
325
- posts. Never import Prisma, call platform APIs, or query the database from
326
- theme code.
323
+ Supported strategies are `latest`, `featured`, `by_tag`, and `manual`. Manual
324
+ queries store only `items` and must not include `limit`. Runtime post resources
325
+ are keyed as `${props.id}.${fieldKey}` with both parts URL-encoded by the
326
+ platform. In the section render function, call
327
+ `getPostResource(puck?.metadata, { componentId: props.id, fieldKey: "postList" })`
328
+ with the exact posts field key. Never import Prisma, call platform APIs, or
329
+ query the database from theme code.
327
330
 
328
331
  Starter pages must include one home/index page with `isHome: true`. Recommended
329
332
  starter pages include `index`, `about-us`, `contact-us`, `services`, and `team`.
@@ -19,7 +19,7 @@
19
19
  "devDependencies": {
20
20
  "@eslint/js": "^9.39.4",
21
21
  "@tailwindcss/postcss": "^4.3.0",
22
- "@puckeditor/core": "^0.21.3",
22
+ "@puckeditor/core": "^0.22.0",
23
23
  "@sudajs/cli": "*",
24
24
  "@sudajs/theme-engine": "*",
25
25
  "@types/node": "^24.13.2",
@@ -42,7 +42,7 @@
42
42
  "vite": "^8.1.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@puckeditor/core": "^0.21.3",
45
+ "@puckeditor/core": "^0.22.0",
46
46
  "@sudajs/theme-engine": "*",
47
47
  "lucide-react": "^1.17.0",
48
48
  "react": "^19.2.7",
@@ -1,11 +1,21 @@
1
1
  import type { SudaComponentConfig, SudaRootConfig } from "@sudajs/theme-engine";
2
- import { getIcpRecord, getPageSlot, getWhiteLabel } from "@sudajs/theme-engine/runtime";
2
+ import {
3
+ createThemeDesignCssVariables,
4
+ createThemeDesignDefault,
5
+ designSystemField,
6
+ getIcpRecord,
7
+ getPageSlot,
8
+ getWhiteLabel,
9
+ resolveThemeDesignTokens,
10
+ type ThemeDesignValue,
11
+ } from "@sudajs/theme-engine/runtime";
3
12
  import type { ReactElement, ReactNode } from "react";
4
13
 
5
14
  import { t } from "./i18n.js";
15
+ import { sourceManifest } from "./manifest.js";
6
16
 
7
17
  type PuckExtras = { puck?: { metadata?: Record<string, unknown> } };
8
- type RootProps = { children?: ReactNode; title?: string };
18
+ type RootProps = { children?: ReactNode; title?: string; designSystem?: ThemeDesignValue };
9
19
  type HeaderProps = { siteName?: string };
10
20
  type PageOutletProps = PuckExtras;
11
21
  type FooterProps = { text?: string } & PuckExtras;
@@ -13,13 +23,21 @@ type FooterProps = { text?: string } & PuckExtras;
13
23
  export const rootConfig: SudaRootConfig<RootProps> = {
14
24
  fields: {
15
25
  title: { type: "text", label: t("layout.root.fields.title") },
26
+ designSystem: designSystemField(t("layout.root.fields.designSystem"), sourceManifest.designSystem),
27
+ },
28
+ defaultProps: {
29
+ title: "__SUDA_THEME_KEY__",
30
+ designSystem: createThemeDesignDefault(sourceManifest.designSystem),
31
+ },
32
+ render: ({ children, designSystem, title }) => {
33
+ const tokens = resolveThemeDesignTokens(sourceManifest.designSystem, designSystem);
34
+ const style = createThemeDesignCssVariables(tokens);
35
+ return (
36
+ <div className="__SUDA_THEME_KEY__-root" data-site-name={title} style={style}>
37
+ {children}
38
+ </div>
39
+ );
16
40
  },
17
- defaultProps: { title: "__SUDA_THEME_KEY__" },
18
- render: ({ children, title }) => (
19
- <div className="__SUDA_THEME_KEY__-root" data-site-name={title}>
20
- {children}
21
- </div>
22
- ),
23
41
  };
24
42
 
25
43
  export const Header: SudaComponentConfig<HeaderProps> = {
@@ -2,7 +2,8 @@
2
2
  "layout": {
3
3
  "root": {
4
4
  "fields": {
5
- "title": "Site title"
5
+ "title": "Site title",
6
+ "designSystem": "Design system"
6
7
  }
7
8
  },
8
9
  "header": {
@@ -8,7 +8,55 @@ export const sourceManifest: ThemeSourceManifest = {
8
8
  key: "__SUDA_THEME_KEY__",
9
9
  name: "__SUDA_THEME_KEY__",
10
10
  categories: ["other"],
11
- minEngineVersion: "0.0.0",
11
+ minEngineVersion: "4.0.0",
12
+ designSystem: {
13
+ version: 1,
14
+ defaultPresetId: "default",
15
+ presets: [
16
+ {
17
+ id: "default",
18
+ label: "Default",
19
+ tokens: {
20
+ colors: {
21
+ background: "#ffffff",
22
+ foreground: "#111827",
23
+ primary: "#111827",
24
+ primaryForeground: "#ffffff",
25
+ accent: "#f8fafc",
26
+ accentForeground: "#111827",
27
+ muted: "#f4f5f7",
28
+ mutedForeground: "#4b5563",
29
+ },
30
+ radius: {
31
+ card: "8px",
32
+ button: "8px",
33
+ input: "8px",
34
+ },
35
+ },
36
+ },
37
+ {
38
+ id: "ocean",
39
+ label: "Ocean",
40
+ tokens: {
41
+ colors: {
42
+ background: "#f8fbff",
43
+ foreground: "#0e1b36",
44
+ primary: "#2563eb",
45
+ primaryForeground: "#ffffff",
46
+ accent: "#dbeafe",
47
+ accentForeground: "#0e1b36",
48
+ muted: "#eff6ff",
49
+ mutedForeground: "#42526e",
50
+ },
51
+ radius: {
52
+ card: "14px",
53
+ button: "9999px",
54
+ input: "10px",
55
+ },
56
+ },
57
+ },
58
+ ],
59
+ },
12
60
  entry: "index.js",
13
61
  clientEntry: "runtime.client.js",
14
62
  // Required. SudaCloud currently hosts SSR themes only; CSR/Hybrid postures
@@ -240,7 +240,10 @@ export const FeaturedPosts: SudaComponentConfig<FeaturedPostsProps> = {
240
240
  postList: { strategy: "featured", limit: 3 },
241
241
  },
242
242
  render: ({ id, title, description, puck }) => {
243
- const resource = getPostResource(puck?.metadata, id);
243
+ const resource = getPostResource(puck?.metadata, {
244
+ componentId: id,
245
+ fieldKey: "postList",
246
+ });
244
247
  const posts = resource.posts;
245
248
  return (
246
249
  <section className="__SUDA_THEME_KEY__-section">
@@ -3,22 +3,22 @@
3
3
 
4
4
  .__SUDA_THEME_KEY__-root {
5
5
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
6
- color: #111827;
7
- background: #ffffff;
6
+ color: var(--suda-color-foreground, #111827);
7
+ background: var(--suda-color-background, #ffffff);
8
8
  }
9
9
  .__SUDA_THEME_KEY__-header,
10
10
  .__SUDA_THEME_KEY__-footer {
11
11
  padding: 20px clamp(20px, 5vw, 64px);
12
- border-bottom: 1px solid #e5e7eb;
12
+ border-bottom: 1px solid var(--suda-color-muted, #e5e7eb);
13
13
  }
14
14
  .__SUDA_THEME_KEY__-footer {
15
15
  display: flex;
16
16
  flex-wrap: wrap;
17
17
  align-items: center;
18
18
  gap: 12px 20px;
19
- border-top: 1px solid #e5e7eb;
19
+ border-top: 1px solid var(--suda-color-muted, #e5e7eb);
20
20
  border-bottom: 0;
21
- color: #6b7280;
21
+ color: var(--suda-color-muted-foreground, #6b7280);
22
22
  }
23
23
  .__SUDA_THEME_KEY__-footer a {
24
24
  display: inline-flex;
@@ -35,19 +35,19 @@
35
35
  padding: 64px clamp(20px, 5vw, 64px);
36
36
  }
37
37
  .__SUDA_THEME_KEY__-hero {
38
- background: #f8fafc;
38
+ background: var(--suda-color-accent, #f8fafc);
39
39
  }
40
40
  .__SUDA_THEME_KEY__-hero-logo {
41
41
  width: 64px;
42
42
  height: 64px;
43
- border-radius: 14px;
43
+ border-radius: var(--suda-radius-card, 14px);
44
44
  margin-bottom: 24px;
45
45
  }
46
46
  .__SUDA_THEME_KEY__-eyebrow {
47
47
  text-transform: uppercase;
48
48
  letter-spacing: 0.08em;
49
49
  font-size: 12px;
50
- color: #2563eb;
50
+ color: var(--suda-color-primary, #2563eb);
51
51
  font-weight: 700;
52
52
  }
53
53
  .__SUDA_THEME_KEY__-section h1 {
@@ -65,16 +65,16 @@
65
65
  .__SUDA_THEME_KEY__-section p {
66
66
  max-width: 680px;
67
67
  line-height: 1.7;
68
- color: #4b5563;
68
+ color: var(--suda-color-muted-foreground, #4b5563);
69
69
  }
70
70
  .__SUDA_THEME_KEY__-button {
71
71
  display: inline-flex;
72
72
  align-items: center;
73
73
  min-height: 42px;
74
74
  padding: 0 18px;
75
- border-radius: 8px;
76
- background: #111827;
77
- color: #ffffff;
75
+ border-radius: var(--suda-radius-button, 8px);
76
+ background: var(--suda-color-primary, #111827);
77
+ color: var(--suda-color-primary-foreground, #ffffff);
78
78
  text-decoration: none;
79
79
  font-weight: 700;
80
80
  }
@@ -85,14 +85,14 @@
85
85
  margin-top: 28px;
86
86
  }
87
87
  .__SUDA_THEME_KEY__-card {
88
- border: 1px solid #e5e7eb;
89
- border-radius: 8px;
88
+ border: 1px solid var(--suda-color-muted, #e5e7eb);
89
+ border-radius: var(--suda-radius-card, 8px);
90
90
  padding: 20px;
91
91
  }
92
92
  .__SUDA_THEME_KEY__-card-icon {
93
93
  width: 24px;
94
94
  height: 24px;
95
- color: #2563eb;
95
+ color: var(--suda-color-primary, #2563eb);
96
96
  }
97
97
  .__SUDA_THEME_KEY__-quote blockquote {
98
98
  max-width: 780px;
@@ -101,15 +101,15 @@
101
101
  margin: 0 0 16px;
102
102
  }
103
103
  .__SUDA_THEME_KEY__-cta {
104
- background: #111827;
105
- color: #ffffff;
104
+ background: var(--suda-color-foreground, #111827);
105
+ color: var(--suda-color-background, #ffffff);
106
106
  }
107
107
  .__SUDA_THEME_KEY__-cta p {
108
- color: #d1d5db;
108
+ color: var(--suda-color-muted, #d1d5db);
109
109
  }
110
110
  .__SUDA_THEME_KEY__-cta .__SUDA_THEME_KEY__-button {
111
- background: #ffffff;
112
- color: #111827;
111
+ background: var(--suda-color-background, #ffffff);
112
+ color: var(--suda-color-foreground, #111827);
113
113
  }
114
114
  @media (max-width: 760px) {
115
115
  .__SUDA_THEME_KEY__-grid {