{"_id":"@booklyease/theme-sdk","_rev":"2-2867a70fcf70c96c238a4bb87f2b5f03","name":"@booklyease/theme-sdk","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@booklyease/theme-sdk","version":"0.1.0","keywords":["booklyease","theme","liquid","sdk"],"license":"MIT","_id":"@booklyease/theme-sdk@0.1.0","maintainers":[{"name":"jcube","email":"alteraweb53@gmail.com"}],"bin":{"booklyease-theme":"bin/booklyease-theme.js"},"dist":{"shasum":"b233ed9913b61d2ba87ef76e5749e4956ca3eead","tarball":"https://registry.npmjs.org/@booklyease/theme-sdk/-/theme-sdk-0.1.0.tgz","fileCount":30,"integrity":"sha512-i8Gs7D2YOYvxpeYqtzi4FbPGpxd8Zg648uoyyAeGCnIUxzUWYmuflLVmtfzCJWOgaFaqtOdrcgpHBHVjYkXDLQ==","signatures":[{"sig":"MEUCIQDbkLdq6B/cZwIwxDHoN2WJ6mNtKfS3tuM5wb72CecVMQIgdaPDJrcPDGrQBprXKt0VqAn0XjFZYcnZQ5KwmewSbHw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":231657},"type":"module","engines":{"node":">=18"},"gitHead":"17f82247698d2890c6a0414fd650e8f9b43118b7","scripts":{"dev":"node bin/booklyease-theme.js dev","pack":"node bin/booklyease-theme.js pack","check":"node bin/booklyease-theme.js check","validate":"node bin/booklyease-theme.js validate"},"_npmUser":{"name":"jcube","email":"alteraweb53@gmail.com"},"_npmVersion":"11.17.0","description":"Local dev toolkit for Booklyease vendor-site themes: preview a theme with fake data, switch block variants, validate and pack the bundle.","directories":{},"_nodeVersion":"20.19.0","dependencies":{"adm-zip":"^0.5.12","chokidar":"^3.6.0","liquidjs":"^10.13.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/theme-sdk_0.1.0_1783937855971_0.2157456742511239","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@booklyease/theme-sdk","version":"0.1.1","description":"Local dev toolkit for Booklyease vendor-site themes: preview a theme with fake data, switch block variants, validate and pack the bundle.","type":"module","bin":{"booklyease-theme":"bin/booklyease-theme.js"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"scripts":{"dev":"node bin/booklyease-theme.js dev","validate":"node bin/booklyease-theme.js validate","check":"node bin/booklyease-theme.js check","pack":"node bin/booklyease-theme.js pack"},"keywords":["booklyease","theme","liquid","sdk"],"dependencies":{"adm-zip":"^0.5.12","chokidar":"^3.6.0","liquidjs":"^10.13.0"},"license":"MIT","gitHead":"17f82247698d2890c6a0414fd650e8f9b43118b7","_id":"@booklyease/theme-sdk@0.1.1","_nodeVersion":"20.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-BCYjMzvTTmTd3nxMOSnUchMacy99+G2Ziu0NeXZDnb8d5h+865+8dPqXGTh+llhOmVsL0bUmwe/bAe3rJHYzug==","shasum":"8adcf03cb608e4df0cc9523b29024e35980187a4","tarball":"https://registry.npmjs.org/@booklyease/theme-sdk/-/theme-sdk-0.1.1.tgz","fileCount":30,"unpackedSize":232046,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIErxmJfyJR2BRNpKClR6By5Oday+v7C+oOgJicPlPrMLAiEA5/eyNxJrhck+uWlEKjjJr7G0d9szhcpc6YVBqEsR7hc="}]},"_npmUser":{"name":"jcube","email":"alteraweb53@gmail.com"},"directories":{},"maintainers":[{"name":"jcube","email":"alteraweb53@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/theme-sdk_0.1.1_1783938103829_0.2115996032505285"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-13T10:17:35.857Z","modified":"2026-07-13T10:21:44.096Z","0.1.0":"2026-07-13T10:17:36.147Z","0.1.1":"2026-07-13T10:21:43.972Z"},"license":"MIT","keywords":["booklyease","theme","liquid","sdk"],"description":"Local dev toolkit for Booklyease vendor-site themes: preview a theme with fake data, switch block variants, validate and pack the bundle.","maintainers":[{"name":"jcube","email":"alteraweb53@gmail.com"}],"readme":"# @booklyease/theme-sdk\n\nLocal dev toolkit for **Booklyease site themes** (the templates that render a\nsalon's storefront site on vendor-site).\n\nBuild a theme on your machine against **fake data** — no Booklyease backend, no\nconfig. Preview it, flip block display **variants** with one dropdown, then\n**validate** and **pack** it into an upload-ready bundle.\n\n## Install\n\nInstall once, globally, to get the `booklyease-theme` command everywhere:\n\n```bash\nnpm install -g @booklyease/theme-sdk\n```\n\nVerify:\n\n```bash\nbooklyease-theme --help\n```\n\nPrefer not to install? Run it on demand with `npx @booklyease/theme-sdk <command>`\n(see Quick start). Requires **Node.js ≥ 18**.\n\nTo upgrade later: `npm install -g @booklyease/theme-sdk@latest`.\n\n## Quick start\n\n```bash\n# preview the bundled example theme\nnpx @booklyease/theme-sdk dev\n\n# or, if installed globally, from your own theme folder:\ncd my-theme\nbooklyease-theme dev\n```\n\nOpen <http://localhost:4500>. Edit any `.liquid` file and save — the page live-reloads.\n\n## The editor (Window Site simulator)\n\nThe preview ships with an **editor drawer** (⚙, bottom-left) that mirrors the\nreal vendor-site editor a salon uses, so you can build and edit a site exactly\nas they would — and catch anything that *isn't* editable before you ship.\n\n- **Блоки** — add/remove/reorder/duplicate blocks, pick a variant, and edit\n  every setting through a form generated from the **real block registry**\n  (text, textarea, toggle, number, range, select, color, image/video URL,\n  link action, and repeaters). Translatable fields edit the current language.\n- **Меню** — build header & footer navigation, footer columns, social links and\n  contacts (per-language labels + links), just like the real menu builder.\n- **Страницы** — create pages (slug, title, home, status), edit per-language SEO\n  (meta/OG/canonical/noindex). Each page has its own blocks.\n- **Оформление** — header/footer toggles, logo/favicon, footer text & social\n  style, and **color schemes**: the available light/dark **modes** and the\n  **palettes** come from your `theme.json` (`modes` / `palettes`), so you test\n  exactly what your theme ships. Pick a scheme or tune any color by hand.\n- **Проверка** — runs the editability check (below) right in the panel.\n\n### Booking page\n\nThe **booking page** (`/booking`) is driven by the **platform booking widget**\n(`main.js`) — the same code for every theme — which calls `/api/booking/*`.\nA theme only ships the booking *shell + CSS* in `pages/booking.liquid`; it does\n**not** own the wizard markup.\n\nSo locally the SDK:\n\n- serves the **real, vendored widget build** at `/theme/assets/js/main.js`, and\n- answers `/api/booking/*` with a **mock API** (fake services, staff, locations,\n  time slots, gym classes + occurrences; `create`/`enroll` always succeed).\n\nYou get the actual production form — **both modes** via the built-in toggle:\n**Услуга** (individual appointment: service → staff → date/time → confirm) and\n**Занятие** (group class: class → occurrence → confirm). Nothing is persisted.\n\nWhat a theme **can** customize today: all the booking CSS and the surrounding\n`booking.liquid` markup (hero, contacts, layout around `#bookingApp`). What it\n**cannot** (yet): the wizard's internal HTML/labels — those come from `main.js`.\n\n### Theme-owned booking + skeleton\n\nTo make the **whole form** theme-owned (structure, classes, labels — not just\nCSS), a theme writes its booking form directly in `pages/booking.liquid` using a\nsmall declarative contract, and a thin SDK driver (`booking-driver.js`) supplies\nthe logic (data from the mock API, step flow, submit). The theme owns 100% of\nthe markup — there is **no separate route**, it's just `/booking`.\n\nThe page shows a **skeleton** immediately (a `[data-bz-skeleton]` block); the\ndriver loads, fills the form, then adds `.is-ready` to `[data-bz-app]` so CSS\nswaps skeleton → form with no layout jump — the real loading sequence. Tune the\nreveal delay with `?delay=<ms>` (e.g. `/booking?delay=2000`). `pulse-gym` ships a\nsample. (If a theme's `booking.liquid` uses the legacy `#bookingApp` shell\ninstead, the SDK loads the platform widget — same `/booking`.)\n\nContract (all attributes optional; the driver adapts):\n\n| Attribute | Meaning |\n| --- | --- |\n| `data-bz-app` `data-api-base` `data-mode` | form root |\n| `data-bz-mode=\"services\\|classes\"` | mode toggle button |\n| `data-bz-screen=\"service\\|staff\\|datetime\\|class\\|occurrence\\|contact\\|done\"` | a step |\n| `data-bz-list=\"service\\|staff\\|day\\|slot\\|class\\|occurrence\"` | where items are cloned |\n| `<template data-bz-tpl=\"…\">` | the markup for one item |\n| `data-bz-field=\"name\\|price\\|duration\\|date\\|time\\|free\\|…\"` | text slot; `data-bz-field-src` = img src |\n| `data-bz-pick` | makes an item selectable (gets `.is-selected`) |\n| `data-bz-input=\"name\\|phone\\|email\\|comment\"` | contact field |\n| `data-bz-summary=\"service\\|staff\\|date\\|time\\|total\"` | live summary slot |\n| `data-bz-next` `data-bz-prev` `data-bz-submit` | navigation |\n\nEdits are saved to `<theme>/.bz-editor/state.json` (gitignored) so they survive\nreloads. Every change (and every reset) first snapshots the previous document to\n`<theme>/.bz-editor/backups/` (last 30 kept) — to undo an accidental reset,\ncopy the newest backup over `state.json`. To run the SDK against throwaway state\nwithout touching a theme's editor data, set `BZ_STATE_DIR=/tmp/whatever`. The eye\nicon (👁) opens the page **without** the editor — the published look. Append\n`/ru`, `/ro`, `/en` to preview a language.\n\n## Commands\n\n| Command | What it does |\n| --- | --- |\n| `booklyease-theme dev [dir] [--port 4500]` | Preview + editor simulator with fake data + live reload |\n| `booklyease-theme validate [dir]` | Check the bundle (theme.json, layouts, blocks) |\n| `booklyease-theme check [dir]` | Verify everything the theme renders is **editable** |\n| `booklyease-theme pack [dir] [--out file.zip]` | Validate, then zip into an upload-ready bundle |\n\n`dir` defaults to the current directory.\n\n## \"Is everything editable?\" (`check`)\n\nA frequent bug: a block prints `block.s.some_field`, but the editor has no\ncontrol for it — so a salon can never change it. `check` cross-references every\n`partials/blocks/<type>.liquid` against what the editor can actually edit\n(the block registry, mirrored from vendor-site) and reports:\n\n- **error** — `block.s.x` is rendered but has **no editor field** (not editable).\n- **warning** — the editor exposes a field the template never reads (dead control),\n  or `header_settings`/`footer_settings` reads a key the editor doesn't expose.\n- **info** — a block partial exists but isn't declared in `theme.json` `blocks`,\n  so it can't be placed.\n\nRun it in CI: it exits non-zero when any rendered setting isn't editable.\n\n## Theme structure (no build step)\n\n```\ntheme.json                      # manifest: name (localized), version (semver), blocks\nlayouts/default.liquid          # page skeleton: uses {{ head }} {{ header }} {{ content }} {{ footer }}\npartials/head.liquid            # <head> — put ALL your CSS inline here (no Vite/SCSS)\npartials/header.liquid\npartials/footer.liquid\npartials/blocks/<type>.liquid   # one template per block type (hero, gallery, services, …)\nlocales/<ru|ro|en>.json         # UI strings for the `t` filter\nassets/…                        # images, fonts (served at /theme/assets/…)\n```\n\nA block template receives its data as `block.s` (settings). Branch on\n`block.s.variant` to support multiple display variants:\n\n```liquid\n{% assign v = block.s.variant | default: 'center' %}\n<section class=\"hero hero--{{ v }}\">\n  <h1>{{ block.s.title }}</h1>\n</section>\n```\n\nBy default a block's editable fields come from the built-in registry (the same\none vendor-site's editor uses). To expose **your own** fields, declare a rich\nschema in `theme.json` instead of a bare type name — the editor (and this SDK)\nthen renders exactly those fields:\n\n```json\n{\n  \"blocks\": [\n    \"hero\",\n    {\n      \"type\": \"promo\",\n      \"label\": \"Promo banner\",\n      \"variants\": [{ \"id\": \"wide\" }, { \"id\": \"tall\" }],\n      \"fields\": [\n        { \"key\": \"title\", \"type\": \"text\", \"translatable\": true, \"label\": \"Title\" },\n        { \"key\": \"image\", \"type\": \"image\", \"translatable\": false, \"label\": \"Image\" }\n      ]\n    }\n  ]\n}\n```\n\n`background_color` and `section_theme` are added to every block automatically.\nRun `check` to confirm every `block.s.*` your template renders is declared.\n\n## Filters available to themes\n\nSame as production (vendor-site):\n\n- `{{ \"nav.book\" | t: locale }}` — localized UI string from `locales/<locale>.json`\n- `{{ block.s.image | asset_url }}` — resolves a media path to its public URL\n- `{{ anything | dump }}` — debug: pretty-prints a value as JSON\n\n## Publishing\n\n1. `booklyease-theme pack` → produces `my-theme-1.0.0.zip`.\n2. In Booklyease admin → **Integrations → Developer → Themes → Create theme**,\n   fill the marketplace card and upload that ZIP.\n3. Submit for review. Once approved, salons can pick your theme for their site.\n\n> Preview uses LiquidJS; production renders with the same Liquid dialect on the\n> server. Keep templates to standard Liquid + the filters above for parity.\n","readmeFilename":"README.md"}