├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── Bug_issue.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── probots.yml └── workflows │ └── ci.yml ├── .gitignore ├── .prettierrc.json ├── .theme-check.yml ├── LICENSE.md ├── README.md ├── assets ├── base.css ├── cart-drawer.js ├── cart-notification.js ├── cart.js ├── collapsible-content.css ├── component-accordion.css ├── component-article-card.css ├── component-card.css ├── component-cart-drawer.css ├── component-cart-items.css ├── component-cart-notification.css ├── component-cart.css ├── component-collection-hero.css ├── component-complementary-products.css ├── component-deferred-media.css ├── component-discounts.css ├── component-facets.css ├── component-image-with-text.css ├── component-list-payment.css ├── component-mega-menu.css ├── component-menu-drawer.css ├── component-model-viewer-ui.css ├── component-pagination.css ├── component-predictive-search.css ├── component-price.css ├── component-product-model.css ├── component-product-variant-picker.css ├── component-rating.css ├── component-search.css ├── component-show-more.css ├── component-slider.css ├── component-slideshow.css ├── component-swatch-input.css ├── component-swatch.css ├── component-totals.css ├── constants.js ├── details-disclosure.js ├── facets.js ├── global.js ├── localization-form.js ├── magnify.js ├── main-search.js ├── media-gallery.js ├── product-form.js ├── product-info.js ├── quantity-popover.css ├── quantity-popover.js ├── quick-add.css ├── quick-add.js ├── search-form.js ├── section-footer.css ├── section-image-banner.css ├── section-main-page.css ├── section-password.css ├── section-related-products.css ├── section-rich-text.css ├── template-collection.css ├── template-giftcard.css ├── theme-editor.js └── video-section.css ├── config ├── settings_data.json └── settings_schema.json ├── layout ├── password.liquid └── theme.liquid ├── locales ├── en.default.json ├── en.default.schema.json ├── fr.json └── fr.schema.json ├── release-notes.md ├── sections ├── announcement-bar.liquid ├── apps.liquid ├── cart-icon-bubble.liquid ├── cart-live-region-text.liquid ├── cart-notification-button.liquid ├── cart-notification-product.liquid ├── collapsible-content.liquid ├── contact-form.liquid ├── custom-liquid.liquid ├── email-signup-banner.liquid ├── featured-collection.liquid ├── featured-product.liquid ├── footer-group.json ├── footer.liquid ├── header-group.json ├── header.liquid ├── image-banner.liquid ├── image-with-text.liquid ├── main-404.liquid ├── main-account.liquid ├── main-activate-account.liquid ├── main-addresses.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-login.liquid ├── main-order.liquid ├── main-page.liquid ├── main-password-footer.liquid ├── main-password-header.liquid ├── main-product.liquid ├── main-register.liquid ├── main-reset-password.liquid ├── main-search.liquid ├── multicolumn.liquid ├── newsletter.liquid ├── page.liquid ├── predictive-search.liquid ├── related-products.liquid ├── rich-text.liquid ├── slideshow.liquid └── video.liquid ├── snippets ├── article-card.liquid ├── buy-buttons.liquid ├── card-collection.liquid ├── card-product.liquid ├── cart-drawer.liquid ├── cart-notification.liquid ├── country-localization.liquid ├── facets.liquid ├── gift-card-recipient-form.liquid ├── header-drawer.liquid ├── header-dropdown-menu.liquid ├── header-mega-menu.liquid ├── header-search.liquid ├── icon-accordion.liquid ├── icon-with-text.liquid ├── language-localization.liquid ├── loading-spinner.liquid ├── meta-tags.liquid ├── pagination.liquid ├── price-facet.liquid ├── price.liquid ├── product-media-gallery.liquid ├── product-media-modal.liquid ├── product-media.liquid ├── product-thumbnail.liquid ├── product-variant-options.liquid ├── product-variant-picker.liquid ├── progress-bar.liquid ├── quantity-input.liquid ├── swatch-input.liquid ├── swatch.liquid └── visual-display.liquid └── templates ├── 404.json ├── article.json ├── blog.json ├── cart.json ├── collection.json ├── customers ├── account.json ├── activate_account.json ├── addresses.json ├── login.json ├── order.json ├── register.json └── reset_password.json ├── gift_card.liquid ├── index.json ├── list-collections.json ├── page.contact.json ├── page.json ├── password.json ├── product.json └── search.json /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | In the interest of fostering an open and welcoming environment, we as 7 | contributors and maintainers pledge to make participation in our project and 8 | our community a harassment-free experience for everyone, regardless of age, body 9 | size, disability, ethnicity, sex characteristics, gender identity and expression, 10 | level of experience, education, socio-economic status, nationality, personal 11 | appearance, race, religion, or sexual identity and orientation. 12 | 13 | ## Our Standards 14 | 15 | Examples of behavior that contributes to creating a positive environment 16 | include: 17 | 18 | * Using welcoming and inclusive language 19 | * Being respectful of differing viewpoints and experiences 20 | * Gracefully accepting constructive criticism 21 | * Focusing on what is best for the community 22 | * Showing empathy towards other community members 23 | 24 | Examples of unacceptable behavior by participants include: 25 | 26 | * The use of sexualized language or imagery and unwelcome sexual attention or 27 | advances 28 | * Trolling, insulting/derogatory comments, and personal or political attacks 29 | * Public or private harassment 30 | * Publishing others' private information, such as a physical or electronic 31 | address, without explicit permission 32 | * Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | ## Our Responsibilities 36 | 37 | Project maintainers are responsible for clarifying the standards of acceptable 38 | behavior and are expected to take appropriate and fair corrective action in 39 | response to any instances of unacceptable behavior. 40 | 41 | Project maintainers have the right and responsibility to remove, edit, or 42 | reject comments, commits, code, wiki edits, issues, and other contributions 43 | that are not aligned to this Code of Conduct, or to ban temporarily or 44 | permanently any contributor for other behaviors that they deem inappropriate, 45 | threatening, offensive, or harmful. 46 | 47 | ## Scope 48 | 49 | This Code of Conduct applies within all project spaces, and it also applies when 50 | an individual is representing the project or its community in public spaces. 51 | Examples of representing a project or community include using an official 52 | project e-mail address, posting via an official social media account, or acting 53 | as an appointed representative at an online or offline event. Representation of 54 | a project may be further defined and clarified by project maintainers. 55 | 56 | ## Enforcement 57 | 58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 59 | reported by contacting the project team at . All 60 | complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 72 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 73 | 74 | [homepage]: https://www.contributor-covenant.org 75 | 76 | For answers to common questions about this code of conduct, see 77 | https://www.contributor-covenant.org/faq 78 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug issue 3 | about: Use this template for reporting a bug 4 | labels: 'type:bug' 5 | 6 | --- 7 | 8 | **Describe the current behavior** 9 | 10 | **Describe the expected behavior** 11 | 12 | **Version information (Dawn, browsers and operating systems)** 13 | - Dawn Version: 1.0.0 14 | - Chrome Version 91.0.4472.114 15 | - macOS Version 11.3.1 16 | 17 | **Possible solution** 18 | 19 | **Additional context/screenshots** 20 | Add any other context about the problem here. If applicable, add screenshots to help explain. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature request" 3 | about: "Use this template for suggesting a Dawn enhancement" 4 | labels: 'i: enhancement' 5 | 6 | --- 7 | 8 | **Describe the enhancement you'd like** 9 | A clear and concise description of what you want added to Dawn. Add any considered drawbacks. 10 | 11 | **Describe alternatives you've considered** 12 | A clear and concise description of any alternative solutions or features you've considered. 13 | 14 | **Additional context/screenshots** 15 | Maybe a screenshot or design? 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Why are these changes introduced?** 2 | 3 | Fixes #0. 4 | 5 | **What approach did you take?** 6 | 7 | **Other considerations** 8 | 9 | **Testing steps/scenarios** 10 | - [ ] _List all the testing tasks that applies to your fix and help peers to review your work._ 11 | 12 | **Demo links** 13 | _Please include a link to a demo store that includes preconfigured sections and settings to allow reviewers to easily test the features you are working on._ 14 | 15 | - [Store](url) 16 | - [Editor](url) 17 | 18 | **Checklist** 19 | - [ ] Followed [theme code principles](https://github.com/Shopify/dawn/blob/main/.github/CONTRIBUTING.md#theme-code-principles) 20 | - [ ] Linted with [Theme Check](https://github.com/Shopify/theme-check) 21 | - [ ] Tested on [mobile](https://shopify.dev/themes/store/requirements#mobile-browser-requirements) 22 | - [ ] Tested on [multiple browsers](https://shopify.dev/themes/store/requirements#desktop-browser-requirements) 23 | - [ ] Tested for [accessibility](https://shopify.dev/themes/best-practices/accessibility) 24 | -------------------------------------------------------------------------------- /.github/probots.yml: -------------------------------------------------------------------------------- 1 | enabled: 2 | - cla 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | lhci: 5 | name: Lighthouse 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - name: Lighthouse 10 | uses: shopify/lighthouse-ci-action@1.0 11 | with: 12 | app_id: ${{ secrets.SHOP_APP_ID }} 13 | app_password: ${{ secrets.SHOP_APP_PASSWORD }} 14 | store: ${{ secrets.SHOP_STORE }} 15 | password: ${{ secrets.SHOP_PASSWORD }} 16 | lhci_github_token: ${{ secrets.LHCI_GITHUB_TOKEN }} 17 | theme-check: 18 | name: Theme Check 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Theme Check 23 | uses: shopify/theme-check-action@v1 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | ehthumbs.db 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "overrides": [ 5 | { 6 | "files": "*.liquid", 7 | "options": { 8 | "singleQuote": false 9 | } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.theme-check.yml: -------------------------------------------------------------------------------- 1 | MatchingTranslations: 2 | enabled: false 3 | TemplateLength: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/cart-drawer.js: -------------------------------------------------------------------------------- 1 | class CartDrawer extends HTMLElement { 2 | constructor() { 3 | super(); 4 | 5 | this.addEventListener('keyup', (evt) => evt.code === 'Escape' && this.close()); 6 | this.querySelector('#CartDrawer-Overlay').addEventListener('click', this.close.bind(this)); 7 | this.setHeaderCartIconAccessibility(); 8 | } 9 | 10 | setHeaderCartIconAccessibility() { 11 | const cartLink = document.querySelector('#cart-icon-bubble'); 12 | if (!cartLink) return; 13 | 14 | cartLink.setAttribute('role', 'button'); 15 | cartLink.setAttribute('aria-haspopup', 'dialog'); 16 | cartLink.addEventListener('click', (event) => { 17 | event.preventDefault(); 18 | this.open(cartLink); 19 | }); 20 | cartLink.addEventListener('keydown', (event) => { 21 | if (event.code.toUpperCase() === 'SPACE') { 22 | event.preventDefault(); 23 | this.open(cartLink); 24 | } 25 | }); 26 | } 27 | 28 | open(triggeredBy) { 29 | if (triggeredBy) this.setActiveElement(triggeredBy); 30 | const cartDrawerNote = this.querySelector('[id^="Details-"] summary'); 31 | if (cartDrawerNote && !cartDrawerNote.hasAttribute('role')) this.setSummaryAccessibility(cartDrawerNote); 32 | // here the animation doesn't seem to always get triggered. A timeout seem to help 33 | setTimeout(() => { 34 | this.classList.add('animate', 'active'); 35 | }); 36 | 37 | this.addEventListener( 38 | 'transitionend', 39 | () => { 40 | const containerToTrapFocusOn = this.classList.contains('is-empty') 41 | ? this.querySelector('.drawer__inner-empty') 42 | : document.getElementById('CartDrawer'); 43 | const focusElement = this.querySelector('.drawer__inner') || this.querySelector('.drawer__close'); 44 | trapFocus(containerToTrapFocusOn, focusElement); 45 | }, 46 | { once: true } 47 | ); 48 | 49 | document.body.classList.add('overflow-hidden'); 50 | } 51 | 52 | close() { 53 | this.classList.remove('active'); 54 | removeTrapFocus(this.activeElement); 55 | document.body.classList.remove('overflow-hidden'); 56 | } 57 | 58 | setSummaryAccessibility(cartDrawerNote) { 59 | cartDrawerNote.setAttribute('role', 'button'); 60 | cartDrawerNote.setAttribute('aria-expanded', 'false'); 61 | 62 | if (cartDrawerNote.nextElementSibling.getAttribute('id')) { 63 | cartDrawerNote.setAttribute('aria-controls', cartDrawerNote.nextElementSibling.id); 64 | } 65 | 66 | cartDrawerNote.addEventListener('click', (event) => { 67 | event.currentTarget.setAttribute('aria-expanded', !event.currentTarget.closest('details').hasAttribute('open')); 68 | }); 69 | 70 | cartDrawerNote.parentElement.addEventListener('keyup', onKeyUpEscape); 71 | } 72 | 73 | renderContents(parsedState) { 74 | this.querySelector('.drawer__inner').classList.contains('is-empty') && 75 | this.querySelector('.drawer__inner').classList.remove('is-empty'); 76 | this.productId = parsedState.id; 77 | this.getSectionsToRender().forEach((section) => { 78 | const sectionElement = section.selector 79 | ? document.querySelector(section.selector) 80 | : document.getElementById(section.id); 81 | 82 | if (!sectionElement) return; 83 | sectionElement.innerHTML = this.getSectionInnerHTML(parsedState.sections[section.id], section.selector); 84 | }); 85 | 86 | setTimeout(() => { 87 | this.querySelector('#CartDrawer-Overlay').addEventListener('click', this.close.bind(this)); 88 | this.open(); 89 | }); 90 | } 91 | 92 | getSectionInnerHTML(html, selector = '.shopify-section') { 93 | return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML; 94 | } 95 | 96 | getSectionsToRender() { 97 | return [ 98 | { 99 | id: 'cart-drawer', 100 | selector: '#CartDrawer', 101 | }, 102 | { 103 | id: 'cart-icon-bubble', 104 | }, 105 | ]; 106 | } 107 | 108 | getSectionDOM(html, selector = '.shopify-section') { 109 | return new DOMParser().parseFromString(html, 'text/html').querySelector(selector); 110 | } 111 | 112 | setActiveElement(element) { 113 | this.activeElement = element; 114 | } 115 | } 116 | 117 | customElements.define('cart-drawer', CartDrawer); 118 | 119 | class CartDrawerItems extends CartItems { 120 | getSectionsToRender() { 121 | return [ 122 | { 123 | id: 'CartDrawer', 124 | section: 'cart-drawer', 125 | selector: '.drawer__inner', 126 | }, 127 | { 128 | id: 'cart-icon-bubble', 129 | section: 'cart-icon-bubble', 130 | selector: '.shopify-section', 131 | }, 132 | ]; 133 | } 134 | } 135 | 136 | customElements.define('cart-drawer-items', CartDrawerItems); 137 | -------------------------------------------------------------------------------- /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( 19 | 'transitionend', 20 | () => { 21 | this.notification.focus(); 22 | trapFocus(this.notification); 23 | }, 24 | { once: true } 25 | ); 26 | 27 | document.body.addEventListener('click', this.onBodyClick); 28 | } 29 | 30 | close() { 31 | this.notification.classList.remove('active'); 32 | document.body.removeEventListener('click', this.onBodyClick); 33 | 34 | removeTrapFocus(this.activeElement); 35 | } 36 | 37 | renderContents(parsedState) { 38 | this.cartItemKey = parsedState.key; 39 | this.getSectionsToRender().forEach((section) => { 40 | document.getElementById(section.id).innerHTML = this.getSectionInnerHTML( 41 | parsedState.sections[section.id], 42 | section.selector 43 | ); 44 | }); 45 | 46 | if (this.header) this.header.reveal(); 47 | this.open(); 48 | } 49 | 50 | getSectionsToRender() { 51 | return [ 52 | { 53 | id: 'cart-notification-product', 54 | selector: `[id="cart-notification-product-${this.cartItemKey}"]`, 55 | }, 56 | { 57 | id: 'cart-notification-button', 58 | }, 59 | { 60 | id: 'cart-icon-bubble', 61 | }, 62 | ]; 63 | } 64 | 65 | getSectionInnerHTML(html, selector = '.shopify-section') { 66 | return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML; 67 | } 68 | 69 | handleBodyClick(evt) { 70 | const target = evt.target; 71 | if (target !== this.notification && !target.closest('cart-notification')) { 72 | const disclosure = target.closest('details-disclosure, header-menu'); 73 | this.activeElement = disclosure ? disclosure.querySelector('summary') : null; 74 | this.close(); 75 | } 76 | } 77 | 78 | setActiveElement(element) { 79 | this.activeElement = element; 80 | } 81 | } 82 | 83 | customElements.define('cart-notification', CartNotification); 84 | -------------------------------------------------------------------------------- /assets/collapsible-content.css: -------------------------------------------------------------------------------- 1 | .collapsible-content { 2 | position: relative; 3 | z-index: 0; 4 | } 5 | 6 | .collapsible-section-layout { 7 | padding-bottom: 5rem; 8 | padding-top: 5rem; 9 | } 10 | 11 | @media screen and (min-width: 750px) { 12 | .collapsible-section-layout { 13 | padding-bottom: 7rem; 14 | padding-top: 7rem; 15 | } 16 | } 17 | 18 | /* Needed for gradient continuity with or without animation so that transparent PNG images come up as we would expect */ 19 | .collapsible-content__media { 20 | background: transparent; 21 | } 22 | 23 | .collapsible-content__media--small { 24 | height: 19.4rem; 25 | } 26 | 27 | .collapsible-content__media--large { 28 | height: 43.5rem; 29 | } 30 | 31 | @media screen and (min-width: 750px) { 32 | .collapsible-content__media--small { 33 | height: 31.4rem; 34 | } 35 | 36 | .collapsible-content__media--large { 37 | height: 69.5rem; 38 | } 39 | } 40 | 41 | @media screen and (min-width: 750px) { 42 | .collapsible-content__grid--reverse { 43 | flex-direction: row-reverse; 44 | } 45 | } 46 | 47 | .collapsible-content-wrapper-narrow { 48 | margin: 0 auto; 49 | padding-right: 1.5rem; 50 | padding-left: 1.5rem; 51 | max-width: 73.4rem; 52 | } 53 | 54 | .collapsible-content__header { 55 | word-break: break-word; 56 | } 57 | 58 | .collapsible-content__heading { 59 | margin-bottom: 2rem; 60 | margin-top: 0; 61 | } 62 | 63 | @media screen and (min-width: 750px) { 64 | .collapsible-content__heading { 65 | margin-bottom: 3rem; 66 | } 67 | } 68 | 69 | .collapsible-none-layout .accordion + .accordion { 70 | border-top: 0; 71 | } 72 | 73 | .collapsible-row-layout .accordion:not(:first-child):not(.color-scheme-1) { 74 | margin-top: 1rem; 75 | } 76 | 77 | .caption-with-letter-spacing + h2 { 78 | margin-top: 1rem; 79 | } 80 | 81 | @media screen and (min-width: 750px) { 82 | .collapsible-content .accordion { 83 | margin-top: 0; 84 | } 85 | } 86 | 87 | .collapsible-row-layout .accordion { 88 | border: var(--text-boxes-border-width) solid rgba(var(--color-foreground), var(--text-boxes-border-opacity)); 89 | margin-bottom: 1.5rem; 90 | /* Needed for gradient continuity with or without animation, the transform scopes the gradient to its container which happens already when animation are turned on */ 91 | transform: perspective(0); 92 | } 93 | 94 | .collapsible-row-layout .accordion summary, 95 | .collapsible-row-layout .accordion .accordion__content { 96 | padding: 1.5rem; 97 | } 98 | 99 | .collapsible-row-layout .accordion .accordion__content { 100 | padding-top: 0; 101 | } 102 | 103 | .collapsible-content summary:hover { 104 | background: rgba(var(--color-foreground), 0.04); 105 | } 106 | 107 | .collapsible-content summary:hover .accordion__title { 108 | text-decoration: underline; 109 | text-underline-offset: 0.3rem; 110 | } 111 | 112 | /* check for flexbox gap in older Safari versions */ 113 | @supports not (inset: 10px) { 114 | @media screen and (min-width: 750px) { 115 | .collapsible-content__grid:not(.collapsible-content__grid--reverse) .grid__item:last-child, 116 | .collapsible-content__grid--reverse .collapsible-content__grid-item { 117 | padding-left: 5rem; 118 | padding-right: 0; 119 | } 120 | } 121 | 122 | @media screen and (min-width: 990px) { 123 | .collapsible-content__grid:not(.collapsible-content__grid--reverse) .grid__item:last-child, 124 | .collapsible-content__grid--reverse .collapsible-content__grid-item { 125 | padding-left: 7rem; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /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 .summary__title + .icon-caret { 14 | height: calc(var(--font-heading-scale) * 0.6rem); 15 | } 16 | 17 | .accordion + .accordion { 18 | margin-top: 0; 19 | border-top: none; 20 | } 21 | 22 | .accordion { 23 | margin-top: 2.5rem; 24 | margin-bottom: 0; 25 | border-top: 0.1rem solid rgba(var(--color-foreground), 0.08); 26 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.08); 27 | } 28 | 29 | .accordion__title { 30 | display: inline-block; 31 | max-width: calc(100% - 6rem); 32 | min-height: 1.6rem; 33 | margin: 0; 34 | word-break: break-word; 35 | } 36 | 37 | .accordion .svg-wrapper { 38 | align-self: center; 39 | fill: rgb(var(--color-foreground)); 40 | height: calc(var(--font-heading-scale) * 2rem); 41 | margin-right: calc(var(--font-heading-scale) * 1rem); 42 | width: calc(var(--font-heading-scale) * 2rem); 43 | } 44 | 45 | .accordion details[open] > summary .icon-caret { 46 | transform: rotate(180deg); 47 | } 48 | 49 | .accordion__content { 50 | margin-bottom: 1.5rem; 51 | word-break: break-word; 52 | overflow-x: auto; 53 | padding: 0 0.6rem; 54 | } 55 | 56 | .accordion__content img { 57 | max-width: 100%; 58 | } 59 | -------------------------------------------------------------------------------- /assets/component-article-card.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width: 749px) { 2 | .articles-wrapper .article { 3 | width: 100%; 4 | } 5 | } 6 | 7 | .article { 8 | display: flex; 9 | align-items: center; 10 | } 11 | 12 | .article.grid__item { 13 | padding: 0; 14 | } 15 | 16 | .grid--peek .article-card { 17 | box-sizing: border-box; 18 | } 19 | 20 | .article-card__image-wrapper > a { 21 | display: block; 22 | } 23 | 24 | .article-card__title { 25 | text-decoration: none; 26 | word-break: break-word; 27 | } 28 | 29 | .article-card__title a:after { 30 | bottom: 0; 31 | content: ''; 32 | height: 100%; 33 | left: 0; 34 | position: absolute; 35 | right: 0; 36 | top: 0; 37 | width: 100%; 38 | z-index: 1; 39 | } 40 | 41 | .article-card__link.link { 42 | padding: 0; 43 | } 44 | 45 | .article-card__link { 46 | text-underline-offset: 0.3rem; 47 | } 48 | 49 | .article-card .card__heading { 50 | margin-bottom: 0.6rem; 51 | } 52 | 53 | .blog-articles .article-card .card__information, 54 | .blog__posts .article-card .card__information { 55 | padding-left: 2rem; 56 | padding-right: 2rem; 57 | } 58 | 59 | .article-card__info { 60 | padding-top: 0.4rem; 61 | } 62 | 63 | .article-card__footer { 64 | letter-spacing: 0.1rem; 65 | font-size: 1.4rem; 66 | } 67 | 68 | .article-card__footer:not(:last-child) { 69 | margin-bottom: 1rem; 70 | } 71 | 72 | .article-card__footer:last-child { 73 | margin-top: auto; 74 | } 75 | 76 | .article-card__excerpt { 77 | width: 100%; 78 | margin-top: 1.2rem; 79 | } 80 | 81 | .article-card__link:not(:only-child) { 82 | margin-right: 3rem; 83 | } 84 | 85 | @media screen and (min-width: 990px) { 86 | .article-card__link:not(:only-child) { 87 | margin-right: 4rem; 88 | } 89 | } 90 | 91 | .article-card__image--small .ratio::before { 92 | padding-bottom: 11rem; 93 | } 94 | 95 | .article-card__image--medium .ratio::before { 96 | padding-bottom: 22rem; 97 | } 98 | 99 | .article-card__image--large .ratio::before { 100 | padding-bottom: 33rem; 101 | } 102 | 103 | @media screen and (min-width: 750px) { 104 | .article-card__image--small .ratio::before { 105 | padding-bottom: 14.3rem; 106 | } 107 | 108 | .article-card__image--medium .ratio::before { 109 | padding-bottom: 21.9rem; 110 | } 111 | 112 | .article-card__image--large .ratio::before { 113 | padding-bottom: 27.5rem; 114 | } 115 | } 116 | 117 | @media screen and (min-width: 990px) { 118 | .article-card__image--small .ratio::before { 119 | padding-bottom: 17.7rem; 120 | } 121 | 122 | .article-card__image--medium .ratio::before { 123 | padding-bottom: 30.7rem; 124 | } 125 | 126 | .article-card__image--large .ratio::before { 127 | padding-bottom: 40.7rem; 128 | } 129 | } 130 | 131 | /* check for flexbox gap in older Safari versions */ 132 | @supports not (inset: 10px) { 133 | .articles-wrapper.grid { 134 | margin: 0 0 5rem 0; 135 | } 136 | 137 | @media screen and (min-width: 750px) { 138 | .articles-wrapper.grid { 139 | margin-bottom: 7rem; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /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 | border-bottom-right-radius: var(--popup-corner-radius); 11 | border-bottom-left-radius: var(--popup-corner-radius); 12 | border-color: rgba(var(--color-foreground), var(--popup-border-opacity)); 13 | border-style: solid; 14 | border-width: 0 0 var(--popup-border-width); 15 | padding: 2.5rem 3.5rem; 16 | position: absolute; 17 | right: 0; 18 | transform: translateY(-100%); 19 | visibility: hidden; 20 | width: 100%; 21 | box-shadow: var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) 22 | rgba(var(--color-shadow), var(--popup-shadow-opacity)); 23 | z-index: -1; 24 | } 25 | 26 | .cart-notification.focused { 27 | box-shadow: 0 0 0.2rem 0 rgba(var(--color-foreground), 0.3), 28 | var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) 29 | rgba(var(--color-shadow), var(--popup-shadow-opacity)); 30 | } 31 | 32 | .cart-notification:focus-visible { 33 | box-shadow: 0 0 0.2rem 0 rgba(var(--color-foreground), 0.3), 34 | var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) 35 | rgba(var(--color-shadow), var(--popup-shadow-opacity)); 36 | } 37 | 38 | @media screen and (min-width: 750px) { 39 | .header-wrapper:not(.header-wrapper--border-bottom) + cart-notification .cart-notification { 40 | border-top-width: var(--popup-border-width); 41 | } 42 | 43 | .cart-notification { 44 | border-width: 0 var(--popup-border-width) var(--popup-border-width); 45 | max-width: 36.8rem; 46 | right: 2.2rem; 47 | } 48 | } 49 | 50 | @media screen and (min-width: 990px) { 51 | .cart-notification-wrapper:is(.page-width) > .cart-notification { 52 | right: 4rem; 53 | } 54 | } 55 | 56 | .cart-notification.animate { 57 | transition: transform var(--duration-short) ease, visibility 0s var(--duration-short) ease; 58 | } 59 | 60 | .cart-notification.active { 61 | transform: translateY(0); 62 | transition: transform var(--duration-default) ease, visibility 0s; 63 | visibility: visible; 64 | } 65 | 66 | .cart-notification__header { 67 | align-items: flex-start; 68 | display: flex; 69 | } 70 | 71 | .cart-notification__heading { 72 | align-items: center; 73 | display: flex; 74 | flex-grow: 1; 75 | margin-bottom: 0; 76 | margin-top: 0; 77 | } 78 | 79 | .cart-notification__heading .icon-checkmark { 80 | color: rgb(var(--color-foreground)); 81 | margin-right: 1rem; 82 | width: 1.3rem; 83 | } 84 | 85 | .cart-notification__close { 86 | margin-top: -2rem; 87 | margin-right: -3rem; 88 | } 89 | 90 | .cart-notification__links { 91 | text-align: center; 92 | } 93 | 94 | .cart-notification__links > * { 95 | margin-top: 1rem; 96 | } 97 | 98 | .cart-notification-product { 99 | align-items: flex-start; 100 | display: flex; 101 | padding-bottom: 3rem; 102 | padding-top: 2rem; 103 | } 104 | 105 | .cart-notification-product dl { 106 | margin-bottom: 0; 107 | margin-top: 0; 108 | } 109 | 110 | .cart-notification-product__image { 111 | display: inline-flex; 112 | margin-right: 1.5rem; 113 | margin-top: 0.5rem; 114 | } 115 | 116 | .cart-notification-product__image:after { 117 | content: none; 118 | } 119 | 120 | .cart-notification-product__name { 121 | margin-bottom: 0.5rem; 122 | margin-top: 0; 123 | } 124 | -------------------------------------------------------------------------------- /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: 3rem 0 1rem; 22 | } 23 | 24 | .cart__empty-text { 25 | margin: 4.5rem 0 2rem; 26 | } 27 | 28 | .cart__contents > * + * { 29 | margin-top: 2.5rem; 30 | } 31 | 32 | .cart__login-title { 33 | margin: 5.5rem 0 0.5rem; 34 | } 35 | 36 | .cart__login-paragraph { 37 | margin-top: 0.8rem; 38 | } 39 | 40 | .cart__login-paragraph a { 41 | font-size: inherit; 42 | } 43 | 44 | @media screen and (min-width: 990px) { 45 | .cart__warnings { 46 | padding: 7rem 0 1rem; 47 | } 48 | 49 | .cart__empty-text { 50 | margin: 0 0 3rem; 51 | } 52 | } 53 | 54 | cart-items { 55 | display: block; 56 | } 57 | 58 | .cart__items { 59 | position: relative; 60 | padding-bottom: 3rem; 61 | border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.08); 62 | } 63 | 64 | .cart__items--disabled { 65 | pointer-events: none; 66 | } 67 | 68 | .cart__footer-wrapper:last-child .cart__footer { 69 | padding-bottom: 5rem; 70 | } 71 | 72 | .cart__footer > div:only-child { 73 | margin-left: auto; 74 | } 75 | 76 | .cart__footer > * + * { 77 | margin-top: 6.5rem; 78 | } 79 | 80 | .cart__footer .discounts { 81 | margin-bottom: 1rem; 82 | } 83 | 84 | .cart__note { 85 | height: fit-content; 86 | top: 2.5rem; 87 | } 88 | 89 | .cart__note label { 90 | display: flex; 91 | align-items: flex-end; 92 | position: absolute; 93 | line-height: 1; 94 | height: 1.8rem; 95 | top: -3rem; 96 | color: rgba(var(--color-foreground), 0.75); 97 | } 98 | 99 | .cart__note .field__input { 100 | height: 100%; 101 | position: relative; 102 | border-radius: var(--inputs-radius); 103 | padding: 1rem 2rem; 104 | } 105 | 106 | .cart__note .text-area { 107 | resize: vertical; 108 | } 109 | 110 | .cart__note:after, 111 | .cart__note:hover.cart__note:after, 112 | .cart__note:before, 113 | .cart__note:hover.cart__note:before, 114 | .cart__note .field__input:focus, 115 | .cart__note .field__input { 116 | border-bottom-right-radius: 0; 117 | } 118 | 119 | @media screen and (min-width: 750px) { 120 | .cart__items { 121 | grid-column-start: 1; 122 | grid-column-end: 3; 123 | padding-bottom: 4rem; 124 | } 125 | 126 | .cart__contents > * + * { 127 | margin-top: 0; 128 | } 129 | 130 | .cart__items + .cart__footer { 131 | grid-column: 2; 132 | } 133 | 134 | .cart__footer { 135 | display: flex; 136 | justify-content: space-between; 137 | border: 0; 138 | } 139 | 140 | .cart__footer-wrapper:last-child { 141 | padding-top: 0; 142 | } 143 | 144 | .cart__footer > * { 145 | width: 35rem; 146 | } 147 | 148 | .cart__footer > * + * { 149 | margin-left: 4rem; 150 | margin-top: 0; 151 | } 152 | } 153 | 154 | .cart__ctas button { 155 | width: 100%; 156 | } 157 | 158 | .cart__ctas > * + * { 159 | margin-top: 1rem; 160 | } 161 | 162 | .cart__update-button { 163 | margin-bottom: 1rem; 164 | } 165 | 166 | .cart__dynamic-checkout-buttons { 167 | max-width: 36rem; 168 | margin: 0 auto; 169 | } 170 | 171 | .cart__dynamic-checkout-buttons:has(.dynamic-checkout__content:empty) { 172 | margin: 0; 173 | } 174 | 175 | .cart__blocks > * + * { 176 | margin-top: 1rem; 177 | } 178 | 179 | .cart-note__label { 180 | display: inline-block; 181 | margin-bottom: 1rem; 182 | line-height: calc(1 + 1 / var(--font-body-scale)); 183 | } 184 | 185 | .tax-note { 186 | margin: 2.2rem 0 1.6rem auto; 187 | text-align: center; 188 | display: block; 189 | } 190 | 191 | .cart__checkout-button { 192 | max-width: 36rem; 193 | } 194 | 195 | .cart__ctas { 196 | text-align: center; 197 | } 198 | 199 | @media screen and (min-width: 750px) { 200 | .cart-note { 201 | max-width: 35rem; 202 | } 203 | 204 | .cart__update-button { 205 | margin-bottom: 0; 206 | margin-right: 0.8rem; 207 | } 208 | 209 | .tax-note { 210 | margin-bottom: 2.2rem; 211 | text-align: right; 212 | } 213 | 214 | [data-shopify-buttoncontainer] { 215 | justify-content: flex-end; 216 | } 217 | 218 | .cart__ctas { 219 | display: flex; 220 | gap: 1rem; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /assets/component-collection-hero.css: -------------------------------------------------------------------------------- 1 | .collection-hero__inner { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .collection-hero--with-image .collection-hero__inner { 7 | margin-bottom: 0; 8 | padding-bottom: 2rem; 9 | } 10 | 11 | @media screen and (min-width: 750px) { 12 | .collection-hero.collection-hero--with-image { 13 | padding: calc(4rem + var(--page-width-margin)) 0 calc(4rem + var(--page-width-margin)); 14 | overflow: hidden; 15 | } 16 | 17 | .collection-hero--with-image .collection-hero__inner { 18 | padding-bottom: 0; 19 | } 20 | } 21 | 22 | .collection-hero__text-wrapper { 23 | flex-basis: 100%; 24 | } 25 | 26 | @media screen and (min-width: 750px) { 27 | .collection-hero { 28 | padding: 0; 29 | } 30 | 31 | .collection-hero__inner { 32 | align-items: center; 33 | flex-direction: row; 34 | padding-bottom: 0; 35 | } 36 | } 37 | 38 | .collection-hero__title { 39 | margin: 2.5rem 0; 40 | } 41 | 42 | .collection-hero__title + .collection-hero__description { 43 | margin-top: 1.5rem; 44 | margin-bottom: 1.5rem; 45 | font-size: 1.6rem; 46 | line-height: calc(1 + 0.5 / var(--font-body-scale)); 47 | } 48 | 49 | @media screen and (min-width: 750px) { 50 | .collection-hero__title + .collection-hero__description { 51 | font-size: 1.8rem; 52 | margin-top: 2rem; 53 | margin-bottom: 2rem; 54 | } 55 | 56 | .collection-hero__description { 57 | max-width: 66.67%; 58 | } 59 | 60 | .collection-hero--with-image .collection-hero__description { 61 | max-width: 100%; 62 | } 63 | } 64 | 65 | .collection-hero--with-image .collection-hero__title { 66 | margin: 0; 67 | } 68 | 69 | .collection-hero--with-image .collection-hero__text-wrapper { 70 | padding: 5rem 0 4rem; 71 | } 72 | 73 | .collection-hero__image-container { 74 | border: var(--media-border-width) solid rgba(var(--color-foreground), var(--media-border-opacity)); 75 | border-radius: var(--media-radius); 76 | box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) 77 | rgba(var(--color-shadow), var(--media-shadow-opacity)); 78 | } 79 | 80 | @media screen and (max-width: 749px) { 81 | .collection-hero__image-container { 82 | height: 20rem; 83 | } 84 | } 85 | 86 | @media screen and (min-width: 750px) { 87 | .collection-hero--with-image .collection-hero__text-wrapper { 88 | padding: 4rem 2rem 4rem 0; 89 | flex-basis: 50%; 90 | } 91 | 92 | .collection-hero__image-container { 93 | align-self: stretch; 94 | flex: 1 0 50%; 95 | margin-left: 3rem; 96 | min-height: 20rem; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /assets/component-complementary-products.css: -------------------------------------------------------------------------------- 1 | .complementary-products__container { 2 | display: flex; 3 | flex-direction: column; 4 | gap: 1.3rem; 5 | } 6 | 7 | product-recommendations:not(.is-accordion) .complementary-products__container { 8 | margin-top: 1.5rem; 9 | } 10 | 11 | .complementary-products__container > details[open] { 12 | padding-bottom: 1.5rem; 13 | } 14 | 15 | .complementary-slider { 16 | margin-top: 0; 17 | gap: 0; 18 | } 19 | 20 | .complementary-slide { 21 | --shadow-padding-sides: calc((var(--shadow-horizontal-offset) + var(--shadow-blur-radius)) * var(--shadow-visible)); 22 | --shadow-padding-sides-negative: calc( 23 | (var(--shadow-horizontal-offset) * -1 + var(--shadow-blur-radius)) * var(--shadow-visible) 24 | ); 25 | } 26 | 27 | .complementary-slide > ul { 28 | display: flex; 29 | flex-direction: column; 30 | gap: var(--grid-mobile-vertical-spacing); 31 | } 32 | 33 | .complementary-slide.complementary-slide--standard > ul { 34 | gap: calc(var(--grid-mobile-vertical-spacing) + 8px); 35 | } 36 | 37 | @media screen and (min-width: 750px) { 38 | .complementary-slide > ul { 39 | gap: var(--grid-desktop-vertical-spacing); 40 | } 41 | 42 | .complementary-slide.complementary-slide--standard > ul { 43 | gap: calc(var(--grid-desktop-vertical-spacing) + 8px); 44 | } 45 | } 46 | 47 | .complementary-slide.grid__item { 48 | width: 100%; 49 | padding-top: max(var(--focus-outline-padding), var(--shadow-padding-top)); 50 | padding-bottom: max(var(--focus-outline-padding), var(--shadow-padding-bottom)); 51 | padding-right: max(var(--focus-outline-padding), var(--shadow-padding-sides)); 52 | padding-left: max(var(--focus-outline-padding), var(--shadow-padding-sides-negative)); 53 | } 54 | 55 | .complementary-slide .card-wrapper { 56 | height: auto; 57 | } 58 | 59 | .complementary-products > .summary__title { 60 | display: flex; 61 | line-height: 1; 62 | padding: 1.5rem 0; 63 | } 64 | 65 | .accordion + product-recommendations .accordion, 66 | product-recommendations.is-accordion + .accordion { 67 | margin-top: 0; 68 | border-top: none; 69 | } 70 | 71 | .complementary-products > .summary__title .icon-accordion { 72 | fill: rgb(var(--color-foreground)); 73 | height: calc(var(--font-heading-scale) * 2rem); 74 | margin-right: calc(var(--font-heading-scale) * 1rem); 75 | width: calc(var(--font-heading-scale) * 2rem); 76 | } 77 | 78 | .complementary-products__container .card--card .card__content, 79 | .complementary-products__container .card--horizontal .card__information { 80 | padding: 0; 81 | } 82 | 83 | .complementary-products__container .card--horizontal .card__inner { 84 | max-width: 20%; 85 | } 86 | 87 | @media screen and (min-width: 750px) and (max-width: 1200px) { 88 | .complementary-products__container .card--horizontal .card__inner { 89 | max-width: 25%; 90 | } 91 | } 92 | 93 | .complementary-slide .card--text .card__content { 94 | grid-template-rows: minmax(0, 1fr) max-content auto; 95 | } 96 | 97 | .complementary-products__container .card--card.card--media > .card__content { 98 | margin-top: 0; 99 | } 100 | 101 | .complementary-products-contains-quick-add .underline-links-hover:hover a { 102 | text-decoration: initial; 103 | } 104 | 105 | .complementary-products-contains-quick-add .card__heading:hover a { 106 | text-decoration: underline; 107 | } 108 | 109 | .complementary-products__container .card--card .card__inner .card__media { 110 | border-radius: calc(var(--corner-radius) - var(--border-width) - var(--image-padding)); 111 | } 112 | 113 | .complementary-products__container .card--horizontal .quick-add { 114 | margin: 0; 115 | max-width: 20rem; 116 | } 117 | 118 | .complementary-products__container .quick-add__submit { 119 | padding: 1.5rem 0; 120 | min-height: inherit; 121 | } 122 | 123 | .complementary-products__container .quick-add__submit .icon-plus { 124 | width: 1.2rem; 125 | } 126 | 127 | .complementary-products__container .icon-wrap { 128 | display: flex; 129 | } 130 | 131 | .complementary-products .sold-out-message:not(.hidden) + .icon-wrap { 132 | display: none; 133 | } 134 | 135 | .complementary-products__container .quick-add__submit:not(.animate-arrow) .icon-wrap { 136 | transition: transform var(--duration-short) ease; 137 | } 138 | 139 | .complementary-products__container .quick-add__submit:not(.animate-arrow):hover .icon-wrap { 140 | transform: rotate(90deg); 141 | } 142 | 143 | .complementary-products__container .quick-add__submit:after, 144 | .complementary-products__container .quick-add__submit:hover:after { 145 | box-shadow: none; 146 | } 147 | 148 | .complementary-products__container .card--horizontal .quick-add, 149 | .complementary-products__container .card__badge { 150 | justify-self: var(--text-alignment); 151 | } 152 | 153 | .product--no-media .complementary-products__container .price { 154 | text-align: var(--text-alignment); 155 | } 156 | 157 | @media screen and (min-width: 750px) { 158 | .complementary-products__container .price--on-sale .price-item--regular { 159 | font-size: 1.3rem; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /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 | overflow: hidden; 10 | border-radius: calc(var(--border-radius) - var(--border-width)); 11 | } 12 | 13 | .media > .deferred-media__poster { 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | 19 | .deferred-media__poster img { 20 | width: auto; 21 | max-width: 100%; 22 | height: 100%; 23 | } 24 | 25 | .deferred-media { 26 | overflow: hidden; 27 | } 28 | 29 | .deferred-media:not([loaded]) template { 30 | z-index: -1; 31 | } 32 | 33 | .deferred-media[loaded] > .deferred-media__poster { 34 | display: none; 35 | } 36 | 37 | .deferred-media__poster:focus-visible { 38 | outline: none; 39 | box-shadow: 0 0 0 var(--media-border-width) rgba(var(--color-foreground), var(--media-border-opacity)), 40 | 0 0 0 calc(var(--media-border-width) + 0.3rem) rgb(var(--color-background)), 41 | 0 0 0 calc(var(--media-border-width) + 0.5rem) rgba(var(--color-foreground), 0.5); 42 | border-radius: calc(var(--media-radius) - var(--media-border-width)); 43 | } 44 | 45 | .deferred-media__poster:focus { 46 | outline: none; 47 | box-shadow: 0 0 0 var(--media-border-width) rgba(var(--color-foreground), var(--media-border-opacity)), 48 | 0 0 0 calc(var(--media-border-width) + 0.3rem) rgb(var(--color-background)), 49 | 0 0 0 calc(var(--media-border-width) + 0.5rem) rgba(var(--color-foreground), 0.5); 50 | border-radius: calc(var(--media-radius) - var(--media-border-width)); 51 | } 52 | 53 | .global-media-settings--full-width .deferred-media__poster, 54 | .global-media-settings--full-width .deferred-media__poster:is(:focus, :focus-visible) { 55 | border-radius: 0; 56 | } 57 | 58 | /* outline styling for Windows High Contrast Mode */ 59 | @media (forced-colors: active) { 60 | .deferred-media__poster:focus { 61 | outline: transparent solid 1px; 62 | } 63 | } 64 | .deferred-media__poster:focus:not(:focus-visible) { 65 | outline: 0; 66 | box-shadow: none; 67 | } 68 | 69 | .deferred-media__poster-button { 70 | background-color: rgb(var(--color-background)); 71 | border: 0.1rem solid rgba(var(--color-foreground), 0.1); 72 | border-radius: 50%; 73 | color: rgb(var(--color-foreground)); 74 | display: flex; 75 | align-items: center; 76 | justify-content: center; 77 | height: 6.2rem; 78 | width: 6.2rem; 79 | position: absolute; 80 | left: 50%; 81 | top: 50%; 82 | transform: translate(-50%, -50%) scale(1); 83 | transition: transform var(--duration-short) ease, color var(--duration-short) ease; 84 | z-index: 1; 85 | } 86 | 87 | .deferred-media__poster-button:hover { 88 | transform: translate(-50%, -50%) scale(1.1); 89 | } 90 | 91 | .deferred-media__poster-button .icon { 92 | width: 2rem; 93 | height: 2rem; 94 | } 95 | 96 | .deferred-media__poster-button .icon-play { 97 | margin-left: 0.2rem; 98 | } 99 | -------------------------------------------------------------------------------- /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: calc(1 + 0.5 / var(--font-body-scale)); 9 | } 10 | 11 | .discounts__discount svg { 12 | color: rgba(var(--color-button), var(--alpha-button-background)); 13 | } 14 | 15 | .discounts__discount--position { 16 | justify-content: center; 17 | } 18 | 19 | @media screen and (min-width: 750px) { 20 | .discounts__discount--position { 21 | justify-content: flex-end; 22 | } 23 | } 24 | 25 | .discounts__discount > .icon { 26 | color: rgb(var(--color-foreground)); 27 | width: 1.2rem; 28 | height: 1.2rem; 29 | margin-right: 0.7rem; 30 | } 31 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/component-mega-menu.css: -------------------------------------------------------------------------------- 1 | .mega-menu { 2 | position: static; 3 | } 4 | 5 | .mega-menu__content { 6 | background-color: rgb(var(--color-background)); 7 | border-left: 0; 8 | border-radius: 0; 9 | border-right: 0; 10 | left: 0; 11 | overflow-y: auto; 12 | padding-bottom: 3rem; 13 | padding-top: 3rem; 14 | position: absolute; 15 | right: 0; 16 | top: 100%; 17 | } 18 | 19 | .shopify-section-header-sticky .mega-menu__content { 20 | max-height: calc(100vh - var(--header-bottom-position-desktop, 20rem) - 4rem); 21 | } 22 | 23 | .header-wrapper--border-bottom .mega-menu__content { 24 | border-top: 0; 25 | } 26 | 27 | .js .mega-menu__content { 28 | opacity: 0; 29 | transform: translateY(-1.5rem); 30 | } 31 | 32 | .mega-menu[open] .mega-menu__content { 33 | opacity: 1; 34 | transform: translateY(0); 35 | } 36 | 37 | .mega-menu__list { 38 | display: grid; 39 | gap: 1.8rem 4rem; 40 | grid-template-columns: repeat(6, minmax(0, 1fr)); 41 | list-style: none; 42 | } 43 | 44 | .mega-menu__link { 45 | color: rgba(var(--color-foreground), 0.75); 46 | display: block; 47 | line-height: calc(1 + 0.3 / var(--font-body-scale)); 48 | padding-bottom: 0.6rem; 49 | padding-top: 0.6rem; 50 | text-decoration: none; 51 | transition: text-decoration var(--duration-short) ease; 52 | word-wrap: break-word; 53 | } 54 | 55 | .mega-menu__link--level-2 { 56 | font-weight: bold; 57 | } 58 | 59 | .header--top-center .mega-menu__list { 60 | display: flex; 61 | justify-content: center; 62 | flex-wrap: wrap; 63 | column-gap: 0; 64 | } 65 | 66 | .header--top-center .mega-menu__list > li { 67 | width: 16%; 68 | padding-right: 2.4rem; 69 | } 70 | 71 | .mega-menu__link:hover, 72 | .mega-menu__link--active { 73 | color: rgb(var(--color-foreground)); 74 | text-decoration: underline; 75 | } 76 | 77 | .mega-menu__link--active:hover { 78 | text-decoration-thickness: 0.2rem; 79 | } 80 | 81 | .mega-menu .mega-menu__list--condensed { 82 | display: block; 83 | } 84 | 85 | .mega-menu__list--condensed .mega-menu__link { 86 | font-weight: normal; 87 | } 88 | -------------------------------------------------------------------------------- /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: 0.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 | -------------------------------------------------------------------------------- /assets/component-pagination.css: -------------------------------------------------------------------------------- 1 | .pagination-wrapper { 2 | margin-top: 4rem; 3 | } 4 | 5 | @media screen and (min-width: 990px) { 6 | .pagination-wrapper { 7 | margin-top: 5rem; 8 | } 9 | } 10 | 11 | .pagination__list { 12 | display: flex; 13 | flex-wrap: wrap; 14 | justify-content: center; 15 | } 16 | 17 | .pagination__list > li { 18 | flex: 1 0 4.4rem; 19 | max-width: 4.4rem; 20 | } 21 | 22 | .pagination__list > li:not(:last-child) { 23 | margin-right: 1rem; 24 | } 25 | 26 | .pagination__item { 27 | color: rgb(var(--color-foreground)); 28 | display: inline-flex; 29 | justify-content: center; 30 | align-items: center; 31 | position: relative; 32 | height: 4.4rem; 33 | width: 100%; 34 | padding: 0; 35 | text-decoration: none; 36 | } 37 | 38 | a.pagination__item:hover::after { 39 | height: 0.1rem; 40 | } 41 | 42 | .pagination__item .icon-caret { 43 | height: 0.6rem; 44 | } 45 | 46 | .pagination__item--current::after { 47 | height: 0.1rem; 48 | } 49 | 50 | .pagination__item--current::after, 51 | .pagination__item:hover::after { 52 | content: ''; 53 | display: block; 54 | width: 2rem; 55 | position: absolute; 56 | bottom: 8px; 57 | left: 50%; 58 | transform: translateX(-50%); 59 | background-color: currentColor; 60 | } 61 | 62 | .pagination__item--next .icon { 63 | margin-left: -0.2rem; 64 | transform: rotate(90deg); 65 | } 66 | 67 | .pagination__item--next:hover .icon { 68 | transform: rotate(90deg) scale(1.07); 69 | } 70 | 71 | .pagination__item--prev .icon { 72 | margin-right: -0.2rem; 73 | transform: rotate(-90deg); 74 | } 75 | 76 | .pagination__item--prev:hover .icon { 77 | transform: rotate(-90deg) scale(1.07); 78 | } 79 | 80 | .pagination__item-arrow:hover::after { 81 | display: none; 82 | } 83 | -------------------------------------------------------------------------------- /assets/component-price.css: -------------------------------------------------------------------------------- 1 | .price { 2 | font-size: 1.6rem; 3 | letter-spacing: 0.1rem; 4 | line-height: calc(1 + 0.5 / var(--font-body-scale)); 5 | color: rgb(var(--color-foreground)); 6 | } 7 | 8 | .price > * { 9 | display: inline-block; 10 | vertical-align: top; 11 | } 12 | 13 | .price.price--unavailable { 14 | visibility: hidden; 15 | } 16 | 17 | .price--end { 18 | text-align: right; 19 | } 20 | 21 | .price .price-item { 22 | display: inline-block; 23 | margin: 0 1rem 0 0; 24 | } 25 | 26 | .price__regular .price-item--regular { 27 | margin-right: 0; 28 | } 29 | 30 | .price:not(.price--show-badge) .price-item--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: calc(1 + 0.5 / var(--font-body-scale)); 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 | display: none; 64 | } 65 | 66 | .price--sold-out .price__badge-sold-out, 67 | .price--on-sale .price__badge-sale, 68 | .volume-pricing--sale-badge .price__badge-sale { 69 | display: inline-block; 70 | } 71 | 72 | .volume-pricing--sale-badge .price__badge-sale { 73 | margin-left: 0.5rem; 74 | } 75 | 76 | .price--on-sale .price__sale { 77 | display: initial; 78 | flex-direction: row; 79 | flex-wrap: wrap; 80 | } 81 | 82 | .price--center { 83 | display: initial; 84 | justify-content: center; 85 | } 86 | 87 | .price--on-sale .price-item--regular { 88 | text-decoration: line-through; 89 | color: rgba(var(--color-foreground), 0.75); 90 | font-size: 1.3rem; 91 | } 92 | 93 | .unit-price { 94 | display: block; 95 | font-size: 1.1rem; 96 | letter-spacing: 0.04rem; 97 | line-height: calc(1 + 0.2 / var(--font-body-scale)); 98 | margin-top: 0.2rem; 99 | text-transform: uppercase; 100 | color: rgba(var(--color-foreground), 0.7); 101 | } 102 | -------------------------------------------------------------------------------- /assets/component-product-model.css: -------------------------------------------------------------------------------- 1 | .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 | display: flex; 7 | } 8 | 9 | .button.product__xr-button:hover { 10 | box-shadow: none; 11 | } 12 | 13 | .product__xr-button[data-shopify-xr-hidden] { 14 | visibility: hidden; 15 | } 16 | 17 | .shopify-design-mode .product__xr-button[data-shopify-xr-hidden] { 18 | display: none; 19 | } 20 | 21 | @media screen and (max-width: 749px) { 22 | slider-component .product__xr-button { 23 | display: none; 24 | } 25 | 26 | .active .product__xr-button:not([data-shopify-xr-hidden]) { 27 | display: block; 28 | } 29 | } 30 | 31 | @media screen and (min-width: 750px) { 32 | slider-component + .button.product__xr-button { 33 | display: none; 34 | } 35 | 36 | .product__xr-button[data-shopify-xr-hidden] { 37 | display: none; 38 | } 39 | } 40 | 41 | .product__xr-button .icon { 42 | width: 1.4rem; 43 | margin-right: 1rem; 44 | } 45 | -------------------------------------------------------------------------------- /assets/component-product-variant-picker.css: -------------------------------------------------------------------------------- 1 | variant-selects { 2 | display: block; 3 | } 4 | 5 | .product--no-media .product-form__input--pill, 6 | .product--no-media .product-form__input--swatch, 7 | .product--no-media .product-form__input--dropdown { 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | text-align: center; 12 | } 13 | 14 | .product--no-media .product-form__input.product-form__input--pill, 15 | .product--no-media .product-form__input.product-form__input--swatch { 16 | flex-wrap: wrap; 17 | margin: 0 auto 1.2rem auto; 18 | } 19 | 20 | .product--no-media .product-form__input--dropdown { 21 | flex-direction: column; 22 | max-width: 100%; 23 | } 24 | 25 | :is(.product-form__input--pill, .product-form__input--swatch) .form__label { 26 | margin-bottom: 0.2rem; 27 | } 28 | 29 | .product-form__input input[type='radio'] { 30 | clip: rect(0, 0, 0, 0); 31 | overflow: hidden; 32 | position: absolute; 33 | height: 1px; 34 | width: 1px; 35 | } 36 | 37 | .product-form__input input[type='radio']:not(.disabled):not(.visually-disabled) + label > .label-unavailable { 38 | display: none; 39 | } 40 | 41 | .product-form__input--dropdown { 42 | --swatch-input--size: 2rem; 43 | margin-bottom: 1.6rem; 44 | } 45 | 46 | .product-form__input--dropdown .dropdown-swatch + select { 47 | padding-left: calc(2.4rem + var(--swatch-input--size)); 48 | } 49 | 50 | .product-form__input--dropdown .dropdown-swatch { 51 | position: absolute; 52 | left: 1.6rem; 53 | top: calc(50% - var(--swatch-input--size) / 2); 54 | width: var(--swatch-input--size); 55 | height: var(--swatch-input--size); 56 | z-index: 1; 57 | } 58 | 59 | /* Custom styles for Pill display type */ 60 | .product-form__input--pill input[type='radio'] + label { 61 | border: var(--variant-pills-border-width) solid rgba(var(--color-foreground), var(--variant-pills-border-opacity)); 62 | background-color: rgb(var(--color-background)); 63 | color: rgba(var(--color-foreground)); 64 | border-radius: var(--variant-pills-radius); 65 | color: rgb(var(--color-foreground)); 66 | display: inline-block; 67 | margin: 0.7rem 0.5rem 0.2rem 0; 68 | padding: 1rem 2rem; 69 | font-size: 1.4rem; 70 | letter-spacing: 0.1rem; 71 | line-height: 1; 72 | text-align: center; 73 | transition: border var(--duration-short) ease; 74 | cursor: pointer; 75 | position: relative; 76 | } 77 | 78 | .product-form__input--pill input[type='radio'] + label:before { 79 | content: ''; 80 | position: absolute; 81 | top: calc(var(--variant-pills-border-width) * -1); 82 | right: calc(var(--variant-pills-border-width) * -1); 83 | bottom: calc(var(--variant-pills-border-width) * -1); 84 | left: calc(var(--variant-pills-border-width) * -1); 85 | z-index: -1; 86 | border-radius: var(--variant-pills-radius); 87 | box-shadow: var(--variant-pills-shadow-horizontal-offset) var(--variant-pills-shadow-vertical-offset) 88 | var(--variant-pills-shadow-blur-radius) rgba(var(--color-shadow), var(--variant-pills-shadow-opacity)); 89 | } 90 | 91 | .product-form__input--pill input[type='radio'] + label:hover { 92 | border-color: rgb(var(--color-foreground)); 93 | } 94 | 95 | .product-form__input--pill input[type='radio']:checked + label { 96 | background-color: rgb(var(--color-foreground)); 97 | color: rgb(var(--color-background)); 98 | } 99 | 100 | @media screen and (forced-colors: active) { 101 | .product-form__input--pill input[type='radio']:checked + label { 102 | text-decoration: underline; 103 | } 104 | 105 | .product-form__input--pill input[type='radio']:focus-visible + label { 106 | outline: transparent solid 1px; 107 | outline-offset: 2px; 108 | } 109 | } 110 | 111 | .product-form__input--pill input[type='radio']:checked + label::selection { 112 | background-color: rgba(var(--color-background), 0.3); 113 | } 114 | 115 | .product-form__input--pill input[type='radio']:disabled + label, 116 | .product-form__input--pill input[type='radio'].disabled + label { 117 | border-color: rgba(var(--color-foreground), 0.1); 118 | color: rgba(var(--color-foreground), 0.6); 119 | text-decoration: line-through; 120 | } 121 | 122 | .product-form__input--pill input[type='radio'].disabled:checked + label, 123 | .product-form__input--pill input[type='radio']:disabled:checked + label { 124 | color: rgba(var(--color-background), 0.6); 125 | } 126 | .product-form__input--pill input[type='radio']:focus-visible + label { 127 | box-shadow: 0 0 0 0.3rem rgb(var(--color-background)), 0 0 0 0.5rem rgba(var(--color-foreground), 0.55); 128 | } 129 | 130 | /* Fallback */ 131 | .product-form__input--pill input[type='radio'].focused + label { 132 | box-shadow: 0 0 0 0.3rem rgb(var(--color-background)), 0 0 0 0.5rem rgba(var(--color-foreground), 0.55); 133 | } 134 | 135 | /* Custom styles for Swatch display type */ 136 | .product-form__input--swatch { 137 | display: flex; 138 | flex-wrap: wrap; 139 | } 140 | 141 | .product-form__input--swatch .swatch-input__input + .swatch-input__label { 142 | --swatch-input--size: 3.6rem; 143 | 144 | margin: 0.7rem 1.2rem 0.2rem 0; 145 | } 146 | 147 | @media screen and (min-width: 750px) { 148 | .product-form__input--swatch .swatch-input__input + .swatch-input__label { 149 | --swatch-input--size: 2.8rem; 150 | } 151 | } 152 | /* End custom styles for Swatch display type */ 153 | -------------------------------------------------------------------------------- /assets/component-rating.css: -------------------------------------------------------------------------------- 1 | .product--no-media .rating-wrapper { 2 | text-align: center; 3 | } 4 | 5 | .rating { 6 | display: inline-block; 7 | margin: 0; 8 | } 9 | 10 | .product .rating-star { 11 | --letter-spacing: 0.8; 12 | --font-size: 1.7; 13 | } 14 | 15 | .card-wrapper .rating-star { 16 | --letter-spacing: 0.7; 17 | --font-size: 1.4; 18 | } 19 | 20 | .rating-star { 21 | --color-rating-star: rgb(var(--color-foreground)); 22 | --percent: calc( 23 | ( 24 | var(--rating) / var(--rating-max) + var(--rating-decimal) * var(--font-size) / 25 | (var(--rating-max) * (var(--letter-spacing) + var(--font-size))) 26 | ) * 100% 27 | ); 28 | letter-spacing: calc(var(--letter-spacing) * 1rem); 29 | font-size: calc(var(--font-size) * 1rem); 30 | line-height: 1; 31 | display: inline-block; 32 | font-family: Times; 33 | margin: 0; 34 | } 35 | 36 | .rating-star::before { 37 | content: '★★★★★'; 38 | background: linear-gradient( 39 | 90deg, 40 | var(--color-rating-star) var(--percent), 41 | rgba(var(--color-foreground), 0.15) var(--percent) 42 | ); 43 | -webkit-background-clip: text; 44 | -webkit-text-fill-color: transparent; 45 | } 46 | 47 | .rating-text { 48 | display: none; 49 | } 50 | 51 | .rating-count { 52 | display: inline-block; 53 | margin: 0; 54 | } 55 | 56 | @media (forced-colors: active) { 57 | .rating { 58 | display: none; 59 | } 60 | 61 | .rating-text { 62 | display: block; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /assets/component-search.css: -------------------------------------------------------------------------------- 1 | .search__input.field__input { 2 | padding-right: 9.8rem; 3 | } 4 | 5 | .search__button { 6 | right: var(--inputs-border-width); 7 | top: var(--inputs-border-width); 8 | } 9 | 10 | .reset__button { 11 | right: calc(var(--inputs-border-width) + 4.4rem); 12 | top: var(--inputs-border-width); 13 | } 14 | 15 | .reset__button:not(:focus-visible)::after { 16 | border-right: 0.1rem solid rgba(var(--color-foreground), 0.08); 17 | display: block; 18 | height: calc(100% - 1.6rem); 19 | content: ''; 20 | position: absolute; 21 | right: 0; 22 | } 23 | 24 | .reset__button:not(:focus)::after { 25 | border-right: 0.1rem solid rgba(var(--color-foreground), 0.08); 26 | display: block; 27 | height: calc(100% - 1.8rem); 28 | content: ''; 29 | position: absolute; 30 | right: 0; 31 | } 32 | 33 | .search__button:focus-visible, 34 | .reset__button:focus-visible { 35 | background-color: rgb(var(--color-background)); 36 | z-index: 4; 37 | } 38 | 39 | .search__button:focus, 40 | .reset__button:focus { 41 | background-color: rgb(var(--color-background)); 42 | z-index: 4; 43 | } 44 | 45 | .search__button:not(:focus-visible):not(.focused), 46 | .reset__button:not(:focus-visible):not(.focused) { 47 | box-shadow: inherit; 48 | background-color: inherit; 49 | } 50 | 51 | .search__button:hover .icon, 52 | .reset__button:hover .icon { 53 | transform: scale(1.07); 54 | } 55 | 56 | .search__button .icon { 57 | height: 1.8rem; 58 | width: 1.8rem; 59 | } 60 | 61 | .reset__button .icon.icon-close { 62 | height: 1.8rem; 63 | width: 1.8rem; 64 | stroke-width: 0.1rem; 65 | } 66 | 67 | /* Remove extra spacing for search inputs in Safari */ 68 | input::-webkit-search-decoration { 69 | -webkit-appearance: none; 70 | } 71 | 72 | .template-search__results { 73 | position: relative; 74 | } 75 | -------------------------------------------------------------------------------- /assets/component-show-more.css: -------------------------------------------------------------------------------- 1 | .button-show-more { 2 | padding-left: 0; 3 | justify-content: flex-start; 4 | padding-bottom: 1.1rem; 5 | } 6 | 7 | .button-show-more, 8 | .button-show-less { 9 | margin-top: 1.5rem; 10 | } 11 | -------------------------------------------------------------------------------- /assets/component-slideshow.css: -------------------------------------------------------------------------------- 1 | slideshow-component { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | slideshow-component .slideshow.banner { 8 | flex-direction: row; 9 | flex-wrap: nowrap; 10 | margin: 0; 11 | gap: 0; 12 | overflow-y: hidden; 13 | } 14 | 15 | .slideshow__slide { 16 | padding: 0; 17 | position: relative; 18 | display: flex; 19 | flex-direction: column; 20 | visibility: visible; 21 | } 22 | 23 | @media screen and (max-width: 749px) { 24 | .slideshow--placeholder.banner--mobile-bottom.banner--adapt_image .slideshow__media, 25 | .slideshow--placeholder.banner--adapt_image:not(.banner--mobile-bottom) { 26 | height: 28rem; 27 | } 28 | } 29 | 30 | @media screen and (min-width: 750px) { 31 | .slideshow--placeholder.banner--adapt_image { 32 | height: 56rem; 33 | } 34 | } 35 | 36 | .slideshow__text.banner__box { 37 | display: flex; 38 | flex-direction: column; 39 | justify-content: center; 40 | max-width: 54.5rem; 41 | } 42 | 43 | .slideshow__text > * { 44 | max-width: 100%; 45 | } 46 | 47 | @media screen and (max-width: 749px) { 48 | slideshow-component.page-width .slideshow__text { 49 | border-right: var(--text-boxes-border-width) solid rgba(var(--color-foreground), var(--text-boxes-border-opacity)); 50 | border-left: var(--text-boxes-border-width) solid rgba(var(--color-foreground), var(--text-boxes-border-opacity)); 51 | } 52 | 53 | .banner--mobile-bottom .slideshow__text.banner__box { 54 | max-width: 100%; 55 | } 56 | 57 | .banner--mobile-bottom .slideshow__text-wrapper { 58 | flex-grow: 1; 59 | } 60 | 61 | .banner--mobile-bottom .slideshow__text.banner__box { 62 | height: 100%; 63 | } 64 | 65 | .banner--mobile-bottom .slideshow__text .button { 66 | flex-grow: 0; 67 | } 68 | 69 | .slideshow__text.slideshow__text-mobile--left { 70 | align-items: flex-start; 71 | text-align: left; 72 | } 73 | 74 | .slideshow__text.slideshow__text-mobile--right { 75 | align-items: flex-end; 76 | text-align: right; 77 | } 78 | } 79 | 80 | @media screen and (min-width: 750px) { 81 | .slideshow__text.slideshow__text--left { 82 | align-items: flex-start; 83 | text-align: left; 84 | } 85 | 86 | .slideshow__text.slideshow__text--right { 87 | align-items: flex-end; 88 | text-align: right; 89 | } 90 | } 91 | 92 | .slideshow:not(.banner--mobile-bottom) .slideshow__text-wrapper { 93 | height: 100%; 94 | } 95 | 96 | @media screen and (min-width: 750px) { 97 | .slideshow__text-wrapper.banner__content { 98 | height: 100%; 99 | padding: 5rem; 100 | } 101 | } 102 | 103 | .slideshow__controls { 104 | border: 0.1rem solid rgba(var(--color-foreground), 0.08); 105 | } 106 | 107 | .slideshow__controls--top { 108 | order: 2; 109 | z-index: 1; 110 | } 111 | 112 | @media screen and (max-width: 749px) { 113 | .slideshow__controls--border-radius-mobile { 114 | border-bottom-right-radius: var(--text-boxes-radius); 115 | border-bottom-left-radius: var(--text-boxes-radius); 116 | } 117 | } 118 | 119 | .spaced-section--full-width:last-child slideshow-component:not(.page-width) .slideshow__controls { 120 | border-bottom: none; 121 | } 122 | 123 | @media screen and (min-width: 750px) { 124 | .slideshow__controls { 125 | position: relative; 126 | } 127 | } 128 | 129 | slideshow-component:not(.page-width) .slider-buttons { 130 | border-right: 0; 131 | border-left: 0; 132 | } 133 | 134 | .slideshow__control-wrapper { 135 | display: flex; 136 | } 137 | 138 | .slideshow__autoplay { 139 | position: absolute; 140 | right: 0; 141 | border-left: none; 142 | display: flex; 143 | justify-content: center; 144 | align-items: center; 145 | } 146 | 147 | @media screen and (max-width: 749px) { 148 | slideshow-component.page-width .slideshow__autoplay { 149 | right: 1.5rem; 150 | } 151 | } 152 | 153 | @media screen and (min-width: 750px) { 154 | .slideshow__autoplay.slider-button { 155 | position: inherit; 156 | margin-left: 0.6rem; 157 | padding: 0 0 0 0.6rem; 158 | border-left: 0.1rem solid rgba(var(--color-foreground), 0.08); 159 | } 160 | } 161 | 162 | .slideshow__autoplay .icon.icon-play, 163 | .slideshow__autoplay .icon.icon-pause { 164 | display: block; 165 | position: absolute; 166 | opacity: 1; 167 | transform: scale(1); 168 | transition: transform 150ms ease, opacity 150ms ease; 169 | width: 0.8rem; 170 | height: 1.2rem; 171 | } 172 | 173 | .slideshow__autoplay .icon.icon-play { 174 | height: 1rem; 175 | } 176 | 177 | .slideshow__autoplay path { 178 | fill: rgba(var(--color-foreground), 0.75); 179 | } 180 | 181 | .slideshow__autoplay:hover path { 182 | fill: rgb(var(--color-foreground)); 183 | } 184 | 185 | @media screen and (forced-colors: active) { 186 | .slideshow__autoplay path, 187 | .slideshow__autoplay:hover path { 188 | fill: CanvasText; 189 | } 190 | } 191 | 192 | .slideshow__autoplay:hover .svg-wrapper { 193 | transform: scale(1.1); 194 | } 195 | 196 | .slideshow__autoplay--paused .icon-pause, 197 | .slideshow__autoplay:not(.slideshow__autoplay--paused) .icon-play { 198 | visibility: hidden; 199 | opacity: 0; 200 | transform: scale(0.8); 201 | } 202 | -------------------------------------------------------------------------------- /assets/component-swatch-input.css: -------------------------------------------------------------------------------- 1 | /* swatch-input lives in its own file for reusability of the swatch in other areas than the product form context */ 2 | .swatch-input__input + .swatch-input__label { 3 | --swatch-input--border-radius: 50%; 4 | display: inline-block; 5 | max-width: 100%; 6 | border-radius: var(--swatch-input--border-radius); 7 | cursor: pointer; 8 | outline-offset: 0.2rem; 9 | outline-color: transparent; 10 | outline-style: solid; 11 | transition-property: outline-color, outline-width, box-shadow; 12 | transition-duration: var(--duration-short); 13 | transition-timing-function: ease; 14 | forced-color-adjust: none; 15 | } 16 | 17 | .swatch-input__input + .swatch-input__label.swatch-input__label--square { 18 | --swatch-input--border-radius: 0.2rem; 19 | } 20 | 21 | /* Active state */ 22 | .swatch-input__input:active + .swatch-input__label, 23 | .swatch-input__input:checked + .swatch-input__label { 24 | outline: 0.1rem solid rgb(var(--color-foreground)); 25 | } 26 | 27 | /* Hover state */ 28 | .swatch-input__input + .swatch-input__label:hover, 29 | .swatch-input__input:hover + .swatch-input__label { 30 | outline: 0.2rem solid rgba(var(--color-foreground), 0.4); 31 | } 32 | 33 | /* Focus visible */ 34 | .swatch-input__input:focus-visible + .swatch-input__label { 35 | outline: 0.2rem solid rgba(var(--color-foreground), 0.5); 36 | box-shadow: 0 0 0 0.2rem rgb(var(--color-background)), 0 0 0.1rem 0.5rem rgba(var(--color-foreground), 0.25); 37 | } 38 | 39 | /* Active and focused */ 40 | .swatch-input__input:active:focus-visible + .swatch-input__label, 41 | .swatch-input__input:checked:focus-visible + .swatch-input__label { 42 | outline: 0.1rem solid rgb(var(--color-foreground)); 43 | box-shadow: 0 0 0 0.2rem rgb(var(--color-background)), 0 0 0.1rem 0.4rem rgba(var(--color-foreground), 0.25); 44 | } 45 | 46 | /* Visually disabled */ 47 | .swatch-input__input.visually-disabled:not(:active):not(:checked) + .swatch-input__label { 48 | transition: none; 49 | } 50 | .swatch-input__input.visually-disabled:not(:active):not(:checked) + .swatch-input__label:hover { 51 | outline: none; 52 | } 53 | 54 | /* Actually disabled */ 55 | .swatch-input__input:disabled + .swatch-input__label { 56 | pointer-events: none; 57 | } 58 | 59 | /* Overrides for swatch snippet when used inside disabled swatch-input */ 60 | .swatch-input__input:disabled + .swatch-input__label > .swatch, 61 | .swatch-input__input.visually-disabled + .swatch-input__label > .swatch { 62 | position: relative; 63 | overflow: hidden; 64 | } 65 | 66 | /* Disabled styles */ 67 | .swatch-input__input:disabled + .swatch-input__label > .swatch, 68 | .swatch-input__input.visually-disabled + .swatch-input__label > .swatch { 69 | opacity: 0.4; 70 | } 71 | 72 | /* Display crossed out line over swatch when input is disabled */ 73 | .swatch-input__input:disabled + .swatch-input__label > .swatch::after, 74 | .swatch-input__input.visually-disabled + .swatch-input__label > .swatch::after { 75 | /* Diagonal of a square = length of the side * sqrt(2) */ 76 | --diagonal--size: calc(var(--swatch-input--size) * 1.414); 77 | --crossed-line--size: 0.1rem; 78 | content: ''; 79 | position: absolute; 80 | bottom: calc(var(--crossed-line--size) * -0.5); 81 | left: 0; 82 | width: var(--diagonal--size); 83 | height: var(--crossed-line--size); 84 | background-color: rgb(var(--color-foreground)); 85 | transform: rotate(-45deg); 86 | transform-origin: left; 87 | } 88 | -------------------------------------------------------------------------------- /assets/component-swatch.css: -------------------------------------------------------------------------------- 1 | /* swatch lives in its own file for reusability of the swatch in swatch-input and dropdown */ 2 | .swatch { 3 | --swatch--size: var(--swatch-input--size, 4.4rem); 4 | --swatch--border-radius: var(--swatch-input--border-radius, 50%); 5 | 6 | display: block; 7 | width: var(--swatch--size); 8 | max-width: 100%; 9 | aspect-ratio: 1 / 1; 10 | background: var(--swatch--background); 11 | background-position: var(--swatch-focal-point, initial); 12 | background-size: cover; 13 | background-origin: border-box; 14 | border: 0.1rem solid rgba(var(--color-foreground), 0.15); 15 | border-radius: var(--swatch--border-radius); 16 | } 17 | 18 | .swatch--square { 19 | --swatch--border-radius: var(--swatch-input--border-radius, 0.2rem); 20 | } 21 | 22 | .swatch--unavailable { 23 | border-style: dashed; 24 | border-color: rgba(var(--color-foreground), 0.5); 25 | } 26 | -------------------------------------------------------------------------------- /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 > h2 { 13 | font-size: calc(var(--font-heading-scale) * 1.6rem); 14 | } 15 | 16 | .totals * { 17 | line-height: 1; 18 | } 19 | 20 | .totals > * + * { 21 | margin-left: 2rem; 22 | } 23 | 24 | .totals__total { 25 | margin-top: .5rem; 26 | } 27 | 28 | .totals__total-value { 29 | font-size: 1.8rem; 30 | } 31 | 32 | .cart__ctas + .totals { 33 | margin-top: 2rem; 34 | } 35 | 36 | @media all and (min-width: 750px) { 37 | .totals { 38 | justify-content: flex-end; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /assets/constants.js: -------------------------------------------------------------------------------- 1 | const ON_CHANGE_DEBOUNCE_TIMER = 300; 2 | 3 | const PUB_SUB_EVENTS = { 4 | cartUpdate: 'cart-update', 5 | quantityUpdate: 'quantity-update', 6 | optionValueSelectionChange: 'option-value-selection-change', 7 | variantChange: 'variant-change', 8 | cartError: 'cart-error', 9 | }; 10 | -------------------------------------------------------------------------------- /assets/details-disclosure.js: -------------------------------------------------------------------------------- 1 | class DetailsDisclosure extends HTMLElement { 2 | constructor() { 3 | super(); 4 | this.mainDetailsToggle = this.querySelector('details'); 5 | this.content = this.mainDetailsToggle.querySelector('summary').nextElementSibling; 6 | 7 | this.mainDetailsToggle.addEventListener('focusout', this.onFocusOut.bind(this)); 8 | this.mainDetailsToggle.addEventListener('toggle', this.onToggle.bind(this)); 9 | } 10 | 11 | onFocusOut() { 12 | setTimeout(() => { 13 | if (!this.contains(document.activeElement)) this.close(); 14 | }); 15 | } 16 | 17 | onToggle() { 18 | if (!this.animations) this.animations = this.content.getAnimations(); 19 | 20 | if (this.mainDetailsToggle.hasAttribute('open')) { 21 | this.animations.forEach((animation) => animation.play()); 22 | } else { 23 | this.animations.forEach((animation) => animation.cancel()); 24 | } 25 | } 26 | 27 | close() { 28 | this.mainDetailsToggle.removeAttribute('open'); 29 | this.mainDetailsToggle.querySelector('summary').setAttribute('aria-expanded', false); 30 | } 31 | } 32 | 33 | customElements.define('details-disclosure', DetailsDisclosure); 34 | 35 | class HeaderMenu extends DetailsDisclosure { 36 | constructor() { 37 | super(); 38 | this.header = document.querySelector('.header-wrapper'); 39 | } 40 | 41 | onToggle() { 42 | if (!this.header) return; 43 | this.header.preventHide = this.mainDetailsToggle.open; 44 | 45 | if (document.documentElement.style.getPropertyValue('--header-bottom-position-desktop') !== '') return; 46 | document.documentElement.style.setProperty( 47 | '--header-bottom-position-desktop', 48 | `${Math.floor(this.header.getBoundingClientRect().bottom)}px` 49 | ); 50 | } 51 | } 52 | 53 | customElements.define('header-menu', HeaderMenu); 54 | -------------------------------------------------------------------------------- /assets/magnify.js: -------------------------------------------------------------------------------- 1 | // create a container and set the full-size image as its background 2 | function createOverlay(image) { 3 | const overlayImage = document.createElement('img'); 4 | overlayImage.setAttribute('src', `${image.src}`); 5 | overlay = document.createElement('div'); 6 | prepareOverlay(overlay, overlayImage); 7 | 8 | image.style.opacity = '50%'; 9 | toggleLoadingSpinner(image); 10 | 11 | overlayImage.onload = () => { 12 | toggleLoadingSpinner(image); 13 | image.parentElement.insertBefore(overlay, image); 14 | image.style.opacity = '100%'; 15 | }; 16 | 17 | return overlay; 18 | } 19 | 20 | function prepareOverlay(container, image) { 21 | container.setAttribute('class', 'image-magnify-full-size'); 22 | container.setAttribute('aria-hidden', 'true'); 23 | container.style.backgroundImage = `url('${image.src}')`; 24 | container.style.backgroundColor = 'var(--gradient-background)'; 25 | } 26 | 27 | function toggleLoadingSpinner(image) { 28 | const loadingSpinner = image.parentElement.parentElement.querySelector(`.loading__spinner`); 29 | loadingSpinner.classList.toggle('hidden'); 30 | } 31 | 32 | function moveWithHover(image, event, zoomRatio) { 33 | // calculate mouse position 34 | const ratio = image.height / image.width; 35 | const container = event.target.getBoundingClientRect(); 36 | const xPosition = event.clientX - container.left; 37 | const yPosition = event.clientY - container.top; 38 | const xPercent = `${xPosition / (image.clientWidth / 100)}%`; 39 | const yPercent = `${yPosition / ((image.clientWidth * ratio) / 100)}%`; 40 | 41 | // determine what to show in the frame 42 | overlay.style.backgroundPosition = `${xPercent} ${yPercent}`; 43 | overlay.style.backgroundSize = `${image.width * zoomRatio}px`; 44 | } 45 | 46 | function magnify(image, zoomRatio) { 47 | const overlay = createOverlay(image); 48 | overlay.onclick = () => overlay.remove(); 49 | overlay.onmousemove = (event) => moveWithHover(image, event, zoomRatio); 50 | overlay.onmouseleave = () => overlay.remove(); 51 | } 52 | 53 | function enableZoomOnHover(zoomRatio) { 54 | const images = document.querySelectorAll('.image-magnify-hover'); 55 | images.forEach((image) => { 56 | image.onclick = (event) => { 57 | magnify(image, zoomRatio); 58 | moveWithHover(image, event, zoomRatio); 59 | }; 60 | }); 61 | } 62 | 63 | enableZoomOnHover(2); 64 | -------------------------------------------------------------------------------- /assets/main-search.js: -------------------------------------------------------------------------------- 1 | class MainSearch extends SearchForm { 2 | constructor() { 3 | super(); 4 | this.allSearchInputs = document.querySelectorAll('input[type="search"]'); 5 | this.setupEventListeners(); 6 | } 7 | 8 | setupEventListeners() { 9 | let allSearchForms = []; 10 | this.allSearchInputs.forEach((input) => allSearchForms.push(input.form)); 11 | this.input.addEventListener('focus', this.onInputFocus.bind(this)); 12 | if (allSearchForms.length < 2) return; 13 | allSearchForms.forEach((form) => form.addEventListener('reset', this.onFormReset.bind(this))); 14 | this.allSearchInputs.forEach((input) => input.addEventListener('input', this.onInput.bind(this))); 15 | } 16 | 17 | onFormReset(event) { 18 | super.onFormReset(event); 19 | if (super.shouldResetForm()) { 20 | this.keepInSync('', this.input); 21 | } 22 | } 23 | 24 | onInput(event) { 25 | const target = event.target; 26 | this.keepInSync(target.value, target); 27 | } 28 | 29 | onInputFocus() { 30 | const isSmallScreen = window.innerWidth < 750; 31 | if (isSmallScreen) { 32 | this.scrollIntoView({ behavior: 'smooth' }); 33 | } 34 | } 35 | 36 | keepInSync(value, target) { 37 | this.allSearchInputs.forEach((input) => { 38 | if (input !== target) { 39 | input.value = value; 40 | } 41 | }); 42 | } 43 | } 44 | 45 | customElements.define('main-search', MainSearch); 46 | -------------------------------------------------------------------------------- /assets/media-gallery.js: -------------------------------------------------------------------------------- 1 | if (!customElements.get('media-gallery')) { 2 | customElements.define( 3 | 'media-gallery', 4 | class MediaGallery extends HTMLElement { 5 | constructor() { 6 | super(); 7 | this.elements = { 8 | liveRegion: this.querySelector('[id^="GalleryStatus"]'), 9 | viewer: this.querySelector('[id^="GalleryViewer"]'), 10 | thumbnails: this.querySelector('[id^="GalleryThumbnails"]'), 11 | }; 12 | this.mql = window.matchMedia('(min-width: 750px)'); 13 | if (!this.elements.thumbnails) return; 14 | 15 | this.elements.viewer.addEventListener('slideChanged', debounce(this.onSlideChanged.bind(this), 500)); 16 | this.elements.thumbnails.querySelectorAll('[data-target]').forEach((mediaToSwitch) => { 17 | mediaToSwitch 18 | .querySelector('button') 19 | .addEventListener('click', this.setActiveMedia.bind(this, mediaToSwitch.dataset.target, false)); 20 | }); 21 | if (this.dataset.desktopLayout.includes('thumbnail') && this.mql.matches) this.removeListSemantic(); 22 | } 23 | 24 | onSlideChanged(event) { 25 | const thumbnail = this.elements.thumbnails.querySelector( 26 | `[data-target="${event.detail.currentElement.dataset.mediaId}"]` 27 | ); 28 | this.setActiveThumbnail(thumbnail); 29 | } 30 | 31 | setActiveMedia(mediaId, prepend) { 32 | const activeMedia = 33 | this.elements.viewer.querySelector(`[data-media-id="${mediaId}"]`) || 34 | this.elements.viewer.querySelector('[data-media-id]'); 35 | if (!activeMedia) { 36 | return; 37 | } 38 | this.elements.viewer.querySelectorAll('[data-media-id]').forEach((element) => { 39 | element.classList.remove('is-active'); 40 | }); 41 | activeMedia?.classList?.add('is-active'); 42 | 43 | if (prepend) { 44 | activeMedia.parentElement.firstChild !== activeMedia && activeMedia.parentElement.prepend(activeMedia); 45 | 46 | if (this.elements.thumbnails) { 47 | const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`); 48 | activeThumbnail.parentElement.firstChild !== activeThumbnail && activeThumbnail.parentElement.prepend(activeThumbnail); 49 | } 50 | 51 | if (this.elements.viewer.slider) this.elements.viewer.resetPages(); 52 | } 53 | 54 | this.preventStickyHeader(); 55 | window.setTimeout(() => { 56 | if (!this.mql.matches || this.elements.thumbnails) { 57 | activeMedia.parentElement.scrollTo({ left: activeMedia.offsetLeft }); 58 | } 59 | const activeMediaRect = activeMedia.getBoundingClientRect(); 60 | // Don't scroll if the image is already in view 61 | if (activeMediaRect.top > -0.5) return; 62 | const top = activeMediaRect.top + window.scrollY; 63 | window.scrollTo({ top: top, behavior: 'smooth' }); 64 | }); 65 | this.playActiveMedia(activeMedia); 66 | 67 | if (!this.elements.thumbnails) return; 68 | const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`); 69 | this.setActiveThumbnail(activeThumbnail); 70 | this.announceLiveRegion(activeMedia, activeThumbnail.dataset.mediaPosition); 71 | } 72 | 73 | setActiveThumbnail(thumbnail) { 74 | if (!this.elements.thumbnails || !thumbnail) return; 75 | 76 | this.elements.thumbnails 77 | .querySelectorAll('button') 78 | .forEach((element) => element.removeAttribute('aria-current')); 79 | thumbnail.querySelector('button').setAttribute('aria-current', true); 80 | if (this.elements.thumbnails.isSlideVisible(thumbnail, 10)) return; 81 | 82 | this.elements.thumbnails.slider.scrollTo({ left: thumbnail.offsetLeft }); 83 | } 84 | 85 | announceLiveRegion(activeItem, position) { 86 | const image = activeItem.querySelector('.product__modal-opener--image img'); 87 | if (!image) return; 88 | image.onload = () => { 89 | this.elements.liveRegion.setAttribute('aria-hidden', false); 90 | this.elements.liveRegion.innerHTML = window.accessibilityStrings.imageAvailable.replace('[index]', position); 91 | setTimeout(() => { 92 | this.elements.liveRegion.setAttribute('aria-hidden', true); 93 | }, 2000); 94 | }; 95 | image.src = image.src; 96 | } 97 | 98 | playActiveMedia(activeItem) { 99 | window.pauseAllMedia(); 100 | const deferredMedia = activeItem.querySelector('.deferred-media'); 101 | if (deferredMedia) deferredMedia.loadContent(false); 102 | } 103 | 104 | preventStickyHeader() { 105 | this.stickyHeader = this.stickyHeader || document.querySelector('sticky-header'); 106 | if (!this.stickyHeader) return; 107 | this.stickyHeader.dispatchEvent(new Event('preventHeaderReveal')); 108 | } 109 | 110 | removeListSemantic() { 111 | if (!this.elements.viewer.slider) return; 112 | this.elements.viewer.slider.setAttribute('role', 'presentation'); 113 | this.elements.viewer.sliderItems.forEach((slide) => slide.setAttribute('role', 'presentation')); 114 | } 115 | } 116 | ); 117 | } 118 | -------------------------------------------------------------------------------- /assets/product-form.js: -------------------------------------------------------------------------------- 1 | if (!customElements.get('product-form')) { 2 | customElements.define( 3 | 'product-form', 4 | class ProductForm extends HTMLElement { 5 | constructor() { 6 | super(); 7 | 8 | this.form = this.querySelector('form'); 9 | this.variantIdInput.disabled = false; 10 | this.form.addEventListener('submit', this.onSubmitHandler.bind(this)); 11 | this.cart = document.querySelector('cart-notification') || document.querySelector('cart-drawer'); 12 | this.submitButton = this.querySelector('[type="submit"]'); 13 | this.submitButtonText = this.submitButton.querySelector('span'); 14 | 15 | if (document.querySelector('cart-drawer')) this.submitButton.setAttribute('aria-haspopup', 'dialog'); 16 | 17 | this.hideErrors = this.dataset.hideErrors === 'true'; 18 | } 19 | 20 | onSubmitHandler(evt) { 21 | evt.preventDefault(); 22 | if (this.submitButton.getAttribute('aria-disabled') === 'true') return; 23 | 24 | this.handleErrorMessage(); 25 | 26 | this.submitButton.setAttribute('aria-disabled', true); 27 | this.submitButton.classList.add('loading'); 28 | this.querySelector('.loading__spinner').classList.remove('hidden'); 29 | 30 | const config = fetchConfig('javascript'); 31 | config.headers['X-Requested-With'] = 'XMLHttpRequest'; 32 | delete config.headers['Content-Type']; 33 | 34 | const formData = new FormData(this.form); 35 | if (this.cart) { 36 | formData.append( 37 | 'sections', 38 | this.cart.getSectionsToRender().map((section) => section.id) 39 | ); 40 | formData.append('sections_url', window.location.pathname); 41 | this.cart.setActiveElement(document.activeElement); 42 | } 43 | config.body = formData; 44 | 45 | fetch(`${routes.cart_add_url}`, config) 46 | .then((response) => response.json()) 47 | .then((response) => { 48 | if (response.status) { 49 | publish(PUB_SUB_EVENTS.cartError, { 50 | source: 'product-form', 51 | productVariantId: formData.get('id'), 52 | errors: response.errors || response.description, 53 | message: response.message, 54 | }); 55 | this.handleErrorMessage(response.description); 56 | 57 | const soldOutMessage = this.submitButton.querySelector('.sold-out-message'); 58 | if (!soldOutMessage) return; 59 | this.submitButton.setAttribute('aria-disabled', true); 60 | this.submitButtonText.classList.add('hidden'); 61 | soldOutMessage.classList.remove('hidden'); 62 | this.error = true; 63 | return; 64 | } else if (!this.cart) { 65 | window.location = window.routes.cart_url; 66 | return; 67 | } 68 | 69 | if (!this.error) 70 | publish(PUB_SUB_EVENTS.cartUpdate, { 71 | source: 'product-form', 72 | productVariantId: formData.get('id'), 73 | cartData: response, 74 | }); 75 | this.error = false; 76 | const quickAddModal = this.closest('quick-add-modal'); 77 | if (quickAddModal) { 78 | document.body.addEventListener( 79 | 'modalClosed', 80 | () => { 81 | setTimeout(() => { 82 | this.cart.renderContents(response); 83 | }); 84 | }, 85 | { once: true } 86 | ); 87 | quickAddModal.hide(true); 88 | } else { 89 | this.cart.renderContents(response); 90 | } 91 | }) 92 | .catch((e) => { 93 | console.error(e); 94 | }) 95 | .finally(() => { 96 | this.submitButton.classList.remove('loading'); 97 | if (this.cart && this.cart.classList.contains('is-empty')) this.cart.classList.remove('is-empty'); 98 | if (!this.error) this.submitButton.removeAttribute('aria-disabled'); 99 | this.querySelector('.loading__spinner').classList.add('hidden'); 100 | }); 101 | } 102 | 103 | handleErrorMessage(errorMessage = false) { 104 | if (this.hideErrors) return; 105 | 106 | this.errorMessageWrapper = 107 | this.errorMessageWrapper || this.querySelector('.product-form__error-message-wrapper'); 108 | if (!this.errorMessageWrapper) return; 109 | this.errorMessage = this.errorMessage || this.errorMessageWrapper.querySelector('.product-form__error-message'); 110 | 111 | this.errorMessageWrapper.toggleAttribute('hidden', !errorMessage); 112 | 113 | if (errorMessage) { 114 | this.errorMessage.textContent = errorMessage; 115 | } 116 | } 117 | 118 | toggleSubmitButton(disable = true, text) { 119 | if (disable) { 120 | this.submitButton.setAttribute('disabled', 'disabled'); 121 | if (text) this.submitButtonText.textContent = text; 122 | } else { 123 | this.submitButton.removeAttribute('disabled'); 124 | this.submitButtonText.textContent = window.variantStrings.addToCart; 125 | } 126 | } 127 | 128 | get variantIdInput() { 129 | return this.form.querySelector('[name=id]'); 130 | } 131 | } 132 | ); 133 | } 134 | -------------------------------------------------------------------------------- /assets/quantity-popover.css: -------------------------------------------------------------------------------- 1 | quantity-popover { 2 | position: relative; 3 | display: block; 4 | } 5 | 6 | quantity-popover volume-pricing li:nth-child(odd) { 7 | background: rgba(var(--color-foreground), 0.03); 8 | } 9 | 10 | quantity-popover volume-pricing li { 11 | font-size: 1.2rem; 12 | letter-spacing: 0.06rem; 13 | padding: 0.6rem 0.8rem; 14 | display: flex; 15 | justify-content: space-between; 16 | } 17 | 18 | .quantity-popover__info.global-settings-popup { 19 | width: 100%; 20 | z-index: 3; 21 | position: absolute; 22 | background-color: rgb(var(--color-background)); 23 | max-width: 36rem; 24 | } 25 | 26 | .quantity-popover__info .button-close, 27 | .variant-remove-total quick-order-list-remove-all-button .button, 28 | .quick-order-list-total__confirmation quick-order-list-remove-all-button .button, 29 | quantity-popover quick-order-list-remove-button .button { 30 | --shadow-opacity: 0; 31 | --border-opacity: 0; 32 | } 33 | 34 | .quantity-popover__info-button { 35 | display: flex; 36 | align-items: center; 37 | margin: 0 0.4rem 0 0; 38 | min-width: 1.5rem; 39 | min-height: 1.5rem; 40 | --shadow-opacity: 0; 41 | --border-opacity: 0; 42 | } 43 | 44 | .quantity-popover__info-button--icon-with-label { 45 | text-align: left; 46 | } 47 | 48 | .quantity-popover__info-button--icon-with-label svg { 49 | flex-shrink: 0; 50 | width: 15px; 51 | height: 14px; 52 | } 53 | 54 | .quantity-popover__info-button--open { 55 | text-decoration: underline; 56 | } 57 | 58 | .quantity-popover__info-button span { 59 | padding-left: 1rem; 60 | } 61 | 62 | .quantity-popover__info-button--icon-only--animation svg { 63 | transform: scale(1.25); 64 | } 65 | 66 | .quantity-popover__info-button--icon-only svg { 67 | transition: transform var(--duration-default) ease; 68 | width: 15px; 69 | height: 14px; 70 | } 71 | 72 | @media screen and (max-width: 989px) { 73 | .quantity-popover__info.global-settings-popup { 74 | left: 0; 75 | top: 100%; 76 | } 77 | 78 | .quantity-popover__info-button { 79 | padding-left: 0; 80 | } 81 | } 82 | 83 | .quantity-popover__info .quantity__rules { 84 | margin-top: 1.2rem; 85 | margin-bottom: 1rem; 86 | } 87 | 88 | .quantity-popover__info .volume-pricing-label { 89 | display: block; 90 | margin-left: 1.2rem; 91 | margin-top: 1.2rem; 92 | font-size: 1.2rem; 93 | } 94 | 95 | .quantity-popover__info .button { 96 | width: 3.2rem; 97 | height: 3.2rem; 98 | position: absolute; 99 | top: 0.4rem; 100 | right: 0; 101 | padding: 0 1.2rem 0 0; 102 | display: flex; 103 | justify-content: flex-end; 104 | } 105 | 106 | .quantity-popover__info .volume-pricing-label ~ .button { 107 | top: -0.2rem; 108 | } 109 | 110 | .quantity-popover__info .button .icon { 111 | width: 1.5rem; 112 | height: 1.5rem; 113 | } 114 | 115 | quantity-popover volume-pricing { 116 | margin-top: 1.2rem; 117 | display: block; 118 | } 119 | 120 | quantity-popover .quantity__rules span:first-of-type { 121 | display: block; 122 | } 123 | 124 | .quantity-popover-container { 125 | display: flex; 126 | padding: 0.5rem 0.5rem 0.5rem 0; 127 | } 128 | 129 | .quantity-popover-container:not(.quantity-popover-container--hover) { 130 | align-items: center; 131 | } 132 | 133 | @media screen and (min-width: 990px) { 134 | .quantity-popover-container--empty { 135 | margin-right: 2.7rem; 136 | } 137 | 138 | .quantity-popover__info.global-settings-popup { 139 | width: 20rem; 140 | } 141 | 142 | .quantity-popover-container { 143 | width: auto; 144 | max-width: 20rem; 145 | } 146 | 147 | .quantity-popover__info.global-settings-popup { 148 | transform: translateX(-100%); 149 | top: 0.5rem; 150 | } 151 | } 152 | 153 | quantity-popover .quantity { 154 | background: rgb(var(--color-background)); 155 | } 156 | 157 | quantity-popover .quantity__rules { 158 | margin-left: 0.8rem; 159 | } 160 | 161 | quantity-popover .quantity__rules .divider:nth-child(2)::before { 162 | content: none; 163 | } 164 | 165 | quantity-popover .quantity__button:not(:focus-visible):not(.focused), 166 | quantity-popover .quantity__input:not(:focus-visible):not(.focused) { 167 | background-color: initial; 168 | } 169 | -------------------------------------------------------------------------------- /assets/quantity-popover.js: -------------------------------------------------------------------------------- 1 | if (!customElements.get('quantity-popover')) { 2 | customElements.define( 3 | 'quantity-popover', 4 | class QuantityPopover extends HTMLElement { 5 | constructor() { 6 | super(); 7 | this.mql = window.matchMedia('(min-width: 990px)'); 8 | this.mqlTablet = window.matchMedia('(min-width: 750px)'); 9 | this.infoButtonDesktop = this.querySelector('.quantity-popover__info-button--icon-only'); 10 | this.infoButtonMobile = this.querySelector('.quantity-popover__info-button--icon-with-label'); 11 | this.popoverInfo = this.querySelector('.quantity-popover__info'); 12 | this.closeButton = this.querySelector('.button-close'); 13 | this.eventMouseEnterHappened = false; 14 | 15 | if (this.closeButton) { 16 | this.closeButton.addEventListener('click', this.closePopover.bind(this)); 17 | } 18 | 19 | if (this.popoverInfo && this.infoButtonDesktop && this.mqlTablet.matches) { 20 | this.popoverInfo.addEventListener('mouseleave', this.closePopover.bind(this)); 21 | } 22 | 23 | if (this.infoButtonDesktop) { 24 | this.infoButtonDesktop.addEventListener('click', this.togglePopover.bind(this)); 25 | this.infoButtonDesktop.addEventListener('focusout', this.closePopover.bind(this)); 26 | } 27 | 28 | if (this.infoButtonMobile) { 29 | this.infoButtonMobile.addEventListener('click', this.togglePopover.bind(this)); 30 | } 31 | 32 | if (this.infoButtonDesktop && this.mqlTablet.matches) { 33 | this.infoButtonDesktop.addEventListener('mouseenter', this.togglePopover.bind(this)); 34 | this.infoButtonDesktop.addEventListener('mouseleave', this.closePopover.bind(this)); 35 | } 36 | } 37 | 38 | togglePopover(event) { 39 | event.preventDefault(); 40 | if (event.type === 'mouseenter') { 41 | this.eventMouseEnterHappened = true; 42 | } 43 | 44 | if (event.type === 'click' && this.eventMouseEnterHappened) return; 45 | 46 | const button = this.infoButtonDesktop && this.mql.matches ? this.infoButtonDesktop : this.infoButtonMobile; 47 | const isExpanded = button.getAttribute('aria-expanded') === 'true'; 48 | 49 | if ((this.mql.matches && !isExpanded) || event.type === 'click') { 50 | button.setAttribute('aria-expanded', !isExpanded); 51 | 52 | this.popoverInfo.toggleAttribute('hidden'); 53 | 54 | button.classList.toggle('quantity-popover__info-button--open'); 55 | 56 | this.infoButtonDesktop.classList.add('quantity-popover__info-button--icon-only--animation'); 57 | } 58 | 59 | const isOpen = button.getAttribute('aria-expanded') === 'true'; 60 | 61 | if (isOpen && event.type !== 'mouseenter') { 62 | button.focus(); 63 | button.addEventListener('keyup', (e) => { 64 | if (e.key === 'Escape') { 65 | this.closePopover(e); 66 | } 67 | }); 68 | } 69 | } 70 | 71 | closePopover(event) { 72 | event.preventDefault(); 73 | const isButtonChild = this.infoButtonDesktop.contains(event.relatedTarget); 74 | const isPopoverChild = this.popoverInfo.contains(event.relatedTarget); 75 | 76 | const button = this.infoButtonDesktop && this.mql.matches ? this.infoButtonDesktop : this.infoButtonMobile; 77 | 78 | if (!isButtonChild && !isPopoverChild) { 79 | button.setAttribute('aria-expanded', 'false'); 80 | button.classList.remove('quantity-popover__info-button--open'); 81 | this.popoverInfo.setAttribute('hidden', ''); 82 | this.infoButtonDesktop.classList.remove('quantity-popover__info-button--icon-only--animation'); 83 | } 84 | 85 | this.eventMouseEnterHappened = false; 86 | } 87 | } 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /assets/quick-add.js: -------------------------------------------------------------------------------- 1 | if (!customElements.get('quick-add-modal')) { 2 | customElements.define( 3 | 'quick-add-modal', 4 | class QuickAddModal extends ModalDialog { 5 | constructor() { 6 | super(); 7 | this.modalContent = this.querySelector('[id^="QuickAddInfo-"]'); 8 | 9 | this.addEventListener('product-info:loaded', ({ target }) => { 10 | target.addPreProcessCallback(this.preprocessHTML.bind(this)); 11 | }); 12 | } 13 | 14 | hide(preventFocus = false) { 15 | const cartNotification = document.querySelector('cart-notification') || document.querySelector('cart-drawer'); 16 | if (cartNotification) cartNotification.setActiveElement(this.openedBy); 17 | this.modalContent.innerHTML = ''; 18 | 19 | if (preventFocus) this.openedBy = null; 20 | super.hide(); 21 | } 22 | 23 | show(opener) { 24 | opener.setAttribute('aria-disabled', true); 25 | opener.classList.add('loading'); 26 | opener.querySelector('.loading__spinner').classList.remove('hidden'); 27 | 28 | fetch(opener.getAttribute('data-product-url')) 29 | .then((response) => response.text()) 30 | .then((responseText) => { 31 | const responseHTML = new DOMParser().parseFromString(responseText, 'text/html'); 32 | const productElement = responseHTML.querySelector('product-info'); 33 | 34 | this.preprocessHTML(productElement); 35 | HTMLUpdateUtility.setInnerHTML(this.modalContent, productElement.outerHTML); 36 | 37 | if (window.Shopify && Shopify.PaymentButton) { 38 | Shopify.PaymentButton.init(); 39 | } 40 | if (window.ProductModel) window.ProductModel.loadShopifyXR(); 41 | 42 | super.show(opener); 43 | }) 44 | .finally(() => { 45 | opener.removeAttribute('aria-disabled'); 46 | opener.classList.remove('loading'); 47 | opener.querySelector('.loading__spinner').classList.add('hidden'); 48 | }); 49 | } 50 | 51 | preprocessHTML(productElement) { 52 | productElement.classList.forEach((classApplied) => { 53 | if (classApplied.startsWith('color-') || classApplied === 'gradient') 54 | this.modalContent.classList.add(classApplied); 55 | }); 56 | this.preventDuplicatedIDs(productElement); 57 | this.removeDOMElements(productElement); 58 | this.removeGalleryListSemantic(productElement); 59 | this.updateImageSizes(productElement); 60 | this.preventVariantURLSwitching(productElement); 61 | } 62 | 63 | preventVariantURLSwitching(productElement) { 64 | productElement.setAttribute('data-update-url', 'false'); 65 | } 66 | 67 | removeDOMElements(productElement) { 68 | const pickupAvailability = productElement.querySelector('pickup-availability'); 69 | if (pickupAvailability) pickupAvailability.remove(); 70 | 71 | const productModal = productElement.querySelector('product-modal'); 72 | if (productModal) productModal.remove(); 73 | 74 | const modalDialog = productElement.querySelectorAll('modal-dialog'); 75 | if (modalDialog) modalDialog.forEach((modal) => modal.remove()); 76 | } 77 | 78 | preventDuplicatedIDs(productElement) { 79 | const sectionId = productElement.dataset.section; 80 | 81 | const oldId = sectionId; 82 | const newId = `quickadd-${sectionId}`; 83 | productElement.innerHTML = productElement.innerHTML.replaceAll(oldId, newId); 84 | Array.from(productElement.attributes).forEach((attribute) => { 85 | if (attribute.value.includes(oldId)) { 86 | productElement.setAttribute(attribute.name, attribute.value.replace(oldId, newId)); 87 | } 88 | }); 89 | 90 | productElement.dataset.originalSection = sectionId; 91 | } 92 | 93 | removeGalleryListSemantic(productElement) { 94 | const galleryList = productElement.querySelector('[id^="Slider-Gallery"]'); 95 | if (!galleryList) return; 96 | 97 | galleryList.setAttribute('role', 'presentation'); 98 | galleryList.querySelectorAll('[id^="Slide-"]').forEach((li) => li.setAttribute('role', 'presentation')); 99 | } 100 | 101 | updateImageSizes(productElement) { 102 | const product = productElement.querySelector('.product'); 103 | const desktopColumns = product?.classList.contains('product--columns'); 104 | if (!desktopColumns) return; 105 | 106 | const mediaImages = product.querySelectorAll('.product__media img'); 107 | if (!mediaImages.length) return; 108 | 109 | let mediaImageSizes = 110 | '(min-width: 1000px) 715px, (min-width: 750px) calc((100vw - 11.5rem) / 2), calc(100vw - 4rem)'; 111 | 112 | if (product.classList.contains('product--medium')) { 113 | mediaImageSizes = mediaImageSizes.replace('715px', '605px'); 114 | } else if (product.classList.contains('product--small')) { 115 | mediaImageSizes = mediaImageSizes.replace('715px', '495px'); 116 | } 117 | 118 | mediaImages.forEach((img) => img.setAttribute('sizes', mediaImageSizes)); 119 | } 120 | } 121 | ); 122 | } 123 | -------------------------------------------------------------------------------- /assets/search-form.js: -------------------------------------------------------------------------------- 1 | class SearchForm extends HTMLElement { 2 | constructor() { 3 | super(); 4 | this.input = this.querySelector('input[type="search"]'); 5 | this.resetButton = this.querySelector('button[type="reset"]'); 6 | 7 | if (this.input) { 8 | this.input.form.addEventListener('reset', this.onFormReset.bind(this)); 9 | this.input.addEventListener( 10 | 'input', 11 | debounce((event) => { 12 | this.onChange(event); 13 | }, 300).bind(this) 14 | ); 15 | } 16 | } 17 | 18 | toggleResetButton() { 19 | const resetIsHidden = this.resetButton.classList.contains('hidden'); 20 | if (this.input.value.length > 0 && resetIsHidden) { 21 | this.resetButton.classList.remove('hidden'); 22 | } else if (this.input.value.length === 0 && !resetIsHidden) { 23 | this.resetButton.classList.add('hidden'); 24 | } 25 | } 26 | 27 | onChange() { 28 | this.toggleResetButton(); 29 | } 30 | 31 | shouldResetForm() { 32 | return !document.querySelector('[aria-selected="true"] a'); 33 | } 34 | 35 | onFormReset(event) { 36 | // Prevent default so the form reset doesn't set the value gotten from the url on page load 37 | event.preventDefault(); 38 | // Don't reset if the user has selected an element on the predictive search dropdown 39 | if (this.shouldResetForm()) { 40 | this.input.value = ''; 41 | this.input.focus(); 42 | this.toggleResetButton(); 43 | } 44 | } 45 | } 46 | 47 | customElements.define('search-form', SearchForm); 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/section-related-products.css: -------------------------------------------------------------------------------- 1 | .related-products { 2 | display: block; 3 | } 4 | 5 | .related-products__heading { 6 | margin: 0 0 3rem; 7 | } 8 | -------------------------------------------------------------------------------- /assets/section-rich-text.css: -------------------------------------------------------------------------------- 1 | .rich-text { 2 | z-index: 1; 3 | } 4 | 5 | .rich-text__wrapper { 6 | display: flex; 7 | justify-content: center; 8 | width: calc(100% - 4rem / var(--font-body-scale)); 9 | } 10 | 11 | .rich-text:not(.rich-text--full-width) .rich-text__wrapper { 12 | margin: auto; 13 | width: calc(100% - 8rem / var(--font-body-scale)); 14 | } 15 | 16 | .rich-text__blocks { 17 | width: 100%; 18 | } 19 | 20 | @media screen and (min-width: 750px) { 21 | .rich-text__wrapper { 22 | width: 100%; 23 | } 24 | 25 | .rich-text__wrapper--left { 26 | justify-content: flex-start; 27 | } 28 | 29 | .rich-text__wrapper--right { 30 | justify-content: flex-end; 31 | } 32 | 33 | .rich-text__blocks { 34 | max-width: 50rem; 35 | } 36 | } 37 | 38 | @media screen and (min-width: 990px) { 39 | .rich-text__blocks { 40 | max-width: 78rem; 41 | } 42 | } 43 | 44 | .rich-text__blocks * { 45 | overflow-wrap: break-word; 46 | } 47 | 48 | .rich-text__blocks > * { 49 | margin-top: 0; 50 | margin-bottom: 0; 51 | } 52 | 53 | .rich-text__blocks > * + * { 54 | margin-top: 2rem; 55 | } 56 | 57 | .rich-text__blocks > * + a { 58 | margin-top: 3rem; 59 | } 60 | 61 | .rich-text__buttons { 62 | display: inline-flex; 63 | justify-content: center; 64 | flex-wrap: wrap; 65 | gap: 1rem; 66 | width: 100%; 67 | max-width: 45rem; 68 | word-break: break-word; 69 | } 70 | 71 | .rich-text__buttons--multiple > * { 72 | flex-grow: 1; 73 | min-width: 22rem; 74 | } 75 | 76 | .rich-text__buttons + .rich-text__buttons { 77 | margin-top: 1rem; 78 | } 79 | 80 | .rich-text__blocks.left .rich-text__buttons { 81 | justify-content: flex-start; 82 | } 83 | 84 | .rich-text__blocks.right .rich-text__buttons { 85 | justify-content: flex-end; 86 | } 87 | -------------------------------------------------------------------------------- /assets/template-collection.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width: 749px) { 2 | .collection .grid__item:only-child { 3 | flex: 0 0 100%; 4 | max-width: 100%; 5 | } 6 | } 7 | 8 | @media screen and (max-width: 989px) { 9 | .collection .slider.slider--tablet { 10 | margin-bottom: 1.5rem; 11 | } 12 | } 13 | 14 | .collection .loading-overlay { 15 | position: absolute; 16 | z-index: 1; 17 | width: 1.8rem; 18 | } 19 | 20 | @media screen and (max-width: 749px) { 21 | .collection .loading-overlay { 22 | top: 0; 23 | right: 0; 24 | } 25 | } 26 | 27 | @media screen and (min-width: 750px) { 28 | .collection .loading-overlay { 29 | left: 0; 30 | } 31 | } 32 | 33 | .collection .loading-overlay { 34 | top: 0; 35 | right: 0; 36 | bottom: 0; 37 | left: 0; 38 | display: none; 39 | width: 100%; 40 | padding: 0 1.5rem; 41 | opacity: 0.7; 42 | } 43 | 44 | @media screen and (min-width: 750px) { 45 | .collection .loading-overlay { 46 | padding-left: 5rem; 47 | padding-right: 5rem; 48 | } 49 | } 50 | 51 | .collection.loading .loading-overlay { 52 | display: block; 53 | } 54 | 55 | .collection--empty .title-wrapper { 56 | margin-top: 10rem; 57 | margin-bottom: 15rem; 58 | } 59 | 60 | @media screen and (max-width: 989px) { 61 | .collection .slider--tablet.product-grid { 62 | scroll-padding-left: 1.5rem; 63 | } 64 | } 65 | 66 | .collection__description > * { 67 | margin: 0; 68 | } 69 | 70 | .collection__title.title-wrapper { 71 | margin-bottom: 2.5rem; 72 | } 73 | 74 | .collection__title .title:not(:only-child) { 75 | margin-bottom: 1rem; 76 | } 77 | 78 | @media screen and (min-width: 990px) { 79 | .collection__title--desktop-slider .title { 80 | margin-bottom: 2.5rem; 81 | } 82 | 83 | .collection__title.title-wrapper--self-padded-tablet-down { 84 | padding: 0 5rem; 85 | } 86 | 87 | .collection slider-component:not(.page-width-desktop) { 88 | padding: 0; 89 | } 90 | 91 | .collection--full-width slider-component:not(.slider-component-desktop) { 92 | padding: 0 1.5rem; 93 | max-width: none; 94 | } 95 | } 96 | 97 | .collection__view-all a:not(.link) { 98 | margin-top: 1rem; 99 | } 100 | -------------------------------------------------------------------------------- /assets/theme-editor.js: -------------------------------------------------------------------------------- 1 | function hideProductModal() { 2 | const productModal = document.querySelectorAll('product-modal[open]'); 3 | productModal && productModal.forEach((modal) => modal.hide()); 4 | } 5 | 6 | document.addEventListener('shopify:block:select', function (event) { 7 | hideProductModal(); 8 | const blockSelectedIsSlide = event.target.classList.contains('slideshow__slide'); 9 | if (!blockSelectedIsSlide) return; 10 | 11 | const parentSlideshowComponent = event.target.closest('slideshow-component'); 12 | parentSlideshowComponent.pause(); 13 | 14 | setTimeout(function () { 15 | parentSlideshowComponent.slider.scrollTo({ 16 | left: event.target.offsetLeft, 17 | }); 18 | }, 200); 19 | }); 20 | 21 | document.addEventListener('shopify:block:deselect', function (event) { 22 | const blockDeselectedIsSlide = event.target.classList.contains('slideshow__slide'); 23 | if (!blockDeselectedIsSlide) return; 24 | const parentSlideshowComponent = event.target.closest('slideshow-component'); 25 | if (parentSlideshowComponent.autoplayButtonIsSetToPlay) parentSlideshowComponent.play(); 26 | }); 27 | 28 | document.addEventListener('shopify:section:load', () => { 29 | hideProductModal(); 30 | const zoomOnHoverScript = document.querySelector('[id^=EnableZoomOnHover]'); 31 | if (!zoomOnHoverScript) return; 32 | if (zoomOnHoverScript) { 33 | const newScriptTag = document.createElement('script'); 34 | newScriptTag.src = zoomOnHoverScript.src; 35 | zoomOnHoverScript.parentNode.replaceChild(newScriptTag, zoomOnHoverScript); 36 | } 37 | }); 38 | 39 | document.addEventListener('shopify:section:unload', (event) => { 40 | document.querySelectorAll(`[data-section="${event.detail.sectionId}"]`).forEach((element) => { 41 | element.remove(); 42 | document.body.classList.remove('overflow-hidden'); 43 | }); 44 | }); 45 | 46 | document.addEventListener('shopify:section:reorder', () => hideProductModal()); 47 | 48 | document.addEventListener('shopify:section:select', () => hideProductModal()); 49 | 50 | document.addEventListener('shopify:section:deselect', () => hideProductModal()); 51 | 52 | document.addEventListener('shopify:inspector:activate', () => hideProductModal()); 53 | 54 | document.addEventListener('shopify:inspector:deactivate', () => hideProductModal()); 55 | -------------------------------------------------------------------------------- /assets/video-section.css: -------------------------------------------------------------------------------- 1 | .video-section__media { 2 | --ratio-percent: 56.25%; 3 | position: relative; 4 | padding-bottom: calc(var(--ratio-percent) - var(--media-border-width)); 5 | } 6 | 7 | /* Needed for gradient continuity with or without animation so that transparent PNG images come up as we would expect */ 8 | .scroll-trigger:where(.gradient.video-section__media) { 9 | background: transparent; 10 | } 11 | 12 | .video-section__media.global-media-settings--full-width { 13 | padding-bottom: var(--ratio-percent); 14 | } 15 | 16 | .video-section__media.deferred-media { 17 | box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) 18 | rgba(var(--color-shadow), var(--media-shadow-opacity)); 19 | } 20 | 21 | .video-section__media.deferred-media:after { 22 | content: none; 23 | } 24 | 25 | .video-section__poster.deferred-media__poster:focus { 26 | outline-offset: 0.3rem; 27 | } 28 | 29 | .video-section__media iframe { 30 | background-color: rgba(var(--color-foreground), 0.03); 31 | border: 0; 32 | } 33 | 34 | .video-section__poster, 35 | .video-section__media iframe, 36 | .video-section__media video { 37 | position: absolute; 38 | width: 100%; 39 | height: 100%; 40 | } 41 | 42 | .video-section__media video { 43 | background: #000000; 44 | } 45 | 46 | .video-section__media.media-fit-cover video { 47 | object-fit: cover; 48 | } 49 | -------------------------------------------------------------------------------- /release-notes.md: -------------------------------------------------------------------------------- 1 | Dawn 15.2.0 provides a few fixes for known bugs and updates the styling for the new dynamic checkout buttons. 2 | ### Changed 3 | - Adjust the local selector dropdown to match the maximum width of its content. 4 | - Adjust the styling for dynamic checkout buttons now that they’re using a new HTML structure. 5 | ### Fixes and improvements 6 | - Fix issue where while in the theme editor, a modal wouldn’t be cleared once the section it belonged to was removed. 7 | - Updated the account login link to use a nofollow attribute so that google doesn’t interpret it as spammy backlinking. 8 | - Fix issue where the svg icon for the filters were not clickable 9 | -------------------------------------------------------------------------------- /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": "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 | -------------------------------------------------------------------------------- /sections/cart-icon-bubble.liquid: -------------------------------------------------------------------------------- 1 | {% if cart == empty %} 2 | {{ 'icon-cart-empty.svg' | inline_asset_content }} 3 | {% else %} 4 | {{ 'icon-cart.svg' | inline_asset_content }} 5 | {% endif %} 6 | 7 | {{ 'templates.cart.cart' | t }} 8 | {%- if cart != empty -%} 9 |
10 | {%- if cart.item_count < 100 -%} 11 | 12 | {%- endif -%} 13 | {{ 'sections.header.cart_count' | t: count: cart.item_count }} 14 |
15 | {%- endif -%} 16 | -------------------------------------------------------------------------------- /sections/cart-live-region-text.liquid: -------------------------------------------------------------------------------- 1 | {{ 'sections.cart.new_estimated_total' | t }}: {{ cart.total_price | money_with_currency }} 2 | -------------------------------------------------------------------------------- /sections/cart-notification-button.liquid: -------------------------------------------------------------------------------- 1 | {{ 'general.cart.view' | t: count: cart.item_count }} 2 | -------------------------------------------------------------------------------- /sections/cart-notification-product.liquid: -------------------------------------------------------------------------------- 1 | {%- if cart != empty -%} 2 | {%- for item in cart.items -%} 3 |
4 | {%- if item.image -%} 5 |
6 | {{ item.image.alt | escape }} 13 |
14 | {%- endif -%} 15 |
16 | {%- if settings.show_vendor -%} 17 |

