├── .gitignore ├── README.md ├── jsconfig.json ├── netlify.toml ├── package-lock.json ├── package.json ├── src ├── app.css ├── app.html ├── components │ ├── CartTable.svelte │ ├── CartTotal.svelte │ ├── Footer.svelte │ ├── Header.svelte │ ├── ProductCard.svelte │ ├── ProductList.svelte │ └── utils │ │ └── currency.js ├── global.d.ts └── routes │ ├── __layout.svelte │ ├── api │ ├── add-to-cart.js │ ├── remove-from-cart.js │ └── utils │ │ ├── addItemToCart.js │ │ ├── createCartWithItem.js │ │ ├── postToShopify.js │ │ └── removeItemFromCart.js │ ├── cart.svelte │ ├── index.svelte │ └── products │ └── [handle].svelte ├── static ├── favicon.png ├── robots.txt ├── svelte-welcome.png └── svelte-welcome.webp ├── store.js └── svelte.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SvelteKit / Shopify Storefront Starter template 2 | 3 | This template provides a bare minimun starter for the new Shopify Storefront API built with [SvelteKit](https://kit.svelte.dev/) 4 | 5 | ### Available features: 6 | 7 | - Get products - Fetch and products from your Storefront API. 8 | - Product details page - Show a detailed product page for each listed product. 9 | - Variants - Show product variants and allow users to select them. 10 | - Cart - Add items to the cart and see a summary in the cart page. 11 | - Remove items from cart 12 | 13 | ## Getting started 14 | 15 | ### 1. Install and run SvelteKit with the commands below: 16 | 17 | ```bash 18 | npm init svelte@next sveltekit-shopify-demo 19 | cd sveltekit-shopify-demo 20 | npm install 21 | npm run dev -- --open 22 | 23 | ``` 24 | 25 | ### 2. Clone the project 26 | 27 | `git clone https://github.com/kenny-io/sveltekit-shopify-ecommerce` 28 | 29 | OR 30 | 31 | Just ... 32 | 33 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/kenny-io/sveltekit-shopify-ecommerce) 34 | 35 | And that's it! 36 | 37 | ### Preview 38 | 39 | This project is hosted on [Netlify](https://app.netlify.com/) and available here for preview https://sveltekit-shopify-ecommerce.netlify.app/ 40 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "$lib": ["src/lib"], 6 | "$lib/*": ["src/lib/*"] 7 | } 8 | }, 9 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] 10 | } 11 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "build/" 4 | functions = "functions/" 5 | 6 | [build.environment] 7 | NODE_VERSION = "12.20" 8 | 9 | 10 | [dev] 11 | command="npm run dev" 12 | publish="build" 13 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "~TODO~", 3 | "version": "0.0.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "~TODO~", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@fontsource/fira-mono": "^4.2.2", 12 | "@lukeed/uuid": "^2.0.0", 13 | "cookie": "^0.4.1" 14 | }, 15 | "devDependencies": { 16 | "@sveltejs/adapter-netlify": "^1.0.0-next.27", 17 | "@sveltejs/kit": "next", 18 | "svelte": "^3.34.0" 19 | } 20 | }, 21 | "node_modules/@fontsource/fira-mono": { 22 | "version": "4.5.0", 23 | "resolved": "https://registry.npmjs.org/@fontsource/fira-mono/-/fira-mono-4.5.0.tgz", 24 | "integrity": "sha512-KE+d3wmgq/YKM0BqgUF7p2yeBNi805Nfof1lC1wJ7E9i2EWoC363sGdKG+MQBVm+ei3GYZu+Bo8Xha1w1pkB7g==" 25 | }, 26 | "node_modules/@iarna/toml": { 27 | "version": "2.2.5", 28 | "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", 29 | "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", 30 | "dev": true 31 | }, 32 | "node_modules/@lukeed/csprng": { 33 | "version": "1.0.0", 34 | "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.0.0.tgz", 35 | "integrity": "sha512-ruuGHsnabmObBdeMg3vKdGRmh06Oog3eFpf/Tk6X0kDSJDpJTDCj2dqdp1+0VjzIUgHlFF9GBm7uFqfYhhdX9g==", 36 | "engines": { 37 | "node": ">=8" 38 | } 39 | }, 40 | "node_modules/@lukeed/uuid": { 41 | "version": "2.0.0", 42 | "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.0.tgz", 43 | "integrity": "sha512-dUz8OmYvlY5A9wXaroHIMSPASpSYRLCqbPvxGSyHguhtTQIy24lC+EGxQlwv71AhRCO55WOtgwhzQLpw27JaJQ==", 44 | "dependencies": { 45 | "@lukeed/csprng": "^1.0.0" 46 | }, 47 | "engines": { 48 | "node": ">=8" 49 | } 50 | }, 51 | "node_modules/@rollup/pluginutils": { 52 | "version": "4.1.1", 53 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", 54 | "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", 55 | "dev": true, 56 | "dependencies": { 57 | "estree-walker": "^2.0.1", 58 | "picomatch": "^2.2.2" 59 | }, 60 | "engines": { 61 | "node": ">= 8.0.0" 62 | } 63 | }, 64 | "node_modules/@sveltejs/adapter-netlify": { 65 | "version": "1.0.0-next.27", 66 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.27.tgz", 67 | "integrity": "sha512-t3kU2tJdCWmHwTBf+BRzzvYaM8ApxL+DEKtU1dUMI3bA8AgkpwkSHYiqZ75U2C+whi4mde+z15PeUFaUWzlKXA==", 68 | "dev": true, 69 | "dependencies": { 70 | "@iarna/toml": "^2.2.5", 71 | "esbuild": "^0.12.5" 72 | } 73 | }, 74 | "node_modules/@sveltejs/kit": { 75 | "version": "1.0.0-next.147", 76 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.147.tgz", 77 | "integrity": "sha512-rAABsKlC1K/B4VfqT2SaVO29t+OV8deseSJ9l+hV7j9zkswTwiJ7h37tZ5SfnvMgCHemcNjXg8Gzg+0U1MCfEA==", 78 | "dev": true, 79 | "dependencies": { 80 | "@sveltejs/vite-plugin-svelte": "^1.0.0-next.16", 81 | "cheap-watch": "^1.0.3", 82 | "sade": "^1.7.4", 83 | "vite": "^2.4.3" 84 | }, 85 | "bin": { 86 | "svelte-kit": "svelte-kit.js" 87 | }, 88 | "engines": { 89 | "node": "^12.20 || >=14.13" 90 | }, 91 | "peerDependencies": { 92 | "svelte": "^3.34.0" 93 | } 94 | }, 95 | "node_modules/@sveltejs/vite-plugin-svelte": { 96 | "version": "1.0.0-next.17", 97 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.17.tgz", 98 | "integrity": "sha512-Xh/YYqBMDJnDheutnGHk/I5TO6w9gZ2GMgvG+qQm/gpIRkaTLts6Mw5xDe6cac/nH/aVPPVPibhq2pf26d44fA==", 99 | "dev": true, 100 | "dependencies": { 101 | "@rollup/pluginutils": "^4.1.1", 102 | "debug": "^4.3.2", 103 | "kleur": "^4.1.4", 104 | "magic-string": "^0.25.7", 105 | "require-relative": "^0.8.7", 106 | "svelte-hmr": "^0.14.7" 107 | }, 108 | "engines": { 109 | "node": "^12.20 || ^14.13.1 || >= 16" 110 | }, 111 | "peerDependencies": { 112 | "diff-match-patch": "^1.0.5", 113 | "svelte": "^3.34.0", 114 | "vite": "^2.3.7" 115 | }, 116 | "peerDependenciesMeta": { 117 | "diff-match-patch": { 118 | "optional": true 119 | } 120 | } 121 | }, 122 | "node_modules/cheap-watch": { 123 | "version": "1.0.3", 124 | "resolved": "https://registry.npmjs.org/cheap-watch/-/cheap-watch-1.0.3.tgz", 125 | "integrity": "sha512-xC5CruMhLzjPwJ5ecUxGu1uGmwJQykUhqd2QrCrYbwvsFYdRyviu6jG9+pccwDXJR/OpmOTOJ9yLFunVgQu9wg==", 126 | "dev": true, 127 | "engines": { 128 | "node": ">=8" 129 | } 130 | }, 131 | "node_modules/colorette": { 132 | "version": "1.3.0", 133 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", 134 | "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", 135 | "dev": true 136 | }, 137 | "node_modules/cookie": { 138 | "version": "0.4.1", 139 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", 140 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", 141 | "engines": { 142 | "node": ">= 0.6" 143 | } 144 | }, 145 | "node_modules/debug": { 146 | "version": "4.3.2", 147 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 148 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 149 | "dev": true, 150 | "dependencies": { 151 | "ms": "2.1.2" 152 | }, 153 | "engines": { 154 | "node": ">=6.0" 155 | }, 156 | "peerDependenciesMeta": { 157 | "supports-color": { 158 | "optional": true 159 | } 160 | } 161 | }, 162 | "node_modules/esbuild": { 163 | "version": "0.12.20", 164 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.20.tgz", 165 | "integrity": "sha512-u7+0qTo9Z64MD9PhooEngCmzyEYJ6ovFhPp8PLNh3UasR5Ihjv6HWVXqm8uHmasdQlpsAf0IsY4U0YVUfCpt4Q==", 166 | "dev": true, 167 | "hasInstallScript": true, 168 | "bin": { 169 | "esbuild": "bin/esbuild" 170 | } 171 | }, 172 | "node_modules/estree-walker": { 173 | "version": "2.0.2", 174 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 175 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 176 | "dev": true 177 | }, 178 | "node_modules/fsevents": { 179 | "version": "2.3.2", 180 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 181 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 182 | "dev": true, 183 | "hasInstallScript": true, 184 | "optional": true, 185 | "os": [ 186 | "darwin" 187 | ], 188 | "engines": { 189 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 190 | } 191 | }, 192 | "node_modules/function-bind": { 193 | "version": "1.1.1", 194 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 195 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 196 | "dev": true 197 | }, 198 | "node_modules/has": { 199 | "version": "1.0.3", 200 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 201 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 202 | "dev": true, 203 | "dependencies": { 204 | "function-bind": "^1.1.1" 205 | }, 206 | "engines": { 207 | "node": ">= 0.4.0" 208 | } 209 | }, 210 | "node_modules/is-core-module": { 211 | "version": "2.5.0", 212 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", 213 | "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", 214 | "dev": true, 215 | "dependencies": { 216 | "has": "^1.0.3" 217 | }, 218 | "funding": { 219 | "url": "https://github.com/sponsors/ljharb" 220 | } 221 | }, 222 | "node_modules/kleur": { 223 | "version": "4.1.4", 224 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", 225 | "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", 226 | "dev": true, 227 | "engines": { 228 | "node": ">=6" 229 | } 230 | }, 231 | "node_modules/magic-string": { 232 | "version": "0.25.7", 233 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", 234 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", 235 | "dev": true, 236 | "dependencies": { 237 | "sourcemap-codec": "^1.4.4" 238 | } 239 | }, 240 | "node_modules/mri": { 241 | "version": "1.1.6", 242 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", 243 | "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", 244 | "dev": true, 245 | "engines": { 246 | "node": ">=4" 247 | } 248 | }, 249 | "node_modules/ms": { 250 | "version": "2.1.2", 251 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 252 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 253 | "dev": true 254 | }, 255 | "node_modules/nanoid": { 256 | "version": "3.1.25", 257 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", 258 | "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", 259 | "dev": true, 260 | "bin": { 261 | "nanoid": "bin/nanoid.cjs" 262 | }, 263 | "engines": { 264 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 265 | } 266 | }, 267 | "node_modules/path-parse": { 268 | "version": "1.0.7", 269 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 270 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 271 | "dev": true 272 | }, 273 | "node_modules/picomatch": { 274 | "version": "2.3.0", 275 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 276 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", 277 | "dev": true, 278 | "engines": { 279 | "node": ">=8.6" 280 | }, 281 | "funding": { 282 | "url": "https://github.com/sponsors/jonschlinkert" 283 | } 284 | }, 285 | "node_modules/postcss": { 286 | "version": "8.3.6", 287 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", 288 | "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", 289 | "dev": true, 290 | "dependencies": { 291 | "colorette": "^1.2.2", 292 | "nanoid": "^3.1.23", 293 | "source-map-js": "^0.6.2" 294 | }, 295 | "engines": { 296 | "node": "^10 || ^12 || >=14" 297 | }, 298 | "funding": { 299 | "type": "opencollective", 300 | "url": "https://opencollective.com/postcss/" 301 | } 302 | }, 303 | "node_modules/require-relative": { 304 | "version": "0.8.7", 305 | "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", 306 | "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", 307 | "dev": true 308 | }, 309 | "node_modules/resolve": { 310 | "version": "1.20.0", 311 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 312 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 313 | "dev": true, 314 | "dependencies": { 315 | "is-core-module": "^2.2.0", 316 | "path-parse": "^1.0.6" 317 | }, 318 | "funding": { 319 | "url": "https://github.com/sponsors/ljharb" 320 | } 321 | }, 322 | "node_modules/rollup": { 323 | "version": "2.56.2", 324 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz", 325 | "integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==", 326 | "dev": true, 327 | "bin": { 328 | "rollup": "dist/bin/rollup" 329 | }, 330 | "engines": { 331 | "node": ">=10.0.0" 332 | }, 333 | "optionalDependencies": { 334 | "fsevents": "~2.3.2" 335 | } 336 | }, 337 | "node_modules/sade": { 338 | "version": "1.7.4", 339 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", 340 | "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", 341 | "dev": true, 342 | "dependencies": { 343 | "mri": "^1.1.0" 344 | }, 345 | "engines": { 346 | "node": ">= 6" 347 | } 348 | }, 349 | "node_modules/source-map-js": { 350 | "version": "0.6.2", 351 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", 352 | "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", 353 | "dev": true, 354 | "engines": { 355 | "node": ">=0.10.0" 356 | } 357 | }, 358 | "node_modules/sourcemap-codec": { 359 | "version": "1.4.8", 360 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 361 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 362 | "dev": true 363 | }, 364 | "node_modules/svelte": { 365 | "version": "3.42.1", 366 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.1.tgz", 367 | "integrity": "sha512-XtExLd2JAU3T7M2g/DkO3UNj/3n1WdTXrfL63OZ5nZq7nAqd9wQw+lR4Pv/wkVbrWbAIPfLDX47UjFdmnY+YtQ==", 368 | "dev": true, 369 | "engines": { 370 | "node": ">= 8" 371 | } 372 | }, 373 | "node_modules/svelte-hmr": { 374 | "version": "0.14.7", 375 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.14.7.tgz", 376 | "integrity": "sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==", 377 | "dev": true, 378 | "peerDependencies": { 379 | "svelte": ">=3.19.0" 380 | } 381 | }, 382 | "node_modules/vite": { 383 | "version": "2.4.4", 384 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.4.4.tgz", 385 | "integrity": "sha512-m1wK6pFJKmaYA6AeZIUXyiAgUAAJzVXhIMYCdZUpCaFMGps0v0IlNJtbmPvkUhVEyautalajmnW5X6NboUPsnw==", 386 | "dev": true, 387 | "dependencies": { 388 | "esbuild": "^0.12.8", 389 | "postcss": "^8.3.6", 390 | "resolve": "^1.20.0", 391 | "rollup": "^2.38.5" 392 | }, 393 | "bin": { 394 | "vite": "bin/vite.js" 395 | }, 396 | "engines": { 397 | "node": ">=12.0.0" 398 | }, 399 | "optionalDependencies": { 400 | "fsevents": "~2.3.2" 401 | } 402 | } 403 | }, 404 | "dependencies": { 405 | "@fontsource/fira-mono": { 406 | "version": "4.5.0", 407 | "resolved": "https://registry.npmjs.org/@fontsource/fira-mono/-/fira-mono-4.5.0.tgz", 408 | "integrity": "sha512-KE+d3wmgq/YKM0BqgUF7p2yeBNi805Nfof1lC1wJ7E9i2EWoC363sGdKG+MQBVm+ei3GYZu+Bo8Xha1w1pkB7g==" 409 | }, 410 | "@iarna/toml": { 411 | "version": "2.2.5", 412 | "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", 413 | "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", 414 | "dev": true 415 | }, 416 | "@lukeed/csprng": { 417 | "version": "1.0.0", 418 | "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.0.0.tgz", 419 | "integrity": "sha512-ruuGHsnabmObBdeMg3vKdGRmh06Oog3eFpf/Tk6X0kDSJDpJTDCj2dqdp1+0VjzIUgHlFF9GBm7uFqfYhhdX9g==" 420 | }, 421 | "@lukeed/uuid": { 422 | "version": "2.0.0", 423 | "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.0.tgz", 424 | "integrity": "sha512-dUz8OmYvlY5A9wXaroHIMSPASpSYRLCqbPvxGSyHguhtTQIy24lC+EGxQlwv71AhRCO55WOtgwhzQLpw27JaJQ==", 425 | "requires": { 426 | "@lukeed/csprng": "^1.0.0" 427 | } 428 | }, 429 | "@rollup/pluginutils": { 430 | "version": "4.1.1", 431 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", 432 | "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", 433 | "dev": true, 434 | "requires": { 435 | "estree-walker": "^2.0.1", 436 | "picomatch": "^2.2.2" 437 | } 438 | }, 439 | "@sveltejs/adapter-netlify": { 440 | "version": "1.0.0-next.27", 441 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.27.tgz", 442 | "integrity": "sha512-t3kU2tJdCWmHwTBf+BRzzvYaM8ApxL+DEKtU1dUMI3bA8AgkpwkSHYiqZ75U2C+whi4mde+z15PeUFaUWzlKXA==", 443 | "dev": true, 444 | "requires": { 445 | "@iarna/toml": "^2.2.5", 446 | "esbuild": "^0.12.5" 447 | } 448 | }, 449 | "@sveltejs/kit": { 450 | "version": "1.0.0-next.147", 451 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.147.tgz", 452 | "integrity": "sha512-rAABsKlC1K/B4VfqT2SaVO29t+OV8deseSJ9l+hV7j9zkswTwiJ7h37tZ5SfnvMgCHemcNjXg8Gzg+0U1MCfEA==", 453 | "dev": true, 454 | "requires": { 455 | "@sveltejs/vite-plugin-svelte": "^1.0.0-next.16", 456 | "cheap-watch": "^1.0.3", 457 | "sade": "^1.7.4", 458 | "vite": "^2.4.3" 459 | } 460 | }, 461 | "@sveltejs/vite-plugin-svelte": { 462 | "version": "1.0.0-next.17", 463 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.17.tgz", 464 | "integrity": "sha512-Xh/YYqBMDJnDheutnGHk/I5TO6w9gZ2GMgvG+qQm/gpIRkaTLts6Mw5xDe6cac/nH/aVPPVPibhq2pf26d44fA==", 465 | "dev": true, 466 | "requires": { 467 | "@rollup/pluginutils": "^4.1.1", 468 | "debug": "^4.3.2", 469 | "kleur": "^4.1.4", 470 | "magic-string": "^0.25.7", 471 | "require-relative": "^0.8.7", 472 | "svelte-hmr": "^0.14.7" 473 | } 474 | }, 475 | "cheap-watch": { 476 | "version": "1.0.3", 477 | "resolved": "https://registry.npmjs.org/cheap-watch/-/cheap-watch-1.0.3.tgz", 478 | "integrity": "sha512-xC5CruMhLzjPwJ5ecUxGu1uGmwJQykUhqd2QrCrYbwvsFYdRyviu6jG9+pccwDXJR/OpmOTOJ9yLFunVgQu9wg==", 479 | "dev": true 480 | }, 481 | "colorette": { 482 | "version": "1.3.0", 483 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", 484 | "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", 485 | "dev": true 486 | }, 487 | "cookie": { 488 | "version": "0.4.1", 489 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", 490 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" 491 | }, 492 | "debug": { 493 | "version": "4.3.2", 494 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 495 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 496 | "dev": true, 497 | "requires": { 498 | "ms": "2.1.2" 499 | } 500 | }, 501 | "esbuild": { 502 | "version": "0.12.20", 503 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.20.tgz", 504 | "integrity": "sha512-u7+0qTo9Z64MD9PhooEngCmzyEYJ6ovFhPp8PLNh3UasR5Ihjv6HWVXqm8uHmasdQlpsAf0IsY4U0YVUfCpt4Q==", 505 | "dev": true 506 | }, 507 | "estree-walker": { 508 | "version": "2.0.2", 509 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 510 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 511 | "dev": true 512 | }, 513 | "fsevents": { 514 | "version": "2.3.2", 515 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 516 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 517 | "dev": true, 518 | "optional": true 519 | }, 520 | "function-bind": { 521 | "version": "1.1.1", 522 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 523 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 524 | "dev": true 525 | }, 526 | "has": { 527 | "version": "1.0.3", 528 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 529 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 530 | "dev": true, 531 | "requires": { 532 | "function-bind": "^1.1.1" 533 | } 534 | }, 535 | "is-core-module": { 536 | "version": "2.5.0", 537 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", 538 | "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", 539 | "dev": true, 540 | "requires": { 541 | "has": "^1.0.3" 542 | } 543 | }, 544 | "kleur": { 545 | "version": "4.1.4", 546 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", 547 | "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", 548 | "dev": true 549 | }, 550 | "magic-string": { 551 | "version": "0.25.7", 552 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", 553 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", 554 | "dev": true, 555 | "requires": { 556 | "sourcemap-codec": "^1.4.4" 557 | } 558 | }, 559 | "mri": { 560 | "version": "1.1.6", 561 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", 562 | "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", 563 | "dev": true 564 | }, 565 | "ms": { 566 | "version": "2.1.2", 567 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 568 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 569 | "dev": true 570 | }, 571 | "nanoid": { 572 | "version": "3.1.25", 573 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", 574 | "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", 575 | "dev": true 576 | }, 577 | "path-parse": { 578 | "version": "1.0.7", 579 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 580 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 581 | "dev": true 582 | }, 583 | "picomatch": { 584 | "version": "2.3.0", 585 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 586 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", 587 | "dev": true 588 | }, 589 | "postcss": { 590 | "version": "8.3.6", 591 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", 592 | "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", 593 | "dev": true, 594 | "requires": { 595 | "colorette": "^1.2.2", 596 | "nanoid": "^3.1.23", 597 | "source-map-js": "^0.6.2" 598 | } 599 | }, 600 | "require-relative": { 601 | "version": "0.8.7", 602 | "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", 603 | "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", 604 | "dev": true 605 | }, 606 | "resolve": { 607 | "version": "1.20.0", 608 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 609 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 610 | "dev": true, 611 | "requires": { 612 | "is-core-module": "^2.2.0", 613 | "path-parse": "^1.0.6" 614 | } 615 | }, 616 | "rollup": { 617 | "version": "2.56.2", 618 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz", 619 | "integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==", 620 | "dev": true, 621 | "requires": { 622 | "fsevents": "~2.3.2" 623 | } 624 | }, 625 | "sade": { 626 | "version": "1.7.4", 627 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", 628 | "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", 629 | "dev": true, 630 | "requires": { 631 | "mri": "^1.1.0" 632 | } 633 | }, 634 | "source-map-js": { 635 | "version": "0.6.2", 636 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", 637 | "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", 638 | "dev": true 639 | }, 640 | "sourcemap-codec": { 641 | "version": "1.4.8", 642 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 643 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 644 | "dev": true 645 | }, 646 | "svelte": { 647 | "version": "3.42.1", 648 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.1.tgz", 649 | "integrity": "sha512-XtExLd2JAU3T7M2g/DkO3UNj/3n1WdTXrfL63OZ5nZq7nAqd9wQw+lR4Pv/wkVbrWbAIPfLDX47UjFdmnY+YtQ==", 650 | "dev": true 651 | }, 652 | "svelte-hmr": { 653 | "version": "0.14.7", 654 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.14.7.tgz", 655 | "integrity": "sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==", 656 | "dev": true, 657 | "requires": {} 658 | }, 659 | "vite": { 660 | "version": "2.4.4", 661 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.4.4.tgz", 662 | "integrity": "sha512-m1wK6pFJKmaYA6AeZIUXyiAgUAAJzVXhIMYCdZUpCaFMGps0v0IlNJtbmPvkUhVEyautalajmnW5X6NboUPsnw==", 663 | "dev": true, 664 | "requires": { 665 | "esbuild": "^0.12.8", 666 | "fsevents": "~2.3.2", 667 | "postcss": "^8.3.6", 668 | "resolve": "^1.20.0", 669 | "rollup": "^2.38.5" 670 | } 671 | } 672 | } 673 | } 674 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "~TODO~", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build", 7 | "preview": "svelte-kit preview" 8 | }, 9 | "devDependencies": { 10 | "@sveltejs/adapter-netlify": "^1.0.0-next.27", 11 | "@sveltejs/kit": "next", 12 | "svelte": "^3.34.0" 13 | }, 14 | "type": "module", 15 | "dependencies": { 16 | "@fontsource/fira-mono": "^4.2.2", 17 | "@lukeed/uuid": "^2.0.0", 18 | "cookie": "^0.4.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | *, 2 | :after, 3 | :before { 4 | box-sizing: border-box; 5 | margin: 0; 6 | } 7 | body, 8 | html { 9 | font-family: Nanum Gothic, Montserrat, -apple-system, BlinkMacSystemFont, 10 | Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; 11 | font-size: 16px; 12 | word-spacing: 1px; 13 | -ms-text-size-adjust: 100%; 14 | -webkit-text-size-adjust: 100%; 15 | -moz-osx-font-smoothing: grayscale; 16 | -webkit-font-smoothing: antialiased; 17 | box-sizing: border-box; 18 | } 19 | body { 20 | border: 10px solid #ccc; 21 | min-height: 100vh; 22 | line-height: 1.4; 23 | } 24 | h1, 25 | h2, 26 | h3 { 27 | font-family: Domine, "PT Serif", -apple-system, BlinkMacSystemFont, Segoe UI, 28 | Roboto, Helvetica Neue, Arial, sans-serif; 29 | font-weight: 400; 30 | } 31 | h1 { 32 | font-size: 2.5rem; 33 | } 34 | p { 35 | margin: 20px 0; 36 | } 37 | a, 38 | a:active, 39 | a:visited { 40 | color: #d96528; 41 | text-decoration: none; 42 | transition: all 0.3s ease; 43 | } 44 | button { 45 | border: 1px solid #ccc; 46 | background: #fff; 47 | padding: 10px 14px; 48 | cursor: pointer; 49 | color: #000; 50 | font-weight: 700; 51 | font-family: Nanum Gothic, Montserrat, -apple-system, BlinkMacSystemFont, 52 | Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; 53 | transition: all 0.3s ease; 54 | } 55 | button:hover { 56 | background: #000; 57 | border: 1px solid #000; 58 | color: #fff; 59 | } 60 | hr { 61 | border-top: 1px solid #eee; 62 | margin: 30px 0; 63 | } 64 | input { 65 | font-family: Nanum Gothic, Montserrat, -apple-system, BlinkMacSystemFont, 66 | Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; 67 | font-size: 16px; 68 | padding: 5px 10px; 69 | } 70 | .app-header { 71 | flex-direction: column; 72 | padding: 40px 40px 0; 73 | } 74 | .app-header, 75 | .main-nav { 76 | display: flex; 77 | justify-content: center; 78 | align-items: center; 79 | } 80 | .main-nav { 81 | width: 80vw; 82 | margin-top: 30px; 83 | border-top: 1px solid #ccc; 84 | border-bottom: 1px solid #ccc; 85 | padding: 8px 0; 86 | } 87 | .main-nav ul { 88 | padding-left: 0; 89 | } 90 | .main-nav-item { 91 | position: relative; 92 | display: inline; 93 | padding: 0 3px; 94 | font-size: 0.6rem; 95 | letter-spacing: 0.1em; 96 | text-transform: uppercase; 97 | } 98 | @media screen and (min-width: 414px) { 99 | .main-nav-item { 100 | padding: 0 8px; 101 | border-left: 1px solid #ddd; 102 | border-right: 1px solid #ddd; 103 | font-size: 0.7rem; 104 | } 105 | } 106 | @media screen and (min-width: 640px) { 107 | .main-nav-item { 108 | padding: 0 10px; 109 | font-size: 0.8rem; 110 | } 111 | } 112 | .main-nav-item a { 113 | color: #000; 114 | } 115 | .main-nav-item a:hover { 116 | color: #d96528; 117 | } 118 | .cart-size { 119 | position: absolute; 120 | top: -18px; 121 | right: -20px; 122 | width: 25px; 123 | height: 25px; 124 | padding: 6px 10px; 125 | border-radius: 1000px; 126 | background: #000; 127 | text-align: center; 128 | color: #fff; 129 | font-size: 10px; 130 | font-weight: 700; 131 | } 132 | @media screen and (min-width: 768px) { 133 | .cart-size { 134 | right: -18px; 135 | } 136 | } 137 | .testimonial { 138 | width: 100%; 139 | height: 280px; 140 | background: url(https://res.cloudinary.com/kennyy/image/upload/v1625749897/testimonial-bg_ssrkzl.jpg) 141 | 50% no-repeat; 142 | background-size: cover; 143 | display: flex; 144 | justify-content: center; 145 | align-items: center; 146 | flex-direction: column; 147 | color: #fff; 148 | } 149 | .testimonial h2 { 150 | padding: 0 30px; 151 | text-align: center; 152 | } 153 | .project-credit { 154 | width: 100%; 155 | padding: 10px 30px; 156 | background: #000; 157 | color: #fff; 158 | text-align: center; 159 | } 160 | .project-credit a, 161 | .project-credit a:active, 162 | .project-credit a:visited { 163 | color: #2af; 164 | font-weight: 700; 165 | } 166 | .app-footer-links { 167 | width: 80%; 168 | padding: 40px 0; 169 | margin-left: 10%; 170 | display: grid; 171 | grid-template-columns: 1fr 1fr; 172 | grid-template-rows: 1fr 1fr; 173 | grid-row-gap: 30px; 174 | } 175 | @media screen and (min-width: 1024px) { 176 | .app-footer-links { 177 | grid-template-columns: 1fr 1fr 2fr; 178 | grid-template-rows: 1fr; 179 | grid-row-gap: 0; 180 | } 181 | } 182 | .app-footer-links ul { 183 | list-style: none; 184 | padding-left: 0; 185 | } 186 | .newsletter { 187 | width: 100%; 188 | grid-column: 1 / span 2; 189 | } 190 | @media screen and (min-width: 1024px) { 191 | .newsletter { 192 | grid-column: 3; 193 | } 194 | } 195 | .newsletter-title { 196 | margin-bottom: 1rem; 197 | } 198 | .newsletter-input { 199 | width: 100%; 200 | padding: 10px; 201 | } 202 | .cart-page { 203 | width: 80vw; 204 | margin: 0 auto; 205 | } 206 | .cart-page-button.is-dark { 207 | background: #222; 208 | color: #f8f8f8; 209 | padding: 10px 14px; 210 | display: inline-block; 211 | } 212 | .cart-page-content { 213 | margin: 2rem 0 3rem; 214 | text-align: center; 215 | } 216 | .cart-page-message { 217 | margin-bottom: 1.5rem; 218 | } 219 | .cart-table { 220 | width: 100%; 221 | margin-top: 20px; 222 | margin-bottom: 30px; 223 | } 224 | .cart-table-cell { 225 | padding: 8px 0; 226 | border-bottom: 1px solid #ccc; 227 | } 228 | .cart-table-heading { 229 | padding: 10px 0; 230 | border-bottom: 1px solid #ccc; 231 | } 232 | .cart-table-row { 233 | text-align: center; 234 | } 235 | .cart-total { 236 | display: grid; 237 | grid-template-columns: repeat(5, 1fr); 238 | } 239 | .cart-total-content { 240 | grid-column: 1 / span 5; 241 | display: grid; 242 | grid-template-columns: repeat(2, 1fr); 243 | } 244 | @media screen and (min-width: 1024px) { 245 | .cart-total-content { 246 | grid-column: 4 / span 2; 247 | } 248 | } 249 | .cart-total-column p { 250 | padding: 10px; 251 | margin: 0; 252 | text-align: right; 253 | } 254 | .cart-total-column p:last-child { 255 | font-weight: 700; 256 | background: #f2eee2; 257 | } 258 | .product-page { 259 | margin: 60px 0; 260 | } 261 | .product-page-content { 262 | width: 80%; 263 | margin: 30px auto 0; 264 | } 265 | @media screen and (min-width: 1024px) { 266 | .product-page-content { 267 | display: grid; 268 | justify-content: space-between; 269 | justify-items: center; 270 | align-items: center; 271 | grid-template-columns: 1fr 1fr; 272 | grid-column-gap: 30px; 273 | } 274 | } 275 | .product-page-image { 276 | width: 100%; 277 | margin-bottom: 30px; 278 | } 279 | @media screen and (min-width: 1024px) { 280 | .product-page-image { 281 | width: 100%; 282 | margin-bottom: 0; 283 | } 284 | } 285 | .product-page-price { 286 | color: #d96528; 287 | font-size: 1.2rem; 288 | margin: 5px 0; 289 | font-weight: 400; 290 | font-family: Domine, "PT Serif", -apple-system, BlinkMacSystemFont, Segoe UI, 291 | Roboto, Helvetica Neue, Arial, sans-serif; 292 | } 293 | .product-page-price-list, 294 | .product-page-price.is-solo { 295 | margin-bottom: 30px; 296 | } 297 | .product-page-quantity-input { 298 | width: 70px; 299 | } 300 | .product-page-quantity-row { 301 | display: flex; 302 | } 303 | .home-page { 304 | margin: 30px 0 45px; 305 | } 306 | .product-grid { 307 | max-width: 60vw; 308 | margin: 0 auto; 309 | display: grid; 310 | grid-template-columns: 1fr; 311 | grid-template-rows: 1fr; 312 | grid-column-gap: 40px; 313 | grid-row-gap: 0; 314 | } 315 | @media screen and (min-width: 640px) { 316 | .product-grid { 317 | grid-template-columns: repeat(2, 1fr); 318 | } 319 | } 320 | @media screen and (min-width: 1024px) { 321 | .product-grid { 322 | grid-template-columns: repeat(3, 1fr); 323 | } 324 | } 325 | @media screen and (min-width: 1280px) { 326 | .product-grid { 327 | grid-template-columns: repeat(4, 1fr); 328 | } 329 | } 330 | .product-card { 331 | max-height: 500px; 332 | display: flex; 333 | justify-content: space-between; 334 | align-items: center; 335 | flex-direction: column; 336 | margin: 20px 0; 337 | } 338 | .product-card-description { 339 | margin-top: 0; 340 | margin-bottom: 1rem; 341 | overflow: hidden; 342 | width: 100%; 343 | display: -webkit-box; 344 | -webkit-box-orient: vertical; 345 | -webkit-line-clamp: 2; 346 | } 347 | .product-card-frame { 348 | height: 120px; 349 | margin-bottom: 0.5rem; 350 | display: flex; 351 | align-content: center; 352 | align-items: center; 353 | border-radius: 10px; 354 | overflow: hidden; 355 | } 356 | .product-card-frame img { 357 | width: 100%; 358 | border-radius: 10px; 359 | -o-object-fit: cover; 360 | object-fit: cover; 361 | height: 100%; 362 | } 363 | .product-card-text { 364 | margin: 0.5rem 0; 365 | } 366 | .product-card-title { 367 | margin: 0.5rem 0; 368 | font-weight: 700; 369 | } 370 | @media (min-width: 720px) { 371 | h1 { 372 | font-size: 2.4rem; 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %svelte.head% 9 | 10 | 11 |
%svelte.body%
12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/CartTable.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | {#each cartItems as { node: item }} 44 | 45 | 50 | 53 | 54 | 57 | 60 | 61 | {/each} 62 | 63 |
ItemPriceQuantityTotalActions
46 | 47 | {item.merchandise.product.title} ({item.merchandise.title}) 48 | 49 | 51 | {formatCurrency(item.merchandise.priceV2.amount, item.merchandise.priceV2.currencyCode)} 52 | {item.quantity} 55 | {itemTotal(item.merchandise.priceV2.amount, item.quantity)} 56 | 58 | 59 |
64 |
65 | -------------------------------------------------------------------------------- /src/components/CartTotal.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 |
16 |
17 |

18 | Subtotal: 19 |

20 |

Shipping:

21 |

Tax:

22 |

Total:

23 |
24 |
25 |

26 | {currency} {subtotal} 27 |

28 |

Free Shipping

29 |

{currency} {calculateTax(tax)}

30 |

{currency} {total}

31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /src/components/Footer.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 40 | -------------------------------------------------------------------------------- /src/components/Header.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
14 |
15 |

Shoperoni

16 | 37 |
38 |
39 | -------------------------------------------------------------------------------- /src/components/ProductCard.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 | 9 | {product.handle} 10 | 11 |
12 |
13 |

{product.title}

14 |

{product.description.substring(0, 60) + '...'}

15 |
16 | 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/components/ProductList.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | {#each products as product} 9 | 10 | {/each} 11 |
12 | -------------------------------------------------------------------------------- /src/components/utils/currency.js: -------------------------------------------------------------------------------- 1 | export const formatCurrency = (amount, currency) => { 2 | const amountFloat = Number(amount).toFixed(2); 3 | 4 | return '$' + amountFloat + ` ${currency}`; 5 | }; 6 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/routes/__layout.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | 9 |
10 | 11 |
12 | 13 |