@homepages/template-kit 0.2.0 → 0.4.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/CHANGELOG.md +222 -0
- package/README.md +96 -17
- package/dist/asset-modules.d.ts +81 -0
- package/dist/base.css +9 -0
- package/dist/cli/check/config.js +41 -0
- package/dist/cli/check/css.js +131 -0
- package/dist/cli/check/diagnostics.js +32 -0
- package/dist/cli/check/index.js +87 -0
- package/dist/cli/check/loader.js +146 -0
- package/dist/cli/check/paths.js +15 -0
- package/dist/cli/check/relativize.js +18 -0
- package/dist/cli/check/render-invariants.js +24 -0
- package/dist/cli/check/resolve-tool.js +38 -0
- package/dist/cli/check/section-assets.js +58 -0
- package/dist/cli/check/stages/deps.js +337 -0
- package/dist/cli/check/stages/lint.js +46 -0
- package/dist/cli/check/stages/render.js +101 -0
- package/dist/cli/check/stages/size.js +274 -0
- package/dist/cli/check/stages/tree.js +206 -0
- package/dist/cli/check/stages/typecheck.js +46 -0
- package/dist/cli/check/stages/validate/catalog-exhaustiveness.js +18 -0
- package/dist/cli/check/stages/validate/facts.js +18 -0
- package/dist/cli/check/stages/validate/formatter-contract.js +14 -0
- package/dist/cli/check/stages/validate/group-contract.js +21 -0
- package/dist/cli/check/stages/validate/index.js +66 -0
- package/dist/cli/check/stages/validate/list-scalar-contract.js +22 -0
- package/dist/cli/check/stages/validate/nav-contract.js +93 -0
- package/dist/cli/check/stages/validate/nested-slot-contract.js +12 -0
- package/dist/cli/check/stages/validate/object-list-contract.js +31 -0
- package/dist/cli/check/stages/validate/orchestrator.js +241 -0
- package/dist/cli/check/stages/validate/produced-by-contract.js +18 -0
- package/dist/cli/check/stages/validate/row-contract.js +31 -0
- package/dist/cli/check/stages/validate/select-contract.js +13 -0
- package/dist/cli/check/stages/validate/source-contract.js +21 -0
- package/dist/cli/check/stages/validate/variant-contract.js +15 -0
- package/dist/cli/check/workspace.js +86 -0
- package/dist/cli/dev/build-css.js +91 -0
- package/dist/cli/dev/catalog.js +35 -0
- package/dist/cli/dev/compose-template.js +38 -0
- package/dist/cli/dev/content-override.js +58 -0
- package/dist/cli/dev/discover.js +35 -0
- package/dist/cli/dev/fill-state.js +75 -0
- package/dist/cli/dev/index.js +32 -0
- package/dist/cli/dev/inspect.js +38 -0
- package/dist/cli/dev/island-bootstrap.js +38 -0
- package/dist/cli/dev/island-map.js +35 -0
- package/dist/cli/dev/island-transform.js +31 -0
- package/dist/cli/dev/manifest-instances.js +31 -0
- package/dist/cli/dev/render-section.js +24 -0
- package/dist/cli/dev/screenshot-target.js +24 -0
- package/dist/cli/dev/section-page.js +54 -0
- package/dist/cli/dev/server.js +480 -0
- package/dist/cli/dev/slot-schema.js +12 -0
- package/dist/cli/dev/structure-summary.js +118 -0
- package/dist/cli/dev/tailwind.js +32 -0
- package/dist/cli/dev/vite-server.js +33 -0
- package/dist/cli/dev/workspace.js +63 -0
- package/dist/cli/link/index.js +74 -0
- package/dist/cli/link/overlay.js +59 -0
- package/dist/cli/link/watch.js +25 -0
- package/dist/cli/new/emit.js +48 -0
- package/dist/cli/new/index.js +69 -0
- package/dist/cli/new/scaffold/section/_Renderer.tsx +20 -0
- package/dist/cli/new/scaffold/section/_fill-spec.ts +18 -0
- package/dist/cli/new/scaffold/section/_fixtures.ts +13 -0
- package/dist/cli/new/scaffold/section/_schema.ts +24 -0
- package/dist/cli/new/scaffold/template/_manifest.json +9 -0
- package/dist/cli/new/scaffold/template/sections/hero/ExpandableText.tsx +45 -0
- package/dist/cli/new/scaffold/template/sections/hero/Renderer.tsx +40 -0
- package/dist/cli/new/scaffold/template/sections/hero/components/Feature.tsx +14 -0
- package/dist/cli/new/scaffold/template/sections/hero/fill-spec.ts +29 -0
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +41 -0
- package/dist/cli/new/scaffold/template/sections/hero/schema.ts +60 -0
- package/dist/cli/new/scaffold/template/theme.css +24 -0
- package/dist/cli/new/scaffold/template/theme.ts +27 -0
- package/dist/cli/new/scaffold-assets.js +20 -0
- package/dist/cli/pack/collect.js +44 -0
- package/dist/cli/pack/guards.js +57 -0
- package/dist/cli/pack/index.js +66 -0
- package/dist/cli/pack/manifest.js +15 -0
- package/dist/cli/pack/zip.js +86 -0
- package/dist/cli/theme/generate.js +43 -0
- package/dist/cli/theme/index.js +33 -0
- package/dist/cli/theme/load-theme.js +69 -0
- package/dist/cli.js +100 -16
- package/dist/contracts/fill-treatments.js +47 -0
- package/dist/design-system/theme.d.ts +30 -300
- package/dist/design-system/theme.js +112 -90
- package/dist/dev-client/assets/index-DfEfrp6P.css +1 -0
- package/dist/dev-client/assets/index-bpMP0b0W.js +50 -0
- package/dist/dev-client/index.html +13 -0
- package/dist/eslint/is-client-file.d.ts +4 -0
- package/dist/eslint/rules/no-hex.js +78 -6
- package/dist/eslint.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/islands/detect.d.ts +16 -0
- package/dist/islands/detect.js +22 -0
- package/dist/islands/discover.d.ts +5 -0
- package/dist/islands/discover.js +19 -0
- package/dist/islands/esbuild-plugin.d.ts +13 -0
- package/dist/islands/esbuild-plugin.js +39 -0
- package/dist/islands/wrap.d.ts +11 -0
- package/dist/islands/wrap.js +48 -0
- package/dist/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +77 -0
- package/dist/node_modules/magic-string/dist/magic-string.es.js +939 -0
- package/dist/package.js +1 -1
- package/dist/primitives/Image.js +1 -1
- package/dist/schema/fill-spec.d.ts +80 -590
- package/dist/schema/fixture-schema.d.ts +5 -81
- package/dist/schema/manifest.d.ts +39 -475
- package/dist/schema/resolve-section-ref.js +10 -0
- package/dist/schema/rows.js +10 -0
- package/dist/schema/section-nav.js +9 -0
- package/dist/schema/section-schema.d.ts +51 -437
- package/dist/schema/slot-types.d.ts +12 -16
- package/dist/ssr.d.ts +31 -0
- package/dist/ssr.js +46 -0
- package/dist/styles.css +31 -88
- package/docs/INDEX.md +12 -3
- package/docs/assets.md +128 -0
- package/docs/check.md +124 -0
- package/docs/dev.md +187 -0
- package/docs/eslint.md +18 -8
- package/docs/islands.md +5 -2
- package/docs/llms.txt +59 -9
- package/docs/new.md +27 -0
- package/docs/overview.md +57 -0
- package/docs/pack.md +46 -0
- package/docs/primitives.md +10 -6
- package/docs/quickstart.md +102 -0
- package/docs/recipes/INDEX.md +27 -0
- package/docs/recipes/bind-property-fact.md +58 -0
- package/docs/recipes/collection-slot.md +100 -0
- package/docs/recipes/fill-spec-decision.md +66 -0
- package/docs/recipes/fixture-states.md +68 -0
- package/docs/recipes/image-slot-crop.md +98 -0
- package/docs/recipes/interactive-island.md +100 -0
- package/docs/recipes/organize-section-folder.md +72 -0
- package/docs/recipes/prepare-submission.md +55 -0
- package/docs/recipes/second-template.md +49 -0
- package/docs/recipes/select-slot.md +59 -0
- package/docs/recipes/static-asset.md +103 -0
- package/docs/recipes/third-party-package.md +90 -0
- package/docs/rules/INDEX.md +14 -5
- package/docs/rules/bundle-binary-asset.md +83 -0
- package/docs/rules/bundle-incomplete.md +2 -2
- package/docs/rules/css-reason.md +3 -3
- package/docs/rules/fixtures-invalid.md +96 -0
- package/docs/rules/license-denied.md +11 -3
- package/docs/rules/manifest-invalid.md +99 -0
- package/docs/rules/no-bare-css-import.md +8 -8
- package/docs/rules/no-css-import-from-render-path.md +7 -8
- package/docs/rules/no-hex.md +76 -10
- package/docs/rules/no-templates.md +87 -0
- package/docs/rules/parse-error.md +76 -0
- package/docs/rules/schema-invalid.md +96 -0
- package/docs/rules/size-assets.md +88 -0
- package/docs/rules/size-island-bundle.md +123 -0
- package/docs/rules/size-section-css.md +19 -14
- package/docs/schema-system.md +28 -28
- package/docs/theme-and-css.md +157 -92
- package/docs/vocabulary.md +98 -0
- package/package.json +14 -11
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/contracts/fill-treatments.ts
|
|
2
|
+
const GENERATED_KINDS = ["text", "list<text>"];
|
|
3
|
+
const COMPUTED_FNS = ["haversine_miles", "mint_id"];
|
|
4
|
+
const CATALOG_FIELDS = [
|
|
5
|
+
"key",
|
|
6
|
+
"label",
|
|
7
|
+
"icon",
|
|
8
|
+
"slot"
|
|
9
|
+
];
|
|
10
|
+
function parseTreatment(raw) {
|
|
11
|
+
if (raw === "source") return {
|
|
12
|
+
kind: "source",
|
|
13
|
+
path: null
|
|
14
|
+
};
|
|
15
|
+
if (raw.startsWith("source:")) {
|
|
16
|
+
const path = raw.slice(7);
|
|
17
|
+
return path ? {
|
|
18
|
+
kind: "source",
|
|
19
|
+
path
|
|
20
|
+
} : null;
|
|
21
|
+
}
|
|
22
|
+
if (raw.startsWith("computed:")) {
|
|
23
|
+
const fn = raw.slice(9);
|
|
24
|
+
return COMPUTED_FNS.includes(fn) ? {
|
|
25
|
+
kind: "computed",
|
|
26
|
+
fn
|
|
27
|
+
} : null;
|
|
28
|
+
}
|
|
29
|
+
if (raw.startsWith("catalog:")) {
|
|
30
|
+
const field = raw.slice(8);
|
|
31
|
+
return CATALOG_FIELDS.includes(field) ? {
|
|
32
|
+
kind: "catalog",
|
|
33
|
+
field
|
|
34
|
+
} : null;
|
|
35
|
+
}
|
|
36
|
+
if (raw.startsWith("generated:")) {
|
|
37
|
+
const outKind = raw.slice(10);
|
|
38
|
+
return GENERATED_KINDS.includes(outKind) ? {
|
|
39
|
+
kind: "generated",
|
|
40
|
+
outKind
|
|
41
|
+
} : null;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { CATALOG_FIELDS, COMPUTED_FNS, GENERATED_KINDS, parseTreatment };
|
|
@@ -1,308 +1,38 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/design-system/theme.d.ts
|
|
3
|
-
declare const
|
|
4
|
-
readonly ink: "--tr-color-ink";
|
|
5
|
-
readonly inkSoft: "--tr-color-ink-soft";
|
|
6
|
-
readonly inkMute: "--tr-color-ink-mute";
|
|
7
|
-
readonly background: "--tr-color-background";
|
|
8
|
-
readonly surface: "--tr-color-surface";
|
|
9
|
-
readonly surfaceAlt: "--tr-color-surface-alt";
|
|
10
|
-
readonly border: "--tr-color-border";
|
|
11
|
-
readonly borderStrong: "--tr-color-border-strong";
|
|
12
|
-
readonly primary: "--tr-color-primary";
|
|
13
|
-
readonly primaryFg: "--tr-color-primary-fg";
|
|
14
|
-
readonly primaryStrong: "--tr-color-primary-darker";
|
|
15
|
-
readonly accent: "--tr-color-accent";
|
|
16
|
-
readonly accentFg: "--tr-color-accent-contrast";
|
|
17
|
-
readonly accentStrong: "--tr-color-accent-strong";
|
|
18
|
-
readonly overlay: "--tr-color-overlay";
|
|
19
|
-
readonly overlayStrong: "--tr-color-overlay-strong";
|
|
20
|
-
readonly overlayLight: "--tr-color-overlay-light";
|
|
21
|
-
readonly darkBg: "--tr-color-footer-bg";
|
|
22
|
-
readonly darkFg: "--tr-color-footer-fg";
|
|
23
|
-
readonly darkFgMute: "--tr-color-footer-fg-mute";
|
|
24
|
-
readonly darkBorder: "--tr-color-footer-divider";
|
|
25
|
-
};
|
|
26
|
-
type ColorRole = keyof typeof COLOR_ROLE_VARS;
|
|
27
|
-
declare const FONT_ROLE_VARS: {
|
|
28
|
-
readonly body: "--tr-font-sans";
|
|
29
|
-
readonly heading: "--tr-font-serif";
|
|
30
|
-
readonly numeric: "--tr-font-num";
|
|
31
|
-
readonly label: "--tr-font-label";
|
|
32
|
-
};
|
|
33
|
-
declare const TYPE_STEP_VARS: {
|
|
34
|
-
readonly xs: "--tr-text-xs";
|
|
35
|
-
readonly sm: "--tr-text-sm";
|
|
36
|
-
readonly base: "--tr-text-base";
|
|
37
|
-
readonly lg: "--tr-text-lg";
|
|
38
|
-
readonly xl: "--tr-text-xl";
|
|
39
|
-
readonly "2xl": "--tr-text-2xl";
|
|
40
|
-
readonly "3xl": "--tr-text-3xl";
|
|
41
|
-
readonly "4xl": "--tr-text-4xl";
|
|
42
|
-
readonly "5xl": "--tr-text-5xl";
|
|
43
|
-
readonly display: "--tr-text-display";
|
|
44
|
-
};
|
|
45
|
-
declare const RADIUS_VARS: {
|
|
46
|
-
readonly sm: "--tr-radius-sm";
|
|
47
|
-
readonly md: "--tr-radius-md";
|
|
48
|
-
readonly lg: "--tr-radius-lg";
|
|
49
|
-
readonly full: "--tr-radius-full";
|
|
50
|
-
};
|
|
51
|
-
declare const SHADOW_VARS: {
|
|
52
|
-
readonly sm: "--tr-shadow-sm";
|
|
53
|
-
readonly md: "--tr-shadow-md";
|
|
54
|
-
readonly lg: "--tr-shadow-lg";
|
|
55
|
-
};
|
|
56
|
-
declare const LAYOUT_VARS: {
|
|
57
|
-
readonly containerMax: "--tr-container-max";
|
|
58
|
-
readonly containerPad: "--tr-container-pad";
|
|
59
|
-
readonly headerHeight: "--tr-header-height";
|
|
60
|
-
};
|
|
3
|
+
declare const TokenNameSchema: z.ZodString;
|
|
61
4
|
declare const TokenThemeSchema: z.ZodObject<{
|
|
62
|
-
colors: z.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
accentStrong: string;
|
|
77
|
-
overlay: string;
|
|
78
|
-
overlayStrong: string;
|
|
79
|
-
overlayLight: string;
|
|
80
|
-
darkBg: string;
|
|
81
|
-
darkFg: string;
|
|
82
|
-
darkFgMute: string;
|
|
83
|
-
darkBorder: string;
|
|
84
|
-
}, {
|
|
85
|
-
ink: string;
|
|
86
|
-
inkSoft: string;
|
|
87
|
-
inkMute: string;
|
|
88
|
-
background: string;
|
|
89
|
-
surface: string;
|
|
90
|
-
surfaceAlt: string;
|
|
91
|
-
border: string;
|
|
92
|
-
borderStrong: string;
|
|
93
|
-
primary: string;
|
|
94
|
-
primaryFg: string;
|
|
95
|
-
primaryStrong: string;
|
|
96
|
-
accent: string;
|
|
97
|
-
accentFg: string;
|
|
98
|
-
accentStrong: string;
|
|
99
|
-
overlay: string;
|
|
100
|
-
overlayStrong: string;
|
|
101
|
-
overlayLight: string;
|
|
102
|
-
darkBg: string;
|
|
103
|
-
darkFg: string;
|
|
104
|
-
darkFgMute: string;
|
|
105
|
-
darkBorder: string;
|
|
106
|
-
}>;
|
|
107
|
-
/** Optional open brand palette → `--tr-color-<name>` (the escape hatch). */
|
|
108
|
-
palette: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
109
|
-
fonts: z.ZodObject<Record<"body" | "heading" | "numeric" | "label", z.ZodString> & {
|
|
110
|
-
/** Font-loading block (@import / @font-face) emitted before :root. */
|
|
111
|
-
fontFaces: z.ZodOptional<z.ZodString>;
|
|
112
|
-
}, "strip", z.ZodTypeAny, {
|
|
113
|
-
body: string;
|
|
114
|
-
heading: string;
|
|
115
|
-
numeric: string;
|
|
116
|
-
label: string;
|
|
117
|
-
fontFaces?: string | undefined;
|
|
118
|
-
}, {
|
|
119
|
-
body: string;
|
|
120
|
-
heading: string;
|
|
121
|
-
numeric: string;
|
|
122
|
-
label: string;
|
|
123
|
-
fontFaces?: string | undefined;
|
|
124
|
-
}>;
|
|
125
|
-
type: z.ZodObject<Record<"xs" | "sm" | "base" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "display", z.ZodString>, "strip", z.ZodTypeAny, {
|
|
126
|
-
xs: string;
|
|
127
|
-
sm: string;
|
|
128
|
-
base: string;
|
|
129
|
-
lg: string;
|
|
130
|
-
xl: string;
|
|
131
|
-
"2xl": string;
|
|
132
|
-
"3xl": string;
|
|
133
|
-
"4xl": string;
|
|
134
|
-
"5xl": string;
|
|
135
|
-
display: string;
|
|
136
|
-
}, {
|
|
137
|
-
xs: string;
|
|
138
|
-
sm: string;
|
|
139
|
-
base: string;
|
|
140
|
-
lg: string;
|
|
141
|
-
xl: string;
|
|
142
|
-
"2xl": string;
|
|
143
|
-
"3xl": string;
|
|
144
|
-
"4xl": string;
|
|
145
|
-
"5xl": string;
|
|
146
|
-
display: string;
|
|
147
|
-
}>;
|
|
148
|
-
radii: z.ZodObject<Record<"sm" | "lg" | "md" | "full", z.ZodString>, "strip", z.ZodTypeAny, {
|
|
149
|
-
sm: string;
|
|
150
|
-
lg: string;
|
|
151
|
-
md: string;
|
|
152
|
-
full: string;
|
|
153
|
-
}, {
|
|
154
|
-
sm: string;
|
|
155
|
-
lg: string;
|
|
156
|
-
md: string;
|
|
157
|
-
full: string;
|
|
158
|
-
}>;
|
|
159
|
-
shadows: z.ZodObject<Record<"sm" | "lg" | "md", z.ZodString>, "strip", z.ZodTypeAny, {
|
|
160
|
-
sm: string;
|
|
161
|
-
lg: string;
|
|
162
|
-
md: string;
|
|
163
|
-
}, {
|
|
164
|
-
sm: string;
|
|
165
|
-
lg: string;
|
|
166
|
-
md: string;
|
|
167
|
-
}>;
|
|
168
|
-
layout: z.ZodObject<Record<"containerMax" | "containerPad" | "headerHeight", z.ZodString>, "strip", z.ZodTypeAny, {
|
|
169
|
-
containerMax: string;
|
|
170
|
-
containerPad: string;
|
|
171
|
-
headerHeight: string;
|
|
172
|
-
}, {
|
|
173
|
-
containerMax: string;
|
|
174
|
-
containerPad: string;
|
|
175
|
-
headerHeight: string;
|
|
176
|
-
}>;
|
|
177
|
-
}, "strict", z.ZodTypeAny, {
|
|
178
|
-
type: {
|
|
179
|
-
xs: string;
|
|
180
|
-
sm: string;
|
|
181
|
-
base: string;
|
|
182
|
-
lg: string;
|
|
183
|
-
xl: string;
|
|
184
|
-
"2xl": string;
|
|
185
|
-
"3xl": string;
|
|
186
|
-
"4xl": string;
|
|
187
|
-
"5xl": string;
|
|
188
|
-
display: string;
|
|
189
|
-
};
|
|
190
|
-
colors: {
|
|
191
|
-
ink: string;
|
|
192
|
-
inkSoft: string;
|
|
193
|
-
inkMute: string;
|
|
194
|
-
background: string;
|
|
195
|
-
surface: string;
|
|
196
|
-
surfaceAlt: string;
|
|
197
|
-
border: string;
|
|
198
|
-
borderStrong: string;
|
|
199
|
-
primary: string;
|
|
200
|
-
primaryFg: string;
|
|
201
|
-
primaryStrong: string;
|
|
202
|
-
accent: string;
|
|
203
|
-
accentFg: string;
|
|
204
|
-
accentStrong: string;
|
|
205
|
-
overlay: string;
|
|
206
|
-
overlayStrong: string;
|
|
207
|
-
overlayLight: string;
|
|
208
|
-
darkBg: string;
|
|
209
|
-
darkFg: string;
|
|
210
|
-
darkFgMute: string;
|
|
211
|
-
darkBorder: string;
|
|
212
|
-
};
|
|
213
|
-
fonts: {
|
|
214
|
-
body: string;
|
|
215
|
-
heading: string;
|
|
216
|
-
numeric: string;
|
|
217
|
-
label: string;
|
|
218
|
-
fontFaces?: string | undefined;
|
|
219
|
-
};
|
|
220
|
-
radii: {
|
|
221
|
-
sm: string;
|
|
222
|
-
lg: string;
|
|
223
|
-
md: string;
|
|
224
|
-
full: string;
|
|
225
|
-
};
|
|
226
|
-
shadows: {
|
|
227
|
-
sm: string;
|
|
228
|
-
lg: string;
|
|
229
|
-
md: string;
|
|
230
|
-
};
|
|
231
|
-
layout: {
|
|
232
|
-
containerMax: string;
|
|
233
|
-
containerPad: string;
|
|
234
|
-
headerHeight: string;
|
|
235
|
-
};
|
|
236
|
-
palette?: Record<string, string> | undefined;
|
|
237
|
-
}, {
|
|
238
|
-
type: {
|
|
239
|
-
xs: string;
|
|
240
|
-
sm: string;
|
|
241
|
-
base: string;
|
|
242
|
-
lg: string;
|
|
243
|
-
xl: string;
|
|
244
|
-
"2xl": string;
|
|
245
|
-
"3xl": string;
|
|
246
|
-
"4xl": string;
|
|
247
|
-
"5xl": string;
|
|
248
|
-
display: string;
|
|
249
|
-
};
|
|
250
|
-
colors: {
|
|
251
|
-
ink: string;
|
|
252
|
-
inkSoft: string;
|
|
253
|
-
inkMute: string;
|
|
254
|
-
background: string;
|
|
255
|
-
surface: string;
|
|
256
|
-
surfaceAlt: string;
|
|
257
|
-
border: string;
|
|
258
|
-
borderStrong: string;
|
|
259
|
-
primary: string;
|
|
260
|
-
primaryFg: string;
|
|
261
|
-
primaryStrong: string;
|
|
262
|
-
accent: string;
|
|
263
|
-
accentFg: string;
|
|
264
|
-
accentStrong: string;
|
|
265
|
-
overlay: string;
|
|
266
|
-
overlayStrong: string;
|
|
267
|
-
overlayLight: string;
|
|
268
|
-
darkBg: string;
|
|
269
|
-
darkFg: string;
|
|
270
|
-
darkFgMute: string;
|
|
271
|
-
darkBorder: string;
|
|
272
|
-
};
|
|
273
|
-
fonts: {
|
|
274
|
-
body: string;
|
|
275
|
-
heading: string;
|
|
276
|
-
numeric: string;
|
|
277
|
-
label: string;
|
|
278
|
-
fontFaces?: string | undefined;
|
|
279
|
-
};
|
|
280
|
-
radii: {
|
|
281
|
-
sm: string;
|
|
282
|
-
lg: string;
|
|
283
|
-
md: string;
|
|
284
|
-
full: string;
|
|
285
|
-
};
|
|
286
|
-
shadows: {
|
|
287
|
-
sm: string;
|
|
288
|
-
lg: string;
|
|
289
|
-
md: string;
|
|
290
|
-
};
|
|
291
|
-
layout: {
|
|
292
|
-
containerMax: string;
|
|
293
|
-
containerPad: string;
|
|
294
|
-
headerHeight: string;
|
|
295
|
-
};
|
|
296
|
-
palette?: Record<string, string> | undefined;
|
|
297
|
-
}>;
|
|
5
|
+
colors: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
6
|
+
fonts: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
7
|
+
type: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
8
|
+
radii: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
9
|
+
shadows: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
10
|
+
layout: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
11
|
+
fontFaces: z.ZodOptional<z.ZodString>;
|
|
12
|
+
document: z.ZodObject<{
|
|
13
|
+
font: z.ZodString;
|
|
14
|
+
color: z.ZodString;
|
|
15
|
+
background: z.ZodString;
|
|
16
|
+
fontSize: z.ZodString;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
}, z.core.$strict>;
|
|
298
19
|
type TokenTheme = z.infer<typeof TokenThemeSchema>;
|
|
299
20
|
/**
|
|
300
|
-
* Compile a `TokenTheme` into the CSS a template's bundle ships:
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
21
|
+
* Compile a `TokenTheme` into the CSS a template's bundle ships:
|
|
22
|
+
*
|
|
23
|
+
* 1. the optional font-loading block;
|
|
24
|
+
* 2. `@theme inline { --color-<name>: var(--tr-color-<name>); … }` — the Tailwind
|
|
25
|
+
* alias layer, which is what brings the token utilities into existence;
|
|
26
|
+
* 3. `:root { --tr-color-<name>: <value>; … }` — the values behind those aliases;
|
|
27
|
+
* 4. `body { … }` — the document defaults, as `var()` indirections so that a runtime
|
|
28
|
+
* `:root` override still cascades to the page.
|
|
29
|
+
*
|
|
30
|
+
* The output MUST be compiled INSIDE the Tailwind build graph: `@theme` is a Tailwind
|
|
31
|
+
* directive, and anywhere else it is inert — silently, yielding a stylesheet with no
|
|
32
|
+
* token utilities and no error to explain why.
|
|
33
|
+
*
|
|
34
|
+
* Deterministic: keys are sorted, so the same theme always content-hashes identically.
|
|
305
35
|
*/
|
|
306
36
|
declare function compileThemeToCss(theme: TokenTheme): string;
|
|
307
37
|
//#endregion
|
|
308
|
-
export {
|
|
38
|
+
export { TokenNameSchema, TokenTheme, TokenThemeSchema, compileThemeToCss };
|
|
@@ -1,102 +1,124 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
//#region src/design-system/theme.ts
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
4
|
+
const TokenNameSchema = z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "token names are kebab-case: [a-z0-9] groups separated by single hyphens");
|
|
5
|
+
const tokens = z.record(TokenNameSchema, z.string().min(1));
|
|
6
|
+
const NAMESPACES = {
|
|
7
|
+
colors: {
|
|
8
|
+
tw: "--color-",
|
|
9
|
+
tr: "--tr-color-"
|
|
10
|
+
},
|
|
11
|
+
fonts: {
|
|
12
|
+
tw: "--font-",
|
|
13
|
+
tr: "--tr-font-"
|
|
14
|
+
},
|
|
15
|
+
type: {
|
|
16
|
+
tw: "--text-",
|
|
17
|
+
tr: "--tr-text-"
|
|
18
|
+
},
|
|
19
|
+
radii: {
|
|
20
|
+
tw: "--radius-",
|
|
21
|
+
tr: "--tr-radius-"
|
|
22
|
+
},
|
|
23
|
+
shadows: {
|
|
24
|
+
tw: "--shadow-",
|
|
25
|
+
tr: "--tr-shadow-"
|
|
26
|
+
}
|
|
26
27
|
};
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const TYPE_STEP_VARS = {
|
|
34
|
-
xs: "--tr-text-xs",
|
|
35
|
-
sm: "--tr-text-sm",
|
|
36
|
-
base: "--tr-text-base",
|
|
37
|
-
lg: "--tr-text-lg",
|
|
38
|
-
xl: "--tr-text-xl",
|
|
39
|
-
"2xl": "--tr-text-2xl",
|
|
40
|
-
"3xl": "--tr-text-3xl",
|
|
41
|
-
"4xl": "--tr-text-4xl",
|
|
42
|
-
"5xl": "--tr-text-5xl",
|
|
43
|
-
display: "--tr-text-display"
|
|
44
|
-
};
|
|
45
|
-
const RADIUS_VARS = {
|
|
46
|
-
sm: "--tr-radius-sm",
|
|
47
|
-
md: "--tr-radius-md",
|
|
48
|
-
lg: "--tr-radius-lg",
|
|
49
|
-
full: "--tr-radius-full"
|
|
50
|
-
};
|
|
51
|
-
const SHADOW_VARS = {
|
|
52
|
-
sm: "--tr-shadow-sm",
|
|
53
|
-
md: "--tr-shadow-md",
|
|
54
|
-
lg: "--tr-shadow-lg"
|
|
55
|
-
};
|
|
56
|
-
const LAYOUT_VARS = {
|
|
57
|
-
containerMax: "--tr-container-max",
|
|
58
|
-
containerPad: "--tr-container-pad",
|
|
59
|
-
headerHeight: "--tr-header-height"
|
|
60
|
-
};
|
|
61
|
-
const colorRoles = Object.fromEntries(Object.keys(COLOR_ROLE_VARS).map((k) => [k, z.string().min(1)]));
|
|
62
|
-
const scale = (keys) => z.object(Object.fromEntries(keys.map((k) => [k, z.string().min(1)])));
|
|
63
|
-
const TokenThemeSchema = z.object({
|
|
64
|
-
colors: z.object(colorRoles),
|
|
65
|
-
/** Optional open brand palette → `--tr-color-<name>` (the escape hatch). */
|
|
66
|
-
palette: z.record(z.string().min(1)).optional(),
|
|
67
|
-
fonts: scale(Object.keys(FONT_ROLE_VARS)).extend({
|
|
68
|
-
/** Font-loading block (@import / @font-face) emitted before :root. */
|
|
69
|
-
fontFaces: z.string().optional() }),
|
|
70
|
-
type: scale(Object.keys(TYPE_STEP_VARS)),
|
|
71
|
-
radii: scale(Object.keys(RADIUS_VARS)),
|
|
72
|
-
shadows: scale(Object.keys(SHADOW_VARS)),
|
|
73
|
-
layout: scale(Object.keys(LAYOUT_VARS))
|
|
28
|
+
const NAMESPACED_GROUPS = Object.keys(NAMESPACES);
|
|
29
|
+
const DocumentDefaultsSchema = z.object({
|
|
30
|
+
font: TokenNameSchema,
|
|
31
|
+
color: TokenNameSchema,
|
|
32
|
+
background: TokenNameSchema,
|
|
33
|
+
fontSize: TokenNameSchema
|
|
74
34
|
}).strict();
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
35
|
+
const TokenThemeSchema = z.object({
|
|
36
|
+
colors: tokens,
|
|
37
|
+
fonts: tokens,
|
|
38
|
+
type: tokens,
|
|
39
|
+
radii: tokens,
|
|
40
|
+
shadows: tokens,
|
|
41
|
+
/** Layout values → `--tr-<name>`. No Tailwind alias: not a utility namespace. */
|
|
42
|
+
layout: tokens,
|
|
43
|
+
/** Font-loading block (@import / @font-face), emitted before every other block. */
|
|
44
|
+
fontFaces: z.string().optional(),
|
|
45
|
+
document: DocumentDefaultsSchema
|
|
46
|
+
}).strict().superRefine((theme, ctx) => {
|
|
47
|
+
for (const name of Object.keys(theme.colors)) if (Object.hasOwn(theme.type, name)) ctx.addIssue({
|
|
48
|
+
code: z.ZodIssueCode.custom,
|
|
49
|
+
path: ["type", name],
|
|
50
|
+
message: `"${name}" is declared in both \`colors\` and \`type\`, and both compile to \`text-${name}\` — rename one.`
|
|
51
|
+
});
|
|
52
|
+
}).superRefine((theme, ctx) => {
|
|
53
|
+
const refs = [
|
|
54
|
+
[
|
|
55
|
+
"font",
|
|
56
|
+
"fonts",
|
|
57
|
+
theme.document.font
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"color",
|
|
61
|
+
"colors",
|
|
62
|
+
theme.document.color
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
"background",
|
|
66
|
+
"colors",
|
|
67
|
+
theme.document.background
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
"fontSize",
|
|
71
|
+
"type",
|
|
72
|
+
theme.document.fontSize
|
|
73
|
+
]
|
|
74
|
+
];
|
|
75
|
+
for (const [field, group, name] of refs) if (!Object.hasOwn(theme[group], name)) ctx.addIssue({
|
|
76
|
+
code: z.ZodIssueCode.custom,
|
|
77
|
+
path: ["document", field],
|
|
78
|
+
message: `document.${field}: "${name}" is not a declared \`${group}\` token`
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
81
|
/**
|
|
82
|
-
* Compile a `TokenTheme` into the CSS a template's bundle ships:
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
82
|
+
* Compile a `TokenTheme` into the CSS a template's bundle ships:
|
|
83
|
+
*
|
|
84
|
+
* 1. the optional font-loading block;
|
|
85
|
+
* 2. `@theme inline { --color-<name>: var(--tr-color-<name>); … }` — the Tailwind
|
|
86
|
+
* alias layer, which is what brings the token utilities into existence;
|
|
87
|
+
* 3. `:root { --tr-color-<name>: <value>; … }` — the values behind those aliases;
|
|
88
|
+
* 4. `body { … }` — the document defaults, as `var()` indirections so that a runtime
|
|
89
|
+
* `:root` override still cascades to the page.
|
|
90
|
+
*
|
|
91
|
+
* The output MUST be compiled INSIDE the Tailwind build graph: `@theme` is a Tailwind
|
|
92
|
+
* directive, and anywhere else it is inert — silently, yielding a stylesheet with no
|
|
93
|
+
* token utilities and no error to explain why.
|
|
94
|
+
*
|
|
95
|
+
* Deterministic: keys are sorted, so the same theme always content-hashes identically.
|
|
87
96
|
*/
|
|
88
97
|
function compileThemeToCss(theme) {
|
|
98
|
+
const aliases = [];
|
|
89
99
|
const decls = [];
|
|
90
|
-
for (const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
100
|
+
for (const group of NAMESPACED_GROUPS) {
|
|
101
|
+
const { tw, tr } = NAMESPACES[group];
|
|
102
|
+
for (const name of Object.keys(theme[group]).sort()) {
|
|
103
|
+
aliases.push(` ${tw}${name}: var(${tr}${name});`);
|
|
104
|
+
decls.push(` ${tr}${name}: ${theme[group][name]};`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const name of Object.keys(theme.layout).sort()) decls.push(` --tr-${name}: ${theme.layout[name]};`);
|
|
108
|
+
const { font, color, background, fontSize } = theme.document;
|
|
109
|
+
const body = `body {
|
|
110
|
+
font-family: var(--tr-font-${font});
|
|
111
|
+
color: var(--tr-color-${color});
|
|
112
|
+
background: var(--tr-color-${background});
|
|
113
|
+
font-size: var(--tr-text-${fontSize});
|
|
114
|
+
}`;
|
|
115
|
+
const blocks = [
|
|
116
|
+
`@theme inline {\n${aliases.join("\n")}\n}`,
|
|
117
|
+
`:root {\n${decls.join("\n")}\n}`,
|
|
118
|
+
body
|
|
119
|
+
].join("\n\n");
|
|
120
|
+
return theme.fontFaces ? `${theme.fontFaces}\n\n${blocks}\n` : `${blocks}\n`;
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
//#endregion
|
|
102
|
-
export {
|
|
124
|
+
export { TokenNameSchema, TokenThemeSchema, compileThemeToCss };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{box-sizing:border-box}html,body,#root{margin:0;padding:0;height:100%;background:#0f1115;color:#e6e7eb;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,Segoe UI,Helvetica,Arial,sans-serif}a{color:inherit;text-decoration:none}button,select,input,textarea{font:inherit;color:inherit;background:#1a1d24;border:1px solid #2c313a;border-radius:4px;padding:6px 10px}button{cursor:pointer}button:hover{background:#232831}button:disabled{opacity:.4;cursor:default}.empty{padding:40px;color:#9ca0a8;text-align:center}.boot-error{padding:24px;color:#ff8b8b;font:13px/1.5 ui-monospace,Menlo,monospace;white-space:pre-wrap}.canvas-mirror{display:flex;flex-direction:column;height:100%;min-height:0}.canvas-toolbar{display:flex;gap:8px;padding:6px 10px;border-bottom:1px solid #e2e5ea;background:#fafbfc}.canvas-toolbar button{font:12px system-ui,sans-serif;padding:3px 8px;border:1px solid #cbd2dc;border-radius:5px;background:#fff;cursor:pointer}.canvas-iframe{flex:1 1 auto;width:100%;border:0;background:#fff;min-height:0}.home{max-width:880px;margin:0 auto;padding:40px 24px}.home-header{margin-bottom:28px}.home-title{font-size:15px;font-weight:600}.home-tagline{font-size:13px;color:#9ca0a8;margin-top:4px}.home-template{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:#9ca0a8;margin-bottom:24px}.home-template select{min-width:160px}.home-tools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.tool-card{display:flex;flex-direction:column;gap:12px;background:#14171c;border:1px solid #21252d;border-radius:8px;padding:20px}.tool-card h2{font-size:14px;font-weight:600;margin:0}.tool-card p{font-size:13px;color:#9ca0a8;margin:0;line-height:1.5}.tool-card .controls{display:flex;flex-direction:column;gap:8px}.tool-card label{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:#9ca0a8}.tool-card label select{min-width:140px}.open-btn{margin-top:auto;text-align:center;padding:8px 12px;border:1px solid #2c313a;border-radius:6px;background:#1a1d24;color:inherit;cursor:pointer}.open-btn:hover{background:#232831}.open-btn:disabled{opacity:.4;cursor:default}.home-hint{font-size:12px;color:#6b7280}.home-link{font-weight:600;color:#1a1d24}.canvas-toolbar .spacer{flex:1}.canvas-mirror__stage{display:flex;min-height:0;flex:1}.canvas-mirror__stage .canvas-iframe{flex:1}.instance-panel{width:340px;flex:none;overflow-y:auto;border-left:1px solid #e5e7eb;padding:12px;background:#fff;font:13px system-ui,sans-serif;display:flex;flex-direction:column;gap:10px}.instance-panel__head{display:flex;flex-direction:column;gap:8px}.instance-panel__slot{display:flex;align-items:center;gap:8px}.instance-panel__type{color:#6b7280}.instance-panel__fill{margin-left:auto;padding:1px 7px;border-radius:999px;font-size:11px}.instance-panel__fill--filled{background:#dcfce7;color:#166534}.instance-panel__fill--empty{background:#f3f4f6;color:#6b7280}.instance-panel__fill--missing{background:#fee2e2;color:#991b1b}.instance-panel__fixture{display:flex;flex-direction:column;gap:3px;color:#6b7280}.instance-panel__json{width:100%;min-height:180px;font:12px ui-monospace,monospace;resize:vertical}.instance-panel__error{color:#b91c1c;white-space:pre-wrap}.instance-panel__actions{display:flex;gap:8px}.instance-panel__note{color:#9ca3af;font-size:11px}
|