├── .babelrc
├── .gitignore
├── .theme-check.yml
├── .vscode
└── extensions.json
├── build
└── Dawn-1.0.0.zip
├── package.json
├── postcss.config.js
├── readme.md
├── rollup.config.js
├── src
├── LICENSE.md
├── README.md
├── assets
│ ├── base.css
│ ├── cart-notification.js
│ ├── cart.js
│ ├── collage.css
│ ├── collection-filters-form.js
│ ├── component-accordion.css
│ ├── component-article-card.css
│ ├── component-badge.css
│ ├── component-card.css
│ ├── component-cart-items.css
│ ├── component-cart-notification.css
│ ├── component-cart.css
│ ├── component-collection-hero.css
│ ├── component-deferred-media.css
│ ├── component-discounts.css
│ ├── component-image-with-text.css
│ ├── component-list-menu.css
│ ├── component-list-payment.css
│ ├── component-list-social.css
│ ├── component-loading-overlay.css
│ ├── component-menu-drawer.css
│ ├── component-model-viewer-ui.css
│ ├── component-newsletter.css
│ ├── component-pagination.css
│ ├── component-pickup-availability.css
│ ├── component-price.css
│ ├── component-product-model.css
│ ├── component-rte.css
│ ├── component-search.css
│ ├── component-slider.css
│ ├── component-totals.css
│ ├── customer.css
│ ├── customer.js
│ ├── details-disclosure.js
│ ├── details-modal.js
│ ├── disclosure.css
│ ├── global.js
│ ├── newsletter-section.css
│ ├── password-modal.js
│ ├── pickup-availability.js
│ ├── product-form.js
│ ├── product-model.js
│ ├── section-blog-post.css
│ ├── section-collection-list.css
│ ├── section-contact-form.css
│ ├── section-featured-blog.css
│ ├── section-footer.css
│ ├── section-image-banner.css
│ ├── section-main-blog.css
│ ├── section-main-page.css
│ ├── section-main-product.css
│ ├── section-multicolumn.css
│ ├── section-password.css
│ ├── section-product-recommendations.css
│ ├── section-rich-text.css
│ ├── share.js
│ ├── slider.js
│ ├── template-collection.css
│ ├── template-giftcard.css
│ └── variants.js
├── config
│ ├── settings_data.json
│ └── settings_schema.json
├── layout
│ ├── password.liquid
│ └── theme.liquid
├── locales
│ ├── bg-BG.json
│ ├── cs.json
│ ├── cs.schema.json
│ ├── da.json
│ ├── da.schema.json
│ ├── de.json
│ ├── de.schema.json
│ ├── el.json
│ ├── en.default.json
│ ├── en.default.schema.json
│ ├── es.json
│ ├── es.schema.json
│ ├── fi.json
│ ├── fi.schema.json
│ ├── fr.json
│ ├── fr.schema.json
│ ├── hr-HR.json
│ ├── hu.json
│ ├── id.json
│ ├── it.json
│ ├── it.schema.json
│ ├── ja.json
│ ├── ja.schema.json
│ ├── ko.json
│ ├── ko.schema.json
│ ├── lt-LT.json
│ ├── nb.json
│ ├── nb.schema.json
│ ├── nl.json
│ ├── nl.schema.json
│ ├── pl.json
│ ├── pl.schema.json
│ ├── pt-BR.json
│ ├── pt-BR.schema.json
│ ├── pt-PT.json
│ ├── pt-PT.schema.json
│ ├── ro-RO.json
│ ├── ru.json
│ ├── sk-SK.json
│ ├── sl-SI.json
│ ├── sv.json
│ ├── sv.schema.json
│ ├── th.json
│ ├── th.schema.json
│ ├── tr.json
│ ├── tr.schema.json
│ ├── vi.json
│ ├── vi.schema.json
│ ├── zh-CN.json
│ ├── zh-CN.schema.json
│ ├── zh-TW.json
│ └── zh-TW.schema.json
├── scripts
│ ├── sections
│ │ ├── header.js
│ │ └── image-banner.js
│ ├── theme.js
│ └── utils
│ │ └── operations.js
├── sections
│ ├── announcement-bar.liquid
│ ├── apps.liquid
│ ├── cart-icon-bubble.liquid
│ ├── cart-live-region-text.liquid
│ ├── cart-notification-button.liquid
│ ├── cart-notification-product.liquid
│ ├── collage.liquid
│ ├── collection-list.liquid
│ ├── contact-form.liquid
│ ├── custom-liquid.liquid
│ ├── featured-blog.liquid
│ ├── featured-collection.liquid
│ ├── footer.liquid
│ ├── header.liquid
│ ├── image-banner.liquid
│ ├── image-with-text.liquid
│ ├── main-404.liquid
│ ├── main-article.liquid
│ ├── main-blog.liquid
│ ├── main-cart-footer.liquid
│ ├── main-cart-items.liquid
│ ├── main-collection-banner.liquid
│ ├── main-collection-product-grid.liquid
│ ├── main-list-collections.liquid
│ ├── main-page.liquid
│ ├── main-password-footer.liquid
│ ├── main-password-header.liquid
│ ├── main-product.liquid
│ ├── main-search.liquid
│ ├── multicolumn.liquid
│ ├── newsletter.liquid
│ ├── page.liquid
│ ├── pickup-availability.liquid
│ ├── product-recommendations.liquid
│ └── rich-text.liquid
├── snippets
│ ├── article-card.liquid
│ ├── cart-notification.liquid
│ ├── icon-3d-model.liquid
│ ├── icon-accordion.liquid
│ ├── icon-account.liquid
│ ├── icon-arrow.liquid
│ ├── icon-caret.liquid
│ ├── icon-cart-empty.liquid
│ ├── icon-cart.liquid
│ ├── icon-checkmark.liquid
│ ├── icon-clipboard.liquid
│ ├── icon-close-small.liquid
│ ├── icon-close.liquid
│ ├── icon-discount.liquid
│ ├── icon-error.liquid
│ ├── icon-facebook.liquid
│ ├── icon-filter.liquid
│ ├── icon-hamburger.liquid
│ ├── icon-instagram.liquid
│ ├── icon-minus.liquid
│ ├── icon-padlock.liquid
│ ├── icon-pinterest.liquid
│ ├── icon-play.liquid
│ ├── icon-plus.liquid
│ ├── icon-remove.liquid
│ ├── icon-share.liquid
│ ├── icon-snapchat.liquid
│ ├── icon-success.liquid
│ ├── icon-tick.liquid
│ ├── icon-tiktok.liquid
│ ├── icon-tumblr.liquid
│ ├── icon-twitter.liquid
│ ├── icon-unavailable.liquid
│ ├── icon-vimeo.liquid
│ ├── icon-youtube.liquid
│ ├── icon-zoom.liquid
│ ├── meta-tags.liquid
│ ├── pagination.liquid
│ ├── price.liquid
│ ├── product-card-placeholder.liquid
│ ├── product-card.liquid
│ ├── product-thumbnail.liquid
│ └── social-sharing.liquid
├── styles
│ ├── sections
│ │ ├── header.css
│ │ └── image-banner.css
│ ├── theme.css
│ └── utils
│ │ ├── autocomplete.css
│ │ └── base.css
├── templates
│ ├── 404.json
│ ├── article.json
│ ├── blog.json
│ ├── cart.json
│ ├── collection.json
│ ├── customers
│ │ ├── account.liquid
│ │ ├── activate_account.liquid
│ │ ├── addresses.liquid
│ │ ├── login.liquid
│ │ ├── order.liquid
│ │ ├── register.liquid
│ │ └── reset_password.liquid
│ ├── gift_card.liquid
│ ├── index.json
│ ├── list-collections.json
│ ├── page.contact.json
│ ├── page.json
│ ├── password.json
│ ├── product.json
│ └── search.json
└── translation.yml
└── tailwind.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false
7 | }
8 | ]
9 | ]
10 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /node_modules
4 | dist/
5 | yarn.lock
--------------------------------------------------------------------------------
/.theme-check.yml:
--------------------------------------------------------------------------------
1 | # If your theme is not using the supported directory structure, provide the root path
2 | # where to find the `templates/`, `sections/`, `snippets/` directories as they would
3 | # be uploaded to Shopify.
4 | root: src
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "shopify.theme-check-vscode"
4 | ]
5 | }
--------------------------------------------------------------------------------
/build/Dawn-1.0.0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stylehatch/hatch/f3f366a5e2d075538804e14d26a5fffb7d792bd1/build/Dawn-1.0.0.zip
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hatch",
3 | "description": "Minimal Shopify OS2 theme build tools using Shopify CLI, Rollupjs and Tailwinds/Postcss",
4 | "version": "1.0.0",
5 | "main": "index.js",
6 | "author": {
7 | "name": "Jonathan Moore",
8 | "url": "https://github.com/jonathanmoore/"
9 | },
10 | "license": "MIT",
11 | "browserslist": [
12 | "last 2 Chrome versions"
13 | ],
14 | "scripts": {
15 | "clean": "rimraf dist && mkdir dist",
16 | "dev": "npm run clean && npm run build && npm-run-all --parallel dev:*",
17 | "dev:rollup": "NODE_ENV=development rollup -c --watch",
18 | "dev:postcss": "NODE_ENV=development TAILWIND_MODE=watch postcss src/styles/{theme.css,sections/*.css} --dir dist/assets --watch",
19 | "dev:shopify": "cd ./dist && shopify theme serve",
20 | "build": "npm-run-all --sequential build:*",
21 | "build:rollup": "NODE_ENV=production rollup -c",
22 | "build:postcss": "NODE_ENV=production postcss src/styles/{theme.css,sections/*.css} --dir dist/assets",
23 | "deploy": "npm-run-all --sequential deploy:*",
24 | "deploy:build": "npm-run-all --sequential build:*",
25 | "deploy:shopify": "cd ./dist && shopify theme push --development",
26 | "package": "npm-run-all --sequential package:*",
27 | "package:build": "npm-run-all --sequential build:*",
28 | "package:shopify": "cd ./dist && shopify theme package",
29 | "package:copy": "mkdir -p build && cpy 'dist/*.zip' build"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.14.6",
33 | "@babel/preset-env": "^7.14.7",
34 | "@jonathanmoore/rollup-plugin-copy": "^3.5.1",
35 | "@rollup/plugin-babel": "^5.3.0",
36 | "@rollup/plugin-commonjs": "^19.0.0",
37 | "@rollup/plugin-eslint": "^8.0.1",
38 | "@rollup/plugin-node-resolve": "^13.0.0",
39 | "@rollup/plugin-replace": "^2.4.2",
40 | "@shopify/stylelint-plugin": "^10.1.2",
41 | "chokidar": "^3.5.2",
42 | "colorette": "^1.2.2",
43 | "cpy-cli": "^3.1.1",
44 | "eslint": "^7.29.0",
45 | "fs-extra": "^10.0.0",
46 | "globby": "^11.0.4",
47 | "is-plain-object": "^5.0.0",
48 | "npm-run-all": "^4.1.5",
49 | "postcss": "^8.3.5",
50 | "postcss-cli": "^8.3.1",
51 | "postcss-import": "^14.0.2",
52 | "postcss-nested": "^5.0.5",
53 | "prettier": "^2.3.2",
54 | "rollup": "^2.52.4",
55 | "rollup-plugin-multi-input": "^1.3.1",
56 | "stylelint": "^13.13.1",
57 | "tailwindcss": "^2.2.4"
58 | },
59 | "dependencies": {
60 | "canvas-confetti": "^1.4.0"
61 | },
62 | "stylelint": {
63 | "extends": [
64 | "@shopify/stylelint-plugin/prettier"
65 | ]
66 | },
67 | "prettier": {
68 | "singleQuote": true,
69 | "trailingComma": "es5",
70 | "bracketSpacing": false
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('postcss-import'),
4 | require('tailwindcss'),
5 | require('postcss-nested'),
6 | // Example of how to exclude plugins by env
7 | // process.env.NODE_ENV === 'production' ? require('autoprefixer') : null,
8 | ],
9 | };
10 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Hatch
2 |
3 | Hatch is a minimal tool to help you build Shopify Online Store 2.0 themes using the (Shopify CLI)[https://github.com/shopify/shopify-cli]. The focus of the build tools is to use the most lightweight, minimal tools for processing JavaScript and CSS file for the use in themes.
4 |
5 | The theme principals and concepts are following Shopify's Dawn theme with individual CSS and JavaScript files associated with each section.
6 |
7 | *Hatch is currently a work in progress and more of a working concept that we are using for our new Online Store 2.0 themes.*
8 |
9 | ## Tools
10 |
11 | Hatch uses the `/src` directory for theme development introducing new `/styles` and `/scripts` directories for processing CSS (PostCSS) files and JavaScript. When running `yarn dev` a new `/dist` directory will be created where all files will be watched and copied into the directory, PostCSS will run to process and copy CSS files into `/dist/assets`, and Rollup.js will bundle and transpile Javascript files into `/dist/assets`.
12 |
13 | (PostCSS)[https://github.com/postcss/postcss] and (Tailwindcss)[https://github.com/tailwindlabs/tailwindcss] JIT compiler is used for creating lean CSS files based on classes used throughout the JavaScript and Liquid files. *Configurations in `postcss.config.js` and `taiwind.config.js`*
14 |
15 | (Rollup.js)[https://github.com/rollup/rollup] is used to copy files, transpile JavaScript and bundle modules. Hatch uses the same evergreen, modern browser approach as Dawn to focus on widely supported ES6 JavaScript rather than adding extra bloat to support older browsers. *Configuration in `rollup.config.js`*
16 |
17 | #### JavaScript files
18 |
19 | `/src/scripts/theme.js` is the primary JavaScript file intended to be used in Layouts/theme.liquid. Each of the sections that require a JavaScript file will be located in `/src/scripts/[section-name].js`.
20 |
21 | #### CSS files
22 |
23 | `/src/scripts/theme.css` is the primary CSS file intended to be used in Layouts/theme.liquid. Each of the sections that require a CSS file will be located in `/src/scripts/[section-name].css`.
24 |
25 | #### Caveats
26 |
27 | Currently adding a new .js or .css file for sections `src/{scripts,styles}/sections` you need to restart `yarn dev` to include the new files in the build tools.
28 |
29 | ## Usage
30 |
31 | #### Installation
32 |
33 | ```bash
34 | # yarn
35 | yarn install
36 | ```
37 |
38 | #### Development
39 |
40 | ```bash
41 | # yarn
42 | yarn dev
43 | ```
44 |
45 | 1. Cleans up and creates the `/dist` directory
46 | 2. Runs Rollup.js, watches for file changes, processes JavaScript files and copies everything into `/src`
47 | 3. Runs Postcss and Tailwindcss JIT to create just-in-time compiled CSS files in `/src/assets`
48 | 4. Runs Shopify CLI `shopify theme serve` in the `/dist` folder
49 |
50 | #### Build
51 |
52 | ```bash
53 | # yarn
54 | yarn build
55 | ```
56 |
57 | 1. Runs Rollup.js, processes JavaScript files and copies everything into `/src`
58 | 2. Runs Postcss and Tailwindcss to create lean CSS files in `/src/assets`
59 |
60 | #### Deploy
61 |
62 | ```bash
63 | # yarn
64 | yarn deploy
65 | ```
66 |
67 | 1. Builds the theme (see above)
68 | 2. Runs Shopify CLI `shopify theme push --development` to push to a development unpublished theme
69 |
70 | #### Package
71 |
72 | ```bash
73 | # yarn
74 | yarn package
75 | ```
76 |
77 | 1. Builds the theme (see above)
78 | 2. Runs Shopify CLI `shopify theme package` to create a versioned .zip file for the theme
79 | 3. Copies the versioned theme .zip file to `/build`
80 |
81 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import babel from '@rollup/plugin-babel';
3 | import resolve from '@rollup/plugin-node-resolve';
4 | import commonjs from '@rollup/plugin-commonjs';
5 | import copy from '@jonathanmoore/rollup-plugin-copy';
6 | import multiInput from 'rollup-plugin-multi-input';
7 |
8 | export default {
9 | // Import multiples
10 | input: ['src/scripts/theme.js', 'src/scripts/sections/*.js'],
11 | output: {
12 | format: 'esm',
13 | dir: 'dist',
14 | },
15 | plugins: [
16 | multiInput({
17 | relative: 'src/',
18 | transformOutputPath: (output, input) => `assets/${path.basename(output)}`,
19 | }),
20 | copy({
21 | watch: process.env.NODE_ENV === 'development' ? [
22 | 'src/assets/',
23 | 'src/config/',
24 | 'src/layout/',
25 | 'src/locales',
26 | 'src/sections/',
27 | 'src/snippets/',
28 | 'src/templates/',
29 | ] : null,
30 | targets: [
31 | {src: 'src/assets/**/*', dest: 'dist/assets'},
32 | {src: 'src/config/*.json', dest: 'dist/config'},
33 | {src: 'src/layout/*.liquid', dest: 'dist/layout'},
34 | {src: 'src/locales/*.json', dest: 'dist/locales'},
35 | {src: 'src/sections/*.liquid', dest: 'dist/sections'},
36 | {src: 'src/snippets/*.liquid', dest: 'dist/snippets'},
37 | {src: 'src/templates/**/*', dest: 'dist/templates'},
38 | ],
39 | verbose: true,
40 | copyOnce: true,
41 | }),
42 | resolve(),
43 | commonjs(),
44 | babel({
45 | exclude: 'node_modules/**',
46 | babelHelpers: 'bundled',
47 | }),
48 | ],
49 | };
50 |
--------------------------------------------------------------------------------
/src/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021-present Shopify Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, sell and/or create derivative works of the Software or any part thereof, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The rights granted above may only be exercised to develop themes that integrate or interoperate with Shopify software or services, and, if applicable, to distribute, offer for sale or otherwise make available any such themes via the Shopify Theme Store. All other uses of the Software are strictly prohibited.
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/src/assets/cart-notification.js:
--------------------------------------------------------------------------------
1 | class CartNotification extends HTMLElement {
2 | constructor() {
3 | super();
4 |
5 | this.notification = document.getElementById('cart-notification');
6 | this.header = document.querySelector('sticky-header');
7 | this.onBodyClick = this.handleBodyClick.bind(this);
8 |
9 | this.notification.addEventListener('keyup', (evt) => evt.code === 'Escape' && this.close());
10 | this.querySelectorAll('button[type="button"]').forEach((closeButton) =>
11 | closeButton.addEventListener('click', this.close.bind(this))
12 | );
13 | }
14 |
15 | open() {
16 | this.notification.classList.add('animate', 'active');
17 |
18 | this.notification.addEventListener('transitionend', () => {
19 | this.notification.focus();
20 | trapFocus(this.notification);
21 | }, { once: true });
22 |
23 | document.body.addEventListener('click', this.onBodyClick);
24 | }
25 |
26 | close() {
27 | this.notification.classList.remove('active');
28 |
29 | document.body.removeEventListener('click', this.onBodyClick);
30 |
31 | removeTrapFocus(this.activeElement);
32 | }
33 |
34 | renderContents(parsedState) {
35 | this.productId = parsedState.id;
36 | this.getSectionsToRender().forEach((section => {
37 | document.getElementById(section.id).innerHTML =
38 | this.getSectionInnerHTML(parsedState.sections[section.id], section.selector);
39 | }));
40 |
41 | this.header?.reveal();
42 | this.open();
43 | }
44 |
45 | getSectionsToRender() {
46 | return [
47 | {
48 | id: 'cart-notification-product',
49 | selector: `#cart-notification-product-${this.productId}`,
50 | },
51 | {
52 | id: 'cart-notification-button'
53 | },
54 | {
55 | id: 'cart-icon-bubble'
56 | }
57 | ];
58 | }
59 |
60 | getSectionInnerHTML(html, selector = '.shopify-section') {
61 | return new DOMParser()
62 | .parseFromString(html, 'text/html')
63 | .querySelector(selector).innerHTML;
64 | }
65 |
66 | handleBodyClick(evt) {
67 | const target = evt.target;
68 | if (target !== this.notification && !target.closest('cart-notification')) {
69 | const disclosure = target.closest('details-disclosure');
70 | this.activeElement = disclosure ? disclosure.querySelector('summary') : null;
71 | this.close();
72 | }
73 | }
74 |
75 | setActiveElement(element) {
76 | this.activeElement = element;
77 | }
78 | }
79 |
80 | customElements.define('cart-notification', CartNotification);
81 |
--------------------------------------------------------------------------------
/src/assets/cart.js:
--------------------------------------------------------------------------------
1 | class CartRemoveButton extends HTMLElement {
2 | constructor() {
3 | super();
4 | this.addEventListener('click', (event) => {
5 | event.preventDefault();
6 | this.closest('cart-items').updateQuantity(this.dataset.index, 0);
7 | });
8 | }
9 | }
10 |
11 | customElements.define('cart-remove-button', CartRemoveButton);
12 |
13 | class CartItems extends HTMLElement {
14 | constructor() {
15 | super();
16 |
17 | this.lineItemStatusElement = document.getElementById('shopping-cart-line-item-status');
18 |
19 | this.currentItemCount = Array.from(this.querySelectorAll('[name="updates[]"]'))
20 | .reduce((total, quantityInput) => total + parseInt(quantityInput.value), 0);
21 |
22 | this.debouncedOnChange = debounce((event) => {
23 | this.onChange(event);
24 | }, 300);
25 |
26 | this.addEventListener('change', this.debouncedOnChange.bind(this));
27 | }
28 |
29 | onChange(event) {
30 | this.updateQuantity(event.target.dataset.index, event.target.value, document.activeElement.getAttribute('name'));
31 | }
32 |
33 | getSectionsToRender() {
34 | return [
35 | {
36 | id: 'main-cart-items',
37 | section: document.getElementById('main-cart-items').dataset.id,
38 | selector: '.js-contents',
39 | },
40 | {
41 | id: 'cart-icon-bubble',
42 | section: 'cart-icon-bubble',
43 | selector: '.shopify-section'
44 | },
45 | {
46 | id: 'cart-live-region-text',
47 | section: 'cart-live-region-text',
48 | selector: '.shopify-section'
49 | },
50 | {
51 | id: 'main-cart-footer',
52 | section: document.getElementById('main-cart-footer').dataset.id,
53 | selector: '.js-contents',
54 | }
55 | ];
56 | }
57 |
58 | updateQuantity(line, quantity, name) {
59 | this.enableLoading(line);
60 |
61 | const body = JSON.stringify({
62 | line,
63 | quantity,
64 | sections: this.getSectionsToRender().map((section) => section.section),
65 | sections_url: window.location.pathname
66 | });
67 |
68 | fetch(`${routes.cart_change_url}`, {...fetchConfig(), ...{ body }})
69 | .then((response) => {
70 | return response.text();
71 | })
72 | .then((state) => {
73 | const parsedState = JSON.parse(state);
74 | this.classList.toggle('is-empty', parsedState.item_count === 0);
75 | document.getElementById('main-cart-footer')?.classList.toggle('is-empty', parsedState.item_count === 0);
76 |
77 | this.getSectionsToRender().forEach((section => {
78 | const elementToReplace =
79 | document.getElementById(section.id).querySelector(section.selector) || document.getElementById(section.id);
80 |
81 | elementToReplace.innerHTML =
82 | this.getSectionInnerHTML(parsedState.sections[section.section], section.selector);
83 | }));
84 |
85 | this.updateLiveRegions(line, parsedState.item_count);
86 | document.getElementById(`CartItem-${line}`)?.querySelector(`[name="${name}"]`)?.focus();
87 | this.disableLoading();
88 | }).catch(() => {
89 | this.querySelectorAll('.loading-overlay').forEach((overlay) => overlay.classList.add('hidden'));
90 | document.getElementById('cart-errors').textContent = window.cartStrings.error;
91 | this.disableLoading();
92 | });
93 | }
94 |
95 | updateLiveRegions(line, itemCount) {
96 | if (this.currentItemCount === itemCount) {
97 | document.getElementById(`Line-item-error-${line}`)
98 | .querySelector('.cart-item__error-text')
99 | .innerHTML = window.cartStrings.quantityError.replace(
100 | '[quantity]',
101 | document.getElementById(`Quantity-${line}`).value
102 | );
103 | }
104 |
105 | this.currentItemCount = itemCount;
106 | this.lineItemStatusElement.setAttribute('aria-hidden', true);
107 |
108 | const cartStatus = document.getElementById('cart-live-region-text');
109 | cartStatus.setAttribute('aria-hidden', false);
110 |
111 | setTimeout(() => {
112 | cartStatus.setAttribute('aria-hidden', true);
113 | }, 1000);
114 | }
115 |
116 | getSectionInnerHTML(html, selector) {
117 | return new DOMParser()
118 | .parseFromString(html, 'text/html')
119 | .querySelector(selector).innerHTML;
120 | }
121 |
122 | enableLoading(line) {
123 | document.getElementById('main-cart-items').classList.add('cart__items--disabled');
124 | this.querySelectorAll('.loading-overlay')[line - 1].classList.remove('hidden');
125 | document.activeElement.blur();
126 | this.lineItemStatusElement.setAttribute('aria-hidden', false);
127 | }
128 |
129 | disableLoading() {
130 | document.getElementById('main-cart-items').classList.remove('cart__items--disabled');
131 | }
132 | }
133 |
134 | customElements.define('cart-items', CartItems);
135 |
--------------------------------------------------------------------------------
/src/assets/component-accordion.css:
--------------------------------------------------------------------------------
1 | .accordion summary {
2 | display: flex;
3 | position: relative;
4 | line-height: 1;
5 | padding: 1.5rem 0;
6 | }
7 |
8 | .accordion .summary__title {
9 | display: flex;
10 | flex: 1;
11 | }
12 |
13 | .accordion + .accordion {
14 | margin-top: 0;
15 | border-top: none;
16 | }
17 |
18 | .accordion {
19 | margin-top: 2.5rem;
20 | margin-bottom: 0;
21 | border-top: 0.1rem solid rgba(var(--color-foreground), 0.2);
22 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.2);
23 | }
24 |
25 | .accordion__title {
26 | display: inline-block;
27 | max-width: calc(100% - 6rem);
28 | min-height: 1.6rem;
29 | margin: 0;
30 | word-break: break-word;
31 | }
32 |
33 | .accordion .icon-accordion {
34 | align-self: center;
35 | min-width: 1.6rem;
36 | margin-right: 1rem;
37 | fill: rgb(var(--color-foreground));
38 | }
39 |
40 | .accordion details[open] > summary .icon-caret {
41 | transform: rotate(180deg);
42 | }
43 |
44 | .accordion__content {
45 | margin-bottom: 1.5rem;
46 | word-break: break-word;
47 | }
48 |
49 | .accordion__content img {
50 | max-width: 100%;
51 | }
52 |
--------------------------------------------------------------------------------
/src/assets/component-article-card.css:
--------------------------------------------------------------------------------
1 | .articles-wrapper.grid {
2 | margin: 0 0 5rem 0;
3 | }
4 |
5 | @media screen and (min-width: 750px) {
6 | .articles-wrapper.grid {
7 | margin-bottom: 7rem;
8 | }
9 | }
10 |
11 | .articles-wrapper .article {
12 | max-width: 100%;
13 | }
14 |
15 | @media screen and (max-width: 749px) {
16 | .articles-wrapper .article {
17 | width: 100%;
18 | }
19 | }
20 |
21 | .article {
22 | display: flex;
23 | align-items: center;
24 | }
25 |
26 | .article.grid__item {
27 | padding: 0;
28 | }
29 |
30 | .article-card {
31 | background-color: rgba(var(--color-foreground), 0.04);
32 | align-self: flex-start;
33 | flex: 0 1 100%;
34 | display: flex;
35 | align-items: flex-start;
36 | height: 100%;
37 | }
38 |
39 | .grid--peek .article-card {
40 | box-sizing: border-box;
41 | }
42 |
43 | .article-card__info {
44 | padding: 2.5rem 2.5rem 3rem;
45 | display: flex;
46 | flex-direction: column;
47 | flex-grow: 1;
48 | }
49 |
50 | @media screen and (min-width: 750px) {
51 | .article-card__info {
52 | padding: 4rem 5rem;
53 | }
54 | }
55 |
56 | .article-content {
57 | width: 100%;
58 | height: 100%;
59 | display: flex;
60 | flex-direction: column;
61 | text-decoration: none;
62 | color: inherit;
63 | }
64 |
65 | .article-content:hover .article-card__title {
66 | text-decoration: underline;
67 | text-underline-offset: 0.3rem;
68 | }
69 |
70 | .article-card__image {
71 | overflow: hidden;
72 | }
73 |
74 | .article-content img {
75 | transition: transform var(--duration-default) ease;
76 | }
77 |
78 | .article-content:hover img {
79 | transform: scale(1.07);
80 | }
81 |
82 | .article-card__image-wrapper > a {
83 | display: block;
84 | }
85 |
86 | .article-card__title {
87 | text-decoration: none;
88 | word-break: break-word;
89 | }
90 |
91 | .article-card__link.link {
92 | padding: 0;
93 | }
94 |
95 | .article-card__link {
96 | text-underline-offset: 0.3rem;
97 | }
98 |
99 | .article-content:hover .article-card__link {
100 | text-decoration-thickness: 0.2rem;
101 | }
102 |
103 | .article-card__header h2 {
104 | margin: 0;
105 | }
106 |
107 | .article-card__header h2:not(:first-child) {
108 | margin-top: 1rem;
109 | }
110 |
111 | .article-card__footer {
112 | letter-spacing: 0.1rem;
113 | font-size: 1.4rem;
114 | }
115 |
116 | .article-card__footer:not(:last-child) {
117 | margin-bottom: 1rem;
118 | }
119 |
120 | .article-card__footer:last-child {
121 | margin-top: auto;
122 | }
123 |
124 | .article-card__link:not(:only-child) {
125 | margin-right: 3rem;
126 | }
127 |
128 | @media screen and (min-width: 990px) {
129 | .article-card__link:not(:only-child) {
130 | margin-right: 4rem;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/assets/component-badge.css:
--------------------------------------------------------------------------------
1 | .badge {
2 | border: 1px solid transparent;
3 | border-radius: 4rem;
4 | display: inline-block;
5 | font-size: 1.2rem;
6 | letter-spacing: 0.1rem;
7 | line-height: 1;
8 | padding: 0.6rem 1.6rem;
9 | text-align: center;
10 | background-color: rgb(var(--color-badge-background));
11 | border-color: rgba(var(--color-badge-border), var(--alpha-badge-border));
12 | color: rgb(var(--color-foreground));
13 | word-break: break-word;
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/component-cart-items.css:
--------------------------------------------------------------------------------
1 | .cart-items td,
2 | .cart-items th {
3 | padding: 0;
4 | border: none;
5 | }
6 |
7 | .cart-items th {
8 | text-align: left;
9 | padding-bottom: 1.8rem;
10 | opacity: 0.85;
11 | font-weight: normal;
12 | }
13 |
14 | .cart-item__totals {
15 | position: relative;
16 | }
17 |
18 | .cart-items *.right {
19 | text-align: right;
20 | }
21 |
22 | .cart-item__image {
23 | max-width: 100%;
24 | }
25 |
26 | .cart-item__details {
27 | font-size: 1.6rem;
28 | line-height: 1.4;
29 | }
30 |
31 | .cart-item__details > * {
32 | margin: 0;
33 | max-width: 30rem;
34 | }
35 |
36 | .cart-item__details > * + * {
37 | margin-top: 0.8rem;
38 | }
39 |
40 | .cart-item__media {
41 | position: relative;
42 | }
43 |
44 | .cart-item__name {
45 | color: rgb(var(--color-foreground));
46 | text-decoration: none;
47 | display: block;
48 | }
49 |
50 | .cart-item__name:hover {
51 | text-decoration: underline;
52 | text-underline-offset: 0.3rem;
53 | text-decoration-thickness: 0.2rem;
54 | }
55 |
56 | .cart-item__price-wrapper {
57 | margin: 0;
58 | }
59 |
60 | .cart-item__price-wrapper > * {
61 | display: block;
62 | margin: 0;
63 | padding: 0;
64 | }
65 |
66 | .cart-item__discounted-prices dd {
67 | margin: 0;
68 | }
69 |
70 | .cart-item__old-price {
71 | opacity: 0.7;
72 | }
73 |
74 | .product-option {
75 | font-size: 1.6rem;
76 | line-height: 1.5;
77 | }
78 |
79 | .cart-item cart-remove-button {
80 | display: inline-block;
81 | margin: 2rem 0 0 auto;
82 | }
83 |
84 | @media screen and (min-width: 750px) and (max-width: 989px) {
85 | .cart-item cart-remove-button {
86 | width: 4.5rem;
87 | height: 4.5rem;
88 | }
89 | }
90 |
91 | cart-remove-button .button {
92 | min-width: 4.5rem;
93 | min-height: 4.5rem;
94 | padding: 0;
95 | margin: 0 0.1rem 0.1rem 0;
96 | }
97 |
98 | @media screen and (min-width: 750px) {
99 | cart-remove-button .button {
100 | min-width: 3.5rem;
101 | min-height: 3.5rem;
102 | }
103 | }
104 |
105 | cart-remove-button .icon-remove {
106 | height: 1.5rem;
107 | width: 1.5rem;
108 | }
109 |
110 | .cart-item .loading-overlay {
111 | top: auto;
112 | left: auto;
113 | right: 0;
114 | bottom: 0;
115 | padding: 0;
116 | }
117 |
118 | @media screen and (min-width: 750px) {
119 | .cart-item .loading-overlay {
120 | top: 0;
121 | padding-top: 5.5rem;
122 | bottom: auto;
123 | }
124 | }
125 |
126 | .loading-overlay:not(.hidden) ~ * {
127 | visibility: hidden;
128 | }
129 |
130 | .cart-item__error {
131 | font-size: 1.2rem;
132 | display: flex;
133 | }
134 |
135 | .cart-item__error-text {
136 | order: 1;
137 | }
138 |
139 | .cart-item__error-text + svg {
140 | width: 1.2rem;
141 | margin-right: 0.7rem;
142 | }
143 |
144 | .cart-item__error-text:empty + svg {
145 | display: none;
146 | }
147 |
148 | .product-option {
149 | color: rgba(var(--color-foreground), 0.7);
150 | }
151 |
152 | .product-option + .product-option {
153 | margin-top: 0.4rem;
154 | }
155 |
156 | .product-option * {
157 | display: inline;
158 | margin: 0;
159 | }
160 |
161 | .cart-items thead th {
162 | text-transform: uppercase;
163 | }
164 |
165 | @media screen and (max-width: 749px) {
166 | .cart-items,
167 | .cart-items thead,
168 | .cart-items tbody {
169 | display: block;
170 | width: 100%;
171 | }
172 |
173 | .cart-items thead tr {
174 | display: flex;
175 | justify-content: space-between;
176 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.2);
177 | margin-bottom: 4rem;
178 | }
179 |
180 | .cart-items .medium-up {
181 | display: none;
182 | }
183 |
184 | .cart-item {
185 | display: grid;
186 | grid-template: repeat(2, auto) / repeat(4, 1fr);
187 | gap: 1.5rem;
188 | margin-bottom: 3.5rem;
189 | }
190 |
191 | .cart-item:last-child {
192 | margin-bottom: 0;
193 | }
194 |
195 | .cart-item__media {
196 | grid-row: 1 / 3;
197 | }
198 |
199 | .cart-item__details {
200 | grid-column: 2 / 4;
201 | }
202 |
203 | .cart-item__quantity {
204 | grid-column: 2 / 4;
205 | }
206 |
207 | .cart-item__totals {
208 | display: flex;
209 | align-items: flex-end;
210 | justify-content: flex-end;
211 | }
212 | }
213 |
214 | @media screen and (min-width: 750px) {
215 | .cart-items {
216 | border-spacing: 0;
217 | border-collapse: separate;
218 | box-shadow: none;
219 | width: 100%;
220 | display: table;
221 | }
222 |
223 | .cart-items th {
224 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.2);
225 | }
226 |
227 | .cart-items th + th {
228 | padding-left: 4rem;
229 | }
230 |
231 | .cart-items td {
232 | vertical-align: top;
233 | padding-top: 4rem;
234 | }
235 |
236 | .cart-item {
237 | display: table-row;
238 | }
239 |
240 | .cart-item > td + td {
241 | padding-left: 4rem;
242 | }
243 |
244 | .cart-item__media {
245 | width: 7.5rem;
246 | }
247 |
248 | .cart-item quantity-input {
249 | margin-top: 0.7rem;
250 | }
251 |
252 | .cart-items .medium-down {
253 | display: none;
254 | }
255 | }
256 |
257 | @media screen and (min-width: 990px) {
258 | .cart-item .cart-item__quantity,
259 | .cart-items .cart-items__heading--wide {
260 | padding-left: 10rem;
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/src/assets/component-cart-notification.css:
--------------------------------------------------------------------------------
1 | .cart-notification-wrapper {
2 | position: relative;
3 | }
4 |
5 | .cart-notification-wrapper .cart-notification {
6 | display: block;
7 | }
8 |
9 | .cart-notification {
10 | background-color: rgb(var(--color-background));
11 | border-color: rgba(var(--color-foreground), 0.2);
12 | border-style: solid;
13 | border-width: 0 0 0.1rem;
14 | padding: 2.5rem 3.5rem;
15 | position: absolute;
16 | right: 0;
17 | transform: translateY(-100%);
18 | visibility: hidden;
19 | width: 100%;
20 | z-index: -1;
21 | }
22 |
23 | @media screen and (min-width: 750px) {
24 | .cart-notification {
25 | border-width: 0 0.1rem 0.1rem;
26 | max-width: 36.8rem;
27 | right: 4rem;
28 | }
29 | }
30 |
31 | .cart-notification.animate {
32 | transition: transform var(--duration-short) ease,
33 | visibility 0s var(--duration-short) ease;
34 | }
35 |
36 | .cart-notification.active {
37 | transform: translateY(0);
38 | transition: transform var(--duration-default) ease, visibility 0s;
39 | visibility: visible;
40 | }
41 |
42 | .cart-notification__header {
43 | align-items: flex-start;
44 | display: flex;
45 | }
46 |
47 | .cart-notification__heading {
48 | align-items: center;
49 | display: flex;
50 | flex-grow: 1;
51 | margin-bottom: 0;
52 | margin-top: 0;
53 | }
54 |
55 | .cart-notification__heading .icon-checkmark {
56 | color: rgb(var(--color-foreground));
57 | margin-right: 1rem;
58 | width: 1.3rem;
59 | }
60 |
61 | .cart-notification__close {
62 | margin-top: -2rem;
63 | margin-right: -3rem;
64 | }
65 |
66 | .cart-notification__links {
67 | text-align: center;
68 | }
69 |
70 | .cart-notification__links > * {
71 | margin-top: 1rem;
72 | }
73 |
74 | .cart-notification-product {
75 | align-items: flex-start;
76 | display: flex;
77 | padding-bottom: 3rem;
78 | padding-top: 2rem;
79 | }
80 |
81 | .cart-notification-product dl {
82 | margin-bottom: 0;
83 | margin-top: 0;
84 | }
85 |
86 | .cart-notification-product__image {
87 | border: 0.1rem solid rgba(var(--color-foreground), 0.03);
88 | margin-right: 1.5rem;
89 | }
90 |
91 | .cart-notification-product__name {
92 | margin-bottom: 0;
93 | margin-top: 0;
94 | }
95 |
96 | .cart-notification-product__option {
97 | color: rgba(var(--color-foreground), 0.7);
98 | margin-top: 1rem;
99 | }
100 |
101 | .cart-notification-product__option + .cart-notification-product__option {
102 | margin-top: 0.5rem;
103 | }
104 |
105 | .cart-notification-product__option > * {
106 | display: inline-block;
107 | margin: 0;
108 | }
109 |
--------------------------------------------------------------------------------
/src/assets/component-cart.css:
--------------------------------------------------------------------------------
1 | .cart {
2 | position: relative;
3 | display: block;
4 | }
5 |
6 | .cart__empty-text,
7 | .is-empty .cart__contents,
8 | cart-items.is-empty .title-wrapper-with-link,
9 | .is-empty .cart__footer {
10 | display: none;
11 | }
12 |
13 | .is-empty .cart__empty-text,
14 | .is-empty .cart__warnings {
15 | display: block;
16 | }
17 |
18 | .cart__warnings {
19 | display: none;
20 | text-align: center;
21 | padding: 7rem 0;
22 | }
23 |
24 | .cart__empty-text {
25 | margin: 4.5rem 0 5.5rem;
26 | }
27 |
28 | .cart__contents > * + * {
29 | margin-top: 2.5rem;
30 | }
31 |
32 | @media screen and (min-width: 990px) {
33 | .cart__warnings {
34 | padding: 10rem 0 15rem;
35 | }
36 |
37 | .cart__empty-text {
38 | margin: 5rem 0 6rem;
39 | }
40 | }
41 |
42 | cart-items {
43 | display: block;
44 | }
45 |
46 | .cart__items {
47 | position: relative;
48 | padding-bottom: 3rem;
49 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.2);
50 | }
51 |
52 | .cart__items--disabled {
53 | pointer-events: none;
54 | }
55 |
56 | .cart__footer {
57 | padding: 4rem 0 0;
58 | }
59 |
60 | .cart__footer-wrapper:last-child .cart__footer {
61 | padding-bottom: 5rem;
62 | }
63 |
64 | .cart__footer > div:only-child {
65 | margin-left: auto;
66 | }
67 |
68 | .cart__footer > * + * {
69 | margin-top: 4rem;
70 | }
71 |
72 | .cart__footer .discounts {
73 | margin-top: 1rem;
74 | }
75 |
76 | .cart__note {
77 | display: block;
78 | }
79 |
80 | .cart__note label {
81 | display: flex;
82 | align-items: flex-end;
83 | line-height: 1;
84 | height: 1.8rem;
85 | margin-bottom: 2rem;
86 | color: rgba(var(--color-foreground), 0.75);
87 | }
88 |
89 | .cart__note .field__input {
90 | padding: 1rem;
91 | }
92 |
93 | @media screen and (min-width: 750px) {
94 | .cart__items {
95 | grid-column-start: 1;
96 | grid-column-end: 3;
97 | padding-bottom: 4rem;
98 | margin-bottom: 4rem;
99 | }
100 |
101 | .cart__contents > * + * {
102 | margin-top: 0;
103 | }
104 |
105 | .cart__items + .cart__footer {
106 | grid-column: 2;
107 | }
108 |
109 | .cart__footer {
110 | display: flex;
111 | justify-content: space-between;
112 | border: 0;
113 | }
114 |
115 | .cart__footer-wrapper:last-child {
116 | padding-top: 0;
117 | }
118 |
119 | .cart__footer > * {
120 | width: 35rem;
121 | }
122 |
123 | .cart__footer > * + * {
124 | margin-left: 4rem;
125 | margin-top: 0;
126 | }
127 | }
128 |
129 | .cart__ctas button {
130 | width: 100%;
131 | }
132 |
133 | .cart__ctas > *:not(noscript:first-child) + * {
134 | margin-top: 1rem;
135 | }
136 |
137 | .cart__update-button {
138 | margin-bottom: 1rem;
139 | }
140 |
141 | .cart__dynamic-checkout-buttons {
142 | max-width: 36rem;
143 | margin: 0 auto;
144 | }
145 |
146 | .cart__blocks > * + * {
147 | margin-top: 1rem;
148 | }
149 |
150 | .cart__dynamic-checkout-buttons div[role='button'] {
151 | border-radius: 0 !important;
152 | }
153 |
154 | .cart-note__label {
155 | display: inline-block;
156 | margin-bottom: 1rem;
157 | line-height: 2;
158 | }
159 |
160 | .tax-note {
161 | margin: 2.2rem 0 1.6rem auto;
162 | text-align: center;
163 | display: block;
164 | }
165 |
166 | .cart__checkout-button {
167 | max-width: 36rem;
168 | }
169 |
170 | .cart__ctas {
171 | text-align: center;
172 | }
173 |
174 | @media screen and (min-width: 750px) {
175 | .cart-note {
176 | max-width: 35rem;
177 | }
178 |
179 | .cart__update-button {
180 | margin-bottom: 0;
181 | margin-right: 0.8rem;
182 | }
183 |
184 | .tax-note {
185 | margin-bottom: 2.2rem;
186 | text-align: right;
187 | }
188 |
189 | [data-shopify-buttoncontainer] {
190 | justify-content: flex-end;
191 | }
192 |
193 | .cart__ctas {
194 | display: flex;
195 | gap: 1rem;
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/assets/component-collection-hero.css:
--------------------------------------------------------------------------------
1 | .collection-hero {
2 | margin-bottom: 2rem;
3 | }
4 |
5 | .collection-hero--with-image {
6 | background-color: rgba(var(--color-foreground), 0.04);
7 | }
8 |
9 | .collection-hero__inner {
10 | display: flex;
11 | flex-direction: column;
12 | padding-bottom: 2rem;
13 | margin-bottom: 2rem;
14 | }
15 |
16 | @media screen and (min-width: 750px) {
17 | .collection-hero.collection-hero--with-image {
18 | padding: 4rem 0 4rem;
19 | }
20 | }
21 |
22 | .collection-hero__text-wrapper {
23 | flex-basis: 100%;
24 | }
25 |
26 | .collection-hero--with-image .collection-hero__inner {
27 | margin-bottom: 4rem;
28 | }
29 |
30 | @media screen and (min-width: 750px) {
31 | .collection-hero {
32 | padding: 0 0 2rem;
33 | margin-bottom: 0;
34 | }
35 |
36 | .collection-hero--with-image {
37 | margin-bottom: 4.5rem;
38 | }
39 |
40 | .collection-hero__inner {
41 | align-items: center;
42 | flex-direction: row;
43 | padding-bottom: 0;
44 | margin-bottom: 0;
45 | }
46 |
47 | .collection-hero--with-image .collection-hero__inner {
48 | margin-bottom: 0;
49 | }
50 | }
51 |
52 | .collection-hero__title {
53 | margin: 5rem 0 0;
54 | }
55 |
56 | .collection-hero__title + .collection-hero__description {
57 | margin-top: 1.5rem;
58 | font-size: 1.6rem;
59 | line-height: 1.5;
60 | }
61 |
62 | @media screen and (min-width: 750px) {
63 | .collection-hero__title + .collection-hero__description {
64 | font-size: 1.8rem;
65 | margin-top: 2rem;
66 | }
67 |
68 | .collection-hero__description {
69 | max-width: 66.67%;
70 | }
71 |
72 | .collection-hero--with-image .collection-hero__description {
73 | max-width: 100%;
74 | }
75 | }
76 |
77 | .collection-hero--with-image .collection-hero__title {
78 | margin: 0;
79 | }
80 |
81 | .collection-hero--with-image .collection-hero__text-wrapper {
82 | padding: 5rem 0 4rem;
83 | }
84 |
85 | @media screen and (max-width: 749px) {
86 | .collection-hero__image-container {
87 | height: 20rem;
88 | }
89 | }
90 |
91 | @media screen and (min-width: 750px) {
92 | .collection-hero--with-image .collection-hero__text-wrapper {
93 | padding: 4rem 2rem 4rem 0;
94 | flex-basis: 50%;
95 | }
96 |
97 | .collection-hero__image-container {
98 | align-self: stretch;
99 | flex: 1 0 50%;
100 | margin-left: 3rem;
101 | min-height: 20rem;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/assets/component-deferred-media.css:
--------------------------------------------------------------------------------
1 | .deferred-media__poster {
2 | background-color: transparent;
3 | border: none;
4 | cursor: pointer;
5 | margin: 0;
6 | padding: 0;
7 | height: 100%;
8 | width: 100%;
9 | }
10 |
11 | .media > .deferred-media__poster {
12 | display: flex;
13 | align-items: center;
14 | justify-content: center;
15 | }
16 |
17 | .deferred-media__poster img {
18 | width: auto;
19 | height: 100%;
20 | }
21 |
22 | .deferred-media {
23 | overflow: hidden;
24 | }
25 |
26 | .deferred-media:not([loaded]) template {
27 | z-index: -1;
28 | }
29 |
30 | .deferred-media[loaded] > .deferred-media__poster {
31 | display: none;
32 | }
33 |
34 | .deferred-media__poster:focus {
35 | outline-offset: -0.3rem;
36 | }
37 |
38 | .deferred-media__poster-button {
39 | background-color: rgb(var(--color-background));
40 | border: 0.1rem solid rgba(var(--color-foreground), 0.1);
41 | border-radius: 50%;
42 | color: rgb(var(--color-foreground));
43 | display: flex;
44 | align-items: center;
45 | justify-content: center;
46 | height: 6.2rem;
47 | width: 6.2rem;
48 | position: absolute;
49 | left: 50%;
50 | top: 50%;
51 | transform: translate(-50%, -50%) scale(1);
52 | transition: transform var(--duration-short) ease, color var(--duration-short) ease;
53 | z-index: 1;
54 | }
55 |
56 | .deferred-media__poster-button:hover {
57 | transform: translate(-50%, -50%) scale(1.1);
58 | }
59 |
60 | .deferred-media__poster-button .icon {
61 | width: 2rem;
62 | height: 2rem;
63 | }
64 |
65 | .deferred-media__poster-button .icon-play {
66 | margin-left: 0.2rem;
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/src/assets/component-discounts.css:
--------------------------------------------------------------------------------
1 | .discounts {
2 | font-size: 1.2rem;
3 | }
4 |
5 | .discounts__discount {
6 | display: flex;
7 | align-items: center;
8 | line-height: 1.5;
9 | }
10 |
11 | .discounts__discount svg {
12 | color: rgba(var(--color-button), var(--alpha-button-background));
13 | }
14 |
15 | .discounts__discount--end {
16 | justify-content: flex-end;
17 | }
18 |
19 | .discounts__discount > .icon {
20 | color: rgb(var(--color-foreground));
21 | width: 1.2rem;
22 | height: 1.2rem;
23 | margin-right: 0.7rem;
24 | }
25 |
--------------------------------------------------------------------------------
/src/assets/component-image-with-text.css:
--------------------------------------------------------------------------------
1 | .image-with-text {
2 | margin-top: 5rem;
3 | }
4 |
5 | .image-with-text:not(.color-scheme-background-1) {
6 | margin-bottom: 5rem;
7 | }
8 |
9 | @media screen and (min-width: 750px) {
10 | .image-with-text {
11 | margin-bottom: 5rem;
12 | }
13 | }
14 |
15 | .image-with-text .grid {
16 | margin-left: 0;
17 | margin-bottom: 0;
18 | }
19 |
20 | .image-with-text__grid {
21 | overflow: hidden;
22 | }
23 |
24 | @media screen and (min-width: 750px) {
25 | .image-with-text__grid--reverse {
26 | flex-direction: row-reverse;
27 | }
28 | }
29 |
30 | .image-with-text__media {
31 | background-color: transparent;
32 | min-height: 100%;
33 | }
34 |
35 | .image-with-text__media--small {
36 | height: 19.4rem;
37 | }
38 |
39 | .image-with-text__media--large {
40 | height: 43.5rem;
41 | }
42 |
43 | @media screen and (min-width: 750px) {
44 | .image-with-text__media--small {
45 | height: 31.4rem;
46 | }
47 |
48 | .image-with-text__media--large {
49 | height: 69.5rem;
50 | }
51 | }
52 |
53 | .image-with-text__media--placeholder {
54 | background-color: rgba(var(--color-foreground), 0.04);
55 | position: relative;
56 | overflow: hidden;
57 | }
58 |
59 | .image-with-text__media--placeholder.image-with-text__media--adapt {
60 | height: 20rem;
61 | }
62 |
63 | @media screen and (min-width: 750px) {
64 | .image-with-text__media--placeholder.image-with-text__media--adapt {
65 | height: 30rem;
66 | }
67 | }
68 |
69 | .image-with-text__media--placeholder > svg {
70 | position: absolute;
71 | left: 50%;
72 | max-width: 80rem;
73 | top: 50%;
74 | transform: translate(-50%, -50%);
75 | width: 100%;
76 | fill: currentColor;
77 | }
78 |
79 | .image-with-text__content {
80 | display: flex;
81 | flex-direction: column;
82 | align-items: flex-start;
83 | height: 100%;
84 | justify-content: center;
85 | padding: 4rem 4rem 5rem;
86 | }
87 |
88 | @media screen and (min-width: 750px) {
89 | .image-with-text__grid--reverse .image-with-text__content {
90 | margin-left: auto;
91 | }
92 | }
93 |
94 | @media screen and (min-width: 990px) {
95 | .image-with-text__content {
96 | padding: 6rem 7rem 7rem;
97 | }
98 | }
99 |
100 | .image-with-text__content > * + * {
101 | margin-top: 2rem;
102 | }
103 |
104 | .image-with-text__content > .image-with-text__text:empty ~ a {
105 | margin-top: 2rem;
106 | }
107 |
108 | .image-with-text__content > :first-child:is(.image-with-text__heading) {
109 | margin-top: 0;
110 | }
111 |
112 | .image-with-text__content :last-child:is(.image-with-text__heading) {
113 | margin-bottom: 0;
114 | }
115 |
116 | .image-with-text__content .button + .image-with-text__text {
117 | margin-top: 2rem;
118 | }
119 |
120 | .image-with-text__content .image-with-text__text + .button {
121 | margin-top: 3rem;
122 | }
123 |
124 | .image-with-text__heading {
125 | margin-bottom: 0;
126 | }
127 |
128 | .image-with-text__text p {
129 | margin-top: 0;
130 | margin-bottom: 1rem;
131 | }
132 |
--------------------------------------------------------------------------------
/src/assets/component-list-menu.css:
--------------------------------------------------------------------------------
1 | .list-menu--right {
2 | right: 0;
3 | }
4 |
5 | .list-menu--disclosure {
6 | position: absolute;
7 | min-width: 100%;
8 | width: 20rem;
9 | border: 1px solid rgba(var(--color-foreground), 0.2);
10 | background-color: rgb(var(--color-background));
11 | }
12 |
13 | .list-menu--disclosure:focus {
14 | outline: none;
15 | }
16 |
17 | .list-menu__item--active {
18 | text-decoration: underline;
19 | text-underline-offset: 0.3rem;
20 | }
21 |
22 | .list-menu--disclosure.localization-selector {
23 | max-height: 18rem;
24 | overflow: auto;
25 | width: 10rem;
26 | padding: 0.5rem;
27 | }
28 |
--------------------------------------------------------------------------------
/src/assets/component-list-payment.css:
--------------------------------------------------------------------------------
1 | .list-payment {
2 | display: flex;
3 | flex-wrap: wrap;
4 | justify-content: center;
5 | margin: -0.5rem 0;
6 | padding-top: 1rem;
7 | padding-left: 0;
8 | }
9 |
10 | @media screen and (min-width: 750px) {
11 | .list-payment {
12 | justify-content: flex-end;
13 | margin: -0.5rem;
14 | padding-top: 0;
15 | }
16 | }
17 |
18 | .list-payment__item {
19 | align-items: center;
20 | display: flex;
21 | padding: 0.5rem;
22 | }
23 |
--------------------------------------------------------------------------------
/src/assets/component-list-social.css:
--------------------------------------------------------------------------------
1 | .list-social {
2 | display: flex;
3 | flex-wrap: wrap;
4 | justify-content: flex-end;
5 | }
6 |
7 | @media only screen and (max-width: 749px) {
8 | .list-social {
9 | justify-content: center;
10 | }
11 | }
12 |
13 | .list-social__item .icon {
14 | height: 1.8rem;
15 | width: 1.8rem;
16 | }
17 |
18 | .list-social__link {
19 | align-items: center;
20 | display: flex;
21 | padding: 1.3rem;
22 | }
23 |
24 | .list-social__link:hover .icon {
25 | transform: scale(1.07);
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/component-loading-overlay.css:
--------------------------------------------------------------------------------
1 | .loading-overlay {
2 | position: absolute;
3 | z-index: 1;
4 | width: 3rem;
5 | }
6 |
7 | @media screen and (max-width: 749px) {
8 | .loading-overlay {
9 | top: 0;
10 | right: 0;
11 | }
12 | }
13 |
14 | @media screen and (min-width: 750px) {
15 | .loading-overlay {
16 | left: 0;
17 | }
18 | }
19 |
20 | .loading-overlay__spinner {
21 | width: 3rem;
22 | display: inline-block;
23 | }
24 |
25 | .spinner {
26 | animation: rotator 1.4s linear infinite;
27 | }
28 |
29 | @keyframes rotator {
30 | 0% {
31 | transform: rotate(0deg);
32 | }
33 | 100% {
34 | transform: rotate(270deg);
35 | }
36 | }
37 |
38 | .path {
39 | stroke-dasharray: 280;
40 | stroke-dashoffset: 0;
41 | transform-origin: center;
42 | stroke: rgb(var(--color-foreground));
43 | animation: dash 1.4s ease-in-out infinite;
44 | }
45 |
46 | @keyframes dash {
47 | 0% {
48 | stroke-dashoffset: 280;
49 | }
50 | 50% {
51 | stroke-dashoffset: 75;
52 | transform: rotate(135deg);
53 | }
54 | 100% {
55 | stroke-dashoffset: 280;
56 | transform: rotate(450deg);
57 | }
58 | }
59 |
60 | .loading-overlay:not(.hidden) + .cart-item__price-wrapper,
61 | .loading-overlay:not(.hidden) ~ cart-remove-button {
62 | opacity: 50%;
63 | }
64 |
65 | .loading-overlay:not(.hidden) ~ cart-remove-button {
66 | pointer-events: none;
67 | cursor: default;
68 | }
69 |
--------------------------------------------------------------------------------
/src/assets/component-model-viewer-ui.css:
--------------------------------------------------------------------------------
1 | .shopify-model-viewer-ui .shopify-model-viewer-ui__controls-area {
2 | background: rgb(var(--color-background));
3 | border-color: rgba(var(--color-foreground), 0.04);
4 | }
5 |
6 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button {
7 | color: rgba(var(--color-foreground), 0.75);
8 | }
9 |
10 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--control:hover {
11 | color: rgba(var(--color-foreground), 0.55);
12 | }
13 |
14 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--control:active,
15 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--control.focus-visible:focus {
16 | color: rgba(var(--color-foreground), 0.55);
17 | background: rgba(var(--color-foreground), 0.04);
18 | }
19 |
20 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--control:not(:last-child):after {
21 | border-color: rgba(var(--color-foreground), 0.04);
22 | }
23 |
24 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--poster {
25 | border-radius: 50%;
26 | color: rgb(var(--color-foreground));
27 | background: rgb(var(--color-background));
28 | border-color: rgba(var(--color-foreground), 0.1);
29 | transform: translate(-50%, -50%) scale(1);
30 | transition: transform var(--duration-short) ease, color var(--duration-short) ease;
31 | }
32 |
33 | .shopify-model-viewer-ui .shopify-model-viewer-ui__poster-control-icon {
34 | width: 4.8rem;
35 | height: 4.8rem;
36 | margin-top: .3rem;
37 | }
38 |
39 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--poster:hover,
40 | .shopify-model-viewer-ui .shopify-model-viewer-ui__button--poster:focus {
41 | transform: translate(-50%, -50%) scale(1.1);
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/assets/component-newsletter.css:
--------------------------------------------------------------------------------
1 | .newsletter-form {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | width: 100%;
7 | position: relative;
8 | }
9 |
10 | @media screen and (min-width: 750px) {
11 | .newsletter-form {
12 | flex-direction: row;
13 | align-items: flex-start;
14 | margin: 0 auto;
15 | max-width: 50rem;
16 | }
17 | }
18 |
19 | .newsletter-form__field-wrapper {
20 | width: 100%;
21 | }
22 |
23 | .newsletter-form__message {
24 | justify-content: center;
25 | margin-bottom: 0;
26 | }
27 |
28 | .newsletter-form__message--success {
29 | margin-top: 2rem;
30 | }
31 |
32 | @media screen and (min-width: 750px) {
33 | .newsletter-form__message {
34 | justify-content: flex-start;
35 | }
36 |
37 | .newsletter-form__message--success {
38 | position: absolute;
39 | left: 0;
40 | bottom: -65%;
41 | }
42 | }
43 |
44 | .newsletter-form__button {
45 | margin-left: 1.4rem;
46 | }
47 |
48 | @media screen and (max-width: 989px) {
49 | .newsletter-form__button {
50 | width: 100%;
51 | margin: 1.4rem 0 0 0;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/assets/component-pagination.css:
--------------------------------------------------------------------------------
1 | .pagination-wrapper {
2 | margin-top: 4rem;
3 | margin-bottom: 7rem;
4 | }
5 |
6 | .pagination-wrapper-small {
7 | margin-top: 1rem;
8 | margin-bottom: 7rem;
9 | }
10 |
11 | @media screen and (min-width: 990px) {
12 | .pagination-wrapper {
13 | margin-top: 5rem;
14 | margin-bottom: 10rem;
15 | }
16 | }
17 |
18 | .pagination__list {
19 | display: flex;
20 | flex-wrap: wrap;
21 | justify-content: center;
22 | }
23 |
24 | .pagination__list > li {
25 | flex: 1 0 4.4rem;
26 | max-width: 4.4rem;
27 | }
28 |
29 | .pagination__list > li:not(:last-child) {
30 | margin-right: 1rem;
31 | }
32 |
33 | .pagination__item {
34 | color: rgb(var(--color-foreground));
35 | display: inline-flex;
36 | justify-content: center;
37 | align-items: center;
38 | position: relative;
39 | height: 4.4rem;
40 | width: 100%;
41 | padding: 0;
42 | text-decoration: none;
43 | }
44 |
45 | .pagination__item:hover {
46 | color: rgb(var(--color-foreground));
47 | }
48 |
49 | a.pagination__item:hover::after {
50 | height: 0.2rem;
51 | }
52 |
53 | .pagination__item .icon-caret {
54 | height: 0.6rem;
55 | }
56 |
57 | .pagination__item--current {
58 | font-weight: 600;
59 | }
60 |
61 | .pagination__item--current::after {
62 | height: 0.1rem;
63 | }
64 |
65 | .pagination__item--current::after,
66 | .pagination__item:hover::after {
67 | content: '';
68 | display: block;
69 | width: 2rem;
70 | position: absolute;
71 | bottom: 8px;
72 | left: 50%;
73 | transform: translateX(-50%);
74 | background-color: currentColor;
75 | }
76 |
77 | .pagination__item--next .icon {
78 | margin-left: -0.2rem;
79 | transform: rotate(90deg);
80 | }
81 |
82 | .pagination__item--next:hover .icon {
83 | transform: rotate(90deg) scale(1.07);
84 | }
85 |
86 | .pagination__item--prev .icon {
87 | margin-right: -0.2rem;
88 | transform: rotate(-90deg);
89 | }
90 |
91 | .pagination__item--prev:hover .icon {
92 | transform: rotate(-90deg) scale(1.07);
93 | }
94 |
95 | .pagination__item-arrow {
96 | color: rgba(var(--color-foreground), 0.75);
97 | }
98 |
99 | .pagination__item-arrow:hover .icon {
100 | color: rgb(var(--color-foreground));
101 | }
102 |
103 | .pagination__item-arrow:hover::after {
104 | display: none;
105 | }
106 |
--------------------------------------------------------------------------------
/src/assets/component-pickup-availability.css:
--------------------------------------------------------------------------------
1 | pickup-availability {
2 | display: block;
3 | }
4 |
5 | pickup-availability[available] {
6 | min-height: 12rem;
7 | }
8 |
9 | .pickup-availability-preview {
10 | align-items: flex-start;
11 | display: flex;
12 | gap: 0.2rem;
13 | }
14 |
15 | @media screen and (min-width: 750px) {
16 | .pickup-availability-preview {
17 | padding: 0 2rem 0 0;
18 | }
19 | }
20 |
21 | .pickup-availability-preview .icon {
22 | flex-shrink: 0;
23 | height: 1.8rem;
24 | }
25 |
26 | .pickup-availability-preview .icon-unavailable {
27 | height: 1.6rem;
28 | margin-top: 0.1rem;
29 | }
30 |
31 | .pickup-availability-button {
32 | background-color: transparent;
33 | color: rgba(var(--color-foreground), 0.75);
34 | letter-spacing: 0.06rem;
35 | padding: 0 0 0.2rem;
36 | text-decoration: underline;
37 | }
38 |
39 | .pickup-availability-button:hover {
40 | color: rgb(var(--color-foreground));
41 | }
42 |
43 | .pickup-availability-info * {
44 | margin: 0 0 0.6rem;
45 | }
46 |
47 | pickup-availability-drawer {
48 | background-color: rgb(var(--color-background));
49 | border: 0.1rem solid rgba(var(--color-foreground), 0.2);
50 | height: 100%;
51 | opacity: 0;
52 | overflow-y: auto;
53 | padding: 2rem;
54 | position: fixed;
55 | top: 0;
56 | right: 0;
57 | z-index: 4;
58 | transition: opacity var(--duration-default) ease,
59 | transform var(--duration-default) ease;
60 | transform: translateX(100%);
61 | width: 100%;
62 | }
63 |
64 | pickup-availability-drawer[open] {
65 | transform: translateX(0);
66 | opacity: 1;
67 | }
68 |
69 | @media screen and (min-width: 750px) {
70 | pickup-availability-drawer {
71 | transform: translateX(100%);
72 | width: 37.5rem;
73 | }
74 |
75 | pickup-availability-drawer[open] {
76 | opacity: 1;
77 | transform: translateX(0);
78 | animation: animateDrawerOpen var(--duration-default) ease;
79 | }
80 | }
81 |
82 | .pickup-availability-header {
83 | align-items: flex-start;
84 | display: flex;
85 | justify-content: space-between;
86 | margin-bottom: 1.2rem;
87 | }
88 |
89 | .pickup-availability-drawer-title {
90 | margin: 0.5rem 0 0;
91 | }
92 |
93 | .pickup-availability-header .icon {
94 | width: 2rem;
95 | }
96 |
97 | .pickup-availability-drawer-button {
98 | background-color: transparent;
99 | border: none;
100 | color: rgb(var(--color-foreground));
101 | cursor: pointer;
102 | display: block;
103 | height: 4.4rem;
104 | padding: 1.2rem;
105 | width: 4.4rem;
106 | }
107 |
108 | .pickup-availability-drawer-button:hover {
109 | color: rgba(var(--color-foreground), 0.75);
110 | }
111 |
112 | .pickup-availability-variant {
113 | font-size: 1.3rem;
114 | line-height: 1.2;
115 | margin: 0 0 1.2rem;
116 | text-transform: capitalize;
117 | }
118 |
119 | .pickup-availability-variant > * + strong {
120 | margin-left: 1rem;
121 | }
122 |
123 | .pickup-availability-list__item {
124 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.2);
125 | padding: 2rem 0;
126 | }
127 |
128 | .pickup-availability-list__item:first-child {
129 | border-top: 0.1rem solid rgba(var(--color-foreground), 0.2);
130 | }
131 |
132 | .pickup-availability-list__item > * {
133 | margin: 0;
134 | }
135 |
136 | .pickup-availability-list__item > * + * {
137 | margin-top: 1rem;
138 | }
139 |
140 | .pickup-availability-address {
141 | font-style: normal;
142 | font-size: 1.2rem;
143 | line-height: 1.5;
144 | }
145 |
146 | .pickup-availability-address p {
147 | margin: 0;
148 | }
149 |
150 | @keyframes animateDrawerOpen {
151 | @media screen and (max-width: 749px) {
152 | 0% {
153 | opacity: 0;
154 | transform: translateX(100%);
155 | }
156 |
157 | 100% {
158 | opacity: 1;
159 | transform: translateX(0);
160 | }
161 | }
162 |
163 | @media screen and (min-width: 750px) {
164 | 0% {
165 | opacity: 0;
166 | transform: translateX(100%);
167 | }
168 |
169 | 100% {
170 | opacity: 1;
171 | transform: translateX(0);
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/assets/component-price.css:
--------------------------------------------------------------------------------
1 | .price {
2 | align-items: center;
3 | display: flex;
4 | flex-direction: row;
5 | flex-wrap: wrap;
6 | font-size: 1.6rem;
7 | letter-spacing: 0.1rem;
8 | line-height: 1.5;
9 | color: rgb(var(--color-foreground));
10 | }
11 |
12 | .price.price--unavailable {
13 | visibility: hidden;
14 | }
15 |
16 | .price--end {
17 | justify-content: flex-end;
18 | }
19 |
20 | .price dl {
21 | margin: 0;
22 | display: flex;
23 | flex-direction: column;
24 | }
25 |
26 | .price dd {
27 | margin: 0 1rem 0 0;
28 | }
29 |
30 | .price .price__last:last-of-type {
31 | margin: 0;
32 | }
33 |
34 | @media screen and (min-width: 750px) {
35 | .price {
36 | margin-bottom: 0;
37 | }
38 | }
39 |
40 | .price--large {
41 | font-size: 1.6rem;
42 | line-height: 1.5;
43 | letter-spacing: 0.13rem;
44 | }
45 |
46 | @media screen and (min-width: 750px) {
47 | .price--large {
48 | font-size: 1.8rem;
49 | }
50 | }
51 |
52 | .price--sold-out .price__availability,
53 | .price__regular {
54 | display: block;
55 | }
56 |
57 | .price__sale,
58 | .price__availability,
59 | .price .price__badge-sale,
60 | .price .price__badge-sold-out,
61 | .price--on-sale .price__regular,
62 | .price--on-sale .price__availability,
63 | .price--no-compare .price__compare {
64 | display: none;
65 | }
66 |
67 | .price--sold-out .price__badge-sold-out,
68 | .price--on-sale .price__badge-sale {
69 | display: inline-flex;
70 | }
71 |
72 | .price--on-sale .price__sale {
73 | display: flex;
74 | flex-direction: row;
75 | flex-wrap: wrap;
76 | }
77 |
78 | .price--center {
79 | display: flex;
80 | justify-content: center;
81 | }
82 |
83 | .price--on-sale .price-item--regular {
84 | text-decoration: line-through;
85 | color: rgba(var(--color-foreground), 0.75);
86 | }
87 |
88 | .unit-price {
89 | font-size: 1.1rem;
90 | letter-spacing: 0.04rem;
91 | line-height: 1.2;
92 | margin-top: 0.2rem;
93 | text-transform: uppercase;
94 | color: rgba(var(--color-foreground), 0.7);
95 | }
96 |
--------------------------------------------------------------------------------
/src/assets/component-product-model.css:
--------------------------------------------------------------------------------
1 | .button.product__xr-button {
2 | background: rgba(var(--color-foreground), 0.08);
3 | color: rgb(var(--color-foreground));
4 | margin: 1rem auto;
5 | box-shadow: none;
6 | }
7 |
8 | .button.product__xr-button:hover {
9 | box-shadow: none;
10 | }
11 |
12 | .product__xr-button[data-shopify-xr-hidden] {
13 | visibility: hidden;
14 | }
15 |
16 | @media screen and (max-width: 749px) {
17 | slider-component .product__xr-button:not([data-shopify-xr-hidden]) {
18 | display: none;
19 | }
20 |
21 | .active .product__xr-button:not([data-shopify-xr-hidden]) {
22 | display: block;
23 | }
24 | }
25 |
26 | @media screen and (min-width: 750px) {
27 | .product__media-wrapper > .button.product__xr-button {
28 | display: none;
29 | }
30 |
31 | .product__xr-button[data-shopify-xr-hidden] {
32 | display: none;
33 | }
34 | }
35 |
36 | .product__xr-button .icon {
37 | width: 1.4rem;
38 | margin-right: 1rem;
39 | }
40 |
--------------------------------------------------------------------------------
/src/assets/component-rte.css:
--------------------------------------------------------------------------------
1 | .rte > p:first-child {
2 | margin-top: 0;
3 | }
4 |
5 | .rte > p:last-child {
6 | margin-bottom: 0;
7 | }
8 |
9 | .rte table {
10 | table-layout: fixed;
11 | }
12 |
13 | @media screen and (min-width: 750px) {
14 | .rte table td {
15 | padding-left: 1.2rem;
16 | padding-right: 1.2rem;
17 | }
18 | }
19 |
20 | .rte img {
21 | height: auto;
22 | max-width: 100%;
23 | }
24 |
25 | .rte ul {
26 | padding-left: 2rem;
27 | }
28 |
29 | .rte li {
30 | list-style: inherit;
31 | }
32 |
33 | .rte li:last-child {
34 | margin-bottom: 0;
35 | }
36 |
37 | .rte a {
38 | color: rgba(var(--color-link), var(--alpha-link));
39 | text-underline-offset: 0.3rem;
40 | text-decoration-thickness: 0.1rem;
41 | transition: text-decoration-thickness var(--duration-short) ease;
42 | }
43 |
44 | .rte a:hover {
45 | color: rgb(var(--color-link));
46 | text-decoration-thickness: 0.2rem;
47 | }
48 |
49 | .rte blockquote {
50 | display: inline-flex;
51 | }
52 |
53 | .rte blockquote > * {
54 | margin: -0.5rem 0 -0.5rem 0;
55 | }
56 |
--------------------------------------------------------------------------------
/src/assets/component-search.css:
--------------------------------------------------------------------------------
1 | .search__input.field__input {
2 | padding-right: 5rem;
3 | }
4 |
5 | .search__button .icon {
6 | height: 1.8rem;
7 | }
8 |
9 | /* Remove extra spacing for search inputs in Safari */
10 | input::-webkit-search-decoration {
11 | -webkit-appearance: none;
12 | }
13 |
--------------------------------------------------------------------------------
/src/assets/component-slider.css:
--------------------------------------------------------------------------------
1 | slider-component {
2 | position: relative;
3 | display: block;
4 | }
5 |
6 | @media screen and (max-width: 989px) {
7 | slider-component .slider {
8 | padding-bottom: 6rem;
9 | }
10 |
11 | .no-js slider-component .slider {
12 | padding-bottom: 3rem;
13 | }
14 | }
15 |
16 | .slider__slide {
17 | scroll-snap-align: start;
18 | flex-shrink: 0;
19 | }
20 |
21 | @media screen and (max-width: 749px) {
22 | .slider.slider--mobile {
23 | position: relative;
24 | flex-wrap: inherit;
25 | overflow-x: auto;
26 | scroll-snap-type: x mandatory;
27 | scroll-behavior: smooth;
28 | scroll-padding-left: 1rem;
29 | -webkit-overflow-scrolling: touch;
30 | }
31 |
32 | .slider.slider--mobile .slider__slide {
33 | margin-bottom: 0;
34 | padding-bottom: 0;
35 | }
36 | }
37 |
38 | @media screen and (max-width: 989px) {
39 | .slider.slider--tablet {
40 | position: relative;
41 | flex-wrap: inherit;
42 | overflow-x: auto;
43 | scroll-snap-type: x mandatory;
44 | scroll-behavior: smooth;
45 | scroll-padding-left: 1rem;
46 | -webkit-overflow-scrolling: touch;
47 | }
48 |
49 | .slider.slider--tablet .slider__slide {
50 | margin-bottom: 0;
51 | padding-bottom: 0;
52 | }
53 | }
54 |
55 | /* Scrollbar */
56 |
57 | .slider {
58 | scrollbar-color: rgb(var(--color-foreground)) rgba(var(--color-foreground), 0.04);
59 | -ms-overflow-style: none;
60 | scrollbar-width: none;
61 | }
62 |
63 | .slider::-webkit-scrollbar {
64 | height: 0.4rem;
65 | width: 0.4rem;
66 | display: none;
67 | }
68 |
69 | .no-js .slider {
70 | -ms-overflow-style: auto;
71 | scrollbar-width: auto;
72 | }
73 |
74 | .no-js .slider::-webkit-scrollbar {
75 | display: initial;
76 | }
77 |
78 | .slider::-webkit-scrollbar-thumb {
79 | background-color: rgb(var(--color-foreground));
80 | border-radius: 0.4rem;
81 | border: 0;
82 | }
83 |
84 | .slider::-webkit-scrollbar-track {
85 | background: rgba(var(--color-foreground), 0.04);
86 | border-radius: 0.4rem;
87 | }
88 |
89 | slider-component .slider-buttons {
90 | position: absolute;
91 | z-index: 2;
92 | right: 0;
93 | bottom: 0;
94 | }
95 |
96 | .slider-buttons.slider-buttons--overlay {
97 | border: 0.1rem solid rgba(var(--color-foreground), 0.08);
98 | background-color: rgb(var(--color-background));
99 | }
100 |
101 | .slider-mobile-gutter .slider-buttons {
102 | right: 1.5rem;
103 | }
104 |
105 | .slider-counter {
106 | margin-right: 3rem;
107 | }
108 |
109 | .slider-buttons--overlay .slider-counter {
110 | margin-right: 0;
111 | padding: 0 1.4rem;
112 | }
113 |
114 | .slider-buttons {
115 | display: flex;
116 | align-items: center;
117 | }
118 |
119 | @media screen and (min-width: 990px) {
120 | .slider-buttons {
121 | display: none;
122 | }
123 | }
124 |
125 | @media screen and (min-width: 750px) {
126 | .slider--mobile + .slider-buttons {
127 | display: none;
128 | }
129 | }
130 |
131 | .slider-button {
132 | color: rgba(var(--color-foreground), 0.75);
133 | border: 0.1rem solid rgba(var(--color-foreground), 0.08);
134 | background-color: rgb(var(--color-background));
135 | cursor: pointer;
136 | width: 44px;
137 | height: 44px;
138 | }
139 |
140 | .slider-button:not([disabled]):hover {
141 | color: rgb(var(--color-foreground));
142 | border-color: rgb(var(--color-foreground));
143 | z-index: 1;
144 | }
145 |
146 | .slider-button:first-of-type {
147 | margin-right: -1px;
148 | }
149 |
150 | .slider-buttons--overlay .slider-button {
151 | margin-top: -1px;
152 | margin-bottom: -1px;
153 | }
154 |
155 | .slider-buttons--overlay .slider-button + .slider-button {
156 | margin-right: -1px;
157 | }
158 |
159 | .slider-button .icon {
160 | height: 0.6rem;
161 | }
162 |
163 | .slider-button[disabled] .icon {
164 | color: rgba(var(--color-foreground), 0.3);
165 | }
166 |
167 | .slider-button--next .icon {
168 | margin-right: -0.2rem;
169 | transform: rotate(-90deg) translateX(0.15rem);
170 | }
171 |
172 | .slider-button--prev .icon {
173 | margin-left: -0.2rem;
174 | transform: rotate(90deg) translateX(-0.15rem);
175 | }
176 |
177 | .slider-button--next:not([disabled]):hover .icon {
178 | transform: rotate(-90deg) translateX(0.15rem) scale(1.07);
179 | }
180 |
181 | .slider-button--prev:not([disabled]):hover .icon {
182 | transform: rotate(90deg) translateX(-0.15rem) scale(1.07);
183 | }
184 |
185 | .slider-button:focus-visible {
186 | z-index: 1;
187 | }
188 |
--------------------------------------------------------------------------------
/src/assets/component-totals.css:
--------------------------------------------------------------------------------
1 | .totals {
2 | display: flex;
3 | justify-content: center;
4 | align-items: flex-end;
5 | }
6 |
7 | .totals > * {
8 | font-size: 1.6rem;
9 | margin: 0;
10 | }
11 |
12 | .totals * {
13 | line-height: 1;
14 | }
15 |
16 | .totals > * + * {
17 | margin-left: 2rem;
18 | }
19 |
20 | .totals__subtotal-value {
21 | font-size: 1.8rem;
22 | }
23 |
24 | .cart__ctas + .totals {
25 | margin-top: 2rem;
26 | }
27 |
28 | @media all and (min-width: 750px) {
29 | .totals {
30 | justify-content: flex-end;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/customer.js:
--------------------------------------------------------------------------------
1 | const selectors = {
2 | customerAddresses: '[data-customer-addresses]',
3 | addressCountrySelect: '[data-address-country-select]',
4 | addressContainer: '[data-address]',
5 | toggleAddressButton: 'button[aria-expanded]',
6 | cancelAddressButton: 'button[type="reset"]',
7 | deleteAddressButton: 'button[data-confirm-message]'
8 | };
9 |
10 | const attributes = {
11 | expanded: 'aria-expanded',
12 | confirmMessage: 'data-confirm-message'
13 | };
14 |
15 | class CustomerAddresses {
16 | constructor() {
17 | this.elements = this._getElements();
18 | if (Object.keys(this.elements).length === 0) return;
19 | this._setupCountries();
20 | this._setupEventListeners();
21 | }
22 |
23 | _getElements() {
24 | const container = document.querySelector(selectors.customerAddresses);
25 | return container ? {
26 | container,
27 | addressContainer: container.querySelector(selectors.addressContainer),
28 | toggleButtons: document.querySelectorAll(selectors.toggleAddressButton),
29 | cancelButtons: container.querySelectorAll(selectors.cancelAddressButton),
30 | deleteButtons: container.querySelectorAll(selectors.deleteAddressButton),
31 | countrySelects: container.querySelectorAll(selectors.addressCountrySelect)
32 | } : {};
33 | }
34 |
35 | _setupCountries() {
36 | if (Shopify && Shopify.CountryProvinceSelector) {
37 | // eslint-disable-next-line no-new
38 | new Shopify.CountryProvinceSelector('AddressCountryNew', 'AddressProvinceNew', {
39 | hideElement: 'AddressProvinceContainerNew'
40 | });
41 | this.elements.countrySelects.forEach((select) => {
42 | const formId = select.dataset.formId;
43 | // eslint-disable-next-line no-new
44 | new Shopify.CountryProvinceSelector(`AddressCountry_${formId}`, `AddressProvince_${formId}`, {
45 | hideElement: `AddressProvinceContainer_${formId}`
46 | });
47 | });
48 | }
49 | }
50 |
51 | _setupEventListeners() {
52 | this.elements.toggleButtons.forEach((element) => {
53 | element.addEventListener('click', this._handleAddEditButtonClick);
54 | });
55 | this.elements.cancelButtons.forEach((element) => {
56 | element.addEventListener('click', this._handleCancelButtonClick);
57 | });
58 | this.elements.deleteButtons.forEach((element) => {
59 | element.addEventListener('click', this._handleDeleteButtonClick);
60 | });
61 | }
62 |
63 | _toggleExpanded(target) {
64 | target.setAttribute(
65 | attributes.expanded,
66 | (target.getAttribute(attributes.expanded) === 'false').toString()
67 | );
68 | }
69 |
70 | _handleAddEditButtonClick = ({ currentTarget }) => {
71 | this._toggleExpanded(currentTarget);
72 | }
73 |
74 | _handleCancelButtonClick = ({ currentTarget }) => {
75 | this._toggleExpanded(
76 | currentTarget
77 | .closest(selectors.addressContainer)
78 | .querySelector(`[${attributes.expanded}]`)
79 | )
80 | }
81 |
82 | _handleDeleteButtonClick = ({ currentTarget }) => {
83 | // eslint-disable-next-line no-alert
84 | if (confirm(currentTarget.getAttribute(attributes.confirmMessage))) {
85 | Shopify.postLink(currentTarget.dataset.target, {
86 | parameters: { _method: 'delete' },
87 | });
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/assets/details-disclosure.js:
--------------------------------------------------------------------------------
1 | class DetailsDisclosure extends HTMLElement {
2 | constructor() {
3 | super();
4 | this.mainDetailsToggle = this.querySelector('details');
5 |
6 | this.addEventListener('keyup', this.onKeyUp);
7 | this.mainDetailsToggle.addEventListener('focusout', this.onFocusOut.bind(this));
8 | }
9 |
10 | onKeyUp(event) {
11 | if(event.code.toUpperCase() !== 'ESCAPE') return;
12 |
13 | const openDetailsElement = event.target.closest('details[open]');
14 | if (!openDetailsElement) return;
15 |
16 | const summaryElement = openDetailsElement.querySelector('summary');
17 | openDetailsElement.removeAttribute('open');
18 | summaryElement.focus();
19 | }
20 |
21 | onFocusOut() {
22 | setTimeout(() => {
23 | if (!this.contains(document.activeElement)) this.close();
24 | })
25 | }
26 |
27 | close() {
28 | this.mainDetailsToggle.removeAttribute('open')
29 | }
30 | }
31 |
32 | customElements.define('details-disclosure', DetailsDisclosure);
33 |
--------------------------------------------------------------------------------
/src/assets/details-modal.js:
--------------------------------------------------------------------------------
1 | class DetailsModal extends HTMLElement {
2 | constructor() {
3 | super();
4 | this.detailsContainer = this.querySelector('details');
5 | this.summaryToggle = this.querySelector('summary');
6 |
7 | this.detailsContainer.addEventListener(
8 | 'keyup',
9 | (event) => event.code.toUpperCase() === 'ESCAPE' && this.close()
10 | );
11 | this.summaryToggle.addEventListener(
12 | 'click',
13 | this.onSummaryClick.bind(this)
14 | );
15 | this.querySelector('button[type="button"]').addEventListener(
16 | 'click',
17 | this.close.bind(this)
18 | );
19 |
20 | this.summaryToggle.setAttribute('role', 'button');
21 | this.summaryToggle.setAttribute('aria-expanded', 'false');
22 | }
23 |
24 | isOpen() {
25 | return this.detailsContainer.hasAttribute('open');
26 | }
27 |
28 | onSummaryClick(event) {
29 | event.preventDefault();
30 | event.target.closest('details').hasAttribute('open')
31 | ? this.close()
32 | : this.open(event);
33 | }
34 |
35 | onBodyClick(event) {
36 | if (!this.contains(event.target)) this.close(false);
37 | }
38 |
39 | open(event) {
40 | this.onBodyClickEvent =
41 | this.onBodyClickEvent || this.onBodyClick.bind(this);
42 | event.target.closest('details').setAttribute('open', true);
43 | document.body.addEventListener('click', this.onBodyClickEvent);
44 |
45 | trapFocus(
46 | this.detailsContainer.querySelector('[tabindex="-1"]'),
47 | this.detailsContainer.querySelector('input:not([type="hidden"])')
48 | );
49 | }
50 |
51 | close(focusToggle = true) {
52 | removeTrapFocus(focusToggle ? this.summaryToggle : null);
53 | this.detailsContainer.removeAttribute('open');
54 | document.body.removeEventListener('click', this.onBodyClickEvent);
55 | }
56 | }
57 |
58 | customElements.define('details-modal', DetailsModal);
59 |
--------------------------------------------------------------------------------
/src/assets/disclosure.css:
--------------------------------------------------------------------------------
1 | .disclosure {
2 | position: relative;
3 | }
4 |
5 | .disclosure__button {
6 | align-items: center;
7 | cursor: pointer;
8 | display: flex;
9 | height: 4rem;
10 | padding: 0 1.5rem 0 1.5rem;
11 | font-size: 1.3rem;
12 | background-color: transparent;
13 | }
14 |
15 | .disclosure__list {
16 | border: 1px solid rgba(var(--color-foreground), 0.2);
17 | font-size: 1.4rem;
18 | margin-top: -0.5rem;
19 | min-height: 8.2rem;
20 | max-height: 19rem;
21 | max-width: 22rem;
22 | min-width: 12rem;
23 | width: max-content;
24 | overflow-y: auto;
25 | padding-bottom: 0.5rem;
26 | padding-top: 0.5rem;
27 | position: absolute;
28 | bottom: 100%;
29 | transform: translateY(-1rem);
30 | z-index: 2;
31 | background-color: rgb(var(--color-background));
32 | }
33 |
34 | .disclosure__item {
35 | position: relative;
36 | }
37 |
38 | .disclosure__link {
39 | display: block;
40 | padding: 0.5rem 2.2rem;
41 | text-decoration: none;
42 | line-height: 1.8;
43 | }
44 |
--------------------------------------------------------------------------------
/src/assets/newsletter-section.css:
--------------------------------------------------------------------------------
1 | .newsletter--narrow .newsletter__wrapper,
2 | .newsletter:not(.newsletter--narrow) .newsletter__wrapper.color-background-1 {
3 | margin-top: 5rem;
4 | margin-bottom: 5rem;
5 | }
6 |
7 | .newsletter__wrapper:not(.color-background-1) {
8 | padding-top: 5rem;
9 | padding-bottom: 5rem;
10 | }
11 |
12 | .newsletter__wrapper {
13 | padding-right: 4rem;
14 | padding-left: 4rem;
15 | }
16 |
17 | @media screen and (min-width: 750px) {
18 | .newsletter__wrapper {
19 | padding-right: 9rem;
20 | padding-left: 9rem;
21 | }
22 | }
23 |
24 | .newsletter__wrapper > * {
25 | margin-top: 0;
26 | margin-bottom: 0;
27 | }
28 |
29 | .newsletter__wrapper > * + * {
30 | margin-top: 2rem;
31 | }
32 |
33 | .newsletter__wrapper > * + .newsletter-form {
34 | margin-top: 3rem;
35 | }
36 |
37 | .newsletter__subheading {
38 | max-width: 70rem;
39 | margin-left: auto;
40 | margin-right: auto;
41 | }
42 |
43 | .newsletter__wrapper .newsletter-form__field-wrapper {
44 | max-width: 36rem;
45 | }
46 |
47 | .newsletter-form__field-wrapper .newsletter-form__message {
48 | margin-top: 1.5rem;
49 | }
50 |
51 | .newsletter__button {
52 | margin-top: 3rem;
53 | width: fit-content;
54 | }
55 |
56 | @media screen and (min-width: 750px) {
57 | .newsletter__button {
58 | flex-shrink: 0;
59 | margin: 0 0 0 1rem;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/assets/password-modal.js:
--------------------------------------------------------------------------------
1 | class PasswordModal extends DetailsModal {
2 | constructor() {
3 | super();
4 |
5 | if (this.querySelector('input[aria-invalid="true"]')) this.open({target: this.querySelector('details')});
6 | }
7 | }
8 |
9 | customElements.define('password-modal', PasswordModal);
10 |
--------------------------------------------------------------------------------
/src/assets/pickup-availability.js:
--------------------------------------------------------------------------------
1 | class PickupAvailability extends HTMLElement {
2 | constructor() {
3 | super();
4 |
5 | if(!this.hasAttribute('available')) return;
6 |
7 | this.errorHtml = this.querySelector('template').content.firstElementChild.cloneNode(true);
8 | this.onClickRefreshList = this.onClickRefreshList.bind(this);
9 | this.fetchAvailability(this.dataset.variantId);
10 | }
11 |
12 | fetchAvailability(variantId) {
13 | const variantSectionUrl = `${this.dataset.baseUrl}variants/${variantId}/?section_id=pickup-availability`;
14 |
15 | fetch(variantSectionUrl)
16 | .then(response => response.text())
17 | .then(text => {
18 | const sectionInnerHTML = new DOMParser()
19 | .parseFromString(text, 'text/html')
20 | .querySelector('.shopify-section');
21 | this.renderPreview(sectionInnerHTML);
22 | })
23 | .catch(e => {
24 | this.querySelector('button')?.removeEventListener('click', this.onClickRefreshList);
25 | this.renderError();
26 | });
27 | }
28 |
29 | onClickRefreshList(evt) {
30 | this.fetchAvailability(this.dataset.variantId);
31 | }
32 |
33 | renderError() {
34 | this.innerHTML = '';
35 | this.appendChild(this.errorHtml);
36 |
37 | this.querySelector('button').addEventListener('click', this.onClickRefreshList);
38 | }
39 |
40 | renderPreview(sectionInnerHTML) {
41 | const drawer = document.querySelector('pickup-availability-drawer');
42 | if (drawer) drawer.remove();
43 | if (!sectionInnerHTML.querySelector('pickup-availability-preview')) {
44 | this.innerHTML = "";
45 | this.removeAttribute('available');
46 | return;
47 | }
48 |
49 | this.innerHTML = sectionInnerHTML.querySelector('pickup-availability-preview').outerHTML;
50 | this.setAttribute('available', '');
51 |
52 | document.body.appendChild(sectionInnerHTML.querySelector('pickup-availability-drawer'));
53 |
54 | this.querySelector('button').addEventListener('click', (evt) => {
55 | document.querySelector('pickup-availability-drawer').show(evt.target);
56 | });
57 | }
58 | }
59 |
60 | customElements.define('pickup-availability', PickupAvailability);
61 |
62 | class PickupAvailabilityDrawer extends HTMLElement {
63 | constructor() {
64 | super();
65 |
66 | this.onBodyClick = this.handleBodyClick.bind(this);
67 |
68 | this.querySelector('button').addEventListener('click', () => {
69 | this.hide();
70 | });
71 |
72 | this.addEventListener('keyup', () => {
73 | if(event.code.toUpperCase() === 'ESCAPE') this.hide();
74 | });
75 | }
76 |
77 | handleBodyClick(evt) {
78 | const target = evt.target;
79 | if (target != this && !target.closest('pickup-availability-drawer') && target.id != 'ShowPickupAvailabilityDrawer') {
80 | this.hide();
81 | }
82 | }
83 |
84 | hide() {
85 | this.removeAttribute('open');
86 | document.body.removeEventListener('click', this.onBodyClick);
87 | document.body.classList.remove('overflow-hidden');
88 | removeTrapFocus(this.focusElement);
89 | }
90 |
91 | show(focusElement) {
92 | this.focusElement = focusElement;
93 | this.setAttribute('open', '');
94 | document.body.addEventListener('click', this.onBodyClick);
95 | document.body.classList.add('overflow-hidden');
96 | trapFocus(this);
97 | }
98 | }
99 |
100 | customElements.define('pickup-availability-drawer', PickupAvailabilityDrawer);
101 |
--------------------------------------------------------------------------------
/src/assets/product-form.js:
--------------------------------------------------------------------------------
1 | class ProductForm extends HTMLElement {
2 | constructor() {
3 | super();
4 |
5 | this.form = this.querySelector('form');
6 | this.form.addEventListener('submit', this.onSubmitHandler.bind(this));
7 | this.cartNotification = document.querySelector('cart-notification');
8 | }
9 |
10 | onSubmitHandler(evt) {
11 | evt.preventDefault();
12 | this.cartNotification.setActiveElement(document.activeElement);
13 |
14 | const submitButton = this.querySelector('[type="submit"]');
15 |
16 | submitButton.setAttribute('disabled', true);
17 | submitButton.classList.add('loading');
18 |
19 | const body = JSON.stringify({
20 | ...JSON.parse(serializeForm(this.form)),
21 | sections: this.cartNotification.getSectionsToRender().map((section) => section.id),
22 | sections_url: window.location.pathname
23 | });
24 |
25 | fetch(`${routes.cart_add_url}`, { ...fetchConfig('javascript'), body })
26 | .then((response) => response.json())
27 | .then((parsedState) => {
28 | this.cartNotification.renderContents(parsedState);
29 | })
30 | .catch((e) => {
31 | console.error(e);
32 | })
33 | .finally(() => {
34 | submitButton.classList.remove('loading');
35 | submitButton.removeAttribute('disabled');
36 | });
37 | }
38 | }
39 |
40 | customElements.define('product-form', ProductForm);
41 |
--------------------------------------------------------------------------------
/src/assets/product-model.js:
--------------------------------------------------------------------------------
1 | class ProductModel extends DeferredMedia {
2 | constructor() {
3 | super();
4 | }
5 |
6 | loadContent() {
7 | super.loadContent();
8 |
9 | Shopify.loadFeatures([
10 | {
11 | name: 'model-viewer-ui',
12 | version: '1.0',
13 | onLoad: this.setupModelViewerUI.bind(this),
14 | },
15 | ]);
16 | }
17 |
18 | setupModelViewerUI(errors) {
19 | if (errors) return;
20 |
21 | this.modelViewerUI = new Shopify.ModelViewerUI(this.querySelector('model-viewer'));
22 | }
23 | }
24 | customElements.define('product-model', ProductModel);
25 |
26 | window.ProductModel = {
27 | loadShopifyXR() {
28 | Shopify.loadFeatures([
29 | {
30 | name: 'shopify-xr',
31 | version: '1.0',
32 | onLoad: this.setupShopifyXR.bind(this),
33 | },
34 | ]);
35 | },
36 |
37 | setupShopifyXR(errors) {
38 | if (errors) return;
39 |
40 | if (!window.ShopifyXR) {
41 | document.addEventListener('shopify_xr_initialized', () =>
42 | this.setupShopifyXR()
43 | );
44 | return;
45 | }
46 |
47 | document.querySelectorAll('[id^="ProductJSON-"]').forEach((modelJSON) => {
48 | window.ShopifyXR.addModels(JSON.parse(modelJSON.textContent));
49 | modelJSON.remove();
50 | });
51 | window.ShopifyXR.setupXRElements();
52 | },
53 | };
54 |
55 | window.addEventListener('DOMContentLoaded', () => { window.ProductModel?.loadShopifyXR(); });
56 |
--------------------------------------------------------------------------------
/src/assets/section-blog-post.css:
--------------------------------------------------------------------------------
1 | .article-template > *:first-child:not(.article-template__hero-container) {
2 | margin-top: 5rem;
3 | }
4 |
5 | .article-template__hero-container {
6 | max-width: 130rem;
7 | margin: 0 auto;
8 | }
9 |
10 | @media screen and (min-width: 1320px) {
11 | .article-template__hero-container:first-child {
12 | margin-top: 5rem;
13 | }
14 | }
15 |
16 | .article-template__hero-medium {
17 | height: 15.6rem;
18 | }
19 |
20 | .article-template__hero-large {
21 | height: 19rem;
22 | }
23 |
24 | @media screen and (min-width: 750px) and (max-width: 989px) {
25 | .article-template__hero-medium {
26 | height: 34.9rem;
27 | }
28 |
29 | .article-template__hero-large {
30 | height: 42.3rem;
31 | }
32 | }
33 |
34 | @media screen and (min-width: 990px) {
35 | .article-template__hero-medium {
36 | height: 54.5rem;
37 | }
38 |
39 | .article-template__hero-large {
40 | height: 66rem;
41 | }
42 | }
43 |
44 | .article-template header {
45 | margin-top: 4.4rem;
46 | margin-bottom: 2rem;
47 | }
48 |
49 | @media screen and (min-width: 750px) {
50 | .article-template header {
51 | margin-top: 5rem;
52 | }
53 | }
54 |
55 | .article-template__title {
56 | margin: 0;
57 | }
58 |
59 | .article-template__title:not(:only-child) {
60 | margin-bottom: 1rem;
61 | }
62 |
63 | .article-template__link {
64 | font-size: 1.8rem;
65 | display: flex;
66 | justify-content: center;
67 | align-items: center;
68 | text-underline-offset: 0.3rem;
69 | }
70 |
71 | .article-template__link:hover {
72 | text-decoration-thickness: 0.2rem;
73 | }
74 |
75 | .article-template__link svg {
76 | width: 1.5rem;
77 | transform: rotate(180deg);
78 | margin-right: 1rem;
79 | }
80 |
81 | .article-template__content {
82 | margin-top: 3rem;
83 | margin-bottom: 3rem;
84 | }
85 |
86 | .article-template__social-sharing {
87 | display: flex;
88 | flex-direction: column;
89 | align-items: self-end;
90 | margin-top: 3rem;
91 | }
92 |
93 | .article-template__social-sharing .social-sharing {
94 | margin-left: -1.3rem;
95 | }
96 |
97 | .article-template__comment-wrapper {
98 | margin-top: 5rem;
99 | }
100 |
101 | @media screen and (min-width: 750px) {
102 | .article-template__comment-wrapper {
103 | margin-top: 6rem;
104 | }
105 | }
106 |
107 | .article-template__comment-wrapper h2 {
108 | margin-top: 0;
109 | }
110 |
111 | .article-template__comments {
112 | margin-bottom: 5rem;
113 | }
114 |
115 | @media screen and (min-width: 750px) {
116 | .article-template__comments {
117 | margin-bottom: 7rem;
118 | }
119 | }
120 |
121 | .article-template__comments-fields {
122 | margin-bottom: 4rem;
123 | }
124 |
125 | .article-template__comments-comment {
126 | color: rgba(var(--color-foreground), 0.75);
127 | background-color: rgb(var(--color-background));
128 | margin-bottom: 1.5rem;
129 | padding: 2rem 2rem 1.5rem;
130 | }
131 |
132 | @media screen and (min-width: 750px) {
133 | .article-template__comments-comment {
134 | padding: 2rem 2.5rem;
135 | }
136 | }
137 |
138 | .article-template__comments-comment p {
139 | margin: 0 0 1rem;
140 | }
141 |
142 | .article-template__comment-fields > * {
143 | margin-bottom: 3rem;
144 | }
145 |
146 | @media screen and (min-width: 750px) {
147 | .article-template__comment-fields {
148 | display: grid;
149 | grid-template-columns: repeat(2, 1fr);
150 | grid-column-gap: 4rem;
151 | }
152 | }
153 |
154 | .article-template__comment-warning {
155 | margin: 2rem 0 2.5rem;
156 | }
157 |
158 | @media screen and (min-width: 990px) {
159 | .article-template__comments .pagination-wrapper {
160 | margin: 5rem 0 8rem;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/assets/section-collection-list.css:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 749px) {
2 | .collage-section + .collection-list-section .no-heading.no-mobile-link {
3 | margin-top: -7rem;
4 | }
5 | .collage-section + .collection-list-section .no-heading:not(.no-mobile-link) {
6 | margin-top: -1rem;
7 | }
8 | }
9 |
10 | @media screen and (min-width: 749px) {
11 | .collage-section + .collection-list-section .no-heading {
12 | margin-top: -4rem;
13 | }
14 | }
15 |
16 | .collection-list-title {
17 | margin: 0;
18 | }
19 |
20 | @media screen and (max-width: 749px) {
21 | .collection-list-wrapper.page-width {
22 | padding: 0;
23 | }
24 |
25 | .collection-list:not(.slider) {
26 | padding-left: 0;
27 | padding-right: 0;
28 | }
29 |
30 | .collection-list-section .collection-list:not(.slider) {
31 | padding-left: 1.5rem;
32 | padding-right: 1.5rem;
33 | }
34 | }
35 |
36 | @media screen and (max-width: 749px) {
37 | .collection-list-wrapper:not(.no-heading) .title-wrapper-with-link {
38 | margin-top: -1rem;
39 | }
40 | }
41 |
42 | @media screen and (min-width: 750px) {
43 | .collection-list-wrapper.no-heading {
44 | margin-top: 6rem;
45 | }
46 | }
47 |
48 | .collection-list__item:only-child {
49 | max-width: 100%;
50 | width: 100%;
51 | }
52 |
53 | .collection-list__item .card--light-border:hover {
54 | border: 0.1rem solid rgba(var(--color-foreground), 0.04);
55 | }
56 |
57 | .collection-list__item:only-child .media {
58 | height: 35rem;
59 | }
60 |
61 | @media screen and (max-width: 749px) {
62 | .collection-list .collection-list__item {
63 | width: calc(100% - 3rem);
64 | }
65 |
66 | .collection-list__item.grid__item {
67 | padding-bottom: 1rem;
68 | }
69 |
70 | .slider.collection-list--1-items {
71 | padding-bottom: 0;
72 | }
73 | }
74 |
75 | .collection-list.negative-margin--small {
76 | margin-bottom: -1rem;
77 | }
78 |
79 | @media screen and (min-width: 750px) and (max-width: 989px) {
80 | .slider.collection-list--1-items,
81 | .slider.collection-list--2-items,
82 | .slider.collection-list--3-items,
83 | .slider.collection-list--4-items {
84 | padding-bottom: 0;
85 | }
86 | }
87 |
88 | @media screen and (min-width: 750px) {
89 | .collection-list__item:only-child > *:not(.card--media) {
90 | height: 320px;
91 | }
92 |
93 | .collection-list__item:only-child .media {
94 | height: 47rem;
95 | }
96 |
97 | .collection-list__item a:hover {
98 | box-shadow: none;
99 | }
100 |
101 | .collection-list.grid--3-col-tablet .grid__item {
102 | max-width: 33.33%;
103 | }
104 |
105 | .collection-list--4-items .grid__item,
106 | .collection-list--7-items .grid__item:nth-child(n + 4),
107 | .collection-list--10-items .grid__item:nth-child(n + 7) {
108 | width: 50%;
109 | }
110 | }
111 |
112 | @media screen and (max-width: 989px) {
113 | .collection-list.slider .collection-list__item {
114 | max-width: 100%;
115 | }
116 | }
117 |
118 | .collection-list__item .card__text,
119 | .collection-list__item .card-colored {
120 | position: relative;
121 | }
122 |
--------------------------------------------------------------------------------
/src/assets/section-contact-form.css:
--------------------------------------------------------------------------------
1 | .contact img {
2 | max-width: 100%;
3 | }
4 |
5 | .contact .form__message {
6 | align-items: flex-start;
7 | }
8 |
9 | .contact .icon-success {
10 | margin-top: 0.2rem;
11 | }
12 |
13 | .contact .field {
14 | margin-bottom: 1.5rem;
15 | }
16 |
17 | @media screen and (min-width: 750px) {
18 | .contact .field {
19 | margin-bottom: 2rem;
20 | }
21 | }
22 |
23 | .contact__button {
24 | margin-top: 3rem;
25 | }
26 |
27 | @media screen and (min-width: 750px) {
28 | .contact__button {
29 | margin-top: 4rem;
30 | }
31 | }
32 |
33 | @media screen and (min-width: 750px) {
34 | .contact__fields {
35 | display: grid;
36 | grid-template-columns: repeat(2, 1fr);
37 | grid-column-gap: 2rem;
38 | }
39 | }
40 |
41 | .grecaptcha-badge {
42 | visibility: hidden;
43 | }
44 |
--------------------------------------------------------------------------------
/src/assets/section-featured-blog.css:
--------------------------------------------------------------------------------
1 | .blog:not(.background-secondary) {
2 | margin: 5rem 0;
3 | }
4 |
5 | .blog.background-secondary {
6 | padding: 4rem 0 5rem;
7 | }
8 |
9 | .blog .placeholder {
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | height: 22rem;
14 | text-align: center;
15 | padding: 4rem 2rem 5rem;
16 | margin: 0 2rem;
17 | }
18 |
19 | @media screen and (min-width: 750px) {
20 | .blog .placeholder {
21 | margin: 0;
22 | }
23 | }
24 |
25 | @media screen and (max-width: 749px) {
26 | .blog:not(.no-heading) {
27 | margin-top: -1rem;
28 | }
29 | }
30 |
31 | @media screen and (min-width: 750px) {
32 | .blog.no-heading {
33 | margin-top: 6rem;
34 | }
35 | }
36 |
37 | .background-secondary .title-wrapper-with-link {
38 | margin-top: 0;
39 | }
40 |
41 | .blog__title {
42 | margin: 0;
43 | }
44 |
45 | .blog__posts.articles-wrapper {
46 | margin-bottom: 0;
47 | }
48 |
49 | @media screen and (min-width: 750px) {
50 | .blog__post:only-child {
51 | text-align: center;
52 | }
53 | }
54 |
55 | @media screen and (min-width: 990px) {
56 | .blog__posts.articles-wrapper {
57 | padding-bottom: 0;
58 | }
59 | }
60 |
61 | .blog__posts.articles-wrapper .article {
62 | scroll-snap-align: start;
63 | }
64 |
65 | @media screen and (min-width: 750px) {
66 | .blog__posts .article + .article {
67 | margin-left: 1rem;
68 | }
69 | }
70 |
71 | @media screen and (max-width: 749px) {
72 | .blog__post.article {
73 | width: calc(100% - 3rem);
74 | padding-left: 0.5rem;
75 | }
76 | }
77 |
78 | .background-secondary .article-card {
79 | background-color: rgb(var(--color-background));
80 | }
81 |
82 | .blog__button {
83 | margin-top: 3rem;
84 | }
85 |
86 | @media screen and (min-width: 750px) {
87 | .blog__button {
88 | margin-top: 5rem;
89 | }
90 | }
91 |
92 | @media screen and (max-width: 749px) {
93 | .slider.blog__posts--1-items {
94 | padding-bottom: 0;
95 | }
96 | }
97 |
98 | @media screen and (min-width: 750px) and (max-width: 989px) {
99 | .slider.blog__posts--1-items,
100 | .slider.blog__posts--2-items {
101 | padding-bottom: 0;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/assets/section-image-banner.css:
--------------------------------------------------------------------------------
1 | .banner {
2 | display: flex;
3 | position: relative;
4 | flex-direction: column;
5 | min-height: initial;
6 | }
7 |
8 | @media screen and (max-width: 749px) {
9 | .banner:not(.banner--stacked) {
10 | flex-direction: row;
11 | flex-wrap: wrap;
12 | }
13 | }
14 |
15 | @media screen and (min-width: 750px) {
16 | .banner {
17 | min-height: 72rem;
18 | flex-direction: row;
19 | }
20 | }
21 |
22 | @media screen and (max-width: 749px) {
23 | .banner--stacked {
24 | height: auto;
25 | }
26 |
27 | .banner--stacked .banner__media {
28 | flex-direction: column;
29 | }
30 | }
31 |
32 | .banner__media {
33 | height: 100%;
34 | left: 0;
35 | top: 0;
36 | width: 100%;
37 | position: relative;
38 | }
39 |
40 | .banner__media-half {
41 | width: 50%;
42 | }
43 |
44 | .banner__media-half + .banner__media-half {
45 | right: 0;
46 | left: auto;
47 | }
48 |
49 | @media screen and (max-width: 749px) {
50 | .banner--stacked .banner__media-half {
51 | width: 100%;
52 | }
53 |
54 | .banner--stacked .banner__media-half + .banner__media-half {
55 | order: 1;
56 | }
57 |
58 | .banner:not(.banner--adapt):not(.banner--stacked) > .banner__media {
59 | height: 39rem;
60 | }
61 | }
62 |
63 | @media screen and (min-width: 750px) {
64 | .banner__media {
65 | position: absolute;
66 | height: 100%;
67 | }
68 | }
69 |
70 | .banner--adapt {
71 | height: auto;
72 | }
73 |
74 | @media screen and (max-width: 749px) {
75 | .banner--stacked:not(.banner--adapt) .banner__media {
76 | height: 39rem;
77 | }
78 |
79 | .banner::before {
80 | display: none !important;
81 | }
82 |
83 | .banner--stacked .banner__media-image-half {
84 | width: 100%;
85 | }
86 | }
87 |
88 | .banner__media .placeholder-svg {
89 | position: absolute;
90 | left: 0;
91 | top: 0;
92 | height: 100%;
93 | width: 100%;
94 | }
95 |
96 | .banner__content {
97 | padding: 0;
98 | display: flex;
99 | position: relative;
100 | width: 100%;
101 | justify-content: center;
102 | }
103 |
104 | @media screen and (min-width: 750px) {
105 | .banner__content {
106 | padding-bottom: 5rem;
107 | padding-top: 5rem;
108 | }
109 | }
110 |
111 | .banner__box {
112 | border: 0;
113 | padding: 4rem 3.5rem;
114 | position: relative;
115 | height: fit-content;
116 | align-items: center;
117 | text-align: center;
118 | width: 100%;
119 | }
120 |
121 | .banner__box > * + .banner__buttons {
122 | margin: 0 auto;
123 | margin-top: 2.3rem;
124 | transform: translateX(1rem);
125 | }
126 |
127 | .banner__box > * + .banner__buttons--multiple {
128 | display: flex;
129 | max-width: 45rem;
130 | flex-wrap: wrap;
131 | align-items: baseline;
132 | justify-content: center;
133 | }
134 |
135 | @media screen and (min-width: 750px) {
136 | .banner__box > * + .banner__buttons {
137 | margin-top: 2rem;
138 | }
139 | }
140 |
141 | .banner__content .button + .button {
142 | margin-top: 1.5rem;
143 | }
144 |
145 | .banner__content .button {
146 | height: auto;
147 | margin-right: 2rem;
148 | }
149 |
150 | .banner__box > * + .banner__text {
151 | margin-top: 1.5rem;
152 | }
153 |
154 | @media screen and (min-width: 750px) {
155 | .banner__box > * + .banner__text {
156 | margin-top: 2rem;
157 | }
158 | }
159 |
160 | .banner__box > * + * {
161 | margin-top: 1rem;
162 | }
163 |
164 | .banner__box > *:first-child {
165 | margin-top: 0;
166 | }
167 |
168 | @media screen and (max-width: 749px) {
169 | .banner__content .button {
170 | flex-grow: 1;
171 | }
172 |
173 | .banner--stacked .banner__box {
174 | width: 100%;
175 | }
176 | }
177 |
178 | @media screen and (min-width: 750px) {
179 | .banner__box {
180 | padding: 4rem;
181 | width: 54.8rem;
182 | }
183 |
184 | .banner__box > .banner__buttons:only-child .button {
185 | margin-top: 0;
186 | }
187 | }
188 |
189 | .banner__heading > *,
190 | .banner__text > * {
191 | word-wrap: break-word;
192 | }
193 |
194 | .banner__heading {
195 | margin-bottom: 0;
196 | }
197 |
--------------------------------------------------------------------------------
/src/assets/section-main-blog.css:
--------------------------------------------------------------------------------
1 | .blog-articles {
2 | display: grid;
3 | grid-gap: 1rem;
4 | }
5 |
6 | @media screen and (min-width: 750px) {
7 | .blog-articles {
8 | grid-template-columns: 1fr 1fr;
9 | }
10 |
11 | .blog-articles > *:first-child,
12 | .blog-articles > *:nth-child(4),
13 | .blog-articles > *:last-child:nth-child(2),
14 | .blog-articles > *:last-child:nth-child(5) {
15 | grid-column: span 2;
16 | text-align: center;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/assets/section-main-page.css:
--------------------------------------------------------------------------------
1 | .page-title {
2 | margin-top: 0;
3 | }
4 |
5 | .main-page-title {
6 | margin-bottom: 3rem;
7 | }
8 |
9 | @media screen and (min-width: 750px) {
10 | .main-page-title {
11 | margin-bottom: 4rem;
12 | }
13 | }
14 |
15 | .page-placeholder-wrapper {
16 | display: flex;
17 | justify-content: center;
18 | }
19 |
20 | .page-placeholder {
21 | width: 52.5rem;
22 | height: 52.5rem;
23 | }
24 |
--------------------------------------------------------------------------------
/src/assets/section-multicolumn.css:
--------------------------------------------------------------------------------
1 | .multicolumn .title {
2 | margin: 0;
3 | }
4 |
5 | .multicolumn.no-heading .title {
6 | display: none;
7 | }
8 |
9 | @media screen and (max-width: 749px) {
10 | .multicolumn.no-heading.background-secondary {
11 | padding-top: 5rem;
12 | }
13 | }
14 |
15 | @media screen and (min-width: 750px) {
16 | .multicolumn.no-heading:not(.background-secondary) {
17 | margin-top: 6rem;
18 | }
19 | }
20 |
21 | .multicolumn.background-secondary .title-wrapper-with-link {
22 | margin-top: 0;
23 | }
24 |
25 | @media screen and (max-width: 749px) {
26 | .multicolumn .title-wrapper-with-link {
27 | margin-bottom: 3rem;
28 | }
29 | }
30 |
31 | .multicolumn-card__image-wrapper--third-width {
32 | width: 33%;
33 | }
34 |
35 | .multicolumn-card__image-wrapper--half-width {
36 | width: 50%;
37 | }
38 |
39 | .multicolumn-list__item.center
40 | .multicolumn-card__image-wrapper:not(.multicolumn-card__image-wrapper--full-width),
41 | .multicolumn-list__item:only-child {
42 | margin-left: auto;
43 | margin-right: auto;
44 | }
45 |
46 | .multicolumn .button {
47 | margin-top: 1.5rem;
48 | }
49 |
50 | @media screen and (min-width: 750px) {
51 | .multicolumn .button {
52 | margin-top: 4rem;
53 | }
54 | }
55 |
56 | .multicolumn-list {
57 | margin-bottom: 0;
58 | padding: 0;
59 | }
60 |
61 | .multicolumn-list__item:only-child {
62 | max-width: 72rem;
63 | }
64 |
65 | .multicolumn:not(.background-none) .multicolumn-card {
66 | background: rgba(var(--color-foreground), 0.04);
67 | height: 100%;
68 | }
69 |
70 | .multicolumn.background-secondary .multicolumn-card {
71 | background: rgb(var(--color-background));
72 | }
73 |
74 | .multicolumn.background-secondary {
75 | padding: 4rem 0 5rem;
76 | }
77 |
78 | .multicolumn:not(.background-secondary) {
79 | margin: 5rem 0;
80 | }
81 |
82 | .multicolumn-list h3,
83 | .multicolumn-list p {
84 | margin: 0;
85 | }
86 |
87 | .multicolumn-card-spacing {
88 | padding-top: 2.5rem;
89 | margin-left: 2.5rem;
90 | margin-right: 2.5rem;
91 | }
92 |
93 | .multicolumn-card__info > :nth-child(2) {
94 | margin-top: 1rem;
95 | }
96 |
97 | .multicolumn-list__item.center .media--adapt,
98 | .multicolumn-list__item .media--adapt img {
99 | width: auto;
100 | }
101 |
102 | .multicolumn-list__item.center .media--adapt img {
103 | left: 50%;
104 | transform: translateX(-50%);
105 | }
106 |
107 | @media screen and (max-width: 749px) {
108 | .multicolumn .page-width {
109 | padding: 0;
110 | }
111 |
112 | .multicolumn-list {
113 | margin: 0;
114 | width: 100%;
115 | }
116 |
117 | .multicolumn-list__item {
118 | margin: 0 0 1rem;
119 | padding: 0;
120 | }
121 |
122 | .multicolumn-list:not(.slider) {
123 | padding-left: 1.5rem;
124 | padding-right: 1.5rem;
125 | }
126 |
127 | .multicolumn-list.slider .multicolumn-list__item {
128 | width: calc(100% - 3rem);
129 | }
130 |
131 | .multicolumn-list.slider .multicolumn-list__item + .multicolumn-list__item {
132 | padding-left: 0.5rem;
133 | }
134 | }
135 |
136 | @media screen and (min-width: 750px) {
137 | .multicolumn-list.slider,
138 | .multicolumn-list.grid--4-col-desktop {
139 | padding: 0;
140 | }
141 |
142 | .multicolumn-list__item,
143 | .grid--4-col-desktop .multicolumn-list__item {
144 | padding-bottom: 0;
145 | }
146 |
147 | .grid--2-col-tablet .multicolumn-list__item {
148 | margin-top: 1rem;
149 | max-width: 50%;
150 | }
151 |
152 | .background-none .grid--2-col-tablet .multicolumn-list__item {
153 | margin-top: 4rem;
154 | }
155 |
156 | .grid--2-col-tablet .multicolumn-list__item:nth-of-type(-n + 2) {
157 | margin-top: 0;
158 | }
159 | }
160 |
161 | @media screen and (min-width: 990px) {
162 | .grid--2-col-tablet.grid--4-col-desktop .multicolumn-list__item {
163 | max-width: 25%;
164 | }
165 |
166 | .grid--2-col-tablet.grid--4-col-desktop
167 | .multicolumn-list__item:nth-of-type(-n + 4) {
168 | margin-top: 0;
169 | }
170 | }
171 |
172 | .background-none .multicolumn-card-spacing {
173 | padding: 0;
174 | margin: 0;
175 | }
176 |
177 | .multicolumn-card__info {
178 | padding: 2.5rem 2.5rem;
179 | }
180 |
181 | .background-none .multicolumn-card__info {
182 | padding-top: 0;
183 | padding-left: 0;
184 | padding-right: 0;
185 | }
186 |
187 | .background-none .multicolumn-card__image-wrapper + .multicolumn-card__info {
188 | padding-top: 2.5rem;
189 | }
190 |
191 | .background-none .slider .multicolumn-card__info {
192 | padding-left: 0.5rem;
193 | }
194 |
195 | .background-none
196 | .slider
197 | .multicolumn-card__image-wrapper
198 | + .multicolumn-card__info {
199 | padding-left: 1.5rem;
200 | }
201 |
202 | .background-none
203 | .multicolumn-list:not(.slider)
204 | .center
205 | .multicolumn-card__info {
206 | padding-left: 2.5rem;
207 | padding-right: 2.5rem;
208 | }
209 |
210 | @media screen and (min-width: 750px) {
211 | .background-none .multicolumn-card__image-wrapper {
212 | margin-left: 1.5rem;
213 | margin-right: 1.5rem;
214 | }
215 |
216 | .background-none .multicolumn-list .multicolumn-card__info,
217 | .background-none
218 | .multicolumn-list:not(.slider)
219 | .center
220 | .multicolumn-card__info {
221 | padding-left: 1.5rem;
222 | padding-right: 1.5rem;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/src/assets/section-product-recommendations.css:
--------------------------------------------------------------------------------
1 | .product-recommendations {
2 | display: block;
3 | }
4 |
5 | .product-recommendations__heading {
6 | margin: 0;
7 | margin-bottom: 3rem;
8 | }
9 |
10 | .product-recommendations .grid__item {
11 | padding-bottom: 0;
12 | }
13 |
--------------------------------------------------------------------------------
/src/assets/section-rich-text.css:
--------------------------------------------------------------------------------
1 | .rich-text {
2 | margin: auto;
3 | max-width: 110rem;
4 | text-align: center;
5 | /* 1.5rem margin on left & right */
6 | width: calc(100% - 3rem);
7 | }
8 |
9 | .rich-text.rich-text--full-width {
10 | max-width: initial;
11 | width: 100%;
12 | }
13 |
14 | .rich-text__blocks {
15 | margin: auto;
16 | /* 2.5rem margin on left & right */
17 | width: calc(100% - 5rem);
18 | }
19 |
20 | .rich-text__blocks * {
21 | overflow-wrap: break-word;
22 | }
23 |
24 | .rich-text--full-width .rich-text__blocks {
25 | /* 4rem (1.5rem + 2.5rem) margin on left & right */
26 | width: calc(100% - 8rem);
27 | }
28 |
29 | .rich-text:not(.rich-text--full-width),
30 | .rich-text--full-width.color-background-1 {
31 | margin-top: 5rem;
32 | margin-bottom: 5rem;
33 | }
34 |
35 | .rich-text:not(.color-background-1) {
36 | padding-top: 5rem;
37 | padding-bottom: 5rem;
38 | }
39 |
40 | @media screen and (min-width: 750px) {
41 | .rich-text {
42 | /* 5rem margin on left & right */
43 | width: calc(100% - 10rem);
44 | }
45 |
46 | .rich-text__blocks {
47 | max-width: 50rem;
48 | }
49 |
50 | .rich-text--full-width .rich-text__blocks {
51 | /* 7.5rem (5rem + 2.5rem) margin on left & right */
52 | width: calc(100% - 15rem);
53 | }
54 | }
55 |
56 | @media screen and (min-width: 990px) {
57 | .rich-text__blocks {
58 | max-width: 78rem;
59 | }
60 | }
61 |
62 | /* Blocks */
63 |
64 | .rich-text__blocks > * {
65 | margin-top: 0;
66 | margin-bottom: 0;
67 | }
68 |
69 | .rich-text__blocks > * + * {
70 | margin-top: 2rem;
71 | }
72 |
73 | .rich-text__blocks > * + a {
74 | margin-top: 3rem;
75 | }
76 |
--------------------------------------------------------------------------------
/src/assets/share.js:
--------------------------------------------------------------------------------
1 | class ShareButton extends DetailsDisclosure {
2 | constructor() {
3 | super();
4 |
5 | this.elements = {
6 | shareButton: this.querySelector('button'),
7 | successMessage: this.querySelector('[id^="ShareMessage"]'),
8 | urlInput: this.querySelector('input')
9 | }
10 | if (navigator.share) {
11 | this.mainDetailsToggle.setAttribute('hidden', '');
12 | this.elements.shareButton.classList.remove('hidden');
13 | this.elements.shareButton.addEventListener('click', () => { navigator.share({ url: document.location.href, title: document.title }) });
14 | } else {
15 | this.mainDetailsToggle.addEventListener('toggle', this.toggleDetails.bind(this));
16 | this.mainDetailsToggle.querySelector('button').addEventListener('click', this.copyToClipboard.bind(this));
17 | }
18 | }
19 |
20 | toggleDetails() {
21 | if (!this.mainDetailsToggle.open)
22 | this.elements.successMessage.classList.add('hidden');
23 | }
24 |
25 | copyToClipboard() {
26 | navigator.clipboard.writeText(this.elements.urlInput.value).then(() => {
27 | this.elements.successMessage.classList.remove('hidden');
28 | this.elements.successMessage.setAttribute('aria-hidden', false);
29 |
30 | setTimeout(() => {
31 | this.elements.successMessage.setAttribute('aria-hidden', true);
32 | }, 6000);
33 | });
34 | }
35 | }
36 |
37 | customElements.define('share-button', ShareButton);
38 |
--------------------------------------------------------------------------------
/src/assets/slider.js:
--------------------------------------------------------------------------------
1 | class SliderComponent extends HTMLElement {
2 | constructor() {
3 | super();
4 | this.slider = this.querySelector('ul');
5 | this.sliderItems = this.querySelectorAll('li');
6 | this.pageCount = this.querySelector('.slider-counter--current');
7 | this.pageTotal = this.querySelector('.slider-counter--total');
8 | this.prevButton = this.querySelector('button[name="previous"]');
9 | this.nextButton = this.querySelector('button[name="next"]');
10 |
11 | if (!this.slider || !this.nextButton) return;
12 |
13 | const resizeObserver = new ResizeObserver(entries => this.initPages());
14 | resizeObserver.observe(this.slider);
15 |
16 | this.slider.addEventListener('scroll', this.update.bind(this));
17 | this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
18 | this.nextButton.addEventListener('click', this.onButtonClick.bind(this));
19 | }
20 |
21 | initPages() {
22 | if (!this.sliderItems.length === 0) return;
23 | this.slidesPerPage = Math.floor(this.slider.clientWidth / this.sliderItems[0].clientWidth);
24 | this.totalPages = this.sliderItems.length - this.slidesPerPage + 1;
25 | this.update();
26 | }
27 |
28 | update() {
29 | if (!this.pageCount || !this.pageTotal) return;
30 | this.currentPage = Math.round(this.slider.scrollLeft / this.sliderItems[0].clientWidth) + 1;
31 |
32 | if (this.currentPage === 1) {
33 | this.prevButton.setAttribute('disabled', true);
34 | } else {
35 | this.prevButton.removeAttribute('disabled');
36 | }
37 |
38 | if (this.currentPage === this.totalPages) {
39 | this.nextButton.setAttribute('disabled', true);
40 | } else {
41 | this.nextButton.removeAttribute('disabled');
42 | }
43 |
44 | this.pageCount.textContent = this.currentPage;
45 | this.pageTotal.textContent = this.totalPages;
46 | }
47 |
48 | onButtonClick(event) {
49 | event.preventDefault();
50 | const slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + this.sliderItems[0].clientWidth : this.slider.scrollLeft - this.sliderItems[0].clientWidth;
51 | this.slider.scrollTo({
52 | left: slideScrollPosition
53 | });
54 | }
55 | }
56 |
57 | customElements.define('slider-component', SliderComponent);
58 |
--------------------------------------------------------------------------------
/src/assets/variants.js:
--------------------------------------------------------------------------------
1 | class VariantSelects extends HTMLElement {
2 | constructor() {
3 | super();
4 | this.addEventListener('change', this.onVariantChange);
5 | }
6 |
7 | onVariantChange() {
8 | this.updateOptions();
9 | this.updateMasterId();
10 | this.toggleAddButton(true, '', false);
11 | this.updatePickupAvailability();
12 |
13 | if (!this.currentVariant) {
14 | this.toggleAddButton(true, '', true);
15 | this.setUnavailable();
16 | } else {
17 | this.updateMedia();
18 | this.updateURL();
19 | this.updateVariantInput();
20 | this.renderProductInfo();
21 | }
22 | }
23 |
24 | updateOptions() {
25 | this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
26 | }
27 |
28 | updateMasterId() {
29 | this.currentVariant = this.getVariantData().find((variant) => {
30 | return !variant.options.map((option, index) => {
31 | return this.options[index] === option;
32 | }).includes(false);
33 | });
34 | }
35 |
36 | updateMedia() {
37 | if (!this.currentVariant || !this.currentVariant?.featured_media) return;
38 | const newMedia = document.querySelector(
39 | `[data-media-id="${this.dataset.section}-${this.currentVariant.featured_media.id}"]`
40 | );
41 | if (!newMedia) return;
42 | const parent = newMedia.parentElement;
43 | parent.prepend(newMedia);
44 | window.setTimeout(() => { parent.scroll(0, 0) });
45 | }
46 |
47 | updateURL() {
48 | if (!this.currentVariant) return;
49 | window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
50 | }
51 |
52 | updateVariantInput() {
53 | const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
54 | productForms.forEach((productForm) => {
55 | const input = productForm.querySelector('input[name="id"]');
56 | input.value = this.currentVariant.id;
57 | input.dispatchEvent(new Event('change', { bubbles: true }));
58 | });
59 | }
60 |
61 | updatePickupAvailability() {
62 | const pickUpAvailability = document.querySelector('pickup-availability');
63 | if (!pickUpAvailability) return;
64 |
65 | if (this.currentVariant?.available) {
66 | pickUpAvailability.fetchAvailability(this.currentVariant.id);
67 | } else {
68 | pickUpAvailability.removeAttribute('available');
69 | pickUpAvailability.innerHTML = '';
70 | }
71 | }
72 |
73 | renderProductInfo() {
74 | fetch(`${this.dataset.url}?variant=${this.currentVariant.id}§ion_id=${this.dataset.section}`)
75 | .then((response) => response.text())
76 | .then((responseText) => {
77 | const id = `price-${this.dataset.section}`;
78 | const html = new DOMParser().parseFromString(responseText, 'text/html')
79 | const destination = document.getElementById(id);
80 | const source = html.getElementById(id);
81 |
82 | if (source && destination) destination.innerHTML = source.innerHTML;
83 |
84 | document.getElementById(`price-${this.dataset.section}`)?.classList.remove('visibility-hidden');
85 | this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
86 | });
87 | }
88 |
89 | toggleAddButton(disable = true, text, modifyClass = true) {
90 | const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
91 |
92 | if (!addButton) return;
93 |
94 | if (disable) {
95 | addButton.setAttribute('disabled', true);
96 | if (text) addButton.textContent = text;
97 | } else {
98 | addButton.removeAttribute('disabled');
99 | addButton.textContent = window.variantStrings.addToCart;
100 | }
101 |
102 | if (!modifyClass) return;
103 | }
104 |
105 | setUnavailable() {
106 | const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
107 | if (!addButton) return;
108 | addButton.textContent = window.variantStrings.unavailable;
109 | document.getElementById(`price-${this.dataset.section}`)?.classList.add('visibility-hidden');
110 | }
111 |
112 | getVariantData() {
113 | this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
114 | return this.variantData;
115 | }
116 | }
117 |
118 | customElements.define('variant-selects', VariantSelects);
119 |
120 | class VariantRadios extends VariantSelects {
121 | constructor() {
122 | super();
123 | }
124 |
125 | updateOptions() {
126 | const fieldsets = Array.from(this.querySelectorAll('fieldset'));
127 | this.options = fieldsets.map((fieldset) => {
128 | return Array.from(fieldset.querySelectorAll('input')).find((radio) => radio.checked).value;
129 | });
130 | }
131 | }
132 |
133 | customElements.define('variant-radios', VariantRadios);
134 |
--------------------------------------------------------------------------------
/src/config/settings_data.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/src/layout/password.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {%- if settings.favicon != blank -%}
12 |
13 | {%- endif -%}
14 |
15 | {%- unless settings.type_header_font.system? -%}
16 |
17 | {%- endunless -%}
18 |
19 | {{ shop.name }}
20 |
21 |
22 |
23 | {% render 'meta-tags' %}
24 |
25 | {{ content_for_header }}
26 |
27 | {%- liquid
28 | assign body_font_bold = settings.type_body_font | font_modify: 'weight', 'bold'
29 | assign body_font_italic = settings.type_body_font | font_modify: 'style', 'italic'
30 | assign body_font_bold_italic = body_font_bold | font_modify: 'style', 'italic'
31 | %}
32 |
33 | {% style %}
34 | {{ settings.type_body_font | font_face: font_display: 'swap' }}
35 | {{ body_font_bold | font_face: font_display: 'swap' }}
36 | {{ body_font_italic | font_face: font_display: 'swap' }}
37 | {{ body_font_bold_italic | font_face: font_display: 'swap' }}
38 | {{ settings.type_header_font | font_face: font_display: 'swap' }}
39 |
40 | :root {
41 | --font-body-family: {{ settings.type_body_font.family }}, {{ settings.type_body_font.fallback_families }};
42 | --font-body-style: {{ settings.type_body_font.style }};
43 | --font-body-weight: {{ settings.type_body_font.weight }};
44 |
45 | --font-heading-family: {{ settings.type_header_font.family }}, {{ settings.type_header_font.fallback_families }};
46 | --font-heading-style: {{ settings.type_header_font.style }};
47 | --font-heading-weight: {{ settings.type_header_font.weight }};
48 |
49 | --color-base-text: {{ settings.colors_text.red }}, {{ settings.colors_text.green }}, {{ settings.colors_text.blue }};
50 | --color-base-background-1: {{ settings.colors_background_1.red }}, {{ settings.colors_background_1.green }}, {{ settings.colors_background_1.blue }};
51 | --color-base-background-2: {{ settings.colors_background_2.red }}, {{ settings.colors_background_2.green }}, {{ settings.colors_background_2.blue }};
52 | --color-base-solid-button-labels: {{ settings.colors_solid_button_labels.red }}, {{ settings.colors_solid_button_labels.green }}, {{ settings.colors_solid_button_labels.blue }};
53 | --color-base-outline-button-labels: {{ settings.colors_outline_button_labels.red }}, {{ settings.colors_outline_button_labels.green }}, {{ settings.colors_outline_button_labels.blue }};
54 | --color-base-accent-1: {{ settings.colors_accent_1.red }}, {{ settings.colors_accent_1.green }}, {{ settings.colors_accent_1.blue }};
55 | --color-base-accent-2: {{ settings.colors_accent_2.red }}, {{ settings.colors_accent_2.green }}, {{ settings.colors_accent_2.blue }};
56 | --payment-terms-background-color: {{ settings.colors_background_1 }};
57 | }
58 | {% endstyle %}
59 |
60 | {%- unless settings.type_body_font.system? -%}
61 |
62 | {%- endunless -%}
63 | {%- unless settings.type_header_font.system? -%}
64 |
65 | {%- endunless -%}
66 |
67 | {{ 'section-password.css' | asset_url | stylesheet_tag }}
68 | {{ 'base.css' | asset_url | stylesheet_tag }}
69 | {{ 'component-list-social.css' | asset_url | stylesheet_tag }}
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | {{ 'accessibility.skip_to_text' | t }}
80 |
81 |
82 | {% section 'main-password-header' %}
83 |
84 |
85 | {{ content_for_layout }}
86 |
87 |
88 | {% section 'main-password-footer' %}
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/src/scripts/sections/header.js:
--------------------------------------------------------------------------------
1 | import confetti from 'canvas-confetti';
2 |
3 | console.log('section - scripts/sections/header.js');
4 |
5 | confetti();
--------------------------------------------------------------------------------
/src/scripts/sections/image-banner.js:
--------------------------------------------------------------------------------
1 | console.log('section - scripts/sections/image-banner.js');
--------------------------------------------------------------------------------
/src/scripts/theme.js:
--------------------------------------------------------------------------------
1 | import {sum, prod} from './utils/operations.js';
2 | const A = 4;
3 | const B = 5;
4 |
5 | console.log(sum(A, B));
6 | const bar = ['a', 'b', 'c'];
7 |
8 | console.log('bar', bar);
9 | console.log('scripts/theme.js');
--------------------------------------------------------------------------------
/src/scripts/utils/operations.js:
--------------------------------------------------------------------------------
1 | const sum = (a, b) => {
2 | return a + b;
3 | };
4 | const prod = (a, b) => {
5 | return a * b;
6 | };
7 | export {sum, prod};
8 |
--------------------------------------------------------------------------------
/src/sections/announcement-bar.liquid:
--------------------------------------------------------------------------------
1 | {%- for block in section.blocks -%}
2 | {%- case block.type -%}
3 | {%- when 'announcement' -%}
4 |
20 | {%- endcase -%}
21 | {%- endfor -%}
22 |
23 | {% schema %}
24 | {
25 | "name": "t:sections.announcement-bar.name",
26 | "max_blocks": 12,
27 | "blocks": [
28 | {
29 | "type": "announcement",
30 | "name": "t:sections.announcement-bar.blocks.announcement.name",
31 | "settings": [
32 | {
33 | "type": "text",
34 | "id": "text",
35 | "default": "Welcome to our store",
36 | "label": "t:sections.announcement-bar.blocks.announcement.settings.text.label"
37 | },
38 | {
39 | "type": "select",
40 | "id": "color_scheme",
41 | "options": [
42 | {
43 | "value": "background-1",
44 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.options__1.label"
45 | },
46 | {
47 | "value": "background-2",
48 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.options__2.label"
49 | },
50 | {
51 | "value": "inverse",
52 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.options__3.label"
53 | },
54 | {
55 | "value": "accent-1",
56 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.options__4.label"
57 | },
58 | {
59 | "value": "accent-2",
60 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.options__5.label"
61 | }
62 | ],
63 | "default": "accent-1",
64 | "label": "t:sections.announcement-bar.blocks.announcement.settings.color_scheme.label"
65 | },
66 | {
67 | "type": "url",
68 | "id": "link",
69 | "label": "t:sections.announcement-bar.blocks.announcement.settings.link.label"
70 | }
71 | ]
72 | }
73 | ],
74 | "default": {
75 | "blocks": [
76 | {
77 | "type": "announcement"
78 | }
79 | ]
80 | }
81 | }
82 | {% endschema %}
83 |
--------------------------------------------------------------------------------
/src/sections/apps.liquid:
--------------------------------------------------------------------------------
1 |
2 | {%- for block in section.blocks -%}
3 | {% render block %}
4 | {%- endfor -%}
5 |
6 |
7 | {% schema %}
8 | {
9 | "name": "t:sections.apps.name",
10 | "tag": "section",
11 | "class": "spaced-section",
12 | "settings": [
13 | {
14 | "type": "checkbox",
15 | "id": "include_margins",
16 | "default": true,
17 | "label": "t:sections.apps.settings.include_margins.label"
18 | }
19 | ],
20 | "blocks": [
21 | {
22 | "type": "@app"
23 | }
24 | ],
25 | "presets": [
26 | {
27 | "name": "t:sections.apps.presets.name"
28 | }
29 | ]
30 | }
31 | {% endschema %}
32 |
--------------------------------------------------------------------------------
/src/sections/cart-icon-bubble.liquid:
--------------------------------------------------------------------------------
1 | {%- liquid
2 | if cart == empty
3 | render 'icon-cart-empty'
4 | else
5 | render 'icon-cart'
6 | endif
7 | -%}
8 | {{ 'templates.cart.cart' | t }}
9 | {%- if cart != empty -%}
10 |
11 | {%- if cart.item_count < 100 -%}
12 | {{ cart.item_count }}
13 | {%- endif -%}
14 | {{ 'sections.header.cart_count' | t: count: cart.item_count }}
15 |
16 | {%- endif -%}
17 |
--------------------------------------------------------------------------------
/src/sections/cart-live-region-text.liquid:
--------------------------------------------------------------------------------
1 | {{ 'sections.cart.new_subtotal' | t }}: {{ cart.total_price | money_with_currency }}
2 |
--------------------------------------------------------------------------------
/src/sections/cart-notification-button.liquid:
--------------------------------------------------------------------------------
1 | {{ 'general.cart.view' | t: count: cart.item_count }}
2 |
--------------------------------------------------------------------------------
/src/sections/cart-notification-product.liquid:
--------------------------------------------------------------------------------
1 | {%- if cart != empty -%}
2 | {%- for item in cart.items -%}
3 |
4 | {% if item.image %}
5 |
12 | {% endif %}
13 |
14 |
{{ item.product.title | escape }}
15 | {%- unless item.product.has_only_default_variant -%}
16 |
17 | {%- for option in item.options_with_values -%}
18 |
19 |
{{ option.name }}:
20 | {{ option.value }}
21 |
22 | {%- endfor -%}
23 |
24 | {%- endunless -%}
25 |
26 |
27 | {%- endfor -%}
28 | {%- endif -%}
29 |
--------------------------------------------------------------------------------
/src/sections/contact-form.liquid:
--------------------------------------------------------------------------------
1 | {{ 'section-contact-form.css' | asset_url | stylesheet_tag }}
2 |
3 |
4 |
{{ section.settings.heading | escape }}
5 | {%- form 'contact', id: 'ContactForm' -%}
6 | {%- if form.posted_successfully? -%}
7 |
{% render 'icon-success' %} {{ 'templates.contact.form.post_success' | t }}
8 | {%- elsif form.errors -%}
9 |
10 |
11 |
12 |
19 | {%- endif -%}
20 |
51 |
52 |
53 | {{ 'templates.contact.form.phone' | t }}
54 |
55 |
56 |
65 | {{ 'templates.contact.form.comment' | t }}
66 |
67 |
68 |
69 | {{ 'templates.contact.form.send' | t }}
70 |
71 |
72 | {%- endform -%}
73 |
74 |
75 | {% schema %}
76 | {
77 | "name": "t:sections.contact-form.name",
78 | "tag": "section",
79 | "class": "spaced-section",
80 | "settings": [
81 | {
82 | "type": "text",
83 | "id": "heading",
84 | "default": "Contact form",
85 | "label": "Heading"
86 | }
87 | ],
88 | "presets": [
89 | {
90 | "name": "t:sections.contact-form.presets.name"
91 | }
92 | ]
93 | }
94 | {% endschema %}
95 |
--------------------------------------------------------------------------------
/src/sections/custom-liquid.liquid:
--------------------------------------------------------------------------------
1 | {{ section.settings.custom_liquid }}
2 |
3 | {% schema %}
4 | {
5 | "name": "t:sections.custom-liquid.name",
6 | "tag": "section",
7 | "class": "spaced-section",
8 | "settings": [
9 | {
10 | "type": "liquid",
11 | "id": "custom_liquid",
12 | "label": "t:sections.custom-liquid.settings.custom_liquid.label"
13 | }
14 | ],
15 | "presets": [
16 | {
17 | "name": "t:sections.custom-liquid.presets.name"
18 | }
19 | ]
20 | }
21 | {% endschema %}
22 |
--------------------------------------------------------------------------------
/src/sections/main-404.liquid:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 | {{ 'templates.404.subtext' | t }}
16 |
17 |
18 | {{ 'templates.404.title' | t }}
19 |
20 |
21 | {{ 'general.continue_shopping' | t }}
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/sections/main-blog.liquid:
--------------------------------------------------------------------------------
1 | {{ 'component-article-card.css' | asset_url | stylesheet_tag }}
2 | {{ 'component-card.css' | asset_url | stylesheet_tag }}
3 | {{ 'section-main-blog.css' | asset_url | stylesheet_tag }}
4 |
5 |
6 | {%- paginate blog.articles by 6 -%}
7 |
8 |
9 |
{{ blog.title | escape }}
10 |
11 |
12 | {%- for article in blog.articles -%}
13 |
14 | {%- render 'article-card', article: article, show_image: section.settings.show_image -%}
15 |
16 | {%- endfor -%}
17 |
18 |
19 | {%- if paginate.pages > 1 -%}
20 | {%- render 'pagination', paginate: paginate -%}
21 | {%- endif -%}
22 |
23 | {%- endpaginate -%}
24 |
25 | {% schema %}
26 | {
27 | "name": "t:sections.main-blog.name",
28 | "tag": "section",
29 | "class": "spaced-section",
30 | "settings": [
31 | {
32 | "type": "header",
33 | "content": "t:sections.main-blog.settings.header.content"
34 | },
35 | {
36 | "type": "checkbox",
37 | "id": "show_image",
38 | "default": true,
39 | "label": "t:sections.main-blog.settings.show_image.label",
40 | "info": "t:sections.main-blog.settings.show_image.info"
41 | },
42 | {
43 | "type": "paragraph",
44 | "content": "t:sections.main-blog.settings.paragraph.content"
45 | }
46 | ],
47 | "blocks": [
48 | {
49 | "type": "title",
50 | "name": "t:sections.main-blog.blocks.title.name",
51 | "limit": 1,
52 | "settings": [
53 | {
54 | "type": "checkbox",
55 | "id": "show_date",
56 | "default": true,
57 | "label": "t:sections.main-blog.blocks.title.settings.show_date.label"
58 | },
59 | {
60 | "type": "checkbox",
61 | "id": "show_author",
62 | "default": false,
63 | "label": "t:sections.main-blog.blocks.title.settings.show_author.label"
64 | }
65 | ]
66 | },
67 | {
68 | "type": "summary",
69 | "name": "t:sections.main-blog.blocks.summary.name",
70 | "limit": 1
71 | },
72 | {
73 | "type": "link",
74 | "name": "t:sections.main-blog.blocks.link.name",
75 | "limit": 1
76 | }
77 | ]
78 | }
79 | {% endschema %}
80 |
--------------------------------------------------------------------------------
/src/sections/main-cart-footer.liquid:
--------------------------------------------------------------------------------
1 | {{ 'component-cart.css' | asset_url | stylesheet_tag }}
2 | {{ 'component-totals.css' | asset_url | stylesheet_tag }}
3 | {{ 'component-price.css' | asset_url | stylesheet_tag }}
4 | {{ 'component-discounts.css' | asset_url | stylesheet_tag }}
5 |
6 |
80 |
81 | {% javascript %}
82 | class CartNote extends HTMLElement {
83 | constructor() {
84 | super();
85 |
86 | this.addEventListener('change', debounce((event) => {
87 | const body = JSON.stringify({ note: event.target.value });
88 | fetch(`${routes.cart_update_url}`, {...fetchConfig(), ...{ body }});
89 | }, 300))
90 | }
91 | }
92 |
93 | customElements.define('cart-note', CartNote);
94 | {% endjavascript %}
95 |
96 | {% schema %}
97 | {
98 | "name": "t:sections.main-cart-footer.name",
99 | "class": "cart__footer-wrapper",
100 | "settings": [
101 | {
102 | "type": "checkbox",
103 | "id": "show_cart_note",
104 | "default": false,
105 | "label": "t:sections.main-cart-footer.settings.show_cart_note.label"
106 | }
107 | ],
108 | "blocks": [
109 | {
110 | "type": "subtotal",
111 | "name": "t:sections.main-cart-footer.blocks.subtotal.name",
112 | "limit": 1
113 | },
114 | {
115 | "type": "buttons",
116 | "name": "t:sections.main-cart-footer.blocks.buttons.name",
117 | "limit": 1
118 | },
119 | {
120 | "type": "@app"
121 | }
122 | ]
123 | }
124 | {% endschema %}
125 |
--------------------------------------------------------------------------------
/src/sections/main-collection-banner.liquid:
--------------------------------------------------------------------------------
1 | {{ 'component-collection-hero.css' | asset_url | stylesheet_tag }}
2 |
3 |
4 |
5 |
6 |
7 | {{ 'sections.collection_template.title' | t }}:
8 | {{- collection.title | escape -}}
9 |
10 |
11 | {%- if section.settings.show_collection_description -%}
12 |
{{ collection.description }}
13 | {%- endif -%}
14 |
15 |
16 | {%- if section.settings.show_collection_image and collection.image -%}
17 |
32 | {%- endif -%}
33 |
34 |
35 |
36 | {% schema %}
37 | {
38 | "name": "t:sections.main-collection-banner.name",
39 | "class": "spaced-section spaced-section--full-width",
40 | "settings": [
41 | {
42 | "type": "paragraph",
43 | "content": "t:sections.main-collection-banner.settings.paragraph.content"
44 | },
45 | {
46 | "type": "checkbox",
47 | "id": "show_collection_description",
48 | "default": false,
49 | "label": "t:sections.main-collection-banner.settings.show_collection_description.label"
50 | },
51 | {
52 | "type": "checkbox",
53 | "id": "show_collection_image",
54 | "default": false,
55 | "label": "t:sections.main-collection-banner.settings.show_collection_image.label",
56 | "info": "t:sections.main-collection-banner.settings.show_collection_image.info"
57 | }
58 | ]
59 | }
60 | {% endschema %}
61 |
--------------------------------------------------------------------------------
/src/sections/main-page.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ 'section-main-page.css' | asset_url | stylesheet_tag }}
5 | {{ 'component-rte.css' | asset_url | stylesheet_tag }}
6 |
7 |
8 |
9 | {{ page.title | escape }}
10 |
11 |
12 | {{ page.content }}
13 |
14 |
15 |
16 | {% schema %}
17 | {
18 | "name": "t:sections.main-page.name",
19 | "tag": "section",
20 | "class": "spaced-section"
21 | }
22 | {% endschema %}
23 |
--------------------------------------------------------------------------------
/src/sections/page.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ 'component-rte.css' | asset_url | stylesheet_tag }}
5 | {{ 'section-main-page.css' | asset_url | stylesheet_tag }}
6 |
7 |
8 |
9 | {%- if section.settings.page.title != blank -%}
10 | {{ section.settings.page.title | escape }}
11 | {%- else -%}
12 | Page title
13 | {%- endif -%}
14 |
15 |
16 | {%- if section.settings.page.content != blank -%}
17 | {{ section.settings.page.content }}
18 | {%- else -%}
19 |
20 | {{ 'page' | placeholder_svg_tag: 'page-placeholder' }}
21 |
22 | {%- endif -%}
23 |
24 |
25 |
26 | {% schema %}
27 | {
28 | "name": "t:sections.page.name",
29 | "tag": "section",
30 | "class": "spaced-section",
31 | "settings": [
32 | {
33 | "type": "page",
34 | "id": "page",
35 | "label": "t:sections.page.settings.page.label"
36 | }
37 | ],
38 | "presets": [
39 | {
40 | "name": "t:sections.page.presets.name"
41 | }
42 | ]
43 | }
44 | {% endschema %}
45 |
--------------------------------------------------------------------------------
/src/sections/pickup-availability.liquid:
--------------------------------------------------------------------------------
1 | {% comment %}theme-check-disable UndefinedObject{% endcomment %}
2 | {%- assign pick_up_availabilities = product_variant.store_availabilities | where: 'pick_up_enabled', true -%}
3 |
4 | {%- if pick_up_availabilities.size > 0 -%}
5 |
6 | {%- liquid
7 | assign closest_location = pick_up_availabilities.first
8 |
9 | if closest_location.available
10 | render 'icon-tick'
11 | endif
12 | -%}
13 |
14 |
15 | {%- if closest_location.available -%}
16 |
{{ 'products.product.pickup_availability.pick_up_available_at_html' | t: location_name: closest_location.location.name }}
17 |
{{ closest_location.pick_up_time }}
18 |
19 | {%- if pick_up_availabilities.size == 1 -%}
20 | {{ 'products.product.pickup_availability.view_store_info' | t }}
21 | {%- else -%}
22 | {{ 'products.product.pickup_availability.check_other_stores' | t }}
23 | {%- endif -%}
24 |
25 | {%- else -%}
26 |
{{ 'products.product.pickup_availability.pick_up_unavailable_at_html' | t: location_name: closest_location.location.name }}
27 | {%- if pick_up_availabilities.size > 1 -%}
28 |
{{ 'products.product.pickup_availability.check_other_stores' | t }}
29 | {%- endif -%}
30 | {%- endif -%}
31 |
32 |
33 |
34 |
35 |
39 |
40 | {%- unless product_variant.product.has_only_default_variant -%}
41 |
42 | {%- for product_option in product_variant.product.options_with_values -%}
43 | {{ product_option.name | escape }}:
44 | {%- for value in product_option.values -%}
45 | {%- if product_option.selected_value == value -%}
46 | {{ value | escape }}
47 | {%- endif -%}
48 | {%- endfor -%}
49 | {%- unless forloop.last -%}, {%- endunless forloop.last -%}
50 | {%- endfor -%}
51 |
52 | {%- endunless -%}
53 |
54 |
75 |
76 | {%- endif -%}
77 |
--------------------------------------------------------------------------------
/src/sections/product-recommendations.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ 'component-badge.css' | asset_url | stylesheet_tag }}
7 | {{ 'component-card.css' | asset_url | stylesheet_tag }}
8 | {{ 'component-price.css' | asset_url | stylesheet_tag }}
9 | {{ 'section-product-recommendations.css' | asset_url | stylesheet_tag }}
10 |
11 |
12 | {% if recommendations.performed and recommendations.products_count > 0 %}
13 | {{ section.settings.heading | escape }}
14 |
15 | {% for recommendation in recommendations.products %}
16 |
17 | {% render 'product-card',
18 | product_card_product: recommendation,
19 | media_size: section.settings.image_ratio,
20 | show_secondary_image: section.settings.show_secondary_image,
21 | add_image_padding: section.settings.add_image_padding,
22 | show_vendor: section.settings.show_vendor
23 | %}
24 |
25 | {% endfor %}
26 |
27 | {% endif %}
28 |
29 |
30 | {% javascript %}
31 | class ProductRecommendations extends HTMLElement {
32 | constructor() {
33 | super();
34 |
35 | const handleIntersection = (entries, observer) => {
36 | if (!entries[0].isIntersecting) return;
37 | observer.unobserve(this);
38 |
39 | fetch(this.dataset.url)
40 | .then(response => response.text())
41 | .then(text => {
42 | const html = document.createElement('div');
43 | html.innerHTML = text;
44 | const recommendations = html.querySelector('product-recommendations');
45 | if (recommendations && recommendations.innerHTML.trim().length) {
46 | this.innerHTML = recommendations.innerHTML;
47 | }
48 | })
49 | .catch(e => {
50 | console.error(e);
51 | });
52 | }
53 |
54 | new IntersectionObserver(handleIntersection.bind(this), {rootMargin: '0px 0px 200px 0px'}).observe(this);
55 | }
56 | }
57 |
58 | customElements.define('product-recommendations', ProductRecommendations);
59 | {% endjavascript %}
60 |
61 | {% schema %}
62 | {
63 | "name": "t:sections.product-recommendations.name",
64 | "tag": "section",
65 | "class": "spaced-section",
66 | "settings": [
67 | {
68 | "type": "paragraph",
69 | "content": "t:sections.product-recommendations.settings.paragraph__1.content"
70 | },
71 | {
72 | "type": "text",
73 | "id": "heading",
74 | "default": "You may also like",
75 | "label": "t:sections.product-recommendations.settings.heading.label"
76 | },
77 | {
78 | "type": "header",
79 | "content": "t:sections.product-recommendations.settings.header__2.content"
80 | },
81 | {
82 | "type": "select",
83 | "id": "image_ratio",
84 | "options": [
85 | {
86 | "value": "adapt",
87 | "label": "t:sections.product-recommendations.settings.image_ratio.options__1.label"
88 | },
89 | {
90 | "value": "portrait",
91 | "label": "t:sections.product-recommendations.settings.image_ratio.options__2.label"
92 | },
93 | {
94 | "value": "square",
95 | "label": "t:sections.product-recommendations.settings.image_ratio.options__3.label"
96 | }
97 | ],
98 | "default": "adapt",
99 | "label": "t:sections.product-recommendations.settings.image_ratio.label"
100 | },
101 | {
102 | "type": "checkbox",
103 | "id": "show_secondary_image",
104 | "default": false,
105 | "label": "t:sections.product-recommendations.settings.show_secondary_image.label"
106 | },
107 | {
108 | "type": "checkbox",
109 | "id": "add_image_padding",
110 | "default": false,
111 | "label": "t:sections.product-recommendations.settings.add_image_padding.label"
112 | },
113 | {
114 | "type": "checkbox",
115 | "id": "show_vendor",
116 | "default": false,
117 | "label": "t:sections.product-recommendations.settings.show_vendor.label"
118 | }
119 | ]
120 | }
121 | {% endschema %}
122 |
--------------------------------------------------------------------------------
/src/sections/rich-text.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ 'component-rte.css' | asset_url | stylesheet_tag }}
5 | {{ 'section-rich-text.css' | asset_url | stylesheet_tag }}
6 |
7 |
8 |
9 | {%- for block in section.blocks -%}
10 | {%- case block.type -%}
11 | {%- when 'heading' -%}
12 |
{{ block.settings.heading | escape }}
13 | {%- when 'text' -%}
14 |
{{ block.settings.text }}
15 | {%- when 'button' -%}
16 |
17 | {{ block.settings.button_label | escape }}
18 |
19 | {%- endcase -%}
20 | {%- endfor -%}
21 |
22 |
23 |
24 | {% schema %}
25 | {
26 | "name": "t:sections.rich-text.name",
27 | "tag": "section",
28 | "class": "spaced-section spaced-section--full-width",
29 | "settings": [
30 | {
31 | "type": "select",
32 | "id": "color_scheme",
33 | "options": [
34 | {
35 | "value": "accent-1",
36 | "label": "t:sections.rich-text.settings.color_scheme.options__1.label"
37 | },
38 | {
39 | "value": "accent-2",
40 | "label": "t:sections.rich-text.settings.color_scheme.options__2.label"
41 | },
42 | {
43 | "value": "background-1",
44 | "label": "t:sections.rich-text.settings.color_scheme.options__3.label"
45 | },
46 | {
47 | "value": "background-2",
48 | "label": "t:sections.rich-text.settings.color_scheme.options__4.label"
49 | },
50 | {
51 | "value": "inverse",
52 | "label": "t:sections.rich-text.settings.color_scheme.options__5.label"
53 | }
54 | ],
55 | "default": "background-1",
56 | "label": "t:sections.rich-text.settings.color_scheme.label"
57 | },
58 | {
59 | "type": "checkbox",
60 | "id": "full_width",
61 | "default": true,
62 | "label": "t:sections.rich-text.settings.full_width.label"
63 | }
64 | ],
65 | "blocks": [
66 | {
67 | "type": "heading",
68 | "name": "t:sections.rich-text.blocks.heading.name",
69 | "limit": 1,
70 | "settings": [
71 | {
72 | "type": "text",
73 | "id": "heading",
74 | "default": "Talk about your brand",
75 | "label": "t:sections.rich-text.blocks.heading.settings.heading.label"
76 | },
77 | {
78 | "type": "select",
79 | "id": "heading_size",
80 | "options": [
81 | {
82 | "value": "small",
83 | "label": "t:sections.rich-text.blocks.heading.settings.heading_size.options__1.label"
84 | },
85 | {
86 | "value": "medium",
87 | "label": "t:sections.rich-text.blocks.heading.settings.heading_size.options__2.label"
88 | }
89 | ],
90 | "default": "medium",
91 | "label": "t:sections.rich-text.blocks.heading.settings.heading_size.label"
92 | }
93 | ]
94 | },
95 | {
96 | "type": "text",
97 | "name": "t:sections.rich-text.blocks.text.name",
98 | "limit": 1,
99 | "settings": [
100 | {
101 | "type": "richtext",
102 | "id": "text",
103 | "default": "Share information about your brand with your customers. Describe a product, make announcements, or welcome customers to your store.
",
104 | "label": "t:sections.rich-text.blocks.text.settings.text.label"
105 | }
106 | ]
107 | },
108 | {
109 | "type": "button",
110 | "name": "t:sections.rich-text.blocks.button.name",
111 | "limit": 1,
112 | "settings": [
113 | {
114 | "type": "text",
115 | "id": "button_label",
116 | "default": "Button label",
117 | "label": "t:sections.rich-text.blocks.button.settings.button_label.label"
118 | },
119 | {
120 | "type": "url",
121 | "id": "button_link",
122 | "label": "t:sections.rich-text.blocks.button.settings.button_link.label"
123 | },
124 | {
125 | "type": "checkbox",
126 | "id": "button_style_secondary",
127 | "default": false,
128 | "label": "t:sections.rich-text.blocks.button.settings.button_style_secondary.label"
129 | }
130 | ]
131 | }
132 | ],
133 | "presets": [
134 | {
135 | "name": "t:sections.rich-text.presets.name",
136 | "blocks": [
137 | {
138 | "type": "heading"
139 | },
140 | {
141 | "type": "text"
142 | },
143 | {
144 | "type": "button"
145 | }
146 | ]
147 | }
148 | ]
149 | }
150 | {% endschema %}
151 |
--------------------------------------------------------------------------------
/src/snippets/article-card.liquid:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Renders an article card for a given blog with settings to either show the image or not.
3 |
4 | Accepts:
5 | - blog: {Object} Blog object
6 | - article: {Object} Article object
7 | - show_image: {String} The setting either show the article image or not. If it's not included it will show the image by default
8 |
9 | Usage:
10 | {% render 'article-card' blog: blog, article: article, show_image: section.settings.show_image %}
11 | {% endcomment %}
12 |
13 |
14 |
15 | {%- if show_image == true and article.image -%}
16 |
17 |
18 |
33 |
34 |
35 | {%- endif -%}
36 |
37 |
38 | {%- for block in section.blocks -%}
39 | {%- case block.type -%}
40 | {%- when 'title'-%}
41 |
42 |
43 | {{ article.title | escape }}
44 |
45 | {%- if block.settings.show_date -%}
46 |
47 | {{- article.published_at | time_tag: format: 'month_year' -}}
48 |
49 | {%- endif -%}
50 | {%- if block.settings.show_author -%}
51 | {{ article.author -}}
52 | {%- endif -%}
53 |
54 |
55 | {%- when 'summary'-%}
56 | {%- if article.excerpt.size > 0 or article.content.size > 0 -%}
57 |
58 | {%- if article.excerpt.size > 0 -%}
59 | {{ article.excerpt | strip_html | truncatewords: 30 }}
60 | {%- else -%}
61 | {{ article.content | strip_html | truncatewords: 30 }}
62 | {%- endif -%}
63 |
64 | {%- endif -%}
65 |
66 | {%- when 'link'-%}
67 |
68 |
69 | {{ 'blogs.article.read_more' | t }}
70 |
71 |
72 | {%- if article.comments_count > 0 and blog.comments_enabled? -%}
73 | {{ 'blogs.article.comments' | t: count: article.comments_count }}
74 | {%- endif -%}
75 |
76 | {%- endcase -%}
77 | {%- endfor -%}
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/snippets/cart-notification.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
16 |
{{ 'general.continue_shopping' | t }}
17 |
18 |
19 |
20 |
21 | {% style %}
22 | .cart-notification {
23 | display: none;
24 | }
25 | {% endstyle %}
26 |
--------------------------------------------------------------------------------
/src/snippets/icon-3d-model.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-account.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-arrow.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-caret.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-cart-empty.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-cart.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-checkmark.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-clipboard.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-close-small.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/snippets/icon-close.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-discount.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-error.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/snippets/icon-facebook.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-filter.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/snippets/icon-hamburger.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-instagram.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/snippets/icon-minus.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-padlock.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-pinterest.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-play.liquid:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/snippets/icon-plus.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-remove.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/snippets/icon-share.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/snippets/icon-snapchat.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-success.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/snippets/icon-tick.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-tiktok.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-tumblr.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-twitter.liquid:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-unavailable.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-vimeo.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-youtube.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/snippets/icon-zoom.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/snippets/meta-tags.liquid:
--------------------------------------------------------------------------------
1 | {%- liquid
2 | assign og_title = page_title | default: shop.name
3 | assign og_url = canonical_url | default: shop.url
4 | assign og_type = 'website'
5 | assign og_description = page_description | default: shop.description | default: shop.name
6 |
7 | if request.page_type == 'product'
8 | assign og_type = 'product'
9 | elsif request.page_type == 'article'
10 | assign og_type = 'article'
11 | elsif request.page_type == 'collection'
12 | assign og_type = 'product.group'
13 | elsif request.page_type == 'password'
14 | assign og_url = shop.url
15 | endif
16 | %}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | {%- if page_image -%}
25 |
26 |
27 |
28 |
29 | {%- endif -%}
30 |
31 | {%- if request.page_type == 'product' -%}
32 |
33 |
34 | {%- endif -%}
35 |
36 | {%- if settings.social_twitter_link != blank -%}
37 |
38 | {%- endif -%}
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/snippets/pagination.liquid:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Renders a set of links for paginated results. Must be used within paginate tags.
3 |
4 | Usage:
5 | {% paginate results by 2 %}
6 | {% render 'pagination', paginate: paginate, anchor: '#yourID' %}
7 | {% endpaginate %}
8 |
9 | Accepts:
10 | - paginate: {Object}
11 | - anchor: {String} (optional) This can be added so that on page reload it takes you to wherever you've placed your anchor tag.
12 | - class: {String} (optional) Appended to container element's class attribute
13 | {% endcomment %}
14 |
15 |
16 | {{ 'component-pagination.css' | asset_url | stylesheet_tag }}
17 |
18 | {%- if paginate.parts.size > 0 -%}
19 |
54 | {%- endif -%}
55 |
--------------------------------------------------------------------------------
/src/snippets/price.liquid:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Renders a list of product's price (regular, sale)
3 |
4 | Accepts:
5 | - product: {Object} Product Liquid object (optional)
6 | - use_variant: {Boolean} Renders selected or first variant price instead of overall product pricing (optional)
7 | - show_badges: {Boolean} Renders 'Sale' and 'Sold Out' tags if the product matches the condition (optional)
8 | - price_class: {String} Adds a price class to the price element (optional)
9 |
10 | Usage:
11 | {% render 'price', product: product %}
12 | {% endcomment %}
13 | {%- liquid
14 | if use_variant
15 | assign target = product.selected_or_first_available_variant
16 | else
17 | assign target = product
18 | endif
19 |
20 | assign compare_at_price = target.compare_at_price
21 | assign price = target.price | default: 1999
22 | assign available = target.available | default: false
23 | assign money_price = price | money
24 |
25 | if target == product and product.price_varies
26 | assign money_price = 'products.product.price.from_price_html' | t: price: money_price
27 | endif
28 | -%}
29 |
30 |
35 |
36 | {%- comment -%}
37 | Explanation of description list:
38 | - div.price__regular: Displayed when there are no variants on sale
39 | - div.price__sale: Displayed when a variant is a sale
40 | - div.price__availability: Displayed when the product is sold out
41 | {%- endcomment -%}
42 |
43 |
44 | {{ 'products.product.price.regular_price' | t }}
45 |
46 |
47 |
48 | {{ money_price }}
49 |
50 |
51 |
52 |
53 |
54 | {{ 'products.product.price.regular_price' | t }}
55 |
56 |
57 |
58 | {{ compare_at_price | money }}
59 |
60 |
61 |
62 | {{ 'products.product.price.sale_price' | t }}
63 |
64 |
65 |
66 | {{ money_price }}
67 |
68 |
69 |
70 |
71 | {{ 'products.product.price.unit_price' | t }}
72 |
73 | {{- product.selected_or_first_available_variant.unit_price | money -}}
74 | /
75 | {{ 'accessibility.unit_price_separator' | t }}
76 |
77 | {%- if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 -%}
78 | {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
79 | {%- endif -%}
80 | {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
81 |
82 |
83 |
84 |
85 | {%- if show_badges -%}
86 |
87 | {{ 'products.product.on_sale' | t }}
88 |
89 |
90 |
91 | {{ 'products.product.sold_out' | t }}
92 |
93 | {%- endif -%}
94 |
95 |
--------------------------------------------------------------------------------
/src/snippets/product-card-placeholder.liquid:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Renders a product card placeholder
3 |
4 | Usage:
5 | {% render 'product-card-placeholder' %}
6 | {% endcomment %}
7 |
8 |
23 |
--------------------------------------------------------------------------------
/src/snippets/social-sharing.liquid:
--------------------------------------------------------------------------------
1 |
46 |
--------------------------------------------------------------------------------
/src/styles/sections/header.css:
--------------------------------------------------------------------------------
1 | .header__test {
2 | @apply border-purple-600 border-8;
3 | }
--------------------------------------------------------------------------------
/src/styles/sections/image-banner.css:
--------------------------------------------------------------------------------
1 | .image-banner__test {
2 | @apply border-green-600 border-8;
3 | }
--------------------------------------------------------------------------------
/src/styles/theme.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss/base";
2 | @import "tailwindcss/components";
3 | @import "tailwindcss/utilities";
4 |
5 | @import './utils/base.css';
6 | @import './utils/autocomplete.css';
7 |
8 | .theme__test {
9 | @apply border-red-600 border-8;
10 | }
--------------------------------------------------------------------------------
/src/styles/utils/autocomplete.css:
--------------------------------------------------------------------------------
1 | .autocomplete {
2 | color: #777;
3 | }
--------------------------------------------------------------------------------
/src/styles/utils/base.css:
--------------------------------------------------------------------------------
1 | .special_input {
2 | appearance: none;
3 | }
--------------------------------------------------------------------------------
/src/templates/404.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-404"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/templates/article.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-article",
5 | "blocks": {
6 | "featured_image": {
7 | "type": "featured_image"
8 | },
9 | "title": {
10 | "type": "title"
11 | },
12 | "content": {
13 | "type": "content"
14 | },
15 | "social_sharing": {
16 | "type": "social_sharing"
17 | }
18 | },
19 | "block_order": [
20 | "featured_image",
21 | "title",
22 | "content",
23 | "social_sharing"
24 | ]
25 | }
26 | },
27 | "order": ["main"]
28 | }
29 |
--------------------------------------------------------------------------------
/src/templates/blog.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-blog",
5 | "blocks": {
6 | "title": {
7 | "type": "title"
8 | },
9 | "summary": {
10 | "type": "summary"
11 | },
12 | "link": {
13 | "type": "link"
14 | }
15 | },
16 | "block_order": [
17 | "title",
18 | "summary",
19 | "link"
20 | ]
21 | }
22 | },
23 | "order": [
24 | "main"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/src/templates/cart.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "cart-items": {
4 | "type": "main-cart-items"
5 | },
6 | "cart-footer": {
7 | "type": "main-cart-footer",
8 | "blocks": {
9 | "subtotal": {
10 | "type": "subtotal"
11 | },
12 | "buttons": {
13 | "type": "buttons"
14 | }
15 | },
16 | "block_order": [
17 | "subtotal",
18 | "buttons"
19 | ]
20 | }
21 | },
22 | "order": [
23 | "cart-items",
24 | "cart-footer"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/src/templates/collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "banner": {
4 | "type": "main-collection-banner"
5 | },
6 | "product-grid": {
7 | "type": "main-collection-product-grid"
8 | }
9 | },
10 | "order": [
11 | "banner",
12 | "product-grid"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/src/templates/customers/activate_account.liquid:
--------------------------------------------------------------------------------
1 | {{ 'customer.css' | asset_url | stylesheet_tag }}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{ 'customer.activate_account.title' | t }}
14 |
15 |
16 | {{ 'customer.activate_account.subtext' | t }}
17 |
18 | {%- form 'activate_customer_password' -%}
19 | {%- if form.errors -%}
20 |
26 |
40 | {%- endif -%}
41 |
42 |
43 |
54 |
55 | {{ 'customer.activate_account.password' | t }}
56 |
57 | {%- if form.errors contains 'password' -%}
58 |
59 |
60 |
61 |
62 | {{ form.errors.translated_fields['password'] | capitalize }} {{ form.errors.messages['password'] }}
63 |
64 | {%- endif -%}
65 |
66 |
67 |
68 |
79 |
80 | {{ 'customer.activate_account.password_confirm' | t }}
81 |
82 | {%- if form.errors contains 'password_confirmation' -%}
83 |
84 |
85 |
86 |
87 | {{ form.errors.translated_fields['password_confirmation'] | capitalize }} {{ form.errors.messages['password_confirmation'] }}
88 |
89 | {%- endif -%}
90 |
91 |
92 |
93 | {{ 'customer.activate_account.submit' | t }}
94 |
95 |
96 | {{ 'customer.activate_account.cancel' | t }}
97 |
98 | {%- endform -%}
99 |
100 |
--------------------------------------------------------------------------------
/src/templates/customers/register.liquid:
--------------------------------------------------------------------------------
1 | {{ 'customer.css' | asset_url | stylesheet_tag }}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{ 'customer.register.title' | t }}
14 |
15 | {%- form 'create_customer', novalidate: 'novalidate' -%}
16 | {%- if form.errors -%}
17 |
23 |
37 | {%- endif -%}
38 |
39 |
47 |
48 | {{ 'customer.register.first_name' | t }}
49 |
50 |
51 |
52 |
60 |
61 | {{ 'customer.register.last_name' | t }}
62 |
63 |
64 |
65 |
80 |
81 | {{ 'customer.register.email' | t }}
82 |
83 |
84 | {%- if form.errors contains 'email' -%}
85 |
86 |
87 |
88 |
89 | {{ form.errors.translated_fields['email'] | capitalize }} {{ form.errors.messages['email'] }}.
90 |
91 | {%- endif -%}
92 |
93 |
104 |
105 | {{ 'customer.register.password' | t }}
106 |
107 |
108 | {%- if form.errors contains 'password' -%}
109 |
110 |
111 |
112 |
113 | {{ form.errors.translated_fields['password'] | capitalize }} {{ form.errors.messages['password'] }}.
114 |
115 | {%- endif -%}
116 |
117 | {{ 'customer.register.submit' | t }}
118 |
119 | {%- endform -%}
120 |
121 |
--------------------------------------------------------------------------------
/src/templates/customers/reset_password.liquid:
--------------------------------------------------------------------------------
1 | {{ 'customer.css' | asset_url | stylesheet_tag }}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{ 'customer.reset_password.title' | t }}
14 |
15 |
16 | {{ 'customer.reset_password.subtext' | t: email: email }}
17 |
18 | {%- form 'reset_customer_password' -%}
19 | {%- if form.errors -%}
20 |
27 |
41 | {%- endif -%}
42 |
43 |
44 |
55 |
56 | {{ 'customer.reset_password.password' | t }}
57 |
58 | {%- if form.errors contains 'password' -%}
59 |
60 |
61 |
62 |
63 | {{ form.errors.translated_fields['password'] | capitalize }} {{ form.errors.messages['password'] }}
64 |
65 | {%- endif -%}
66 |
67 |
68 |
69 |
80 |
81 | {{ 'customer.reset_password.password_confirm' | t }}
82 |
83 | {%- if form.errors contains 'password_confirmation' -%}
84 |
85 |
86 |
87 |
88 | {{ form.errors.translated_fields['password_confirmation'] | capitalize }} {{ form.errors.messages['password_confirmation'] }}
89 |
90 | {%- endif -%}
91 |
92 |
93 |
94 | {{ 'customer.reset_password.submit' | t }}
95 |
96 | {%- endform -%}
97 |
98 |
--------------------------------------------------------------------------------
/src/templates/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "image_banner": {
4 | "type": "image-banner",
5 | "settings": {
6 | "desktop_text_box_position": "flex-end"
7 | },
8 | "blocks": {
9 | "heading": {
10 | "type": "heading",
11 | "settings": {
12 | "heading": "Talk about your brand"
13 | }
14 | },
15 | "button": {
16 | "type": "buttons",
17 | "settings": {
18 | "button_label_1": "Shop all",
19 | "button_link_1": "shopify:\/\/collections\/all",
20 | "button_label_2": ""
21 | }
22 | }
23 | },
24 | "block_order": [
25 | "heading",
26 | "button"
27 | ]
28 | },
29 | "featured_products": {
30 | "type": "featured-collection",
31 | "settings": {
32 | "title": "Featured products"
33 | }
34 | },
35 | "image_text": {
36 | "type": "image-with-text",
37 | "blocks": {
38 | "heading": {
39 | "type": "heading"
40 | },
41 | "text": {
42 | "type": "text"
43 | },
44 | "button": {
45 | "type": "button"
46 | }
47 | },
48 | "block_order": [
49 | "heading",
50 | "text",
51 | "button"
52 | ]
53 | }
54 | },
55 | "order": [
56 | "image_banner",
57 | "featured_products",
58 | "image_text"
59 | ]
60 | }
61 |
--------------------------------------------------------------------------------
/src/templates/list-collections.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-list-collections"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/templates/page.contact.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-page"
5 | },
6 | "form": {
7 | "type": "contact-form",
8 | "settings": {
9 | "heading": ""
10 | }
11 | }
12 | },
13 | "order": [
14 | "main",
15 | "form"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/src/templates/page.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-page"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/templates/password.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "password",
3 | "sections": {
4 | "main": {
5 | "type": "newsletter",
6 | "settings": {
7 | "full_width": false
8 | },
9 | "blocks": {
10 | "heading": {
11 | "type": "heading",
12 | "settings": {
13 | "heading": "Opening soon"
14 | }
15 | },
16 | "paragraph": {
17 | "type": "paragraph",
18 | "settings": {
19 | "paragraph": "Be the first to know when we launch.
"
20 | }
21 | },
22 | "email_form": {
23 | "type": "email_form"
24 | }
25 | },
26 | "block_order": [
27 | "heading",
28 | "paragraph",
29 | "email_form"
30 | ]
31 | }
32 | },
33 | "order": [
34 | "main"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/src/templates/product.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-product",
5 | "blocks": {
6 | "vendor": {
7 | "type": "text",
8 | "settings": {
9 | "text_style": "uppercase",
10 | "text": "{{ product.vendor }}"
11 | }
12 | },
13 | "title": {
14 | "type": "title"
15 | },
16 | "subtitle": {
17 | "type": "text",
18 | "settings": {
19 | "text": "{{ product.metafields.descriptors.subtitle.value }}",
20 | "text_style": "subtitle"
21 | }
22 | },
23 | "price": {
24 | "type": "price"
25 | },
26 | "variant_picker": {
27 | "type": "variant_picker"
28 | },
29 | "quantity_selector": {
30 | "type": "quantity_selector"
31 | },
32 | "buy_buttons": {
33 | "type": "buy_buttons"
34 | },
35 | "description": {
36 | "type": "description"
37 | },
38 | "share": {
39 | "type": "share"
40 | }
41 | },
42 | "block_order": [
43 | "vendor",
44 | "title",
45 | "subtitle",
46 | "price",
47 | "variant_picker",
48 | "quantity_selector",
49 | "buy_buttons",
50 | "description",
51 | "share"
52 | ]
53 | },
54 | "product-recommendations": {
55 | "type": "product-recommendations"
56 | }
57 | },
58 | "order": [
59 | "main",
60 | "product-recommendations"
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/src/templates/search.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-search"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/translation.yml:
--------------------------------------------------------------------------------
1 | source_language: en
2 | target_languages: [bg-BG, cs, da, de, el, es, fi, fr, hr-HR, hu, id, it, ja, ko, lt-LT, nb, nl, pl, pt-BR, pt-PT, ro-RO, ru, sk-SK, sl-SI, sv, th, tr, vi, zh-CN, zh-TW]
3 | components:
4 | - name: buyer
5 | audience: buyer
6 | scheme: 'online-store-theme'
7 | paths:
8 | - locales/{{language}}.json
9 | - name: merchant
10 | target_languages: [cs, da, de, es, fi, fr, it, ja, ko, nb, nl, pl, pt-BR, pt-PT, sv, th, tr, vi, zh-CN, zh-TW]
11 | audience: merchant
12 | scheme: 'online-store-theme'
13 | paths:
14 | - locales/{{language}}.schema.json
15 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mode: 'jit',
3 | purge: ['./src/**/*.liquid', './src/**/*.html', './src/**/*.js'],
4 | darkMode: false, // or 'media' or 'class'
5 | theme: {
6 | extend: {},
7 | },
8 | variants: {
9 | extend: {},
10 | },
11 | plugins: [],
12 | };
13 |
--------------------------------------------------------------------------------