create-magic-storefront 0.5.0 → 0.6.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 (139) hide show
  1. package/package.json +3 -3
  2. package/template/.claude/skills/storefront-design/SKILL.md +14 -10
  3. package/template/AGENTS.md +32 -16
  4. package/template/DESIGN.md +117 -0
  5. package/template/PAGES.md +107 -29
  6. package/template/README.md +15 -3
  7. package/template/app/account/addresses/page.tsx +16 -0
  8. package/template/app/account/layout.tsx +14 -0
  9. package/template/app/account/loading.tsx +15 -0
  10. package/template/app/account/orders/[id]/page.tsx +15 -0
  11. package/template/app/account/page.tsx +12 -244
  12. package/template/app/account/profile/page.tsx +16 -0
  13. package/template/app/blog/(index)/loading.tsx +22 -0
  14. package/template/app/blog/{page.tsx → (index)/page.tsx} +42 -25
  15. package/template/app/blog/[handle]/page.tsx +92 -56
  16. package/template/app/blog/author/[handle]/page.tsx +1 -1
  17. package/template/app/cart/layout.tsx +14 -0
  18. package/template/app/cart/page.tsx +49 -101
  19. package/template/app/checkout/layout.tsx +14 -0
  20. package/template/app/checkout/page.tsx +98 -281
  21. package/template/app/collections/[handle]/layout.tsx +20 -0
  22. package/template/app/collections/[handle]/loading.tsx +23 -0
  23. package/template/app/collections/[handle]/page.tsx +131 -15
  24. package/template/app/collections/page.tsx +49 -0
  25. package/template/app/contacts/page.tsx +196 -0
  26. package/template/app/error.tsx +19 -8
  27. package/template/app/fonts/OFL.txt +93 -0
  28. package/template/app/fonts/index.ts +14 -0
  29. package/template/app/fonts/onest-variable.woff2 +0 -0
  30. package/template/app/globals.css +14 -518
  31. package/template/app/layout.tsx +73 -50
  32. package/template/app/not-found.tsx +34 -4
  33. package/template/app/page.tsx +1 -1
  34. package/template/app/pages/[handle]/page.tsx +1 -1
  35. package/template/app/products/[handle]/layout.tsx +20 -0
  36. package/template/app/products/[handle]/loading.tsx +25 -0
  37. package/template/app/products/[handle]/page.tsx +112 -15
  38. package/template/app/providers.tsx +5 -1
  39. package/template/app/search/loading.tsx +12 -0
  40. package/template/app/search/page.tsx +138 -25
  41. package/template/app/sitemap.ts +5 -1
  42. package/template/app/styles/base.css +138 -0
  43. package/template/app/styles/components.css +1108 -0
  44. package/template/app/styles/layout.css +455 -0
  45. package/template/app/styles/pages.css +1839 -0
  46. package/template/app/styles/reset.css +55 -0
  47. package/template/app/styles/sections.css +415 -0
  48. package/template/app/styles/tokens.css +167 -0
  49. package/template/app/styles/utilities.css +37 -0
  50. package/template/app/wishlist/page.tsx +26 -0
  51. package/template/components/account/account-shell.tsx +100 -0
  52. package/template/components/account/addresses.tsx +247 -0
  53. package/template/components/account/order-detail.tsx +281 -0
  54. package/template/components/account/order-list.tsx +94 -0
  55. package/template/components/account/order-status.tsx +19 -0
  56. package/template/components/account/profile.tsx +129 -0
  57. package/template/components/account/sign-in.tsx +164 -0
  58. package/template/components/article-body.tsx +3 -2
  59. package/template/components/article-card.tsx +37 -12
  60. package/template/components/cart/cart-drawer.tsx +149 -0
  61. package/template/components/cart/cart-lines.tsx +89 -0
  62. package/template/components/cart/cart-summary.tsx +191 -0
  63. package/template/components/catalog/catalog-form.tsx +107 -0
  64. package/template/components/catalog/catalog-layout.tsx +82 -0
  65. package/template/components/catalog/facets-shell.tsx +60 -0
  66. package/template/components/catalog/facets.tsx +216 -0
  67. package/template/components/checkout/order-summary.tsx +84 -0
  68. package/template/components/checkout/radio-card.tsx +34 -0
  69. package/template/components/checkout/step-indicator.tsx +56 -0
  70. package/template/components/checkout/steps.tsx +264 -0
  71. package/template/components/checkout/thank-you.tsx +48 -0
  72. package/template/components/checkout/use-checkout.ts +90 -0
  73. package/template/components/footer/site-footer.tsx +132 -0
  74. package/template/components/header/cart-button.tsx +43 -0
  75. package/template/components/header/desktop-nav.tsx +133 -0
  76. package/template/components/header/mobile-menu.tsx +102 -0
  77. package/template/components/header/site-header.tsx +78 -0
  78. package/template/components/page-loading.tsx +20 -0
  79. package/template/components/pager.tsx +3 -1
  80. package/template/components/product/buy-box.tsx +148 -0
  81. package/template/components/product/gallery.tsx +179 -0
  82. package/template/components/product/pre-order-form.tsx +93 -0
  83. package/template/components/product/product-selection.tsx +31 -0
  84. package/template/components/product/recommendations.tsx +26 -0
  85. package/template/components/product/review-list.tsx +159 -0
  86. package/template/components/product/reviews.tsx +80 -0
  87. package/template/components/product/variant-picker.tsx +75 -0
  88. package/template/components/product-card.tsx +103 -0
  89. package/template/components/product-grid.tsx +27 -57
  90. package/template/components/quick-add.tsx +62 -0
  91. package/template/components/search/predictive-search.tsx +282 -0
  92. package/template/components/sections/announcement-bar.tsx +1 -1
  93. package/template/components/sections/banner.tsx +1 -1
  94. package/template/components/sections/collections.tsx +50 -13
  95. package/template/components/sections/deal-of-day.tsx +2 -2
  96. package/template/components/sections/product-shelves.tsx +13 -5
  97. package/template/components/sections/shoppable-stories.tsx +2 -2
  98. package/template/components/sections/store-reviews.tsx +10 -4
  99. package/template/components/share-button.tsx +42 -0
  100. package/template/components/ui/accordion.tsx +35 -0
  101. package/template/components/ui/badge.tsx +20 -0
  102. package/template/components/ui/breadcrumbs.tsx +31 -0
  103. package/template/components/ui/button.tsx +90 -0
  104. package/template/components/ui/drawer.tsx +84 -0
  105. package/template/components/ui/empty-state.tsx +27 -0
  106. package/template/components/ui/field.tsx +33 -0
  107. package/template/components/ui/icon.tsx +112 -0
  108. package/template/components/ui/price.tsx +35 -0
  109. package/template/components/ui/quantity-stepper.tsx +91 -0
  110. package/template/components/ui/rating.tsx +48 -0
  111. package/template/components/ui/skeleton.tsx +46 -0
  112. package/template/components/wishlist/wishlist-view.tsx +134 -0
  113. package/template/lib/article-outline.ts +35 -0
  114. package/template/lib/catalog-params.ts +170 -0
  115. package/template/lib/contacts.ts +34 -0
  116. package/template/lib/errors.ts +29 -0
  117. package/template/lib/i18n.ts +484 -0
  118. package/template/lib/menu.ts +70 -0
  119. package/template/lib/theme-settings.ts +36 -0
  120. package/template/theme/index.ts +7 -1
  121. package/template/theme/sections/collapsible-content.tsx +75 -0
  122. package/template/theme/sections/collection-list.tsx +32 -4
  123. package/template/theme/sections/featured-collection.tsx +22 -2
  124. package/template/theme/sections/hero.tsx +94 -7
  125. package/template/theme/sections/image-with-text.tsx +19 -3
  126. package/template/theme/sections/multicolumn.tsx +113 -0
  127. package/template/theme/sections/page-content.tsx +10 -4
  128. package/template/theme/sections/product-shelf.tsx +26 -4
  129. package/template/theme/sections/rich-text.tsx +13 -1
  130. package/template/theme/sections/testimonials.tsx +14 -9
  131. package/template/theme/settings.ts +85 -1
  132. package/template/theme/templates/index.json +4 -2
  133. package/template/.screenshots/home-1280.png +0 -0
  134. package/template/.screenshots/home-390.png +0 -0
  135. package/template/.screenshots/home-filled-1280.png +0 -0
  136. package/template/.screenshots/home-filled-390.png +0 -0
  137. package/template/.screenshots/page-1280.png +0 -0
  138. package/template/components/buy-box.tsx +0 -89
  139. package/template/components/cart-link.tsx +0 -15
