@shopify/create-hydrogen 1.0.9 → 2.0.2
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 +26 -0
- package/dist/commands/init.js +133 -62
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +12 -8
- package/templates/template-hydrogen-default/.devcontainer/devcontainer.json +0 -18
- package/templates/template-hydrogen-default/.eslintrc.js +0 -3
- package/templates/template-hydrogen-default/.gitignore +0 -7
- package/templates/template-hydrogen-default/.stylelintrc.js +0 -17
- package/templates/template-hydrogen-default/.vscode/extensions.json +0 -8
- package/templates/template-hydrogen-default/README.md +0 -40
- package/templates/template-hydrogen-default/_gitignore +0 -80
- package/templates/template-hydrogen-default/index.html +0 -20
- package/templates/template-hydrogen-default/package.json.liquid +0 -48
- package/templates/template-hydrogen-default/postcss.config.js +0 -6
- package/templates/template-hydrogen-default/public/favicon.ico +0 -0
- package/templates/template-hydrogen-default/shopify.config.js +0 -5
- package/templates/template-hydrogen-default/src/App.server.jsx +0 -27
- package/templates/template-hydrogen-default/src/components/Button.client.jsx +0 -65
- package/templates/template-hydrogen-default/src/components/Cart.client.jsx +0 -265
- package/templates/template-hydrogen-default/src/components/CartIcon.jsx +0 -33
- package/templates/template-hydrogen-default/src/components/CartIconWithItems.client.jsx +0 -28
- package/templates/template-hydrogen-default/src/components/CartProvider.client.jsx +0 -35
- package/templates/template-hydrogen-default/src/components/CartToggle.client.jsx +0 -30
- package/templates/template-hydrogen-default/src/components/CartUIProvider.client.jsx +0 -45
- package/templates/template-hydrogen-default/src/components/CountrySelector.client.jsx +0 -116
- package/templates/template-hydrogen-default/src/components/DefaultSeo.server.jsx +0 -36
- package/templates/template-hydrogen-default/src/components/FeaturedCollection.jsx +0 -26
- package/templates/template-hydrogen-default/src/components/Footer.server.jsx +0 -103
- package/templates/template-hydrogen-default/src/components/Gallery.client.jsx +0 -66
- package/templates/template-hydrogen-default/src/components/Header.client.jsx +0 -62
- package/templates/template-hydrogen-default/src/components/Layout.server.jsx +0 -86
- package/templates/template-hydrogen-default/src/components/LoadMoreProducts.client.jsx +0 -56
- package/templates/template-hydrogen-default/src/components/LoadingFallback.jsx +0 -26
- package/templates/template-hydrogen-default/src/components/MobileCountrySelector.client.jsx +0 -64
- package/templates/template-hydrogen-default/src/components/MobileNavigation.client.jsx +0 -98
- package/templates/template-hydrogen-default/src/components/MoneyCompareAtPrice.client.jsx +0 -14
- package/templates/template-hydrogen-default/src/components/MoneyPrice.client.jsx +0 -15
- package/templates/template-hydrogen-default/src/components/Navigation.client.jsx +0 -23
- package/templates/template-hydrogen-default/src/components/NotFound.server.jsx +0 -93
- package/templates/template-hydrogen-default/src/components/OpenIcon.jsx +0 -33
- package/templates/template-hydrogen-default/src/components/ProductCard.jsx +0 -50
- package/templates/template-hydrogen-default/src/components/ProductDetails.client.jsx +0 -233
- package/templates/template-hydrogen-default/src/components/ProductOptions.client.jsx +0 -49
- package/templates/template-hydrogen-default/src/components/Welcome.server.jsx +0 -188
- package/templates/template-hydrogen-default/src/index.css +0 -68
- package/templates/template-hydrogen-default/src/pages/collections/[handle].server.jsx +0 -105
- package/templates/template-hydrogen-default/src/pages/index.server.jsx +0 -241
- package/templates/template-hydrogen-default/src/pages/pages/[handle].server.jsx +0 -37
- package/templates/template-hydrogen-default/src/pages/products/[handle].server.jsx +0 -66
- package/templates/template-hydrogen-default/src/pages/redirect.server.jsx +0 -4
- package/templates/template-hydrogen-default/src/pages/robots.txt.server.js +0 -40
- package/templates/template-hydrogen-default/src/pages/sitemap.xml.server.jsx +0 -151
- package/templates/template-hydrogen-default/src/routes/collections/[handle].server.jsx +0 -105
- package/templates/template-hydrogen-default/src/routes/index.server.jsx +0 -241
- package/templates/template-hydrogen-default/src/routes/pages/[handle].server.jsx +0 -37
- package/templates/template-hydrogen-default/src/routes/products/[handle].server.jsx +0 -66
- package/templates/template-hydrogen-default/src/routes/redirect.server.jsx +0 -4
- package/templates/template-hydrogen-default/src/routes/robots.txt.server.js +0 -40
- package/templates/template-hydrogen-default/src/routes/sitemap.xml.server.jsx +0 -151
- package/templates/template-hydrogen-default/tailwind.config.js +0 -26
- package/templates/template-hydrogen-default/vite.config.js +0 -10
- package/templates/template-hydrogen-minimal/README.md +0 -8
- package/templates/template-hydrogen-minimal/package.json +0 -14
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import {Fragment, useEffect, useState} from 'react';
|
|
2
|
-
import {Link} from '@shopify/hydrogen/client';
|
|
3
|
-
import {FocusTrap} from '@headlessui/react';
|
|
4
|
-
|
|
5
|
-
import MobileCountrySelector from './MobileCountrySelector.client';
|
|
6
|
-
import OpenIcon from './OpenIcon';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A client component that defines the navigation for a mobile storefront
|
|
10
|
-
*/
|
|
11
|
-
export default function MobileNavigation({collections, isOpen, setIsOpen}) {
|
|
12
|
-
const OpenFocusTrap = isOpen ? FocusTrap : Fragment;
|
|
13
|
-
|
|
14
|
-
const [topScrollOffset, setTopScrollOffset] = useState(0);
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (isOpen) {
|
|
18
|
-
setTopScrollOffset(window.scrollY);
|
|
19
|
-
document.body.style.position = 'fixed';
|
|
20
|
-
} else {
|
|
21
|
-
document.body.style.position = '';
|
|
22
|
-
window.scrollTo(0, parseInt(topScrollOffset, 10));
|
|
23
|
-
}
|
|
24
|
-
}, [isOpen, topScrollOffset]);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<div className="lg:hidden">
|
|
28
|
-
<OpenFocusTrap>
|
|
29
|
-
<button
|
|
30
|
-
type="button"
|
|
31
|
-
className="flex justify-center items-center w-7 h-full"
|
|
32
|
-
onClick={() => setIsOpen((previousIsOpen) => !previousIsOpen)}
|
|
33
|
-
>
|
|
34
|
-
{isOpen ? <CloseIcon /> : <OpenIcon />}
|
|
35
|
-
</button>
|
|
36
|
-
{isOpen ? (
|
|
37
|
-
<div className="fixed -left-0 top-20 w-full h-screen z-10 bg-gray-50 px-4 md:px-12 py-7">
|
|
38
|
-
<ul>
|
|
39
|
-
{collections.map((collection) => (
|
|
40
|
-
<li className="border-b border-gray-200" key={collection.id}>
|
|
41
|
-
<Link
|
|
42
|
-
className="group py-5 text-gray-700 flex items-center justify-between"
|
|
43
|
-
to={`/collections/${collection.handle}`}
|
|
44
|
-
onClick={() => setIsOpen(false)}
|
|
45
|
-
>
|
|
46
|
-
{collection.title}
|
|
47
|
-
<ArrowRightIcon className="hidden group-hover:block" />
|
|
48
|
-
</Link>
|
|
49
|
-
</li>
|
|
50
|
-
))}
|
|
51
|
-
</ul>
|
|
52
|
-
<MobileCountrySelector />
|
|
53
|
-
</div>
|
|
54
|
-
) : null}
|
|
55
|
-
</OpenFocusTrap>
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function CloseIcon() {
|
|
61
|
-
return (
|
|
62
|
-
<svg
|
|
63
|
-
width="18"
|
|
64
|
-
height="18"
|
|
65
|
-
viewBox="0 0 18 18"
|
|
66
|
-
fill="none"
|
|
67
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
68
|
-
>
|
|
69
|
-
<path
|
|
70
|
-
d="M1 17L17 1M1 1L17 17"
|
|
71
|
-
stroke="black"
|
|
72
|
-
strokeWidth="2"
|
|
73
|
-
strokeLinecap="round"
|
|
74
|
-
strokeLinejoin="round"
|
|
75
|
-
/>
|
|
76
|
-
</svg>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function ArrowRightIcon({className}) {
|
|
81
|
-
return (
|
|
82
|
-
<svg
|
|
83
|
-
className={className}
|
|
84
|
-
width="7"
|
|
85
|
-
height="12"
|
|
86
|
-
viewBox="0 0 7 12"
|
|
87
|
-
fill="none"
|
|
88
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
89
|
-
>
|
|
90
|
-
<path
|
|
91
|
-
fillRule="evenodd"
|
|
92
|
-
clipRule="evenodd"
|
|
93
|
-
d="M0.999762 12C0.743762 12 0.487762 11.902 0.292762 11.707C-0.0982383 11.316 -0.0982383 10.684 0.292762 10.293L4.58576 6.00001L0.292762 1.70701C-0.0982383 1.31601 -0.0982383 0.684006 0.292762 0.293006C0.683762 -0.0979941 1.31576 -0.0979941 1.70676 0.293006L6.70676 5.29301C7.09776 5.68401 7.09776 6.31601 6.70676 6.70701L1.70676 11.707C1.51176 11.902 1.25576 12 0.999762 12Z"
|
|
94
|
-
fill="black"
|
|
95
|
-
/>
|
|
96
|
-
</svg>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {useMoney} from '@shopify/hydrogen/client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A client component that renders a product's compare at price
|
|
5
|
-
*/
|
|
6
|
-
export default function MoneyCompareAtPrice({money}) {
|
|
7
|
-
const {amount, currencyNarrowSymbol} = useMoney(money);
|
|
8
|
-
return (
|
|
9
|
-
<span className="line-through text-lg mr-2.5 text-gray-500">
|
|
10
|
-
{currencyNarrowSymbol}
|
|
11
|
-
{amount}
|
|
12
|
-
</span>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import {useMoney} from '@shopify/hydrogen/client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A client component that defines the currency code, currency symbol, and amount of a product
|
|
5
|
-
*/
|
|
6
|
-
export default function MoneyPrice({money}) {
|
|
7
|
-
const {currencyCode, currencyNarrowSymbol, amount} = useMoney(money);
|
|
8
|
-
return (
|
|
9
|
-
<span className="text-black text-md">
|
|
10
|
-
{currencyCode}
|
|
11
|
-
{currencyNarrowSymbol}
|
|
12
|
-
{amount}
|
|
13
|
-
</span>
|
|
14
|
-
);
|
|
15
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {Link} from '@shopify/hydrogen/client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A client component that defines the navigation for a web storefront
|
|
5
|
-
*/
|
|
6
|
-
export default function Navigation({collections}) {
|
|
7
|
-
return (
|
|
8
|
-
<nav className="hidden lg:block text-center">
|
|
9
|
-
<ul className="md:flex items-center justify-center">
|
|
10
|
-
{collections.map((collection) => (
|
|
11
|
-
<li key={collection.id}>
|
|
12
|
-
<Link
|
|
13
|
-
to={`/collections/${collection.handle}`}
|
|
14
|
-
className="block p-4 hover:opacity-80"
|
|
15
|
-
>
|
|
16
|
-
{collection.title}
|
|
17
|
-
</Link>
|
|
18
|
-
</li>
|
|
19
|
-
))}
|
|
20
|
-
</ul>
|
|
21
|
-
</nav>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useShopQuery,
|
|
3
|
-
ProductProviderFragment,
|
|
4
|
-
flattenConnection,
|
|
5
|
-
} from '@shopify/hydrogen';
|
|
6
|
-
import gql from 'graphql-tag';
|
|
7
|
-
|
|
8
|
-
import Layout from './Layout.server';
|
|
9
|
-
import Button from './Button.client';
|
|
10
|
-
import ProductCard from './ProductCard';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A server component that defines the content to display when a page isn't found (404 error)
|
|
14
|
-
*/
|
|
15
|
-
function NotFoundHero() {
|
|
16
|
-
return (
|
|
17
|
-
<div className="py-10 border-b border-gray-200">
|
|
18
|
-
<div className="max-w-3xl text-center mx-4 md:mx-auto">
|
|
19
|
-
<h1 className="font-bold text-4xl md:text-5xl text-gray-900 mb-6 mt-6">
|
|
20
|
-
We've lost this page
|
|
21
|
-
</h1>
|
|
22
|
-
<p className="text-lg m-8 text-gray-500">
|
|
23
|
-
We couldn’t find the page you’re looking for. Try checking the URL or
|
|
24
|
-
heading back to the home page.
|
|
25
|
-
</p>
|
|
26
|
-
<Button
|
|
27
|
-
className="w-full md:mx-auto md:w-96"
|
|
28
|
-
url="/"
|
|
29
|
-
label="Take me to the home page"
|
|
30
|
-
/>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default function NotFound({country = {isoCode: 'US'}}) {
|
|
37
|
-
const {data} = useShopQuery({
|
|
38
|
-
query: QUERY,
|
|
39
|
-
variables: {
|
|
40
|
-
country: country.isoCode,
|
|
41
|
-
numProductMetafields: 0,
|
|
42
|
-
numProductVariants: 250,
|
|
43
|
-
numProductMedia: 0,
|
|
44
|
-
numProductVariantMetafields: 0,
|
|
45
|
-
numProductVariantSellingPlanAllocations: 0,
|
|
46
|
-
numProductSellingPlanGroups: 0,
|
|
47
|
-
numProductSellingPlans: 0,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
const products = data ? flattenConnection(data.products) : [];
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<Layout>
|
|
54
|
-
<NotFoundHero />
|
|
55
|
-
<div className="my-8">
|
|
56
|
-
<p className="mb-8 text-lg text-black font-medium uppercase">
|
|
57
|
-
Products you might like
|
|
58
|
-
</p>
|
|
59
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-16">
|
|
60
|
-
{products.map((product) => (
|
|
61
|
-
<div key={product.id}>
|
|
62
|
-
<ProductCard product={product} />
|
|
63
|
-
</div>
|
|
64
|
-
))}
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
</Layout>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const QUERY = gql`
|
|
72
|
-
query NotFoundProductDetails(
|
|
73
|
-
$country: CountryCode
|
|
74
|
-
$includeReferenceMetafieldDetails: Boolean = false
|
|
75
|
-
$numProductMetafields: Int!
|
|
76
|
-
$numProductVariants: Int!
|
|
77
|
-
$numProductMedia: Int!
|
|
78
|
-
$numProductVariantMetafields: Int!
|
|
79
|
-
$numProductVariantSellingPlanAllocations: Int!
|
|
80
|
-
$numProductSellingPlanGroups: Int!
|
|
81
|
-
$numProductSellingPlans: Int!
|
|
82
|
-
) @inContext(country: $country) {
|
|
83
|
-
products(first: 3) {
|
|
84
|
-
edges {
|
|
85
|
-
node {
|
|
86
|
-
...ProductProviderFragment
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
${ProductProviderFragment}
|
|
93
|
-
`;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A shared component that specifies the icon to render when opened
|
|
3
|
-
*/
|
|
4
|
-
export default function OpenIcon() {
|
|
5
|
-
return (
|
|
6
|
-
<svg
|
|
7
|
-
width="24"
|
|
8
|
-
height="20"
|
|
9
|
-
viewBox="0 0 24 20"
|
|
10
|
-
fill="none"
|
|
11
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
-
>
|
|
13
|
-
<path
|
|
14
|
-
fillRule="evenodd"
|
|
15
|
-
clipRule="evenodd"
|
|
16
|
-
d="M0.800049 1.9999C0.800049 1.11625 1.51639 0.399902 2.40005 0.399902H21.6C22.4837 0.399902 23.2001 1.11625 23.2001 1.9999C23.2001 2.88356 22.4837 3.5999 21.6 3.5999H2.40005C1.51639 3.5999 0.800049 2.88356 0.800049 1.9999Z"
|
|
17
|
-
fill="black"
|
|
18
|
-
/>
|
|
19
|
-
<path
|
|
20
|
-
fillRule="evenodd"
|
|
21
|
-
clipRule="evenodd"
|
|
22
|
-
d="M0.800049 9.9999C0.800049 9.11625 1.51639 8.3999 2.40005 8.3999H21.6C22.4837 8.3999 23.2001 9.11625 23.2001 9.9999C23.2001 10.8836 22.4837 11.5999 21.6 11.5999H2.40005C1.51639 11.5999 0.800049 10.8836 0.800049 9.9999Z"
|
|
23
|
-
fill="black"
|
|
24
|
-
/>
|
|
25
|
-
<path
|
|
26
|
-
fillRule="evenodd"
|
|
27
|
-
clipRule="evenodd"
|
|
28
|
-
d="M0.800049 17.9999C0.800049 17.1162 1.51639 16.3999 2.40005 16.3999H21.6C22.4837 16.3999 23.2001 17.1162 23.2001 17.9999C23.2001 18.8836 22.4837 19.5999 21.6 19.5999H2.40005C1.51639 19.5999 0.800049 18.8836 0.800049 17.9999Z"
|
|
29
|
-
fill="black"
|
|
30
|
-
/>
|
|
31
|
-
</svg>
|
|
32
|
-
);
|
|
33
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import {Image, Link} from '@shopify/hydrogen';
|
|
2
|
-
|
|
3
|
-
import MoneyCompareAtPrice from './MoneyCompareAtPrice.client';
|
|
4
|
-
import MoneyPrice from './MoneyPrice.client';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A shared component that displays a single product to allow buyers to quickly identify a particular item of interest
|
|
8
|
-
*/
|
|
9
|
-
export default function ProductCard({product}) {
|
|
10
|
-
const selectedVariant = product.variants.edges[0].node;
|
|
11
|
-
|
|
12
|
-
if (selectedVariant == null) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<div className="text-md mb-4 relative">
|
|
18
|
-
<Link to={`/products/${product.handle}`}>
|
|
19
|
-
<div className="rounded-lg border-2 border-gray-200 mb-2 relative flex items-center justify-center overflow-hidden object-cover h-96">
|
|
20
|
-
{selectedVariant.image ? (
|
|
21
|
-
<Image
|
|
22
|
-
className="bg-white absolute w-full h-full transition-all duration-500 ease-in-out transform bg-center bg-cover object-center object-contain hover:scale-110"
|
|
23
|
-
data={selectedVariant.image}
|
|
24
|
-
/>
|
|
25
|
-
) : null}
|
|
26
|
-
{!selectedVariant?.availableForSale && (
|
|
27
|
-
<div className="absolute top-3 left-3 rounded-3xl text-xs bg-black text-white py-3 px-4">
|
|
28
|
-
Out of stock
|
|
29
|
-
</div>
|
|
30
|
-
)}
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<span className="text-black font-semibold mb-0.5">{product.title}</span>
|
|
34
|
-
|
|
35
|
-
{product.vendor && (
|
|
36
|
-
<p className="text-gray-900 font-medium text-sm mb-0.5">
|
|
37
|
-
{product.vendor}
|
|
38
|
-
</p>
|
|
39
|
-
)}
|
|
40
|
-
|
|
41
|
-
<div className="flex ">
|
|
42
|
-
{selectedVariant.compareAtPriceV2 && (
|
|
43
|
-
<MoneyCompareAtPrice money={selectedVariant.compareAtPriceV2} />
|
|
44
|
-
)}
|
|
45
|
-
<MoneyPrice money={selectedVariant.priceV2} />
|
|
46
|
-
</div>
|
|
47
|
-
</Link>
|
|
48
|
-
</div>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
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,49 +0,0 @@
|
|
|
1
|
-
import {useProduct} from '@shopify/hydrogen/client';
|
|
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
|
-
*/
|
|
6
|
-
export default function ProductOptions() {
|
|
7
|
-
const {options, setSelectedOption, selectedOptions} = useProduct();
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<>
|
|
11
|
-
{options.map(({name, values}) => {
|
|
12
|
-
return (
|
|
13
|
-
<fieldset key={name} className="mt-8">
|
|
14
|
-
<legend className="mb-4 text-xl font-medium text-gray-900">
|
|
15
|
-
{name}
|
|
16
|
-
</legend>
|
|
17
|
-
<div className="flex items-center flex-wrap gap-4">
|
|
18
|
-
{values.map((value) => {
|
|
19
|
-
const checked = selectedOptions[name] === value;
|
|
20
|
-
const id = `option-${name}-${value}`;
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<label key={id} htmlFor={id}>
|
|
24
|
-
<input
|
|
25
|
-
className="sr-only"
|
|
26
|
-
type="radio"
|
|
27
|
-
id={id}
|
|
28
|
-
name={`option[${name}]`}
|
|
29
|
-
value={value}
|
|
30
|
-
checked={checked}
|
|
31
|
-
onChange={() => setSelectedOption(name, value)}
|
|
32
|
-
/>
|
|
33
|
-
<div
|
|
34
|
-
className={`p-2 border cursor-pointer rounded text-sm md:text-md ${
|
|
35
|
-
checked ? 'bg-gray-900 text-white' : 'text-gray-900'
|
|
36
|
-
}`}
|
|
37
|
-
>
|
|
38
|
-
{value}
|
|
39
|
-
</div>
|
|
40
|
-
</label>
|
|
41
|
-
);
|
|
42
|
-
})}
|
|
43
|
-
</div>
|
|
44
|
-
</fieldset>
|
|
45
|
-
);
|
|
46
|
-
})}
|
|
47
|
-
</>
|
|
48
|
-
);
|
|
49
|
-
}
|