@shopify/create-hydrogen 0.2.0 → 0.16.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 (96) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/run.cmd +3 -0
  3. package/bin/run.js +5 -0
  4. package/dist/commands/init.js +76397 -0
  5. package/dist/commands/init.js.map +1 -0
  6. package/dist/index.js +21 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +61 -14
  9. package/templates/template-hydrogen/.devcontainer/devcontainer.json +18 -0
  10. package/templates/template-hydrogen/.eslintrc.js +3 -0
  11. package/templates/template-hydrogen/.gitignore +7 -0
  12. package/templates/template-hydrogen/.stackblitzrc +4 -0
  13. package/{template-hydrogen → templates/template-hydrogen}/.stylelintrc.js +1 -1
  14. package/templates/template-hydrogen/.vscode/extensions.json +8 -0
  15. package/templates/template-hydrogen/Dockerfile +15 -0
  16. package/{template-hydrogen → templates/template-hydrogen}/README.md +11 -2
  17. package/{template-hydrogen → templates/template-hydrogen}/_gitignore +0 -0
  18. package/templates/template-hydrogen/index.html +20 -0
  19. package/{template-hydrogen → templates/template-hydrogen}/package.json +20 -16
  20. package/{template-hydrogen → templates/template-hydrogen}/postcss.config.js +0 -0
  21. package/{template-hydrogen/src → templates/template-hydrogen/public}/favicon.svg +0 -0
  22. package/{template-hydrogen → templates/template-hydrogen}/server.js +4 -2
  23. package/{template-hydrogen → templates/template-hydrogen}/shopify.config.js +1 -2
  24. package/templates/template-hydrogen/src/App.client.jsx +8 -0
  25. package/templates/template-hydrogen/src/App.server.jsx +27 -0
  26. package/templates/template-hydrogen/src/components/Button.client.jsx +65 -0
  27. package/templates/template-hydrogen/src/components/Cart.client.jsx +265 -0
  28. package/templates/template-hydrogen/src/components/CartIcon.jsx +33 -0
  29. package/templates/template-hydrogen/src/components/CartIconWithItems.client.jsx +28 -0
  30. package/templates/template-hydrogen/src/components/CartProvider.client.jsx +35 -0
  31. package/templates/template-hydrogen/src/components/CartToggle.client.jsx +30 -0
  32. package/{template-hydrogen → templates/template-hydrogen}/src/components/CartUIProvider.client.jsx +3 -0
  33. package/templates/template-hydrogen/src/components/CountrySelector.client.jsx +116 -0
  34. package/templates/template-hydrogen/src/components/DefaultSeo.server.jsx +35 -0
  35. package/templates/template-hydrogen/src/components/FeaturedCollection.jsx +26 -0
  36. package/templates/template-hydrogen/src/components/Footer.server.jsx +103 -0
  37. package/templates/template-hydrogen/src/components/Gallery.client.jsx +65 -0
  38. package/templates/template-hydrogen/src/components/Header.client.jsx +62 -0
  39. package/templates/template-hydrogen/src/components/Layout.server.jsx +87 -0
  40. package/templates/template-hydrogen/src/components/LoadMoreProducts.client.jsx +56 -0
  41. package/templates/template-hydrogen/src/components/LoadingFallback.jsx +26 -0
  42. package/templates/template-hydrogen/src/components/MobileCountrySelector.client.jsx +64 -0
  43. package/templates/template-hydrogen/src/components/MobileNavigation.client.jsx +98 -0
  44. package/templates/template-hydrogen/src/components/MoneyCompareAtPrice.client.jsx +14 -0
  45. package/templates/template-hydrogen/src/components/MoneyPrice.client.jsx +15 -0
  46. package/templates/template-hydrogen/src/components/Navigation.client.jsx +23 -0
  47. package/templates/template-hydrogen/src/components/NotFound.server.jsx +93 -0
  48. package/templates/template-hydrogen/src/components/OpenIcon.jsx +33 -0
  49. package/templates/template-hydrogen/src/components/ProductCard.jsx +50 -0
  50. package/templates/template-hydrogen/src/components/ProductDetails.client.jsx +242 -0
  51. package/{template-hydrogen → templates/template-hydrogen}/src/components/ProductOptions.client.jsx +7 -4
  52. package/templates/template-hydrogen/src/components/Welcome.server.jsx +188 -0
  53. package/templates/template-hydrogen/src/entry-client.jsx +7 -0
  54. package/templates/template-hydrogen/src/entry-server.jsx +6 -0
  55. package/{template-hydrogen → templates/template-hydrogen}/src/index.css +31 -0
  56. package/templates/template-hydrogen/src/pages/collections/[handle].server.jsx +105 -0
  57. package/templates/template-hydrogen/src/pages/index.server.jsx +237 -0
  58. package/{template-hydrogen → templates/template-hydrogen}/src/pages/pages/[handle].server.jsx +14 -5
  59. package/templates/template-hydrogen/src/pages/products/[handle].server.jsx +69 -0
  60. package/templates/template-hydrogen/src/pages/redirect.server.jsx +4 -0
  61. package/templates/template-hydrogen/src/pages/robots.txt.server.js +10 -0
  62. package/{template-hydrogen → templates/template-hydrogen}/src/pages/sitemap.xml.server.jsx +2 -2
  63. package/templates/template-hydrogen/tailwind.config.js +26 -0
  64. package/{template-hydrogen → templates/template-hydrogen}/vite.config.js +1 -0
  65. package/{template-hydrogen → templates/template-hydrogen}/worker.js +1 -0
  66. package/README.md +0 -3
  67. package/index.js +0 -205
  68. package/scripts/tmp-copy-template-from-dev.js +0 -21
  69. package/scripts/utils.js +0 -29
  70. package/template-hydrogen/.eslintrc.js +0 -41
  71. package/template-hydrogen/.vscode/extensions.json +0 -3
  72. package/template-hydrogen/Dockerfile +0 -15
  73. package/template-hydrogen/index.html +0 -14
  74. package/template-hydrogen/src/App.server.jsx +0 -42
  75. package/template-hydrogen/src/components/Cart.client.jsx +0 -296
  76. package/template-hydrogen/src/components/CartProvider.client.jsx +0 -40
  77. package/template-hydrogen/src/components/DefaultSeo.server.jsx +0 -22
  78. package/template-hydrogen/src/components/Footer.jsx +0 -12
  79. package/template-hydrogen/src/components/Gallery.client.jsx +0 -36
  80. package/template-hydrogen/src/components/Header.client.jsx +0 -103
  81. package/template-hydrogen/src/components/HightlightedProduct.client.jsx +0 -54
  82. package/template-hydrogen/src/components/Layout.client.jsx +0 -41
  83. package/template-hydrogen/src/components/MediaPlaceholder.jsx +0 -21
  84. package/template-hydrogen/src/components/NotFound.server.jsx +0 -104
  85. package/template-hydrogen/src/components/ProductCard.client.jsx +0 -39
  86. package/template-hydrogen/src/components/ProductDetails.client.jsx +0 -184
  87. package/template-hydrogen/src/components/Seo.client.jsx +0 -75
  88. package/template-hydrogen/src/entry-client.jsx +0 -12
  89. package/template-hydrogen/src/entry-server.jsx +0 -7
  90. package/template-hydrogen/src/pages/Index.server.jsx +0 -199
  91. package/template-hydrogen/src/pages/blogs/[handle]/[articleHandle].server.jsx +0 -49
  92. package/template-hydrogen/src/pages/blogs/[handle].server.jsx +0 -76
  93. package/template-hydrogen/src/pages/collections/[handle].server.jsx +0 -69
  94. package/template-hydrogen/src/pages/products/[handle].server.jsx +0 -62
  95. package/template-hydrogen/src/pages/search.server.jsx +0 -107
  96. package/template-hydrogen/tailwind.config.js +0 -9
