@design.estate/dees-catalog 9.3.0 → 9.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +1372 -2727
- package/dist_bundle/bundle.js.map +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.js +2 -1
- package/dist_ts_web/elements/00group-input/dees-input-quantityselector/dees-input-quantityselector.js +4 -2
- package/dist_ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.d.ts +11 -9
- package/dist_ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.d.ts +2 -2
- package/dist_ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.js +148 -319
- package/dist_ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.js +60 -279
- package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.d.ts +25 -10
- package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.d.ts +3 -4
- package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.js +229 -388
- package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.js +253 -813
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.demo.d.ts +2 -0
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.demo.js +150 -389
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.js +67 -11
- package/package.json +1 -1
- package/readme.hints.md +26 -0
- package/readme.md +76 -15
- package/scripts/bdtheme-baseline.json +0 -2
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-button/dees-button/dees-button.ts +1 -0
- package/ts_web/elements/00group-input/dees-input-quantityselector/dees-input-quantityselector.ts +3 -1
- package/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.ts +67 -332
- package/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.ts +65 -322
- package/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.ts +136 -382
- package/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts +224 -872
- package/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.demo.ts +116 -421
- package/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts +66 -10
package/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.ts
CHANGED
|
@@ -1,332 +1,67 @@
|
|
|
1
|
-
import { html, css, cssManager } from '@design.estate/dees-element';
|
|
2
|
-
import '
|
|
3
|
-
import '
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.selected-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
`}
|
|
69
|
-
</style>
|
|
70
|
-
|
|
71
|
-
<div class="demo-container">
|
|
72
|
-
<dees-panel .title=${'Basic Product Cards'} .subtitle=${'Simple product display with various configurations'}>
|
|
73
|
-
<div class="product-grid">
|
|
74
|
-
<dees-shopping-productcard
|
|
75
|
-
.productData=${{
|
|
76
|
-
name: 'Wireless Bluetooth Headphones',
|
|
77
|
-
category: 'Audio',
|
|
78
|
-
description: 'Premium sound quality with active noise cancellation',
|
|
79
|
-
price: 149.99,
|
|
80
|
-
originalPrice: 199.99,
|
|
81
|
-
iconName: 'lucide:headphones'
|
|
82
|
-
}}
|
|
83
|
-
.quantity=${1}
|
|
84
|
-
></dees-shopping-productcard>
|
|
85
|
-
|
|
86
|
-
<dees-shopping-productcard
|
|
87
|
-
.productData=${{
|
|
88
|
-
name: 'Smart Watch Series 7',
|
|
89
|
-
category: 'Wearables',
|
|
90
|
-
description: 'Track your fitness and stay connected on the go',
|
|
91
|
-
price: 399.00,
|
|
92
|
-
iconName: 'lucide:watch'
|
|
93
|
-
}}
|
|
94
|
-
.quantity=${1}
|
|
95
|
-
></dees-shopping-productcard>
|
|
96
|
-
|
|
97
|
-
<dees-shopping-productcard
|
|
98
|
-
.productData=${{
|
|
99
|
-
name: 'USB-C Hub',
|
|
100
|
-
category: 'Accessories',
|
|
101
|
-
price: 49.99,
|
|
102
|
-
iconName: 'lucide:usb',
|
|
103
|
-
inStock: false
|
|
104
|
-
}}
|
|
105
|
-
.quantity=${0}
|
|
106
|
-
></dees-shopping-productcard>
|
|
107
|
-
</div>
|
|
108
|
-
</dees-panel>
|
|
109
|
-
|
|
110
|
-
<dees-panel .title=${'Interactive Shopping Cart'} .subtitle=${'Product cards with dynamic cart calculation'} .runAfterRender=${async (elementArg: HTMLElement) => {
|
|
111
|
-
const products = [
|
|
112
|
-
{ id: 'laptop', element: null as DeesShoppingProductcard | null, data: { name: 'MacBook Pro 14"', category: 'Computers', description: 'M3 Pro chip with 18GB RAM', price: 1999, originalPrice: 2199, iconName: 'lucide:laptop' }},
|
|
113
|
-
{ id: 'tablet', element: null as DeesShoppingProductcard | null, data: { name: 'Tablet Air', category: 'Tablets', description: '10.9" high-resolution display', price: 599, iconName: 'lucide:tablet' }},
|
|
114
|
-
{ id: 'keyboard', element: null as DeesShoppingProductcard | null, data: { name: 'Magic Keyboard', category: 'Accessories', description: 'Wireless keyboard with Touch ID', price: 149, iconName: 'lucide:keyboard' }}
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
const updateCartSummary = () => {
|
|
118
|
-
let total = 0;
|
|
119
|
-
const items: string[] = [];
|
|
120
|
-
|
|
121
|
-
products.forEach(product => {
|
|
122
|
-
const element = elementArg.querySelector(`#${product.id}`) as DeesShoppingProductcard;
|
|
123
|
-
if (element && element.quantity > 0) {
|
|
124
|
-
const subtotal = product.data.price * element.quantity;
|
|
125
|
-
total += subtotal;
|
|
126
|
-
items.push(`
|
|
127
|
-
<div class="cart-item">
|
|
128
|
-
<span>${product.data.name} (${element.quantity})</span>
|
|
129
|
-
<span>$${subtotal.toFixed(2)}</span>
|
|
130
|
-
</div>
|
|
131
|
-
`);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const summary = elementArg.querySelector('#interactive-cart-summary');
|
|
136
|
-
if (summary) {
|
|
137
|
-
summary.innerHTML = `
|
|
138
|
-
${items.join('')}
|
|
139
|
-
${items.length === 0 ? '<div class="cart-item" style="text-align: center; color: #999;">Your cart is empty</div>' : ''}
|
|
140
|
-
<div class="cart-total">
|
|
141
|
-
<span>Total</span>
|
|
142
|
-
<span>$${total.toFixed(2)}</span>
|
|
143
|
-
</div>
|
|
144
|
-
`;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// Initial update
|
|
149
|
-
setTimeout(updateCartSummary, 100);
|
|
150
|
-
|
|
151
|
-
// Set up listeners
|
|
152
|
-
elementArg.querySelectorAll('dees-shopping-productcard').forEach(card => {
|
|
153
|
-
card.addEventListener('quantityChange', updateCartSummary);
|
|
154
|
-
});
|
|
155
|
-
}}>
|
|
156
|
-
<div class="product-grid">
|
|
157
|
-
<dees-shopping-productcard
|
|
158
|
-
id="laptop"
|
|
159
|
-
.productData=${{
|
|
160
|
-
name: 'MacBook Pro 14"',
|
|
161
|
-
category: 'Computers',
|
|
162
|
-
description: 'M3 Pro chip with 18GB RAM',
|
|
163
|
-
price: 1999,
|
|
164
|
-
originalPrice: 2199,
|
|
165
|
-
iconName: 'lucide:laptop'
|
|
166
|
-
}}
|
|
167
|
-
.quantity=${1}
|
|
168
|
-
></dees-shopping-productcard>
|
|
169
|
-
|
|
170
|
-
<dees-shopping-productcard
|
|
171
|
-
id="tablet"
|
|
172
|
-
.productData=${{
|
|
173
|
-
name: 'Tablet Air',
|
|
174
|
-
category: 'Tablets',
|
|
175
|
-
description: '10.9" high-resolution display',
|
|
176
|
-
price: 599,
|
|
177
|
-
iconName: 'lucide:tablet'
|
|
178
|
-
}}
|
|
179
|
-
.quantity=${0}
|
|
180
|
-
></dees-shopping-productcard>
|
|
181
|
-
|
|
182
|
-
<dees-shopping-productcard
|
|
183
|
-
id="keyboard"
|
|
184
|
-
.productData=${{
|
|
185
|
-
name: 'Magic Keyboard',
|
|
186
|
-
category: 'Accessories',
|
|
187
|
-
description: 'Wireless keyboard with Touch ID',
|
|
188
|
-
price: 149,
|
|
189
|
-
iconName: 'lucide:keyboard'
|
|
190
|
-
}}
|
|
191
|
-
.quantity=${2}
|
|
192
|
-
></dees-shopping-productcard>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div class="cart-summary">
|
|
196
|
-
<h3 class="cart-summary-title">Shopping Cart</h3>
|
|
197
|
-
<div id="interactive-cart-summary">
|
|
198
|
-
<!-- Dynamically updated -->
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
</dees-panel>
|
|
202
|
-
|
|
203
|
-
<dees-panel .title=${'Selectable Product Cards'} .subtitle=${'Click cards or checkboxes to select products'}>
|
|
204
|
-
<div class="product-grid">
|
|
205
|
-
<dees-shopping-productcard
|
|
206
|
-
.productData=${{
|
|
207
|
-
name: 'Sony Alpha 7 IV',
|
|
208
|
-
category: 'Cameras',
|
|
209
|
-
description: 'Full-frame mirrorless camera',
|
|
210
|
-
price: 2498,
|
|
211
|
-
iconName: 'lucide:camera'
|
|
212
|
-
}}
|
|
213
|
-
.selectable=${true}
|
|
214
|
-
.showQuantitySelector=${false}
|
|
215
|
-
@selectionChange=${(e: CustomEvent) => {
|
|
216
|
-
const output = document.querySelector('#selection-output');
|
|
217
|
-
if (output) {
|
|
218
|
-
const selectedCards = document.querySelectorAll('dees-shopping-productcard[selectable]');
|
|
219
|
-
const selectedProducts: string[] = [];
|
|
220
|
-
(selectedCards as NodeListOf<DeesShoppingProductcard>).forEach((card) => {
|
|
221
|
-
if (card.selected) {
|
|
222
|
-
selectedProducts.push(card.productData.name);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
output.textContent = selectedProducts.length > 0
|
|
226
|
-
? `Selected: ${selectedProducts.join(', ')}`
|
|
227
|
-
: 'No products selected';
|
|
228
|
-
}
|
|
229
|
-
}}
|
|
230
|
-
></dees-shopping-productcard>
|
|
231
|
-
|
|
232
|
-
<dees-shopping-productcard
|
|
233
|
-
.productData=${{
|
|
234
|
-
name: 'DJI Mini 3 Pro',
|
|
235
|
-
category: 'Drones',
|
|
236
|
-
description: 'Lightweight drone with 4K camera',
|
|
237
|
-
price: 759,
|
|
238
|
-
iconName: 'lucide:plane'
|
|
239
|
-
}}
|
|
240
|
-
.selectable=${true}
|
|
241
|
-
.showQuantitySelector=${false}
|
|
242
|
-
@selectionChange=${(e: CustomEvent) => {
|
|
243
|
-
const output = document.querySelector('#selection-output');
|
|
244
|
-
if (output) {
|
|
245
|
-
const selectedCards = document.querySelectorAll('dees-shopping-productcard[selectable]');
|
|
246
|
-
const selectedProducts: string[] = [];
|
|
247
|
-
(selectedCards as NodeListOf<DeesShoppingProductcard>).forEach((card) => {
|
|
248
|
-
if (card.selected) {
|
|
249
|
-
selectedProducts.push(card.productData.name);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
output.textContent = selectedProducts.length > 0
|
|
253
|
-
? `Selected: ${selectedProducts.join(', ')}`
|
|
254
|
-
: 'No products selected';
|
|
255
|
-
}
|
|
256
|
-
}}
|
|
257
|
-
></dees-shopping-productcard>
|
|
258
|
-
|
|
259
|
-
<dees-shopping-productcard
|
|
260
|
-
.productData=${{
|
|
261
|
-
name: 'GoPro HERO12',
|
|
262
|
-
category: 'Action Cameras',
|
|
263
|
-
description: '5.3K video with HyperSmooth 6.0',
|
|
264
|
-
price: 399,
|
|
265
|
-
originalPrice: 449,
|
|
266
|
-
iconName: 'lucide:video'
|
|
267
|
-
}}
|
|
268
|
-
.selectable=${true}
|
|
269
|
-
.showQuantitySelector=${false}
|
|
270
|
-
@selectionChange=${(e: CustomEvent) => {
|
|
271
|
-
const output = document.querySelector('#selection-output');
|
|
272
|
-
if (output) {
|
|
273
|
-
const selectedCards = document.querySelectorAll('dees-shopping-productcard[selectable]');
|
|
274
|
-
const selectedProducts: string[] = [];
|
|
275
|
-
(selectedCards as NodeListOf<DeesShoppingProductcard>).forEach((card) => {
|
|
276
|
-
if (card.selected) {
|
|
277
|
-
selectedProducts.push(card.productData.name);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
output.textContent = selectedProducts.length > 0
|
|
281
|
-
? `Selected: ${selectedProducts.join(', ')}`
|
|
282
|
-
: 'No products selected';
|
|
283
|
-
}
|
|
284
|
-
}}
|
|
285
|
-
></dees-shopping-productcard>
|
|
286
|
-
</div>
|
|
287
|
-
|
|
288
|
-
<div class="selected-products" id="selection-output" style="margin-top: 16px;">
|
|
289
|
-
No products selected
|
|
290
|
-
</div>
|
|
291
|
-
</dees-panel>
|
|
292
|
-
|
|
293
|
-
<dees-panel .title=${'Product Variations'} .subtitle=${'Different states and configurations'}>
|
|
294
|
-
<div class="product-grid">
|
|
295
|
-
<dees-shopping-productcard
|
|
296
|
-
.productData=${{
|
|
297
|
-
name: 'Limited Edition Sneakers',
|
|
298
|
-
category: 'Footwear',
|
|
299
|
-
description: 'Exclusive colorway - Only 500 pairs',
|
|
300
|
-
price: 299,
|
|
301
|
-
iconName: 'lucide:footprints',
|
|
302
|
-
inStock: false,
|
|
303
|
-
stockText: 'Sold Out'
|
|
304
|
-
}}
|
|
305
|
-
.quantity=${0}
|
|
306
|
-
></dees-shopping-productcard>
|
|
307
|
-
|
|
308
|
-
<dees-shopping-productcard
|
|
309
|
-
.productData=${{
|
|
310
|
-
name: 'Minimalist Wallet',
|
|
311
|
-
price: 39.99,
|
|
312
|
-
iconName: 'lucide:wallet'
|
|
313
|
-
}}
|
|
314
|
-
.quantity=${1}
|
|
315
|
-
></dees-shopping-productcard>
|
|
316
|
-
|
|
317
|
-
<dees-shopping-productcard
|
|
318
|
-
.productData=${{
|
|
319
|
-
name: 'Premium Coffee Beans',
|
|
320
|
-
category: 'Food & Beverage',
|
|
321
|
-
description: 'Single origin, medium roast',
|
|
322
|
-
price: 18.50,
|
|
323
|
-
iconName: 'lucide:coffee',
|
|
324
|
-
currency: '€'
|
|
325
|
-
}}
|
|
326
|
-
.quantity=${2}
|
|
327
|
-
></dees-shopping-productcard>
|
|
328
|
-
</div>
|
|
329
|
-
</dees-panel>
|
|
330
|
-
</div>
|
|
331
|
-
</dees-demowrapper>
|
|
332
|
-
`;
|
|
1
|
+
import { html, css, cssManager, customElement, state, DeesElement } from '@design.estate/dees-element';
|
|
2
|
+
import { themeDefaultStyles } from '../../00theme.js';
|
|
3
|
+
import { demoPage } from '../../../demos/templates.js';
|
|
4
|
+
import type { IProductData } from './dees-shopping-productcard.js';
|
|
5
|
+
import '../../00group-input/dees-input-multitoggle/dees-input-multitoggle.js';
|
|
6
|
+
import '../../00group-button/dees-button/dees-button.js';
|
|
7
|
+
|
|
8
|
+
// Small original vector product studies keep this fixture sharp and self-contained.
|
|
9
|
+
const illustration = (content: string) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"><rect width="400" height="300" fill="#e8e6e1"/>${content}</svg>`)}`;
|
|
10
|
+
const products: IProductData[] = [
|
|
11
|
+
{ name: 'Studio headphones', category: 'Sound', description: 'A quiet space, wherever you work.', price: 179, originalPrice: 219, iconName: 'lucide:headphones', imageUrl: illustration('<path d="M125 172v-40a75 75 0 0 1 150 0v40" fill="none" stroke="#383a3c" stroke-width="17"/><path d="M135 136v-5a65 65 0 0 1 130 0v5" fill="none" stroke="#b4b1ab" stroke-width="7"/><rect x="106" y="130" width="42" height="88" rx="20" fill="#343638"/><rect x="124" y="130" width="30" height="88" rx="15" fill="#616467"/><rect x="252" y="130" width="42" height="88" rx="20" fill="#343638"/><rect x="246" y="130" width="30" height="88" rx="15" fill="#616467"/>') },
|
|
12
|
+
{ name: 'Everyday keyboard', category: 'Desk', description: 'Low-profile keys. A little more focus.', price: 89, iconName: 'lucide:keyboard', imageUrl: illustration('<rect x="54" y="109" width="292" height="111" rx="14" fill="#a6a4a0"/><rect x="54" y="101" width="292" height="111" rx="14" fill="#cecbc4"/>' + Array.from({ length: 3 }, (_, row) => Array.from({ length: 11 }, (_, col) => `<rect x="${67 + col * 24}" y="${112 + row * 23}" width="19" height="17" rx="4" fill="#f6f5f1"/>`).join('')).join('') + '<rect x="67" y="181" width="42" height="17" rx="4" fill="#f6f5f1"/><rect x="115" y="181" width="165" height="17" rx="4" fill="#f6f5f1"/><rect x="286" y="181" width="43" height="17" rx="4" fill="#f6f5f1"/>') },
|
|
13
|
+
{ name: 'Pocket notebook', category: 'Ideas', description: 'For the ideas that start on paper.', price: 24, iconName: 'lucide:notebook', imageUrl: illustration('<rect x="122" y="51" width="156" height="210" rx="8" fill="#a7ada5"/><rect x="116" y="43" width="156" height="210" rx="8" fill="#737e6d"/><path d="M129 43v210" stroke="#596750" stroke-width="3"/><path d="M248 43v210" stroke="#485541" stroke-width="7"/><rect x="151" y="94" width="72" height="1" fill="#aeb6a6"/><rect x="151" y="103" width="50" height="1" fill="#aeb6a6"/><path d="M207 252v18l8-5 8 5v-18" fill="#c0b391"/>') },
|
|
14
|
+
{ name: 'Desktop hub', category: 'Connections', description: 'One cable. Everything connected.', price: 69, inStock: false, stockText: 'Back soon', iconName: 'lucide:usb', imageUrl: illustration('<path d="M253 135h30q37 0 37-40v-8" fill="none" stroke="#53565a" stroke-width="10"/><rect x="307" y="58" width="25" height="35" rx="5" fill="#33383d"/><rect x="76" y="130" width="220" height="73" rx="19" fill="#646a71"/><rect x="76" y="118" width="220" height="67" rx="19" fill="#adb3ba"/><rect x="97" y="159" width="40" height="9" rx="3" fill="#33383d"/><rect x="151" y="159" width="40" height="9" rx="3" fill="#33383d"/><rect x="217" y="159" width="31" height="9" rx="4" fill="#33383d"/><circle cx="268" cy="163" r="3" fill="#d4dddc"/>') },
|
|
15
|
+
];
|
|
16
|
+
const money = (value: number) => `$${value.toFixed(2)}`;
|
|
17
|
+
|
|
18
|
+
@customElement('dees-demo-simple-shop')
|
|
19
|
+
class DeesDemoSimpleShop extends DeesElement {
|
|
20
|
+
@state() private accessor mode = 'shop';
|
|
21
|
+
@state() private accessor quantities = products.map(() => 0);
|
|
22
|
+
@state() private accessor selected: number[] = [];
|
|
23
|
+
@state() private accessor restocked = false;
|
|
24
|
+
@state() private accessor result = 'Add a few essentials to your bag, or build a kit.';
|
|
25
|
+
private get inventory(): IProductData[] { return products.map(product => product.inStock === false && this.restocked ? { ...product, inStock: true, stockText: 'In stock' } : product); }
|
|
26
|
+
public static styles = [themeDefaultStyles, cssManager.defaultStyles, css`
|
|
27
|
+
:host { display: grid; gap: 24px; container-type: inline-size; font: 13px/1.5 var(--dees-font-family); }
|
|
28
|
+
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; }
|
|
29
|
+
.layout { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 24px; align-items: start; }
|
|
30
|
+
.products { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
|
|
31
|
+
.bag { position: sticky; top: 20px; display: grid; gap: 20px; padding: 24px; border-radius: var(--dees-radius-2xl); corner-shape: var(--dees-corner-shape); background: var(--dees-color-bg-primary); border: 1px solid var(--dees-color-border-subtle); }
|
|
32
|
+
h2 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -.02em; }
|
|
33
|
+
p { margin: 0; color: var(--dees-color-text-secondary); }
|
|
34
|
+
.empty { display: grid; justify-items: start; gap: 12px; padding: 16px 0; color: var(--dees-color-text-secondary); }
|
|
35
|
+
.lines { display: grid; gap: 16px; }
|
|
36
|
+
.line, .total { display: flex; gap: 16px; justify-content: space-between; }
|
|
37
|
+
.line small { display: block; color: var(--dees-color-text-secondary); margin-top: 3px; }
|
|
38
|
+
.line > span, .total { font-variant-numeric: tabular-nums; }
|
|
39
|
+
.total { border-top: 1px solid var(--dees-color-border-subtle); padding-top: 16px; font-weight: 600; }
|
|
40
|
+
.kit { display: grid; gap: 12px; padding-top: 20px; border-top: 1px solid var(--dees-color-border-subtle); }
|
|
41
|
+
output { padding: 14px 16px; border-radius: var(--dees-radius-lg); background: var(--dees-color-bg-secondary); color: var(--dees-color-text-secondary); }
|
|
42
|
+
@container (max-width: 760px) { .layout { grid-template-columns: minmax(0, 1fr); } .bag { position: static; } }
|
|
43
|
+
@container (max-width: 500px) { .products { grid-template-columns: minmax(0, 1fr); } }
|
|
44
|
+
`];
|
|
45
|
+
public render() {
|
|
46
|
+
const inventory = this.inventory;
|
|
47
|
+
const count = this.quantities.reduce((sum, quantity) => sum + quantity, 0);
|
|
48
|
+
const total = this.quantities.reduce((sum, quantity, index) => sum + quantity * inventory[index].price, 0);
|
|
49
|
+
return html`<div class="toolbar"><dees-input-multitoggle aria-label="Shopping mode" .options=${[{ key: 'shop', label: 'Shop essentials' }, { key: 'kit', label: 'Build a kit' }]} .value=${this.mode}
|
|
50
|
+
@change=${(event: CustomEvent) => { this.mode = event.detail.value; }}></dees-input-multitoggle>
|
|
51
|
+
<dees-button type="ghost" text=${this.restocked ? 'Hub restocked' : 'Restock hub'} .disabled=${this.restocked} @clicked=${() => { this.restocked = true; this.result = 'Desktop hub is available again.'; }}></dees-button></div>
|
|
52
|
+
<div class="layout"><div class="products">${inventory.map((product, index) => html`<dees-shopping-productcard .productData=${product} .quantity=${this.quantities[index]}
|
|
53
|
+
.selectable=${this.mode === 'kit' && product.inStock !== false} .selected=${this.mode === 'kit' && this.selected.includes(index)} .showQuantitySelector=${product.inStock !== false}
|
|
54
|
+
@quantityChange=${(event: CustomEvent<{ quantity: number }>) => { this.quantities = this.quantities.map((value, i) => i === index ? event.detail.quantity : value); this.result = `${product.name}: ${event.detail.quantity} in your bag.`; }}
|
|
55
|
+
@selectionChange=${(event: CustomEvent<{ selected: boolean }>) => { this.selected = event.detail.selected ? [...this.selected, index] : this.selected.filter(i => i !== index); this.result = `${this.selected.length} essentials selected for your kit.`; }}></dees-shopping-productcard>`)}</div>
|
|
56
|
+
<aside class="bag" aria-label="Shopping bag"><h2>Your bag${count ? ` · ${count}` : ''}</h2>
|
|
57
|
+
${count ? html`<div class="lines">${inventory.map((product, index) => this.quantities[index] ? html`<div class="line"><div>${product.name}<small>Quantity ${this.quantities[index]}</small></div><span>${money(product.price * this.quantities[index])}</span></div>` : '')}</div>` : html`<div class="empty"><dees-icon icon="lucide:shoppingBag" iconSize="28"></dees-icon><p>A few good essentials.<br>A space that feels like yours.</p></div>`}
|
|
58
|
+
<div class="total"><span>Subtotal</span><span>${money(total)}</span></div>
|
|
59
|
+
<dees-button full-width type="accent" text="Review bag" .disabled=${count === 0} @clicked=${() => { this.result = `Your sample bag has ${count} items, totaling ${money(total)}. No order has been placed.`; }}></dees-button>
|
|
60
|
+
${count ? html`<dees-button type="ghost" size="sm" text="Clear bag" @clicked=${() => { this.quantities = products.map(() => 0); this.result = 'Your bag is empty.'; }}></dees-button>` : ''}
|
|
61
|
+
${this.mode === 'kit' ? html`<div class="kit"><p>${this.selected.length} items selected for your kit.</p><dees-button full-width type="outline" text="Add kit to bag" .disabled=${!this.selected.length}
|
|
62
|
+
@clicked=${() => { this.quantities = this.quantities.map((quantity, index) => quantity + (this.selected.includes(index) ? 1 : 0)); this.result = 'One of each selected essential was added to your bag.'; }}></dees-button></div>` : ''}
|
|
63
|
+
</aside>
|
|
64
|
+
</div><output role="status">${this.result}</output>`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export const demoFunc = () => demoPage('Good things for good work.', 'A considered set of desk essentials. Find your favorites and build a kit that works together.', html`<dees-demo-simple-shop></dees-demo-simple-shop>`);
|