@bytesbrains/weblocks 0.6.2 → 0.7.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/AGENT.md +5 -5
- package/CATALOG.md +66 -2
- package/CHANGELOG.md +49 -0
- package/README.md +54 -5
- package/catalog.json +412 -1
- package/lib/blocks/booking.d.ts +2 -0
- package/lib/blocks/booking.js +117 -0
- package/lib/blocks/hours.d.ts +2 -0
- package/lib/blocks/hours.js +97 -0
- package/lib/blocks/menu.d.ts +2 -0
- package/lib/blocks/menu.js +93 -0
- package/lib/blocks/product.d.ts +2 -0
- package/lib/blocks/product.js +92 -0
- package/lib/blocks/reviews.d.ts +2 -0
- package/lib/blocks/reviews.js +96 -0
- package/lib/generate.d.ts +19 -2
- package/lib/generate.js +43 -3
- package/lib/index.d.ts +3 -1
- package/lib/index.js +2 -0
- package/lib/islands/hours.d.ts +1 -0
- package/lib/islands/hours.js +69 -0
- package/lib/registry.js +9 -4
- package/lib/templates.d.ts +37 -0
- package/lib/templates.js +450 -0
- package/lib/verticals.d.ts +40 -0
- package/lib/verticals.js +117 -0
- package/package.json +2 -1
package/AGENT.md
CHANGED
|
@@ -46,19 +46,19 @@ its exact config schema:
|
|
|
46
46
|
- `catalogPrompt()` — a compact text menu for a system prompt.
|
|
47
47
|
- `CATALOG.md` — the same, human-readable.
|
|
48
48
|
|
|
49
|
-
The
|
|
49
|
+
The 50 block types, by group:
|
|
50
50
|
|
|
51
51
|
- **Chrome/app-shell:** `nav`, `app-shell`, `sidebar`, `announcement-bar`, `footer`
|
|
52
52
|
- **Heroes:** `hero`, `hero-app`
|
|
53
53
|
- **Résumé / profile:** `profile-header` (avatar, name, contacts, Download-PDF/Share buttons), `experience` (dated entries — reuse for Education/Certifications by changing its title), `skills` (tags or level bars)
|
|
54
54
|
- **Content:** `features`, `about`, `rich-text`, `split`, `steps`, `stats`,
|
|
55
|
-
`services-catalogue`, `pricing`, `logos`, `team`
|
|
55
|
+
`services-catalogue`, `menu` (food/drink menu — sections, dietary tags, spice), `product` (shoppable grid — price, badge, buy/enquire), `pricing`, `logos`, `team`
|
|
56
56
|
- **Media:** `gallery`, `carousel`, `video`, `video-gallery`, `map`
|
|
57
57
|
- **Location:** `directions` (deep links to open the visitor’s map app)
|
|
58
|
-
- **Structured:** `timeline`, `tabs`, `accordion`, `testimonials`, `faq`
|
|
58
|
+
- **Structured:** `timeline`, `tabs`, `accordion`, `testimonials`, `reviews` (star ratings + source), `faq`
|
|
59
59
|
- **Collections:** `blog-list`, `blog-post`, `feed`
|
|
60
|
-
- **Dynamic (powered):** `contact-form`, `newsletter`, `search`, `auth`
|
|
61
|
-
- **Conversion/rhythm:** `cta`, `social-links`, `contact-details`, `divider`, `spacer`, `copyright`
|
|
60
|
+
- **Dynamic (powered):** `booking` (appointment/reservation request — service, date, time), `contact-form`, `newsletter`, `search`, `auth`
|
|
61
|
+
- **Conversion/rhythm:** `cta`, `social-links`, `contact-details`, `hours` (structured weekly opening hours with a live open-now badge), `divider`, `spacer`, `copyright`
|
|
62
62
|
- **Legal:** `legal` (terms/privacy links that open safe-Markdown dialogs; content is Markdown, never raw HTML)
|
|
63
63
|
|
|
64
64
|
Interactivity is safe to enable: `gallery` with `lightbox: true`, `carousel` with
|
package/CATALOG.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# @bytesbrains/weblocks — Block Catalog (v0.
|
|
1
|
+
# @bytesbrains/weblocks — Block Catalog (v0.7.0)
|
|
2
2
|
|
|
3
3
|
The AI composes a `SiteManifest` (`{ meta, design, blocks[] }`) using **only** the block types below, then the engine validates + renders it to static HTML. This file is generated from the code (`npm run emit:catalog`) — do not edit by hand.
|
|
4
4
|
|
|
5
|
-
**Block types:** `app-shell` · `nav` · `announcement-bar` · `sidebar` · `hero` · `hero-app` · `profile-header` · `experience` · `skills` · `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `pricing` · `logos` · `team` · `gallery` · `carousel` · `video` · `video-gallery` · `map` · `timeline` · `tabs` · `accordion` · `testimonials` · `faq` · `blog-list` · `blog-post` · `feed` · `contact-form` · `newsletter` · `search` · `auth` · `cta` · `social-links` · `contact-details` · `directions` · `legal` · `divider` · `spacer` · `copyright` · `footer`
|
|
5
|
+
**Block types:** `app-shell` · `nav` · `announcement-bar` · `sidebar` · `hero` · `hero-app` · `profile-header` · `experience` · `skills` · `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `menu` · `product` · `pricing` · `logos` · `team` · `gallery` · `carousel` · `video` · `video-gallery` · `map` · `timeline` · `tabs` · `accordion` · `testimonials` · `reviews` · `faq` · `blog-list` · `blog-post` · `feed` · `booking` · `contact-form` · `newsletter` · `search` · `auth` · `cta` · `social-links` · `contact-details` · `hours` · `directions` · `legal` · `divider` · `spacer` · `copyright` · `footer`
|
|
6
6
|
|
|
7
7
|
## `app-shell`
|
|
8
8
|
|
|
@@ -178,6 +178,27 @@ A grid of services or products, each with a name, optional price, description, a
|
|
|
178
178
|
| `subtitle` | string | | |
|
|
179
179
|
| `items` | array | | |
|
|
180
180
|
|
|
181
|
+
## `menu`
|
|
182
|
+
|
|
183
|
+
A food/drink menu: named sections, each with items that have an optional price, dietary/allergen tags (e.g. V, VG, GF), and a 0–3 spice level. Use for restaurants and cafés.
|
|
184
|
+
|
|
185
|
+
| field | type | required | notes |
|
|
186
|
+
|---|---|---|---|
|
|
187
|
+
| `title` | string | | |
|
|
188
|
+
| `subtitle` | string | | |
|
|
189
|
+
| `sections` | array | | |
|
|
190
|
+
|
|
191
|
+
## `product`
|
|
192
|
+
|
|
193
|
+
A shoppable product grid: each item has an image, price (with optional "was" price and badge), and a buy/enquire link. Use for retail and e-commerce; the cart/checkout is the host's.
|
|
194
|
+
|
|
195
|
+
| field | type | required | notes |
|
|
196
|
+
|---|---|---|---|
|
|
197
|
+
| `title` | string | | |
|
|
198
|
+
| `subtitle` | string | | |
|
|
199
|
+
| `columns` | integer (2\|3\|4) | | |
|
|
200
|
+
| `items` | array | | |
|
|
201
|
+
|
|
181
202
|
## `pricing`
|
|
182
203
|
|
|
183
204
|
A row of pricing/tier cards, each with a name, price, feature list, and a call-to-action button; one plan can be highlighted.
|
|
@@ -299,6 +320,19 @@ A grid of customer quotes, each with the quote text and an optional author name
|
|
|
299
320
|
| `title` | string | | |
|
|
300
321
|
| `items` | array | | |
|
|
301
322
|
|
|
323
|
+
## `reviews`
|
|
324
|
+
|
|
325
|
+
Star-rated customer reviews (1–5 stars) each with an optional author, date, and source (Google, Yelp, …), plus an optional aggregate score. Richer than plain testimonial quotes.
|
|
326
|
+
|
|
327
|
+
| field | type | required | notes |
|
|
328
|
+
|---|---|---|---|
|
|
329
|
+
| `title` | string | | |
|
|
330
|
+
| `subtitle` | string | | |
|
|
331
|
+
| `average` | string | | |
|
|
332
|
+
| `count` | string | | |
|
|
333
|
+
| `source` | string | | |
|
|
334
|
+
| `items` | array | | |
|
|
335
|
+
|
|
302
336
|
## `faq`
|
|
303
337
|
|
|
304
338
|
An accordion of question/answer pairs. Expands/collapses natively (no JS).
|
|
@@ -341,6 +375,25 @@ A generic data-driven list of items in a list or card layout, each with a title,
|
|
|
341
375
|
| `layout` | undefined (list\|cards) | | |
|
|
342
376
|
| `items` | array | | |
|
|
343
377
|
|
|
378
|
+
## `booking`
|
|
379
|
+
|
|
380
|
+
An appointment/reservation request form (service, date, time, contact) that posts to a host-provided runtime. For booking-driven businesses — salons, clinics, gyms, hotels, events. No raw HTML.
|
|
381
|
+
|
|
382
|
+
| field | type | required | notes |
|
|
383
|
+
|---|---|---|---|
|
|
384
|
+
| `title` | string | | |
|
|
385
|
+
| `intro` | string | | |
|
|
386
|
+
| `submitLabel` | string | | |
|
|
387
|
+
| `successMessage` | string | | |
|
|
388
|
+
| `serviceLabel` | string | | |
|
|
389
|
+
| `services` | array | | |
|
|
390
|
+
| `askDate` | boolean | | |
|
|
391
|
+
| `askTime` | boolean | | |
|
|
392
|
+
| `askParty` | boolean | | |
|
|
393
|
+
| `askPhone` | boolean | | |
|
|
394
|
+
| `askNotes` | boolean | | |
|
|
395
|
+
| `notesLabel` | string | | |
|
|
396
|
+
|
|
344
397
|
## `contact-form`
|
|
345
398
|
|
|
346
399
|
A configurable contact form with typed fields (text, email, tel, textarea, select, checkbox) that posts to a host-provided runtime. No raw HTML.
|
|
@@ -424,6 +477,17 @@ A contact info block: address, phone, email, and opening hours (each optional).
|
|
|
424
477
|
| `email` | string | | |
|
|
425
478
|
| `hours` | string | | |
|
|
426
479
|
|
|
480
|
+
## `hours`
|
|
481
|
+
|
|
482
|
+
Structured weekly opening hours (24h times per day, split shifts allowed) rendered as an accessible table with a live "open now / closed" badge. Use for shops, cafés, salons, and clinics.
|
|
483
|
+
|
|
484
|
+
| field | type | required | notes |
|
|
485
|
+
|---|---|---|---|
|
|
486
|
+
| `title` | string | | |
|
|
487
|
+
| `timezone` | string | | |
|
|
488
|
+
| `note` | string | | |
|
|
489
|
+
| `days` | array | | |
|
|
490
|
+
|
|
427
491
|
## `directions`
|
|
428
492
|
|
|
429
493
|
A location card with deep links that open the visitor’s map app (Google/Apple Maps) for directions, from an address, GPS coordinates, or a pasted map link.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,55 @@ follows [semantic versioning](https://semver.org): the **block catalog** and the
|
|
|
5
5
|
**`SiteManifest` shape** are the public contract — additive block/field changes
|
|
6
6
|
are minor, breaking changes to either are major.
|
|
7
7
|
|
|
8
|
+
## 0.7.0 — 2026-07-17
|
|
9
|
+
|
|
10
|
+
Business verticals land: a vertical taxonomy, named starter templates, and five
|
|
11
|
+
new blocks that cover the booking-driven and shop verticals. Additive and
|
|
12
|
+
**non-breaking** — every `0.6.x` manifest still validates and renders
|
|
13
|
+
identically. Catalog 45 → 50.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Five new blocks for vertical coverage (#32).** Catalog 45 → 50.
|
|
17
|
+
- **`booking`** — an appointment/reservation request form (service, date, time,
|
|
18
|
+
contact) for the booking-driven verticals (salon, clinic, gym, hotel,
|
|
19
|
+
events). Powered brick: posts to the host `booking.request` capability, inert
|
|
20
|
+
fallback with no runtime, native form post + optional host island.
|
|
21
|
+
- **`hours`** — structured weekly opening hours (24h, split shifts) as an
|
|
22
|
+
accessible table with a live "open now / closed" badge via a shipped `hours`
|
|
23
|
+
island (static-first: the full week always renders without JS).
|
|
24
|
+
- **`menu`** — a food/drink menu: sections → items with price, dietary/allergen
|
|
25
|
+
tags, and a 0–3 spice level.
|
|
26
|
+
- **`product`** — a shoppable product grid: image, price (+ optional "was" and
|
|
27
|
+
badge), and a buy/enquire link per item.
|
|
28
|
+
- **`reviews`** — star-rated (1–5) customer reviews with author, date, and
|
|
29
|
+
source (Google/Yelp/…), plus an optional aggregate score.
|
|
30
|
+
|
|
31
|
+
Additive + non-breaking: every `0.6.x` manifest still validates and renders
|
|
32
|
+
identically. The booking-driven verticals (#30) now have a home block.
|
|
33
|
+
- **Named starter templates (`templates.ts`, #31).** One complete, realistic,
|
|
34
|
+
`validateManifest`-clean `SiteManifest` per vertical (17 in all), each with a
|
|
35
|
+
fitting preset baked in. Exposed as `TEMPLATES` / `templateNames()` /
|
|
36
|
+
`templatesForVertical()` / `getTemplate()` so a host can render an instant,
|
|
37
|
+
zero-LLM starter and the AI can scaffold from the same source of truth. A
|
|
38
|
+
runnable example (`npm run example:templates`) renders them all to
|
|
39
|
+
`templates-output/`.
|
|
40
|
+
- **Template-aware generation.** `generateSite` / `buildGenerationPrompt` accept
|
|
41
|
+
`{ template }` (a template id or a raw `SiteManifest`); when present the
|
|
42
|
+
structure + design are seeded into the prompt ("start from this, keep the
|
|
43
|
+
section set unless the brief conflicts, rewrite the copy for THIS business").
|
|
44
|
+
Blank-slate compose is unchanged when omitted.
|
|
45
|
+
- **Business-vertical taxonomy (`verticals.ts`, #30).** A small, stable list that
|
|
46
|
+
maps each vertical (`restaurant`, `salon`, `healthcare`, … `other`) to its
|
|
47
|
+
recommended sections (in order), a fitting `preset`, a copy `tone`, and a
|
|
48
|
+
`booking` flag. Exposed as `VERTICALS` / `verticalNames()` / `getVertical()` so
|
|
49
|
+
a host renders one source of truth instead of hardcoding a category list. Every
|
|
50
|
+
recommended block is a real catalog type (unit-tested).
|
|
51
|
+
- **Vertical-aware generation.** `generateSite` / `buildGenerationPrompt` accept
|
|
52
|
+
an optional `{ vertical }`; when present, the vertical's recommended sections +
|
|
53
|
+
preset are injected as advisory defaults ("prefer these unless the brief says
|
|
54
|
+
otherwise"). Blank-slate compose is unchanged when omitted. `GenerateOptions`
|
|
55
|
+
is exported.
|
|
56
|
+
|
|
8
57
|
## 0.6.2 — 2026-07-17
|
|
9
58
|
|
|
10
59
|
Bug fix: in-page nav links now scroll.
|
package/README.md
CHANGED
|
@@ -139,20 +139,20 @@ import catalogJson from '@bytesbrains/weblocks/catalog.json' with { type: 'json'
|
|
|
139
139
|
|
|
140
140
|
## Block catalog
|
|
141
141
|
|
|
142
|
-
**
|
|
142
|
+
**50 typed blocks.** Full field reference in [`CATALOG.md`](./CATALOG.md).
|
|
143
143
|
|
|
144
144
|
| Group | Blocks |
|
|
145
145
|
|---|---|
|
|
146
146
|
| Chrome / app-shell | `nav` · `app-shell` · `sidebar` · `announcement-bar` · `footer` |
|
|
147
147
|
| Heroes | `hero` · `hero-app` |
|
|
148
148
|
| Résumé / profile | `profile-header` · `experience` · `skills` (live CV — avatar, dated entries, skills, Download-PDF/Share) |
|
|
149
|
-
| Content | `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `pricing` · `logos` · `team` |
|
|
149
|
+
| Content | `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `menu` · `product` · `pricing` · `logos` · `team` |
|
|
150
150
|
| Media | `gallery` · `carousel` · `video` · `video-gallery` · `map` |
|
|
151
151
|
| Location | `directions` (deep links to the visitor’s map app) |
|
|
152
|
-
| Structured | `timeline` · `tabs` · `accordion` · `testimonials` · `faq` |
|
|
152
|
+
| Structured | `timeline` · `tabs` · `accordion` · `testimonials` · `reviews` · `faq` |
|
|
153
153
|
| Collections | `blog-list` · `blog-post` · `feed` |
|
|
154
|
-
| Dynamic (powered) | `contact-form` · `newsletter` · `search` · `auth` |
|
|
155
|
-
| Conversion / rhythm | `cta` · `social-links` · `contact-details` · `divider` · `spacer` · `copyright` |
|
|
154
|
+
| Dynamic (powered) | `booking` · `contact-form` · `newsletter` · `search` · `auth` |
|
|
155
|
+
| Conversion / rhythm | `cta` · `social-links` · `contact-details` · `hours` · `divider` · `spacer` · `copyright` |
|
|
156
156
|
| Legal | `legal` (terms/privacy links → safe-Markdown dialogs) |
|
|
157
157
|
|
|
158
158
|
`rich-text` and `blog-post` carry **typed** content nodes (headings, paragraphs,
|
|
@@ -273,6 +273,8 @@ All exports are named; types are shipped (`lib/index.d.ts`).
|
|
|
273
273
|
| **Catalog** | `catalog` · `catalogPrompt` |
|
|
274
274
|
| **Registry** | `REGISTRY` · `getSpec` · `blockTypes` · `needsIsland` |
|
|
275
275
|
| **Theming** | `DEFAULT_TOKENS` · `normalizeTokens` · `tokensToCss` · `sectionOverrideCss` · `readableOn` · `PRESETS` · `presetNames` · `getPreset` |
|
|
276
|
+
| **Verticals** | `VERTICALS` · `verticalNames` · `getVertical` |
|
|
277
|
+
| **Templates** | `TEMPLATES` · `templateNames` · `templatesForVertical` · `getTemplate` |
|
|
276
278
|
| **Runtime** | `NOOP_RUNTIME` · `pathRuntime` · `runtimeNeeds` |
|
|
277
279
|
| **PWA** | `buildWebManifest` · `buildWebManifestJson` · `buildServiceWorker` · `emitPwa` |
|
|
278
280
|
| **Schema utils** | `parse` · `escapeHtml` · `escapeAttr` · `sanitizeUrl` |
|
|
@@ -284,6 +286,52 @@ Core types: `SiteManifest` · `Block` · `DesignTokens` · `Palette` ·
|
|
|
284
286
|
`ModelCall` is `(args: { system: string; user: string }) => Promise<string>` — the
|
|
285
287
|
one thing you inject, so the engine never depends on a provider.
|
|
286
288
|
|
|
289
|
+
## Verticals
|
|
290
|
+
|
|
291
|
+
`verticals.ts` is a small, stable **business-vertical taxonomy** — one source of
|
|
292
|
+
truth for what *kind* of site is being built. Each entry maps a stable `id`
|
|
293
|
+
(persist it host-side as e.g. `businessType`) to a label + icon, a recommended
|
|
294
|
+
section set in order, a fitting `preset`, a copy `tone`, and a `booking` flag.
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
import { verticalNames, getVertical, generateSite } from '@bytesbrains/weblocks';
|
|
298
|
+
|
|
299
|
+
verticalNames(); // ['restaurant','retail','salon', … ,'other']
|
|
300
|
+
getVertical('salon'); // { id, label, blocks:[…], preset:'candy', booking:true, … }
|
|
301
|
+
|
|
302
|
+
// Seed compose with the vertical's recommended sections + preset (advisory):
|
|
303
|
+
await generateSite('a hair salon in Leeds', callModel, { vertical: 'salon' });
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Hosts building a category picker should **render `verticalNames()`** rather than
|
|
307
|
+
hardcode their own list — the same way the block editor consumes `catalog.json` —
|
|
308
|
+
so chips, the AI's section defaults, and starter templates all derive from one
|
|
309
|
+
list. Verticals are additive and stable: new ones are safe; existing `id`s are
|
|
310
|
+
never renamed or repurposed.
|
|
311
|
+
|
|
312
|
+
## Templates
|
|
313
|
+
|
|
314
|
+
`templates.ts` ships **named starter templates** — one complete, validated
|
|
315
|
+
`SiteManifest` per vertical, with realistic copy and a fitting preset baked in.
|
|
316
|
+
They serve two callers from one source of truth: a host renders one as an
|
|
317
|
+
instant, zero-LLM starter/preview, and generation seeds one as a scaffold to
|
|
318
|
+
personalise.
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
import { templatesForVertical, getTemplate, generateSite, renderSite } from '@bytesbrains/weblocks';
|
|
322
|
+
|
|
323
|
+
templatesForVertical('salon'); // [{ id:'salon-spa', label, manifest }, …]
|
|
324
|
+
renderSite(getTemplate('salon-spa')!.manifest); // instant preview, no model call
|
|
325
|
+
|
|
326
|
+
// Or scaffold generation from a template — keep the structure, rewrite the copy:
|
|
327
|
+
await generateSite('a taco truck in Austin', callModel, { template: 'restaurant-modern' });
|
|
328
|
+
// A raw SiteManifest works too: { template: myManifest }. Omit → blank-slate compose.
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Render every template to eyeball them: `npm run example:templates` →
|
|
332
|
+
`templates-output/index.html`. Templates are additive and stable (ids never
|
|
333
|
+
renamed); every manifest is `validateManifest`-clean (unit-tested).
|
|
334
|
+
|
|
287
335
|
## Adding a block
|
|
288
336
|
|
|
289
337
|
Register a `BlockSpec` (`type` + `schema` + `css` + `render`, optionally `island`
|
|
@@ -300,6 +348,7 @@ npm run build # tsc → lib/
|
|
|
300
348
|
npm test # block definition-of-done + engine invariants
|
|
301
349
|
npm run example # render a sample landing page → example-output.html
|
|
302
350
|
npm run example:resume # render a live résumé/CV → resume-output.html (try its Download-PDF)
|
|
351
|
+
npm run example:templates # render every starter template → templates-output/index.html
|
|
303
352
|
npm run emit:catalog # regenerate catalog.json + CATALOG.md from code
|
|
304
353
|
```
|
|
305
354
|
|