@bytesbrains/weblocks 0.6.1 → 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 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 45 block types, by group:
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.6.1)
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,74 @@ 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
+
57
+ ## 0.6.2 — 2026-07-17
58
+
59
+ Bug fix: in-page nav links now scroll.
60
+
61
+ ### Fixed
62
+ - **In-page nav links now scroll (#26).** `renderSite` previously emitted sections
63
+ without ids, so `#about` / `#menu` / `#contact` resolved to nothing on every
64
+ generated site. It now emits a stable, de-duped anchor `id` on each content
65
+ section (a canonical slug — e.g. `contact-details` → `#contact`,
66
+ `services-catalogue` → `#services`, `testimonials` → `#reviews`), and `nav`
67
+ (plus its CTA) resolves links by `#hash`, label, or a common alias
68
+ (`Menu` → services, `Get in touch` → contact, …). External/relative links pass
69
+ through; unresolved links fall back to `#` (top), never a dead anchor. Chrome
70
+ and rhythm blocks get no anchor. **Render-side, so re-rendering an existing
71
+ manifest just works** — no manifest change needed.
72
+
73
+ ### Added
74
+ - `slugify` exported (`'About Us!'` → `'about-us'`, folds diacritics).
75
+
8
76
  ## 0.6.1 — 2026-07-16
9
77
 
10
78
  Docs only — no engine changes.
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
- **45 typed blocks.** Full field reference in [`CATALOG.md`](./CATALOG.md).
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