@shopify/create-hydrogen 0.2.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/init.js +76397 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -14
- package/templates/template-hydrogen/.devcontainer/devcontainer.json +18 -0
- package/templates/template-hydrogen/.eslintrc.js +3 -0
- package/templates/template-hydrogen/.gitignore +7 -0
- package/templates/template-hydrogen/.stackblitzrc +4 -0
- package/{template-hydrogen → templates/template-hydrogen}/.stylelintrc.js +1 -1
- package/templates/template-hydrogen/.vscode/extensions.json +8 -0
- package/templates/template-hydrogen/Dockerfile +15 -0
- package/{template-hydrogen → templates/template-hydrogen}/README.md +11 -2
- package/{template-hydrogen → templates/template-hydrogen}/_gitignore +0 -0
- package/templates/template-hydrogen/index.html +20 -0
- package/{template-hydrogen → templates/template-hydrogen}/package.json +20 -16
- package/{template-hydrogen → templates/template-hydrogen}/postcss.config.js +0 -0
- package/{template-hydrogen/src → templates/template-hydrogen/public}/favicon.svg +0 -0
- package/{template-hydrogen → templates/template-hydrogen}/server.js +4 -2
- package/{template-hydrogen → templates/template-hydrogen}/shopify.config.js +1 -2
- package/templates/template-hydrogen/src/App.client.jsx +8 -0
- package/templates/template-hydrogen/src/App.server.jsx +27 -0
- package/templates/template-hydrogen/src/components/Button.client.jsx +65 -0
- package/templates/template-hydrogen/src/components/Cart.client.jsx +265 -0
- package/templates/template-hydrogen/src/components/CartIcon.jsx +33 -0
- package/templates/template-hydrogen/src/components/CartIconWithItems.client.jsx +28 -0
- package/templates/template-hydrogen/src/components/CartProvider.client.jsx +35 -0
- package/templates/template-hydrogen/src/components/CartToggle.client.jsx +30 -0
- package/{template-hydrogen → templates/template-hydrogen}/src/components/CartUIProvider.client.jsx +3 -0
- package/templates/template-hydrogen/src/components/CountrySelector.client.jsx +116 -0
- package/templates/template-hydrogen/src/components/DefaultSeo.server.jsx +35 -0
- package/templates/template-hydrogen/src/components/FeaturedCollection.jsx +26 -0
- package/templates/template-hydrogen/src/components/Footer.server.jsx +103 -0
- package/templates/template-hydrogen/src/components/Gallery.client.jsx +65 -0
- package/templates/template-hydrogen/src/components/Header.client.jsx +62 -0
- package/templates/template-hydrogen/src/components/Layout.server.jsx +87 -0
- package/templates/template-hydrogen/src/components/LoadMoreProducts.client.jsx +56 -0
- package/templates/template-hydrogen/src/components/LoadingFallback.jsx +26 -0
- package/templates/template-hydrogen/src/components/MobileCountrySelector.client.jsx +64 -0
- package/templates/template-hydrogen/src/components/MobileNavigation.client.jsx +98 -0
- package/templates/template-hydrogen/src/components/MoneyCompareAtPrice.client.jsx +14 -0
- package/templates/template-hydrogen/src/components/MoneyPrice.client.jsx +15 -0
- package/templates/template-hydrogen/src/components/Navigation.client.jsx +23 -0
- package/templates/template-hydrogen/src/components/NotFound.server.jsx +93 -0
- package/templates/template-hydrogen/src/components/OpenIcon.jsx +33 -0
- package/templates/template-hydrogen/src/components/ProductCard.jsx +50 -0
- package/templates/template-hydrogen/src/components/ProductDetails.client.jsx +242 -0
- package/{template-hydrogen → templates/template-hydrogen}/src/components/ProductOptions.client.jsx +7 -4
- package/templates/template-hydrogen/src/components/Welcome.server.jsx +188 -0
- package/templates/template-hydrogen/src/entry-client.jsx +7 -0
- package/templates/template-hydrogen/src/entry-server.jsx +6 -0
- package/{template-hydrogen → templates/template-hydrogen}/src/index.css +31 -0
- package/templates/template-hydrogen/src/pages/collections/[handle].server.jsx +105 -0
- package/templates/template-hydrogen/src/pages/index.server.jsx +237 -0
- package/{template-hydrogen → templates/template-hydrogen}/src/pages/pages/[handle].server.jsx +14 -5
- package/templates/template-hydrogen/src/pages/products/[handle].server.jsx +69 -0
- package/templates/template-hydrogen/src/pages/redirect.server.jsx +4 -0
- package/templates/template-hydrogen/src/pages/robots.txt.server.js +10 -0
- package/{template-hydrogen → templates/template-hydrogen}/src/pages/sitemap.xml.server.jsx +2 -2
- package/templates/template-hydrogen/tailwind.config.js +26 -0
- package/{template-hydrogen → templates/template-hydrogen}/vite.config.js +1 -0
- package/{template-hydrogen → templates/template-hydrogen}/worker.js +1 -0
- package/README.md +0 -3
- package/index.js +0 -205
- 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/src/App.server.jsx +0 -42
- package/template-hydrogen/src/components/Cart.client.jsx +0 -296
- package/template-hydrogen/src/components/CartProvider.client.jsx +0 -40
- 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 -103
- package/template-hydrogen/src/components/HightlightedProduct.client.jsx +0 -54
- package/template-hydrogen/src/components/Layout.client.jsx +0 -41
- 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/pages/Index.server.jsx +0 -199
- 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 -62
- package/template-hydrogen/src/pages/search.server.jsx +0 -107
- package/template-hydrogen/tailwind.config.js +0 -9
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {useShop, Helmet} from '@shopify/hydrogen/client';
|
|
2
|
-
|
|
3
|
-
export default function Seo({shopName, product}) {
|
|
4
|
-
const {locale} = useShop();
|
|
5
|
-
const lang = locale.split(/[-_]/)[0];
|
|
6
|
-
|
|
7
|
-
if (product) {
|
|
8
|
-
const variant = product.variants.edges[0].node;
|
|
9
|
-
const price = variant.priceV2;
|
|
10
|
-
const image = product.images.edges[0]?.node;
|
|
11
|
-
const title = product.seo?.title ?? product.title;
|
|
12
|
-
const description = product.seo?.description ?? product.description;
|
|
13
|
-
|
|
14
|
-
/* TODO: Find a way to get the full URL */
|
|
15
|
-
const url = typeof window === 'undefined' ? '' : window.location.href;
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<Helmet>
|
|
19
|
-
<title>{title}</title>
|
|
20
|
-
<meta name="description" content={description} />
|
|
21
|
-
{url && <meta property="og:url" content={url} />}
|
|
22
|
-
<meta property="og:title" content={title} />
|
|
23
|
-
<meta property="og:type" content="product" />
|
|
24
|
-
<meta property="og:description" content={description} />
|
|
25
|
-
<meta property="og:price:amount" content={price.amount} />
|
|
26
|
-
<meta property="og:price:currency" content={price.currencyCode} />
|
|
27
|
-
|
|
28
|
-
{image && <meta property="og:image" content={image.originalSrc} />}
|
|
29
|
-
{image && (
|
|
30
|
-
<meta property="og:image:secure_url" content={image.originalSrc} />
|
|
31
|
-
)}
|
|
32
|
-
|
|
33
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
34
|
-
<meta name="twitter:title" content={title} />
|
|
35
|
-
<meta name="twitter:description" content={description} />
|
|
36
|
-
|
|
37
|
-
<script type="application/ld+json">{`
|
|
38
|
-
{
|
|
39
|
-
"@context": "https://schema.org/",
|
|
40
|
-
"@type": "Product",
|
|
41
|
-
"name": "${product.title}",
|
|
42
|
-
"image": [
|
|
43
|
-
${image ? `"${image.originalSrc}"` : ''}
|
|
44
|
-
],
|
|
45
|
-
"description": "${description}",
|
|
46
|
-
"brand": {
|
|
47
|
-
"@type": "Brand",
|
|
48
|
-
"name": "${product.vendor}"
|
|
49
|
-
},
|
|
50
|
-
"offers": {
|
|
51
|
-
"@type": "Offer",
|
|
52
|
-
"url": "${url}",
|
|
53
|
-
"priceCurrency": "${price.currencyCode}",
|
|
54
|
-
"price": "${price.amount}",
|
|
55
|
-
"availability": "https://schema.org/${
|
|
56
|
-
variant.availableForSale ? 'InStock' : 'OutOfStock'
|
|
57
|
-
}"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
`}</script>
|
|
61
|
-
</Helmet>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Return a global SEO helper if no other props were passed.
|
|
67
|
-
* Useful for placing in the "main" <App> container.
|
|
68
|
-
*/
|
|
69
|
-
return (
|
|
70
|
-
<Helmet defaultTitle={shopName} titleTemplate={`%s - ${shopName}`}>
|
|
71
|
-
<html lang={lang} />
|
|
72
|
-
<meta property="og:site_name" content={shopName} />
|
|
73
|
-
</Helmet>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import renderHydrogen from '@shopify/hydrogen/entry-client';
|
|
2
|
-
import {ShopifyProvider} from '@shopify/hydrogen/client';
|
|
3
|
-
|
|
4
|
-
import shopifyConfig from '../shopify.config';
|
|
5
|
-
|
|
6
|
-
function ClientApp({children}) {
|
|
7
|
-
return (
|
|
8
|
-
<ShopifyProvider shopifyConfig={shopifyConfig}>{children}</ShopifyProvider>
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default renderHydrogen(ClientApp);
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useShopQuery,
|
|
3
|
-
flattenConnection,
|
|
4
|
-
ProductProviderFragment,
|
|
5
|
-
} from '@shopify/hydrogen';
|
|
6
|
-
import gql from 'graphql-tag';
|
|
7
|
-
|
|
8
|
-
import HighlightedProduct from '../components/HightlightedProduct.client';
|
|
9
|
-
import Layout from '../components/Layout.client';
|
|
10
|
-
import ProductCard from '../components/ProductCard.client';
|
|
11
|
-
import MediaPlaceholder from '../components/MediaPlaceholder';
|
|
12
|
-
|
|
13
|
-
export default function Index() {
|
|
14
|
-
const {data} = useShopQuery({
|
|
15
|
-
query: QUERY,
|
|
16
|
-
variables: {
|
|
17
|
-
numProducts: 3,
|
|
18
|
-
numProductMetafields: 0,
|
|
19
|
-
numProductVariants: 250,
|
|
20
|
-
numProductMedia: 1,
|
|
21
|
-
numProductVariantMetafields: 10,
|
|
22
|
-
numProductVariantSellingPlanAllocations: 10,
|
|
23
|
-
numProductSellingPlanGroups: 10,
|
|
24
|
-
numProductSellingPlans: 10,
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const products = data ? flattenConnection(data.products) : [];
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Layout>
|
|
32
|
-
<div className="z-0 gradient w-screen h-screen top-0 left-0 right-0 fixed" />
|
|
33
|
-
<div className="z-5 relative space-y-16">
|
|
34
|
-
<section className="md:px-4 pt-10 pb-4">
|
|
35
|
-
<HydrogenGettingStarted />
|
|
36
|
-
</section>
|
|
37
|
-
|
|
38
|
-
<section className="space-y-6 md:space-y-0 md:grid grid-cols-3 gap-10">
|
|
39
|
-
<div>
|
|
40
|
-
<CommerceReadyComponents />
|
|
41
|
-
</div>
|
|
42
|
-
<div className="col-span-2 md:flex shadow-xl p-4 md:p-6 rounded-md bg-white">
|
|
43
|
-
{products[0] ? (
|
|
44
|
-
<HighlightedProduct product={products[0]} />
|
|
45
|
-
) : (
|
|
46
|
-
<MediaPlaceholder text="Your product here" />
|
|
47
|
-
)}
|
|
48
|
-
</div>
|
|
49
|
-
</section>
|
|
50
|
-
|
|
51
|
-
<section className="space-y-6 md:space-y-0 md:grid grid-cols-3 gap-10 flex flex-col-reverse">
|
|
52
|
-
{products.length > 2 && (
|
|
53
|
-
<div className="col-span-2 md:flex shadow-xl p-4 md:p-6 rounded-md space-y-6 md:space-y-0 md:space-x-6 bg-white">
|
|
54
|
-
{[products[1], products[2]].map((product) => {
|
|
55
|
-
return (
|
|
56
|
-
<div key={product.id}>
|
|
57
|
-
<ProductCard product={product} />
|
|
58
|
-
</div>
|
|
59
|
-
);
|
|
60
|
-
})}
|
|
61
|
-
</div>
|
|
62
|
-
)}
|
|
63
|
-
<div>
|
|
64
|
-
<StyleWithTailwind />
|
|
65
|
-
</div>
|
|
66
|
-
</section>
|
|
67
|
-
</div>
|
|
68
|
-
</Layout>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function HydrogenGettingStarted() {
|
|
73
|
-
const links = [
|
|
74
|
-
{
|
|
75
|
-
text: 'Browse Hydrogen documentation',
|
|
76
|
-
url: 'https://shopify.dev/beta/hydrogen/',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
text: 'Open the GraphiQL editor',
|
|
80
|
-
url: '/graphiql',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
text: 'Explore starter templates',
|
|
84
|
-
url: '/',
|
|
85
|
-
},
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<>
|
|
90
|
-
<h2 className="text-4xl md:text-7xl font-extrabold text-center">
|
|
91
|
-
Hello, Hydrogen
|
|
92
|
-
</h2>
|
|
93
|
-
|
|
94
|
-
<p className="text-xl text-center mt-4 mb-8">
|
|
95
|
-
Welcome to your custom storefront. Let‘s get building.
|
|
96
|
-
</p>
|
|
97
|
-
|
|
98
|
-
<ul className="md:flex justify-center gap-5 space-y-4 md:space-y-0">
|
|
99
|
-
{links.map((link) => (
|
|
100
|
-
<li key={link.url}>
|
|
101
|
-
<a
|
|
102
|
-
href={link.url}
|
|
103
|
-
className="rounded-full bg-white px-4 py-2 bg-opacity-80 flex items-center gap-2"
|
|
104
|
-
>
|
|
105
|
-
{link.text}
|
|
106
|
-
<svg
|
|
107
|
-
width="7"
|
|
108
|
-
height="13"
|
|
109
|
-
viewBox="0 0 7 13"
|
|
110
|
-
fill="none"
|
|
111
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
112
|
-
>
|
|
113
|
-
<path
|
|
114
|
-
d="M1 1.5L6 6.5L1 11.5"
|
|
115
|
-
stroke="currentColor"
|
|
116
|
-
strokeWidth="2"
|
|
117
|
-
strokeLinecap="round"
|
|
118
|
-
strokeLinejoin="round"
|
|
119
|
-
/>
|
|
120
|
-
</svg>
|
|
121
|
-
</a>
|
|
122
|
-
</li>
|
|
123
|
-
))}
|
|
124
|
-
</ul>
|
|
125
|
-
</>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function CommerceReadyComponents() {
|
|
130
|
-
return (
|
|
131
|
-
<>
|
|
132
|
-
<h2 className="font-bold text-3xl">Commerce-ready components</h2>
|
|
133
|
-
<p className="text-xl leading-8 mt-2 mb-4">
|
|
134
|
-
Hydrogen includes the most common components for commerce, powered by
|
|
135
|
-
your Shopify custom storefront. They're accessible, performant, and
|
|
136
|
-
ready for implementation.
|
|
137
|
-
</p>
|
|
138
|
-
<a
|
|
139
|
-
className="text-blue-500 text-xl flex items-center gap-1"
|
|
140
|
-
href="https://shopify.dev/beta/hydrogen/"
|
|
141
|
-
>
|
|
142
|
-
Browse components
|
|
143
|
-
<svg
|
|
144
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
145
|
-
className="h-5 w-5"
|
|
146
|
-
viewBox="0 0 20 20"
|
|
147
|
-
fill="currentColor"
|
|
148
|
-
>
|
|
149
|
-
<path
|
|
150
|
-
fillRule="evenodd"
|
|
151
|
-
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
|
|
152
|
-
clipRule="evenodd"
|
|
153
|
-
/>
|
|
154
|
-
</svg>
|
|
155
|
-
</a>
|
|
156
|
-
</>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function StyleWithTailwind() {
|
|
161
|
-
return (
|
|
162
|
-
<>
|
|
163
|
-
<h2 className="font-bold text-3xl">
|
|
164
|
-
Style with Tailwind or roll your own
|
|
165
|
-
</h2>
|
|
166
|
-
<p className="text-xl leading-8 mt-2 mb-4">
|
|
167
|
-
Hydrogen starter templates are styled using the flexible{' '}
|
|
168
|
-
<a className="text-blue-500" href="https://www.tailwindcss.com">
|
|
169
|
-
Tailwind CSS
|
|
170
|
-
</a>{' '}
|
|
171
|
-
framework. Start building with Tailwind's library or choose your
|
|
172
|
-
own styling - it's up to you.
|
|
173
|
-
</p>
|
|
174
|
-
</>
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const QUERY = gql`
|
|
179
|
-
query indexContent(
|
|
180
|
-
$numProducts: Int!
|
|
181
|
-
$numProductMetafields: Int!
|
|
182
|
-
$numProductVariants: Int!
|
|
183
|
-
$numProductMedia: Int!
|
|
184
|
-
$numProductVariantMetafields: Int!
|
|
185
|
-
$numProductVariantSellingPlanAllocations: Int!
|
|
186
|
-
$numProductSellingPlanGroups: Int!
|
|
187
|
-
$numProductSellingPlans: Int!
|
|
188
|
-
) {
|
|
189
|
-
products(first: $numProducts) {
|
|
190
|
-
edges {
|
|
191
|
-
node {
|
|
192
|
-
...ProductProviderFragment
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
${ProductProviderFragment}
|
|
199
|
-
`;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import {RawHtml, useShopQuery} from '@shopify/hydrogen';
|
|
2
|
-
import {useParams} from 'react-router-dom';
|
|
3
|
-
import gql from 'graphql-tag';
|
|
4
|
-
|
|
5
|
-
import Layout from '../../../components/Layout.client';
|
|
6
|
-
|
|
7
|
-
export default function Article() {
|
|
8
|
-
const {handle, articleHandle} = useParams();
|
|
9
|
-
const {data} = useShopQuery({
|
|
10
|
-
query: QUERY,
|
|
11
|
-
variables: {handle, articleHandle},
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const article = data.blogByHandle.articleByHandle;
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<Layout>
|
|
18
|
-
<section className="my-8 px-4 pt-10 pb-4 text-white">
|
|
19
|
-
<h1 className="text-7xl mb-4 font-semibold tracking-tight">
|
|
20
|
-
{article.title}
|
|
21
|
-
</h1>
|
|
22
|
-
</section>
|
|
23
|
-
|
|
24
|
-
<section className="my-8 bg-white rounded-3xl p-10 sticky shadow-2xl">
|
|
25
|
-
<p className="font-medium mt-1">
|
|
26
|
-
Published {new Date(article.publishedAt).toLocaleDateString()} by{' '}
|
|
27
|
-
{article.author.name}
|
|
28
|
-
</p>
|
|
29
|
-
|
|
30
|
-
<RawHtml string={article.contentHtml} className="prose mt-8" />
|
|
31
|
-
</section>
|
|
32
|
-
</Layout>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const QUERY = gql`
|
|
37
|
-
query ArticleDetails($handle: String!, $articleHandle: String!) {
|
|
38
|
-
blogByHandle(handle: $handle) {
|
|
39
|
-
articleByHandle(handle: $articleHandle) {
|
|
40
|
-
title
|
|
41
|
-
contentHtml
|
|
42
|
-
publishedAt
|
|
43
|
-
author: authorV2 {
|
|
44
|
-
name
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`;
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import {useParams} from 'react-router-dom';
|
|
2
|
-
import {useShopQuery, RawHtml, Link} from '@shopify/hydrogen';
|
|
3
|
-
import gql from 'graphql-tag';
|
|
4
|
-
|
|
5
|
-
import Layout from '../../components/Layout.client';
|
|
6
|
-
|
|
7
|
-
export default function Blog() {
|
|
8
|
-
const {handle} = useParams();
|
|
9
|
-
const {data} = useShopQuery({query: QUERY, variables: {handle}});
|
|
10
|
-
|
|
11
|
-
const blog = data.blogByHandle;
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Layout>
|
|
15
|
-
<div className="relative">
|
|
16
|
-
<section className="my-8 px-4 pt-10 pb-4 text-white">
|
|
17
|
-
<h1 className="text-7xl mb-4 font-semibold tracking-tight">
|
|
18
|
-
{blog.title}
|
|
19
|
-
</h1>
|
|
20
|
-
</section>
|
|
21
|
-
|
|
22
|
-
<section className="my-8 px-4 pb-4">
|
|
23
|
-
<ul className="space-y-12 mt-8">
|
|
24
|
-
{blog.articles.edges.map((edge) => {
|
|
25
|
-
const article = edge.node;
|
|
26
|
-
return (
|
|
27
|
-
<li
|
|
28
|
-
key={article.id}
|
|
29
|
-
className="p-5 rounded-3xl overflow-hidden shadow-2xl bg-white bg-opacity-70"
|
|
30
|
-
>
|
|
31
|
-
<h2 className="text-xl font-medium">
|
|
32
|
-
<Link to={`/blogs/${handle}/${article.handle}`}>
|
|
33
|
-
{article.title}
|
|
34
|
-
</Link>
|
|
35
|
-
</h2>
|
|
36
|
-
<p className="font-medium mt-1">
|
|
37
|
-
Published on{' '}
|
|
38
|
-
{new Date(article.publishedAt).toLocaleDateString()} by{' '}
|
|
39
|
-
{article.author.name}
|
|
40
|
-
</p>
|
|
41
|
-
|
|
42
|
-
<RawHtml
|
|
43
|
-
string={article.contentHtml}
|
|
44
|
-
className="mt-2 prose"
|
|
45
|
-
/>
|
|
46
|
-
</li>
|
|
47
|
-
);
|
|
48
|
-
})}
|
|
49
|
-
</ul>
|
|
50
|
-
</section>
|
|
51
|
-
</div>
|
|
52
|
-
</Layout>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const QUERY = gql`
|
|
57
|
-
query BlogDetails($handle: String!) {
|
|
58
|
-
blogByHandle(handle: $handle) {
|
|
59
|
-
title
|
|
60
|
-
articles(first: 10) {
|
|
61
|
-
edges {
|
|
62
|
-
node {
|
|
63
|
-
id
|
|
64
|
-
title
|
|
65
|
-
handle
|
|
66
|
-
publishedAt
|
|
67
|
-
contentHtml
|
|
68
|
-
author {
|
|
69
|
-
name
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
`;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import {MediaFileFragment, useShopQuery} from '@shopify/hydrogen';
|
|
2
|
-
import {useParams} from 'react-router-dom';
|
|
3
|
-
import gql from 'graphql-tag';
|
|
4
|
-
|
|
5
|
-
import Layout from '../../components/Layout.client';
|
|
6
|
-
import ProductCard from '../../components/ProductCard.client';
|
|
7
|
-
|
|
8
|
-
export default function Collection() {
|
|
9
|
-
const {handle} = useParams();
|
|
10
|
-
const {data} = useShopQuery({query: QUERY, variables: {handle}});
|
|
11
|
-
|
|
12
|
-
const collection = data.collectionByHandle;
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<Layout>
|
|
16
|
-
<h1 className="text-2xl font-bold">{collection.title}</h1>
|
|
17
|
-
|
|
18
|
-
<ul className="grid lg:grid-cols-3 gap-6 mt-4">
|
|
19
|
-
{collection.products.edges.map((edge) => (
|
|
20
|
-
<li key={edge.node.id}>
|
|
21
|
-
<ProductCard product={edge.node} />
|
|
22
|
-
</li>
|
|
23
|
-
))}
|
|
24
|
-
</ul>
|
|
25
|
-
</Layout>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const QUERY = gql`
|
|
30
|
-
fragment CollectionProductDetails on Product {
|
|
31
|
-
id
|
|
32
|
-
title
|
|
33
|
-
handle
|
|
34
|
-
priceRange {
|
|
35
|
-
maxVariantPrice {
|
|
36
|
-
amount
|
|
37
|
-
currencyCode
|
|
38
|
-
}
|
|
39
|
-
minVariantPrice {
|
|
40
|
-
amount
|
|
41
|
-
currencyCode
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
media(first: 1) {
|
|
45
|
-
edges {
|
|
46
|
-
node {
|
|
47
|
-
...MediaFileFragment
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
query CollectionDetails($handle: String!) {
|
|
54
|
-
collectionByHandle(handle: $handle) {
|
|
55
|
-
id
|
|
56
|
-
title
|
|
57
|
-
|
|
58
|
-
products(first: 10) {
|
|
59
|
-
edges {
|
|
60
|
-
node {
|
|
61
|
-
...CollectionProductDetails
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
${MediaFileFragment}
|
|
69
|
-
`;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import {useShopQuery, ProductProviderFragment} from '@shopify/hydrogen';
|
|
2
|
-
import {useParams} from 'react-router-dom';
|
|
3
|
-
import gql from 'graphql-tag';
|
|
4
|
-
|
|
5
|
-
import ProductDetails from '../../components/ProductDetails.client';
|
|
6
|
-
import NotFound from '../../components/NotFound.server';
|
|
7
|
-
|
|
8
|
-
export default function Product() {
|
|
9
|
-
const {handle} = useParams();
|
|
10
|
-
|
|
11
|
-
const {data} = useShopQuery({
|
|
12
|
-
query: QUERY,
|
|
13
|
-
variables: {
|
|
14
|
-
handle,
|
|
15
|
-
numProductMetafields: 10,
|
|
16
|
-
numProductVariants: 250,
|
|
17
|
-
numProductMedia: 6,
|
|
18
|
-
numProductVariantMetafields: 10,
|
|
19
|
-
numProductVariantSellingPlanAllocations: 10,
|
|
20
|
-
numProductSellingPlanGroups: 10,
|
|
21
|
-
numProductSellingPlans: 10,
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (!data.product) {
|
|
26
|
-
return <NotFound />;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return <ProductDetails data={data} />;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const QUERY = gql`
|
|
33
|
-
query product(
|
|
34
|
-
$handle: String!
|
|
35
|
-
$numProductMetafields: Int!
|
|
36
|
-
$numProductVariants: Int!
|
|
37
|
-
$numProductMedia: Int!
|
|
38
|
-
$numProductVariantMetafields: Int!
|
|
39
|
-
$numProductVariantSellingPlanAllocations: Int!
|
|
40
|
-
$numProductSellingPlanGroups: Int!
|
|
41
|
-
$numProductSellingPlans: Int!
|
|
42
|
-
) {
|
|
43
|
-
product: product(handle: $handle) {
|
|
44
|
-
id
|
|
45
|
-
vendor
|
|
46
|
-
seo {
|
|
47
|
-
title
|
|
48
|
-
description
|
|
49
|
-
}
|
|
50
|
-
images(first: 1) {
|
|
51
|
-
edges {
|
|
52
|
-
node {
|
|
53
|
-
originalSrc
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
...ProductProviderFragment
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
${ProductProviderFragment}
|
|
62
|
-
`;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import {useEffect, useMemo, useState} from 'react';
|
|
2
|
-
import {useHistory, useLocation} from 'react-router-dom';
|
|
3
|
-
import {useShopQuery, MediaFileFragment} from '@shopify/hydrogen';
|
|
4
|
-
import gql from 'graphql-tag';
|
|
5
|
-
|
|
6
|
-
import Layout from '../components/Layout.client';
|
|
7
|
-
import ProductCard from '../components/ProductCard.client';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* TODO: Refactor to a true server component.
|
|
11
|
-
*/
|
|
12
|
-
export default function Search() {
|
|
13
|
-
const {search} = useLocation();
|
|
14
|
-
const originalQuery = useMemo(
|
|
15
|
-
() => new URLSearchParams(search).get('query'),
|
|
16
|
-
[search],
|
|
17
|
-
);
|
|
18
|
-
const history = useHistory();
|
|
19
|
-
const [query, setQuery] = useState(originalQuery);
|
|
20
|
-
const [newQuery, setNewQuery] = useState(query);
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (originalQuery) {
|
|
24
|
-
setQuery(originalQuery);
|
|
25
|
-
}
|
|
26
|
-
}, [originalQuery]);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<Layout>
|
|
30
|
-
<h1 className="text-2xl font-bold">Search</h1>
|
|
31
|
-
<form
|
|
32
|
-
onSubmit={(event) => {
|
|
33
|
-
event.preventDefault();
|
|
34
|
-
setQuery(newQuery);
|
|
35
|
-
history.push(`/search?query=${newQuery}`);
|
|
36
|
-
}}
|
|
37
|
-
className="mt-4 space-x-2"
|
|
38
|
-
>
|
|
39
|
-
<label htmlFor="search">Search Products:</label>
|
|
40
|
-
<input
|
|
41
|
-
autocomplete="off"
|
|
42
|
-
name="search"
|
|
43
|
-
id="search"
|
|
44
|
-
type="search"
|
|
45
|
-
value={newQuery}
|
|
46
|
-
onChange={(event) => setNewQuery(event.target.value)}
|
|
47
|
-
className="p-1"
|
|
48
|
-
/>
|
|
49
|
-
<button type="submit" className="bg-black text-white font-bold p-1">
|
|
50
|
-
Search
|
|
51
|
-
</button>
|
|
52
|
-
</form>
|
|
53
|
-
{query && <SearchResults query={query} />}
|
|
54
|
-
</Layout>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function SearchResults({query}) {
|
|
59
|
-
const {data, fetching} = useShopQuery({query: QUERY, variables: {query}});
|
|
60
|
-
|
|
61
|
-
if (fetching) return <p>Loading...</p>;
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<>
|
|
65
|
-
<h2 className="text-xl font-medium mt-8">Search results for: {query}</h2>
|
|
66
|
-
|
|
67
|
-
{data.products.edges.length ? (
|
|
68
|
-
<ul className="grid lg:grid-cols-3 gap-6 mt-4">
|
|
69
|
-
{data.products.edges.map((edge) => (
|
|
70
|
-
<li key={edge.node.id}>
|
|
71
|
-
<ProductCard product={edge.node} />
|
|
72
|
-
</li>
|
|
73
|
-
))}
|
|
74
|
-
</ul>
|
|
75
|
-
) : (
|
|
76
|
-
<p>No results found.</p>
|
|
77
|
-
)}
|
|
78
|
-
</>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const QUERY = gql`
|
|
83
|
-
fragment SearchProductDetails on Product {
|
|
84
|
-
id
|
|
85
|
-
title
|
|
86
|
-
handle
|
|
87
|
-
media(first: 1) {
|
|
88
|
-
edges {
|
|
89
|
-
node {
|
|
90
|
-
...MediaFileFragment
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
query ProductSearch($query: String!) {
|
|
97
|
-
products(query: $query, first: 10) {
|
|
98
|
-
edges {
|
|
99
|
-
node {
|
|
100
|
-
...SearchProductDetails
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
${MediaFileFragment}
|
|
107
|
-
`;
|