@booklyease/theme-sdk
v0.1.1
Published
Local dev toolkit for Booklyease vendor-site themes: preview a theme with fake data, switch block variants, validate and pack the bundle.
Downloads
37
Readme
@booklyease/theme-sdk
Local dev toolkit for Booklyease site themes (the templates that render a salon's storefront site on vendor-site).
Build a theme on your machine against fake data — no Booklyease backend, no config. Preview it, flip block display variants with one dropdown, then validate and pack it into an upload-ready bundle.
Install
Install once, globally, to get the booklyease-theme command everywhere:
npm install -g @booklyease/theme-sdkVerify:
booklyease-theme --helpPrefer not to install? Run it on demand with npx @booklyease/theme-sdk <command>
(see Quick start). Requires Node.js ≥ 18.
To upgrade later: npm install -g @booklyease/theme-sdk@latest.
Quick start
# preview the bundled example theme
npx @booklyease/theme-sdk dev
# or, if installed globally, from your own theme folder:
cd my-theme
booklyease-theme devOpen http://localhost:4500. Edit any .liquid file and save — the page live-reloads.
The editor (Window Site simulator)
The preview ships with an editor drawer (⚙, bottom-left) that mirrors the real vendor-site editor a salon uses, so you can build and edit a site exactly as they would — and catch anything that isn't editable before you ship.
- Блоки — add/remove/reorder/duplicate blocks, pick a variant, and edit every setting through a form generated from the real block registry (text, textarea, toggle, number, range, select, color, image/video URL, link action, and repeaters). Translatable fields edit the current language.
- Меню — build header & footer navigation, footer columns, social links and contacts (per-language labels + links), just like the real menu builder.
- Страницы — create pages (slug, title, home, status), edit per-language SEO (meta/OG/canonical/noindex). Each page has its own blocks.
- Оформление — header/footer toggles, logo/favicon, footer text & social
style, and color schemes: the available light/dark modes and the
palettes come from your
theme.json(modes/palettes), so you test exactly what your theme ships. Pick a scheme or tune any color by hand. - Проверка — runs the editability check (below) right in the panel.
Booking page
The booking page (/booking) is driven by the platform booking widget
(main.js) — the same code for every theme — which calls /api/booking/*.
A theme only ships the booking shell + CSS in pages/booking.liquid; it does
not own the wizard markup.
So locally the SDK:
- serves the real, vendored widget build at
/theme/assets/js/main.js, and - answers
/api/booking/*with a mock API (fake services, staff, locations, time slots, gym classes + occurrences;create/enrollalways succeed).
You get the actual production form — both modes via the built-in toggle: Услуга (individual appointment: service → staff → date/time → confirm) and Занятие (group class: class → occurrence → confirm). Nothing is persisted.
What a theme can customize today: all the booking CSS and the surrounding
booking.liquid markup (hero, contacts, layout around #bookingApp). What it
cannot (yet): the wizard's internal HTML/labels — those come from main.js.
Theme-owned booking + skeleton
To make the whole form theme-owned (structure, classes, labels — not just
CSS), a theme writes its booking form directly in pages/booking.liquid using a
small declarative contract, and a thin SDK driver (booking-driver.js) supplies
the logic (data from the mock API, step flow, submit). The theme owns 100% of
the markup — there is no separate route, it's just /booking.
The page shows a skeleton immediately (a [data-bz-skeleton] block); the
driver loads, fills the form, then adds .is-ready to [data-bz-app] so CSS
swaps skeleton → form with no layout jump — the real loading sequence. Tune the
reveal delay with ?delay=<ms> (e.g. /booking?delay=2000). pulse-gym ships a
sample. (If a theme's booking.liquid uses the legacy #bookingApp shell
instead, the SDK loads the platform widget — same /booking.)
Contract (all attributes optional; the driver adapts):
| Attribute | Meaning |
| --- | --- |
| data-bz-app data-api-base data-mode | form root |
| data-bz-mode="services\|classes" | mode toggle button |
| data-bz-screen="service\|staff\|datetime\|class\|occurrence\|contact\|done" | a step |
| data-bz-list="service\|staff\|day\|slot\|class\|occurrence" | where items are cloned |
| <template data-bz-tpl="…"> | the markup for one item |
| data-bz-field="name\|price\|duration\|date\|time\|free\|…" | text slot; data-bz-field-src = img src |
| data-bz-pick | makes an item selectable (gets .is-selected) |
| data-bz-input="name\|phone\|email\|comment" | contact field |
| data-bz-summary="service\|staff\|date\|time\|total" | live summary slot |
| data-bz-next data-bz-prev data-bz-submit | navigation |
Edits are saved to <theme>/.bz-editor/state.json (gitignored) so they survive
reloads. Every change (and every reset) first snapshots the previous document to
<theme>/.bz-editor/backups/ (last 30 kept) — to undo an accidental reset,
copy the newest backup over state.json. To run the SDK against throwaway state
without touching a theme's editor data, set BZ_STATE_DIR=/tmp/whatever. The eye
icon (👁) opens the page without the editor — the published look. Append
/ru, /ro, /en to preview a language.
Commands
| Command | What it does |
| --- | --- |
| booklyease-theme dev [dir] [--port 4500] | Preview + editor simulator with fake data + live reload |
| booklyease-theme validate [dir] | Check the bundle (theme.json, layouts, blocks) |
| booklyease-theme check [dir] | Verify everything the theme renders is editable |
| booklyease-theme pack [dir] [--out file.zip] | Validate, then zip into an upload-ready bundle |
dir defaults to the current directory.
"Is everything editable?" (check)
A frequent bug: a block prints block.s.some_field, but the editor has no
control for it — so a salon can never change it. check cross-references every
partials/blocks/<type>.liquid against what the editor can actually edit
(the block registry, mirrored from vendor-site) and reports:
- error —
block.s.xis rendered but has no editor field (not editable). - warning — the editor exposes a field the template never reads (dead control),
or
header_settings/footer_settingsreads a key the editor doesn't expose. - info — a block partial exists but isn't declared in
theme.jsonblocks, so it can't be placed.
Run it in CI: it exits non-zero when any rendered setting isn't editable.
Theme structure (no build step)
theme.json # manifest: name (localized), version (semver), blocks
layouts/default.liquid # page skeleton: uses {{ head }} {{ header }} {{ content }} {{ footer }}
partials/head.liquid # <head> — put ALL your CSS inline here (no Vite/SCSS)
partials/header.liquid
partials/footer.liquid
partials/blocks/<type>.liquid # one template per block type (hero, gallery, services, …)
locales/<ru|ro|en>.json # UI strings for the `t` filter
assets/… # images, fonts (served at /theme/assets/…)A block template receives its data as block.s (settings). Branch on
block.s.variant to support multiple display variants:
{% assign v = block.s.variant | default: 'center' %}
<section class="hero hero--{{ v }}">
<h1>{{ block.s.title }}</h1>
</section>By default a block's editable fields come from the built-in registry (the same
one vendor-site's editor uses). To expose your own fields, declare a rich
schema in theme.json instead of a bare type name — the editor (and this SDK)
then renders exactly those fields:
{
"blocks": [
"hero",
{
"type": "promo",
"label": "Promo banner",
"variants": [{ "id": "wide" }, { "id": "tall" }],
"fields": [
{ "key": "title", "type": "text", "translatable": true, "label": "Title" },
{ "key": "image", "type": "image", "translatable": false, "label": "Image" }
]
}
]
}background_color and section_theme are added to every block automatically.
Run check to confirm every block.s.* your template renders is declared.
Filters available to themes
Same as production (vendor-site):
{{ "nav.book" | t: locale }}— localized UI string fromlocales/<locale>.json{{ block.s.image | asset_url }}— resolves a media path to its public URL{{ anything | dump }}— debug: pretty-prints a value as JSON
Publishing
booklyease-theme pack→ producesmy-theme-1.0.0.zip.- In Booklyease admin → Integrations → Developer → Themes → Create theme, fill the marketplace card and upload that ZIP.
- Submit for review. Once approved, salons can pick your theme for their site.
Preview uses LiquidJS; production renders with the same Liquid dialect on the server. Keep templates to standard Liquid + the filters above for parity.
