@shopify/create-hydrogen 1.0.0-alpha.23 → 1.0.4
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/CHANGELOG.md +256 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +7 -0
- package/dist/commands/init.js +157943 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.js +151598 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -16
- package/templates/template-hydrogen-default/.devcontainer/devcontainer.json +18 -0
- package/templates/template-hydrogen-default/.eslintrc.js +3 -0
- package/templates/template-hydrogen-default/.gitignore +7 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/.stylelintrc.js +1 -1
- package/templates/template-hydrogen-default/.vscode/extensions.json +8 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/README.md +11 -2
- package/{template-hydrogen → templates/template-hydrogen-default}/_gitignore +0 -0
- package/templates/template-hydrogen-default/index.html +20 -0
- package/templates/template-hydrogen-default/package.json.liquid +48 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/postcss.config.js +0 -0
- package/templates/template-hydrogen-default/public/favicon.ico +0 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/shopify.config.js +1 -2
- package/templates/template-hydrogen-default/src/App.server.jsx +27 -0
- package/templates/template-hydrogen-default/src/components/Button.client.jsx +65 -0
- package/templates/template-hydrogen-default/src/components/Cart.client.jsx +265 -0
- package/templates/template-hydrogen-default/src/components/CartIcon.jsx +33 -0
- package/templates/template-hydrogen-default/src/components/CartIconWithItems.client.jsx +28 -0
- package/templates/template-hydrogen-default/src/components/CartProvider.client.jsx +35 -0
- package/templates/template-hydrogen-default/src/components/CartToggle.client.jsx +30 -0
- package/templates/template-hydrogen-default/src/components/CartUIProvider.client.jsx +45 -0
- package/templates/template-hydrogen-default/src/components/CountrySelector.client.jsx +116 -0
- package/templates/template-hydrogen-default/src/components/DefaultSeo.server.jsx +36 -0
- package/templates/template-hydrogen-default/src/components/FeaturedCollection.jsx +26 -0
- package/templates/template-hydrogen-default/src/components/Footer.server.jsx +103 -0
- package/templates/template-hydrogen-default/src/components/Gallery.client.jsx +66 -0
- package/templates/template-hydrogen-default/src/components/Header.client.jsx +62 -0
- package/templates/template-hydrogen-default/src/components/Layout.server.jsx +86 -0
- package/templates/template-hydrogen-default/src/components/LoadMoreProducts.client.jsx +56 -0
- package/templates/template-hydrogen-default/src/components/LoadingFallback.jsx +26 -0
- package/templates/template-hydrogen-default/src/components/MobileCountrySelector.client.jsx +64 -0
- package/templates/template-hydrogen-default/src/components/MobileNavigation.client.jsx +98 -0
- package/templates/template-hydrogen-default/src/components/MoneyCompareAtPrice.client.jsx +14 -0
- package/templates/template-hydrogen-default/src/components/MoneyPrice.client.jsx +15 -0
- package/templates/template-hydrogen-default/src/components/Navigation.client.jsx +23 -0
- package/templates/template-hydrogen-default/src/components/NotFound.server.jsx +93 -0
- package/templates/template-hydrogen-default/src/components/OpenIcon.jsx +33 -0
- package/templates/template-hydrogen-default/src/components/ProductCard.jsx +50 -0
- package/templates/template-hydrogen-default/src/components/ProductDetails.client.jsx +233 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/src/components/ProductOptions.client.jsx +7 -4
- package/templates/template-hydrogen-default/src/components/Welcome.server.jsx +188 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/src/index.css +31 -0
- package/templates/template-hydrogen-default/src/pages/collections/[handle].server.jsx +105 -0
- package/templates/template-hydrogen-default/src/pages/index.server.jsx +241 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/src/pages/pages/[handle].server.jsx +14 -5
- package/templates/template-hydrogen-default/src/pages/products/[handle].server.jsx +66 -0
- package/templates/template-hydrogen-default/src/pages/redirect.server.jsx +4 -0
- package/templates/template-hydrogen-default/src/pages/robots.txt.server.js +40 -0
- package/templates/template-hydrogen-default/src/pages/sitemap.xml.server.jsx +151 -0
- package/templates/template-hydrogen-default/src/routes/collections/[handle].server.jsx +105 -0
- package/templates/template-hydrogen-default/src/routes/index.server.jsx +241 -0
- package/templates/template-hydrogen-default/src/routes/pages/[handle].server.jsx +37 -0
- package/templates/template-hydrogen-default/src/routes/products/[handle].server.jsx +66 -0
- package/templates/template-hydrogen-default/src/routes/redirect.server.jsx +4 -0
- package/templates/template-hydrogen-default/src/routes/robots.txt.server.js +40 -0
- package/templates/template-hydrogen-default/src/routes/sitemap.xml.server.jsx +151 -0
- package/templates/template-hydrogen-default/tailwind.config.js +26 -0
- package/{template-hydrogen → templates/template-hydrogen-default}/vite.config.js +1 -0
- package/templates/template-hydrogen-minimal/README.md +8 -0
- package/templates/template-hydrogen-minimal/package.json +14 -0
- package/index.js +0 -201
- package/scripts/tmp-copy-template-from-dev.js +0 -21
- package/scripts/utils.js +0 -29
- package/template-hydrogen/.eslintrc.js +0 -41
- package/template-hydrogen/.vscode/extensions.json +0 -3
- package/template-hydrogen/Dockerfile +0 -15
- package/template-hydrogen/index.html +0 -14
- package/template-hydrogen/package.json +0 -43
- package/template-hydrogen/server.js +0 -40
- package/template-hydrogen/src/App.server.jsx +0 -42
- package/template-hydrogen/src/components/Cart.client.jsx +0 -287
- package/template-hydrogen/src/components/CartProvider.client.jsx +0 -15
- package/template-hydrogen/src/components/DefaultSeo.server.jsx +0 -22
- package/template-hydrogen/src/components/Footer.jsx +0 -12
- package/template-hydrogen/src/components/Gallery.client.jsx +0 -36
- package/template-hydrogen/src/components/Header.client.jsx +0 -46
- package/template-hydrogen/src/components/HightlightedProduct.client.jsx +0 -54
- package/template-hydrogen/src/components/Layout.client.jsx +0 -61
- package/template-hydrogen/src/components/MediaPlaceholder.jsx +0 -21
- package/template-hydrogen/src/components/NotFound.server.jsx +0 -104
- package/template-hydrogen/src/components/ProductCard.client.jsx +0 -39
- package/template-hydrogen/src/components/ProductDetails.client.jsx +0 -184
- package/template-hydrogen/src/components/Seo.client.jsx +0 -75
- package/template-hydrogen/src/entry-client.jsx +0 -12
- package/template-hydrogen/src/entry-server.jsx +0 -7
- package/template-hydrogen/src/favicon.svg +0 -15
- package/template-hydrogen/src/pages/Index.server.jsx +0 -186
- package/template-hydrogen/src/pages/blogs/[handle]/[articleHandle].server.jsx +0 -49
- package/template-hydrogen/src/pages/blogs/[handle].server.jsx +0 -76
- package/template-hydrogen/src/pages/collections/[handle].server.jsx +0 -69
- package/template-hydrogen/src/pages/products/[handle].server.jsx +0 -56
- package/template-hydrogen/src/pages/search.server.jsx +0 -107
- package/template-hydrogen/src/pages/sitemap.xml.server.jsx +0 -64
- package/template-hydrogen/tailwind.config.js +0 -9
- package/template-hydrogen/worker.js +0 -22
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flattenConnection,
|
|
3
|
+
useProduct,
|
|
4
|
+
useParsedMetafields,
|
|
5
|
+
ProductProvider,
|
|
6
|
+
ProductTitle,
|
|
7
|
+
ProductDescription,
|
|
8
|
+
ProductPrice,
|
|
9
|
+
AddToCartButton,
|
|
10
|
+
BuyNowButton,
|
|
11
|
+
} from '@shopify/hydrogen/client';
|
|
12
|
+
import ProductOptions from './ProductOptions.client';
|
|
13
|
+
import Gallery from './Gallery.client';
|
|
14
|
+
import {
|
|
15
|
+
BUTTON_PRIMARY_CLASSES,
|
|
16
|
+
BUTTON_SECONDARY_CLASSES,
|
|
17
|
+
} from './Button.client';
|
|
18
|
+
|
|
19
|
+
function AddToCartMarkup() {
|
|
20
|
+
const {selectedVariant} = useProduct();
|
|
21
|
+
const isOutOfStock = !selectedVariant.availableForSale;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="space-y-2 mb-8">
|
|
25
|
+
<AddToCartButton
|
|
26
|
+
className={BUTTON_PRIMARY_CLASSES}
|
|
27
|
+
disabled={isOutOfStock}
|
|
28
|
+
>
|
|
29
|
+
{isOutOfStock ? 'Out of stock' : 'Add to bag'}
|
|
30
|
+
</AddToCartButton>
|
|
31
|
+
{isOutOfStock ? (
|
|
32
|
+
<p className="text-black text-center">Available in 2-3 weeks</p>
|
|
33
|
+
) : (
|
|
34
|
+
<BuyNowButton
|
|
35
|
+
variantId={selectedVariant.id}
|
|
36
|
+
className={BUTTON_SECONDARY_CLASSES}
|
|
37
|
+
>
|
|
38
|
+
Buy it now
|
|
39
|
+
</BuyNowButton>
|
|
40
|
+
)}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function SizeChart() {
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<h3
|
|
49
|
+
className="text-xl text-black font-semibold mt-8 mb-4"
|
|
50
|
+
id="size-chart"
|
|
51
|
+
>
|
|
52
|
+
Size Chart
|
|
53
|
+
</h3>
|
|
54
|
+
<table className="min-w-full table-fixed text-sm text-center bg-white">
|
|
55
|
+
<thead>
|
|
56
|
+
<tr className="bg-black text-white">
|
|
57
|
+
<th className="w-1/4 py-2 px-4 font-normal">Board Size</th>
|
|
58
|
+
<th className="w-1/4 py-2 px-4 font-normal">154</th>
|
|
59
|
+
<th className="w-1/4 py-2 px-4 font-normal">158</th>
|
|
60
|
+
</tr>
|
|
61
|
+
</thead>
|
|
62
|
+
<tbody>
|
|
63
|
+
<tr>
|
|
64
|
+
<td className="p-3 border border-black">Weight Range</td>
|
|
65
|
+
<td className="p-3 border border-black">120-180 lbs. /54-82kg</td>
|
|
66
|
+
<td className="p-3 border border-black">150-200 lbs. /68-91 kg</td>
|
|
67
|
+
</tr>
|
|
68
|
+
<tr>
|
|
69
|
+
<td className="p-3 border border-black">Waist Width</td>
|
|
70
|
+
<td className="p-3 border border-black">246mm</td>
|
|
71
|
+
<td className="p-3 border border-black">255mm</td>
|
|
72
|
+
</tr>
|
|
73
|
+
<tr>
|
|
74
|
+
<td className="p-3 border border-black">Stance Width</td>
|
|
75
|
+
<td className="p-3 border border-black">-40</td>
|
|
76
|
+
<td className="p-3 border border-black">-40</td>
|
|
77
|
+
</tr>
|
|
78
|
+
<tr>
|
|
79
|
+
<td className="p-3 border border-black">Binding Sizes</td>
|
|
80
|
+
<td className="p-3 border border-black">
|
|
81
|
+
Men’s S/M, Women’s S/M
|
|
82
|
+
</td>
|
|
83
|
+
<td className="p-3 border border-black">
|
|
84
|
+
Men’s L, Women’s L
|
|
85
|
+
</td>
|
|
86
|
+
</tr>
|
|
87
|
+
</tbody>
|
|
88
|
+
</table>
|
|
89
|
+
</>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default function ProductDetails({product}) {
|
|
94
|
+
const initialVariant = flattenConnection(product.variants)[0];
|
|
95
|
+
|
|
96
|
+
const productMetafields = useParsedMetafields(product.metafields);
|
|
97
|
+
const sizeChartMetafield = productMetafields.find(
|
|
98
|
+
(metafield) =>
|
|
99
|
+
metafield.namespace === 'my_fields' && metafield.key === 'size_chart',
|
|
100
|
+
);
|
|
101
|
+
const sustainableMetafield = productMetafields.find(
|
|
102
|
+
(metafield) =>
|
|
103
|
+
metafield.namespace === 'my_fields' && metafield.key === 'sustainable',
|
|
104
|
+
);
|
|
105
|
+
const lifetimeWarrantyMetafield = productMetafields.find(
|
|
106
|
+
(metafield) =>
|
|
107
|
+
metafield.namespace === 'my_fields' &&
|
|
108
|
+
metafield.key === 'lifetime_warranty',
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<>
|
|
113
|
+
<ProductProvider data={product} initialVariantId={initialVariant.id}>
|
|
114
|
+
<div className="grid grid-cols-1 md:grid-cols-[2fr,1fr] gap-x-8 my-16">
|
|
115
|
+
<div className="md:hidden mt-5 mb-8">
|
|
116
|
+
<ProductTitle
|
|
117
|
+
as="h1"
|
|
118
|
+
className="text-4xl font-bold text-black mb-4"
|
|
119
|
+
/>
|
|
120
|
+
{product.vendor && (
|
|
121
|
+
<div className="text-sm font-medium mb-2 text-gray-900">
|
|
122
|
+
{product.vendor}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
<span />
|
|
126
|
+
<div className="flex justify-between md:block">
|
|
127
|
+
<ProductPrice
|
|
128
|
+
className="text-gray-500 line-through text-lg font-semibold"
|
|
129
|
+
priceType="compareAt"
|
|
130
|
+
variantId={initialVariant.id}
|
|
131
|
+
/>
|
|
132
|
+
<ProductPrice
|
|
133
|
+
className="text-gray-900 text-lg font-semibold"
|
|
134
|
+
variantId={initialVariant.id}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<Gallery />
|
|
140
|
+
|
|
141
|
+
<div>
|
|
142
|
+
<div className="hidden md:block">
|
|
143
|
+
<ProductTitle
|
|
144
|
+
as="h1"
|
|
145
|
+
className="text-5xl font-bold text-black mb-4"
|
|
146
|
+
/>
|
|
147
|
+
{product.vendor && (
|
|
148
|
+
<div className="text-sm font-medium mb-2 text-gray-900">
|
|
149
|
+
{product.vendor}
|
|
150
|
+
</div>
|
|
151
|
+
)}
|
|
152
|
+
<ProductPrice
|
|
153
|
+
className="text-gray-500 line-through text-lg font-semibold"
|
|
154
|
+
priceType="compareAt"
|
|
155
|
+
variantId={initialVariant.id}
|
|
156
|
+
/>
|
|
157
|
+
<ProductPrice
|
|
158
|
+
className="text-gray-900 text-lg font-semibold"
|
|
159
|
+
variantId={initialVariant.id}
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
{/* Product Options */}
|
|
163
|
+
<div className="mt-8">
|
|
164
|
+
<ProductOptions />
|
|
165
|
+
{sizeChartMetafield?.value && (
|
|
166
|
+
<a
|
|
167
|
+
href="#size-chart"
|
|
168
|
+
className="block underline text-gray-500 text-sm tracking-wide my-4"
|
|
169
|
+
>
|
|
170
|
+
Size Chart
|
|
171
|
+
</a>
|
|
172
|
+
)}
|
|
173
|
+
<AddToCartMarkup />
|
|
174
|
+
<div className="flex items space-x-4">
|
|
175
|
+
{sustainableMetafield?.value && (
|
|
176
|
+
<span className="flex items-center mb-8">
|
|
177
|
+
<svg
|
|
178
|
+
width="24"
|
|
179
|
+
height="24"
|
|
180
|
+
viewBox="0 0 24 24"
|
|
181
|
+
fill="none"
|
|
182
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
183
|
+
className="stroke-current text-blue-600 mr-3"
|
|
184
|
+
>
|
|
185
|
+
<path
|
|
186
|
+
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364-.7071-.7071M6.34315 6.34315l-.70711-.70711m12.72796.00005-.7071.70711M6.3432 17.6569l-.70711.7071M16 12c0 2.2091-1.7909 4-4 4-2.20914 0-4-1.7909-4-4 0-2.20914 1.79086-4 4-4 2.2091 0 4 1.79086 4 4Z"
|
|
187
|
+
strokeWidth="2"
|
|
188
|
+
strokeLinecap="round"
|
|
189
|
+
strokeLinejoin="round"
|
|
190
|
+
/>
|
|
191
|
+
</svg>
|
|
192
|
+
<span className="text-sm text-gray-900 font-medium">
|
|
193
|
+
Sustainable Material
|
|
194
|
+
</span>
|
|
195
|
+
</span>
|
|
196
|
+
)}
|
|
197
|
+
{lifetimeWarrantyMetafield?.value && (
|
|
198
|
+
<span className="flex items-center mb-8">
|
|
199
|
+
<svg
|
|
200
|
+
width="24"
|
|
201
|
+
height="24"
|
|
202
|
+
viewBox="0 0 24 24"
|
|
203
|
+
fill="none"
|
|
204
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
205
|
+
className="stroke-current text-blue-600 mr-3"
|
|
206
|
+
>
|
|
207
|
+
<path
|
|
208
|
+
d="M9 12L11 14L15 10M20.6179 5.98434C20.4132 5.99472 20.2072 5.99997 20 5.99997C16.9265 5.99997 14.123 4.84453 11.9999 2.94434C9.87691 4.84446 7.07339 5.99985 4 5.99985C3.79277 5.99985 3.58678 5.9946 3.38213 5.98422C3.1327 6.94783 3 7.95842 3 9.00001C3 14.5915 6.82432 19.2898 12 20.622C17.1757 19.2898 21 14.5915 21 9.00001C21 7.95847 20.8673 6.94791 20.6179 5.98434Z"
|
|
209
|
+
strokeWidth="2"
|
|
210
|
+
strokeLinecap="round"
|
|
211
|
+
strokeLinejoin="round"
|
|
212
|
+
/>
|
|
213
|
+
</svg>
|
|
214
|
+
<span className="text-sm text-gray-900 font-medium">
|
|
215
|
+
Lifetime Warranty
|
|
216
|
+
</span>
|
|
217
|
+
</span>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
{/* Product Description */}
|
|
222
|
+
<ProductDescription className="prose border-t border-gray-200 pt-6 text-black text-md" />
|
|
223
|
+
{sizeChartMetafield?.value && (
|
|
224
|
+
<div className="border-t border-gray-200">
|
|
225
|
+
<SizeChart />
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</ProductProvider>
|
|
231
|
+
</>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import {useProduct} from '@shopify/hydrogen/client';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A client component that tracks a selected variant and/or selling plan state, as well as callbacks for modifying the state
|
|
5
|
+
*/
|
|
3
6
|
export default function ProductOptions() {
|
|
4
7
|
const {options, setSelectedOption, selectedOptions} = useProduct();
|
|
5
8
|
|
|
@@ -7,11 +10,11 @@ export default function ProductOptions() {
|
|
|
7
10
|
<>
|
|
8
11
|
{options.map(({name, values}) => {
|
|
9
12
|
return (
|
|
10
|
-
<fieldset key={name} className="
|
|
11
|
-
<legend className="mb-
|
|
13
|
+
<fieldset key={name} className="mt-8">
|
|
14
|
+
<legend className="mb-4 text-xl font-medium text-gray-900">
|
|
12
15
|
{name}
|
|
13
16
|
</legend>
|
|
14
|
-
<div className="flex items-center flex-wrap gap-
|
|
17
|
+
<div className="flex items-center flex-wrap gap-4">
|
|
15
18
|
{values.map((value) => {
|
|
16
19
|
const checked = selectedOptions[name] === value;
|
|
17
20
|
const id = `option-${name}-${value}`;
|
|
@@ -28,7 +31,7 @@ export default function ProductOptions() {
|
|
|
28
31
|
onChange={() => setSelectedOption(name, value)}
|
|
29
32
|
/>
|
|
30
33
|
<div
|
|
31
|
-
className={`p-2 border
|
|
34
|
+
className={`p-2 border cursor-pointer rounded text-sm md:text-md ${
|
|
32
35
|
checked ? 'bg-gray-900 text-white' : 'text-gray-900'
|
|
33
36
|
}`}
|
|
34
37
|
>
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import {useShopQuery, flattenConnection, Link} from '@shopify/hydrogen';
|
|
2
|
+
import gql from 'graphql-tag';
|
|
3
|
+
import {Suspense} from 'react';
|
|
4
|
+
|
|
5
|
+
function ExternalIcon() {
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
className="ml-3"
|
|
9
|
+
width="15"
|
|
10
|
+
height="14"
|
|
11
|
+
viewBox="0 0 15 14"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
fill="currentColor"
|
|
14
|
+
>
|
|
15
|
+
<path d="M8.11963 0.000976562C7.56734 0.000976562 7.11963 0.448692 7.11963 1.00098C7.11963 1.55326 7.56734 2.00098 8.11963 2.00098H10.7054L4.41252 8.29387C4.022 8.68439 4.022 9.31756 4.41252 9.70808C4.80305 10.0986 5.43621 10.0986 5.82674 9.70808L12.1196 3.41519V6.00098C12.1196 6.55326 12.5673 7.00098 13.1196 7.00098C13.6719 7.00098 14.1196 6.55326 14.1196 6.00098V1.00098C14.1196 0.448692 13.6719 0.000976562 13.1196 0.000976562H8.11963Z" />
|
|
16
|
+
<path d="M2.11963 2.00098C1.01506 2.00098 0.119629 2.89641 0.119629 4.00098V12.001C0.119629 13.1055 1.01506 14.001 2.11963 14.001H10.1196C11.2242 14.001 12.1196 13.1055 12.1196 12.001V9.00098C12.1196 8.44869 11.6719 8.00098 11.1196 8.00098C10.5673 8.00098 10.1196 8.44869 10.1196 9.00098V12.001H2.11963V4.00098L5.11963 4.00098C5.67191 4.00098 6.11963 3.55326 6.11963 3.00098C6.11963 2.44869 5.67191 2.00098 5.11963 2.00098H2.11963Z" />
|
|
17
|
+
</svg>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function DocsButton({url, label}) {
|
|
22
|
+
return (
|
|
23
|
+
<a
|
|
24
|
+
href={url}
|
|
25
|
+
target="_blank"
|
|
26
|
+
className="bg-white shadow py-2 px-5 rounded-full inline-flex items-center hover:opacity-80"
|
|
27
|
+
rel="noreferrer"
|
|
28
|
+
>
|
|
29
|
+
{label}
|
|
30
|
+
<ExternalIcon />
|
|
31
|
+
</a>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function BoxFallback() {
|
|
36
|
+
return (
|
|
37
|
+
<div className="bg-white p-12 shadow-xl rounded-xl text-gray-900 h-60"></div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function StorefrontInfo() {
|
|
42
|
+
const {data} = useShopQuery({query: QUERY, preload: true});
|
|
43
|
+
const shopName = data ? data.shop.name : '';
|
|
44
|
+
const products = data && flattenConnection(data.products);
|
|
45
|
+
const collections = data && flattenConnection(data.collections);
|
|
46
|
+
const totalProducts = products && products.length;
|
|
47
|
+
const totalCollections = collections && collections.length;
|
|
48
|
+
|
|
49
|
+
const pluralize = (count, noun, suffix = 's') =>
|
|
50
|
+
`${count} ${noun}${count === 1 ? '' : suffix}`;
|
|
51
|
+
return (
|
|
52
|
+
<div className="bg-white p-12 shadow-xl rounded-xl text-gray-900">
|
|
53
|
+
<p className="text-md font-medium uppercase mb-4">Connected Storefront</p>
|
|
54
|
+
<h2 className="text-2xl font-bold mb-4">{shopName}</h2>
|
|
55
|
+
<p className="text-md">
|
|
56
|
+
{pluralize(totalProducts, 'Product')}
|
|
57
|
+
{', '}
|
|
58
|
+
{pluralize(totalCollections, 'Collection')}
|
|
59
|
+
</p>
|
|
60
|
+
{totalProducts === 0 && totalCollections === 0 && (
|
|
61
|
+
<div className="py-2 px-3 bg-red-100 text-md">
|
|
62
|
+
Use the{' '}
|
|
63
|
+
<a
|
|
64
|
+
href="https://shopify.dev/apps/tools/cli/getting-started"
|
|
65
|
+
className="text-primary font-mono font-bold underline"
|
|
66
|
+
target="_blank"
|
|
67
|
+
rel="noreferrer"
|
|
68
|
+
>
|
|
69
|
+
Shopify CLI
|
|
70
|
+
</a>{' '}
|
|
71
|
+
to populate sample products and collections.
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
<hr className="my-4" />
|
|
75
|
+
<a
|
|
76
|
+
href="https://shopify.dev/custom-storefronts/hydrogen/getting-started/create#step-2-update-information-about-your-shopify-storefront"
|
|
77
|
+
className="text-md inline-flex items-center text-blue-700 font-medium hover:underline"
|
|
78
|
+
target="_blank"
|
|
79
|
+
rel="noreferrer"
|
|
80
|
+
>
|
|
81
|
+
Change your storefront access token
|
|
82
|
+
<ExternalIcon />
|
|
83
|
+
</a>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function TemplateLinks() {
|
|
89
|
+
const {data} = useShopQuery({query: QUERY, preload: true});
|
|
90
|
+
const products = data && flattenConnection(data.products);
|
|
91
|
+
const collections = data && flattenConnection(data.collections);
|
|
92
|
+
|
|
93
|
+
const firstProduct = products && products.length ? products[0].handle : '';
|
|
94
|
+
const firstCollection = collections[0] ? collections[0].handle : '';
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div className="bg-white p-12 md:p-12 shadow-xl rounded-xl text-gray-900">
|
|
98
|
+
<p className="text-md font-medium uppercase mb-4">
|
|
99
|
+
Explore the templates
|
|
100
|
+
</p>
|
|
101
|
+
<ul>
|
|
102
|
+
<li className="mb-4">
|
|
103
|
+
<Link
|
|
104
|
+
to={`/collections/${firstCollection}`}
|
|
105
|
+
className="text-md font-medium text-blue-700 hover:underline"
|
|
106
|
+
>
|
|
107
|
+
Collection template
|
|
108
|
+
</Link>
|
|
109
|
+
</li>
|
|
110
|
+
<li className="mb-4">
|
|
111
|
+
<Link
|
|
112
|
+
to={`/products/${firstProduct}`}
|
|
113
|
+
className="text-md font-medium text-blue-700 hover:underline"
|
|
114
|
+
>
|
|
115
|
+
Product template
|
|
116
|
+
</Link>
|
|
117
|
+
</li>
|
|
118
|
+
<li>
|
|
119
|
+
<Link
|
|
120
|
+
to="/error-page"
|
|
121
|
+
className="text-md font-medium text-blue-700 hover:underline"
|
|
122
|
+
>
|
|
123
|
+
404 template
|
|
124
|
+
</Link>
|
|
125
|
+
</li>
|
|
126
|
+
</ul>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A server component that displays the content on the homepage of the Hydrogen app
|
|
133
|
+
*/
|
|
134
|
+
export default function Welcome() {
|
|
135
|
+
return (
|
|
136
|
+
<div className="text-gray-900 pt-16 rounded-[40px] my-16 px-4 xl:px-12 bg-gradient-to-b from-white -mx-4 xl:-mx-12">
|
|
137
|
+
<div className="text-center mb-16">
|
|
138
|
+
<h1 className="font-extrabold mb-4 text-5xl md:text-7xl">
|
|
139
|
+
Hello, Hydrogen
|
|
140
|
+
</h1>
|
|
141
|
+
<p className="text-lg mb-8">
|
|
142
|
+
Welcome to your custom storefront. Let’s get building.
|
|
143
|
+
</p>
|
|
144
|
+
<div className="flex flex-col lg:flex-row justify-center items-center gap-8 text-gray-700">
|
|
145
|
+
<DocsButton
|
|
146
|
+
url="https://shopify.dev/custom-storefronts/hydrogen"
|
|
147
|
+
label="Browse Hydrogen documentation"
|
|
148
|
+
/>
|
|
149
|
+
<DocsButton url="/graphql" label="Open the GraphiQL explorer" />
|
|
150
|
+
<DocsButton
|
|
151
|
+
url="https://github.com/Shopify/hydrogen-examples"
|
|
152
|
+
label="Explore Hydrogen examples"
|
|
153
|
+
/>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16">
|
|
157
|
+
<Suspense fallback={<BoxFallback />}>
|
|
158
|
+
<StorefrontInfo />
|
|
159
|
+
</Suspense>
|
|
160
|
+
<Suspense fallback={<BoxFallback />}>
|
|
161
|
+
<TemplateLinks />
|
|
162
|
+
</Suspense>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const QUERY = gql`
|
|
169
|
+
query welcomeContent {
|
|
170
|
+
shop {
|
|
171
|
+
name
|
|
172
|
+
}
|
|
173
|
+
products(first: 250) {
|
|
174
|
+
edges {
|
|
175
|
+
node {
|
|
176
|
+
handle
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
collections(first: 250) {
|
|
181
|
+
edges {
|
|
182
|
+
node {
|
|
183
|
+
handle
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
@tailwind components;
|
|
3
3
|
@tailwind utilities;
|
|
4
4
|
|
|
5
|
+
@layer utilities {
|
|
6
|
+
.scroll-snap-x {
|
|
7
|
+
scroll-snap-type: x mandatory;
|
|
8
|
+
}
|
|
9
|
+
.snap-start {
|
|
10
|
+
scroll-snap-align: start;
|
|
11
|
+
}
|
|
12
|
+
.snap-smooth {
|
|
13
|
+
scroll-behavior: smooth;
|
|
14
|
+
}
|
|
15
|
+
.snap-px-4 {
|
|
16
|
+
scroll-padding-left: 1rem;
|
|
17
|
+
scroll-padding-right: 1rem;
|
|
18
|
+
}
|
|
19
|
+
.no-scrollbar::-webkit-scrollbar {
|
|
20
|
+
display: none;
|
|
21
|
+
}
|
|
22
|
+
.no-scrollbar {
|
|
23
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
24
|
+
scrollbar-width: none; /* Firefox */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
* {
|
|
29
|
+
font-variant-ligatures: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
html {
|
|
33
|
+
scroll-padding-top: 10rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
5
36
|
model-viewer::part(default-progress-mask) {
|
|
6
37
|
display: none;
|
|
7
38
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MediaFileFragment,
|
|
3
|
+
ProductProviderFragment,
|
|
4
|
+
useShopQuery,
|
|
5
|
+
flattenConnection,
|
|
6
|
+
RawHtml,
|
|
7
|
+
Seo,
|
|
8
|
+
} from '@shopify/hydrogen';
|
|
9
|
+
import gql from 'graphql-tag';
|
|
10
|
+
|
|
11
|
+
import LoadMoreProducts from '../../components/LoadMoreProducts.client';
|
|
12
|
+
import Layout from '../../components/Layout.server';
|
|
13
|
+
import ProductCard from '../../components/ProductCard';
|
|
14
|
+
import NotFound from '../../components/NotFound.server';
|
|
15
|
+
|
|
16
|
+
export default function Collection({
|
|
17
|
+
country = {isoCode: 'US'},
|
|
18
|
+
collectionProductCount = 24,
|
|
19
|
+
params,
|
|
20
|
+
}) {
|
|
21
|
+
const {handle} = params;
|
|
22
|
+
const {data} = useShopQuery({
|
|
23
|
+
query: QUERY,
|
|
24
|
+
variables: {
|
|
25
|
+
handle,
|
|
26
|
+
country: country.isoCode,
|
|
27
|
+
numProducts: collectionProductCount,
|
|
28
|
+
},
|
|
29
|
+
preload: true,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (data?.collection == null) {
|
|
33
|
+
return <NotFound />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const collection = data.collection;
|
|
37
|
+
const products = flattenConnection(collection.products);
|
|
38
|
+
const hasNextPage = data.collection.products.pageInfo.hasNextPage;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Layout>
|
|
42
|
+
{/* the seo object will be expose in API version 2022-04 or later */}
|
|
43
|
+
<Seo type="collection" data={{seo: {}, ...collection}} />
|
|
44
|
+
<h1 className="font-bold text-4xl md:text-5xl text-gray-900 mb-6 mt-6">
|
|
45
|
+
{collection.title}
|
|
46
|
+
</h1>
|
|
47
|
+
<RawHtml string={collection.descriptionHtml} className="text-lg" />
|
|
48
|
+
<p className="text-sm text-gray-500 mt-5 mb-5">
|
|
49
|
+
{products.length} {products.length > 1 ? 'products' : 'product'}
|
|
50
|
+
</p>
|
|
51
|
+
<ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-16">
|
|
52
|
+
{products.map((product) => (
|
|
53
|
+
<li key={product.id}>
|
|
54
|
+
<ProductCard product={product} />
|
|
55
|
+
</li>
|
|
56
|
+
))}
|
|
57
|
+
</ul>
|
|
58
|
+
{hasNextPage && (
|
|
59
|
+
<LoadMoreProducts startingCount={collectionProductCount} />
|
|
60
|
+
)}
|
|
61
|
+
</Layout>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const QUERY = gql`
|
|
66
|
+
query CollectionDetails(
|
|
67
|
+
$handle: String!
|
|
68
|
+
$country: CountryCode
|
|
69
|
+
$numProducts: Int!
|
|
70
|
+
$includeReferenceMetafieldDetails: Boolean = false
|
|
71
|
+
$numProductMetafields: Int = 0
|
|
72
|
+
$numProductVariants: Int = 250
|
|
73
|
+
$numProductMedia: Int = 6
|
|
74
|
+
$numProductVariantMetafields: Int = 0
|
|
75
|
+
$numProductVariantSellingPlanAllocations: Int = 0
|
|
76
|
+
$numProductSellingPlanGroups: Int = 0
|
|
77
|
+
$numProductSellingPlans: Int = 0
|
|
78
|
+
) @inContext(country: $country) {
|
|
79
|
+
collection(handle: $handle) {
|
|
80
|
+
id
|
|
81
|
+
title
|
|
82
|
+
description
|
|
83
|
+
descriptionHtml
|
|
84
|
+
image {
|
|
85
|
+
url
|
|
86
|
+
width
|
|
87
|
+
height
|
|
88
|
+
}
|
|
89
|
+
products(first: $numProducts) {
|
|
90
|
+
edges {
|
|
91
|
+
node {
|
|
92
|
+
vendor
|
|
93
|
+
...ProductProviderFragment
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
pageInfo {
|
|
97
|
+
hasNextPage
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
${MediaFileFragment}
|
|
104
|
+
${ProductProviderFragment}
|
|
105
|
+
`;
|