@orderlyshop/web-components 0.1.0-build.7045
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 +110 -0
- package/README.md +685 -0
- package/bin/orderly-build-category-pages.mjs +160 -0
- package/bin/orderly-generate-category-pages.mjs +308 -0
- package/bin/orderly-hydrate-static-pages.mjs +595 -0
- package/bin/orderly-init-navigation.mjs +327 -0
- package/bin/orderly-init-shop.mjs +876 -0
- package/bin/orderly-init-taxonomy.mjs +2 -0
- package/bin/orderly-publish-site.mjs +342 -0
- package/custom-elements.json +505 -0
- package/dist/browser/orderly-web-components.define.global.js +3551 -0
- package/dist/browser/orderly-web-components.define.global.js.map +1 -0
- package/dist/browser/orderly-web-components.global.js +3551 -0
- package/dist/browser/orderly-web-components.global.js.map +1 -0
- package/dist/default-shop-DgX6uy10.d.ts +221 -0
- package/dist/default-shop.d.ts +6 -0
- package/dist/default-shop.js +762 -0
- package/dist/default-shop.js.map +1 -0
- package/dist/define-BNMhl19n.d.ts +9 -0
- package/dist/define.d.ts +2 -0
- package/dist/define.js +11094 -0
- package/dist/define.js.map +1 -0
- package/dist/index.d.ts +683 -0
- package/dist/index.js +11417 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation.d.ts +61 -0
- package/dist/navigation.js +1125 -0
- package/dist/navigation.js.map +1 -0
- package/dist/query.d.ts +31 -0
- package/dist/query.js +115 -0
- package/dist/query.js.map +1 -0
- package/dist/registry-CPDecU3g.d.ts +6 -0
- package/dist/shop-BgQhGRzS.d.ts +173 -0
- package/dist/shop-query.d.ts +8 -0
- package/dist/shop-query.js +100 -0
- package/dist/shop-query.js.map +1 -0
- package/dist/shop.d.ts +8 -0
- package/dist/shop.js +11187 -0
- package/dist/shop.js.map +1 -0
- package/dist/stores.d.ts +46 -0
- package/dist/stores.js +145 -0
- package/dist/stores.js.map +1 -0
- package/dist/taxonomy.d.ts +35 -0
- package/dist/taxonomy.js +247 -0
- package/dist/taxonomy.js.map +1 -0
- package/dist/types-Bjez59Hr.d.ts +96 -0
- package/docs/components/README.md +708 -0
- package/docs/components/product-grid.md +182 -0
- package/docs/components/product-rail.md +174 -0
- package/examples/shop/README.md +72 -0
- package/examples/shop/package.json +28 -0
- package/examples/shop/src/category.html +20 -0
- package/examples/shop/src/checkout.html +21 -0
- package/examples/shop/src/forretningsbetingelser.html +81 -0
- package/examples/shop/src/includes/body-end.html +1 -0
- package/examples/shop/src/includes/body-start.html +3 -0
- package/examples/shop/src/includes/head.html +32 -0
- package/examples/shop/src/index.html +25 -0
- package/examples/shop/src/navigation.ts +154 -0
- package/examples/shop/src/product.html +24 -0
- package/examples/shop/src/templates/page-layouts.html +162 -0
- package/examples/shop/src/templates/shop-footer.html +76 -0
- package/examples/shop/tsconfig.json +32 -0
- package/examples/shop/vite.config.mjs +190 -0
- package/html-custom-data.json +279 -0
- package/package.json +118 -0
- package/server/README.md +111 -0
- package/server/apache/.htaccess +18 -0
- package/server/nginx/orderly-products.conf +24 -0
- package/server/node/product-snapshot-server.mjs +133 -0
- package/server/php/orderly-product.php +204 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# `orderly-product-grid`
|
|
2
|
+
|
|
3
|
+
`orderly-product-grid` owns product search state. It accepts a `SearchQuery`, calls `SearchService.Search`, renders products, supports sorting, and uses continuation tokens for manual or automatic paging.
|
|
4
|
+
|
|
5
|
+
`orderly-product-rail` and `orderly-collection-page` delegate product fetching to this component.
|
|
6
|
+
|
|
7
|
+
## Basic Markup
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<orderly-product-grid
|
|
11
|
+
base-url="https://service.orderly.shop"
|
|
12
|
+
paging="dynamic"
|
|
13
|
+
keywords="sneakers"
|
|
14
|
+
tags="sko,sport"
|
|
15
|
+
order-by="CreatedTime desc">
|
|
16
|
+
</orderly-product-grid>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Typed Query
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { create } from "@bufbuild/protobuf";
|
|
23
|
+
import { SearchQuerySchema } from "@orderlyshop/core-client";
|
|
24
|
+
|
|
25
|
+
grid.query = create(SearchQuerySchema, {
|
|
26
|
+
Query: "sneakers",
|
|
27
|
+
OrderBy: ["CreatedTime desc"]
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Default Query Scope
|
|
32
|
+
|
|
33
|
+
Use `defaultQuery` for shop-wide or component-local constraints:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
grid.defaultQuery = defaultQuery;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Global default query:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
configureShop({ defaultShop: { defaultQuery } });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The final request is:
|
|
46
|
+
|
|
47
|
+
1. Global default query.
|
|
48
|
+
2. Component `defaultQuery`, when supplied.
|
|
49
|
+
3. Grid `query` or declarative query markup.
|
|
50
|
+
4. Continuation token, when loading the next page.
|
|
51
|
+
|
|
52
|
+
## Attributes
|
|
53
|
+
|
|
54
|
+
- `base-url`: Backend URL used when no `client` property is assigned.
|
|
55
|
+
- `paging`: `button`, `manual`, `dynamic`, or `infinite`.
|
|
56
|
+
- `sort-label`: Sort control label.
|
|
57
|
+
- `clear-search-label`: Clear-search button label for custom context templates.
|
|
58
|
+
- `error-label`: Error text.
|
|
59
|
+
- `loading-label`: Loading text.
|
|
60
|
+
- `results-label`: Result count suffix for custom context templates.
|
|
61
|
+
- `searching-label`: Active query prefix for custom context templates.
|
|
62
|
+
- `keywords`: Maps to `SearchQuery.Query`.
|
|
63
|
+
- `tags`: Comma-separated values mapped to `SearchQuery.Tags`.
|
|
64
|
+
- `hidden-query`: Maps to `SearchQuery.HiddenQuery`.
|
|
65
|
+
- `order-by`: Comma-separated values mapped to `SearchQuery.OrderBy`.
|
|
66
|
+
- `store-id`: Maps to `SearchQuery.StoreId`.
|
|
67
|
+
- `featured`: Boolean mapped to `SearchQuery.Featured`.
|
|
68
|
+
|
|
69
|
+
## Properties
|
|
70
|
+
|
|
71
|
+
- `client: OrderlyClient | undefined`: Explicit client instance.
|
|
72
|
+
- `query: SearchQuery | undefined`: Explicit search query. Takes precedence over declarative query markup.
|
|
73
|
+
- `defaultQuery: SearchQuery | undefined`: Component-level default query.
|
|
74
|
+
- `shopQuery: SearchQuery | undefined`: Backward-compatible alias for `defaultQuery`.
|
|
75
|
+
- `sortOptions: SortOption[]`: Sort options rendered by the grid.
|
|
76
|
+
- `basketController: BasketController | undefined`: Shared basket state.
|
|
77
|
+
- `paging: "manual" | "button" | "infinite" | "dynamic"`: Paging behavior.
|
|
78
|
+
- `products: SearchObject[]`: Current products.
|
|
79
|
+
- `continuationToken: ContinuationToken | undefined`: Current continuation token.
|
|
80
|
+
- `hasMore: boolean`: Whether more results can be loaded.
|
|
81
|
+
- `state: ProductGridState`: Loading/error/result snapshot.
|
|
82
|
+
- `productTileTagName: string`: Product tile tag name for custom prefixes.
|
|
83
|
+
|
|
84
|
+
## Methods
|
|
85
|
+
|
|
86
|
+
- `refresh(): Promise<void>`: Clears current products and loads the first page.
|
|
87
|
+
- `loadNextPage(): Promise<void>`: Loads the next page when a continuation token is available.
|
|
88
|
+
- `setSort(orderBy: string[]): Promise<void>`: Applies sort and refreshes.
|
|
89
|
+
- `clearSearch(): Promise<void>`: Clears `SearchQuery.Query` and refreshes. The default layout does not render a clear-search button; custom context templates can call this with `data-orderly-action="clear-search"`.
|
|
90
|
+
|
|
91
|
+
## Paging
|
|
92
|
+
|
|
93
|
+
- `paging="dynamic"` and `paging="infinite"` use an intersection observer sentinel and do not render a load-more button.
|
|
94
|
+
- `paging="button"` renders a load-more control when a continuation token exists.
|
|
95
|
+
- `paging="manual"` never renders a button; call `loadNextPage()` yourself.
|
|
96
|
+
|
|
97
|
+
## Sort Options
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
grid.sortOptions = [
|
|
101
|
+
{ label: "Nyeste", orderBy: ["CreatedTime desc"] },
|
|
102
|
+
{ label: "Pris: lav til høj", orderBy: ["Price asc"] },
|
|
103
|
+
{ label: "Pris: høj til lav", orderBy: ["Price desc"] }
|
|
104
|
+
];
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Templates
|
|
108
|
+
|
|
109
|
+
### `layout`
|
|
110
|
+
|
|
111
|
+
Replaces the grid structure. Include:
|
|
112
|
+
|
|
113
|
+
- `data-orderly-slot="context"`
|
|
114
|
+
- `data-orderly-slot="sort"`
|
|
115
|
+
- `data-orderly-bind="status"`
|
|
116
|
+
- `data-orderly-slot="items"`
|
|
117
|
+
- `data-orderly-action="load-more"` if button paging is used.
|
|
118
|
+
- `data-orderly-sentinel` if dynamic paging is used.
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<template data-orderly-template="layout">
|
|
122
|
+
<section class="catalog">
|
|
123
|
+
<div data-orderly-slot="context"></div>
|
|
124
|
+
<div data-orderly-slot="sort"></div>
|
|
125
|
+
<p data-orderly-bind="status"></p>
|
|
126
|
+
<ol data-orderly-slot="items"></ol>
|
|
127
|
+
<button type="button" data-orderly-action="load-more">Flere varer</button>
|
|
128
|
+
<span data-orderly-sentinel></span>
|
|
129
|
+
</section>
|
|
130
|
+
</template>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### `product`
|
|
134
|
+
|
|
135
|
+
Replaces each product item. The grid binds the `SearchObject` into an inner `orderly-product-tile` when present.
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<template data-orderly-template="product">
|
|
139
|
+
<li class="catalog-item">
|
|
140
|
+
<orderly-product-tile></orderly-product-tile>
|
|
141
|
+
</li>
|
|
142
|
+
</template>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Other Templates
|
|
146
|
+
|
|
147
|
+
- `context`
|
|
148
|
+
- `sort`
|
|
149
|
+
- `loading`
|
|
150
|
+
- `empty`
|
|
151
|
+
|
|
152
|
+
## Events
|
|
153
|
+
|
|
154
|
+
- `orderly-results`: Fired after successful search. Detail is `ProductGridState`.
|
|
155
|
+
- `orderly-error`: Fired when search fails.
|
|
156
|
+
- Product tile events bubble through the grid:
|
|
157
|
+
- `orderly-product-selected`
|
|
158
|
+
- `orderly-add-to-basket`
|
|
159
|
+
- `orderly-remove-from-basket`
|
|
160
|
+
|
|
161
|
+
## Styling
|
|
162
|
+
|
|
163
|
+
Default class names:
|
|
164
|
+
|
|
165
|
+
- `orderly-product-grid`
|
|
166
|
+
- `orderly-product-grid__toolbar`
|
|
167
|
+
- `orderly-product-grid__context`
|
|
168
|
+
- `orderly-product-grid__sort`
|
|
169
|
+
- `orderly-product-grid__status`
|
|
170
|
+
- `orderly-product-grid__items`
|
|
171
|
+
- `orderly-product-grid__item`
|
|
172
|
+
- `orderly-product-grid__load-more`
|
|
173
|
+
- `orderly-product-grid__sentinel`
|
|
174
|
+
- `orderly-product-grid__loading-item`
|
|
175
|
+
|
|
176
|
+
Useful CSS variables:
|
|
177
|
+
|
|
178
|
+
- `--orderly-product-grid-gap`
|
|
179
|
+
- `--orderly-product-grid-item-min-width`
|
|
180
|
+
- `--orderly-product-grid-item-max-width`
|
|
181
|
+
|
|
182
|
+
The default grid uses responsive full-width `auto-fit` tracks, spaces cards with `--orderly-product-grid-gap`, and caps product tiles at `--orderly-product-grid-item-max-width` inside each column, so desktop layouts keep using the full row width without stretching each tile indefinitely. Host applications can override the variables, style the default classes directly, or replace templates entirely.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# `orderly-product-rail`
|
|
2
|
+
|
|
3
|
+
`orderly-product-rail` renders a `SearchQuery` as a horizontal product list with a heading and optional CTA link. It composes `orderly-product-grid`, so search execution, product rendering, loading state, basket wiring, and default query merging follow the same behavior as the grid.
|
|
4
|
+
|
|
5
|
+
Use it for homepage rows, category highlights, editorial collections, and "more like this" rails.
|
|
6
|
+
|
|
7
|
+
## Basic Markup
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<orderly-product-rail
|
|
11
|
+
title="Sko"
|
|
12
|
+
cta-label="Se alle"
|
|
13
|
+
cta-href="/categories/?category=sko"
|
|
14
|
+
keywords="H&M"
|
|
15
|
+
tags="børnetøj,bluser"
|
|
16
|
+
order-by="CreatedTime desc">
|
|
17
|
+
</orderly-product-rail>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Child Query Markup
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<orderly-product-rail
|
|
24
|
+
title="Sko"
|
|
25
|
+
cta-label="Se alle"
|
|
26
|
+
cta-href="/categories/?category=sko">
|
|
27
|
+
<query>
|
|
28
|
+
<tags>børnetøj,bluser</tags>
|
|
29
|
+
<keywords>H&M</keywords>
|
|
30
|
+
<order-by>CreatedTime desc</order-by>
|
|
31
|
+
</query>
|
|
32
|
+
</orderly-product-rail>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The child `<query>` element is hidden by the component and is only used as configuration.
|
|
36
|
+
|
|
37
|
+
## Typed Query
|
|
38
|
+
|
|
39
|
+
Use the typed `query` property for the full Core contract:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { create } from "@bufbuild/protobuf";
|
|
43
|
+
import { SearchQuerySchema, TagSchema } from "@orderlyshop/core-client";
|
|
44
|
+
|
|
45
|
+
productRail.query = create(SearchQuerySchema, {
|
|
46
|
+
Query: "H&M",
|
|
47
|
+
Tags: [
|
|
48
|
+
create(TagSchema, { Value: "børnetøj" }),
|
|
49
|
+
create(TagSchema, { Value: "bluser" })
|
|
50
|
+
],
|
|
51
|
+
OrderBy: ["CreatedTime desc"]
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Default Query Scope
|
|
56
|
+
|
|
57
|
+
`defaultQuery` is merged with the rail query before the backend search call. This is useful for tenant scope, published-only filters, store scope, or other shop-wide constraints.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
productRail.defaultQuery = defaultQuery;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Global default query:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
configureShop({ defaultShop: { defaultQuery } });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
When both are present, the per-rail `defaultQuery` is merged with the global default query and then the rail's own query is applied.
|
|
70
|
+
|
|
71
|
+
## Attributes
|
|
72
|
+
|
|
73
|
+
- `base-url`: Backend URL used when no `client` property is assigned.
|
|
74
|
+
- `title`: Heading text.
|
|
75
|
+
- `cta-label`: CTA link label. Hidden when empty.
|
|
76
|
+
- `cta-href`: CTA link URL.
|
|
77
|
+
- `empty-label`: Empty result copy.
|
|
78
|
+
- `loading-label`: Loading copy forwarded to the internal grid.
|
|
79
|
+
- `error-label`: Error copy forwarded to the internal grid.
|
|
80
|
+
- `keywords`: Maps to `SearchQuery.Query`.
|
|
81
|
+
- `tags`: Comma-separated values mapped to `SearchQuery.Tags`.
|
|
82
|
+
- `hidden-query`: Maps to `SearchQuery.HiddenQuery`.
|
|
83
|
+
- `order-by`: Comma-separated values mapped to `SearchQuery.OrderBy`.
|
|
84
|
+
- `store-id`: Maps to `SearchQuery.StoreId`.
|
|
85
|
+
- `featured`: Boolean mapped to `SearchQuery.Featured`.
|
|
86
|
+
|
|
87
|
+
## Properties
|
|
88
|
+
|
|
89
|
+
- `client: OrderlyClient | undefined`: Explicit client instance.
|
|
90
|
+
- `query: SearchQuery | undefined`: Explicit search query. Takes precedence over declarative query markup.
|
|
91
|
+
- `defaultQuery: SearchQuery | undefined`: Per-rail default query merged before `query`.
|
|
92
|
+
- `shopQuery: SearchQuery | undefined`: Backward-compatible alias for `defaultQuery`.
|
|
93
|
+
- `basketController: BasketController | undefined`: Shared basket state.
|
|
94
|
+
|
|
95
|
+
## Templates
|
|
96
|
+
|
|
97
|
+
### `layout`
|
|
98
|
+
|
|
99
|
+
Replaces the outer rail structure. Include a `data-orderly-slot="grid"` target.
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<template data-orderly-template="layout">
|
|
103
|
+
<section class="my-rail">
|
|
104
|
+
<header>
|
|
105
|
+
<h2 data-orderly-bind="title"></h2>
|
|
106
|
+
<a data-orderly-bind="ctaHref">
|
|
107
|
+
<span data-orderly-bind="ctaLabel"></span>
|
|
108
|
+
</a>
|
|
109
|
+
</header>
|
|
110
|
+
<div data-orderly-slot="grid"></div>
|
|
111
|
+
</section>
|
|
112
|
+
</template>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `grid`
|
|
116
|
+
|
|
117
|
+
Replaces the internal grid layout. Include:
|
|
118
|
+
|
|
119
|
+
- `data-orderly-bind="status"` for loading/error text.
|
|
120
|
+
- `data-orderly-slot="items"` for product items.
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<template data-orderly-template="grid">
|
|
124
|
+
<section class="my-horizontal-list">
|
|
125
|
+
<p data-orderly-bind="status"></p>
|
|
126
|
+
<div data-orderly-slot="items"></div>
|
|
127
|
+
</section>
|
|
128
|
+
</template>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Product State Templates
|
|
132
|
+
|
|
133
|
+
These are forwarded to the internal `orderly-product-grid`:
|
|
134
|
+
|
|
135
|
+
- `product`
|
|
136
|
+
- `loading`
|
|
137
|
+
- `empty`
|
|
138
|
+
|
|
139
|
+
## Events
|
|
140
|
+
|
|
141
|
+
Product events bubble from child product tiles:
|
|
142
|
+
|
|
143
|
+
- `orderly-product-selected`
|
|
144
|
+
- `orderly-add-to-basket`
|
|
145
|
+
- `orderly-remove-from-basket`
|
|
146
|
+
- `orderly-results`
|
|
147
|
+
- `orderly-error`
|
|
148
|
+
|
|
149
|
+
## Styling
|
|
150
|
+
|
|
151
|
+
The default rail uses light DOM and stable class names:
|
|
152
|
+
|
|
153
|
+
- `orderly-product-rail`
|
|
154
|
+
- `orderly-product-rail__header`
|
|
155
|
+
- `orderly-product-rail__title`
|
|
156
|
+
- `orderly-product-rail__cta`
|
|
157
|
+
- `orderly-product-rail__items`
|
|
158
|
+
- `orderly-product-rail__status`
|
|
159
|
+
- `orderly-product-rail__empty`
|
|
160
|
+
|
|
161
|
+
CSS custom properties:
|
|
162
|
+
|
|
163
|
+
- `--orderly-product-rail-item-width`
|
|
164
|
+
- `--orderly-product-rail-gap`
|
|
165
|
+
- `--orderly-product-rail-padding`
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
|
|
169
|
+
```css
|
|
170
|
+
orderly-product-rail {
|
|
171
|
+
--orderly-product-rail-item-width: minmax(220px, 260px);
|
|
172
|
+
--orderly-product-rail-gap: 18px;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Orderly Example Shop
|
|
2
|
+
|
|
3
|
+
This is a private vanilla HTML storefront with strongly typed TypeScript navigation data. It demonstrates how to configure the default shop provided by `@orderlyshop/web-components`.
|
|
4
|
+
|
|
5
|
+
It is included as source code in the `@orderlyshop/web-components` npm package under `examples/shop` so developers and coding agents can inspect how to override navigation and content without rebuilding the default page wiring. The example uses shared global `layout` templates to move the built-in navigation into `primary-nav` and render it in horizontal mode.
|
|
6
|
+
|
|
7
|
+
## Run
|
|
8
|
+
|
|
9
|
+
From the npm workspace root:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm run dev --workspace @orderlyshop/example-shop
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Build the static app with generated and hydrated category pages:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm run build --workspace @orderlyshop/example-shop
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Generate real category URL pages from `src/navigation.ts`:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm run generate:categories --workspace @orderlyshop/example-shop
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That creates simple generated source pages such as `src/categories/toej-og-mode/dame/index.html`. Each page only wraps the reusable `orderly-category-page` element and builds to `dist/categories/...`:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<orderly-category-page slug="toej-og-mode/dame"></orderly-category-page>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Run the explicit category-page build directly:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm run build:category-pages --workspace @orderlyshop/example-shop
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The default build and the explicit category-page build both hydrate `dist/index.html` and the generated `dist/categories/**/index.html` files with initial category/home markup. The hydration step reads `VITE_ORDERLY_BASE_URL` and otherwise uses the default `https://service.orderly.shop` backend for product snapshots.
|
|
40
|
+
|
|
41
|
+
Clean generated category pages:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npm run clean:categories --workspace @orderlyshop/example-shop
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
These scripts call the generic CLI tools installed by `@orderlyshop/web-components`: `orderly-generate-category-pages`, `orderly-build-category-pages`, and `orderly-hydrate-static-pages`. The example shop does not own category generation or hydration logic.
|
|
48
|
+
|
|
49
|
+
The default backend is `https://service.orderly.shop`. Override it for local development:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
VITE_ORDERLY_BASE_URL=https://your-service.example npm run dev --workspace @orderlyshop/example-shop
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Stored images use the default image base URL from `@orderlyshop/web-components`. Override it only when the shop needs a different image CDN:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
VITE_ORDERLY_IMAGE_BASE_URL=https://images.example/ npm run dev --workspace @orderlyshop/example-shop
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Structure
|
|
62
|
+
|
|
63
|
+
- `src/index.html` is a standalone homepage that uses `orderly-home-page` to render one horizontal product rail for every top-level category.
|
|
64
|
+
- `src/category.html` is the reusable category page template. Production builds generate real pages under `dist/categories/**/index.html`, and dev mode serves `/categories/.../` through the same template.
|
|
65
|
+
- `src/product.html` wraps `orderly-product-detail-page` and resolves products from `#url=<encoded-share-url>`.
|
|
66
|
+
- `src/checkout.html` wraps the reusable `orderly-checkout-page` element and only adds example utility-strip content.
|
|
67
|
+
- `src/forretningsbetingelser.html` is a static terms page linked from checkout through `checkoutTermsHref`.
|
|
68
|
+
- `src/navigation.ts` owns strongly typed recursive `NavigationDefinition` data with stable slugs, hero images, and plain `SearchQueryInput` objects.
|
|
69
|
+
- `src/includes/head.html` imports `@orderlyshop/web-components`, registers the elements, and configures backend, navigation, checkout links, responsive settings, and image URLs.
|
|
70
|
+
- `src/includes/body-start.html` is the shared body-start include for snippets such as analytics fallbacks and imports the shared global page-layout templates plus the shop-specific footer template.
|
|
71
|
+
- `src/templates/page-layouts.html` owns the shared global `layout` overrides for the built-in page components so the example shop uses horizontal primary navigation across home, category, product, and checkout pages.
|
|
72
|
+
- `src/templates/shop-footer.html` owns the declarative footer content while still using the package footer component and default footer classes.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@orderlyshop/example-shop",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Example storefront built with Orderly web components.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite",
|
|
9
|
+
"generate:categories": "node ../../bin/orderly-generate-category-pages.mjs --template src/category.html --categories-dir src/categories --site-title \"Orderly Example Shop\"",
|
|
10
|
+
"clean:categories": "node ../../bin/orderly-generate-category-pages.mjs --template src/category.html --categories-dir src/categories --clean",
|
|
11
|
+
"build:category-pages": "node ../../bin/orderly-build-category-pages.mjs --template src/category.html --categories-dir src/categories --site-title \"Orderly Example Shop\" --build-command \"npm run typecheck && vite build\"",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"build": "node ../../bin/orderly-build-category-pages.mjs --template src/category.html --categories-dir src/categories --site-title \"Orderly Example Shop\" --build-command \"npm run typecheck && vite build\"",
|
|
14
|
+
"preview": "vite preview",
|
|
15
|
+
"test": "vitest run --passWithNoTests"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@bufbuild/protobuf": "^2.11.0",
|
|
19
|
+
"@orderlyshop/core-client": "^0.1.0",
|
|
20
|
+
"@orderlyshop/web-components": "^0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^24.12.2",
|
|
24
|
+
"typescript": "^5.9.3",
|
|
25
|
+
"vite": "^7.3.2",
|
|
26
|
+
"vitest": "^3.2.4"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="da">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Kategori | Orderly Example Shop</title>
|
|
7
|
+
<!-- orderly-head-includes -->
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- orderly-body-start-includes -->
|
|
11
|
+
<orderly-category-page>
|
|
12
|
+
<div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
|
|
13
|
+
<span>Gratis levering over 499 kr.</span>
|
|
14
|
+
<span>30 dages returret</span>
|
|
15
|
+
<span>Sikker betaling</span>
|
|
16
|
+
</div>
|
|
17
|
+
</orderly-category-page>
|
|
18
|
+
<!-- orderly-body-end-includes -->
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="da">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Betaling | Orderly Example Shop</title>
|
|
7
|
+
<!-- orderly-head-includes -->
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- orderly-body-start-includes -->
|
|
11
|
+
<orderly-checkout-page>
|
|
12
|
+
<div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
|
|
13
|
+
<span>Gratis levering over 499 kr.</span>
|
|
14
|
+
<span>30 dages returret</span>
|
|
15
|
+
<span>Sikker betaling</span>
|
|
16
|
+
</div>
|
|
17
|
+
</orderly-checkout-page>
|
|
18
|
+
|
|
19
|
+
<!-- orderly-body-end-includes -->
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="da">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Forretningsbetingelser | Orderly Example Shop</title>
|
|
7
|
+
<!-- orderly-head-includes -->
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- orderly-body-start-includes -->
|
|
11
|
+
<orderly-page-layout>
|
|
12
|
+
<div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
|
|
13
|
+
<span>Gratis levering over 499 kr.</span>
|
|
14
|
+
<span>30 dages returret</span>
|
|
15
|
+
<span>Sikker betaling</span>
|
|
16
|
+
</div>
|
|
17
|
+
<a slot="header" class="orderly-checkout-page__brand" href="/">
|
|
18
|
+
<span>Orderly Example Shop</span>
|
|
19
|
+
</a>
|
|
20
|
+
<orderly-navigation slot="primary-nav" layout="horizontal" aria-label="Hovednavigation"></orderly-navigation>
|
|
21
|
+
<section slot="content" class="orderly-content-page">
|
|
22
|
+
<header class="orderly-content-page__header">
|
|
23
|
+
<h1>Forretningsbetingelser</h1>
|
|
24
|
+
<p>Her finder du betingelser for køb, levering, betaling, retur og reklamation.</p>
|
|
25
|
+
</header>
|
|
26
|
+
<article class="orderly-content-page__card orderly-content-page__body" aria-labelledby="termsTitle">
|
|
27
|
+
<h2 id="termsTitle">Køb hos Orderly Example Shop</h2>
|
|
28
|
+
<p>
|
|
29
|
+
Disse forretningsbetingelser gælder for køb foretaget i Orderly Example Shop. Teksten er eksempelindhold og skal tilpasses den konkrete butik, før den bruges juridisk.
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
<h2>Virksomhedsoplysninger</h2>
|
|
33
|
+
<p>
|
|
34
|
+
Orderly Example Shop ApS<br>
|
|
35
|
+
Demo Allé 12<br>
|
|
36
|
+
8000 Aarhus C<br>
|
|
37
|
+
Danmark<br>
|
|
38
|
+
Email: hello@example.orderly.shop
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<h2>Bestilling</h2>
|
|
42
|
+
<p>
|
|
43
|
+
Når du gennemfører en ordre, modtager du en ordrebekræftelse på den emailadresse, du har angivet. Aftalen er indgået, når ordren er bekræftet.
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<h2>Priser og betaling</h2>
|
|
47
|
+
<p>
|
|
48
|
+
Alle priser vises i danske kroner inklusive moms. Betaling gennemføres med de betalingsmetoder, der vises i checkout.
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<h2>Levering</h2>
|
|
52
|
+
<p>
|
|
53
|
+
Leveringspris og tilgængelige leveringsmetoder beregnes ud fra kurvens indhold og den leveringsadresse, du indtaster i checkout. Hvis du vælger pakkeshop, skal du vælge et udleveringssted, før ordren gennemføres.
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<h2>Fortrydelsesret og retur</h2>
|
|
57
|
+
<p>
|
|
58
|
+
Du har 30 dages returret fra den dag, du modtager varen. Varen skal returneres i væsentligt samme stand, som den blev modtaget.
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+
<h2>Reklamation</h2>
|
|
62
|
+
<p>
|
|
63
|
+
Købelovens reklamationsregler gælder. Kontakt kundeservice hurtigst muligt, hvis en vare har fejl eller mangler.
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
<h2>Persondata</h2>
|
|
67
|
+
<p>
|
|
68
|
+
Vi behandler de oplysninger, der er nødvendige for at gennemføre din ordre, levere varen og håndtere kundeservice. Oplysninger deles kun med relevante betalings- og leveringspartnere.
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
<h2>Kontakt</h2>
|
|
72
|
+
<p>
|
|
73
|
+
Har du spørgsmål til din ordre eller disse betingelser, kan du kontakte os på hello@example.orderly.shop.
|
|
74
|
+
</p>
|
|
75
|
+
</article>
|
|
76
|
+
</section>
|
|
77
|
+
<orderly-shop-footer slot="footer"></orderly-shop-footer>
|
|
78
|
+
</orderly-page-layout>
|
|
79
|
+
<!-- orderly-body-end-includes -->
|
|
80
|
+
</body>
|
|
81
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- Add shared body-end snippets here, for example storefront-wide scripts. -->
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- Add shared head snippets here, for example analytics, consent, or preconnect tags. -->
|
|
2
|
+
<link rel="icon" href="https://orderly.shop/home/App_Icon.svg" type="image/svg+xml">
|
|
3
|
+
<script type="module">
|
|
4
|
+
import { configureShop } from "@orderlyshop/web-components";
|
|
5
|
+
import { navigationDefinitions } from "/src/navigation.ts";
|
|
6
|
+
|
|
7
|
+
const configuredCategoryUrlMode =
|
|
8
|
+
globalThis.ORDERLY_CATEGORY_URL_MODE === "path" || globalThis.ORDERLY_CATEGORY_URL_MODE === "hash"
|
|
9
|
+
? globalThis.ORDERLY_CATEGORY_URL_MODE
|
|
10
|
+
: import.meta.env.VITE_ORDERLY_CATEGORY_URL_MODE === "path" || import.meta.env.VITE_ORDERLY_CATEGORY_URL_MODE === "hash"
|
|
11
|
+
? import.meta.env.VITE_ORDERLY_CATEGORY_URL_MODE
|
|
12
|
+
: undefined;
|
|
13
|
+
const categoryUrlMode = configuredCategoryUrlMode ?? "path";
|
|
14
|
+
|
|
15
|
+
configureShop({
|
|
16
|
+
uiLanguage: "DA",
|
|
17
|
+
defaultShop: {
|
|
18
|
+
brandLabel: "Orderly Example Shop",
|
|
19
|
+
homeHref: "/",
|
|
20
|
+
productHref: "/product.html",
|
|
21
|
+
checkoutHref: "/checkout.html",
|
|
22
|
+
checkoutTermsHref: "/forretningsbetingelser.html",
|
|
23
|
+
navigationDefinitions,
|
|
24
|
+
categoryPageRoot: categoryUrlMode === "hash" ? "/category.html" : "/categories/",
|
|
25
|
+
categoryUrlMode
|
|
26
|
+
},
|
|
27
|
+
pageLayout: {
|
|
28
|
+
logoSrc: "https://orderly.shop/home/App_Icon.svg",
|
|
29
|
+
logoAlt: "Orderly Example Shop",
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="da">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Orderly Example Shop</title>
|
|
7
|
+
<!-- orderly-head-includes -->
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- orderly-body-start-includes -->
|
|
11
|
+
<orderly-home-page
|
|
12
|
+
eyebrow="Nye fund i alle afdelinger"
|
|
13
|
+
title="Find næste favorit"
|
|
14
|
+
rail-cta-label="Se alle"
|
|
15
|
+
empty-label="Der blev ikke fundet varer."
|
|
16
|
+
checkout-label="Gå til betaling">
|
|
17
|
+
<div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
|
|
18
|
+
<span>Gratis levering over 499 kr.</span>
|
|
19
|
+
<span>30 dages returret</span>
|
|
20
|
+
<span>Sikker betaling</span>
|
|
21
|
+
</div>
|
|
22
|
+
</orderly-home-page>
|
|
23
|
+
<!-- orderly-body-end-includes -->
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|