{{ item.product.vendor }}

18 | {%- endif -%} 19 |

{{ item.product.title | escape }}

20 |
21 | {%- unless item.product.has_only_default_variant -%} 22 | {%- for option in item.options_with_values -%} 23 |
24 |
{{ option.name }}:
25 |
{{ option.value }}
26 |
27 | {%- endfor -%} 28 | {%- endunless -%} 29 | {%- for property in item.properties -%} 30 | {%- assign property_first_char = property.first | slice: 0 -%} 31 | {%- if property.last != blank and property_first_char != '_' -%} 32 |
33 |
{{ property.first }}:
34 |
35 | {%- if property.last contains '/uploads/' -%} 36 | 37 | {{ property.last | split: '/' | last }} 38 | 39 | {%- else -%} 40 | {{ property.last }} 41 | {%- endif -%} 42 |
43 |
44 | {%- endif -%} 45 | {%- endfor -%} 46 |
47 | {%- if item.selling_plan_allocation != null -%} 48 |

{{ item.selling_plan_allocation.selling_plan.name }}

49 | {%- endif -%} 50 |
51 |
52 | {%- endfor -%} 53 | {%- endif -%} 54 | -------------------------------------------------------------------------------- /sections/custom-liquid.liquid: -------------------------------------------------------------------------------- 1 | {%- style -%} 2 | .section-{{ section.id }}-padding { 3 | padding-top: calc({{ section.settings.padding_top }}px * 0.75); 4 | padding-bottom: calc({{ section.settings.padding_bottom }}px * 0.75); 5 | } 6 | 7 | @media screen and (min-width: 750px) { 8 | .section-{{ section.id }}-padding { 9 | padding-top: {{ section.settings.padding_top }}px; 10 | padding-bottom: {{ section.settings.padding_bottom }}px; 11 | } 12 | } 13 | {%- endstyle -%} 14 |
15 |
16 | {{ section.settings.custom_liquid }} 17 |
18 |
19 | 20 | {% schema %} 21 | { 22 | "name": "t:sections.custom-liquid.name", 23 | "tag": "section", 24 | "class": "section", 25 | "settings": [ 26 | { 27 | "type": "liquid", 28 | "id": "custom_liquid", 29 | "label": "t:sections.custom-liquid.settings.custom_liquid.label", 30 | "info": "t:sections.custom-liquid.settings.custom_liquid.info" 31 | }, 32 | { 33 | "type": "color_scheme", 34 | "id": "color_scheme", 35 | "label": "t:sections.all.colors.label", 36 | "default": "scheme-1" 37 | }, 38 | { 39 | "type": "header", 40 | "content": "t:sections.all.padding.section_padding_heading" 41 | }, 42 | { 43 | "type": "range", 44 | "id": "padding_top", 45 | "min": 0, 46 | "max": 100, 47 | "step": 4, 48 | "unit": "px", 49 | "label": "t:sections.all.padding.padding_top", 50 | "default": 40 51 | }, 52 | { 53 | "type": "range", 54 | "id": "padding_bottom", 55 | "min": 0, 56 | "max": 100, 57 | "step": 4, 58 | "unit": "px", 59 | "label": "t:sections.all.padding.padding_bottom", 60 | "default": 52 61 | } 62 | ], 63 | "presets": [ 64 | { 65 | "name": "t:sections.custom-liquid.presets.name" 66 | } 67 | ] 68 | } 69 | {% endschema %} 70 | -------------------------------------------------------------------------------- /sections/footer-group.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "t:sections.footer.name", 3 | "type": "footer", 4 | "sections": { 5 | "footer": { 6 | "type": "footer", 7 | "blocks": { 8 | "footer-0": { 9 | "type": "link_list", 10 | "settings": { 11 | "heading": "Quick links", 12 | "menu": "footer" 13 | } 14 | }, 15 | "footer-1": { 16 | "type": "link_list", 17 | "settings": { 18 | "heading": "Info", 19 | "menu": "footer" 20 | } 21 | }, 22 | "footer-2": { 23 | "type": "text", 24 | "settings": { 25 | "heading": "Our mission", 26 | "subtext": "

Share contact information, store details, and brand content with your customers.<\/p>" 27 | } 28 | } 29 | }, 30 | "block_order": [ 31 | "footer-0", 32 | "footer-1", 33 | "footer-2" 34 | ], 35 | "settings": { 36 | "color_scheme": "scheme-1", 37 | "newsletter_enable": true, 38 | "newsletter_heading": "Subscribe to our emails", 39 | "show_social": true, 40 | "enable_country_selector": false, 41 | "enable_language_selector": false, 42 | "payment_enable": true, 43 | "show_policy": false, 44 | "margin_top": 48, 45 | "padding_top": 36, 46 | "padding_bottom": 36 47 | } 48 | } 49 | }, 50 | "order": [ 51 | "footer" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /sections/header-group.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "t:sections.header.name", 3 | "type": "header", 4 | "sections": { 5 | "announcement-bar": { 6 | "type": "announcement-bar", 7 | "blocks": { 8 | "announcement-bar-0": { 9 | "type": "announcement", 10 | "settings": { 11 | "text": "Welcome to our store", 12 | "text_alignment": "center", 13 | "color_scheme": "scheme-1", 14 | "link": "" 15 | } 16 | } 17 | }, 18 | "block_order": [ 19 | "announcement-bar-0" 20 | ] 21 | }, 22 | "header": { 23 | "type": "header", 24 | "settings": { 25 | "color_scheme": "scheme-1", 26 | "logo_position": "middle-left", 27 | "menu": "main-menu", 28 | "menu_type_desktop": "dropdown", 29 | "sticky_header_type": "on-scroll-up", 30 | "show_line_separator": true, 31 | "enable_country_selector": true, 32 | "enable_language_selector": true, 33 | "mobile_logo_position": "center", 34 | "margin_bottom": 0, 35 | "padding_top": 20, 36 | "padding_bottom": 20 37 | } 38 | } 39 | }, 40 | "order": [ 41 | "announcement-bar", 42 | "header" 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sections/main-activate-account.liquid: -------------------------------------------------------------------------------- 1 | {{ 'customer.css' | asset_url | stylesheet_tag }} 2 | 3 | {%- style -%} 4 | .section-{{ section.id }}-padding { 5 | padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; 6 | padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; 7 | } 8 | 9 | @media screen and (min-width: 750px) { 10 | .section-{{ section.id }}-padding { 11 | padding-top: {{ section.settings.padding_top }}px; 12 | padding-bottom: {{ section.settings.padding_bottom }}px; 13 | } 14 | } 15 | {%- endstyle -%} 16 | 17 |
18 |

19 | {{ 'customer.activate_account.title' | t }} 20 |

21 |

22 | {{ 'customer.activate_account.subtext' | t }} 23 |

24 | {%- form 'activate_customer_password' -%} 25 | {%- if form.errors -%} 26 |

27 | 28 | {{- 'icon-error.svg' | inline_asset_content -}} 29 | 30 | {{ 'templates.contact.form.error_heading' | t }} 31 |

32 | 46 | {%- endif -%} 47 | 48 |
49 | 60 | 63 | {%- if form.errors contains 'password' -%} 64 | 65 | 66 | {{- 'icon-error.svg' | inline_asset_content -}} 67 | 68 | {{ form.errors.translated_fields.password | capitalize }} 69 | {{ form.errors.messages.password }} 70 | 71 | {%- endif -%} 72 |
73 | 74 |
75 | 86 | 89 | {%- if form.errors contains 'password_confirmation' -%} 90 | 91 | 92 | {{- 'icon-error.svg' | inline_asset_content -}} 93 | 94 | {{ form.errors.translated_fields.password_confirmation | capitalize }} 95 | {{ form.errors.messages.password_confirmation }} 96 | 97 | {%- endif -%} 98 |
99 | 100 | 103 | 106 | {%- endform -%} 107 |
108 | 109 | {% schema %} 110 | { 111 | "name": "t:sections.main-activate-account.name", 112 | "settings": [ 113 | { 114 | "type": "header", 115 | "content": "t:sections.all.padding.section_padding_heading" 116 | }, 117 | { 118 | "type": "range", 119 | "id": "padding_top", 120 | "min": 0, 121 | "max": 100, 122 | "step": 4, 123 | "unit": "px", 124 | "label": "t:sections.all.padding.padding_top", 125 | "default": 36 126 | }, 127 | { 128 | "type": "range", 129 | "id": "padding_bottom", 130 | "min": 0, 131 | "max": 100, 132 | "step": 4, 133 | "unit": "px", 134 | "label": "t:sections.all.padding.padding_bottom", 135 | "default": 36 136 | } 137 | ] 138 | } 139 | {% endschema %} 140 | -------------------------------------------------------------------------------- /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 | {%- style -%} 6 | .section-{{ section.id }}-padding { 7 | padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; 8 | padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; 9 | } 10 | 11 | @media screen and (min-width: 750px) { 12 | .section-{{ section.id }}-padding { 13 | padding-top: {{ section.settings.padding_top }}px; 14 | padding-bottom: {{ section.settings.padding_bottom }}px; 15 | } 16 | } 17 | {%- endstyle -%} 18 | 19 | {%- paginate blog.articles by 6 -%} 20 |
21 |

22 | {{ blog.title | escape }} 23 |

24 | 25 |
26 | {%- for article in blog.articles -%} 27 |
34 | {%- render 'article-card', 35 | article: article, 36 | media_height: section.settings.image_height, 37 | media_aspect_ratio: article.image.aspect_ratio, 38 | show_image: section.settings.show_image, 39 | show_date: section.settings.show_date, 40 | show_author: section.settings.show_author, 41 | show_excerpt: true 42 | -%} 43 |
44 | {%- endfor -%} 45 |
46 | 47 | {%- if paginate.pages > 1 -%} 48 | {%- render 'pagination', paginate: paginate -%} 49 | {%- endif -%} 50 |
51 | {%- endpaginate -%} 52 | 53 | {% schema %} 54 | { 55 | "name": "t:sections.main-blog.name", 56 | "tag": "section", 57 | "class": "section", 58 | "settings": [ 59 | { 60 | "type": "header", 61 | "content": "t:sections.main-blog.settings.header.content" 62 | }, 63 | { 64 | "type": "select", 65 | "id": "layout", 66 | "options": [ 67 | { 68 | "value": "grid", 69 | "label": "t:sections.main-blog.settings.layout.options__1.label" 70 | }, 71 | { 72 | "value": "collage", 73 | "label": "t:sections.main-blog.settings.layout.options__2.label" 74 | } 75 | ], 76 | "default": "collage", 77 | "label": "t:sections.main-blog.settings.layout.label", 78 | "info": "t:sections.main-blog.settings.layout.info" 79 | }, 80 | { 81 | "type": "checkbox", 82 | "id": "show_image", 83 | "default": true, 84 | "label": "t:sections.main-blog.settings.show_image.label" 85 | }, 86 | { 87 | "type": "select", 88 | "id": "image_height", 89 | "options": [ 90 | { 91 | "value": "adapt", 92 | "label": "t:sections.main-blog.settings.image_height.options__1.label" 93 | }, 94 | { 95 | "value": "small", 96 | "label": "t:sections.main-blog.settings.image_height.options__2.label" 97 | }, 98 | { 99 | "value": "medium", 100 | "label": "t:sections.main-blog.settings.image_height.options__3.label" 101 | }, 102 | { 103 | "value": "large", 104 | "label": "t:sections.main-blog.settings.image_height.options__4.label" 105 | } 106 | ], 107 | "default": "medium", 108 | "label": "t:sections.main-blog.settings.image_height.label", 109 | "info": "t:sections.main-blog.settings.image_height.info" 110 | }, 111 | { 112 | "type": "checkbox", 113 | "id": "show_date", 114 | "default": true, 115 | "label": "t:sections.main-blog.settings.show_date.label" 116 | }, 117 | { 118 | "type": "checkbox", 119 | "id": "show_author", 120 | "default": false, 121 | "label": "t:sections.main-blog.settings.show_author.label" 122 | }, 123 | { 124 | "type": "paragraph", 125 | "content": "t:sections.main-blog.settings.paragraph.content" 126 | }, 127 | { 128 | "type": "header", 129 | "content": "t:sections.all.padding.section_padding_heading" 130 | }, 131 | { 132 | "type": "range", 133 | "id": "padding_top", 134 | "min": 0, 135 | "max": 100, 136 | "step": 4, 137 | "unit": "px", 138 | "label": "t:sections.all.padding.padding_top", 139 | "default": 36 140 | }, 141 | { 142 | "type": "range", 143 | "id": "padding_bottom", 144 | "min": 0, 145 | "max": 100, 146 | "step": 4, 147 | "unit": "px", 148 | "label": "t:sections.all.padding.padding_bottom", 149 | "default": 36 150 | } 151 | ] 152 | } 153 | {% endschema %} 154 | -------------------------------------------------------------------------------- /sections/main-collection-banner.liquid: -------------------------------------------------------------------------------- 1 | {% comment %}theme-check-disable ImgLazyLoading{% endcomment %} 2 | {{ 'component-collection-hero.css' | asset_url | stylesheet_tag }} 3 | 4 | {%- style -%} 5 | @media screen and (max-width: 749px) { 6 | .collection-hero--with-image .collection-hero__inner { 7 | padding-bottom: calc({{ settings.media_shadow_vertical_offset | at_least: 0 }}px + 2rem); 8 | } 9 | } 10 | {%- endstyle -%} 11 | 12 |
13 |
14 |
15 |

16 | {{ 'sections.collection_template.title' | t }}: 17 | {{- collection.title | escape -}} 18 |

19 | 20 | {%- if section.settings.show_collection_description -%} 21 |
{{ collection.description }}
22 | {%- endif -%} 23 |
24 | 25 | {%- if section.settings.show_collection_image and collection.image -%} 26 |
27 | {{ collection.image.alt | escape }} 43 |
44 | {%- endif -%} 45 |
46 |
47 | 48 | {% schema %} 49 | { 50 | "name": "t:sections.main-collection-banner.name", 51 | "class": "section", 52 | "settings": [ 53 | { 54 | "type": "paragraph", 55 | "content": "t:sections.main-collection-banner.settings.paragraph.content" 56 | }, 57 | { 58 | "type": "checkbox", 59 | "id": "show_collection_description", 60 | "default": true, 61 | "label": "t:sections.main-collection-banner.settings.show_collection_description.label" 62 | }, 63 | { 64 | "type": "checkbox", 65 | "id": "show_collection_image", 66 | "default": false, 67 | "label": "t:sections.main-collection-banner.settings.show_collection_image.label", 68 | "info": "t:sections.main-collection-banner.settings.show_collection_image.info" 69 | }, 70 | { 71 | "type": "color_scheme", 72 | "id": "color_scheme", 73 | "label": "t:sections.all.colors.label", 74 | "default": "scheme-1" 75 | } 76 | ] 77 | } 78 | {% endschema %} 79 | -------------------------------------------------------------------------------- /sections/main-list-collections.liquid: -------------------------------------------------------------------------------- 1 | {{ 'component-card.css' | asset_url | stylesheet_tag }} 2 | {{ 'section-collection-list.css' | asset_url | stylesheet_tag }} 3 | 4 |
5 |

6 | {{ section.settings.title }} 7 |

8 | {%- liquid 9 | case section.settings.sort 10 | when 'products_high', 'products_low' 11 | assign collections = collections | sort: 'all_products_count' 12 | when 'date', 'date_reversed' 13 | assign collections = collections | sort: 'published_at' 14 | endcase 15 | 16 | if section.settings.sort == 'products_high' or section.settings.sort == 'date_reversed' or section.settings.sort == 'alphabetical_reversed' 17 | assign collections = collections | reverse 18 | endif 19 | 20 | assign moduloResult = 28 | modulo: section.settings.columns_desktop 21 | assign paginate_by = 30 22 | if moduloResult == 0 23 | assign paginate_by = 28 24 | endif 25 | -%} 26 | {%- paginate collections by paginate_by -%} 27 | 47 | {% render 'pagination', paginate: paginate %} 48 | {%- endpaginate -%} 49 |
50 | {% schema %} 51 | { 52 | "name": "t:sections.main-list-collections.name", 53 | "class": "section", 54 | "settings": [ 55 | { 56 | "type": "inline_richtext", 57 | "id": "title", 58 | "label": "t:sections.main-list-collections.settings.title.label", 59 | "default": "t:sections.main-list-collections.settings.title.default" 60 | }, 61 | { 62 | "type": "select", 63 | "id": "sort", 64 | "options": [ 65 | { 66 | "value": "alphabetical", 67 | "label": "t:sections.main-list-collections.settings.sort.options__1.label" 68 | }, 69 | { 70 | "value": "alphabetical_reversed", 71 | "label": "t:sections.main-list-collections.settings.sort.options__2.label" 72 | }, 73 | { 74 | "value": "date_reversed", 75 | "label": "t:sections.main-list-collections.settings.sort.options__3.label" 76 | }, 77 | { 78 | "value": "date", 79 | "label": "t:sections.main-list-collections.settings.sort.options__4.label" 80 | }, 81 | { 82 | "value": "products_high", 83 | "label": "t:sections.main-list-collections.settings.sort.options__5.label" 84 | }, 85 | { 86 | "value": "products_low", 87 | "label": "t:sections.main-list-collections.settings.sort.options__6.label" 88 | } 89 | ], 90 | "default": "alphabetical", 91 | "label": "t:sections.main-list-collections.settings.sort.label" 92 | }, 93 | { 94 | "type": "select", 95 | "id": "image_ratio", 96 | "options": [ 97 | { 98 | "value": "adapt", 99 | "label": "t:sections.main-list-collections.settings.image_ratio.options__1.label" 100 | }, 101 | { 102 | "value": "portrait", 103 | "label": "t:sections.main-list-collections.settings.image_ratio.options__2.label" 104 | }, 105 | { 106 | "value": "square", 107 | "label": "t:sections.main-list-collections.settings.image_ratio.options__3.label" 108 | } 109 | ], 110 | "default": "adapt", 111 | "label": "t:sections.main-list-collections.settings.image_ratio.label", 112 | "info": "t:sections.main-list-collections.settings.image_ratio.info" 113 | }, 114 | { 115 | "type": "range", 116 | "id": "columns_desktop", 117 | "min": 1, 118 | "max": 6, 119 | "step": 1, 120 | "default": 3, 121 | "label": "t:sections.main-list-collections.settings.columns_desktop.label" 122 | }, 123 | { 124 | "type": "header", 125 | "content": "t:sections.main-list-collections.settings.header_mobile.content" 126 | }, 127 | { 128 | "type": "select", 129 | "id": "columns_mobile", 130 | "options": [ 131 | { 132 | "value": "1", 133 | "label": "t:sections.main-list-collections.settings.columns_mobile.options__1.label" 134 | }, 135 | { 136 | "value": "2", 137 | "label": "t:sections.main-list-collections.settings.columns_mobile.options__2.label" 138 | } 139 | ], 140 | "default": "2", 141 | "label": "t:sections.main-list-collections.settings.columns_mobile.label" 142 | } 143 | ] 144 | } 145 | {% endschema %} 146 | -------------------------------------------------------------------------------- /sections/main-page.liquid: -------------------------------------------------------------------------------- 1 | {{ 'section-main-page.css' | asset_url | stylesheet_tag }} 2 | 3 | {%- style -%} 4 | .section-{{ section.id }}-padding { 5 | padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; 6 | padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; 7 | } 8 | 9 | @media screen and (min-width: 750px) { 10 | .section-{{ section.id }}-padding { 11 | padding-top: {{ section.settings.padding_top }}px; 12 | padding-bottom: {{ section.settings.padding_bottom }}px; 13 | } 14 | } 15 | {%- endstyle -%} 16 | 17 |
18 |

19 | {{ page.title | escape }} 20 |

21 |
22 | {{ page.content }} 23 |
24 |
25 | 26 | {% schema %} 27 | { 28 | "name": "t:sections.main-page.name", 29 | "tag": "section", 30 | "class": "section", 31 | "settings": [ 32 | { 33 | "type": "header", 34 | "content": "t:sections.all.padding.section_padding_heading" 35 | }, 36 | { 37 | "type": "range", 38 | "id": "padding_top", 39 | "min": 0, 40 | "max": 100, 41 | "step": 4, 42 | "unit": "px", 43 | "label": "t:sections.all.padding.padding_top", 44 | "default": 36 45 | }, 46 | { 47 | "type": "range", 48 | "id": "padding_bottom", 49 | "min": 0, 50 | "max": 100, 51 | "step": 4, 52 | "unit": "px", 53 | "label": "t:sections.all.padding.padding_bottom", 54 | "default": 36 55 | } 56 | ] 57 | } 58 | {% endschema %} 59 | -------------------------------------------------------------------------------- /sections/main-password-footer.liquid: -------------------------------------------------------------------------------- 1 | {% assign scheme1 = settings.color_schemes | first %} 2 | {%- if section.settings.color_scheme == scheme1 -%}
{%- endif -%} 3 | 113 | 114 | {% schema %} 115 | { 116 | "name": "t:sections.main-password-footer.name", 117 | "settings": [ 118 | { 119 | "type": "color_scheme", 120 | "id": "color_scheme", 121 | "label": "t:sections.all.colors.label", 122 | "default": "scheme-1" 123 | } 124 | ] 125 | } 126 | {% endschema %} 127 | -------------------------------------------------------------------------------- /sections/main-password-header.liquid: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 | {%- if settings.logo != blank -%} 10 | {%- assign logo_alt = settings.logo.alt | default: shop.name | escape -%} 11 | {%- assign logo_height = settings.logo_width | divided_by: settings.logo.aspect_ratio -%} 12 | {{ 13 | settings.logo 14 | | image_url: width: 500 15 | | image_tag: 16 | class: 'password-logo', 17 | widths: '50, 100, 150, 200, 250, 300, 400, 500', 18 | width: settings.logo_width, 19 | height: logo_height, 20 | alt: logo_alt 21 | }} 22 | {%- else -%} 23 |

{{ shop.name }}

24 | {%- endif -%} 25 | 26 | {%- if shop.password_message != blank -%} 27 |
28 | {{ shop.password_message }} 29 |
30 | {%- endif -%} 31 | 32 | 33 | 99 | 100 |
101 |
102 | {% assign scheme1 = settings.color_schemes | first %} 103 | {%- if section.settings.color_scheme == scheme1 -%}
{%- endif -%} 104 | 105 | {% schema %} 106 | { 107 | "name": "t:sections.main-password-header.name", 108 | "settings": [ 109 | { 110 | "type": "header", 111 | "content": "t:sections.main-password-header.settings.logo_header.content" 112 | }, 113 | { 114 | "type": "paragraph", 115 | "content": "t:sections.main-password-header.settings.logo_help.content" 116 | }, 117 | { 118 | "type": "color_scheme", 119 | "id": "color_scheme", 120 | "label": "t:sections.all.colors.label", 121 | "default": "scheme-1" 122 | } 123 | ] 124 | } 125 | {% endschema %} 126 | -------------------------------------------------------------------------------- /sections/main-reset-password.liquid: -------------------------------------------------------------------------------- 1 | {{ 'customer.css' | asset_url | stylesheet_tag }} 2 | 3 | {%- style -%} 4 | .section-{{ section.id }}-padding { 5 | padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; 6 | padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; 7 | } 8 | 9 | @media screen and (min-width: 750px) { 10 | .section-{{ section.id }}-padding { 11 | padding-top: {{ section.settings.padding_top }}px; 12 | padding-bottom: {{ section.settings.padding_bottom }}px; 13 | } 14 | } 15 | {%- endstyle -%} 16 | 17 |
18 |

19 | {{ 'customer.reset_password.title' | t }} 20 |

21 |

22 | {{ 'customer.reset_password.subtext' | t }} 23 |

24 | {%- form 'reset_customer_password' -%} 25 | {%- if form.errors -%} 26 |

27 | {{ 'accessibility.error' | t }} 28 | 29 | {{- 'icon-error.svg' | inline_asset_content -}} 30 | 31 | {{ 'templates.contact.form.error_heading' | t }} 32 |

33 | 47 | {%- endif -%} 48 | 49 |
50 | 61 | 64 | {%- if form.errors contains 'password' -%} 65 | 66 | 67 | {{- 'icon-error.svg' | inline_asset_content -}} 68 | 69 | {{ form.errors.translated_fields.password | capitalize }} 70 | {{ form.errors.messages.password }} 71 | 72 | {%- endif -%} 73 |
74 | 75 |
76 | 87 | 90 | {%- if form.errors contains 'password_confirmation' -%} 91 | 92 | 93 | {{- 'icon-error.svg' | inline_asset_content -}} 94 | 95 | {{ form.errors.translated_fields.password_confirmation | capitalize }} 96 | {{ form.errors.messages.password_confirmation }} 97 | 98 | {%- endif -%} 99 |
100 | 101 | 104 | {%- endform -%} 105 |
106 | 107 | {% schema %} 108 | { 109 | "name": "t:sections.main-reset-password.name", 110 | "settings": [ 111 | { 112 | "type": "header", 113 | "content": "t:sections.all.padding.section_padding_heading" 114 | }, 115 | { 116 | "type": "range", 117 | "id": "padding_top", 118 | "min": 0, 119 | "max": 100, 120 | "step": 4, 121 | "unit": "px", 122 | "label": "t:sections.all.padding.padding_top", 123 | "default": 36 124 | }, 125 | { 126 | "type": "range", 127 | "id": "padding_bottom", 128 | "min": 0, 129 | "max": 100, 130 | "step": 4, 131 | "unit": "px", 132 | "label": "t:sections.all.padding.padding_bottom", 133 | "default": 36 134 | } 135 | ] 136 | } 137 | {% endschema %} 138 | -------------------------------------------------------------------------------- /sections/page.liquid: -------------------------------------------------------------------------------- 1 | {{ 'section-main-page.css' | asset_url | stylesheet_tag }} 2 | 3 | {%- style -%} 4 | .section-{{ section.id }}-padding { 5 | padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; 6 | padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; 7 | } 8 | 9 | @media screen and (min-width: 750px) { 10 | .section-{{ section.id }}-padding { 11 | padding-top: {{ section.settings.padding_top }}px; 12 | padding-bottom: {{ section.settings.padding_bottom }}px; 13 | } 14 | } 15 | {%- endstyle -%} 16 | 17 |
18 |
19 |

20 | {%- if section.settings.page.title != blank -%} 21 | {{ section.settings.page.title | escape }} 22 | {%- else -%} 23 | {{ 'sections.page.title' | t }} 24 | {%- endif -%} 25 |

26 |
27 | {%- if section.settings.page.content != blank -%} 28 | {{ section.settings.page.content }} 29 | {%- else -%} 30 |
31 | {{ 'page' | placeholder_svg_tag: 'page-placeholder' }} 32 |
33 | {%- endif -%} 34 |
35 |
36 |
37 | 38 | {% schema %} 39 | { 40 | "name": "t:sections.page.name", 41 | "tag": "section", 42 | "class": "section", 43 | "disabled_on": { 44 | "groups": ["header", "footer"] 45 | }, 46 | "settings": [ 47 | { 48 | "type": "page", 49 | "id": "page", 50 | "label": "t:sections.page.settings.page.label" 51 | }, 52 | { 53 | "type": "select", 54 | "id": "heading_size", 55 | "options": [ 56 | { 57 | "value": "h2", 58 | "label": "t:sections.all.heading_size.options__1.label" 59 | }, 60 | { 61 | "value": "h1", 62 | "label": "t:sections.all.heading_size.options__2.label" 63 | }, 64 | { 65 | "value": "h0", 66 | "label": "t:sections.all.heading_size.options__3.label" 67 | }, 68 | { 69 | "value": "hxl", 70 | "label": "t:sections.all.heading_size.options__4.label" 71 | }, 72 | { 73 | "value": "hxxl", 74 | "label": "t:sections.all.heading_size.options__5.label" 75 | } 76 | ], 77 | "default": "h1", 78 | "label": "t:sections.all.heading_size.label" 79 | }, 80 | { 81 | "type": "color_scheme", 82 | "id": "color_scheme", 83 | "label": "t:sections.all.colors.label", 84 | "default": "scheme-1" 85 | }, 86 | { 87 | "type": "header", 88 | "content": "t:sections.all.padding.section_padding_heading" 89 | }, 90 | { 91 | "type": "range", 92 | "id": "padding_top", 93 | "min": 0, 94 | "max": 100, 95 | "step": 4, 96 | "unit": "px", 97 | "label": "t:sections.all.padding.padding_top", 98 | "default": 36 99 | }, 100 | { 101 | "type": "range", 102 | "id": "padding_bottom", 103 | "min": 0, 104 | "max": 100, 105 | "step": 4, 106 | "unit": "px", 107 | "label": "t:sections.all.padding.padding_bottom", 108 | "default": 36 109 | } 110 | ], 111 | "presets": [ 112 | { 113 | "name": "t:sections.page.presets.name" 114 | } 115 | ] 116 | } 117 | {% endschema %} 118 | -------------------------------------------------------------------------------- /snippets/cart-notification.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders cart notification 3 | 4 | Accepts: 5 | - color_scheme: {String} sets the color scheme of the notification (optional) 6 | - desktop_menu_type: {String} passes the desktop menu type which allows us to use the right css class (optional) 7 | 8 | Usage: 9 | {% render 'cart-notification' %} 10 | {% endcomment %} 11 | 12 | 13 |
14 | 54 |
55 |
56 | {% style %} 57 | .cart-notification { 58 | display: none; 59 | } 60 | {% endstyle %} 61 | -------------------------------------------------------------------------------- /snippets/header-dropdown-menu.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a standard dropdown style menu for the header. 3 | 4 | Usage: 5 | {% render 'header-dropdown-menu' %} 6 | {% endcomment %} 7 | 8 | 104 | -------------------------------------------------------------------------------- /snippets/header-mega-menu.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a megamenu for the header. 3 | 4 | Usage: 5 | {% render 'header-mega-menu' %} 6 | {% endcomment %} 7 | 8 | 95 | -------------------------------------------------------------------------------- /snippets/header-search.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a header search modal. Should be used with 'header.liquid' 3 | 4 | Accepts: 5 | - input_id: {String} Id for the search input element (required) 6 | 7 | Usage: 8 | {% render 'header-search', input_id: 'My-Id'%} 9 | {% endcomment %} 10 | 11 | 12 |
13 | 18 | 19 | 20 | {{- 'icon-search.svg' | inline_asset_content -}} 21 | 22 | 23 | {{- 'icon-close.svg' | inline_asset_content -}} 24 | 25 | 26 | 27 | 107 |
108 |
109 | -------------------------------------------------------------------------------- /snippets/icon-accordion.liquid: -------------------------------------------------------------------------------- 1 | {%- if icon != 'none' -%} 2 | {%- assign file = icon | replace: '_', '-' | prepend: 'icon-' | append: '.svg' -%} 3 | {{ file | inline_asset_content }} 4 | {%- endif -%} 5 | -------------------------------------------------------------------------------- /snippets/icon-with-text.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders icon with text block 3 | 4 | Accepts: 5 | - block: {Object} passes in the block information. 6 | 7 | 8 | Usage: 9 | {% render 'icon-with-text', 10 | block: block 11 | %} 12 | {% endcomment %} 13 | {%- liquid 14 | assign heading_1_empty = false 15 | assign heading_2_empty = false 16 | assign heading_3_empty = false 17 | assign text_only_all_items = true 18 | 19 | if block.settings.heading_1 == empty 20 | assign heading_1_empty = true 21 | endif 22 | 23 | if block.settings.heading_2 == empty 24 | assign heading_2_empty = true 25 | endif 26 | 27 | if block.settings.heading_3 == empty 28 | assign heading_3_empty = true 29 | endif 30 | 31 | if heading_1_empty == false and block.settings.icon_1 != 'none' or block.settings.image_1 != null 32 | assign text_only_all_items = false 33 | elsif heading_2_empty == false and block.settings.icon_2 != 'none' or block.settings.image_2 != null 34 | assign text_only_all_items = false 35 | elsif heading_3_empty == false and block.settings.icon_3 != 'none' or block.settings.image_3 != null 36 | assign text_only_all_items = false 37 | endif 38 | -%} 39 | 110 | -------------------------------------------------------------------------------- /snippets/language-localization.liquid: -------------------------------------------------------------------------------- 1 | {%- comment -%} 2 | Renders the language picker for the localization form 3 | 4 | Accepts: 5 | - localPosition: pass in the position in which the form is coming up to create specific IDs 6 | {%- endcomment -%} 7 | 8 |
9 | 19 | 48 |
49 | 50 | -------------------------------------------------------------------------------- /snippets/loading-spinner.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders loading-spinner. 3 | Accepts: 4 | - class: {string} css classes to replace the default ones (optional) 5 | 6 | Usage: 7 | {% render 'loading-spinner' %} 8 | {% endcomment %} 9 | 10 |
11 | {{ 'loading-spinner.svg' | inline_asset_content }} 12 |
13 | -------------------------------------------------------------------------------- /snippets/meta-tags.liquid: -------------------------------------------------------------------------------- 1 | {%- liquid 2 | assign og_title = page_title | default: shop.name 3 | assign og_url = canonical_url | default: request.origin 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 == 'password' 12 | assign og_url = request.origin 13 | endif 14 | %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {%- if page_image -%} 23 | 24 | 25 | 26 | 27 | {%- endif -%} 28 | 29 | {%- if request.page_type == 'product' -%} 30 | 31 | 32 | {%- endif -%} 33 | 34 | {%- if settings.social_twitter_link != blank -%} 35 | 36 | {%- endif -%} 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /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 | {% endcomment %} 13 | 14 | {{ 'component-pagination.css' | asset_url | stylesheet_tag }} 15 | 16 | {%- if paginate.parts.size > 0 -%} 17 |
18 | 77 |
78 | {%- endif -%} 79 | -------------------------------------------------------------------------------- /snippets/price-facet.liquid: -------------------------------------------------------------------------------- 1 | {{ cart.currency.symbol }} 2 | 3 |
4 | 18 | 21 |
22 | 23 | {%- if filter_type != 'vertical' -%} 24 | {{ cart.currency.symbol }} 25 | {%- endif -%} 26 | 27 |
28 | 42 | 45 |
46 | -------------------------------------------------------------------------------- /snippets/product-media-modal.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a product media modal. Also see 'product-media-gallery' 3 | 4 | Accepts: 5 | - product: {Object} Product liquid object 6 | - variant_images: {Array} Product images associated with a variant 7 | 8 | Usage: 9 | {% render 'product-media-modal' %} 10 | {% endcomment %} 11 | 12 | 13 | 57 | 58 | -------------------------------------------------------------------------------- /snippets/product-variant-options.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders product variant options 3 | 4 | Accepts: 5 | - product: {Object} product object. 6 | - option: {Object} current product_option object. 7 | - block: {Object} block object. 8 | - picker_type: {String} type of picker to dispay 9 | 10 | 11 | Usage: 12 | {% render 'product-variant-options', 13 | product: product, 14 | option: option, 15 | block: block 16 | picker_type: picker_type 17 | %} 18 | {% endcomment %} 19 | {%- liquid 20 | assign product_form_id = 'product-form-' | append: section.id 21 | -%} 22 | 23 | {%- for value in option.values -%} 24 | {%- liquid 25 | assign swatch_focal_point = null 26 | if value.swatch.image 27 | assign image_url = value.swatch.image | image_url: width: 50 28 | assign swatch_value = 'url(' | append: image_url | append: ')' 29 | assign swatch_focal_point = value.swatch.image.presentation.focal_point 30 | elsif value.swatch.color 31 | assign swatch_value = 'rgb(' | append: value.swatch.color.rgb | append: ')' 32 | else 33 | assign swatch_value = null 34 | endif 35 | 36 | assign option_disabled = true 37 | if value.available 38 | assign option_disabled = false 39 | endif 40 | -%} 41 | 42 | {%- capture input_id -%} 43 | {{ section.id }}-{{ option.position }}-{{ forloop.index0 -}} 44 | {%- endcapture -%} 45 | 46 | {%- capture input_name -%} 47 | {{ option.name }}-{{ option.position }} 48 | {%- endcapture -%} 49 | 50 | {%- capture input_dataset -%} 51 | data-product-url="{{ value.product_url }}" 52 | data-option-value-id="{{ value.id }}" 53 | {%- endcapture -%} 54 | 55 | {%- capture label_unavailable -%} 56 | 57 | {{- 'products.product.variant_sold_out_or_unavailable' | t -}} 58 | 59 | {%- endcapture -%} 60 | 61 | {%- if picker_type == 'swatch' -%} 62 | {%- capture help_text -%} 63 | {{ value | escape }} 64 | {{ label_unavailable }} 65 | {%- endcapture -%} 66 | {% 67 | render 'swatch-input', 68 | id: input_id, 69 | name: input_name, 70 | value: value | escape, 71 | swatch: value.swatch, 72 | product_form_id: product_form_id, 73 | checked: value.selected, 74 | visually_disabled: option_disabled, 75 | shape: block.settings.swatch_shape, 76 | help_text: help_text, 77 | additional_props: input_dataset 78 | %} 79 | {%- elsif picker_type == 'button' -%} 80 | 94 | 98 | {%- elsif picker_type == 'dropdown' or picker_type == 'swatch_dropdown' -%} 99 | 119 | {%- endif -%} 120 | {%- endfor -%} 121 | -------------------------------------------------------------------------------- /snippets/product-variant-picker.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders product variant-picker 3 | 4 | Accepts: 5 | - product: {Object} product object. 6 | - block: {Object} passing the block information. 7 | - product_form_id: {String} Id of the product form to which the variant picker is associated. 8 | Usage: 9 | {% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %} 10 | {% endcomment %} 11 | {%- unless product.has_only_default_variant -%} 12 | 17 | {%- for option in product.options_with_values -%} 18 | {%- liquid 19 | assign swatch_count = option.values | map: 'swatch' | compact | size 20 | assign picker_type = block.settings.picker_type 21 | 22 | if swatch_count > 0 and block.settings.swatch_shape != 'none' 23 | if block.settings.picker_type == 'dropdown' 24 | assign picker_type = 'swatch_dropdown' 25 | else 26 | assign picker_type = 'swatch' 27 | endif 28 | endif 29 | -%} 30 | {%- if picker_type == 'swatch' -%} 31 |
32 | 33 | {{ option.name }}: 34 | 35 | {{- option.selected_value -}} 36 | 37 | 38 | {% render 'product-variant-options', 39 | product: product, 40 | option: option, 41 | block: block, 42 | picker_type: picker_type 43 | %} 44 |
45 | {%- elsif picker_type == 'button' -%} 46 |
47 | {{ option.name }} 48 | {% render 'product-variant-options', 49 | product: product, 50 | option: option, 51 | block: block, 52 | picker_type: picker_type 53 | %} 54 |
55 | {%- else -%} 56 |
57 | 60 |
61 | {%- if picker_type == 'swatch_dropdown' -%} 62 | 66 | {% render 'swatch', swatch: option.selected_value.swatch, shape: block.settings.swatch_shape %} 67 | 68 | {%- endif -%} 69 | 82 | 83 | {{- 'icon-caret.svg' | inline_asset_content -}} 84 | 85 |
86 |
87 | {%- endif -%} 88 | {%- endfor -%} 89 | 90 | 93 |
94 | {%- endunless -%} 95 | -------------------------------------------------------------------------------- /snippets/progress-bar.liquid: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /snippets/quantity-input.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Quantity input 3 | 4 | Accepts: 5 | - variant: {Object} Variant object 6 | - variant_id: {String} Variant ID (optional) 7 | - min: {Number} Min (optional) 8 | 9 | Usage: 10 | {% render 'quantity-input' variant: variant %} 11 | {% endcomment %} 12 | 13 | 14 | 20 | 39 | 45 | {%- render 'progress-bar' -%} 46 | 47 | -------------------------------------------------------------------------------- /snippets/swatch-input.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a swatch input component. 3 | Accepts: 4 | - id: {String} unique input id 5 | - type: {String} input type. Accepts 'radio' or 'checkbox', defaults to 'radio' (optional) 6 | - name: {String} input name, 7 | - value: {ProductOptionValueDrop} input value 8 | - swatch: {SwatchDrop} the swatch drop 9 | - product_form_id: {String} id of the form associted with the input 10 | - checked: {Boolean} default checked status 11 | - disabled: {Boolean} default disabled status (optional) 12 | - visually_disabled: {Boolean} style the swatch as disabled, but leave the input enabled (optional) 13 | - shape: {String} swatch shape. Accepts 'square', defaults to circle (optional) 14 | - help_text: {String} additional content to render inside the label (optional) 15 | - additional_props: {String} (optional) additional properties to attach to the input 16 | 17 | Usage: 18 | {% render 'swatch-input', 19 | id: input_id, 20 | name: input_name, 21 | value: input_value, 22 | swatch: swatch, 23 | product_form_id: product_form_id, 24 | checked: checked 25 | %} 26 | {% endcomment %} 27 | 28 | 45 | 53 | -------------------------------------------------------------------------------- /snippets/swatch.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a swatch component. 3 | Accepts: 4 | - swatch: {Object} a swatch object 5 | - shape: {String} swatch shape. Accepts 'square', defaults to circle. 6 | 7 | Usage: 8 | {% render 'swatch', 9 | swatch: value.swatch 10 | shape: 'square' 11 | %} 12 | {% endcomment %} 13 | 14 | {%- liquid 15 | assign swatch_value = null 16 | if swatch.image 17 | assign image_url = swatch.image | image_url: width: 50 18 | assign swatch_value = 'url(' | append: image_url | append: ')' 19 | assign swatch_focal_point = swatch.image.presentation.focal_point 20 | elsif swatch.color 21 | assign swatch_value = 'rgb(' | append: swatch.color.rgb | append: ')' 22 | endif 23 | -%} 24 | 25 | 33 | -------------------------------------------------------------------------------- /snippets/visual-display.liquid: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Renders a visual display element, currently just a swatch. If wrapped in "visual-display-parent" and "visual-display-parent--swatch" classes, this will receive hover and focus states. 3 | 4 | Add a class of "active" or "disabled" to the parent element to change the state of the visual display. 5 | 6 | Accepts: 7 | - type: {String} Can be "colors" or "image", or nothing to represent an empty state. 8 | - value: {Object} Will be an array of color drops, or image drop, depending on the "type" 9 | - presentation: {String} Can only be "swatch" 10 | 11 | Usage: 12 | {% render 'visual-display', type: value.display.type, value: value.display.value, presentation: filter.presentation %} 13 | {% endcomment %} 14 |
15 | {%- case type -%} 16 | {%- when 'colors' -%} 17 | {% liquid 18 | assign size_limit = value.size | at_most: 4 19 | assign rotation = '0deg' 20 | if size_limit == 2 21 | assign rotation = '45deg' 22 | endif 23 | 24 | assign angle_increment = 360 | divided_by: size_limit 25 | assign angle = 0 26 | %} 27 | {%- capture conic_gradient -%} 28 | {%- for color in value limit: size_limit -%} 29 | {{ color }} {{ angle }}deg{%- assign angle = angle | plus: angle_increment %} {{ angle }}deg{%- unless forloop.last %}, {%- endunless -%} 30 | {%- endfor -%} 31 | {%- endcapture -%} 32 |
36 | {%- when 'image' -%} 37 | {{ 38 | value 39 | | image_url: width: 300 40 | | image_tag: class: 'visual-display__child visual-display__image', alt: value.alt 41 | }} 42 | {%- else -%} 43 |
44 | {%- endcase -%} 45 |
46 | -------------------------------------------------------------------------------- /templates/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-404" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/article.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-article", 5 | "blocks": { 6 | "featured_image": { 7 | "type": "featured_image", 8 | "settings": { 9 | "image_height": "adapt" 10 | } 11 | }, 12 | "title": { 13 | "type": "title", 14 | "settings": { 15 | "blog_show_date": true, 16 | "blog_show_author": false 17 | } 18 | }, 19 | "share": { 20 | "type": "share", 21 | "settings": { 22 | "share_label": "Share" 23 | } 24 | }, 25 | "content": { 26 | "type": "content" 27 | } 28 | }, 29 | "block_order": [ 30 | "featured_image", 31 | "title", 32 | "share", 33 | "content" 34 | ] 35 | } 36 | }, 37 | "order": [ 38 | "main" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /templates/blog.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-blog", 5 | "settings": { 6 | "layout": "collage", 7 | "show_image": true, 8 | "image_height": "medium", 9 | "show_date": true, 10 | "show_author": false, 11 | "padding_top": 36, 12 | "padding_bottom": 36 13 | } 14 | } 15 | }, 16 | "order": [ 17 | "main" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /templates/cart.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "cart-items": { 4 | "type": "main-cart-items", 5 | "settings": { 6 | "padding_top": 36, 7 | "padding_bottom": 36 8 | } 9 | }, 10 | "cart-footer": { 11 | "type": "main-cart-footer", 12 | "blocks": { 13 | "subtotal": { 14 | "type": "subtotal", 15 | "settings": { 16 | } 17 | }, 18 | "buttons": { 19 | "type": "buttons", 20 | "settings": { 21 | } 22 | } 23 | }, 24 | "block_order": [ 25 | "subtotal", 26 | "buttons" 27 | ] 28 | }, 29 | "featured-collection": { 30 | "type": "featured-collection", 31 | "settings": { 32 | "title": "Featured collection", 33 | "heading_size": "h2", 34 | "collection": "all", 35 | "products_to_show": 4, 36 | "columns_desktop": 4, 37 | "color_scheme": "scheme-1", 38 | "show_view_all": true, 39 | "swipe_on_mobile": false, 40 | "image_ratio": "square", 41 | "show_secondary_image": false, 42 | "show_vendor": false, 43 | "show_rating": false, 44 | "columns_mobile": "2", 45 | "padding_top": 36, 46 | "padding_bottom": 36 47 | } 48 | } 49 | }, 50 | "order": [ 51 | "cart-items", 52 | "cart-footer", 53 | "featured-collection" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /templates/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "banner": { 4 | "type": "main-collection-banner", 5 | "settings": { 6 | "show_collection_description": true, 7 | "show_collection_image": false, 8 | "color_scheme": "scheme-1" 9 | } 10 | }, 11 | "product-grid": { 12 | "type": "main-collection-product-grid", 13 | "settings": { 14 | "products_per_page": 16, 15 | "columns_desktop": 4, 16 | "image_ratio": "adapt", 17 | "show_secondary_image": false, 18 | "show_vendor": false, 19 | "show_rating": false, 20 | "enable_filtering": true, 21 | "enable_sorting": true, 22 | "columns_mobile": "2", 23 | "padding_top": 36, 24 | "padding_bottom": 36 25 | } 26 | } 27 | }, 28 | "order": [ 29 | "banner", 30 | "product-grid" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /templates/customers/account.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-account" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/activate_account.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-activate-account" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-addresses" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-login" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/order.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-order" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/register.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-register" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/customers/reset_password.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-reset-password" 5 | } 6 | }, 7 | "order": [ 8 | "main" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /templates/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "image_banner": { 4 | "type": "image-banner", 5 | "blocks": { 6 | "heading": { 7 | "type": "heading", 8 | "settings": { 9 | "heading": "Image banner", 10 | "heading_size": "h0" 11 | } 12 | }, 13 | "text": { 14 | "type": "text", 15 | "settings": { 16 | "text": "Give customers details about the banner image(s) or content on the template.", 17 | "text_style": "body" 18 | } 19 | }, 20 | "button": { 21 | "type": "buttons", 22 | "settings": { 23 | "button_label_1": "Shop all", 24 | "button_link_1": "shopify://collections/all", 25 | "button_style_secondary_1": true, 26 | "button_label_2": "", 27 | "button_link_2": "", 28 | "button_style_secondary_2": false 29 | } 30 | } 31 | }, 32 | "block_order": [ 33 | "heading", 34 | "text", 35 | "button" 36 | ], 37 | "settings": { 38 | "image_overlay_opacity": 40, 39 | "image_height": "large", 40 | "desktop_content_position": "bottom-center", 41 | "show_text_box": false, 42 | "desktop_content_alignment": "center", 43 | "color_scheme": "scheme-3", 44 | "mobile_content_alignment": "center", 45 | "stack_images_on_mobile": false, 46 | "show_text_below": false 47 | } 48 | }, 49 | "rich_text": { 50 | "type": "rich-text", 51 | "blocks": { 52 | "heading": { 53 | "type": "heading", 54 | "settings": { 55 | "heading": "Talk about your brand", 56 | "heading_size": "h1" 57 | } 58 | }, 59 | "text": { 60 | "type": "text", 61 | "settings": { 62 | "text": "

Share information about your brand with your customers. Describe a product, make announcements, or welcome customers to your store.<\/p>" 63 | } 64 | } 65 | }, 66 | "block_order": [ 67 | "heading", 68 | "text" 69 | ], 70 | "settings": { 71 | "color_scheme": "scheme-1", 72 | "full_width": true, 73 | "padding_top": 40, 74 | "padding_bottom": 0 75 | } 76 | }, 77 | "featured_collection": { 78 | "type": "featured-collection", 79 | "settings": { 80 | "title": "Featured products", 81 | "heading_size": "h2", 82 | "collection": "all", 83 | "products_to_show": 8, 84 | "columns_desktop": 4, 85 | "color_scheme": "scheme-1", 86 | "show_view_all": false, 87 | "swipe_on_mobile": false, 88 | "image_ratio": "adapt", 89 | "show_secondary_image": true, 90 | "show_vendor": false, 91 | "show_rating": false, 92 | "columns_mobile": "2", 93 | "padding_top": 28, 94 | "padding_bottom": 36 95 | } 96 | }, 97 | "video": { 98 | "type": "video", 99 | "settings": { 100 | "heading": "", 101 | "video_url": "https://www.youtube.com/watch?v=_9VUPq3SxOc", 102 | "heading_size": "h1", 103 | "description": "", 104 | "full_width": false, 105 | "color_scheme": "scheme-1", 106 | "padding_top": 36, 107 | "padding_bottom": 36 108 | } 109 | }, 110 | "multicolumn": { 111 | "type": "multicolumn", 112 | "blocks": { 113 | "column1": { 114 | "type": "column", 115 | "settings": { 116 | "title": "Column", 117 | "text": "

Pair text with an image to focus on your chosen product, collection, or blog post. Add details on availability, style, or even provide a review.<\/p>", 118 | "link_label": "", 119 | "link": "" 120 | } 121 | }, 122 | "column2": { 123 | "type": "column", 124 | "settings": { 125 | "title": "Column", 126 | "text": "

Pair text with an image to focus on your chosen product, collection, or blog post. Add details on availability, style, or even provide a review.<\/p>", 127 | "link_label": "", 128 | "link": "" 129 | } 130 | }, 131 | "column3": { 132 | "type": "column", 133 | "settings": { 134 | "title": "Column", 135 | "text": "

Pair text with an image to focus on your chosen product, collection, or blog post. Add details on availability, style, or even provide a review.<\/p>", 136 | "link_label": "", 137 | "link": "" 138 | } 139 | } 140 | }, 141 | "block_order": [ 142 | "column1", 143 | "column2", 144 | "column3" 145 | ], 146 | "settings": { 147 | "title": "", 148 | "heading_size": "h1", 149 | "image_width": "third", 150 | "image_ratio": "adapt", 151 | "columns_desktop": 3, 152 | "column_alignment": "center", 153 | "background_style": "none", 154 | "button_label": "", 155 | "button_link": "", 156 | "swipe_on_mobile": false, 157 | "color_scheme": "scheme-1", 158 | "columns_mobile": "1", 159 | "padding_top": 36, 160 | "padding_bottom": 36 161 | } 162 | } 163 | }, 164 | "order": [ 165 | "image_banner", 166 | "rich_text", 167 | "featured_collection", 168 | "video", 169 | "multicolumn" 170 | ] 171 | } 172 | -------------------------------------------------------------------------------- /templates/list-collections.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-list-collections", 5 | "settings": { 6 | "title": "Collections", 7 | "sort": "alphabetical", 8 | "image_ratio": "square" 9 | } 10 | } 11 | }, 12 | "order": [ 13 | "main" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /templates/page.contact.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-page", 5 | "settings": { 6 | "padding_top": 36, 7 | "padding_bottom": 36 8 | } 9 | }, 10 | "form": { 11 | "type": "contact-form", 12 | "settings": { 13 | "heading": "", 14 | "heading_size": "h1", 15 | "color_scheme": "scheme-1", 16 | "padding_top": 36, 17 | "padding_bottom": 36 18 | } 19 | } 20 | }, 21 | "order": [ 22 | "main", 23 | "form" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /templates/page.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-page", 5 | "settings": { 6 | "padding_top": 28, 7 | "padding_bottom": 28 8 | } 9 | } 10 | }, 11 | "order": [ 12 | "main" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /templates/password.json: -------------------------------------------------------------------------------- 1 | { 2 | "layout": "password", 3 | "sections": { 4 | "main": { 5 | "type": "email-signup-banner", 6 | "blocks": { 7 | "heading": { 8 | "type": "heading", 9 | "settings": { 10 | "heading": "Opening soon", 11 | "heading_size": "h1" 12 | } 13 | }, 14 | "paragraph": { 15 | "type": "paragraph", 16 | "settings": { 17 | "text": "

Be the first to know when we launch.<\/p>", 18 | "text_style": "body" 19 | } 20 | }, 21 | "email_form": { 22 | "type": "email_form" 23 | } 24 | }, 25 | "block_order": [ 26 | "heading", 27 | "paragraph", 28 | "email_form" 29 | ], 30 | "settings": { 31 | "image_overlay_opacity": 0, 32 | "show_background_image": true, 33 | "image_height": "medium", 34 | "desktop_content_position": "middle-center", 35 | "show_text_box": true, 36 | "desktop_content_alignment": "center", 37 | "color_scheme": "scheme-1", 38 | "mobile_content_alignment": "center", 39 | "show_text_below": true 40 | } 41 | } 42 | }, 43 | "order": [ 44 | "main" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /templates/search.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": { 3 | "main": { 4 | "type": "main-search", 5 | "settings": { 6 | "columns_desktop": 4, 7 | "image_ratio": "adapt", 8 | "show_secondary_image": false, 9 | "show_vendor": false, 10 | "show_rating": false, 11 | "enable_filtering": true, 12 | "enable_sorting": true, 13 | "article_show_date": true, 14 | "article_show_author": false, 15 | "columns_mobile": "2", 16 | "padding_top": 36, 17 | "padding_bottom": 36 18 | } 19 | } 20 | }, 21 | "order": [ 22 | "main" 23 | ] 24 | } 25 | --------------------------------------------------------------------------------