@orderlyshop/web-components 0.1.0-build.7050 → 0.1.0-build.7056
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/AGENTS.md +2 -0
- package/README.md +148 -34
- package/bin/orderly-generate-server-renderers.mjs +624 -0
- package/bin/orderly-hydrate-static-pages.mjs +3 -2
- package/bin/orderly-init-shop.mjs +56 -88
- package/custom-elements.json +37 -4
- package/dist/browser/orderly-web-components.define.global.js +967 -251
- package/dist/browser/orderly-web-components.define.global.js.map +1 -1
- package/dist/browser/orderly-web-components.global.js +967 -251
- package/dist/browser/orderly-web-components.global.js.map +1 -1
- package/dist/{default-shop-DgX6uy10.d.ts → default-shop-D3ONKY6z.d.ts} +54 -9
- package/dist/default-shop.d.ts +2 -2
- package/dist/default-shop.js +88 -0
- package/dist/default-shop.js.map +1 -1
- package/dist/define-B607vO7u.d.ts +9 -0
- package/dist/define.d.ts +1 -1
- package/dist/define.js +2506 -429
- package/dist/define.js.map +1 -1
- package/dist/index.d.ts +67 -10
- package/dist/index.js +3018 -438
- package/dist/index.js.map +1 -1
- package/dist/navigation.d.ts +5 -2
- package/dist/navigation.js +240 -38
- package/dist/navigation.js.map +1 -1
- package/dist/{shop-BgQhGRzS.d.ts → shop-D1M9VnvQ.d.ts} +6 -1
- package/dist/shop.d.ts +4 -4
- package/dist/shop.js +2948 -451
- package/dist/shop.js.map +1 -1
- package/dist/stores.d.ts +26 -3
- package/dist/stores.js +200 -2
- package/dist/stores.js.map +1 -1
- package/dist/taxonomy.d.ts +2 -2
- package/dist/types-CXEwL2xS.d.ts +170 -0
- package/docs/components/README.md +76 -5
- package/docs/components/product-grid.md +1 -2
- package/examples/shop/README.md +8 -4
- package/examples/shop/package.json +2 -2
- package/examples/shop/src/includes/head.html +16 -4
- package/examples/shop/src/payment-failure.html +20 -0
- package/examples/shop/src/payment-success.html +20 -0
- package/examples/shop/src/storefront-router.ts +151 -0
- package/examples/shop/src/templates/page-layouts.html +199 -1
- package/examples/shop/vite.config.mjs +2 -67
- package/html-custom-data.json +33 -4
- package/package.json +7 -3
- package/server/README.md +57 -80
- package/server/ssr.mjs +783 -0
- package/server/vite.mjs +48 -0
- package/dist/define-BNMhl19n.d.ts +0 -9
- package/dist/types-Bjez59Hr.d.ts +0 -96
package/AGENTS.md
CHANGED
|
@@ -5,6 +5,7 @@ Use this package as a headless storefront component library. Prefer native custo
|
|
|
5
5
|
## Discovery
|
|
6
6
|
|
|
7
7
|
- Read `README.md` for setup and package-wide concepts.
|
|
8
|
+
- Read `DESIGN.md` before changing the visual theme. It defines the semantic design tokens that should be changed first.
|
|
8
9
|
- Read `docs/components/README.md` for component APIs.
|
|
9
10
|
- Read `docs/components/product-rail.md` and `docs/components/product-grid.md` before implementing product listing UI.
|
|
10
11
|
- Read `custom-elements.json` for machine-readable custom element metadata.
|
|
@@ -34,6 +35,7 @@ Use this package as a headless storefront component library. Prefer native custo
|
|
|
34
35
|
## Implementation Defaults
|
|
35
36
|
|
|
36
37
|
- Keep components headless. Add behavior and default light-DOM markup, not bundled theme CSS.
|
|
38
|
+
- Start theme work from the semantic tokens in `DESIGN.md`. Use component-local selectors and hooks only for deliberate exceptions after the shared tokens are set.
|
|
37
39
|
- Built-in UI copy defaults to Danish. Use `configureShop({ uiLanguage: "EN" })` for English shops, and prefer shop attributes/templates for wording that is unique to one storefront.
|
|
38
40
|
- Preserve template override support through `data-orderly-template`, `data-orderly-bind`, `data-orderly-slot`, and `data-orderly-action`.
|
|
39
41
|
- Put shop-wide templates in a shared document-level registry, for example template files included from `body-start.html`, using `data-orderly-template` plus `data-orderly-for`.
|
package/README.md
CHANGED
|
@@ -20,13 +20,15 @@ npm install
|
|
|
20
20
|
npm run dev
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Agents and developers should use `npx orderly-init-shop` before hand-writing shop files. It creates `src/index.html`, `src/category.html`, `src/product.html`, `src/checkout.html`, `src/includes/head.html`, `src/navigation.ts`, `src/shop-query.ts`, `src/templates/*.html`, `src/style.css`, `vite.config.mjs`, and package scripts. Pass an account id when the shop-wide default query should be tenant-scoped from the start:
|
|
23
|
+
Agents and developers should use `npx orderly-init-shop` before hand-writing shop files. It creates `src/index.html`, `src/category.html`, `src/product.html`, `src/checkout.html`, `src/payment-success.html`, `src/payment-failure.html`, `src/includes/head.html`, `src/navigation.ts`, `src/shop-query.ts`, `src/templates/*.html`, `src/style.css`, `vite.config.mjs`, and package scripts. The payment pages are physical callback URLs for payment providers and use the package `orderly-payment-success-page` and `orderly-payment-failure-page` components. Pass an account id when the shop-wide default query should be tenant-scoped from the start:
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
npx orderly-init-shop --account-id 00000000-0000-0000-0000-000000000000
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Re-running `npx orderly-init-shop` in an existing shop is non-destructive by default. Existing scaffold files are left unchanged with warnings, while missing new scaffold files are added. Use `--force` only when you explicitly want scaffold files overwritten.
|
|
30
|
+
|
|
31
|
+
The scaffold uses Vite for local development and static builds, but Vite is added to the generated shop's `devDependencies`. Dev mode SSR for product/category URLs is enabled by default, so View Source on local category/product URLs shows semantic server-rendered markup. Consumers should test locally from `http://localhost:61677` or `https://localhost:61677` because those are the expected local development origins for backend CORS. The generated Vite setup defaults to `http://localhost:61677`; if a local reverse proxy or TLS terminator is added, keep the same `localhost:61677` origin over HTTPS. `@orderlyshop/web-components` does not depend on Vite at runtime.
|
|
30
32
|
|
|
31
33
|
## Browser Standalone Bundle
|
|
32
34
|
|
|
@@ -66,7 +68,7 @@ Use the auto-register bundle for the built-in default shop or pages that configu
|
|
|
66
68
|
|
|
67
69
|
The normal package entrypoints remain ESM for bundlers. The standalone files are classic browser scripts and expose `window.OrderlyWebComponents`.
|
|
68
70
|
|
|
69
|
-
`configureShop()` is the recommended one-call setup for HTML head scripts. Its parameter is strongly typed as `ShopConfig`, so VS Code/TypeScript can provide completions directly on the object literal. All fields are optional: `uiLanguage`, `defaultShop`, `pageLayout`, `responsiveTemplates`, `shopFooter`, `storedImageUrls`, and `components`. It applies configuration first and then registers custom elements. Pass `components: false` only when elements are registered elsewhere.
|
|
71
|
+
`configureShop()` is the recommended one-call setup for HTML head scripts. Its parameter is strongly typed as `ShopConfig`, so VS Code/TypeScript can provide completions directly on the object literal. All fields are optional: `uiLanguage`, `defaultShop`, `storefrontRouter`, `pageLayout`, `responsiveTemplates`, `shopFooter`, `storedImageUrls`, and `components`. It applies configuration first and then registers custom elements. The built-in SPA storefront router is enabled by default; pass `storefrontRouter: { enabled: false }` only when a shop needs traditional full-page navigation for every internal link. Pass `components: false` only when elements are registered elsewhere.
|
|
70
72
|
|
|
71
73
|
Built-in component copy is Danish by default (`uiLanguage: "DA"`). Set `uiLanguage: "EN"` to switch built-in labels, empty states, checkout copy, navigation controls, and page defaults to English. Shop-specific attributes, templates, and `defaultShop` label fields still take precedence over language defaults.
|
|
72
74
|
|
|
@@ -74,6 +76,7 @@ Built-in component copy is Danish by default (`uiLanguage: "DA"`). Set `uiLangua
|
|
|
74
76
|
|
|
75
77
|
Developers and coding agents should start with these package-owned docs:
|
|
76
78
|
|
|
79
|
+
- [`DESIGN.md`](./DESIGN.md) defines the package-wide design tokens and the recommended theming workflow for consistent styling across all components.
|
|
77
80
|
- [`docs/components/README.md`](./docs/components/README.md) lists every custom element, common attributes, typed properties, events, and template hooks.
|
|
78
81
|
- [`docs/components/product-grid.md`](./docs/components/product-grid.md) documents search loading, sorting, paging, default query merging, and declarative query markup.
|
|
79
82
|
- [`docs/components/product-rail.md`](./docs/components/product-rail.md) documents homepage/category rails and their query configuration.
|
|
@@ -118,6 +121,82 @@ import "@orderlyshop/web-components/define";
|
|
|
118
121
|
|
|
119
122
|
The default backend is `https://service.orderly.shop`. Category links use real `/categories/<category-path>/` URLs by default so production builds can ship server-rendered category HTML. Use `categoryUrlMode: "hash"` only when a shop explicitly wants the older `/category.html#id=<category>` routing.
|
|
120
123
|
|
|
124
|
+
## SPA Storefront Navigation
|
|
125
|
+
|
|
126
|
+
SPA-style storefront navigation is the default when a shop calls `configureShop()`. It is implemented as progressive enhancement, not as a replacement for normal URLs:
|
|
127
|
+
|
|
128
|
+
- Links remain normal same-origin `<a href>` links, so Google, no-JS browsers, new tabs, copied links, and server-rendered entry pages still work.
|
|
129
|
+
- Ordinary left-click navigation between known storefront routes is intercepted in the browser and rendered without a physical reload.
|
|
130
|
+
- The router uses `history.pushState`, `popstate`, scroll restoration, canonical URLs, meta description updates, document title updates, and optional View Transitions.
|
|
131
|
+
- A shared `BasketController` is kept alive across home, category, product, checkout, payment result, and configured static routes.
|
|
132
|
+
- Unknown routes, external links, modified clicks, downloads, `_blank` links, and hash-only links fall back to the browser.
|
|
133
|
+
|
|
134
|
+
The default route coverage is:
|
|
135
|
+
|
|
136
|
+
- home: `defaultShop.homeHref`, default `/`
|
|
137
|
+
- categories: real category paths generated from `navigationDefinitions`, default `/categories/<category-path>/`
|
|
138
|
+
- product details: either hash or path product URLs, controlled by `defaultShop.productUrlMode`
|
|
139
|
+
- checkout: `defaultShop.checkoutHref`, default `/checkout.html`
|
|
140
|
+
- payment result pages: `/payment-success.html?orderid=...` and `/payment-failure.html?orderid=...`
|
|
141
|
+
- static pages: routes explicitly supplied in `storefrontRouter.staticRoutes`
|
|
142
|
+
|
|
143
|
+
The simplest setup needs no router block:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
configureShop({
|
|
147
|
+
defaultShop: {
|
|
148
|
+
homeHref: "/",
|
|
149
|
+
productHref: "/products/",
|
|
150
|
+
productUrlMode: "path",
|
|
151
|
+
productPathRoot: "/products/",
|
|
152
|
+
checkoutHref: "/checkout.html",
|
|
153
|
+
navigationDefinitions
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Use `storefrontRouter` only when the shop needs custom static pages, custom page factories, View Transition control, or an explicit opt-out:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
configureShop({
|
|
162
|
+
defaultShop: {
|
|
163
|
+
homeHref: "/",
|
|
164
|
+
productHref: "/products/",
|
|
165
|
+
productUrlMode: "path",
|
|
166
|
+
productPathRoot: "/products/",
|
|
167
|
+
checkoutHref: "/checkout.html"
|
|
168
|
+
},
|
|
169
|
+
storefrontRouter: {
|
|
170
|
+
product: {
|
|
171
|
+
mode: "path",
|
|
172
|
+
pathRoot: "/products/"
|
|
173
|
+
},
|
|
174
|
+
staticRoutes: [
|
|
175
|
+
{
|
|
176
|
+
path: "/forretningsbetingelser.html",
|
|
177
|
+
title: "Forretningsbetingelser | Example Shop",
|
|
178
|
+
description: "Køb, levering, betaling, retur og reklamation.",
|
|
179
|
+
create: () => document.querySelector("#termsPage")!.cloneNode(true) as HTMLElement
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Disable SPA navigation explicitly when a host application owns routing or when every internal link must perform a full document navigation:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
configureShop({
|
|
190
|
+
storefrontRouter: {
|
|
191
|
+
enabled: false
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
If a shop still uses hash-based product URLs, set `productUrlMode: "hash"` or `storefrontRouter.product.mode: "hash"`. The package supports both `#url=<encoded-share-url>` and real product paths; path URLs are preferred for SEO, while hash URLs remain a fallback for shops that cannot add server-side product routing yet.
|
|
197
|
+
|
|
198
|
+
For SEO, keep physical pages or static generated pages available for every URL the router can render dynamically. The router improves navigation after the first load; it does not remove the need for server/static support for direct requests to category, product, checkout, and content URLs.
|
|
199
|
+
|
|
121
200
|
Customize the default once per shop from the HTML head:
|
|
122
201
|
|
|
123
202
|
```ts
|
|
@@ -194,13 +273,15 @@ After installing from the repository workspace, run it with:
|
|
|
194
273
|
npm run dev --workspace @orderlyshop/example-shop
|
|
195
274
|
```
|
|
196
275
|
|
|
276
|
+
Open the local shop from `http://localhost:61677` during normal development, or `https://localhost:61677` when a local TLS proxy is in front of the dev server. Consumers should keep that exact localhost origin because the backend CORS development policy expects it.
|
|
277
|
+
|
|
197
278
|
Inside an installed package, inspect the same reference implementation at:
|
|
198
279
|
|
|
199
280
|
```text
|
|
200
281
|
node_modules/@orderlyshop/web-components/examples/shop
|
|
201
282
|
```
|
|
202
283
|
|
|
203
|
-
The example demonstrates how to customize the package default with Danish navigation, shop copy,
|
|
284
|
+
The example demonstrates how to customize the package default with Danish navigation, shop copy, declarative home/category/product/checkout pages, and the default SPA router. Its router config only adds static content routes and page factories; `enabled: true` is not required. It intentionally avoids local CSS and templates while the package default look and feel is developed. Shared component configuration lives in `src/includes/head.html`; the strongly typed navigation data lives in `src/navigation.ts`. It uses the package-level `orderly-generate-category-pages` and `orderly-build-category-pages` commands for simple real-URL category pages. It is included as readable source code and is not exported as part of the runtime API.
|
|
204
285
|
|
|
205
286
|
## Navigation Setup
|
|
206
287
|
|
|
@@ -296,7 +377,7 @@ Build with generated category pages and then clean the generated source files. S
|
|
|
296
377
|
npx orderly-build-category-pages
|
|
297
378
|
```
|
|
298
379
|
|
|
299
|
-
`orderly-build-category-pages` also hydrates the built `dist/index.html` and generated `dist/categories/**/index.html` pages with SEO-friendly fallback HTML. The hydration step embeds
|
|
380
|
+
`orderly-build-category-pages` also hydrates the built `dist/index.html` and generated `dist/categories/**/index.html` pages with SEO-friendly fallback HTML. The hydration step embeds semantic product cards per category using `SearchService.Search`; it reads `--base-url`, `VITE_ORDERLY_BASE_URL`, or `ORDERLY_BASE_URL`, and otherwise uses the default `https://service.orderly.shop` backend. Live web components read the semantic fallback as initial state, hide it, and then continue as normal client components.
|
|
300
381
|
|
|
301
382
|
Hydrate an already-built site manually, for example in a nightly job:
|
|
302
383
|
|
|
@@ -308,6 +389,26 @@ Use `--skip-products` for metadata-only hydration, `--strict-products` when a ni
|
|
|
308
389
|
|
|
309
390
|
The category generator expects `src/navigation.ts` or `src/navigation.js` to export `navigationDefinitions` and the template page to contain `<orderly-category-page></orderly-category-page>`. TypeScript navigation files use the current shop project's `typescript` dependency for one-off transpilation. Useful options include `--navigation`, `--template`, `--categories-dir`, `--site-title`, `--component-tag`, and `--export`. The older `--taxonomy` flag and `categoryDefinitions` export are still accepted as compatibility aliases.
|
|
310
391
|
|
|
392
|
+
## Local SSR Dev Mode
|
|
393
|
+
|
|
394
|
+
Scaffolded shops use SSR in dev mode by default through the package Vite middleware:
|
|
395
|
+
|
|
396
|
+
```js
|
|
397
|
+
import { orderlySsrDevServer } from "@orderlyshop/web-components/server/vite";
|
|
398
|
+
|
|
399
|
+
export default defineConfig({
|
|
400
|
+
plugins: [htmlIncludes(), orderlySsrDevServer(), rootHtmlOutput()]
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
When you run `npm run dev`, product and category URLs such as `http://localhost:61677/products/example.html/` and `http://localhost:61677/categories/sko/` are served from the normal `src/product.html` and `src/category.html` templates with semantic SSR HTML injected before Vite transforms the page. Use browser View Source to inspect the server-rendered markup.
|
|
405
|
+
|
|
406
|
+
SSR responses include a small inline critical CSS block for the semantic fallback markup. Normal browser requests hide that fallback and route component light DOM, such as utility banners, until the web components hydrate, so users do not see an unstyled intermediate layout. Googlebot user agents receive the visible fallback layout instead. The HTML source is identical in both cases; only fallback visibility changes.
|
|
407
|
+
|
|
408
|
+
After the first SSR entry render, the default storefront router intercepts same-origin category, product, checkout, payment-result, and configured static-page links. Navigation then stays virtual with `pushState` and persistent app-shell state, while the anchors still keep real `href` values for SEO, no-JS clients, copied links, and direct entry URLs. Set `storefrontRouter: { enabled: false }` only if the host app deliberately wants physical navigation after every click.
|
|
409
|
+
|
|
410
|
+
Set `ORDERLY_DEV_SSR=0` or run `npm run dev -- --no-ssr` to debug pure client-side rendering. Dev SSR uses `VITE_ORDERLY_BASE_URL`, `ORDERLY_BASE_URL`, or `https://service.orderly.shop`, defaults to `grpc-web`, and keeps a short per-URL in-memory cache. Override the cache with `ORDERLY_DEV_SSR_CACHE_TTL_MS`.
|
|
411
|
+
|
|
311
412
|
## Publish Static Sites
|
|
312
413
|
|
|
313
414
|
Installing `@orderlyshop/web-components` also installs a publish command for the consuming shop project. Run it from the project directory. The command generates category pages, builds, hydrates the built homepage/category pages, and publishes the resulting `dist` folder as vanilla HTML/JS/CSS.
|
|
@@ -338,33 +439,25 @@ Re-enter saved FTP settings:
|
|
|
338
439
|
npx orderly-publish-site --target ftp --configure
|
|
339
440
|
```
|
|
340
441
|
|
|
341
|
-
## Server Side Product URLs
|
|
442
|
+
## Server Side Product And Category URLs
|
|
342
443
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
- `server/apache/.htaccess` rewrites unknown product-like `.html` URLs to PHP.
|
|
346
|
-
- `server/php/orderly-product.php` reuses the built `product.html`, injects declarative SSR fallback markup into `<orderly-product-detail-page>`, and preserves built JS/CSS references.
|
|
347
|
-
- `server/nginx/orderly-products.conf` provides the equivalent Nginx rewrite for PHP-FPM.
|
|
348
|
-
- `server/node/product-snapshot-server.mjs` is an optional Node snapshot endpoint that calls `SearchService.Search` through `@orderlyshop/core-client` and returns product title, brand, price, image, and description as JSON.
|
|
349
|
-
|
|
350
|
-
Apache deployment example:
|
|
444
|
+
Production SSR for Apache/PHP is generated into the built site:
|
|
351
445
|
|
|
352
446
|
```sh
|
|
353
447
|
npm run build
|
|
354
|
-
|
|
355
|
-
cp node_modules/@orderlyshop/web-components/server/php/orderly-product.php dist/orderly-product.php
|
|
448
|
+
npx orderly-generate-server-renderers --site-title "My Shop"
|
|
356
449
|
```
|
|
357
450
|
|
|
358
|
-
|
|
451
|
+
Scaffolded shops run that generator from `npm run build` by default. It writes `dist/product.php`, `dist/category.php`, `dist/.htaccess`, and `dist/orderly-ssr-manifest.json`. The PHP renderers call `SearchService.Search` over gRPC-web, inject semantic HTML into the built `product.html` or `category.html`, and preserve the normal web-component scripts and styles.
|
|
359
452
|
|
|
360
|
-
|
|
361
|
-
ORDERLY_BACKEND_URL=https://service.orderly.shop \
|
|
362
|
-
node node_modules/@orderlyshop/web-components/server/node/product-snapshot-server.mjs
|
|
453
|
+
Runtime options:
|
|
363
454
|
|
|
364
|
-
|
|
365
|
-
|
|
455
|
+
- `ORDERLY_BASE_URL` overrides the backend URL used by PHP.
|
|
456
|
+
- `ORDERLY_SSR_TIMEOUT` controls PHP backend timeout in seconds.
|
|
457
|
+
- `ORDERLY_SSR_HEADERS` can add internal server-side request headers. Do not expose API keys or bearer tokens to browser JavaScript.
|
|
458
|
+
- `ORDERLY_SSR_MANIFEST` can point PHP to a manifest outside the web root.
|
|
366
459
|
|
|
367
|
-
The
|
|
460
|
+
The semantic fallback uses real headings, links, images, schema.org Product/Offer metadata, and small `data-orderly-*` attributes only for behavior-critical values. Components hydrate from that HTML, then hide the fallback and continue as normal interactive web components. Generated SSR output keeps the same HTML for users and crawlers, hides fallback visibility for normal browser hydration, and serves a visible fallback layout to Googlebot. See [`server/README.md`](./server/README.md) for details.
|
|
368
461
|
|
|
369
462
|
## Define Elements
|
|
370
463
|
|
|
@@ -467,27 +560,49 @@ collection.query = searchQuery;
|
|
|
467
560
|
## Components
|
|
468
561
|
|
|
469
562
|
- `orderly-page-layout` provides reusable page regions for header, header actions, left/right sidebars, content, footer, and overlay content. It includes a default logo image using `https://orderly.shop/home/App_Icon.svg`; override it with `logo-src`, `logo-alt`, and `logo-href`.
|
|
470
|
-
- `orderly-home-page` composes page layout, side navigation, one product rail per top-level category, basket icon, basket drawer, product detail dialog, and footer. Configure it with `configureShop({ defaultShop })` plus attributes such as `title`, `eyebrow`, `rail-cta-label`, and `product-href`. The product dialog
|
|
471
|
-
- `orderly-category-page` composes page layout, navigation, search, product grid, product detail, basket icon, and basket around a navigation category. Without properties it uses the package default shop configuration. Override with `configureShop({ defaultShop })` once per shop, set `base-url` or `product-href` in markup, or assign `category`, `navigationItems`, `sortOptions`, `client`, `defaultQuery`, and `basketController` from JavaScript for advanced cases. The product dialog
|
|
563
|
+
- `orderly-home-page` composes page layout, side navigation, one product rail per top-level category, basket icon, basket drawer, product detail dialog, and footer. Configure it with `configureShop({ defaultShop })` plus attributes such as `title`, `eyebrow`, `rail-cta-label`, and `product-href`. The product dialog expand link follows the configured product URL mode, and compact `https://orderly.shop/...` product URLs are preserved when it builds hash or path routes.
|
|
564
|
+
- `orderly-category-page` composes page layout, navigation, search, product grid, product detail, basket icon, and basket around a navigation category. Without properties it uses the package default shop configuration. Override with `configureShop({ defaultShop })` once per shop, set `base-url` or `product-href` in markup, or assign `category`, `navigationItems`, `sortOptions`, `client`, `defaultQuery`, and `basketController` from JavaScript for advanced cases. The product dialog expand link uses the configured product URL mode and still supports explicit per-page `product-href` overrides when a shop wants a different physical product page URL.
|
|
472
565
|
- `orderly-checkout-page` composes page layout, side navigation, checkout form, basket order summary, footer, shared basket state, delivery loading, and order-created cleanup. Delivery methods render as radio cards after address entry, service points render as radio-card pickup choices when required, and delivery changes verify the draft so totals update. Configure copy through `configureShop({ defaultShop: { checkoutPageTitle, checkoutPageDescription, checkoutOrderTitle, checkoutTermsHref, checkoutLabels, basketLabels } })`, or assign `client`, `basketController`, `navigationItems`, `checkoutLabels`, and `basketLabels` from JavaScript.
|
|
473
566
|
- `orderly-product-detail-page` composes page layout, navigation, product detail, basket drawer, and footer for a product route. Set `share-url`, the `shareUrl` property, or pass `#url=<encoded-share-url>` in the page URL; compact Orderly slugs are restored to `https://orderly.shop/...` before it calls `SearchService.Search` with `SearchQuery.ShareUrl` and renders the resolved `SearchObject`.
|
|
474
567
|
- `orderly-stored-image` accepts `image: StoredImage`, resolves image URLs from the configured prefix, and applies `RotationDeg`, crop, and full-size metadata in the browser.
|
|
475
568
|
- `orderly-credit` accepts `credit: Credit` or declarative `amount` and `currency` attributes, then renders stylable money markup. DKK values are formatted as `kr. <pris>`, for example `kr. 100,00`.
|
|
476
|
-
- `orderly-product-tile` accepts `product: SearchObject` and emits `orderly-product-selected`, `orderly-add-to-basket`, and `orderly-remove-from-basket`. Templates can bind the product share URL with `data-orderly-bind="share-url"`; anchors
|
|
569
|
+
- `orderly-product-tile` accepts `product: SearchObject` and emits `orderly-product-selected`, `orderly-add-to-basket`, and `orderly-remove-from-basket`. Templates can bind the product share URL with `data-orderly-bind="share-url"`; anchors without an existing `href` keep the raw share URL, while anchors that already point at a product page are rewritten to the configured physical product route using hash or path mode. Default tiles and statically hydrated category tiles include `schema.org/Product` and `schema.org/Offer` microdata for name, image, URL, description, SKU, brand, price, currency, and in-stock availability when those fields are present. When a `BasketController` is assigned through `basketController`, the default action button toggles between add and remove, using an icon-only button next to the price.
|
|
477
570
|
- `orderly-product-page` accepts `product: SearchObject`, renders all product image thumbnails, switches the selected image on thumbnail click, and exposes product details plus add-to-basket behavior.
|
|
478
571
|
- `orderly-search-box` binds to a target `orderly-product-grid`. Use `mode="textbox"` for an inline search input or `mode="icon"` for a header icon that opens a full-page search overlay. Icon mode searches automatically with a 500ms debounce and renders matching product tiles below the search field. Default home and category pages use icon mode next to the basket icon.
|
|
479
572
|
- `orderly-product-grid` accepts `query: SearchQuery`, merges the configured shop query scope, calls `SearchService.Search`, renders its own sort control from `sortOptions`, supports opaque `ContinuationToken` paging, manual paging, dynamic/infinite scroll, and default loading placeholders while the first page is pending.
|
|
480
573
|
- `orderly-product-rail` accepts `query: SearchQuery`, title, CTA label, and CTA href, then renders the search as a horizontal scroll list by composing `orderly-product-grid`. It is useful for homepages and editorial rows where several category searches should be stacked vertically.
|
|
481
574
|
- `orderly-collection-page` accepts `query: SearchQuery`, title, description, and hero image, then delegates fetching to `orderly-product-grid`.
|
|
482
575
|
- `orderly-shop-footer` renders configurable logo, about text, address, contact information, opening hours, and information links.
|
|
483
|
-
- `orderly-basket-icon` and `orderly-basket` share a `BasketController` backed by `DraftOrder` persistence. Basket state events such as `orderly-basket-open`, `orderly-basket-change`, and `orderly-basket-verified` use the current `DraftOrder` directly as `event.detail`, so consumers can derive counts and totals from Core contracts instead of an internal basket data shape. `orderly-basket` renders an item overview, verifies
|
|
484
|
-
- `orderly-checkout` persists checkout
|
|
485
|
-
- `orderly-navigation` uses `NavigationController` and can be subclassed with site-specific `NavigationItem[]`. It is sticky by default, including when placed in `left`, `right`, or `primary-nav`; set `sticky="false"` to opt out.
|
|
576
|
+
- `orderly-basket-icon` and `orderly-basket` share a `BasketController` backed by `DraftOrder` persistence. Basket state events such as `orderly-basket-open`, `orderly-basket-change`, and `orderly-basket-verified` use the current `DraftOrder` directly as `event.detail`, so consumers can derive counts and totals from Core contracts instead of an internal basket data shape. `orderly-basket` renders an item overview, verifies non-empty persisted drafts on load plus later basket mutations through `OrderService.VerifyDraft` when a client or `base-url` is configured, includes a configurable checkout link through `checkout-href` and `checkout-label`, and only exposes quantity selection for lines where `MaxQuantity > 1`. Summary rows now render only backend-provided `DraftOrder` values, never local subtotal/total math, and the component renders both `DraftOrder.Errors` and `DraftOrderLine.Errors`. Custom basket templates can project order-level errors through `data-orderly-slot="errors"`.
|
|
577
|
+
- `orderly-checkout` persists checkout contact and address fields directly on `DraftOrder.Transport`, defaults the phone country picker to `+45`, validates email and phone values with built-in component logic, looks up Danish city names from the entered postal code through Dataforsyningen's `https://api.dataforsyningen.dk/postnumre/{postnr}` endpoint, loads delivery methods and service points, verifies the draft, and calls `OrderService.Create`.
|
|
578
|
+
- `orderly-navigation` uses `NavigationController` and can be subclassed with site-specific `NavigationItem[]`. It is sticky by default, including when placed in `left`, `right`, or `primary-nav`; set `sticky="false"` to opt out. Use `layout="vertical"` for disclosure side navigation, `layout="horizontal"` for the tiered desktop bar, or `layout="burgermenu"` for an icon trigger that expands into the same nested disclosure menu inside a floating panel.
|
|
486
579
|
- `orderly-search-box`, `orderly-sort-select`, `orderly-filter-panel`, and `orderly-load-more` bind to `orderly-product-grid`.
|
|
487
580
|
|
|
488
581
|
## Rendering And Styling
|
|
489
582
|
|
|
490
|
-
The package ships baseline default CSS and uses light DOM. Default markup uses stable `orderly-*` class names and CSS variables
|
|
583
|
+
The package ships baseline default CSS and uses light DOM. Default markup uses stable `orderly-*` class names and CSS variables, so host CSS can style or replace the default look directly.
|
|
584
|
+
|
|
585
|
+
For consistent theming across the whole package, start with the semantic design contract in [`DESIGN.md`](./DESIGN.md). In practice that means overriding `--orderly-color-primary`, `--orderly-color-primary-soft`, `--orderly-color-primary-contrast`, the `--orderly-action-primary-*` and `--orderly-action-secondary-*` tokens, plus shared tokens such as `--orderly-link-accent-color`, `--orderly-selection-*`, and `--orderly-badge-*`. `--orderly-color-accent` is kept as a compatibility alias, but new themes should treat `--orderly-color-primary` as the source of truth.
|
|
586
|
+
|
|
587
|
+
Example:
|
|
588
|
+
|
|
589
|
+
```css
|
|
590
|
+
:root {
|
|
591
|
+
--orderly-color-primary: #1f7a43;
|
|
592
|
+
--orderly-color-primary-soft: #e7f4eb;
|
|
593
|
+
--orderly-color-primary-contrast: #ffffff;
|
|
594
|
+
--orderly-link-accent-color: var(--orderly-color-primary);
|
|
595
|
+
--orderly-selection-border: var(--orderly-color-primary);
|
|
596
|
+
--orderly-selection-background: var(--orderly-color-primary-soft);
|
|
597
|
+
--orderly-badge-background: var(--orderly-color-primary);
|
|
598
|
+
--orderly-badge-color: var(--orderly-color-primary-contrast);
|
|
599
|
+
--orderly-action-primary-background: var(--orderly-color-primary);
|
|
600
|
+
--orderly-action-primary-border: var(--orderly-color-primary);
|
|
601
|
+
--orderly-action-primary-color: var(--orderly-color-primary-contrast);
|
|
602
|
+
--orderly-action-secondary-border: var(--orderly-color-primary);
|
|
603
|
+
--orderly-action-secondary-color: var(--orderly-color-primary);
|
|
604
|
+
}
|
|
605
|
+
```
|
|
491
606
|
|
|
492
607
|
Rendering can be replaced with templates:
|
|
493
608
|
|
|
@@ -537,7 +652,7 @@ Rendering can be replaced with templates:
|
|
|
537
652
|
|
|
538
653
|
For dynamic paging, `orderly-product-grid` keeps the returned `PageResult.Continuation` as an opaque `ContinuationToken` and sends it as `SearchQuery.Continuation` when the sentinel enters the viewport. Dynamic and infinite paging do not render a load-more button. Use `paging="button"` only when a visible load-more button is desired, `paging="manual"` when another control calls `loadNextPage()`, and `paging="dynamic"` or `paging="infinite"` for automatic loading.
|
|
539
654
|
|
|
540
|
-
Every component has a default light-DOM implementation and matching template hooks. Use `data-orderly-bind` for values, `data-orderly-action` for behavior, and `data-orderly-slot` for repeated or projected content. Product tile templates can bind `basket-action-icon`, `basket-action-label`, and `basket-action-state` and use `data-orderly-action="add-to-basket"` for the add/remove toggle. Product page galleries use `data-orderly-slot="thumbnails"` and `data-orderly-action="select-image"` for custom thumbnail markup. Product rail templates can replace the outer `layout`, inner `grid`, product item, loading state, and empty state. The main template names are `layout`, `grid`, `footer`, `product`, `thumbnail`, `image`, `basket`, `basket-icon`, `line`, `checkout`, `navigation`, `item`, `search-box`, `sort`, `sort-select`, `filter-panel`, `load-more`, `address-line`, `contact-item`, `opening-hour`, and `information-link`.
|
|
655
|
+
Every component has a default light-DOM implementation and matching template hooks. Use `data-orderly-bind` for values, `data-orderly-action` for behavior, and `data-orderly-slot` for repeated or projected content. Product tile templates can bind `basket-action-icon`, `basket-action-label`, and `basket-action-state` and use `data-orderly-action="add-to-basket"` for the add/remove toggle. Product page galleries use `data-orderly-slot="thumbnails"` and `data-orderly-action="select-image"` for custom thumbnail markup. Basket templates can add `data-orderly-slot="errors"` to place order-level `DraftOrder.Errors` exactly where a shop wants them. Product rail templates can replace the outer `layout`, inner `grid`, product item, loading state, and empty state. The main template names are `layout`, `grid`, `footer`, `product`, `thumbnail`, `image`, `basket`, `basket-icon`, `line`, `checkout`, `navigation`, `item`, `search-box`, `sort`, `sort-select`, `filter-panel`, `load-more`, `address-line`, `contact-item`, `opening-hour`, and `information-link`.
|
|
541
656
|
|
|
542
657
|
Product sorting belongs to `orderly-product-grid`: assign `grid.sortOptions = [{ label, orderBy }]` or pass sort options through `orderly-collection-page.sortOptions`. The default grid layout renders the sort select above the products. Custom grid layouts should include `data-orderly-slot="sort"` where the control should appear, and custom sort templates can use `data-orderly-template="sort"` with a `<select data-orderly-action="sort">`.
|
|
543
658
|
|
|
@@ -671,15 +786,14 @@ productImage.image = searchObject.Images[0];
|
|
|
671
786
|
|
|
672
787
|
## State And Security
|
|
673
788
|
|
|
674
|
-
Basket drafts
|
|
789
|
+
Basket drafts are persisted to localStorage by default. Checkout contact and address data are stored directly on `DraftOrder.Transport`, so basket items, delivery selection, and checkout form state all share the same persisted draft. That draft can contain PII such as name, address, email, and phone. Provide a custom basket store to change or disable that behavior. This package never stores tokens, API keys, OAuth responses, or cookie values.
|
|
675
790
|
|
|
676
|
-
|
|
791
|
+
Persistence uses `LocalStorageBasketStore` and stores the full `DraftOrder`:
|
|
677
792
|
|
|
678
793
|
```ts
|
|
679
794
|
import { createBasketController } from "@orderlyshop/web-components";
|
|
680
795
|
|
|
681
796
|
basket.basketController = createBasketController({ store: myBasketStore });
|
|
682
|
-
checkout.profileStore = myCheckoutProfileStore;
|
|
683
797
|
```
|
|
684
798
|
|
|
685
799
|
Authentication remains owned by `@orderlyshop/core-client`. Browser cookie-backed sessions work through the core browser client and credentialed gRPC-web requests.
|