@@ -0,0 +1,455 @@
1
+ /* The site shell: container, announcement, header, main, footer. */
2
+ @layer layout {
3
+ .page-width {
4
+ width: 100%;
5
+ max-width: var(--container);
6
+ margin-inline: auto;
7
+ padding-inline: var(--gutter);
8
+ }
9
+ .page-width--narrow {
10
+ max-width: calc(48rem + 2 * var(--gutter));
11
+ }
12
+
13
+ /* At least a screen tall: the footer starts below the fold, so a page streaming in, or a client
14
+ list replacing its placeholder, never moves anything on screen (CLS). */
15
+ .site-main {
16
+ flex: 1;
17
+ min-height: 100svh;
18
+ width: 100%;
19
+ max-width: var(--container);
20
+ margin-inline: auto;
21
+ padding: var(--space-5) var(--gutter) var(--space-8);
22
+ }
23
+ @media (min-width: 990px) {
24
+ .site-main {
25
+ padding-top: var(--space-6);
26
+ }
27
+ }
28
+
29
+ .site-announcement {
30
+ margin: 0;
31
+ padding: var(--space-2) var(--gutter);
32
+ background: var(--accent);
33
+ color: var(--on-accent);
34
+ font-size: var(--text-sm);
35
+ text-align: center;
36
+ }
37
+
38
+ .skip-link {
39
+ position: absolute;
40
+ top: var(--space-2);
41
+ left: var(--space-2);
42
+ z-index: var(--z-toast);
43
+ padding: var(--space-3) var(--space-4);
44
+ border-radius: var(--radius-sm);
45
+ background: var(--fg);
46
+ color: var(--bg);
47
+ transform: translateY(-200%);
48
+ }
49
+ .skip-link:focus {
50
+ transform: none;
51
+ }
52
+ .site-main:focus {
53
+ outline: none;
54
+ }
55
+
56
+ /* Header: phone = menu + search | logo | icons; desktop = logo | nav | icons. */
57
+ .site-header {
58
+ position: relative;
59
+ z-index: var(--z-header);
60
+ background: var(--nav-bg);
61
+ color: var(--nav-fg);
62
+ border-bottom: 1px solid color-mix(in srgb, var(--nav-fg) 12%, transparent);
63
+ }
64
+ :root[data-sticky-header] .site-header {
65
+ position: sticky;
66
+ top: 0;
67
+ }
68
+ .site-header__inner {
69
+ display: grid;
70
+ grid-template-columns: 1fr auto 1fr;
71
+ align-items: center;
72
+ gap: var(--space-2);
73
+ min-height: var(--header-h);
74
+ max-width: var(--container);
75
+ margin-inline: auto;
76
+ padding-inline: calc(var(--gutter) - var(--space-2));
77
+ }
78
+ .site-header a {
79
+ color: inherit;
80
+ text-decoration: none;
81
+ }
82
+ .site-header :focus-visible {
83
+ outline-color: currentColor;
84
+ }
85
+ .site-header__start,
86
+ .site-header__icons {
87
+ display: flex;
88
+ align-items: center;
89
+ }
90
+ .site-header__icons {
91
+ justify-content: flex-end;
92
+ }
93
+ .site-header__logo {
94
+ display: flex;
95
+ align-items: center;
96
+ min-height: 44px;
97
+ max-width: 50vw;
98
+ font-size: var(--text-lg);
99
+ font-weight: var(--weight-heading);
100
+ letter-spacing: -0.01em;
101
+ white-space: nowrap;
102
+ overflow: hidden;
103
+ text-overflow: ellipsis;
104
+ }
105
+ .site-header__logo img {
106
+ width: auto;
107
+ height: 36px;
108
+ object-fit: contain;
109
+ }
110
+ .site-header__search,
111
+ .site-header__account,
112
+ .site-header__wishlist,
113
+ .site-header__text-link,
114
+ .desktop-nav {
115
+ display: none;
116
+ }
117
+ .site-header__text-link {
118
+ align-items: center;
119
+ min-height: 44px;
120
+ padding-inline: var(--space-3);
121
+ font-size: var(--text-sm);
122
+ font-weight: var(--weight-medium);
123
+ }
124
+ @media (min-width: 750px) {
125
+ .site-header__account,
126
+ .site-header__wishlist {
127
+ display: inline-grid;
128
+ }
129
+ }
130
+ @media (min-width: 990px) {
131
+ .site-header__inner {
132
+ grid-template-columns: auto minmax(0, 1fr) auto;
133
+ gap: var(--space-6);
134
+ padding-inline: var(--gutter);
135
+ }
136
+ .site-header__start {
137
+ display: none;
138
+ }
139
+ .site-header__logo {
140
+ max-width: 16rem;
141
+ }
142
+ .site-header__search {
143
+ display: inline-grid;
144
+ }
145
+ .site-header__text-link,
146
+ .desktop-nav {
147
+ display: flex;
148
+ }
149
+ }
150
+
151
+ .header-cart {
152
+ position: relative;
153
+ }
154
+ .header-cart__count {
155
+ position: absolute;
156
+ top: 4px;
157
+ right: 2px;
158
+ display: grid;
159
+ place-items: center;
160
+ min-width: 1.125rem;
161
+ height: 1.125rem;
162
+ padding: 0 0.25rem;
163
+ border-radius: var(--radius-pill);
164
+ background: var(--accent);
165
+ color: var(--on-accent);
166
+ font-size: 0.6875rem;
167
+ font-weight: var(--weight-heading);
168
+ line-height: 1;
169
+ box-shadow: 0 0 0 2px var(--nav-bg);
170
+ }
171
+
172
+ /* Desktop navigation: one line; it scrolls sideways rather than wrapping when the menu is long. */
173
+ .desktop-nav {
174
+ min-width: 0;
175
+ overflow-x: auto;
176
+ scrollbar-width: none;
177
+ }
178
+ .desktop-nav::-webkit-scrollbar {
179
+ display: none;
180
+ }
181
+ .desktop-nav__list {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: var(--space-1);
185
+ margin: 0;
186
+ padding: 0;
187
+ list-style: none;
188
+ }
189
+ .desktop-nav__item {
190
+ display: flex;
191
+ align-items: center;
192
+ flex: none;
193
+ }
194
+ .desktop-nav__link {
195
+ display: flex;
196
+ align-items: center;
197
+ min-height: 44px;
198
+ padding-inline: var(--space-3);
199
+ font-size: var(--text-sm);
200
+ font-weight: var(--weight-medium);
201
+ white-space: nowrap;
202
+ border-radius: var(--radius-sm);
203
+ }
204
+ .desktop-nav__item:has(.desktop-nav__toggle) .desktop-nav__link {
205
+ padding-right: var(--space-1);
206
+ }
207
+ .desktop-nav__link:hover,
208
+ .desktop-nav__link[aria-current='page'] {
209
+ text-decoration: underline;
210
+ text-underline-offset: 0.35em;
211
+ }
212
+ .desktop-nav__toggle {
213
+ display: grid;
214
+ place-items: center;
215
+ width: 28px;
216
+ min-height: 44px;
217
+ padding: 0;
218
+ border: 0;
219
+ background: none;
220
+ color: inherit;
221
+ }
222
+ .desktop-nav__toggle[aria-expanded='true'] .icon {
223
+ transform: rotate(180deg);
224
+ }
225
+
226
+ /* A submenu: a full-width row under the header (its containing block is the header). */
227
+ .nav-panel {
228
+ position: absolute;
229
+ top: 100%;
230
+ left: 0;
231
+ right: 0;
232
+ background: var(--bg);
233
+ color: var(--fg);
234
+ border-bottom: 1px solid var(--line);
235
+ box-shadow: var(--shadow-2);
236
+ }
237
+ .nav-panel[hidden] {
238
+ display: none;
239
+ }
240
+ .nav-panel__inner {
241
+ display: flex;
242
+ flex-wrap: wrap;
243
+ gap: var(--space-5) var(--space-8);
244
+ max-width: var(--container);
245
+ margin-inline: auto;
246
+ padding: var(--space-6) var(--gutter);
247
+ }
248
+ .nav-panel__list {
249
+ display: flex;
250
+ flex-direction: column;
251
+ gap: var(--space-1);
252
+ margin: 0;
253
+ padding: 0;
254
+ list-style: none;
255
+ }
256
+ .nav-panel a {
257
+ display: inline-flex;
258
+ align-items: center;
259
+ min-height: 36px;
260
+ }
261
+ .nav-panel a:hover {
262
+ text-decoration: underline;
263
+ }
264
+ .nav-panel__column {
265
+ min-width: 12rem;
266
+ }
267
+ .nav-panel__heading {
268
+ font-weight: var(--weight-heading);
269
+ }
270
+ .nav-panel__all {
271
+ align-self: flex-start;
272
+ font-weight: var(--weight-medium);
273
+ text-decoration: underline !important;
274
+ }
275
+ .nav-panel--mega .nav-panel__all {
276
+ flex-basis: 100%;
277
+ }
278
+
279
+ /* Mobile menu (a left drawer). */
280
+ .mobile-menu .drawer__body {
281
+ padding-inline: 0;
282
+ }
283
+ .mobile-menu__list,
284
+ .mobile-menu__secondary {
285
+ margin: 0;
286
+ padding: 0;
287
+ list-style: none;
288
+ }
289
+ .mobile-menu__item {
290
+ display: flex;
291
+ align-items: center;
292
+ }
293
+ .mobile-menu__link {
294
+ flex: 1;
295
+ display: flex;
296
+ align-items: center;
297
+ min-height: 52px;
298
+ padding-inline: var(--space-5);
299
+ font-size: var(--text-lg);
300
+ font-weight: var(--weight-medium);
301
+ text-decoration: none;
302
+ }
303
+ .mobile-menu__open {
304
+ display: grid;
305
+ place-items: center;
306
+ width: 52px;
307
+ min-height: 52px;
308
+ padding: 0;
309
+ border: 0;
310
+ border-left: 1px solid var(--line);
311
+ border-radius: 0;
312
+ background: none;
313
+ }
314
+ .mobile-menu__level {
315
+ display: flex;
316
+ flex-direction: column;
317
+ gap: var(--space-2);
318
+ padding: 0 var(--space-5) var(--space-3);
319
+ border-bottom: 1px solid var(--line);
320
+ margin-bottom: var(--space-2);
321
+ }
322
+ .mobile-menu__back {
323
+ align-self: flex-start;
324
+ display: inline-flex;
325
+ align-items: center;
326
+ gap: var(--space-1);
327
+ padding: 0;
328
+ border: 0;
329
+ background: none;
330
+ color: var(--muted);
331
+ }
332
+ .mobile-menu__current {
333
+ display: flex;
334
+ flex-direction: column;
335
+ font-size: var(--text-xl);
336
+ font-weight: var(--weight-heading);
337
+ text-decoration: none;
338
+ }
339
+ .mobile-menu__current .muted {
340
+ font-size: var(--text-sm);
341
+ font-weight: var(--weight-regular);
342
+ text-decoration: underline;
343
+ }
344
+ .mobile-menu__secondary {
345
+ margin-top: var(--space-4);
346
+ padding-top: var(--space-4);
347
+ border-top: 1px solid var(--line);
348
+ }
349
+ .mobile-menu__secondary a {
350
+ display: flex;
351
+ align-items: center;
352
+ min-height: 44px;
353
+ padding-inline: var(--space-5);
354
+ color: var(--muted);
355
+ text-decoration: none;
356
+ }
357
+
358
+ /* Footer */
359
+ .site-footer {
360
+ margin-top: auto;
361
+ border-top: 1px solid var(--line);
362
+ background: var(--subtle);
363
+ font-size: var(--text-sm);
364
+ }
365
+ .site-footer__inner {
366
+ display: flex;
367
+ flex-direction: column;
368
+ gap: var(--space-6);
369
+ max-width: var(--container);
370
+ margin-inline: auto;
371
+ padding: var(--space-7) var(--gutter) var(--space-5);
372
+ }
373
+ .site-footer__columns {
374
+ display: grid;
375
+ grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
376
+ gap: var(--space-6);
377
+ }
378
+ .site-footer__heading {
379
+ margin-bottom: var(--space-3);
380
+ font-size: var(--text-base);
381
+ }
382
+ .site-footer__list,
383
+ .site-footer__socials,
384
+ .site-footer__policies {
385
+ margin: 0;
386
+ padding: 0;
387
+ list-style: none;
388
+ }
389
+ /* The row's spacing is the link's own padding: the whole row is the tap target. */
390
+ .site-footer__list a,
391
+ .site-footer__list .site-footer__contact {
392
+ display: inline-flex;
393
+ padding-block: var(--space-2);
394
+ }
395
+ .site-footer a {
396
+ color: var(--muted);
397
+ text-decoration: none;
398
+ }
399
+ .site-footer a:hover {
400
+ color: var(--fg);
401
+ text-decoration: underline;
402
+ }
403
+ .site-footer__contact {
404
+ display: inline-flex;
405
+ align-items: flex-start;
406
+ gap: var(--space-2);
407
+ color: var(--muted);
408
+ }
409
+ .site-footer__contact .icon {
410
+ margin-top: 0.15em;
411
+ }
412
+ .site-footer__socials {
413
+ display: flex;
414
+ flex-wrap: wrap;
415
+ gap: var(--space-2);
416
+ margin-top: var(--space-3);
417
+ }
418
+ .site-footer__socials a {
419
+ display: inline-flex;
420
+ align-items: center;
421
+ min-height: 44px;
422
+ padding-inline: var(--space-4);
423
+ border: 1px solid var(--line-strong);
424
+ border-radius: var(--radius-pill);
425
+ }
426
+ .site-footer__text {
427
+ max-width: 65ch;
428
+ color: var(--muted);
429
+ }
430
+ .site-footer__bottom {
431
+ display: flex;
432
+ flex-wrap: wrap;
433
+ justify-content: space-between;
434
+ gap: var(--space-3);
435
+ padding-top: var(--space-5);
436
+ border-top: 1px solid var(--line);
437
+ color: var(--muted);
438
+ }
439
+ .site-footer__policies {
440
+ display: flex;
441
+ flex-wrap: wrap;
442
+ gap: var(--space-2) var(--space-4);
443
+ }
444
+
445
+ /* A page's sections (home, content pages): one rhythm between them. */
446
+ .page-sections {
447
+ display: flex;
448
+ flex-direction: column;
449
+ gap: var(--section-gap);
450
+ }
451
+ /* A section with nothing to show yet renders nothing, but ThemeSections still wraps it. */
452
+ [data-section-id]:empty {
453
+ display: none;
454
+ }
455
+ }