@getvitops/create 0.8.2 → 0.9.0-alpha.1
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 +103 -0
- package/package.json +2 -2
- package/templates/emdash/.agents/skills/custom-blocks/SKILL.md +104 -0
- package/templates/emdash/.agents/skills/setup/SKILL.md +4 -4
- package/templates/emdash/.claude/hooks/session-start.sh +4 -1
- package/templates/emdash/.github/workflows/deploy-prod.yml +12 -0
- package/templates/emdash/AGENTS.md +228 -28
- package/templates/emdash/README.md +48 -37
- package/templates/emdash/SETUP.html +45 -27
- package/templates/emdash/_gitignore +3 -0
- package/templates/emdash/astro.config.mjs +14 -1
- package/templates/emdash/package.json +7 -5
- package/templates/emdash/public/_headers +19 -4
- package/templates/emdash/scripts/pull-content.mjs +83 -0
- package/templates/emdash/seed/seed.json +188 -6
- package/templates/emdash/site.json +102 -3
- package/templates/emdash/src/cloudflare-workers.d.ts +9 -0
- package/templates/emdash/src/layouts/Layout.astro +27 -45
- package/templates/emdash/src/pages/404.astro +4 -3
- package/templates/emdash/src/pages/[...slug].astro +22 -12
- package/templates/emdash/src/pages/api/track.ts +158 -0
- package/templates/emdash/src/pages/index.astro +10 -9
- package/templates/static/.agents/skills/setup/SKILL.md +4 -4
- package/templates/static/AGENTS.md +68 -14
- package/templates/static/README.md +7 -7
- package/templates/static/SETUP.html +45 -27
- package/templates/static/public/_headers +16 -4
- package/templates/static/site.json +54 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,108 @@
|
|
|
1
1
|
# @getvitops/create
|
|
2
2
|
|
|
3
|
+
## 0.9.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 24c568b: Escape hatches on every block, a section theme, widget areas, a badges block, Tailwind scanning of package renderers, and a sturdier `vitops audit`.
|
|
8
|
+
|
|
9
|
+
**@getvitops/emdash**
|
|
10
|
+
|
|
11
|
+
- Every `vitops.*` block and `vitops_section` gains three fields: `anchor` (rendered as the `id`, so `#contact` works), `className` (`class_name` on the section type: block-type slugs are lowercase) and `style`. `style` takes CSS custom properties only (`--p-card: 2rem`); any other declaration, and any value containing `url(`, `@`, `{`, `}` or a backslash, is dropped. With the `tailwind` format a class typed in the CMS only works if the site already uses it. They are applied to the block's own outermost element (the grid `<ul>` for `vitops.cards`), never an extra wrapper, so a block's markup is the same whether or not an editor fills them in.
|
|
12
|
+
- `vitops_section` gains a `theme` select: a role, or `<role>:solid`, with readable text chosen by the generator's contrast rules. It overrides `tone`/`color`/`solid`, which stay for existing content. Other site roles still go through `tone`.
|
|
13
|
+
- New `vitops.badges` block (a row of `.badge` or `.tag` labels, each with an optional tone, icon and link) and `vitops.widgetArea` block, plus `<VitopsWidgetArea name level />` from `@getvitops/emdash/astro`. A widget area is content defined once under Widgets and shown wherever it is placed. An area cannot hold another area, and an area containing a `core:*` component widget is rendered by EmDash's own renderer.
|
|
14
|
+
- Existing sites: re-run the block-type seed only on a new database; on an existing one add the `theme`, `anchor`, `className` and `style` fields to the `vitops_section` block type in the admin.
|
|
15
|
+
|
|
16
|
+
**@getvitops/create**: the emdash template seeds `announcement` and `pre-footer` widget areas, renders them in `Layout.astro`, and documents when to use a Section, a block or a widget area. Sites scaffolded earlier add the two `<VitopsWidgetArea>` lines and the `widgetAreas` seed entries by hand.
|
|
17
|
+
|
|
18
|
+
**@getvitops/generator / astro / vite** (`tailwind` format only): the Astro integration now adds `@source` lines for `@getvitops/astro` and `@getvitops/emdash`, because Tailwind v4 does not scan `node_modules`; utilities used only by their renderers (`font-display`, `font-caption`, `font-footnote`) were never emitted and the page silently rendered at body size. New `sources` option on `generate()` and the Vite plugin. A site's `src/package-classes.txt` workaround can be deleted. css and bricks: no change.
|
|
19
|
+
|
|
20
|
+
**@getvitops/cli**: `vitops emdash check-prerender` now also warns when a page uses a type-role class (`font-display`, …) the built CSS has no rule for; `--strict` makes it fail. `vitops audit` checks for its optional packages and a Chromium binary before starting the preview server (so a failed run no longer leaves port 4398 busy), stops the server on Ctrl+C and termination, and takes its page list from the built sitemap, then the menus; the guessed defaults (`/privacy`, `/contact`, …) are used only when neither exists.
|
|
21
|
+
|
|
22
|
+
**@getvitops/utils**: the audit helpers behind the above (`preflight`, `fetchSitemapPaths`, `sitemapLocs`, `pathsFromSitemapLocs`).
|
|
23
|
+
|
|
24
|
+
**@getvitops/core** (all formats): new `.block-anchor` rule gives an anchored block `scroll-margin-top: var(--header-offset, 5rem)`; set `--header-offset` to a sticky header's height. New `widget-area.css` partial. No other consumer-facing change.
|
|
25
|
+
|
|
26
|
+
The other fixed-group packages: no consumer-facing change beyond the above.
|
|
27
|
+
|
|
28
|
+
**Also fixed in the emdash template** (`site.json`): it defined only the `display`, `heading` and `body` type roles while the blocks use `title`, `eyebrow`, `lead`, `caption` and `footnote`, so those rendered at body size with no rule behind them. The roles are added with the reference design system's specs. A site scaffolded earlier adds the same five entries under `designSystem.themes.default.typography.roles`; `vitops emdash check-prerender` now names any that are missing.
|
|
29
|
+
|
|
30
|
+
## 0.9.0-alpha.0
|
|
31
|
+
|
|
32
|
+
### Minor Changes
|
|
33
|
+
|
|
34
|
+
- 161c7f3: A contact form that works end to end: `vitops setup turnstile`, `<wc-turnstile>`, the `vitops.form` EmDash block, and the route the emdash template ships to receive it.
|
|
35
|
+
|
|
36
|
+
**CSS, all formats** (no existing class changes): `forms.css` gains `.form-notice--target:not(:target)` (a message revealed only when the URL fragment names it, which is how a prerendered page shows a no-JS form's result) and `:where(wc-turnstile) { display: block }`.
|
|
37
|
+
|
|
38
|
+
**`@getvitops/core`:** new `<wc-turnstile sitekey="…">` in `elements.js`. It loads Cloudflare Turnstile on the first interaction with its form (no request to `challenges.cloudflare.com` for a visitor who only reads the page), holds an early submit until the token arrives, and leaves its slotted no-JS explanation in place until JS takes over. Turnstile is category `necessary`, so it is not behind the consent banner.
|
|
39
|
+
|
|
40
|
+
**`@getvitops/utils` / `@getvitops/cli`:** new `@getvitops/utils/turnstile` and `vitops setup turnstile [--dry] [--check] [--no-write] [--no-secret]`. It plans from the site's hostnames, creates a managed widget unless one already covers them (an existing widget is adopted, never edited, rotated or deleted), writes the public key to `site.security.turnstile.siteKey`, and pipes the one-time secret to `wrangler secret put VITOPS_TURNSTILE_SECRET` without writing it to any file. Needs `CLOUDFLARE_API_TOKEN` with **Account > Turnstile > Edit** and `CLOUDFLARE_ACCOUNT_ID`.
|
|
41
|
+
|
|
42
|
+
**`@getvitops/astro`:** `virtual:getvitops/head` gains `turnstileSiteKey` (read from `site.security.turnstile.siteKey`) so blocks can render the widget. No other change.
|
|
43
|
+
|
|
44
|
+
**`@getvitops/generator`:** `TIERS` gains a `turnstile` entry (wc-turnstile, claimed by `vitops.form`); `wc-multi-field`'s `emdashExempt` reason is reworded now the form block exists.
|
|
45
|
+
|
|
46
|
+
**`@getvitops/emdash`:** new `vitops.form` block: a field repeater (text, email, phone, long text, choose one, tick box), required flags, help text, success/error messages, optional Turnstile. It renders a semantic `<form method="post">` that works with no JavaScript, with a honeypot named per `createConversionRoute`'s defaults. A field named `phone` submits as `tel`, because the route reserves `phone` and `event`.
|
|
47
|
+
|
|
48
|
+
**`@getvitops/create`:** the emdash template ships `src/pages/api/track.ts` (`prerender = false`, `createConversionRoute()`), a seeded contact form, and `challenges.cloudflare.com` in both templates' Report-Only CSP (`script-src`, `frame-src`). The route refuses a post with nowhere to deliver and fails closed when a site key exists without `VITOPS_TURNSTILE_SECRET`. SETUP.html gains the Turnstile step. Existing sites: copy the route and the CSP change, then run `vitops setup turnstile`.
|
|
49
|
+
|
|
50
|
+
- fec1b4b: The EmDash template's two build scripts are now CLI commands, so fixes reach existing sites with `vp update` instead of a re-copy.
|
|
51
|
+
|
|
52
|
+
- `vitops emdash prepare-db` migrates and seeds the local D1 the build prerenders from (was `scripts/prepare-local-db.mjs`). The start and stop calls time out after 5 minutes and it prints progress.
|
|
53
|
+
- `vitops emdash check-prerender [dir]` fails the build if a prerendered page is not a real page (was `scripts/check-prerender.mjs`).
|
|
54
|
+
|
|
55
|
+
**Migration for a site scaffolded earlier:** delete `scripts/prepare-local-db.mjs` and `scripts/check-prerender.mjs`, then in `package.json` set `"prepare-local-db": "vitops emdash prepare-db"`, `"build": "astro build && vitops emdash check-prerender"`, and use the same two commands in place of `node scripts/…` inside `deploy` and `deploy:dev`. A site that never had the scripts needs only the `package.json` entries.
|
|
56
|
+
|
|
57
|
+
- 224a731: **`@getvitops/astro` (no CSS change; all formats unaffected)**
|
|
58
|
+
|
|
59
|
+
- **`site.fonts` is no longer silently ignored.** `vitops()` now turns webfonts on by default when the site config (`site` option, or a `css.input` that is a site config) declares `site.fonts`, and logs that it did. Before, no `@font-face`, preload or warning was emitted unless you also passed `fonts: true`. Pass `fonts: false` to opt out. Migration: none — sites that already set `fonts` behave the same; sites that declared `site.fonts` without it will start loading those families.
|
|
60
|
+
- **The icon sprite is served when the site config asks for it.** `site.icons.sprite: true` made the generator write `icons.svg`, but only the `icons` integration option copied it to `public/vitops/`, so `/vitops/icons.svg` was never served. It is now mirrored whenever the site config sets it.
|
|
61
|
+
- **Strict CSP is achievable.** New build-time exports `inlineScriptHashes()`, `cspScriptHash()` and `contentSecurityPolicy()` give the SHA-256 hashes of the two inline scripts `<Head />` emits (colour-scheme bootstrap, consent-gate stub) and a starting policy built on them, with no `'unsafe-inline'` in `script-src`. The scripts moved from `Head.astro`'s frontmatter to `src/inline-scripts.ts` (shipped in the package) so the hash and the emitted bytes are the same constant; the rendered output is byte-identical.
|
|
62
|
+
|
|
63
|
+
**`@getvitops/create` (templates; existing scaffolded sites are not changed)**
|
|
64
|
+
|
|
65
|
+
- **emdash: every public page is prerendered.** `index.astro`, `[...slug].astro` (via `getStaticPaths` over the published `pages`) and `404.astro` set `prerender = true`. Unknown URLs now return the prerendered 404 with a real 404 status — the old `Astro.rewrite('/404')` from an on-demand route to a prerendered one was refused by Astro, so every unknown URL was a 500. `scripts/pull-content.mjs` (first step of `deploy`/`deploy:dev`) loads production's D1 into the local build database, because the Cloudflare adapter prerenders against a local D1 that is empty on CI; it fails closed. The deploy-prod workflow also runs on a `repository_dispatch` of type `emdash-publish`. Migration for an existing site: copy those pages, the script and the two `package.json` scripts, and add the trigger; previews of unpublished drafts no longer work on the public routes (see AGENTS.md).
|
|
66
|
+
- **emdash: seed menus are `primary` (Contact), `footer-sitemap` (Home, Contact) and `footer-legal` (Privacy Policy, Terms & Conditions, Cookie Notice)**, replacing `primary` (Home, About) and `footer` (Terms, Privacy), with placeholder `contact` and `cookies` pages so every seeded link resolves. The template Layout still reads the old menu names until it is updated; the seed only applies to an empty database, so existing sites keep their menus.
|
|
67
|
+
- **Both templates: `badge` and `tag` patterns (group `label`) are enabled, `button` carries `class: "btn"` so `<a class="btn">` is styled, and `neutral`/`surface` are declared as surface roles** (they were chromatic, which emitted no `.bg-neutral`/`text-neutral-muted`). css/bricks/tailwind output of a scaffolded site changes accordingly.
|
|
68
|
+
- **Both templates ship `public/_headers` with a `Content-Security-Policy-Report-Only` default** naming `<Head />`'s inline scripts by hash. It blocks nothing. `_headers` applies to static assets only, not Worker-rendered responses; see AGENTS.md for the EmDash admin and HTML-block trade-off.
|
|
69
|
+
- **Guidance is Vite+-first**: `AGENTS.md`, README, the `setup` skill, `SETUP.html` and the session hook use `vp`/`vpr`/`vp exec` instead of `pnpm`/`npx`, with one command table; `vpr dev` is documented as returning immediately. There is no `vp change`/`vp pm change` (checked against vp 1.5.0); the release flow is `dev` → promote.
|
|
70
|
+
- emdash ships `.agents/skills/custom-blocks/SKILL.md` (compose, extend, site-local, upstream; naming and lifecycle rules) and the favicon `themeColor`/`name` now derive from `site.json`.
|
|
71
|
+
- Label vocabulary: `badge` is a static label, `tag` is static or dynamic; `chip`/`pill` are not used.
|
|
72
|
+
|
|
73
|
+
**`@getvitops/cli`**: the bundled `vitops-design-system` skill points at `vp exec vitops docs <topic>`.
|
|
74
|
+
|
|
75
|
+
No consumer-facing change in `@getvitops/core`, `@getvitops/generator`, `@getvitops/utils` or `@getvitops/vite`.
|
|
76
|
+
|
|
77
|
+
- 55061e2: **Added: `<SiteNav>` and `<SiteFooter>` for Astro/EmDash sites.** Both are tier-1 markup over the existing `sitenav` pattern (no runtime JS: `<details>` accordions + Popover API drawer). Non-breaking.
|
|
78
|
+
|
|
79
|
+
- `<SiteNav {...await loadNavMenus(getMenu)} />` renders EmDash menu `primary` (the default: depth 3, dropdowns from the `md` container width, drawer below). If a `primary-mobile` menu exists it replaces the nav below `md` (depth 1); if `primary-mega` exists it replaces it from `xl` (mega panels). Adding the menu in the admin is the whole change. Only one tier is in the accessibility tree at a time. An item's `titleAttr` is its description (EmDash has no description field yet).
|
|
80
|
+
- `<SiteFooter sitemap legal name>` renders `footer-sitemap` + `footer-legal` + a copyright line.
|
|
81
|
+
- `@getvitops/astro/components/sitenav.ts` exports the pure helpers (`loadNavMenus`, `selectTiers`, ...).
|
|
82
|
+
- CSS (`patterns/sitenav.css`, **all formats**): tier visibility classes (`.sitenav-tier--below-*`/`--from-*`), `.sitenav--mega`, `.sitenav__desc`, `.sitefooter*`, `aria-current` styling, reduced-motion and forced-colors handling. Existing `.sitenav` rules are unchanged, so the Bricks element is unaffected.
|
|
83
|
+
- `@getvitops/create` (emdash template): the layout now renders header and footer through these components, with the colour-scheme toggle in the header. It reads menus `primary`, `footer-sitemap` and `footer-legal`; a template whose seed still has the old `footer` menu renders no footer links until the seed is updated.
|
|
84
|
+
- `@getvitops/generator`: `TIERS.sitenav` now lists the two Astro components.
|
|
85
|
+
|
|
86
|
+
- 7a4241e: EmDash template: make the database a build prerenders from valid before it builds, and fail the build when it isn't. The template runs `migrations: { runtime: 'check' }`, so a build against a local D1 with pending migrations prerendered EmDash's one-line "Database migrations are required" response into every page while still succeeding. A fresh CI runner, a first deploy, a `SKIP_PULL_CONTENT=1` build and an upgrade deploy all hit it.
|
|
87
|
+
|
|
88
|
+
- **New `scripts/prepare-local-db.mjs`** (`vpr prepare-local-db`): starts `astro dev` once, calls EmDash's `dev-bypass` setup (which migrates and applies the seed's sample content), checks the home page renders, and stops it. Writes only the disposable `.wrangler/state`. Run after `pull-content` by `vpr deploy`, `vpr deploy:dev` and the reusable deploy workflow. `SKIP_PREPARE_LOCAL_DB=1` skips it.
|
|
89
|
+
- **New `scripts/check-prerender.mjs`**, part of `vpr build` and both deploy scripts: fails when any prerendered page is not an HTML document with a title, or carries the pending-migrations message.
|
|
90
|
+
- **Existing sites:** add the two scripts, the `prepare-local-db` script entry, and `&& node scripts/check-prerender.mjs` after `astro build`; add a "Prepare local database" step before each Build step in a copied deploy workflow. Run `vpr prepare-local-db` once before a first local `vpr build`.
|
|
91
|
+
|
|
92
|
+
No consumer-facing change in the other toolchain packages.
|
|
93
|
+
|
|
94
|
+
### Patch Changes
|
|
95
|
+
|
|
96
|
+
- 06d6112: Fix the EmDash `/design-system` admin page erroring on a tailwind site. It fetches `/vitops/design-manifest.json`, which the `tailwind` format never emitted and the integration only mirrored under `editor: true` (which also loads `editor.js` on every public page).
|
|
97
|
+
|
|
98
|
+
- **generator** (`tailwind` format only): `design-manifest.json` is now emitted alongside `tailwind.css`. No change to the CSS.
|
|
99
|
+
- **astro**: new `vitops({ editorManifest: true })` writes everything an outside host needs into `public/vitops/` (`design-manifest.json`, `editor.js`, a standalone `editor.css`, and `design-system-editor.html`) without loading the editor on public pages. `editor: true` still loads it from `<Head />`.
|
|
100
|
+
- **vite**: `editorManifestDir` also writes `vitops/editor.css`, from a throwaway `css`-format pass on tailwind sites.
|
|
101
|
+
- **emdash**: the `/design-system` admin page was unstyled and overflowed the admin, because the editor borrows the framework CSS and the admin never loads it. It now embeds `/vitops/design-system-editor.html` in an iframe, so the design system can't leak into the admin's styles. **Requires `editorManifest: true`** in `vitops({ … })`.
|
|
102
|
+
- **create**: the EmDash template sets `editorManifest: true`. Existing sites: add it to `vitops({ … })` in `astro.config.mjs`.
|
|
103
|
+
|
|
104
|
+
No consumer-facing change in the other toolchain packages.
|
|
105
|
+
|
|
3
106
|
## 0.8.2
|
|
4
107
|
|
|
5
108
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getvitops/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-alpha.1",
|
|
4
4
|
"description": "Project templates for the Vitops design system — scaffold wired-up sites with `vp create @getvitops`.",
|
|
5
5
|
"homepage": "https://docs.vitops.ca",
|
|
6
6
|
"bugs": "https://github.com/getvitops/design-system/issues",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@getvitops/generator": "8.
|
|
22
|
+
"@getvitops/generator": "8.3.0-alpha.1"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
25
|
"node": ">=24"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: custom-blocks
|
|
3
|
+
description: Decide whether a page section needs a new EmDash block type, and if so how to name, build, version and retire it. Use before creating, renaming or deleting any block type, any `src/components/blocks/*` renderer, or when asked to "add a block", "make an editable section" or "add a component the editors can place".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Custom blocks
|
|
7
|
+
|
|
8
|
+
Pages are composed from **blocks** so non-technical editors can rearrange and edit
|
|
9
|
+
them in the CMS. A new block type is the most expensive way to get a section onto a
|
|
10
|
+
page: it adds a content-model entry, a renderer, a field schema and a migration
|
|
11
|
+
burden, and **a block type cannot be renamed or deleted** once pages use it (see
|
|
12
|
+
"Lifecycle"). So work down this list and stop at the first rung that fits.
|
|
13
|
+
|
|
14
|
+
## 1. Decision rule
|
|
15
|
+
|
|
16
|
+
1. **Compose what exists.** The `vitops.*` blocks from `@getvitops/emdash` (cards,
|
|
17
|
+
carousel, gallery, accordion, details, banner, hero, marquee, image-compare,
|
|
18
|
+
copy button, action link, …) resolve inside any block type's `portableText` field,
|
|
19
|
+
so "a section with a heading, intro and then a row of cards" is a section block
|
|
20
|
+
whose body holds `vitops.cards` — not a new "cards section" type. Check what is
|
|
21
|
+
installed first: `vp exec vitops docs components` lists every block the toolchain
|
|
22
|
+
ships and which tier provides it.
|
|
23
|
+
2. **Extend an existing block** if one is close. An extra option (a `variant`
|
|
24
|
+
select, an optional slot) on a block that already exists is a version bump on that
|
|
25
|
+
block, not a new type. Prefer this when the new thing is a variation of the same
|
|
26
|
+
content shape.
|
|
27
|
+
3. **Site-local block type** only when the content shape is specific to this site
|
|
28
|
+
(a bespoke dashboard mock, an A-versus-B argument with hard-coded figures). Keep
|
|
29
|
+
the renderer in `src/components/blocks/` and the type name prefixed for the site
|
|
30
|
+
(see "Naming"). Code-owned widgets expose only a caption field; the numbers live in
|
|
31
|
+
code, not in the CMS.
|
|
32
|
+
4. **Upstream it** when a second site would plausibly want it. Don't build a
|
|
33
|
+
generic block here and quietly fork it: raise it against the toolchain
|
|
34
|
+
(`getvitops/design-system`) with the shape you used, so every site gets it. Until
|
|
35
|
+
it ships, keep the local version and mark it `local (watch)` in a comment, so it
|
|
36
|
+
is easy to retire when the real one lands.
|
|
37
|
+
|
|
38
|
+
A form, a section container, a stats row, a logo grid, a CTA band and a steps list
|
|
39
|
+
are all _generic_ — expect to find them upstream or to upstream them, not to keep
|
|
40
|
+
them local.
|
|
41
|
+
|
|
42
|
+
## 2. Naming: check the framework's vocabulary first
|
|
43
|
+
|
|
44
|
+
Block types are permanent, so the name has to be right the first time. Before you
|
|
45
|
+
name one:
|
|
46
|
+
|
|
47
|
+
- Run `vp exec vitops docs components` and `vp exec vitops docs classes`. If the
|
|
48
|
+
framework already has a pattern by that name, **use its meaning**: `badge` is a
|
|
49
|
+
_static_ label; `tag` is a label that may be static or dynamic (editable,
|
|
50
|
+
dismissable). Never `chip` or `pill`. A block called `chips` that renders badges
|
|
51
|
+
cost one site a new type, a content migration and a permanently retired type.
|
|
52
|
+
- Prefix site-local types with a short site code (`acme_section`), never `vitops.`
|
|
53
|
+
— that namespace belongs to the toolchain.
|
|
54
|
+
- Name the thing, not its look: `section`, `steps`, `logos`; not `green-box`.
|
|
55
|
+
|
|
56
|
+
## 3. Field and renderer conventions
|
|
57
|
+
|
|
58
|
+
- **Colour: `tone` plus optional `color`.** `tone` takes a **role** name from
|
|
59
|
+
`site.json`'s `colors.roles` (preferred), falling back to a semantic name
|
|
60
|
+
(`info` `success` `warning` `danger`); `color` is the escape hatch for a palette
|
|
61
|
+
hue/step and should be rare — a site that sets it on every item is telling you a
|
|
62
|
+
role is missing. A select field can only list static options, so either list the
|
|
63
|
+
roles you actually use or take a validated string. Resolve it in one shared helper
|
|
64
|
+
(`src/components/blocks/tone.ts`) rather than per block.
|
|
65
|
+
- **Class names cannot be built from field values.** Tailwind only emits classes it
|
|
66
|
+
can read in source, so `` `bg-${tone}` `` produces nothing. Resolve a tone to CSS
|
|
67
|
+
custom properties (or a lookup table of whole class names) instead.
|
|
68
|
+
- **Links are `url` fields**, not `string`: EmDash's `url` type accepts site-relative
|
|
69
|
+
paths. (`string` is a mistake that needs a breaking version to undo.)
|
|
70
|
+
- **Repeater sub-fields are scalar-only** (no `portableText`, no links inside text),
|
|
71
|
+
so a checklist is one newline-separated `text` field. Don't fight it; rich item
|
|
72
|
+
bodies need EmDash to lift that limit.
|
|
73
|
+
- **Blocks don't nest.** A "section containing stats" is the section's own body
|
|
74
|
+
holding `vitops.*` blocks, or a flat sequence of sibling blocks; per-section
|
|
75
|
+
backdrops don't carry across siblings.
|
|
76
|
+
- **Reach for framework classes** (`centered`, `region`, `rhythm`, `subgrid`,
|
|
77
|
+
`cluster`, `font-*`, `card`, `badge`, `tag`) in the renderer; run
|
|
78
|
+
`vpr lint:design` — hand-written layout CSS in a block is the signal that the
|
|
79
|
+
framework is missing a pattern worth upstreaming.
|
|
80
|
+
- A card title is a heading: render a real `<h2>`–`<h4>` with a level prop, not a
|
|
81
|
+
styled `<p>`.
|
|
82
|
+
|
|
83
|
+
## 4. Lifecycle
|
|
84
|
+
|
|
85
|
+
- **Create** with the schema tools (the `schema_*` actions on the site's MCP server,
|
|
86
|
+
`/_emdash/api/mcp`) or the admin; commit the matching renderer and the
|
|
87
|
+
`emdash export-seed` output so a fresh environment gets the same model.
|
|
88
|
+
- **A breaking change is a new version**, not an edit: add the version, migrate the
|
|
89
|
+
entries that use the old one, then activate it. Two things the tooling does not say:
|
|
90
|
+
`schema_activate_block_type_version`'s `expectedFingerprint` is the fingerprint of
|
|
91
|
+
the **currently active** version, not the one you are activating (a mismatch is a
|
|
92
|
+
`CONFLICT`), and `schema_update_block_type` **replaces the whole `fields` list**, so
|
|
93
|
+
send every field, not just the changed one.
|
|
94
|
+
- **Migrating content:** `emdash content update` has no `--migrate-blocks` flag; the
|
|
95
|
+
REST route `PUT /_emdash/api/content/<collection>/<id>` with
|
|
96
|
+
`{ data, _rev, migrateBlocks: true }` does (it takes Portable Text arrays; the CLI
|
|
97
|
+
and MCP take Markdown). Updating a published entry stages a **draft** — a separate
|
|
98
|
+
`content publish` is needed before the live page changes, and (because pages are
|
|
99
|
+
prerendered) a rebuild after that.
|
|
100
|
+
- **Retiring is not deleting.** A type that was renamed or superseded stays in the
|
|
101
|
+
database and the seed permanently; keep its renderer mapping old values so existing
|
|
102
|
+
content still renders, mark it retired, and stop offering it to editors.
|
|
103
|
+
- **Typed fields:** `emdash types` does not type `blocks` fields (they come out as
|
|
104
|
+
`unknown[]`); hand-write a value type per renderer until EmDash generates it.
|
|
@@ -7,14 +7,14 @@ description: Work the client-onboarding checklist (SETUP.html) autonomously —
|
|
|
7
7
|
|
|
8
8
|
`SETUP.html` is the canonical checklist — this skill adds only sequencing,
|
|
9
9
|
gates, and where to stop. It does not restate the steps; read `SETUP.html`
|
|
10
|
-
(or `
|
|
10
|
+
(or `vp exec vitops setup --help`) for what each stage actually does and why.
|
|
11
11
|
|
|
12
12
|
## Steps
|
|
13
13
|
|
|
14
14
|
1. **Preview the whole sequence first.**
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
17
|
+
vp exec vitops setup all --dry
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Read the plan before doing anything. It names every step it would take and
|
|
@@ -24,10 +24,10 @@ gates, and where to stop. It does not restate the steps; read `SETUP.html`
|
|
|
24
24
|
2. **Run it.**
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
|
|
27
|
+
vp exec vitops setup all
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Re-run `
|
|
30
|
+
Re-run `vp exec vitops setup --check` after each leg rather than retrying on
|
|
31
31
|
your own judgment — a step already done resolves to a no-op skip, so a
|
|
32
32
|
second run is safe, and `--check` tells you exactly what still needs doing
|
|
33
33
|
instead of you guessing from output.
|
|
@@ -31,10 +31,13 @@ export PATH="$NODE24_BIN:$PATH"
|
|
|
31
31
|
echo "export PATH=\"$NODE24_BIN:\$PATH\"" >> "$CLAUDE_ENV_FILE"
|
|
32
32
|
|
|
33
33
|
# --- Dependencies (pnpm, pinned via package.json > packageManager) -----------
|
|
34
|
+
# pnpm is the bootstrap here: `vp` (Vite+) is a devDependency, so it only exists
|
|
35
|
+
# once this install has run. After that, use `vp install` / `vpr <script>` /
|
|
36
|
+
# `vp exec <bin>` — see AGENTS.md "Commands".
|
|
34
37
|
cd "$CLAUDE_PROJECT_DIR"
|
|
35
38
|
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
|
36
39
|
corepack enable
|
|
37
40
|
# `install` (not `--frozen-lockfile`) so the warmed container cache is reusable.
|
|
38
41
|
pnpm install
|
|
39
42
|
|
|
40
|
-
echo "Ready: Node $(node --version), pnpm $(pnpm --version)"
|
|
43
|
+
echo "Ready: Node $(node --version), pnpm $(pnpm --version), vp $(./node_modules/.bin/vp --version 2>/dev/null | head -1 || echo 'not installed')"
|
|
@@ -8,12 +8,23 @@
|
|
|
8
8
|
# Deploys via the vitops toolchain's reusable EmDash deploy workflow — see
|
|
9
9
|
# https://github.com/getvitops/design-system/blob/main/.github/workflows/site-deploy-emdash.yml
|
|
10
10
|
#
|
|
11
|
+
# Also runs on a `repository_dispatch` of type `emdash-publish`: pages are
|
|
12
|
+
# prerendered, so a publish in the EmDash admin only goes live after a rebuild,
|
|
13
|
+
# and an EmDash `content:afterPublish` hook POSTs that event (AGENTS.md,
|
|
14
|
+
# "Publish-triggered rebuilds"). A dispatch runs this file from the DEFAULT branch
|
|
15
|
+
# (`dev`), so `ref` pins the build to `main` — production's code, not dev's. It
|
|
16
|
+
# still goes through the `production` environment, so it still waits for the
|
|
17
|
+
# reviewers' approval; relax that rule if editors' publishes should go live
|
|
18
|
+
# unattended.
|
|
19
|
+
#
|
|
11
20
|
# Required repo secrets: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID
|
|
12
21
|
name: Deploy prod
|
|
13
22
|
|
|
14
23
|
on:
|
|
15
24
|
push:
|
|
16
25
|
branches: [main]
|
|
26
|
+
repository_dispatch:
|
|
27
|
+
types: [emdash-publish]
|
|
17
28
|
|
|
18
29
|
concurrency:
|
|
19
30
|
group: deploy-prod
|
|
@@ -25,6 +36,7 @@ jobs:
|
|
|
25
36
|
with:
|
|
26
37
|
environment: production
|
|
27
38
|
is-dev: false
|
|
39
|
+
ref: ${{ github.event_name == 'repository_dispatch' && 'main' || '' }}
|
|
28
40
|
# Set this to your production URL once known.
|
|
29
41
|
health-check-url: ''
|
|
30
42
|
secrets:
|