astryx-dracula 0.1.3 → 0.2.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.
Files changed (94) hide show
  1. package/BRAND.md +1 -1
  2. package/README.md +2 -0
  3. package/USAGE.md +13 -0
  4. package/astryx-dracula.js +4 -4
  5. package/astryx.integration.mjs +3 -0
  6. package/package.json +4 -2
  7. package/templates/ai-chat-landing.template.mjs +6 -0
  8. package/templates/ai-chat-landing.tsx +476 -0
  9. package/templates/ai-chat.template.mjs +6 -0
  10. package/templates/ai-chat.tsx +762 -0
  11. package/templates/blank.template.mjs +6 -0
  12. package/templates/blank.tsx +16 -0
  13. package/templates/centered-hero.template.mjs +6 -0
  14. package/templates/centered-hero.tsx +188 -0
  15. package/templates/classic-gallery.template.mjs +6 -0
  16. package/templates/classic-gallery.tsx +181 -0
  17. package/templates/contact-form.template.mjs +6 -0
  18. package/templates/contact-form.tsx +292 -0
  19. package/templates/dashboard-portfolio.template.mjs +6 -0
  20. package/templates/dashboard-portfolio.tsx +800 -0
  21. package/templates/dashboard.template.mjs +6 -0
  22. package/templates/dashboard.tsx +774 -0
  23. package/templates/detail-page.template.mjs +6 -0
  24. package/templates/detail-page.tsx +695 -0
  25. package/templates/documentation-design.template.mjs +6 -0
  26. package/templates/documentation-design.tsx +751 -0
  27. package/templates/documentation-technical.template.mjs +6 -0
  28. package/templates/documentation-technical.tsx +292 -0
  29. package/templates/documentation.template.mjs +6 -0
  30. package/templates/documentation.tsx +347 -0
  31. package/templates/editor.template.mjs +6 -0
  32. package/templates/editor.tsx +959 -0
  33. package/templates/file-explorer.template.mjs +6 -0
  34. package/templates/file-explorer.tsx +577 -0
  35. package/templates/form-two-column.template.mjs +6 -0
  36. package/templates/form-two-column.tsx +314 -0
  37. package/templates/gallery-hero.template.mjs +6 -0
  38. package/templates/gallery-hero.tsx +287 -0
  39. package/templates/ide.template.mjs +6 -0
  40. package/templates/ide.tsx +533 -0
  41. package/templates/incident-console.template.mjs +6 -0
  42. package/templates/incident-console.tsx +584 -0
  43. package/templates/kanban-board.template.mjs +6 -0
  44. package/templates/kanban-board.tsx +746 -0
  45. package/templates/library.template.mjs +6 -0
  46. package/templates/library.tsx +489 -0
  47. package/templates/login-card.template.mjs +6 -0
  48. package/templates/login-card.tsx +200 -0
  49. package/templates/login-split.template.mjs +6 -0
  50. package/templates/login-split.tsx +318 -0
  51. package/templates/login-sso.template.mjs +6 -0
  52. package/templates/login-sso.tsx +277 -0
  53. package/templates/login.template.mjs +6 -0
  54. package/templates/login.tsx +98 -0
  55. package/templates/messaging-shell.template.mjs +6 -0
  56. package/templates/messaging-shell.tsx +675 -0
  57. package/templates/mixed-gallery.template.mjs +6 -0
  58. package/templates/mixed-gallery.tsx +190 -0
  59. package/templates/payment-form.template.mjs +6 -0
  60. package/templates/payment-form.tsx +990 -0
  61. package/templates/product-detail.template.mjs +6 -0
  62. package/templates/product-detail.tsx +366 -0
  63. package/templates/product-gallery.template.mjs +6 -0
  64. package/templates/product-gallery.tsx +173 -0
  65. package/templates/settings-dialog.template.mjs +6 -0
  66. package/templates/settings-dialog.tsx +920 -0
  67. package/templates/settings-sidebar.template.mjs +6 -0
  68. package/templates/settings-sidebar.tsx +952 -0
  69. package/templates/settings.template.mjs +6 -0
  70. package/templates/settings.tsx +235 -0
  71. package/templates/shell-nav.template.mjs +6 -0
  72. package/templates/shell-nav.tsx +306 -0
  73. package/templates/shell-side-nav.template.mjs +6 -0
  74. package/templates/shell-side-nav.tsx +238 -0
  75. package/templates/shell-top-nav.template.mjs +6 -0
  76. package/templates/shell-top-nav.tsx +243 -0
  77. package/templates/side-gallery.template.mjs +6 -0
  78. package/templates/side-gallery.tsx +179 -0
  79. package/templates/table-grouped.template.mjs +6 -0
  80. package/templates/table-grouped.tsx +1174 -0
  81. package/templates/table-page-chart.template.mjs +6 -0
  82. package/templates/table-page-chart.tsx +693 -0
  83. package/templates/table-page-heatmap-status.template.mjs +6 -0
  84. package/templates/table-page-heatmap-status.tsx +547 -0
  85. package/templates/table-page-shoe-store-heatmap.template.mjs +6 -0
  86. package/templates/table-page-shoe-store-heatmap.tsx +1038 -0
  87. package/templates/table-page.template.mjs +6 -0
  88. package/templates/table-page.tsx +445 -0
  89. package/templates/table.template.mjs +6 -0
  90. package/templates/table.tsx +84 -0
  91. package/templates/theme-showcase.template.mjs +6 -0
  92. package/templates/theme-showcase.tsx +1282 -0
  93. package/theme.css +4 -4
  94. package/tokens.css +4 -4