package/index.js DELETED
@@ -1,205 +0,0 @@
1
- #!/usr/bin/env node
2
- // @ts-check
3
-
4
- // Inspired by and borrowed from https://github.com/vitejs/vite/blob/main/packages/create-app/index.js
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
- const argv = require('minimist')(process.argv.slice(2));
9
- const {prompt} = require('enquirer');
10
- const {yellow} = require('kolorist');
11
- const {copy} = require('./scripts/utils.js');
12
-
13
- const cwd = process.cwd();
14
-
15
- const TEMPLATES = ['hydrogen'];
16
-
17
- const renameFiles = {
18
- _gitignore: '.gitignore',
19
- };
20
-
21
- console.warn(
22
- 'DEPRECATED: Please use `npm init hydrogen-app@latest` or `yarn create hydrogen-app` instead.'
23
- );
24
-
25
- async function init() {
26
- let targetDir = argv._[0];
27
- if (!targetDir) {
28
- /**
29
- * @type {{ projectName: string }}
30
- */
31
- const {projectName} = await prompt({
32
- type: 'input',
33
- name: 'projectName',
34
- message: `Project name:`,
35
- initial: 'hydrogen-app',
36
- });
37
- targetDir = projectName;
38
- }
39
-
40
- const packageName = await getValidPackageName(targetDir);
41
- const root = path.join(cwd, targetDir);
42
- console.log(`\nScaffolding Hydrogen app in ${root}...`);
43
-
44
- if (!fs.existsSync(root)) {
45
- fs.mkdirSync(root, {recursive: true});
46
- } else {
47
- const existing = fs.readdirSync(root);
48
- if (existing.length) {
49
- /**
50
- * @type {{ yes: boolean }}
51
- */
52
- const {yes} = await prompt({
53
- type: 'confirm',
54
- name: 'yes',
55
- initial: 'Y',
56
- message:
57
- `Target directory ${targetDir} is not empty.\n` +
58
- `Remove existing files and continue?`,
59
- });
60
- if (yes) {
61
- emptyDir(root);
62
- } else {
63
- return;
64
- }
65
- }
66
- }
67
-
68
- // Determine template
69
- let template = argv.t || argv.template;
70
- let message = 'Select a template:';
71
- let isValidTemplate = false;
72
-
73
- // --template expects a value
74
- if (typeof template === 'string') {
75
- isValidTemplate = TEMPLATES.includes(template);
76
- message = `${template} isn't a valid template. Please choose from below:`;
77
- }
78
-
79
- if (!template || !isValidTemplate) {
80
- /**
81
- * @type {{ t: string }}
82
- */
83
- const {t} = await prompt({
84
- type: 'select',
85
- name: 't',
86
- message,
87
- choices: TEMPLATES,
88
- });
89
- template = t;
90
- }
91
-
92
- const templateDir = path.join(__dirname, `template-${template}`);
93
-
94
- const write = (file, content) => {
95
- const targetPath = renameFiles[file]
96
- ? path.join(root, renameFiles[file])
97
- : path.join(root, file);
98
- if (content) {
99
- fs.writeFileSync(targetPath, content);
100
- } else {
101
- copy(path.join(templateDir, file), targetPath);
102
- }
103
- };
104
-
105
- const files = fs.readdirSync(templateDir);
106
- const skipFiles = ['package.json', 'node_modules', 'dist'];
107
- for (const file of files.filter((f) => !skipFiles.includes(f))) {
108
- write(file);
109
- }
110
-
111
- const pkg = require(path.join(templateDir, `package.json`));
112
-
113
- pkg.name = packageName;
114
-
115
- /**
116
- * When the user is running a LOCAL version of hydrogen external from the
117
- * monorepo, they expect to use the local version of the library instead
118
- * of the registry version. We need to use a file reference here because
119
- * yarn fails to link scoped packages.
120
- **/
121
-
122
- if (process.env.LOCAL) {
123
- pkg.dependencies['@shopify/hydrogen'] =
124
- 'file:../../Shopify/hydrogen/packages/hydrogen';
125
- }
126
-
127
- /**
128
- * Rewrite the build:client task to strip out the custom HYDROGEN_PATH
129
- * we add for use in the monorepo.
130
- */
131
- pkg.scripts['build:client'] =
132
- pkg.scripts['build:client'].match(/(vite .+)$/)[0];
133
-
134
- write('package.json', JSON.stringify(pkg, null, 2));
135
-
136
- const pkgManager = /yarn/.test(process.env.npm_execpath) ? 'yarn' : 'npm';
137
-
138
- console.log(`\nDone. Now:\n`);
139
- console.log(
140
- ` Update ${yellow(
141
- packageName + '/shopify.config.js'
142
- )} with the values for your storefront.`
143
- );
144
- console.log(`\nand then run:\n`);
145
- if (root !== cwd) {
146
- console.log(` cd ${path.relative(cwd, root)}`);
147
- }
148
-
149
- /**
150
- * The LOCAL option only works with Yarn due to issues with NPM
151
- * and symlinking yarn monorepos.
152
- */
153
- const usesYarn = pkgManager === 'yarn' || process.env.LOCAL;
154
-
155
- console.log(` ${usesYarn ? `yarn` : `npm install`}`);
156
- console.log(` ${usesYarn ? `yarn dev` : `npm run dev`}`);
157
- console.log();
158
- }
159
-
160
- async function getValidPackageName(projectName) {
161
- const packageNameRegExp =
162
- /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
163
- if (packageNameRegExp.test(projectName)) {
164
- return projectName;
165
- } else {
166
- const suggestedPackageName = projectName
167
- .trim()
168
- .toLowerCase()
169
- .replace(/\s+/g, '-')
170
- .replace(/^[._]/, '')
171
- .replace(/[^a-z0-9-~]+/g, '-');
172
-
173
- /**
174
- * @type {{ inputPackageName: string }}
175
- */
176
- const {inputPackageName} = await prompt({
177
- type: 'input',
178
- name: 'inputPackageName',
179
- message: `Package name:`,
180
- initial: suggestedPackageName,
181
- validate: (input) =>
182
- packageNameRegExp.test(input) ? true : 'Invalid package.json name',
183
- });
184
- return inputPackageName;
185
- }
186
- }
187
-
188
- function emptyDir(dir) {
189
- if (!fs.existsSync(dir)) {
190
- return;
191
- }
192
- for (const file of fs.readdirSync(dir)) {
193
- const abs = path.resolve(dir, file);
194
- if (fs.lstatSync(abs).isDirectory()) {
195
- emptyDir(abs);
196
- fs.rmdirSync(abs);
197
- } else {
198
- fs.unlinkSync(abs);
199
- }
200
- }
201
- }
202
-
203
- init().catch((e) => {
204
- console.error(e);
205
- });
@@ -1,21 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * This is a temporary script meant to copy `packages/dev` to `./template-hydrogen`
5
- * while we are actively developing H2 in `dev`. Eventually, the template will just
6
- * live in this folder.
7
- */
8
-
9
- const path = require('path');
10
- const fs = require('fs');
11
- const {copy} = require('./utils');
12
-
13
- const devPath = path.resolve(__dirname, '..', '..', 'dev');
14
- const templatePath = path.resolve(__dirname, '..', './template-hydrogen');
15
- const skipFiles = ['node_modules', 'dist'];
16
-
17
- // Remove the symlink and replace it with a folder
18
- fs.unlinkSync(templatePath);
19
- fs.mkdirSync(templatePath, {recursive: true});
20
-
21
- copy(devPath, templatePath, skipFiles);
package/scripts/utils.js DELETED
@@ -1,29 +0,0 @@
1
- // @ts-check
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- function copyDir(srcDir, destDir, skipFiles = []) {
6
- fs.mkdirSync(destDir, {recursive: true});
7
- for (const file of fs.readdirSync(srcDir)) {
8
- const srcFile = path.resolve(srcDir, file);
9
- const destFile = path.resolve(destDir, file);
10
- copy(srcFile, destFile, skipFiles);
11
- }
12
- }
13
-
14
- function copy(src, dest, skipFiles = []) {
15
- if (skipFiles.some((file) => src.includes(file))) return;
16
-
17
- const stat = fs.statSync(src);
18
-
19
- if (stat.isDirectory()) {
20
- copyDir(src, dest, skipFiles);
21
- } else {
22
- fs.copyFileSync(src, dest);
23
- }
24
- }
25
-
26
- module.exports = {
27
- copy,
28
- copyDir,
29
- };
@@ -1,41 +0,0 @@
1
- module.exports = {
2
- extends: [
3
- 'plugin:@shopify/typescript',
4
- 'plugin:@shopify/react',
5
- 'plugin:@shopify/node',
6
- 'plugin:@shopify/prettier',
7
- ],
8
- rules: {
9
- '@shopify/jsx-no-hardcoded-content': 'off',
10
- '@shopify/jsx-no-complex-expressions': 'off',
11
-
12
- /**
13
- * React overrides
14
- */
15
- 'react/react-in-jsx-scope': 'off',
16
- 'react/jsx-filename-extension': ['error', {extensions: ['.tsx', '.jsx']}],
17
- 'react/prop-types': 'off',
18
-
19
- /**
20
- * Import overrides
21
- */
22
- 'import/no-unresolved': ['error', {ignore: ['@shopify/hydrogen']}],
23
-
24
- /**
25
- * ESlint overrides
26
- */
27
- 'no-use-before-define': 'off',
28
- 'no-warning-comments': 'off',
29
-
30
- /**
31
- * jsx-a11y overrides
32
- */
33
- 'jsx-a11y/click-events-have-key-events': 'off',
34
- 'jsx-a11y/no-noninteractive-element-interactions': 'off',
35
-
36
- // These two rules result in a significant number of false positives so we
37
- // need to keep them disabled.
38
- 'jsx-a11y/label-has-for': 'off',
39
- 'jsx-a11y/control-has-associated-label': 'off',
40
- },
41
- };
@@ -1,3 +0,0 @@
1
- {
2
- "recommendations": ["graphql.vscode-graphql", "bradlc.vscode-tailwindcss"]
3
- }
@@ -1,15 +0,0 @@
1
- FROM node:14 AS build-env
2
- ADD . /app
3
-
4
- WORKDIR /app
5
- RUN npm install
6
- RUN npm run build
7
-
8
- FROM gcr.io/distroless/nodejs:14 AS run-env
9
- ENV NODE_ENV production
10
- COPY --from=build-env /app /app
11
-
12
- EXPOSE 8080
13
-
14
- WORKDIR /app
15
- CMD ["server.js"]
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Hydrogen App</title>
8
- <link rel="stylesheet" href="/src/index.css" />
9
- </head>
10
- <body>
11
- <div id="root"></div>
12
- <script type="module" src="/src/entry-client.jsx"></script>
13
- </body>
14
- </html>
@@ -1,42 +0,0 @@
1
- import {
2
- ShopifyServerProvider,
3
- DefaultRoutes,
4
- CartServerProvider,
5
- } from '@shopify/hydrogen';
6
- import {Switch} from 'react-router-dom';
7
- import {Suspense} from 'react';
8
-
9
- import shopifyConfig from '../shopify.config';
10
-
11
- import DefaultSeo from './components/DefaultSeo.server';
12
- import NotFound from './components/NotFound.server';
13
- import CartProvider from './components/CartProvider.client';
14
-
15
- export default function App({...serverState}) {
16
- const pages = import.meta.globEager('./pages/**/*.server.(jsx|tsx)');
17
-
18
- return (
19
- <ShopifyServerProvider shopifyConfig={shopifyConfig} {...serverState}>
20
- {/* START: Workaround for CartContext */}
21
- <CartServerProvider request={serverState.request}>
22
- {({cart, numCartLines}) => {
23
- return (
24
- <CartProvider cart={cart} numCartLines={numCartLines}>
25
- {/* END: Workaround for CartContext */}
26
- <Suspense fallback="Loading...">
27
- <DefaultSeo />
28
- <Switch>
29
- <DefaultRoutes
30
- pages={pages}
31
- serverState={serverState}
32
- fallback={<NotFound />}
33
- />
34
- </Switch>
35
- </Suspense>
36
- </CartProvider>
37
- );
38
- }}
39
- </CartServerProvider>
40
- </ShopifyServerProvider>
41
- );
42
- }
@@ -1,296 +0,0 @@
1
- import FocusTrap from 'focus-trap-react';
2
- import {
3
- useCart,
4
- useCartLinesTotalQuantity,
5
- CartCheckoutButton,
6
- Link,
7
- CartLines,
8
- CartLine,
9
- CartShopPayButton,
10
- CartEstimatedCost,
11
- } from '@shopify/hydrogen/client';
12
-
13
- import {useCartUI} from './CartUIProvider.client';
14
-
15
- export default function Cart() {
16
- const {isCartOpen} = useCartUI();
17
- const itemCount = useCartLinesTotalQuantity();
18
- const {error} = useCart();
19
-
20
- return (
21
- <FocusTrap active={isCartOpen} focusTrapOptions={{allowOutsideClick: true}}>
22
- <aside
23
- className={`pointer-events-none z-50 fixed right-0 top-0 bottom-0 md:p-5 flex flex-col w-full max-w-md min-w-sm transition-transform duration-500 transform-gpu ${
24
- isCartOpen ? 'right-0' : 'translate-x-full'
25
- }`}
26
- id="cart"
27
- tabIndex={-1}
28
- aria-hidden={!isCartOpen}
29
- aria-label="Cart"
30
- >
31
- <div className="overflow-hidden md:h-auto pointer-events-auto">
32
- <div className="flex flex-col shadow-xl max-h-full">
33
- <header className="bg-white px-4 md:px-8 md:h-20 border-b border-gray-300 border-solid rounded-t-md flex flex-shrink-0 items-center justify-between">
34
- <CartHeader />
35
- </header>
36
-
37
- <div className="bg-white px-4 md:px-8 overflow-y-scroll md:max-h-96">
38
- {itemCount > 0 ? (
39
- <CartLineItems />
40
- ) : (
41
- <p className="text-center text-gray-600 my-8">
42
- Your cart is empty
43
- </p>
44
- )}
45
- </div>
46
-
47
- {error ? (
48
- <div
49
- className="border bg-red-200 border-red-400 text-red-800 mb-4 mx-8 px-4 py-3 rounded relative"
50
- role="alert"
51
- >
52
- {error}
53
- </div>
54
- ) : null}
55
-
56
- <footer
57
- className={`${
58
- itemCount > 0 ? 'border-t border-solid border-gray-300' : ''
59
- } bg-white p-4 md:p-8 space-y-4 flex-shrink-0 rounded-b-md`}
60
- >
61
- {itemCount > 0 ? <CartFooter /> : null}
62
- </footer>
63
- </div>
64
- </div>
65
- </aside>
66
- </FocusTrap>
67
- );
68
- }
69
-
70
- function CartHeader() {
71
- const {isCartOpen, toggleCart} = useCartUI();
72
- const itemCount = useCartLinesTotalQuantity();
73
-
74
- return (
75
- <>
76
- <button
77
- type="button"
78
- aria-expanded={isCartOpen}
79
- aria-controls="cart"
80
- onClick={toggleCart}
81
- >
82
- <div>
83
- <svg
84
- xmlns="http://www.w3.org/2000/svg"
85
- className="h-5 w-5 text-gray-600"
86
- viewBox="0 0 20 20"
87
- fill="currentColor"
88
- >
89
- <path
90
- fillRule="evenodd"
91
- d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
92
- clipRule="evenodd"
93
- />
94
- </svg>
95
- </div>
96
- <span className="sr-only">Close cart</span>
97
- </button>
98
- <div className="h-12 w-12 p-2 md:h-7 md:w-7 md:p-0">
99
- <div className="relative">
100
- <svg
101
- width="19"
102
- height="24"
103
- viewBox="0 0 19 24"
104
- fill="none"
105
- xmlns="http://www.w3.org/2000/svg"
106
- >
107
- <path
108
- d="M15.5894 7H3.41063C2.89451 7 2.46318 7.39279 2.415 7.90666L1.205 20.8133C1.09502 21.9865 2.01796 23 3.19627 23H15.8037C16.982 23 17.905 21.9865 17.795 20.8133L16.585 7.90666C16.5368 7.39279 16.1055 7 15.5894 7Z"
109
- stroke="#1F2937"
110
- strokeWidth="2"
111
- strokeMiterlimit="10"
112
- strokeLinecap="round"
113
- />
114
- <path
115
- d="M6 7V9.98952C6 12.0075 7.63589 13.6434 9.65386 13.6434V13.6434C11.6718 13.6434 13.3077 12.0075 13.3077 9.98952V7"
116
- stroke="#1F2937"
117
- strokeWidth="2"
118
- />
119
- <path
120
- d="M13 6L13 4.5C13 2.567 11.433 1 9.5 1V1C7.567 1 6 2.567 6 4.5L6 6"
121
- stroke="#1F2937"
122
- strokeWidth="2"
123
- className={`${itemCount > 0 ? 'block' : 'hidden'}`}
124
- />
125
- </svg>
126
- </div>
127
- </div>
128
- </>
129
- );
130
- }
131
-
132
- function CartLineItems() {
133
- return (
134
- <div role="table" aria-label="Shopping cart">
135
- <div role="row" className="sr-only">
136
- <div role="columnheader">Image</div>
137
- <div role="columnheader">Item details</div>
138
- <div role="columnheader">Price</div>
139
- </div>
140
- <CartLines>
141
- {({merchandise}) => (
142
- <div
143
- role="row"
144
- className="pt-8 pb-8 border-b border-solid border-gray-300 last:border-0"
145
- >
146
- <div className="flex space-x-8 relative">
147
- <div role="cell">
148
- <div className="w-20 h-20 relative">
149
- <Link to={`/products/${merchandise.product.handle}`}>
150
- <CartLine.Image className="bg-white rounded w-full h-full object-cover" />
151
- </Link>
152
- </div>
153
- </div>
154
- <div
155
- role="cell"
156
- className="flex-grow flex flex-col justify-between"
157
- >
158
- <div className="flex gap-2">
159
- <div className="flex-grow">
160
- <CartLine.ProductTitle className="text-gray-900 font-semibold" />
161
- <CartLine.SelectedOptions className="text-sm">
162
- {({name, value}) => (
163
- <>
164
- {name}: {value}
165
- </>
166
- )}
167
- </CartLine.SelectedOptions>
168
- <CartLine.Attributes className="text-sm">
169
- {({key, value}) => (
170
- <>
171
- {key}: {value}
172
- </>
173
- )}
174
- </CartLine.Attributes>
175
- </div>
176
- <div className="flex-shrink">
177
- <CartLine.QuantityAdjustButton
178
- adjust="remove"
179
- aria-label="Remove from cart"
180
- >
181
- <svg
182
- xmlns="http://www.w3.org/2000/svg"
183
- className="h-5 w-5"
184
- viewBox="0 0 20 20"
185
- fill="currentColor"
186
- >
187
- <path
188
- fillRule="evenodd"
189
- d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
190
- clipRule="evenodd"
191
- />
192
- </svg>
193
- </CartLine.QuantityAdjustButton>
194
- </div>
195
- </div>
196
- <div className="flex mt-2">
197
- <div className="flex-grow">
198
- <div className="border border-solid border-gray-300 inline-flex items-center text-gray-500 rounded">
199
- <CartLine.QuantityAdjustButton
200
- adjust="decrease"
201
- className="p-2"
202
- aria-label="Decrease quantity"
203
- >
204
- <svg
205
- xmlns="http://www.w3.org/2000/svg"
206
- className="h-5 w-5"
207
- viewBox="0 0 20 20"
208
- fill="currentColor"
209
- >
210
- <path
211
- fillRule="evenodd"
212
- d="M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z"
213
- clipRule="evenodd"
214
- />
215
- </svg>
216
- </CartLine.QuantityAdjustButton>
217
- <CartLine.Quantity
218
- as="div"
219
- className="p-2 text-gray-900 text-center"
220
- />
221
- <CartLine.QuantityAdjustButton
222
- adjust="increase"
223
- className="p-2"
224
- aria-label="Increase quantity"
225
- >
226
- <svg
227
- xmlns="http://www.w3.org/2000/svg"
228
- className="h-5 w-5"
229
- viewBox="0 0 20 20"
230
- fill="currentColor"
231
- >
232
- <path
233
- fillRule="evenodd"
234
- d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
235
- clipRule="evenodd"
236
- />
237
- </svg>
238
- </CartLine.QuantityAdjustButton>
239
- </div>
240
- </div>
241
- </div>
242
- <CartLine.Price
243
- role="cell"
244
- className="absolute bottom-0 right-0 mb-3"
245
- />
246
- </div>
247
- </div>
248
- </div>
249
- )}
250
- </CartLines>
251
- </div>
252
- );
253
- }
254
-
255
- function CartFooter() {
256
- return (
257
- <>
258
- <div role="table" className="w-full" aria-label="Cost summary">
259
- <div role="row" className="flex items-center justify-between">
260
- <div role="rowheader" className="font-semibold">
261
- Subtotal
262
- </div>
263
- <CartEstimatedCost
264
- amountType="subtotal"
265
- role="cell"
266
- className="text-right"
267
- />
268
- </div>
269
- <div role="row" className="flex items-center justify-between">
270
- <div role="rowheader" className="font-semibold">
271
- Shipping
272
- </div>
273
- <div role="cell" className="text-right">
274
- Free
275
- </div>
276
- </div>
277
- <div role="row" className="flex items-center justify-between">
278
- <div role="rowheader" className="font-semibold">
279
- Total
280
- </div>
281
- <CartEstimatedCost
282
- amountType="total"
283
- role="cell"
284
- className="text-right"
285
- />
286
- </div>
287
- </div>
288
- <div className="space-y-2">
289
- <CartShopPayButton className="flex justify-center w-full" />
290
- <CartCheckoutButton className="block w-full text-white uppercase text-sm rounded-md md:mb-8 bg-black px-3 py-4 disabled:cursor-wait disabled:opacity-60">
291
- Checkout
292
- </CartCheckoutButton>
293
- </div>
294
- </>
295
- );
296
- }