@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,227 @@
|
|
|
1
1
|
# @homepages/template-kit
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 94d6458: `template-kit dev`: a full-template published page at `/template/<t>`, scope-aware
|
|
8
|
+
`/api/screenshot` (section or whole template, with `width`), and a new `/api/inspect`
|
|
9
|
+
endpoint returning per-slot fill-state (filled / empty / missing + a render
|
|
10
|
+
cross-check), resolved props, and the null-corpus. Retires `/api/structure-summary`
|
|
11
|
+
(its outline is now `/api/inspect?format=text`).
|
|
12
|
+
- 47dbbc6: Section-folder static assets are now first-class. `check`'s `bundle-binary-asset` rule
|
|
13
|
+
flags only an _unreferenced_ binary in a section folder; an asset imported in a component
|
|
14
|
+
(`import crest from "./assets/crest.svg"` → `<Image src={crest} …>`) or `url()`-referenced
|
|
15
|
+
from a section stylesheet is allowed. A `declare module "*.svg"` (and the other supported
|
|
16
|
+
asset extensions) type shim ships so component imports of assets typecheck.
|
|
17
|
+
- 9a3e0e1: Adds a read-only canvas mirror to `template-kit dev`, at `/canvas/<template>`. It frames
|
|
18
|
+
the **whole template** — every section instance, stacked in one scroll container, exactly
|
|
19
|
+
as the deliverable renders — in an iframe and paints a hover/select overlay on top: click
|
|
20
|
+
an editable slot to select it (a gold ring), hover to preview it (a blue ring);
|
|
21
|
+
non-editable regions select their enclosing section instead. Selection is scoped per
|
|
22
|
+
section instance, so the same slot name in two sections resolves independently. The
|
|
23
|
+
overlay is purely visual — it never alters the rendered markup. A mode toggle switches to
|
|
24
|
+
a clean published render of the full template with no overlay, and the current view —
|
|
25
|
+
template, mode, and the selected instance/slot — is captured in the URL, so a canvas link
|
|
26
|
+
reloads and shares exactly what you see.
|
|
27
|
+
|
|
28
|
+
The `dev` server gains `GET /api/template-schema?template=<t>`, returning each section
|
|
29
|
+
instance's editability map (per slot: its type and whether it is user-editable) for the
|
|
30
|
+
whole template, so a tool can tell which slots are selectable without re-parsing the
|
|
31
|
+
section schemas. (The per-section `/api/render` response also still carries its own
|
|
32
|
+
`slotSchema` map.)
|
|
33
|
+
|
|
34
|
+
- 7f68570: Canvas mirror: exercise slots interactively. Selecting an editable slot opens a
|
|
35
|
+
side panel with a JSON editor for its value; applying a change re-renders that
|
|
36
|
+
section instance live. A per-instance fixture picker drives different content —
|
|
37
|
+
including the empty/missing states from the section's fixture corpus — without
|
|
38
|
+
editing fixture files.
|
|
39
|
+
- 5a8dcd4: Adds the `dev` command: `template-kit dev [template] [--port <n>]`. A local preview
|
|
40
|
+
server for a workspace's templates — it renders every section against its fixtures
|
|
41
|
+
server-side, with the template's theme and compiled Tailwind utilities, exactly the way
|
|
42
|
+
the platform does. A browser UI gives you a picker (template → section → fixture) and a
|
|
43
|
+
grid contact sheet of every fixture at each breakpoint, including empty and null states;
|
|
44
|
+
each section also has a standalone preview at `/sections/<template>/<section>/<fixture>`.
|
|
45
|
+
Editing a section reloads open previews; editing a theme hot-swaps its stylesheet.
|
|
46
|
+
|
|
47
|
+
Endpoints render a section without a browser, for an agent verifying its work from a
|
|
48
|
+
terminal: `/api/inspect` (a low-context per-slot fill-state view as JSON, with
|
|
49
|
+
`?format=text` for the rendered outline) and `/api/screenshot` (a full-page PNG). Like
|
|
50
|
+
`check`, `dev` runs your
|
|
51
|
+
toolchain — Vite and Tailwind resolved from your workspace, not shipped by the kit:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm i -D vite @vitejs/plugin-react tailwindcss @tailwindcss/cli
|
|
55
|
+
npm i -D @playwright/test # optional, for /api/screenshot
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- 13c3132: Add `template-kit pack <template>` — the per-template submission zip (template
|
|
59
|
+
source + workspace lockfile + a stamped `pack-manifest.json`), which refuses on a
|
|
60
|
+
failing `check`, an active link overlay, a missing lockfile, or local-protocol
|
|
61
|
+
deps. Add the internal `link`/`unlink`/`status` overlay for developing the kit
|
|
62
|
+
against a real consumer without publishing.
|
|
63
|
+
- bcf6fbb: `@homepages/template-kit/ssr` now also exports `wrapClientModuleSource` (the `"use
|
|
64
|
+
client"` → `IslandMarker` codemod), `findSectionIslands` (recursive `"use client"`
|
|
65
|
+
component discovery under a section directory), and `islandTransformEsbuildPlugin`
|
|
66
|
+
(an esbuild `onLoad` plugin that applies the same codemod across a build graph, keyed
|
|
67
|
+
`islandKey(sectionKey, <file-basename>)`). All three are the same primitives
|
|
68
|
+
`template-kit dev`'s Vite plugin already used internally, now exposed so a build-time
|
|
69
|
+
consumer — the publish renderer bundle's esbuild pass, or a native-import loader hook —
|
|
70
|
+
can wrap island modules identically without duplicating the codemod. `esbuild` stays a
|
|
71
|
+
devDependency of the kit; `islandTransformEsbuildPlugin` imports its `Plugin` type only.
|
|
72
|
+
- b76f822: Add the node-only `@homepages/template-kit/ssr` subpath: the shared section SSR helper (`loadSectionBundle`, `renderSectionHtml`) that renders a section + fixture to the exact HTML the publisher emits, plus island detection (`isClientComponentFile`, `hasClientDirective`) and key derivation (`islandKey`) for a section's `"use client"` components.
|
|
73
|
+
|
|
74
|
+
## 0.3.0
|
|
75
|
+
|
|
76
|
+
### Minor Changes
|
|
77
|
+
|
|
78
|
+
- bdb4dec: `zod` is now the kit's only dependency of any kind, besides its React peers. ESLint,
|
|
79
|
+
`@typescript-eslint/parser` and `esbuild` are no longer declared by the kit at all — a
|
|
80
|
+
linter and a bundler are development tools, and as dependencies they landed in the
|
|
81
|
+
**production** install of every consumer, including apps that only render a published
|
|
82
|
+
template and deploy with `npm ci --omit=dev`. For a consuming service that lints, the
|
|
83
|
+
production dependency graph drops by roughly 125 packages.
|
|
84
|
+
|
|
85
|
+
**Action required if you use the ESLint preset or the `check` command** — install the
|
|
86
|
+
toolchain they run, which they now resolve from your workspace rather than shipping
|
|
87
|
+
their own copy of:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npm i -D eslint @typescript-eslint/parser # for @homepages/template-kit/eslint
|
|
91
|
+
npm i -D typescript esbuild # for template-kit check (with the two above)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Nothing changes for code that only imports the kit's primitives, schema system or theme
|
|
95
|
+
tokens. The preset's rules and parser wiring are unchanged; `check`'s stages and rule ids
|
|
96
|
+
are unchanged — and it now reports a missing tool by name, with the install line, instead
|
|
97
|
+
of failing obscurely. As a side benefit, `check` runs against _your_ pinned TypeScript,
|
|
98
|
+
ESLint and esbuild.
|
|
99
|
+
|
|
100
|
+
- 49177ab: Adds the `check` command: `template-kit check [template] [--all] [--json]`. Runs a
|
|
101
|
+
template's authoring contract end to end — type errors, the lint preset, the schema and
|
|
102
|
+
manifest contracts, section-folder structure (contract files present, editor slot
|
|
103
|
+
markers, hand-CSS hygiene), a render-regression pass (determinism, broken images, and
|
|
104
|
+
other objective defects), and per-section bundle-size budgets — plus workspace-wide
|
|
105
|
+
dependency gates (lockfile health, a single copy of React, dependency licenses,
|
|
106
|
+
vulnerability severity) evaluated once per run. Every failure prints a stable rule id, a
|
|
107
|
+
file and line, and a one-line fix. Exits non-zero on any failure; pass `--json` for a
|
|
108
|
+
script-consumable report.
|
|
109
|
+
- 2a30f0b: `template-kit theme` generates your template's `theme.css` from its `theme.ts`.
|
|
110
|
+
|
|
111
|
+
`@theme` is a Tailwind directive — it only does anything when a real `.css` file carrying
|
|
112
|
+
it flows through your Tailwind entry. So the alias layer `compileThemeToCss` produces from
|
|
113
|
+
your `theme.ts` has to reach that entry as a file. Rather than call the compiler from your
|
|
114
|
+
own build script (and risk `theme.css` silently drifting from `theme.ts`), run:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
template-kit theme # the template in the current folder
|
|
118
|
+
template-kit theme <name> # a named template
|
|
119
|
+
template-kit theme --all # every template in the workspace
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
It reads `templates/<key>/theme.ts` (which must `export const theme: TokenTheme`), validates
|
|
123
|
+
it, and writes `templates/<key>/theme.css` with a "generated — do not edit" header. Import
|
|
124
|
+
that file into your Tailwind entry after `@import "tailwindcss"` and the kit's `styles.css`:
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
@import "tailwindcss";
|
|
128
|
+
@import "@homepages/template-kit/styles.css";
|
|
129
|
+
@import "./theme.css"; /* generated by `template-kit theme` */
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Re-run the command whenever you change `theme.ts`; a token you add becomes a working Tailwind
|
|
133
|
+
utility with nothing else to edit. A missing `theme.ts`, a missing `theme` export, or a theme
|
|
134
|
+
that fails validation each fail with an actionable message.
|
|
135
|
+
|
|
136
|
+
- e15de58: Your template now owns its design tokens end to end — and names them itself.
|
|
137
|
+
|
|
138
|
+
`TokenTheme` no longer imposes a vocabulary. Instead of satisfying a fixed set of
|
|
139
|
+
semantic roles (`ink`, `surfaceAlt`, `primaryStrong`, …), you declare whatever tokens
|
|
140
|
+
your design actually has, under kebab-case names you choose, and `compileThemeToCss`
|
|
141
|
+
generates the Tailwind `@theme inline` alias layer from them. Declare `lagoon` and
|
|
142
|
+
`bg-lagoon` exists. Nothing is required, and Tailwind's own defaults (`text-2xl`,
|
|
143
|
+
`rounded-lg`, `red-500`) still work underneath, so a sparse theme is a working theme.
|
|
144
|
+
|
|
145
|
+
This also closes the hole that made the old "open palette" a fiction: a brand swatch
|
|
146
|
+
only became a usable utility once it was added to the kit's shared `styles.css`, so it
|
|
147
|
+
was never really yours. There is no shared file to edit any more.
|
|
148
|
+
|
|
149
|
+
**Upgrading — three changes:**
|
|
150
|
+
|
|
151
|
+
1. **Rewrite `theme.ts`.** `colors` and `palette` merge into one open record, and keys
|
|
152
|
+
become kebab-case (`inkSoft` → `ink-soft`). `fontFaces` moves out of `fonts` to the
|
|
153
|
+
top level. Emission is verbatim: the key `ink-soft` becomes `--tr-color-ink-soft` and
|
|
154
|
+
the `text-ink-soft` utility.
|
|
155
|
+
|
|
156
|
+
One token yields exactly one utility, so two utility names mean two tokens. If you
|
|
157
|
+
relied on an alias that pointed two names at one value, declare both.
|
|
158
|
+
|
|
159
|
+
2. **Add a `document` block.** The `body` defaults can no longer be assumed — there is no
|
|
160
|
+
`ink` to guess at — so name the tokens that dress the page:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
document: { font: "sans", color: "ink", background: "page", fontSize: "base" }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Each reference is validated against your declared tokens: a typo fails at build
|
|
167
|
+
rather than rendering an unthemed page in silence.
|
|
168
|
+
|
|
169
|
+
3. **Import your compiled theme into your Tailwind entry.** `@theme` is a Tailwind
|
|
170
|
+
directive and is inert outside the build graph, so the theme partial must be
|
|
171
|
+
`@import`ed by your entry, after the kit's `styles.css`:
|
|
172
|
+
|
|
173
|
+
```css
|
|
174
|
+
@import "tailwindcss";
|
|
175
|
+
@import "@homepages/template-kit/styles.css";
|
|
176
|
+
@import "./theme.css"; /* compileThemeToCss output */
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`styles.css` and `base.css` keep their export paths — no import changes. `styles.css`
|
|
180
|
+
now carries only the breakpoint ladder, the `--spacing` base unit, and the motion
|
|
181
|
+
defaults.
|
|
182
|
+
|
|
183
|
+
The `Image` primitive no longer paints its frame with `bg-surface-alt` (a token your
|
|
184
|
+
theme may not declare). The fill lives on `.tr-image-frame` in `base.css`; retint it by
|
|
185
|
+
setting `--tr-image-frame-bg`.
|
|
186
|
+
|
|
187
|
+
- 57eddee: Migrate the schema system from Zod 3 to Zod 4.
|
|
188
|
+
|
|
189
|
+
`zod` is the kit's one runtime dependency, and it now tracks Zod 4 (`"zod": "^4"`).
|
|
190
|
+
Because the types you author section schemas against are Zod types, bumping Zod a
|
|
191
|
+
major is a breaking change for authors: your workspace resolves Zod 4 in its
|
|
192
|
+
lockfile, and the schema/slot types you see in editor tooltips are now Zod 4 types.
|
|
193
|
+
|
|
194
|
+
**Action required** — if your workspace declares `zod`, move it to `^4` so a single
|
|
195
|
+
Zod copy resolves across your workspace and the kit:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm i zod@^4
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Nothing else changes. The authoring API is untouched — the slot-type catalog, the
|
|
202
|
+
source/transform vocabulary, and `SectionProps<typeof schema>` inference are all
|
|
203
|
+
identical, and every section still materializes to a byte-identical serialized
|
|
204
|
+
schema. This is a dependency migration, invisible to an author apart from the Zod
|
|
205
|
+
version in the lockfile.
|
|
206
|
+
|
|
207
|
+
### Patch Changes
|
|
208
|
+
|
|
209
|
+
- 6675c4c: `no-hex` no longer reports a `color-mix()` whose colour arguments are all theme-derived.
|
|
210
|
+
A mix over `var(--…)` references, `transparent`, or `currentColor` carries no palette of
|
|
211
|
+
its own — it composes a state colour (hover, active, pressed) out of the theme the
|
|
212
|
+
section was handed — so banning it contradicted the rule's own reason. A hard-coded
|
|
213
|
+
argument still reports: `color-mix(in srgb, var(--tr-color-primary) 80%, #fff)` and
|
|
214
|
+
`color-mix(…, white)` are violations, as is a `var()` fallback that bakes a colour
|
|
215
|
+
(`var(--x, #fff)`). The carve-out is `color-mix()` only — `rgb()`, `oklch()`, and the
|
|
216
|
+
rest take raw channel values and stay banned outright, so the "a section carries zero
|
|
217
|
+
palette" guarantee is unchanged.
|
|
218
|
+
- 1749cea: `no-hex` now ships as a **warning**, not an error. Centralized theme colours are
|
|
219
|
+
encouraged, not gated: a hard-coded colour still squiggles in the editor and the rule
|
|
220
|
+
still explains how to derive the colour from theme tokens, but it no longer fails
|
|
221
|
+
`template-kit check` locally or at ingest (both gate on errors only). Every other preset
|
|
222
|
+
rule stays an error — this is the one advisory rule. The `color-mix()` over theme-derived
|
|
223
|
+
arguments carve-out is unchanged; it just governs a warning now instead of an error.
|
|
224
|
+
|
|
3
225
|
## 0.2.0
|
|
4
226
|
|
|
5
227
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,21 +1,48 @@
|
|
|
1
1
|
# @homepages/template-kit
|
|
2
2
|
|
|
3
3
|
The authoring surface for HomePages marketing-section templates: schema system,
|
|
4
|
-
contract primitives, theme
|
|
4
|
+
contract primitives, the theme system, and the `template-kit` CLI.
|
|
5
5
|
|
|
6
6
|
**Status: 0.0.x.** The **schema system** (the section authoring contract and the closed
|
|
7
|
-
vocabulary it validates against), the **contract primitives**, and the **theme
|
|
7
|
+
vocabulary it validates against), the **contract primitives**, and the **theme system**
|
|
8
8
|
are complete — a section is authorable end to end against the kit. The `template-kit`
|
|
9
|
-
CLI's commands are
|
|
9
|
+
CLI's `check`, `theme`, `dev`, and `pack` commands are implemented — see
|
|
10
|
+
[Checking a workspace](#checking-a-workspace), [Generating a theme](#generating-a-theme),
|
|
11
|
+
and [Previewing a workspace](#previewing-a-workspace) below — and `new` / `new-section`
|
|
12
|
+
scaffold a template or a section into a workspace (see [docs/new.md](docs/new.md)).
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
The fastest way to start is the workspace scaffolder — it creates a workspace with a
|
|
17
|
+
working starter template and the full toolchain already wired:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm create homepages-workspace <name>
|
|
21
|
+
cd <name>
|
|
22
|
+
npm install
|
|
23
|
+
npm run dev # preview the starter; the island hydrates
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Add more templates with `npx template-kit new <template>` and sections with
|
|
27
|
+
`npx template-kit new-section <template>/<section>` — see [docs/new.md](docs/new.md).
|
|
28
|
+
Prefer to wire a workspace by hand? See **Install** below.
|
|
10
29
|
|
|
11
30
|
## Install
|
|
12
31
|
|
|
13
32
|
```bash
|
|
14
33
|
npm install @homepages/template-kit react react-dom
|
|
34
|
+
npm install -D typescript eslint @typescript-eslint/parser esbuild # the authoring toolchain
|
|
15
35
|
```
|
|
16
36
|
|
|
17
37
|
React 19 is a **peer dependency** — the kit never bundles its own copy.
|
|
18
38
|
|
|
39
|
+
The kit has exactly **one runtime dependency** (`zod`). The authoring toolchain the
|
|
40
|
+
[`check` command](docs/check.md) and the [ESLint preset](docs/eslint.md) run on is
|
|
41
|
+
yours: both resolve TypeScript, ESLint, the parser and esbuild from your workspace, so
|
|
42
|
+
your pinned versions are the ones that judge your code. The kit does not depend on them
|
|
43
|
+
at all — which is why a linter never lands in the production install of an app that
|
|
44
|
+
merely renders a published template.
|
|
45
|
+
|
|
19
46
|
## Authoring a section
|
|
20
47
|
|
|
21
48
|
A section is four files: `schema.ts` (slots + options), `fill-spec.ts` (how AI
|
|
@@ -64,7 +91,7 @@ Full contract: **[docs/primitives.md](docs/primitives.md)**.
|
|
|
64
91
|
| `@homepages/template-kit` | Authoring API — schema system, primitives, marker contract, theme types, and the golden fixtures |
|
|
65
92
|
| `@homepages/template-kit/island-runtime` | Browser loader that hydrates a page's islands |
|
|
66
93
|
| `@homepages/template-kit/browser` | Browser helpers for published pages (site config, signed ingest) |
|
|
67
|
-
| `@homepages/template-kit/styles.css` |
|
|
94
|
+
| `@homepages/template-kit/styles.css` | The global Tailwind preamble: the breakpoint ladder, the spacing base unit, the motion defaults, kit source registration |
|
|
68
95
|
| `@homepages/template-kit/base.css` | Cascade-layer order, the three reset gaps Tailwind's preflight leaves, `.tr-section`, and the motion tokens |
|
|
69
96
|
| `@homepages/template-kit/eslint` | ESLint flat-config preset |
|
|
70
97
|
| `@homepages/template-kit/tsconfig` | tsconfig preset (`"extends"`) |
|
|
@@ -72,18 +99,21 @@ Full contract: **[docs/primitives.md](docs/primitives.md)**.
|
|
|
72
99
|
The authoring API has **no subpath imports** — one specifier for everything you
|
|
73
100
|
write a section against. The two CSS entries are the deliberate exception.
|
|
74
101
|
|
|
75
|
-
`styles.css` does **not** import Tailwind. Import it *after* Tailwind in your entry
|
|
102
|
+
`styles.css` does **not** import Tailwind. Import it *after* Tailwind in your entry, then
|
|
103
|
+
your generated theme after that:
|
|
76
104
|
|
|
77
105
|
```css
|
|
78
106
|
@import "tailwindcss";
|
|
79
107
|
@import "@homepages/template-kit/styles.css";
|
|
108
|
+
@import "./theme.css"; /* generated by `template-kit theme` from theme.ts */
|
|
80
109
|
```
|
|
81
110
|
|
|
82
|
-
Two `@import "tailwindcss"` in one graph double-emits preflight.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
Two `@import "tailwindcss"` in one graph double-emits preflight. Your generated theme
|
|
112
|
+
belongs in this entry and nowhere else: it carries an `@theme` block, a Tailwind directive
|
|
113
|
+
that is inert outside the build graph. `base.css` is not part of that entry — it loads as
|
|
114
|
+
its own stylesheet on the page. `base.css` ships no reset of its own — it depends on the
|
|
115
|
+
preflight your entry's `@import "tailwindcss"` brings. Both must be on the page. Full
|
|
116
|
+
contract: **[docs/theme-and-css.md](docs/theme-and-css.md)**.
|
|
87
117
|
|
|
88
118
|
## Rules
|
|
89
119
|
|
|
@@ -93,6 +123,52 @@ The lint preset and the `template-kit check` CLI share one id namespace,
|
|
|
93
123
|
Start at **[docs/rules/INDEX.md](docs/rules/INDEX.md)**; the full doc set is routed
|
|
94
124
|
from **[docs/INDEX.md](docs/INDEX.md)**.
|
|
95
125
|
|
|
126
|
+
## Generating a theme
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
template-kit theme # infer the template from cwd, or the workspace's one template
|
|
130
|
+
template-kit theme --all # generate every template's theme.css
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`theme` compiles a template's `theme.ts` into `templates/<key>/theme.css` — the file your
|
|
134
|
+
Tailwind entry imports. The output is generated: don't hand-edit it, and re-run the
|
|
135
|
+
command whenever `theme.ts` changes. Full contract:
|
|
136
|
+
**[docs/theme-and-css.md](docs/theme-and-css.md#generating-themecss)**.
|
|
137
|
+
|
|
138
|
+
## Previewing a workspace
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
template-kit dev # serve every template in the workspace
|
|
142
|
+
template-kit dev <template> # preselect one template in the picker
|
|
143
|
+
template-kit dev --port 4000 # choose the port (default 5180)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`dev` starts a local server that renders every section against its fixtures the same way
|
|
147
|
+
the platform does — with your template's theme and compiled Tailwind — and reloads as you
|
|
148
|
+
edit. A browser UI gives you a picker and a grid contact sheet across breakpoints; each
|
|
149
|
+
section also has a standalone page, and so does the whole template at
|
|
150
|
+
`/template/<template>`. Three endpoints let an agent verify a render from a terminal:
|
|
151
|
+
`/api/inspect` (per-slot fill-state as JSON), `/api/render` (the full structured render
|
|
152
|
+
payload), and `/api/screenshot` (a full-page PNG, section or whole template). Like
|
|
153
|
+
`check`, it runs **your** toolchain — Vite and Tailwind resolved from your workspace,
|
|
154
|
+
installed with `npm i -D vite @vitejs/plugin-react tailwindcss @tailwindcss/cli` — not
|
|
155
|
+
shipped by the kit. Full contract: **[docs/dev.md](docs/dev.md)**.
|
|
156
|
+
|
|
157
|
+
## Checking a workspace
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
template-kit check # infer the template from cwd, or the workspace's one template
|
|
161
|
+
template-kit check --all # check every template
|
|
162
|
+
template-kit check --json # machine-readable report
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`check` typechecks, lints, and validates a template's schema/fill-spec/fixtures/manifest
|
|
166
|
+
contracts, runs a determinism render probe, and enforces per-section byte budgets —
|
|
167
|
+
plus workspace-wide dependency gates (lockfile health, a single React, license and
|
|
168
|
+
vulnerability checks) evaluated once per run. It exits non-zero on any failure and is
|
|
169
|
+
the same gate the platform re-runs when you submit a template. Full contract:
|
|
170
|
+
**[docs/check.md](docs/check.md)**.
|
|
171
|
+
|
|
96
172
|
## Development
|
|
97
173
|
|
|
98
174
|
```bash
|
|
@@ -101,11 +177,13 @@ npm run check # typecheck + lint + build + island-size gate + test + publint
|
|
|
101
177
|
```
|
|
102
178
|
|
|
103
179
|
`npm run verify:consumer` is the boundary gate: it packs the kit, installs the
|
|
104
|
-
tarball into
|
|
180
|
+
tarball into scratch projects, and asserts that a service which pins the kit and
|
|
181
|
+
deploys with `npm ci --omit=dev` installs no ESLint or esbuild package at all, with
|
|
182
|
+
`dependencies` carrying nothing but `zod`; that types resolve; that a real section
|
|
105
183
|
triple typechecks against the installed package, with a misspelled property fact or
|
|
106
|
-
slot key still failing to compile; that
|
|
107
|
-
|
|
108
|
-
before every release.
|
|
184
|
+
slot key still failing to compile; that the ESLint preset lints using the consumer's
|
|
185
|
+
own parser; that Tailwind's cross-package `@source` scan reaches the shipped `dist`;
|
|
186
|
+
and that only one React ends up in the tree. Run it before every release.
|
|
109
187
|
|
|
110
188
|
The island loader (`@homepages/template-kit/island-runtime`) has its own gate,
|
|
111
189
|
`npm run size:islands`: it must stay under 3072 B gzip and never import
|
|
@@ -131,9 +209,10 @@ token anywhere, and adding one would silently disable OIDC.
|
|
|
131
209
|
|
|
132
210
|
3. **Merge the Version Packages PR.** That merge publishes to npm.
|
|
133
211
|
|
|
134
|
-
Semver contract: the platform vocabulary (slot types, sources, transforms
|
|
135
|
-
|
|
136
|
-
|
|
212
|
+
Semver contract: the platform vocabulary (slot types, sources, transforms) is
|
|
213
|
+
closed and versioned. A breaking change to it is a **major**; a new optional
|
|
214
|
+
capability is a **minor**. Design tokens are *not* part of that vocabulary —
|
|
215
|
+
your template names its own.
|
|
137
216
|
|
|
138
217
|
### Bumping the version by hand
|
|
139
218
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//#region src/asset-modules.d.ts
|
|
2
|
+
declare module "*.svg" {
|
|
3
|
+
const src: string;
|
|
4
|
+
export default src;
|
|
5
|
+
}
|
|
6
|
+
declare module "*.png" {
|
|
7
|
+
const src: string;
|
|
8
|
+
export default src;
|
|
9
|
+
}
|
|
10
|
+
declare module "*.jpg" {
|
|
11
|
+
const src: string;
|
|
12
|
+
export default src;
|
|
13
|
+
}
|
|
14
|
+
declare module "*.jpeg" {
|
|
15
|
+
const src: string;
|
|
16
|
+
export default src;
|
|
17
|
+
}
|
|
18
|
+
declare module "*.gif" {
|
|
19
|
+
const src: string;
|
|
20
|
+
export default src;
|
|
21
|
+
}
|
|
22
|
+
declare module "*.webp" {
|
|
23
|
+
const src: string;
|
|
24
|
+
export default src;
|
|
25
|
+
}
|
|
26
|
+
declare module "*.avif" {
|
|
27
|
+
const src: string;
|
|
28
|
+
export default src;
|
|
29
|
+
}
|
|
30
|
+
declare module "*.ico" {
|
|
31
|
+
const src: string;
|
|
32
|
+
export default src;
|
|
33
|
+
}
|
|
34
|
+
declare module "*.woff" {
|
|
35
|
+
const src: string;
|
|
36
|
+
export default src;
|
|
37
|
+
}
|
|
38
|
+
declare module "*.woff2" {
|
|
39
|
+
const src: string;
|
|
40
|
+
export default src;
|
|
41
|
+
}
|
|
42
|
+
declare module "*.ttf" {
|
|
43
|
+
const src: string;
|
|
44
|
+
export default src;
|
|
45
|
+
}
|
|
46
|
+
declare module "*.otf" {
|
|
47
|
+
const src: string;
|
|
48
|
+
export default src;
|
|
49
|
+
}
|
|
50
|
+
declare module "*.eot" {
|
|
51
|
+
const src: string;
|
|
52
|
+
export default src;
|
|
53
|
+
}
|
|
54
|
+
declare module "*.mp4" {
|
|
55
|
+
const src: string;
|
|
56
|
+
export default src;
|
|
57
|
+
}
|
|
58
|
+
declare module "*.webm" {
|
|
59
|
+
const src: string;
|
|
60
|
+
export default src;
|
|
61
|
+
}
|
|
62
|
+
declare module "*.mov" {
|
|
63
|
+
const src: string;
|
|
64
|
+
export default src;
|
|
65
|
+
}
|
|
66
|
+
declare module "*.mp3" {
|
|
67
|
+
const src: string;
|
|
68
|
+
export default src;
|
|
69
|
+
}
|
|
70
|
+
declare module "*.wav" {
|
|
71
|
+
const src: string;
|
|
72
|
+
export default src;
|
|
73
|
+
}
|
|
74
|
+
declare module "*.pdf" {
|
|
75
|
+
const src: string;
|
|
76
|
+
export default src;
|
|
77
|
+
}
|
|
78
|
+
declare module "*.zip" {
|
|
79
|
+
const src: string;
|
|
80
|
+
export default src;
|
|
81
|
+
}
|
package/dist/base.css
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - The cascade-layer order declaration above — the one place it is stated
|
|
10
10
|
* - The three reset gaps Tailwind's preflight leaves (below)
|
|
11
11
|
* - The section box model (.tr-section, emitted by the <Section> primitive)
|
|
12
|
+
* - The <Image> frame's placeholder fill (.tr-image-frame)
|
|
12
13
|
* - Universal tokens: motion
|
|
13
14
|
*
|
|
14
15
|
* REQUIRES A TAILWIND ENTRY ON THE PAGE. Your entry's `@import "tailwindcss"` brings
|
|
@@ -54,6 +55,14 @@
|
|
|
54
55
|
margin: 0;
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/* The <Image> frame's placeholder fill, showing while an image is absent or loading.
|
|
59
|
+
* It is a plain class rather than a `bg-*` utility on the primitive because a template
|
|
60
|
+
* names its own tokens — there is no colour token this primitive may assume exists.
|
|
61
|
+
* Retint it by setting --tr-image-frame-bg in your theme's layout tokens. */
|
|
62
|
+
.tr-image-frame {
|
|
63
|
+
background-color: var(--tr-image-frame-bg, oklch(0.97 0 0));
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
/* ----- Universal tokens ------------------------------------------------- */
|
|
58
67
|
|
|
59
68
|
:root {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/cli/check/config.ts
|
|
2
|
+
const CHECK_CONFIG = {
|
|
3
|
+
size: {
|
|
4
|
+
/** Gzipped bytes of a section's renderer bundle, React excluded. */
|
|
5
|
+
rendererBundleGzip: 50 * 1024,
|
|
6
|
+
/** Gzipped bytes of a section's stylesheet, including CSS pulled in from packages. */
|
|
7
|
+
sectionCssGzip: 50 * 1024,
|
|
8
|
+
/** Gzipped bytes of a section's largest island (browser) bundle, React excluded. */
|
|
9
|
+
islandBundleGzip: 50 * 1024,
|
|
10
|
+
/** Raw bytes of a section's static assets (svg/images/fonts). RAW, not gzip — images/fonts are already compressed. */
|
|
11
|
+
assets: 250 * 1024
|
|
12
|
+
},
|
|
13
|
+
audit: {
|
|
14
|
+
/** A vulnerability at or above this severity fails the check. */
|
|
15
|
+
failOn: ["high", "critical"] },
|
|
16
|
+
/**
|
|
17
|
+
* A package whose license is not on this list fails the check. A missing
|
|
18
|
+
* license field, or a bespoke "SEE LICENSE IN …", is a denial — not a pass.
|
|
19
|
+
*/
|
|
20
|
+
licenseAllowlist: [
|
|
21
|
+
"MIT",
|
|
22
|
+
"ISC",
|
|
23
|
+
"Apache-2.0",
|
|
24
|
+
"BSD-2-Clause",
|
|
25
|
+
"BSD-3-Clause",
|
|
26
|
+
"0BSD",
|
|
27
|
+
"Unlicense",
|
|
28
|
+
"CC0-1.0"
|
|
29
|
+
],
|
|
30
|
+
/**
|
|
31
|
+
* The license gate walks the *shipped* dependency graph of every third-party
|
|
32
|
+
* package a template pulls in — this is the first-party exception to that.
|
|
33
|
+
* The kit itself is `UNLICENSED` by design (it is not published for reuse
|
|
34
|
+
* outside this platform) and every workspace depends on it, so without this
|
|
35
|
+
* exemption the gate would deny the kit on a stock, correct workspace.
|
|
36
|
+
*/
|
|
37
|
+
licenseExemptions: ["@homepages/template-kit"]
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { CHECK_CONFIG };
|