@@ -0,0 +1,1038 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import type {CSSProperties} from 'react';
4
+ import {
5
+ VStack,
6
+ HStack,
7
+ StackItem,
8
+ Layout,
9
+ LayoutContent,
10
+ LayoutHeader,
11
+ } from '@astryxdesign/core/Layout';
12
+ import {Text, Heading} from '@astryxdesign/core/Text';
13
+ import {Button} from '@astryxdesign/core/Button';
14
+ import {IconButton} from '@astryxdesign/core/IconButton';
15
+ import {Icon} from '@astryxdesign/core/Icon';
16
+ import {Badge} from '@astryxdesign/core/Badge';
17
+ import {Card} from '@astryxdesign/core/Card';
18
+ import {Link} from '@astryxdesign/core/Link';
19
+ import {Table, proportional, pixel} from '@astryxdesign/core/Table';
20
+ import type {TableColumn} from '@astryxdesign/core/Table';
21
+ import {Filter, Download, Plus, Square} from 'lucide-react';
22
+
23
+ // ============= ICONS (verified lucide-react exports) =============
24
+ // Filter ← FunnelIcon, Download ← ArrowDownTrayIcon, Plus ← PlusIcon.
25
+ // Square marks the chart legend swatch.
26
+
27
+ const swatchStyle: CSSProperties = {flexShrink: 0};
28
+
29
+ // Rounded product swatch: Dracula surface with a per-product accent glyph.
30
+ function ProductSwatch({accent, label}: {accent: string; label: string}) {
31
+ return (
32
+ <svg
33
+ viewBox="0 0 36 36"
34
+ width={36}
35
+ height={36}
36
+ style={swatchStyle}
37
+ role="img"
38
+ aria-label={`${label} swatch`}>
39
+ <rect width={36} height={36} rx={5} fill="var(--dracula-bg-light)" />
40
+ <rect
41
+ x={1}
42
+ y={1}
43
+ width={34}
44
+ height={34}
45
+ rx={4}
46
+ fill="none"
47
+ stroke="var(--color-widget-content-border)"
48
+ />
49
+ <circle cx={18} cy={18} r={7} fill="none" stroke={accent} strokeWidth={3} />
50
+ </svg>
51
+ );
52
+ }
53
+
54
+ // ============= DATA =============
55
+
56
+ type ProductCategory =
57
+ 'Running' | 'Lifestyle' | 'Basketball' | 'Training' | 'Skateboarding';
58
+
59
+ interface OrderRow extends Record<string, unknown> {
60
+ id: string;
61
+ customer: string;
62
+ email: string;
63
+ product: string;
64
+ category: ProductCategory;
65
+ imageIndex: number;
66
+ amount: number;
67
+ status: 'completed' | 'processing' | 'shipped' | 'refunded';
68
+ date: string;
69
+ }
70
+
71
+ const PRODUCTS = [
72
+ {
73
+ name: 'Air Max 90',
74
+ category: 'Lifestyle' as ProductCategory,
75
+ accent: 'var(--dracula-yellow)',
76
+ price: 130,
77
+ },
78
+ {
79
+ name: 'UltraBoost 22',
80
+ category: 'Running' as ProductCategory,
81
+ accent: 'var(--dracula-cyan)',
82
+ price: 190,
83
+ },
84
+ {
85
+ name: 'Old Skool',
86
+ category: 'Skateboarding' as ProductCategory,
87
+ accent: 'var(--dracula-orange)',
88
+ price: 70,
89
+ },
90
+ {
91
+ name: 'Jordan 1 Retro',
92
+ category: 'Basketball' as ProductCategory,
93
+ accent: 'var(--dracula-purple)',
94
+ price: 180,
95
+ },
96
+ {
97
+ name: 'Metcon 8',
98
+ category: 'Training' as ProductCategory,
99
+ accent: 'var(--dracula-red)',
100
+ price: 140,
101
+ },
102
+ {
103
+ name: 'Dunk Low',
104
+ category: 'Skateboarding' as ProductCategory,
105
+ accent: 'var(--dracula-green)',
106
+ price: 110,
107
+ },
108
+ ];
109
+
110
+ const orders: OrderRow[] = [
111
+ // Sun (0) — spread across 9am–5pm, very hot
112
+ {
113
+ id: 'ORD-1001',
114
+ customer: 'Sarah Chen',
115
+ email: 'sarah.chen@acme.co',
116
+ product: PRODUCTS[0].name,
117
+ category: PRODUCTS[0].category,
118
+ imageIndex: 0,
119
+ amount: 130,
120
+ status: 'completed',
121
+ date: '2025-01-12',
122
+ },
123
+ {
124
+ id: 'ORD-1002',
125
+ customer: 'Marcus Rivera',
126
+ email: 'mrivera@globex.com',
127
+ product: PRODUCTS[1].name,
128
+ category: PRODUCTS[1].category,
129
+ imageIndex: 1,
130
+ amount: 190,
131
+ status: 'completed',
132
+ date: '2025-01-12',
133
+ },
134
+ {
135
+ id: 'ORD-1003',
136
+ customer: 'Aisha Patel',
137
+ email: 'aisha.p@initech.io',
138
+ product: PRODUCTS[2].name,
139
+ category: PRODUCTS[2].category,
140
+ imageIndex: 2,
141
+ amount: 70,
142
+ status: 'shipped',
143
+ date: '2025-01-12',
144
+ },
145
+ {
146
+ id: 'ORD-1004',
147
+ customer: "James O'Brien",
148
+ email: 'jobrien@umbrella.net',
149
+ product: PRODUCTS[3].name,
150
+ category: PRODUCTS[3].category,
151
+ imageIndex: 3,
152
+ amount: 180,
153
+ status: 'processing',
154
+ date: '2025-01-12',
155
+ },
156
+ {
157
+ id: 'ORD-1005',
158
+ customer: 'Yuki Tanaka',
159
+ email: 'yuki@soylent.jp',
160
+ product: PRODUCTS[4].name,
161
+ category: PRODUCTS[4].category,
162
+ imageIndex: 4,
163
+ amount: 140,
164
+ status: 'completed',
165
+ date: '2025-01-12',
166
+ },
167
+ {
168
+ id: 'ORD-1006',
169
+ customer: 'Elena Volkov',
170
+ email: 'elena.v@wayne.com',
171
+ product: PRODUCTS[5].name,
172
+ category: PRODUCTS[5].category,
173
+ imageIndex: 5,
174
+ amount: 110,
175
+ status: 'completed',
176
+ date: '2025-01-12',
177
+ },
178
+ {
179
+ id: 'ORD-1007',
180
+ customer: 'David Kim',
181
+ email: 'dkim@stark.io',
182
+ product: PRODUCTS[0].name,
183
+ category: PRODUCTS[0].category,
184
+ imageIndex: 0,
185
+ amount: 130,
186
+ status: 'completed',
187
+ date: '2025-01-12',
188
+ },
189
+ {
190
+ id: 'ORD-1008',
191
+ customer: 'Fatima Al-Rashid',
192
+ email: 'fatima@oscorp.ae',
193
+ product: PRODUCTS[1].name,
194
+ category: PRODUCTS[1].category,
195
+ imageIndex: 1,
196
+ amount: 190,
197
+ status: 'shipped',
198
+ date: '2025-01-12',
199
+ },
200
+ {
201
+ id: 'ORD-1009',
202
+ customer: 'Lucas Andersson',
203
+ email: 'lucas.a@cyberdyne.se',
204
+ product: PRODUCTS[2].name,
205
+ category: PRODUCTS[2].category,
206
+ imageIndex: 2,
207
+ amount: 70,
208
+ status: 'completed',
209
+ date: '2025-01-12',
210
+ },
211
+ {
212
+ id: 'ORD-1010',
213
+ customer: 'Priya Sharma',
214
+ email: 'priya@aperture.in',
215
+ product: PRODUCTS[3].name,
216
+ category: PRODUCTS[3].category,
217
+ imageIndex: 3,
218
+ amount: 180,
219
+ status: 'completed',
220
+ date: '2025-01-12',
221
+ },
222
+ {
223
+ id: 'ORD-1011',
224
+ customer: 'Noah Williams',
225
+ email: 'noah.w@massive.com',
226
+ product: PRODUCTS[4].name,
227
+ category: PRODUCTS[4].category,
228
+ imageIndex: 4,
229
+ amount: 140,
230
+ status: 'completed',
231
+ date: '2025-01-12',
232
+ },
233
+ {
234
+ id: 'ORD-1012',
235
+ customer: 'Sofia Garcia',
236
+ email: 'sgarcia@tyrell.mx',
237
+ product: PRODUCTS[5].name,
238
+ category: PRODUCTS[5].category,
239
+ imageIndex: 5,
240
+ amount: 110,
241
+ status: 'completed',
242
+ date: '2025-01-12',
243
+ },
244
+ {
245
+ id: 'ORD-1013',
246
+ customer: 'Oliver Brown',
247
+ email: 'oliver.b@weyland.uk',
248
+ product: PRODUCTS[0].name,
249
+ category: PRODUCTS[0].category,
250
+ imageIndex: 0,
251
+ amount: 130,
252
+ status: 'shipped',
253
+ date: '2025-01-12',
254
+ },
255
+ {
256
+ id: 'ORD-1014',
257
+ customer: 'Mei Lin',
258
+ email: 'mei.lin@choam.cn',
259
+ product: PRODUCTS[1].name,
260
+ category: PRODUCTS[1].category,
261
+ imageIndex: 1,
262
+ amount: 190,
263
+ status: 'completed',
264
+ date: '2025-01-12',
265
+ },
266
+ // Mon (1) — light-medium, midday into afternoon
267
+ {
268
+ id: 'ORD-1015',
269
+ customer: 'Hassan Ahmed',
270
+ email: 'hahmed@abstergo.eg',
271
+ product: PRODUCTS[2].name,
272
+ category: PRODUCTS[2].category,
273
+ imageIndex: 2,
274
+ amount: 70,
275
+ status: 'refunded',
276
+ date: '2025-01-13',
277
+ },
278
+ {
279
+ id: 'ORD-1016',
280
+ customer: 'Isabella Rossi',
281
+ email: 'irossi@genom.it',
282
+ product: PRODUCTS[3].name,
283
+ category: PRODUCTS[3].category,
284
+ imageIndex: 3,
285
+ amount: 180,
286
+ status: 'completed',
287
+ date: '2025-01-13',
288
+ },
289
+ {
290
+ id: 'ORD-1058',
291
+ customer: 'Thiago Lima',
292
+ email: 'tlima@shinra.br',
293
+ product: PRODUCTS[4].name,
294
+ category: PRODUCTS[4].category,
295
+ imageIndex: 4,
296
+ amount: 140,
297
+ status: 'completed',
298
+ date: '2025-01-13',
299
+ },
300
+ {
301
+ id: 'ORD-1059',
302
+ customer: 'Nadia Popov',
303
+ email: 'npopov@kaiba.ro',
304
+ product: PRODUCTS[5].name,
305
+ category: PRODUCTS[5].category,
306
+ imageIndex: 5,
307
+ amount: 110,
308
+ status: 'shipped',
309
+ date: '2025-01-13',
310
+ },
311
+ // Tue (2) — afternoon concentrated: 2pm–5pm hot
312
+ {
313
+ id: 'ORD-1017',
314
+ customer: 'Liam Murphy',
315
+ email: 'liam.m@mishima.ie',
316
+ product: PRODUCTS[4].name,
317
+ category: PRODUCTS[4].category,
318
+ imageIndex: 4,
319
+ amount: 140,
320
+ status: 'processing',
321
+ date: '2025-01-14',
322
+ },
323
+ {
324
+ id: 'ORD-1018',
325
+ customer: 'Chloe Dubois',
326
+ email: 'cdubois@armacham.fr',
327
+ product: PRODUCTS[5].name,
328
+ category: PRODUCTS[5].category,
329
+ imageIndex: 5,
330
+ amount: 110,
331
+ status: 'completed',
332
+ date: '2025-01-14',
333
+ },
334
+ {
335
+ id: 'ORD-1019',
336
+ customer: 'Andre Santos',
337
+ email: 'asantos@shinra.br',
338
+ product: PRODUCTS[0].name,
339
+ category: PRODUCTS[0].category,
340
+ imageIndex: 0,
341
+ amount: 130,
342
+ status: 'shipped',
343
+ date: '2025-01-14',
344
+ },
345
+ {
346
+ id: 'ORD-1020',
347
+ customer: 'Nina Johansson',
348
+ email: 'nina.j@lexcorp.se',
349
+ product: PRODUCTS[1].name,
350
+ category: PRODUCTS[1].category,
351
+ imageIndex: 1,
352
+ amount: 190,
353
+ status: 'completed',
354
+ date: '2025-01-14',
355
+ },
356
+ {
357
+ id: 'ORD-1021',
358
+ customer: 'Raj Kapoor',
359
+ email: 'raj.k@vaultec.in',
360
+ product: PRODUCTS[2].name,
361
+ category: PRODUCTS[2].category,
362
+ imageIndex: 2,
363
+ amount: 70,
364
+ status: 'completed',
365
+ date: '2025-01-14',
366
+ },
367
+ {
368
+ id: 'ORD-1022',
369
+ customer: 'Emma Thompson',
370
+ email: 'ethompson@monarch.uk',
371
+ product: PRODUCTS[3].name,
372
+ category: PRODUCTS[3].category,
373
+ imageIndex: 3,
374
+ amount: 180,
375
+ status: 'completed',
376
+ date: '2025-01-14',
377
+ },
378
+ {
379
+ id: 'ORD-1023',
380
+ customer: 'Carlos Mendez',
381
+ email: 'cmendez@sirius.ar',
382
+ product: PRODUCTS[4].name,
383
+ category: PRODUCTS[4].category,
384
+ imageIndex: 4,
385
+ amount: 140,
386
+ status: 'shipped',
387
+ date: '2025-01-14',
388
+ },
389
+ {
390
+ id: 'ORD-1024',
391
+ customer: 'Zoe Mitchell',
392
+ email: 'zoe.m@hyperion.au',
393
+ product: PRODUCTS[5].name,
394
+ category: PRODUCTS[5].category,
395
+ imageIndex: 5,
396
+ amount: 110,
397
+ status: 'processing',
398
+ date: '2025-01-14',
399
+ },
400
+ {
401
+ id: 'ORD-1025',
402
+ customer: 'Henrik Larsson',
403
+ email: 'hlarsson@volvo.se',
404
+ product: PRODUCTS[0].name,
405
+ category: PRODUCTS[0].category,
406
+ imageIndex: 0,
407
+ amount: 130,
408
+ status: 'completed',
409
+ date: '2025-01-14',
410
+ },
411
+ // Wed (3) — light-medium, midday into afternoon
412
+ {
413
+ id: 'ORD-1026',
414
+ customer: 'Amara Okafor',
415
+ email: 'aokafor@wakanda.ng',
416
+ product: PRODUCTS[1].name,
417
+ category: PRODUCTS[1].category,
418
+ imageIndex: 1,
419
+ amount: 190,
420
+ status: 'completed',
421
+ date: '2025-01-15',
422
+ },
423
+ {
424
+ id: 'ORD-1027',
425
+ customer: 'Leo Fischer',
426
+ email: 'lfischer@kruger.de',
427
+ product: PRODUCTS[2].name,
428
+ category: PRODUCTS[2].category,
429
+ imageIndex: 2,
430
+ amount: 70,
431
+ status: 'completed',
432
+ date: '2025-01-15',
433
+ },
434
+ {
435
+ id: 'ORD-1028',
436
+ customer: 'Maya Petrov',
437
+ email: 'mpetrov@kaiba.ru',
438
+ product: PRODUCTS[3].name,
439
+ category: PRODUCTS[3].category,
440
+ imageIndex: 3,
441
+ amount: 180,
442
+ status: 'shipped',
443
+ date: '2025-01-15',
444
+ },
445
+ {
446
+ id: 'ORD-1060',
447
+ customer: 'Kai Nakamura',
448
+ email: 'knakamura@capsule.jp',
449
+ product: PRODUCTS[0].name,
450
+ category: PRODUCTS[0].category,
451
+ imageIndex: 0,
452
+ amount: 130,
453
+ status: 'completed',
454
+ date: '2025-01-15',
455
+ },
456
+ {
457
+ id: 'ORD-1061',
458
+ customer: 'Elisa Moretti',
459
+ email: 'emoretti@genom.it',
460
+ product: PRODUCTS[4].name,
461
+ category: PRODUCTS[4].category,
462
+ imageIndex: 4,
463
+ amount: 140,
464
+ status: 'completed',
465
+ date: '2025-01-15',
466
+ },
467
+ // Thu (4) — afternoon concentrated: 1pm–5pm hot
468
+ {
469
+ id: 'ORD-1029',
470
+ customer: 'Tomás Herrera',
471
+ email: 'therrera@nexus.co',
472
+ product: PRODUCTS[4].name,
473
+ category: PRODUCTS[4].category,
474
+ imageIndex: 4,
475
+ amount: 140,
476
+ status: 'completed',
477
+ date: '2025-01-09',
478
+ },
479
+ {
480
+ id: 'ORD-1030',
481
+ customer: 'Grace Nakamura',
482
+ email: 'gnakamura@capsule.jp',
483
+ product: PRODUCTS[5].name,
484
+ category: PRODUCTS[5].category,
485
+ imageIndex: 5,
486
+ amount: 110,
487
+ status: 'completed',
488
+ date: '2025-01-09',
489
+ },
490
+ {
491
+ id: 'ORD-1031',
492
+ customer: 'Kenji Watanabe',
493
+ email: 'kwatanabe@tyrell.jp',
494
+ product: PRODUCTS[0].name,
495
+ category: PRODUCTS[0].category,
496
+ imageIndex: 0,
497
+ amount: 130,
498
+ status: 'completed',
499
+ date: '2025-01-09',
500
+ },
501
+ {
502
+ id: 'ORD-1032',
503
+ customer: 'Lucia Fernandez',
504
+ email: 'lfernandez@nexus.es',
505
+ product: PRODUCTS[1].name,
506
+ category: PRODUCTS[1].category,
507
+ imageIndex: 1,
508
+ amount: 190,
509
+ status: 'completed',
510
+ date: '2025-01-09',
511
+ },
512
+ {
513
+ id: 'ORD-1033',
514
+ customer: 'Oscar Nilsson',
515
+ email: 'onilsson@cyberdyne.se',
516
+ product: PRODUCTS[2].name,
517
+ category: PRODUCTS[2].category,
518
+ imageIndex: 2,
519
+ amount: 70,
520
+ status: 'shipped',
521
+ date: '2025-01-09',
522
+ },
523
+ {
524
+ id: 'ORD-1034',
525
+ customer: 'Dani Alves',
526
+ email: 'dalves@globex.br',
527
+ product: PRODUCTS[3].name,
528
+ category: PRODUCTS[3].category,
529
+ imageIndex: 3,
530
+ amount: 180,
531
+ status: 'completed',
532
+ date: '2025-01-09',
533
+ },
534
+ {
535
+ id: 'ORD-1035',
536
+ customer: 'Rina Sato',
537
+ email: 'rsato@soylent.jp',
538
+ product: PRODUCTS[4].name,
539
+ category: PRODUCTS[4].category,
540
+ imageIndex: 4,
541
+ amount: 140,
542
+ status: 'completed',
543
+ date: '2025-01-09',
544
+ },
545
+ {
546
+ id: 'ORD-1036',
547
+ customer: 'Ivan Petrov',
548
+ email: 'ipetrov@kaiba.ru',
549
+ product: PRODUCTS[5].name,
550
+ category: PRODUCTS[5].category,
551
+ imageIndex: 5,
552
+ amount: 110,
553
+ status: 'processing',
554
+ date: '2025-01-09',
555
+ },
556
+ {
557
+ id: 'ORD-1037',
558
+ customer: 'Aiko Mori',
559
+ email: 'amori@capsule.jp',
560
+ product: PRODUCTS[0].name,
561
+ category: PRODUCTS[0].category,
562
+ imageIndex: 0,
563
+ amount: 130,
564
+ status: 'completed',
565
+ date: '2025-01-09',
566
+ },
567
+ // Fri (5) — medium, early afternoon
568
+ {
569
+ id: 'ORD-1038',
570
+ customer: 'Felix Braun',
571
+ email: 'fbraun@kruger.de',
572
+ product: PRODUCTS[1].name,
573
+ category: PRODUCTS[1].category,
574
+ imageIndex: 1,
575
+ amount: 190,
576
+ status: 'completed',
577
+ date: '2025-01-10',
578
+ },
579
+ {
580
+ id: 'ORD-1039',
581
+ customer: 'Rosa Delgado',
582
+ email: 'rdelgado@sirius.mx',
583
+ product: PRODUCTS[2].name,
584
+ category: PRODUCTS[2].category,
585
+ imageIndex: 2,
586
+ amount: 70,
587
+ status: 'completed',
588
+ date: '2025-01-10',
589
+ },
590
+ {
591
+ id: 'ORD-1040',
592
+ customer: 'Nils Eriksson',
593
+ email: 'neriksson@volvo.se',
594
+ product: PRODUCTS[3].name,
595
+ category: PRODUCTS[3].category,
596
+ imageIndex: 3,
597
+ amount: 180,
598
+ status: 'shipped',
599
+ date: '2025-01-10',
600
+ },
601
+ {
602
+ id: 'ORD-1041',
603
+ customer: 'Suki Park',
604
+ email: 'spark@stark.kr',
605
+ product: PRODUCTS[4].name,
606
+ category: PRODUCTS[4].category,
607
+ imageIndex: 4,
608
+ amount: 140,
609
+ status: 'completed',
610
+ date: '2025-01-10',
611
+ },
612
+ // Sat (6) — spread across 9am–6pm, very hot
613
+ {
614
+ id: 'ORD-1042',
615
+ customer: 'Omar Haddad',
616
+ email: 'ohaddad@oscorp.lb',
617
+ product: PRODUCTS[5].name,
618
+ category: PRODUCTS[5].category,
619
+ imageIndex: 5,
620
+ amount: 110,
621
+ status: 'completed',
622
+ date: '2025-01-11',
623
+ },
624
+ {
625
+ id: 'ORD-1043',
626
+ customer: 'Freya Jensen',
627
+ email: 'fjensen@cyberdyne.dk',
628
+ product: PRODUCTS[0].name,
629
+ category: PRODUCTS[0].category,
630
+ imageIndex: 0,
631
+ amount: 130,
632
+ status: 'shipped',
633
+ date: '2025-01-11',
634
+ },
635
+ {
636
+ id: 'ORD-1044',
637
+ customer: 'Marco Bianchi',
638
+ email: 'mbianchi@genom.it',
639
+ product: PRODUCTS[1].name,
640
+ category: PRODUCTS[1].category,
641
+ imageIndex: 1,
642
+ amount: 190,
643
+ status: 'completed',
644
+ date: '2025-01-11',
645
+ },
646
+ {
647
+ id: 'ORD-1045',
648
+ customer: 'Aya Tanaka',
649
+ email: 'atanaka@capsule.jp',
650
+ product: PRODUCTS[2].name,
651
+ category: PRODUCTS[2].category,
652
+ imageIndex: 2,
653
+ amount: 70,
654
+ status: 'completed',
655
+ date: '2025-01-11',
656
+ },
657
+ {
658
+ id: 'ORD-1046',
659
+ customer: 'Lars Müller',
660
+ email: 'lmuller@kruger.de',
661
+ product: PRODUCTS[3].name,
662
+ category: PRODUCTS[3].category,
663
+ imageIndex: 3,
664
+ amount: 180,
665
+ status: 'completed',
666
+ date: '2025-01-11',
667
+ },
668
+ {
669
+ id: 'ORD-1047',
670
+ customer: 'Mia Chang',
671
+ email: 'mchang@aperture.tw',
672
+ product: PRODUCTS[4].name,
673
+ category: PRODUCTS[4].category,
674
+ imageIndex: 4,
675
+ amount: 140,
676
+ status: 'processing',
677
+ date: '2025-01-11',
678
+ },
679
+ {
680
+ id: 'ORD-1048',
681
+ customer: 'Petra Novak',
682
+ email: 'pnovak@umbrella.cz',
683
+ product: PRODUCTS[5].name,
684
+ category: PRODUCTS[5].category,
685
+ imageIndex: 5,
686
+ amount: 110,
687
+ status: 'completed',
688
+ date: '2025-01-11',
689
+ },
690
+ {
691
+ id: 'ORD-1049',
692
+ customer: 'Tariq Osman',
693
+ email: 'tosman@abstergo.eg',
694
+ product: PRODUCTS[0].name,
695
+ category: PRODUCTS[0].category,
696
+ imageIndex: 0,
697
+ amount: 130,
698
+ status: 'completed',
699
+ date: '2025-01-11',
700
+ },
701
+ {
702
+ id: 'ORD-1050',
703
+ customer: 'Lena Holm',
704
+ email: 'lholm@lexcorp.se',
705
+ product: PRODUCTS[1].name,
706
+ category: PRODUCTS[1].category,
707
+ imageIndex: 1,
708
+ amount: 190,
709
+ status: 'completed',
710
+ date: '2025-01-11',
711
+ },
712
+ {
713
+ id: 'ORD-1051',
714
+ customer: 'Vera Costa',
715
+ email: 'vcosta@shinra.pt',
716
+ product: PRODUCTS[2].name,
717
+ category: PRODUCTS[2].category,
718
+ imageIndex: 2,
719
+ amount: 70,
720
+ status: 'shipped',
721
+ date: '2025-01-11',
722
+ },
723
+ {
724
+ id: 'ORD-1052',
725
+ customer: 'Hugo Blanc',
726
+ email: 'hblanc@armacham.fr',
727
+ product: PRODUCTS[3].name,
728
+ category: PRODUCTS[3].category,
729
+ imageIndex: 3,
730
+ amount: 180,
731
+ status: 'completed',
732
+ date: '2025-01-11',
733
+ },
734
+ {
735
+ id: 'ORD-1053',
736
+ customer: 'Ingrid Berg',
737
+ email: 'iberg@volvo.no',
738
+ product: PRODUCTS[4].name,
739
+ category: PRODUCTS[4].category,
740
+ imageIndex: 4,
741
+ amount: 140,
742
+ status: 'completed',
743
+ date: '2025-01-11',
744
+ },
745
+ {
746
+ id: 'ORD-1054',
747
+ customer: 'Hana Kim',
748
+ email: 'hkim@stark.kr',
749
+ product: PRODUCTS[5].name,
750
+ category: PRODUCTS[5].category,
751
+ imageIndex: 5,
752
+ amount: 110,
753
+ status: 'completed',
754
+ date: '2025-01-11',
755
+ },
756
+ {
757
+ id: 'ORD-1055',
758
+ customer: 'Axel Lindgren',
759
+ email: 'alindgren@lexcorp.se',
760
+ product: PRODUCTS[0].name,
761
+ category: PRODUCTS[0].category,
762
+ imageIndex: 0,
763
+ amount: 130,
764
+ status: 'shipped',
765
+ date: '2025-01-11',
766
+ },
767
+ {
768
+ id: 'ORD-1056',
769
+ customer: 'Yara Mansour',
770
+ email: 'ymansour@abstergo.lb',
771
+ product: PRODUCTS[1].name,
772
+ category: PRODUCTS[1].category,
773
+ imageIndex: 1,
774
+ amount: 190,
775
+ status: 'completed',
776
+ date: '2025-01-11',
777
+ },
778
+ {
779
+ id: 'ORD-1057',
780
+ customer: 'Dmitri Volkov',
781
+ email: 'dvolkov@kaiba.ru',
782
+ product: PRODUCTS[2].name,
783
+ category: PRODUCTS[2].category,
784
+ imageIndex: 2,
785
+ amount: 70,
786
+ status: 'completed',
787
+ date: '2025-01-11',
788
+ },
789
+ ];
790
+
791
+ const revenueData = [
792
+ {date: 'Jan 1', revenue: 5200},
793
+ {date: 'Jan 2', revenue: 4800},
794
+ {date: 'Jan 3', revenue: 6100},
795
+ {date: 'Jan 4', revenue: 7400},
796
+ {date: 'Jan 5', revenue: 5900},
797
+ {date: 'Jan 6', revenue: 6800},
798
+ {date: 'Jan 7', revenue: 7200},
799
+ {date: 'Jan 8', revenue: 8300},
800
+ {date: 'Jan 9', revenue: 6500},
801
+ {date: 'Jan 10', revenue: 5400},
802
+ {date: 'Jan 11', revenue: 7800},
803
+ {date: 'Jan 12', revenue: 9200},
804
+ {date: 'Jan 13', revenue: 6900},
805
+ {date: 'Jan 14', revenue: 8600},
806
+ {date: 'Jan 15', revenue: 7100},
807
+ ];
808
+
809
+ const statusColor: Record<string, 'green' | 'blue' | 'orange' | 'red'> = {
810
+ completed: 'green',
811
+ shipped: 'blue',
812
+ processing: 'orange',
813
+ refunded: 'red',
814
+ };
815
+
816
+ const columns: TableColumn<OrderRow>[] = [
817
+ {
818
+ key: 'id',
819
+ header: 'Order',
820
+ width: pixel(110),
821
+ renderCell: (item: OrderRow) => (
822
+ <Link href="#/templates/table-page-shoe-store-heatmap" isStandalone>
823
+ {item.id}
824
+ </Link>
825
+ ),
826
+ },
827
+ {
828
+ key: 'product',
829
+ header: 'Product',
830
+ width: proportional(3),
831
+ renderCell: (item: OrderRow) => (
832
+ <HStack gap={3} vAlign="center">
833
+ <ProductSwatch
834
+ accent={PRODUCTS[item.imageIndex].accent}
835
+ label={item.product}
836
+ />
837
+ <VStack gap={0}>
838
+ <Text type="body">{item.product}</Text>
839
+ <Text type="supporting" color="secondary">
840
+ {item.category}
841
+ </Text>
842
+ </VStack>
843
+ </HStack>
844
+ ),
845
+ },
846
+ {
847
+ key: 'amount',
848
+ header: 'Amount',
849
+ width: pixel(90),
850
+ renderCell: (item: OrderRow) => (
851
+ <Text type="body" hasTabularNumbers>
852
+ ${item.amount}
853
+ </Text>
854
+ ),
855
+ },
856
+ {
857
+ key: 'customer',
858
+ header: 'Customer',
859
+ width: proportional(2),
860
+ renderCell: (item: OrderRow) => <Text type="body">{item.customer}</Text>,
861
+ },
862
+ {
863
+ key: 'email',
864
+ header: 'Email',
865
+ width: proportional(2),
866
+ renderCell: (item: OrderRow) => <Text type="body">{item.email}</Text>,
867
+ },
868
+ {
869
+ key: 'status',
870
+ header: 'Status',
871
+ width: pixel(120),
872
+ renderCell: (item: OrderRow) => (
873
+ <Badge
874
+ label={item.status.charAt(0).toUpperCase() + item.status.slice(1)}
875
+ variant={statusColor[item.status]}
876
+ />
877
+ ),
878
+ },
879
+ {
880
+ key: 'date',
881
+ header: 'Date',
882
+ width: pixel(110),
883
+ renderCell: (item: OrderRow) => (
884
+ <Text type="body" hasTabularNumbers>
885
+ {item.date}
886
+ </Text>
887
+ ),
888
+ },
889
+ ];
890
+
891
+ // ============= REVENUE CHART (hand SVG, Dracula ramp) =============
892
+
893
+ const revenueLine = 'var(--dracula-cyan)';
894
+
895
+ function RevenueChart() {
896
+ const W = 540;
897
+ const H = 200;
898
+ const padLeft = 44;
899
+ const padRight = 12;
900
+ const padTop = 12;
901
+ const baseline = 164;
902
+ const max = 10000;
903
+ const plotW = W - padLeft - padRight;
904
+ const plotH = baseline - padTop;
905
+ const points = revenueData.map((d, i) => ({
906
+ ...d,
907
+ x: padLeft + (i / (revenueData.length - 1)) * plotW,
908
+ y: baseline - (d.revenue / max) * plotH,
909
+ }));
910
+ const linePath = points
911
+ .map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`)
912
+ .join(' ');
913
+ const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(1)},${baseline} L${points[0].x.toFixed(1)},${baseline} Z`;
914
+ const gridTicks = [0, 2000, 4000, 6000, 8000, 10000];
915
+ return (
916
+ <VStack gap={3}>
917
+ <Card
918
+ padding={3}
919
+ style={{
920
+ backgroundColor: 'var(--color-background)',
921
+ border: 'var(--border-width) solid var(--color-separator)',
922
+ }}>
923
+ <svg
924
+ viewBox={`0 0 ${W} ${H}`}
925
+ width="100%"
926
+ role="img"
927
+ aria-label="Daily revenue, January 1 to 15">
928
+ {gridTicks.map(tick => {
929
+ const y = baseline - (tick / max) * plotH;
930
+ return (
931
+ <g key={tick}>
932
+ <line
933
+ x1={padLeft}
934
+ y1={y}
935
+ x2={W - padRight}
936
+ y2={y}
937
+ stroke="var(--color-separator)"
938
+ strokeDasharray={tick === 0 ? undefined : '3 3'}
939
+ opacity={tick === 0 ? 1 : 0.5}
940
+ />
941
+ <text
942
+ x={padLeft - 6}
943
+ y={y + 3}
944
+ textAnchor="end"
945
+ fontSize={9}
946
+ fill="var(--color-text-paragraph)"
947
+ fontFamily="var(--font-family-mono)">
948
+ {tick === 0 ? '$0' : `$${tick / 1000}k`}
949
+ </text>
950
+ </g>
951
+ );
952
+ })}
953
+ <path d={areaPath} fill={revenueLine} opacity={0.25} />
954
+ <path
955
+ d={linePath}
956
+ fill="none"
957
+ stroke={revenueLine}
958
+ strokeWidth={2}
959
+ strokeLinejoin="round"
960
+ strokeLinecap="round"
961
+ />
962
+ {points.map(
963
+ (p, i) =>
964
+ (i % 3 === 0 || i === points.length - 1) && (
965
+ <text
966
+ key={p.date}
967
+ x={i === points.length - 1 ? W - padRight - 2 : p.x}
968
+ y={H - 8}
969
+ textAnchor={i === points.length - 1 ? 'end' : 'middle'}
970
+ fontSize={9}
971
+ fill="var(--color-text-paragraph)"
972
+ fontFamily="var(--font-family-mono)">
973
+ {p.date}
974
+ </text>
975
+ ),
976
+ )}
977
+ </svg>
978
+ </Card>
979
+ <Text type="supporting" color="secondary">
980
+ Daily revenue · Jan 1–15
981
+ </Text>
982
+ <HStack gap={2} vAlign="center">
983
+ <Icon icon={Square} size="xsm" style={{color: revenueLine}} />
984
+ <Text type="supporting" color="secondary">
985
+ Revenue
986
+ </Text>
987
+ </HStack>
988
+ </VStack>
989
+ );
990
+ }
991
+
992
+ // ============= PAGE =============
993
+
994
+ export default function ShoeStoreTable() {
995
+ return (
996
+ <Layout
997
+ height="fill"
998
+ header={
999
+ <LayoutHeader hasDivider>
1000
+ <HStack gap={2} vAlign="center">
1001
+ <StackItem size="fill">
1002
+ <Heading level={1}>Midnight Kicks</Heading>
1003
+ </StackItem>
1004
+ <IconButton
1005
+ label="Filter"
1006
+ icon={<Icon icon={Filter} size="sm" />}
1007
+ variant="ghost"
1008
+ tooltip="Filter"
1009
+ />
1010
+ <IconButton
1011
+ label="Export"
1012
+ icon={<Icon icon={Download} size="sm" />}
1013
+ variant="ghost"
1014
+ tooltip="Export"
1015
+ />
1016
+ <Button label="New order" icon={<Icon icon={Plus} size="sm" />} />
1017
+ </HStack>
1018
+ </LayoutHeader>
1019
+ }
1020
+ content={
1021
+ <LayoutContent padding={3}>
1022
+ <VStack gap={4}>
1023
+ <RevenueChart />
1024
+
1025
+ <Table<OrderRow>
1026
+ data={orders}
1027
+ columns={columns}
1028
+ idKey="id"
1029
+ density="balanced"
1030
+ dividers="rows"
1031
+ hasHover
1032
+ />
1033
+ </VStack>
1034
+ </LayoutContent>
1035
+ }
1036
+ />
1037
+ );
1038
+ }