From 6bceba004f66f609d0bdb3c11b0832f010255bb0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Jul 2025 01:29:22 +0000 Subject: [PATCH 1/4] Merge latest changes from Shopify/horizon-private Upstream-SHA: c27f1fdbfffc22ee843a6f32a40b379fce096ff7 --- README.md | 106 +- assets/accordion-custom.js | 106 + assets/account-login-actions.js | 34 + assets/anchored-popover.js | 80 + assets/announcement-bar.js | 130 + assets/auto-close-details.js | 15 + assets/base.css | 4225 +++++++++++++++++ assets/blog-posts-list.js | 10 + assets/cart-discount.js | 203 + assets/cart-drawer.js | 46 + assets/cart-icon.js | 108 + assets/cart-note.js | 46 + assets/collection-links.js | 195 + assets/component-cart-items.js | 259 + assets/component-quantity-selector.js | 100 + assets/component.js | 330 ++ assets/copy-to-clipboard.js | 26 + assets/critical.js | 464 ++ assets/dialog.js | 172 + assets/drag-zoom-wrapper.js | 352 ++ assets/events.js | 285 ++ assets/facets.js | 910 ++++ assets/floating-panel.js | 60 + assets/focus.js | 104 + assets/global.d.ts | 72 + assets/header-drawer.js | 155 + assets/header-menu.js | 214 + assets/header.js | 245 + assets/icon-account.svg | 1 + assets/icon-add-to-cart.svg | 1 + assets/icon-arrow.svg | 1 + assets/icon-available.svg | 3 + assets/icon-caret.svg | 3 + assets/icon-cart.svg | 1 + assets/icon-checkmark.svg | 3 + assets/icon-close.svg | 4 + assets/icon-delete.svg | 4 + assets/icon-discount.svg | 4 + assets/icon-error.svg | 6 + assets/icon-external.svg | 1 + assets/icon-filter.svg | 1 + assets/icon-filters-close.svg | 6 + assets/icon-grid-default.svg | 6 + assets/icon-grid-dense.svg | 11 + assets/icon-inventory.svg | 5 + assets/icon-menu.svg | 4 + assets/icon-minus.svg | 3 + assets/icon-one-col-mobile.svg | 3 + assets/icon-orders.svg | 4 + assets/icon-pause.svg | 4 + assets/icon-play.svg | 3 + assets/icon-plus.svg | 4 + assets/icon-reset.svg | 1 + assets/icon-search.svg | 1 + assets/icon-shopify.svg | 1 + assets/icon-unavailable.svg | 3 + assets/jsconfig.json | 14 + assets/jumbo-text.js | 151 + assets/local-pickup.js | 79 + assets/localization.js | 548 +++ assets/marquee.js | 221 + assets/media-gallery.js | 84 + assets/media.js | 248 + assets/morph.js | 469 ++ assets/overflow-list.css | 58 + assets/paginated-list.js | 503 ++ assets/performance.js | 75 + assets/predictive-search.js | 476 ++ assets/product-card-link.js | 68 + assets/product-card.js | 502 ++ assets/product-form.js | 448 ++ assets/product-inventory.js | 36 + assets/product-price.js | 47 + assets/product-recommendations.js | 144 + assets/product-title-truncation.js | 86 + assets/qr-code-generator.js | 1665 +++++++ assets/qr-code-image.js | 33 + assets/quick-add.js | 229 + assets/recently-viewed-products.js | 35 + assets/results-list.js | 78 + assets/rte-formatter.js | 26 + assets/scrolling.js | 404 ++ assets/search-page-input.js | 58 + assets/section-renderer.js | 180 + assets/show-more.js | 162 + assets/slideshow.js | 750 +++ assets/template-giftcard.css | 137 + assets/theme-editor.js | 268 ++ assets/utilities.js | 603 +++ assets/variant-picker.js | 296 ++ assets/video-background.js | 32 + assets/view-transitions.js | 87 + assets/zoom-dialog.js | 276 ++ blocks/_accordion-row.liquid | 351 ++ blocks/_announcement.liquid | 330 ++ blocks/_blog-post-card.liquid | 118 + blocks/_blog-post-content.liquid | 26 + blocks/_blog-post-description.liquid | 356 ++ blocks/_blog-post-image.liquid | 127 + blocks/_blog-post-info-text.liquid | 155 + blocks/_cart-products.liquid | 117 + blocks/_cart-summary.liquid | 249 + blocks/_cart-title.liquid | 171 + blocks/_collection-card-image.liquid | 267 ++ blocks/_collection-card.liquid | 196 + blocks/_collection-image.liquid | 168 + blocks/_collection-info.liquid | 166 + blocks/_collection-link.liquid | 166 + blocks/_content-without-appearance.liquid | 117 + blocks/_content.liquid | 162 + blocks/_divider.liquid | 79 + blocks/_featured-product-gallery.liquid | 61 + blocks/_featured-product-price.liquid | 109 + blocks/_featured-product.liquid | 41 + blocks/_footer-copyright.liquid | 74 + blocks/_footer-policy-list.liquid | 96 + blocks/_footer-social-icons.liquid | 34 + blocks/_header-logo.liquid | 233 + blocks/_header-menu.liquid | 995 ++++ blocks/_heading.liquid | 339 ++ blocks/_image.liquid | 170 + blocks/_inline-collection-title.liquid | 165 + blocks/_inline-text.liquid | 163 + blocks/_marquee.liquid | 212 + blocks/_media-without-appearance.liquid | 105 + blocks/_media.liquid | 136 + blocks/_product-card-gallery.liquid | 177 + blocks/_product-card-group.liquid | 517 ++ blocks/_product-card.liquid | 174 + blocks/_product-details.liquid | 708 +++ blocks/_product-list-button.liquid | 121 + blocks/_product-list-content.liquid | 456 ++ blocks/_product-list-text.liquid | 400 ++ blocks/_product-media-gallery.liquid | 906 ++++ blocks/_search-input.liquid | 249 + blocks/_slide.liquid | 500 ++ blocks/_social-link.liquid | 115 + blocks/accelerated-checkout.liquid | 65 + blocks/accordion.liquid | 312 ++ blocks/add-to-cart.liquid | 52 + blocks/button.liquid | 115 + blocks/buy-buttons.liquid | 475 ++ blocks/collection-card.liquid | 220 + blocks/collection-title.liquid | 399 ++ blocks/contact-form-submit-button.liquid | 106 + blocks/contact-form.liquid | 133 + blocks/custom-liquid.liquid | 26 + blocks/email-signup.liquid | 569 +++ blocks/featured-collection.liquid | 31 + blocks/filters.liquid | 1236 +++++ blocks/follow-on-shop.liquid | 74 + blocks/footer-utilities.liquid | 124 + blocks/group.liquid | 505 ++ blocks/icon.liquid | 327 ++ blocks/image.liquid | 337 ++ blocks/jumbo-text.liquid | 137 + blocks/logo.liquid | 291 ++ blocks/menu.liquid | 341 ++ blocks/page-content.liquid | 12 + blocks/page.liquid | 142 + blocks/payment-icons.liquid | 140 + blocks/popup-link.liquid | 265 ++ blocks/price.liquid | 438 ++ blocks/product-card.liquid | 247 + blocks/product-description.liquid | 405 ++ blocks/product-inventory.liquid | 184 + blocks/product-recommendations.liquid | 476 ++ blocks/product-title.liquid | 399 ++ blocks/quantity.liquid | 10 + blocks/review.liquid | 269 ++ blocks/spacer.liquid | 184 + blocks/swatches.liquid | 216 + blocks/text.liquid | 404 ++ blocks/variant-picker.liquid | 105 + blocks/video.liquid | 254 + config/settings_data.json | 420 ++ config/settings_schema.json | 2317 +++++++++ layout/password.liquid | 161 + layout/theme.liquid | 67 + locales/bg.json | 271 ++ locales/cs.json | 283 ++ locales/cs.schema.json | 929 ++++ locales/da.json | 271 ++ locales/da.schema.json | 929 ++++ locales/de.json | 271 ++ locales/de.schema.json | 929 ++++ locales/el.json | 271 ++ locales/en.default.json | 281 ++ locales/en.default.schema.json | 940 ++++ locales/es.json | 277 ++ locales/es.schema.json | 929 ++++ locales/fi.json | 271 ++ locales/fi.schema.json | 929 ++++ locales/fr.json | 277 ++ locales/fr.schema.json | 929 ++++ locales/hr.json | 277 ++ locales/hu.json | 271 ++ locales/id.json | 271 ++ locales/it.json | 277 ++ locales/it.schema.json | 929 ++++ locales/ja.json | 271 ++ locales/ja.schema.json | 929 ++++ locales/ko.json | 271 ++ locales/ko.schema.json | 929 ++++ locales/lt.json | 283 ++ locales/nb.json | 271 ++ locales/nb.schema.json | 929 ++++ locales/nl.json | 271 ++ locales/nl.schema.json | 929 ++++ locales/pl.json | 283 ++ locales/pl.schema.json | 929 ++++ locales/pt-BR.json | 277 ++ locales/pt-BR.schema.json | 929 ++++ locales/pt-PT.json | 277 ++ locales/pt-PT.schema.json | 929 ++++ locales/ro.json | 277 ++ locales/ru.json | 283 ++ locales/sk.json | 283 ++ locales/sl.json | 283 ++ locales/sv.json | 271 ++ locales/sv.schema.json | 929 ++++ locales/th.json | 271 ++ locales/th.schema.json | 929 ++++ locales/tr.json | 271 ++ locales/tr.schema.json | 929 ++++ locales/vi.json | 271 ++ locales/zh-CN.json | 271 ++ locales/zh-CN.schema.json | 929 ++++ locales/zh-TW.json | 271 ++ locales/zh-TW.schema.json | 929 ++++ release-notes.md | 34 + sections/_blocks.liquid | 427 ++ sections/collection-links.liquid | 371 ++ sections/collection-list.liquid | 970 ++++ sections/custom-liquid.liquid | 75 + sections/divider.liquid | 132 + sections/featured-product.liquid | 193 + sections/footer-group.json | 246 + sections/footer.liquid | 374 ++ sections/header-announcements.liquid | 219 + sections/header-group.json | 93 + sections/header.liquid | 1056 ++++ sections/hero.liquid | 940 ++++ sections/main-404.liquid | 188 + sections/main-blog-post.liquid | 171 + sections/main-blog.liquid | 206 + sections/main-cart.liquid | 200 + sections/main-collection-list.liquid | 405 ++ sections/main-collection.liquid | 309 ++ sections/main-page.liquid | 96 + sections/marquee.liquid | 192 + sections/media-with-content.liquid | 434 ++ sections/password.liquid | 531 +++ sections/predictive-search-empty.liquid | 11 + sections/predictive-search.liquid | 1221 +++++ sections/product-information.liquid | 390 ++ sections/product-list.liquid | 943 ++++ sections/product-recommendations.liquid | 561 +++ sections/search-header.liquid | 83 + sections/search-results.liquid | 221 + .../section-rendering-product-card.liquid | 63 + sections/section.liquid | 1326 ++++++ sections/slideshow.liquid | 306 ++ snippets/account-actions.liquid | 194 + snippets/account-button.liquid | 90 + snippets/account-drawer.liquid | 103 + snippets/account-popover.liquid | 75 + snippets/add-to-cart-button.liquid | 118 + snippets/background-image.liquid | 40 + snippets/background-media.liquid | 7 + snippets/background-video.liquid | 57 + snippets/bento-grid.liquid | 210 + snippets/blog-comment-form.liquid | 206 + snippets/border-override.liquid | 7 + snippets/button.liquid | 43 + snippets/card-gallery.liquid | 385 ++ snippets/cart-bubble.liquid | 40 + snippets/cart-discount.liquid | 232 + snippets/cart-drawer.liquid | 171 + snippets/cart-icon-component.liquid | 32 + snippets/cart-note.liquid | 38 + snippets/cart-products.liquid | 753 +++ snippets/cart-summary.liquid | 126 + snippets/checkbox.liquid | 50 + snippets/collection-card.liquid | 191 + snippets/color-schemes.liquid | 99 + snippets/contact-form.liquid | 170 + snippets/divider.liquid | 54 + snippets/drawer-localization.liquid | 125 + snippets/dropdown-localization.liquid | 92 + snippets/editorial-collection-grid.liquid | 117 + snippets/editorial-product-grid.liquid | 124 + snippets/facets-actions.liquid | 220 + snippets/filter-remove-buttons.liquid | 178 + snippets/filters-toggle.liquid | 149 + snippets/fonts.liquid | 49 + snippets/gap-style.liquid | 25 + snippets/grid-density-controls.liquid | 179 + snippets/group.liquid | 90 + snippets/header-actions.liquid | 280 ++ snippets/header-drawer.liquid | 1117 +++++ snippets/header-menu.liquid | 90 + snippets/header-row.liquid | 78 + snippets/icon-or-image.liquid | 40 + snippets/icon.liquid | 399 ++ snippets/image.liquid | 32 + snippets/jumbo-text.liquid | 186 + snippets/layout-panel-style.liquid | 33 + snippets/link-featured-image.liquid | 40 + snippets/list-filter.liquid | 783 +++ snippets/localization-form.liquid | 817 ++++ snippets/media.liquid | 116 + snippets/mega-menu-list.liquid | 288 ++ snippets/mega-menu.liquid | 29 + snippets/menu-font-styles.liquid | 23 + snippets/meta-tags.liquid | 121 + snippets/overflow-list.liquid | 63 + snippets/overlay.liquid | 38 + snippets/predictive-search-empty-state.liquid | 39 + .../predictive-search-products-list.liquid | 112 + ...predictive-search-resource-carousel.liquid | 65 + snippets/predictive-search.liquid | 135 + snippets/price-filter.liquid | 239 + snippets/price.liquid | 79 + snippets/product-card-badges.liquid | 77 + snippets/product-card.liquid | 231 + snippets/product-grid.liquid | 207 + snippets/product-media.liquid | 208 + snippets/quantity-selector.liquid | 74 + snippets/quick-add-modal.liquid | 442 ++ snippets/quick-add.liquid | 324 ++ snippets/resource-card.liquid | 273 ++ snippets/resource-list-carousel.liquid | 59 + snippets/scripts.liquid | 247 + snippets/search-modal.liquid | 108 + snippets/search.liquid | 52 + snippets/section.liquid | 96 + snippets/size-style.liquid | 33 + snippets/skip-to-content-link.liquid | 16 + snippets/slideshow-arrow.liquid | 49 + snippets/slideshow-arrows.liquid | 29 + snippets/slideshow-controls.liquid | 180 + snippets/slideshow-slide.liquid | 42 + snippets/slideshow.liquid | 77 + snippets/sorting.liquid | 361 ++ snippets/spacing-padding.liquid | 11 + snippets/spacing-style.liquid | 49 + snippets/strikethrough-variant.liquid | 11 + snippets/stylesheets.liquid | 3 + snippets/submenu-font-styles.liquid | 48 + snippets/swatch.liquid | 41 + snippets/tax-info.liquid | 84 + snippets/text.liquid | 216 + snippets/theme-editor.liquid | 4 + snippets/theme-styles-variables.liquid | 556 +++ snippets/timeline-scope.liquid | 11 + snippets/typography-style.liquid | 75 + snippets/unit-price.liquid | 16 + snippets/util-autofill-img-size-attr.liquid | 75 + snippets/util-product-grid-card-size.liquid | 45 + snippets/util-product-media-sizes-attr.liquid | 141 + snippets/variant-main-picker.liquid | 477 ++ snippets/variant-quick-add.liquid | 101 + snippets/variant-swatches.liquid | 145 + snippets/video.liquid | 215 + templates/404.json | 318 ++ templates/article.json | 53 + templates/blog.json | 125 + templates/cart.json | 162 + templates/collection.json | 232 + templates/gift_card.liquid | 228 + templates/index.json | 1883 ++++++++ templates/list-collections.json | 169 + templates/page.contact.json | 149 + templates/page.json | 43 + templates/password.json | 72 + templates/product.json | 440 ++ templates/search.json | 211 + 378 files changed, 102063 insertions(+), 2 deletions(-) create mode 100644 assets/accordion-custom.js create mode 100644 assets/account-login-actions.js create mode 100644 assets/anchored-popover.js create mode 100644 assets/announcement-bar.js create mode 100644 assets/auto-close-details.js create mode 100644 assets/base.css create mode 100644 assets/blog-posts-list.js create mode 100644 assets/cart-discount.js create mode 100644 assets/cart-drawer.js create mode 100644 assets/cart-icon.js create mode 100644 assets/cart-note.js create mode 100644 assets/collection-links.js create mode 100644 assets/component-cart-items.js create mode 100644 assets/component-quantity-selector.js create mode 100644 assets/component.js create mode 100644 assets/copy-to-clipboard.js create mode 100644 assets/critical.js create mode 100644 assets/dialog.js create mode 100644 assets/drag-zoom-wrapper.js create mode 100644 assets/events.js create mode 100644 assets/facets.js create mode 100644 assets/floating-panel.js create mode 100644 assets/focus.js create mode 100644 assets/global.d.ts create mode 100644 assets/header-drawer.js create mode 100644 assets/header-menu.js create mode 100644 assets/header.js create mode 100644 assets/icon-account.svg create mode 100644 assets/icon-add-to-cart.svg create mode 100644 assets/icon-arrow.svg create mode 100644 assets/icon-available.svg create mode 100644 assets/icon-caret.svg create mode 100644 assets/icon-cart.svg create mode 100644 assets/icon-checkmark.svg create mode 100644 assets/icon-close.svg create mode 100644 assets/icon-delete.svg create mode 100644 assets/icon-discount.svg create mode 100644 assets/icon-error.svg create mode 100644 assets/icon-external.svg create mode 100644 assets/icon-filter.svg create mode 100644 assets/icon-filters-close.svg create mode 100644 assets/icon-grid-default.svg create mode 100644 assets/icon-grid-dense.svg create mode 100644 assets/icon-inventory.svg create mode 100644 assets/icon-menu.svg create mode 100644 assets/icon-minus.svg create mode 100644 assets/icon-one-col-mobile.svg create mode 100644 assets/icon-orders.svg create mode 100644 assets/icon-pause.svg create mode 100644 assets/icon-play.svg create mode 100644 assets/icon-plus.svg create mode 100644 assets/icon-reset.svg create mode 100644 assets/icon-search.svg create mode 100644 assets/icon-shopify.svg create mode 100644 assets/icon-unavailable.svg create mode 100644 assets/jsconfig.json create mode 100644 assets/jumbo-text.js create mode 100644 assets/local-pickup.js create mode 100644 assets/localization.js create mode 100644 assets/marquee.js create mode 100644 assets/media-gallery.js create mode 100644 assets/media.js create mode 100644 assets/morph.js create mode 100644 assets/overflow-list.css create mode 100644 assets/paginated-list.js create mode 100644 assets/performance.js create mode 100644 assets/predictive-search.js create mode 100644 assets/product-card-link.js create mode 100644 assets/product-card.js create mode 100644 assets/product-form.js create mode 100644 assets/product-inventory.js create mode 100644 assets/product-price.js create mode 100644 assets/product-recommendations.js create mode 100644 assets/product-title-truncation.js create mode 100644 assets/qr-code-generator.js create mode 100644 assets/qr-code-image.js create mode 100644 assets/quick-add.js create mode 100644 assets/recently-viewed-products.js create mode 100644 assets/results-list.js create mode 100644 assets/rte-formatter.js create mode 100644 assets/scrolling.js create mode 100644 assets/search-page-input.js create mode 100644 assets/section-renderer.js create mode 100644 assets/show-more.js create mode 100644 assets/slideshow.js create mode 100644 assets/template-giftcard.css create mode 100644 assets/theme-editor.js create mode 100644 assets/utilities.js create mode 100644 assets/variant-picker.js create mode 100644 assets/video-background.js create mode 100644 assets/view-transitions.js create mode 100644 assets/zoom-dialog.js create mode 100644 blocks/_accordion-row.liquid create mode 100644 blocks/_announcement.liquid create mode 100644 blocks/_blog-post-card.liquid create mode 100644 blocks/_blog-post-content.liquid create mode 100644 blocks/_blog-post-description.liquid create mode 100644 blocks/_blog-post-image.liquid create mode 100644 blocks/_blog-post-info-text.liquid create mode 100644 blocks/_cart-products.liquid create mode 100644 blocks/_cart-summary.liquid create mode 100644 blocks/_cart-title.liquid create mode 100644 blocks/_collection-card-image.liquid create mode 100644 blocks/_collection-card.liquid create mode 100644 blocks/_collection-image.liquid create mode 100644 blocks/_collection-info.liquid create mode 100644 blocks/_collection-link.liquid create mode 100644 blocks/_content-without-appearance.liquid create mode 100644 blocks/_content.liquid create mode 100644 blocks/_divider.liquid create mode 100644 blocks/_featured-product-gallery.liquid create mode 100644 blocks/_featured-product-price.liquid create mode 100644 blocks/_featured-product.liquid create mode 100644 blocks/_footer-copyright.liquid create mode 100644 blocks/_footer-policy-list.liquid create mode 100644 blocks/_footer-social-icons.liquid create mode 100644 blocks/_header-logo.liquid create mode 100644 blocks/_header-menu.liquid create mode 100644 blocks/_heading.liquid create mode 100644 blocks/_image.liquid create mode 100644 blocks/_inline-collection-title.liquid create mode 100644 blocks/_inline-text.liquid create mode 100644 blocks/_marquee.liquid create mode 100644 blocks/_media-without-appearance.liquid create mode 100644 blocks/_media.liquid create mode 100644 blocks/_product-card-gallery.liquid create mode 100644 blocks/_product-card-group.liquid create mode 100644 blocks/_product-card.liquid create mode 100644 blocks/_product-details.liquid create mode 100644 blocks/_product-list-button.liquid create mode 100644 blocks/_product-list-content.liquid create mode 100644 blocks/_product-list-text.liquid create mode 100644 blocks/_product-media-gallery.liquid create mode 100644 blocks/_search-input.liquid create mode 100644 blocks/_slide.liquid create mode 100644 blocks/_social-link.liquid create mode 100644 blocks/accelerated-checkout.liquid create mode 100644 blocks/accordion.liquid create mode 100644 blocks/add-to-cart.liquid create mode 100644 blocks/button.liquid create mode 100644 blocks/buy-buttons.liquid create mode 100644 blocks/collection-card.liquid create mode 100644 blocks/collection-title.liquid create mode 100644 blocks/contact-form-submit-button.liquid create mode 100644 blocks/contact-form.liquid create mode 100644 blocks/custom-liquid.liquid create mode 100644 blocks/email-signup.liquid create mode 100644 blocks/featured-collection.liquid create mode 100644 blocks/filters.liquid create mode 100644 blocks/follow-on-shop.liquid create mode 100644 blocks/footer-utilities.liquid create mode 100644 blocks/group.liquid create mode 100644 blocks/icon.liquid create mode 100644 blocks/image.liquid create mode 100644 blocks/jumbo-text.liquid create mode 100644 blocks/logo.liquid create mode 100644 blocks/menu.liquid create mode 100644 blocks/page-content.liquid create mode 100644 blocks/page.liquid create mode 100644 blocks/payment-icons.liquid create mode 100644 blocks/popup-link.liquid create mode 100644 blocks/price.liquid create mode 100644 blocks/product-card.liquid create mode 100644 blocks/product-description.liquid create mode 100644 blocks/product-inventory.liquid create mode 100644 blocks/product-recommendations.liquid create mode 100644 blocks/product-title.liquid create mode 100644 blocks/quantity.liquid create mode 100644 blocks/review.liquid create mode 100644 blocks/spacer.liquid create mode 100644 blocks/swatches.liquid create mode 100644 blocks/text.liquid create mode 100644 blocks/variant-picker.liquid create mode 100644 blocks/video.liquid create mode 100644 config/settings_data.json create mode 100644 config/settings_schema.json create mode 100644 layout/password.liquid create mode 100644 layout/theme.liquid create mode 100644 locales/bg.json create mode 100644 locales/cs.json create mode 100644 locales/cs.schema.json create mode 100644 locales/da.json create mode 100644 locales/da.schema.json create mode 100644 locales/de.json create mode 100644 locales/de.schema.json create mode 100644 locales/el.json create mode 100644 locales/en.default.json create mode 100644 locales/en.default.schema.json create mode 100644 locales/es.json create mode 100644 locales/es.schema.json create mode 100644 locales/fi.json create mode 100644 locales/fi.schema.json create mode 100644 locales/fr.json create mode 100644 locales/fr.schema.json create mode 100644 locales/hr.json create mode 100644 locales/hu.json create mode 100644 locales/id.json create mode 100644 locales/it.json create mode 100644 locales/it.schema.json create mode 100644 locales/ja.json create mode 100644 locales/ja.schema.json create mode 100644 locales/ko.json create mode 100644 locales/ko.schema.json create mode 100644 locales/lt.json create mode 100644 locales/nb.json create mode 100644 locales/nb.schema.json create mode 100644 locales/nl.json create mode 100644 locales/nl.schema.json create mode 100644 locales/pl.json create mode 100644 locales/pl.schema.json create mode 100644 locales/pt-BR.json create mode 100644 locales/pt-BR.schema.json create mode 100644 locales/pt-PT.json create mode 100644 locales/pt-PT.schema.json create mode 100644 locales/ro.json create mode 100644 locales/ru.json create mode 100644 locales/sk.json create mode 100644 locales/sl.json create mode 100644 locales/sv.json create mode 100644 locales/sv.schema.json create mode 100644 locales/th.json create mode 100644 locales/th.schema.json create mode 100644 locales/tr.json create mode 100644 locales/tr.schema.json create mode 100644 locales/vi.json create mode 100644 locales/zh-CN.json create mode 100644 locales/zh-CN.schema.json create mode 100644 locales/zh-TW.json create mode 100644 locales/zh-TW.schema.json create mode 100644 release-notes.md create mode 100644 sections/_blocks.liquid create mode 100644 sections/collection-links.liquid create mode 100644 sections/collection-list.liquid create mode 100644 sections/custom-liquid.liquid create mode 100644 sections/divider.liquid create mode 100644 sections/featured-product.liquid create mode 100644 sections/footer-group.json create mode 100644 sections/footer.liquid create mode 100644 sections/header-announcements.liquid create mode 100644 sections/header-group.json create mode 100644 sections/header.liquid create mode 100644 sections/hero.liquid create mode 100644 sections/main-404.liquid create mode 100644 sections/main-blog-post.liquid create mode 100644 sections/main-blog.liquid create mode 100644 sections/main-cart.liquid create mode 100644 sections/main-collection-list.liquid create mode 100644 sections/main-collection.liquid create mode 100644 sections/main-page.liquid create mode 100644 sections/marquee.liquid create mode 100644 sections/media-with-content.liquid create mode 100644 sections/password.liquid create mode 100644 sections/predictive-search-empty.liquid create mode 100644 sections/predictive-search.liquid create mode 100644 sections/product-information.liquid create mode 100644 sections/product-list.liquid create mode 100644 sections/product-recommendations.liquid create mode 100644 sections/search-header.liquid create mode 100644 sections/search-results.liquid create mode 100644 sections/section-rendering-product-card.liquid create mode 100644 sections/section.liquid create mode 100644 sections/slideshow.liquid create mode 100644 snippets/account-actions.liquid create mode 100644 snippets/account-button.liquid create mode 100644 snippets/account-drawer.liquid create mode 100644 snippets/account-popover.liquid create mode 100644 snippets/add-to-cart-button.liquid create mode 100644 snippets/background-image.liquid create mode 100644 snippets/background-media.liquid create mode 100644 snippets/background-video.liquid create mode 100644 snippets/bento-grid.liquid create mode 100644 snippets/blog-comment-form.liquid create mode 100644 snippets/border-override.liquid create mode 100644 snippets/button.liquid create mode 100644 snippets/card-gallery.liquid create mode 100644 snippets/cart-bubble.liquid create mode 100644 snippets/cart-discount.liquid create mode 100644 snippets/cart-drawer.liquid create mode 100644 snippets/cart-icon-component.liquid create mode 100644 snippets/cart-note.liquid create mode 100644 snippets/cart-products.liquid create mode 100644 snippets/cart-summary.liquid create mode 100644 snippets/checkbox.liquid create mode 100644 snippets/collection-card.liquid create mode 100644 snippets/color-schemes.liquid create mode 100644 snippets/contact-form.liquid create mode 100644 snippets/divider.liquid create mode 100644 snippets/drawer-localization.liquid create mode 100644 snippets/dropdown-localization.liquid create mode 100644 snippets/editorial-collection-grid.liquid create mode 100644 snippets/editorial-product-grid.liquid create mode 100644 snippets/facets-actions.liquid create mode 100644 snippets/filter-remove-buttons.liquid create mode 100644 snippets/filters-toggle.liquid create mode 100644 snippets/fonts.liquid create mode 100644 snippets/gap-style.liquid create mode 100644 snippets/grid-density-controls.liquid create mode 100644 snippets/group.liquid create mode 100644 snippets/header-actions.liquid create mode 100644 snippets/header-drawer.liquid create mode 100644 snippets/header-menu.liquid create mode 100644 snippets/header-row.liquid create mode 100644 snippets/icon-or-image.liquid create mode 100644 snippets/icon.liquid create mode 100644 snippets/image.liquid create mode 100644 snippets/jumbo-text.liquid create mode 100644 snippets/layout-panel-style.liquid create mode 100644 snippets/link-featured-image.liquid create mode 100644 snippets/list-filter.liquid create mode 100644 snippets/localization-form.liquid create mode 100644 snippets/media.liquid create mode 100644 snippets/mega-menu-list.liquid create mode 100644 snippets/mega-menu.liquid create mode 100644 snippets/menu-font-styles.liquid create mode 100644 snippets/meta-tags.liquid create mode 100644 snippets/overflow-list.liquid create mode 100644 snippets/overlay.liquid create mode 100644 snippets/predictive-search-empty-state.liquid create mode 100644 snippets/predictive-search-products-list.liquid create mode 100644 snippets/predictive-search-resource-carousel.liquid create mode 100644 snippets/predictive-search.liquid create mode 100644 snippets/price-filter.liquid create mode 100644 snippets/price.liquid create mode 100644 snippets/product-card-badges.liquid create mode 100644 snippets/product-card.liquid create mode 100644 snippets/product-grid.liquid create mode 100644 snippets/product-media.liquid create mode 100644 snippets/quantity-selector.liquid create mode 100644 snippets/quick-add-modal.liquid create mode 100644 snippets/quick-add.liquid create mode 100644 snippets/resource-card.liquid create mode 100644 snippets/resource-list-carousel.liquid create mode 100644 snippets/scripts.liquid create mode 100644 snippets/search-modal.liquid create mode 100644 snippets/search.liquid create mode 100644 snippets/section.liquid create mode 100644 snippets/size-style.liquid create mode 100644 snippets/skip-to-content-link.liquid create mode 100644 snippets/slideshow-arrow.liquid create mode 100644 snippets/slideshow-arrows.liquid create mode 100644 snippets/slideshow-controls.liquid create mode 100644 snippets/slideshow-slide.liquid create mode 100644 snippets/slideshow.liquid create mode 100644 snippets/sorting.liquid create mode 100644 snippets/spacing-padding.liquid create mode 100644 snippets/spacing-style.liquid create mode 100644 snippets/strikethrough-variant.liquid create mode 100644 snippets/stylesheets.liquid create mode 100644 snippets/submenu-font-styles.liquid create mode 100644 snippets/swatch.liquid create mode 100644 snippets/tax-info.liquid create mode 100644 snippets/text.liquid create mode 100644 snippets/theme-editor.liquid create mode 100644 snippets/theme-styles-variables.liquid create mode 100644 snippets/timeline-scope.liquid create mode 100644 snippets/typography-style.liquid create mode 100644 snippets/unit-price.liquid create mode 100644 snippets/util-autofill-img-size-attr.liquid create mode 100644 snippets/util-product-grid-card-size.liquid create mode 100644 snippets/util-product-media-sizes-attr.liquid create mode 100644 snippets/variant-main-picker.liquid create mode 100644 snippets/variant-quick-add.liquid create mode 100644 snippets/variant-swatches.liquid create mode 100644 snippets/video.liquid create mode 100644 templates/404.json create mode 100644 templates/article.json create mode 100644 templates/blog.json create mode 100644 templates/cart.json create mode 100644 templates/collection.json create mode 100644 templates/gift_card.liquid create mode 100644 templates/index.json create mode 100644 templates/list-collections.json create mode 100644 templates/page.contact.json create mode 100644 templates/page.json create mode 100644 templates/password.json create mode 100644 templates/product.json create mode 100644 templates/search.json diff --git a/README.md b/README.md index ff60c29f3..d23430c6a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,104 @@ -# horizon -Shopify's Horizon theme source code +# Horizon + +[Getting started](#getting-started) | +[Staying up to date with Horizon changes](#staying-up-to-date-with-horizon-changes) | +[Developer tools](#developer-tools) | +[Contributing](#contributing) | +[Code of conduct](#code-of-conduct) | +[Theme Store submission](#theme-store-submission) | +[License](#license) + +Horizon is the first of a new generation of first party Shopify themes. It incorporates the latest Liquid Storefronts features, including [theme blocks](https://shopify.dev/docs/storefronts/themes/architecture/blocks/theme-blocks/quick-start?framework=liquid). + +- **Web-native in its purest form:** Themes run on the [evergreen web](https://www.w3.org/2001/tag/doc/evergreen-web/). We leverage the latest web browsers to their fullest, while maintaining support for the older ones through progressive enhancement—not polyfills. +- **Lean, fast, and reliable:** Functionality and design defaults to “no” until it meets this requirement. Code ships on quality. Themes must be built with purpose. They shouldn’t support each and every feature in Shopify. +- **Server-rendered:** HTML must be rendered by Shopify servers using Liquid. Business logic and platform primitives such as translations and money formatting don’t belong on the client. Async and on-demand rendering of parts of the page is OK, but we do it sparingly as a progressive enhancement. +- **Functional, not pixel-perfect:** The Web doesn’t require each page to be rendered pixel-perfect by each browser engine. Using semantic markup, progressive enhancement, and clever design, we ensure that themes remain functional regardless of the browser. + +You can find a more detailed version of our theme code principles in the [contribution guide](https://github.com/Shopify/horizon/blob/main/.github/CONTRIBUTING.md#theme-code-principles). + +## Getting started + +We recommend using the Skeleton Theme as a starting point for theme development. [Learn more on Shopify.dev](https://shopify.dev/themes/getting-started/create). + +> If you're building a theme for the Shopify Theme Store, then you can use Horizon as a starting point. However, the theme that you submit needs to be [substantively different from Horizon](https://shopify.dev/themes/store/requirements#uniqueness) so that it provides added value for merchants. Learn about the [theme developer tools](https://shopify.dev/docs/storefronts/themes/tools). + +Please note that the main branch may include code for features not yet released. The "stable" version of Horizon is available in the theme store. + +## Staying up to date with Horizon changes + +Say you're building a new theme off Horizon but you still want to be able to pull in the latest changes, you can add a remote `upstream` pointing to this Horizon repository. + +1. Navigate to your local theme folder. +2. Verify the list of remotes and validate that you have both an `origin` and `upstream`: + +```sh +git remote -v +``` + +3. If you don't see an `upstream`, you can add one that points to Shopify's Horizon repository: + +```sh +git remote add upstream https://github.com/Shopify/horizon.git +``` + +4. Pull in the latest Horizon changes into your repository: + +```sh +git fetch upstream +git pull upstream main +``` + +## Developer tools + +There are a number of really useful tools that the Shopify Themes team uses during development. Horizon is already set up to work with these tools. + +### Shopify CLI + +[Shopify CLI](https://shopify.dev/docs/storefronts/themes/tools/cli) helps you build Shopify themes faster and is used to automate and enhance your local development workflow. It comes bundled with a suite of commands for developing Shopify themes—everything from working with themes on a Shopify store (e.g. creating, publishing, deleting themes) or launching a development server for local theme development. + +You can follow this [quick start guide for theme developers](https://shopify.dev/docs/themes/tools/cli) to get started. + +### Theme Check + +We recommend using [Theme Check](https://github.com/shopify/theme-check) as a way to validate and lint your Shopify themes. + +We've added Theme Check to Horizon's [list of VS Code extensions](/.vscode/extensions.json) so if you're using Visual Studio Code as your code editor of choice, you'll be prompted to install the [Theme Check VS Code](https://marketplace.visualstudio.com/items?itemName=Shopify.theme-check-vscode) extension upon opening VS Code after you've forked and cloned Horizon. + +You can also run it from a terminal with the following Shopify CLI command: + +```bash +shopify theme check +``` + +You can follow the [theme check documentation](https://shopify.dev/docs/storefronts/themes/tools/theme-check) for more details. + +### Continuous Integration + +Horizon uses [GitHub Actions](https://github.com/features/actions) to maintain the quality of the theme. [This is a starting point](https://github.com/Shopify/horizon/blob/main/.github/workflows/ci.yml) and what we suggest to use in order to ensure you're building better themes. Feel free to build off of it! + +#### Shopify/lighthouse-ci-action + +We love fast websites! Which is why we created [Shopify/lighthouse-ci-action](https://github.com/Shopify/lighthouse-ci-action). This runs a series of [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) audits for the home, product and collections pages on a store to ensure code that gets added doesn't degrade storefront performance over time. + +#### Shopify/theme-check-action + +Horizon runs [Theme Check](#Theme-Check) on every commit via [Shopify/theme-check-action](https://github.com/Shopify/theme-check-action). + +## Contributing + +We are not accepting contributions to Horizon at this time. + +## Code of conduct + +All developers who wish to contribute through code, please first read our [Code of Conduct](https://github.com/Shopify/horizon/blob/main/.github/CODE_OF_CONDUCT.md). + +## Theme Store submission + +The [Shopify Theme Store](https://themes.shopify.com/) is the place where Shopify merchants find the themes that they'll use to showcase and support their business. As a theme partner, you can create themes for the Shopify Theme Store and reach an international audience of an ever-growing number of entrepreneurs. + +Ensure that you follow the list of [theme store requirements](https://shopify.dev/themes/store/requirements) if you're interested in becoming a [Shopify Theme Partner](https://themes.shopify.com/services/themes/guidelines) and building themes for the Shopify platform. + +## License + +Copyright (c) 2021-present Shopify Inc. See [LICENSE](/LICENSE.md) for further details. diff --git a/assets/accordion-custom.js b/assets/accordion-custom.js new file mode 100644 index 000000000..608ce905e --- /dev/null +++ b/assets/accordion-custom.js @@ -0,0 +1,106 @@ +import { mediaQueryLarge, isMobileBreakpoint } from '@theme/utilities'; + +// Accordion +class AccordionCustom extends HTMLElement { + /** @type {HTMLDetailsElement} */ + get details() { + const details = this.querySelector('details'); + + if (!(details instanceof HTMLDetailsElement)) throw new Error('Details element not found'); + + return details; + } + + /** @type {HTMLElement} */ + get summary() { + const summary = this.details.querySelector('summary'); + + if (!(summary instanceof HTMLElement)) throw new Error('Summary element not found'); + + return summary; + } + + get #disableOnMobile() { + return this.dataset.disableOnMobile === 'true'; + } + + get #disableOnDesktop() { + return this.dataset.disableOnDesktop === 'true'; + } + + get #closeWithEscape() { + return this.dataset.closeWithEscape === 'true'; + } + + #controller = new AbortController(); + + connectedCallback() { + const { signal } = this.#controller; + + this.#setDefaultOpenState(); + + this.addEventListener('keydown', this.#handleKeyDown, { signal }); + this.summary.addEventListener('click', this.handleClick, { signal }); + mediaQueryLarge.addEventListener('change', this.#handleMediaQueryChange, { signal }); + } + + /** + * Handles the disconnect event. + */ + disconnectedCallback() { + // Disconnect all the event listeners + this.#controller.abort(); + } + + /** + * Handles the click event. + * @param {Event} event - The event. + */ + handleClick = (event) => { + const isMobile = isMobileBreakpoint(); + const isDesktop = !isMobile; + + // Stop default behaviour from the browser + if ((isMobile && this.#disableOnMobile) || (isDesktop && this.#disableOnDesktop)) { + event.preventDefault(); + return; + } + }; + + /** + * Handles the media query change event. + */ + #handleMediaQueryChange = () => { + this.#setDefaultOpenState(); + }; + + /** + * Sets the default open state of the accordion based on the `open-by-default-on-mobile` and `open-by-default-on-desktop` attributes. + */ + #setDefaultOpenState() { + const isMobile = isMobileBreakpoint(); + + this.details.open = + (isMobile && this.hasAttribute('open-by-default-on-mobile')) || + (!isMobile && this.hasAttribute('open-by-default-on-desktop')); + } + + /** + * Handles keydown events for the accordion + * + * @param {KeyboardEvent} event - The keyboard event. + */ + #handleKeyDown(event) { + // Close the accordion when used as a menu + if (event.key === 'Escape' && this.#closeWithEscape) { + event.preventDefault(); + + this.details.open = false; + this.summary.focus(); + } + } +} + +if (!customElements.get('accordion-custom')) { + customElements.define('accordion-custom', AccordionCustom); +} diff --git a/assets/account-login-actions.js b/assets/account-login-actions.js new file mode 100644 index 000000000..fb2b488b1 --- /dev/null +++ b/assets/account-login-actions.js @@ -0,0 +1,34 @@ +/** + * A custom element that manages the account login actions. + * + * @extends {HTMLElement} + */ +class AccountLoginActions extends HTMLElement { + /** + * @type {Element | null} + */ + shopLoginButton = null; + + connectedCallback() { + this.shopLoginButton = this.querySelector('shop-login-button'); + + if (this.shopLoginButton) { + // We don't have control over the shop-login-button markup, so we need to set additional attributes here + this.shopLoginButton.setAttribute('full-width', 'true'); + this.shopLoginButton.setAttribute('persist-after-sign-in', 'true'); + // Do this only if New Customer Account is ALWAYS the sign in option (and never Classic Customer Account) + this.shopLoginButton.setAttribute('analytics-context', 'loginWithShopSelfServe'); + this.shopLoginButton.setAttribute('flow-version', 'account-actions-popover'); + this.shopLoginButton.setAttribute('return-uri', window.location.href); + + // Reload the page after the login is completed, otherwise the page state is incorrect + this.shopLoginButton.addEventListener('completed', () => { + window.location.reload(); + }); + } + } +} + +if (!customElements.get('account-login-actions')) { + customElements.define('account-login-actions', AccountLoginActions); +} diff --git a/assets/anchored-popover.js b/assets/anchored-popover.js new file mode 100644 index 000000000..631dbaa01 --- /dev/null +++ b/assets/anchored-popover.js @@ -0,0 +1,80 @@ +import { Component } from '@theme/component'; +import { debounce, requestIdleCallback } from '@theme/utilities'; + +/** + * A custom element that manages the popover + popover trigger relationship for anchoring. + * Calculates the trigger position and inlines custom properties on the popover element + * that can be consumed by CSS for positioning. + * + * @extends {Component} + * + * @example + * ```html + * + * + * + * + * ``` + * + * @property {string[]} requiredRefs - Required refs: 'popover' and 'trigger' + * @property {string} [data-close-on-resize] - When present, closes popover on window resize + */ +export class AnchoredPopoverComponent extends Component { + requiredRefs = ['popover', 'trigger']; + + /** + * Updates the popover position by calculating trigger element bounds + * and setting CSS custom properties on the popover element. + */ + #updatePosition = async () => { + const popover = /** @type {HTMLElement} */ (this.refs.popover); + const trigger = /** @type {HTMLElement} */ (this.refs.trigger); + if (!popover || !trigger) return; + const positions = trigger.getBoundingClientRect(); + popover.style.setProperty('--anchor-top', `${positions.top}`); + popover.style.setProperty('--anchor-right', `${window.innerWidth - positions.right}`); + popover.style.setProperty('--anchor-bottom', `${window.innerHeight - positions.bottom}`); + popover.style.setProperty('--anchor-left', `${positions.left}`); + }; + + /** + * Debounced resize handler that optionally closes the popover + * when the window is resized, based on the data-close-on-resize attribute. + */ + #resizeListener = debounce(() => { + if (this.dataset.closeOnResize) { + const popover = /** @type {HTMLElement} */ (this.refs.popover); + if (popover && popover.matches(':popover-open')) { + popover.hidePopover(); + } + } + }, 100); + + /** + * Component initialization - sets up event listeners for resize and popover toggle events. + */ + connectedCallback() { + super.connectedCallback(); + const popover = /** @type {HTMLElement} */ (this.refs.popover); + popover?.addEventListener('beforetoggle', (event) => { + const evt = /** @type {ToggleEvent} */ (event); + this.#updatePosition(); + window[evt.newState === 'open' ? 'addEventListener' : 'removeEventListener']('resize', this.#resizeListener); + }); + requestIdleCallback(() => { + this.#updatePosition(); + }); + } + + /** + * Component cleanup - removes resize event listener. + */ + disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener('resize', this.#resizeListener); + } +} + +if (!customElements.get('anchored-popover-component')) { + customElements.define('anchored-popover-component', AnchoredPopoverComponent); +} diff --git a/assets/announcement-bar.js b/assets/announcement-bar.js new file mode 100644 index 000000000..37de90aa2 --- /dev/null +++ b/assets/announcement-bar.js @@ -0,0 +1,130 @@ +import { Component } from '@theme/component'; + +/** + * Announcement banner custom element that allows fading between content. + * Based on the Slideshow component. + * + * @typedef {object} Refs + * @property {HTMLElement} slideshowContainer + * @property {HTMLElement[]} [slides] + * @property {HTMLButtonElement} [previous] + * @property {HTMLButtonElement} [next] + * + * @extends {Component} + */ +export class AnnouncementBar extends Component { + #current = 0; + + /** + * The interval ID for automatic playback. + * @type {number|undefined} + */ + #interval = undefined; + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener('mouseenter', this.suspend); + this.addEventListener('mouseleave', this.resume); + document.addEventListener('visibilitychange', this.#handleVisibilityChange); + + this.play(); + } + + next() { + this.current += 1; + } + + previous() { + this.current -= 1; + } + + /** + * Starts automatic slide playback. + * @param {number} [interval] - The time interval in seconds between slides. + */ + play(interval = this.autoplayInterval) { + if (!this.autoplay) return; + + this.paused = false; + + this.#interval = setInterval(() => { + if (this.matches(':hover') || document.hidden) return; + + this.next(); + }, interval); + } + + /** + * Pauses automatic slide playback. + */ + pause() { + this.paused = true; + this.suspend(); + } + + get paused() { + return this.hasAttribute('paused'); + } + + set paused(paused) { + this.toggleAttribute('paused', paused); + } + + /** + * Suspends automatic slide playback. + */ + suspend() { + clearInterval(this.#interval); + this.#interval = undefined; + } + + /** + * Resumes automatic slide playback if autoplay is enabled. + */ + resume() { + if (!this.autoplay || this.paused) return; + + this.pause(); + this.play(); + } + + get autoplay() { + return Boolean(this.autoplayInterval); + } + + get autoplayInterval() { + const interval = this.getAttribute('autoplay'); + const value = parseInt(`${interval}`, 10); + + if (Number.isNaN(value)) return undefined; + + return value * 1000; + } + + get current() { + return this.#current; + } + + set current(current) { + this.#current = current; + + let relativeIndex = current % (this.refs.slides ?? []).length; + if (relativeIndex < 0) { + relativeIndex += (this.refs.slides ?? []).length; + } + + this.refs.slides?.forEach((slide, index) => { + slide.setAttribute('aria-hidden', `${index !== relativeIndex}`); + }); + } + + /** + * Pause the slideshow when the page is hidden. + */ + #handleVisibilityChange = () => (document.hidden ? this.pause() : this.resume()); +} + +if (!customElements.get('announcement-bar-component')) { + customElements.define('announcement-bar-component', AnnouncementBar); +} diff --git a/assets/auto-close-details.js b/assets/auto-close-details.js new file mode 100644 index 000000000..6af50e14a --- /dev/null +++ b/assets/auto-close-details.js @@ -0,0 +1,15 @@ +(function autoCloseDetails() { + document.addEventListener('click', function (event) { + const detailsToClose = [...document.querySelectorAll('details[data-auto-close-details][open]')].filter( + (element) => { + const closingOn = window.innerWidth < 750 ? 'mobile' : 'desktop'; + return ( + element.getAttribute('data-auto-close-details')?.includes(closingOn) && + !(event.target instanceof Node && element.contains(event.target)) + ); + } + ); + + for (const detailsElement of detailsToClose) detailsElement.removeAttribute('open'); + }); +})(); diff --git a/assets/base.css b/assets/base.css new file mode 100644 index 000000000..7159ef6ae --- /dev/null +++ b/assets/base.css @@ -0,0 +1,4225 @@ +* { + box-sizing: border-box; +} + +body { + color: var(--color-foreground); + background: var(--color-background); + display: flex; + flex-direction: column; + margin: 0; + min-height: 100svh; +} + +:root { + --hover-lift-amount: 4px; + --hover-scale-amount: 1.03; + --hover-subtle-zoom-amount: 1.015; + --hover-shadow-color: var(--color-shadow); + --hover-transition-duration: 0.25s; + --hover-transition-timing: ease-out; +} + +html { + /* Firefox */ + scrollbar-width: thin; + scrollbar-color: rgb(var(--color-foreground-rgb) / var(--opacity-40)) var(--color-background); + scroll-behavior: smooth; +} + +html[scroll-lock] { + overflow: hidden; +} + +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} + +img { + width: 100%; + height: auto; +} + +input, +textarea, +select { + font: inherit; + border-radius: var(--style-border-radius-inputs); +} + +input:hover { + background-color: var(--color-input-hover-background); +} + +/** override ios and firefox defaults */ +select { + background-color: var(--color-background); + color: currentcolor; +} + +.product-card, +.collection-card, +.resource-card, +.predictive-search-results__card--product, +.predictive-search-results__card { + position: relative; + transition: transform var(--hover-transition-duration) var(--hover-transition-timing), + box-shadow var(--hover-transition-duration) var(--hover-transition-timing); + will-change: transform, box-shadow; + z-index: var(--layer-flat); +} + +.product-card__link { + position: absolute; + inset: 0; +} + +.product-card__content { + position: relative; +} + +.product-card__content { + cursor: pointer; +} + +.product-card__content slideshow-component { + --cursor: pointer; +} + +.predictive-search-results__card .product-card, +.predictive-search-results__card .collection-card, +.predictive-search-results__card .resource-card { + transition: none; + will-change: auto; +} + +@media (any-pointer: fine) and (prefers-reduced-motion: no-preference) { + .card-hover-effect-lift .product-card:hover, + .card-hover-effect-lift .collection-card:hover, + .card-hover-effect-lift .resource-card:hover, + .card-hover-effect-lift .predictive-search-results__card:hover { + transform: translateY(calc(-1 * var(--hover-lift-amount))); + } + + .card-hover-effect-lift .header .product-card:hover, + .card-hover-effect-lift .header .collection-card:hover, + .card-hover-effect-lift .header .resource-card:hover, + .card-hover-effect-lift .header-drawer .product-card:hover, + .card-hover-effect-lift .header-drawer .collection-card:hover, + .card-hover-effect-lift .header-drawer .resource-card:hover { + transform: none; + } + + .card-hover-effect-scale .product-card:hover, + .card-hover-effect-scale .collection-card:hover, + .card-hover-effect-scale .resource-card:hover, + .card-hover-effect-scale .predictive-search-results__card:hover { + transform: scale(var(--hover-scale-amount)); + } + + .card-hover-effect-scale .header .product-card:hover, + .card-hover-effect-scale .header .collection-card:hover, + .card-hover-effect-scale .header .resource-card:hover, + .card-hover-effect-scale .header-drawer .product-card:hover, + .card-hover-effect-scale .header-drawer .collection-card:hover, + .card-hover-effect-scale .header-drawer .resource-card:hover { + transform: none; + } + + .card-hover-effect-subtle-zoom .card-gallery, + .card-hover-effect-subtle-zoom .collection-card__image, + .card-hover-effect-subtle-zoom .product-card__image, + .card-hover-effect-subtle-zoom .resource-card__image { + overflow: hidden; + transition: transform var(--hover-transition-duration) var(--hover-transition-timing); + } + + .predictive-search-results__card .card-gallery, + .predictive-search-results__card .collection-card__image, + .predictive-search-results__card .product-card__image, + .predictive-search-results__card .resource-card__image { + transition: none; + } + + .card-hover-effect-subtle-zoom .product-card:hover .card-gallery, + .card-hover-effect-subtle-zoom .collection-card:hover .collection-card__image, + .card-hover-effect-subtle-zoom .product-card:hover .product-card__image, + .card-hover-effect-subtle-zoom .resource-card:hover .resource-card__image, + .card-hover-effect-subtle-zoom .predictive-search-results__card:hover { + transform: scale(var(--hover-subtle-zoom-amount)); + } + + .card-hover-effect-subtle-zoom .header .product-card:hover .card-gallery, + .card-hover-effect-subtle-zoom .header .collection-card:hover .collection-card__image, + .card-hover-effect-subtle-zoom .header .product-card:hover .product-card__image, + .card-hover-effect-subtle-zoom .header .resource-card:hover .resource-card__image, + .card-hover-effect-subtle-zoom .header-drawer .product-card:hover .card-gallery, + .card-hover-effect-subtle-zoom .header-drawer .collection-card:hover .collection-card__image, + .card-hover-effect-subtle-zoom .header-drawer .product-card:hover .product-card__image, + .card-hover-effect-subtle-zoom .header-drawer .resource-card:hover .resource-card__image { + transform: none; + } + + .predictive-search-results__card .product-card:hover, + .predictive-search-results__card .collection-card:hover, + .predictive-search-results__card .resource-card:hover, + .header .product-card:hover, + .header .collection-card:hover, + .header .resource-card:hover, + .header-drawer .product-card:hover, + .header-drawer .collection-card:hover, + .header-drawer .resource-card:hover { + transform: none; + box-shadow: none; + } +} + +dialog { + /* the ::backdrop inherits from the originating element, custom properties must be set on the dialog element */ + --backdrop-color-rgb: var(--color-shadow-rgb); + + background-color: var(--color-background); + color: var(--color-foreground); +} + +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; +} + +p:empty { + display: none; +} + +:first-child:is(p, h1, h2, h3, h4, h5, h6), +:first-child:empty + :where(p, h1, h2, h3, h4, h5, h6) { + margin-block-start: 0; +} + +/* Remove bottom margin from last text item, or previous to last if the last is empty */ +:last-child:is(p, h1, h2, h3, h4, h5, h6), +:where(p, h1, h2, h3, h4, h5, h6):nth-child(2):has(+ :last-child:empty) { + margin-block-end: 0; +} + +/* view transitions */ +@media (prefers-reduced-motion: no-preference) { + @view-transition { + navigation: auto; + } + + /* Keep page interactive while view transitions are running */ + :root { + view-transition-name: none; + } + + /* Have the root transition during page navigation */ + html:active-view-transition-type(page-navigation), + html:active-view-transition-type(product-image-transition) { + view-transition-name: root-custom; + } + + ::view-transition { + pointer-events: none; + } + + html:active-view-transition-type(page-navigation) main[data-page-transition-enabled='true'] { + view-transition-name: main-content; + } + + html:active-view-transition-type(page-navigation) main[data-product-transition='true'][data-template*='product'] { + view-transition-name: none; + } + + ::view-transition-old(main-content) { + animation: var(--view-transition-old-main-content); + } + + ::view-transition-new(main-content) { + animation: var(--view-transition-new-main-content); + } + + html:active-view-transition-type(product-image-transition) { + [data-view-transition-type='product-image-transition'] { + view-transition-name: product-image-transition; + } + + [data-view-transition-type='product-details'] { + view-transition-name: product-details; + } + } + + ::view-transition-group(product-image-transition) { + z-index: 1; + } + + ::view-transition-group(product-image-transition), + ::view-transition-group(product-details) { + animation-duration: var(--animation-speed); + animation-timing-function: var(--animation-easing); + } + + ::view-transition-old(product-image-transition), + ::view-transition-new(product-image-transition) { + block-size: 100%; + overflow: hidden; + object-fit: cover; + animation-duration: 0.25s; + animation-timing-function: var(--animation-easing); + } + + ::view-transition-new(product-details) { + animation: var(--view-transition-new-main-content); + } +} + +/* Focus */ +*:focus-visible { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); +} + +@supports not selector(:focus-visible) { + *:focus { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } +} + +.focus-inset { + outline-offset: calc(var(--focus-outline-width) * -1); +} + +/* Layout */ +.content-for-layout { + flex: 1; +} + +/* Set up page widths & margins */ +.page-width-wide, +.page-width-normal, +.page-width-narrow, +.page-width-content { + --page-margin: 16px; +} + +@media screen and (min-width: 750px) { + .page-width-wide, + .page-width-normal, + .page-width-narrow, + .page-width-content { + --page-margin: 40px; + } +} + +.page-width-wide { + /* NOTE: This results in a page width of 2400px because of how we set up margins with grid */ + --page-content-width: var(--wide-page-width); + --page-width: calc(var(--page-content-width) + (var(--page-margin) * 2)); +} + +.page-width-normal { + --page-content-width: var(--normal-page-width); + --page-width: calc(var(--page-content-width) + (var(--page-margin) * 2)); +} + +.page-width-narrow, +.page-width-content { + /* NOTE: This results in a page width of 1400px because of how we set up margins with grid */ + --page-content-width: var(--narrow-page-width); + --page-width: calc(var(--page-content-width) + (var(--page-margin) * 2)); +} + +.page-width-content { + --page-content-width: var(--normal-content-width); + --page-width: calc(var(--page-content-width) + (var(--page-margin) * 2)); +} + +/* Section width full vs. page + The reason we use a grid to contain the section is to allow for the section to have a + full-width background image even if the section content is constrained by the page width. Do not try + to rewrite this to max-width: --page-width; margin: 0 auto;, it doesn't work. */ +.section { + --full-page-grid-central-column-width: min( + var(--page-width) - var(--page-margin) * 2, + calc(100% - var(--page-margin) * 2) + ); + --full-page-grid-margin: minmax(var(--page-margin), 1fr); + --full-page-grid-with-margins: var(--full-page-grid-margin) var(--full-page-grid-central-column-width) + var(--full-page-grid-margin); + + /* Utility variable gives the grid's first column width. Provides an offset width for components like carousels */ + --util-page-margin-offset: max( + var(--page-margin), + calc((100% - min(var(--page-content-width), calc(100% - (var(--page-margin) * 2)))) / 2) + ); + + /* Offset for full-width sections to account for the page margin, + used for Marquee — note that --util-page-margin-offset doesn't work here */ + --full-page-margin-inline-offset: calc(((100vw - var(--full-page-grid-central-column-width)) / 2) * -1); + + width: 100%; + + /* This is required to make background images work, which are rendered absolutely */ + position: relative; + + /* Set up the grid */ + display: grid; + grid-template-columns: var(--full-page-grid-with-margins); + min-height: var(--section-min-height, 'auto'); +} + +/* Place all direct children in the center column by default */ +.section > * { + grid-column: 2; +} + +/* Make the actual section background transparent, and instead apply it to a separate sibling element to enable stacking with hero shadow */ +.shopify-section:not(.header-section) :is(.section, .cart__summary-container) { + background: transparent; +} + +.shopify-section:not(.header-section):has(.section) { + position: relative; +} + +.shopify-section:not(.header-section) .section-background { + content: ''; + position: absolute; + inset: 0; + z-index: var(--layer-section-background); +} + +/* For page-width sections, all content goes in the center column */ +.section--page-width > * { + grid-column: 2; +} + +/* For full-width sections, content spans all columns */ +.section--full-width > * { + grid-column: 1 / -1; +} + +/* Some page-width sections should still extend all the way to the right edge of the page, e.g. collection carousel */ +.section--page-width.section--full-width-right > * { + grid-column: 2 / 4; +} + +/* For full-width sections with margin, content still spans full width but with space on the sides */ +.section--full-width.section--full-width-margin > * { + grid-column: 1 / -1; + + @media screen and (min-width: 750px) { + padding-left: var(--page-margin); + padding-right: var(--page-margin); + } +} + +/* Some section content break out to full width of the page */ +.section > .force-full-width { + grid-column: 1 / -1; +} + +.section--height-small { + --section-min-height: var(--section-height-small); +} + +.section--height-medium { + --section-min-height: var(--section-height-medium); +} + +.section--height-large { + --section-min-height: var(--section-height-large); +} + +.section--height-full-screen { + --section-min-height: 100svh; +} + +.section-content-wrapper.section-content-wrapper { + min-height: calc(var(--section-min-height, 'auto') - var(--section-height-offset, 0px)); + position: relative; + width: 100%; + height: 100%; +} + +/* Utility */ + +.hidden { + /* stylelint-disable-next-line declaration-no-important */ + display: none !important; +} + +@media screen and (max-width: 749px) { + .hidden--mobile, + .mobile\:hidden { + /* stylelint-disable-next-line declaration-no-important */ + display: none !important; + } +} + +@media screen and (min-width: 750px) { + .hidden--desktop, + .desktop\:hidden { + /* stylelint-disable-next-line declaration-no-important */ + display: none !important; + } +} + +.hide-when-empty:empty { + /* stylelint-disable-next-line declaration-no-important */ + display: none !important; +} + +.visually-hidden:not(:focus, :active) { + /* stylelint-disable-next-line declaration-no-important */ + position: absolute !important; + overflow: hidden; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + /* stylelint-disable-next-line declaration-no-important */ + word-wrap: normal !important; +} + +@media screen and (max-width: 749px) { + .is-visually-hidden-mobile:not(:focus, :active) { + /* stylelint-disable-next-line declaration-no-important */ + position: absolute !important; + overflow: hidden; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + /* stylelint-disable-next-line declaration-no-important */ + word-wrap: normal !important; + } +} + +.flex { + display: flex; + gap: var(--gap-md); +} + +.grid { + --centered-column-number: 12; + --full-width-column-number: 14; + --centered: column-1 / span var(--centered-column-number); + --full-width: column-0 / span var(--full-width-column-number); + + display: flex; + flex-direction: column; +} + +@media screen and (min-width: 750px) { + .grid { + display: grid; + gap: 0; + grid-template-columns: var(--margin-4xl) repeat(var(--centered-column-number), minmax(0, 1fr)) var(--margin-4xl); + grid-template-areas: 'column-0 column-1 column-2 column-3 column-4 column-5 column-6 column-7 column-8 column-9 column-10 column-11 column-12 column-13'; + } +} + +@media screen and (min-width: 1400px) { + .grid { + grid-template-columns: + 1fr repeat( + var(--centered-column-number), + minmax(0, calc((var(--page-width) - var(--page-margin) * 2) / var(--centered-column-number))) + ) + 1fr; + } +} + +.flex { + display: flex; + gap: var(--gap-md); +} + +.flip-x { + scale: -1 1; +} + +.flip-y { + scale: 1 -1; +} + +.list-unstyled { + margin: 0; + padding: 0; + list-style: none; +} + +.skip-to-content-link { + position: absolute; + overflow: hidden; + height: 1px; + left: -99999px; + word-wrap: normal !important; +} + +.skip-to-content-link:focus { + z-index: var(--layer-temporary); + overflow: auto; + width: auto; + height: auto; + padding: var(--padding-lg) var(--padding-4xl); + left: var(--margin-lg); + top: var(--margin-lg); + box-shadow: 0 0 0 var(--focus-outline-offset) var(--color-background); +} + +.text-left { + --text-align: left; + + text-align: left; +} + +.text-center { + --text-align: center; + + text-align: center; +} + +.text-right { + --text-align: right; + + text-align: right; +} + +.text-inherit { + color: inherit; +} + +.justify-left { + justify-content: left; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + justify-content: right; +} + +.title--aligned-center { + display: flex; + align-items: center; + gap: 1rem; +} + +.background-image-container { + overflow: hidden; + position: absolute; + inset: 0; + opacity: var(--image-opacity); +} + +.background-image-container img, +.background-image-container svg { + object-fit: cover; + width: 100%; + height: 100%; +} + +.background-image-fit img, +.background-image-fit svg { + object-fit: contain; +} + +.svg-wrapper { + color: currentcolor; + display: inline-flex; + justify-content: center; + align-items: center; + width: var(--icon-size-sm); + height: var(--icon-size-sm); + pointer-events: none; +} + +.svg-wrapper--smaller { + width: var(--icon-size-2xs); + height: var(--icon-size-2xs); +} + +.svg-wrapper--small { + width: var(--icon-size-xs); + height: var(--icon-size-xs); +} + +.svg-wrapper > svg { + width: var(--icon-size-sm); + height: var(--icon-size-sm); +} + +.relative { + position: relative; +} + +/* Icons */ +.icon-success, +.icon-error { + width: var(--icon-size-md); + height: var(--icon-size-md); + flex-shrink: 0; +} + +.icon-success { + color: var(--color-success); +} + +.icon-error { + fill: var(--color-error); +} + +placeholder-image { + display: block; + height: 100%; + aspect-ratio: var(--ratio); +} + +placeholder-image[data-type='product'] { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-15)); + width: 100%; +} + +/** Placeholder background for the placeholder image, the dimensions are the same as the product images */ +placeholder-image[data-type='product']:not(:has(> img)) { + aspect-ratio: var(--ratio); + height: 350px; +} + +placeholder-image > img { + object-fit: cover; + aspect-ratio: var(--ratio); + height: 100%; +} + +/* Base text and heading styles */ +body, +.paragraph:not(.button), +.paragraph > * { + font-family: var(--font-paragraph--family); + font-style: var(--font-paragraph--style); + font-weight: var(--font-paragraph--weight); + font-size: var(--font-paragraph--size); + line-height: var(--font-paragraph--line-height); + text-transform: var(--font-paragraph--case); + -webkit-font-smoothing: antialiased; + color: var(--color, var(--color-foreground)); +} + +/* Ensure inputs with type presets maintain minimum 16px on mobile to prevent iOS zoom */ +@media screen and (max-width: 1200px) { + input.paragraph.paragraph, + input.paragraph.paragraph:not([type]), + textarea.paragraph.paragraph, + select.paragraph.paragraph { + font-size: max(1rem, var(--font-paragraph--size)); + } +} + +.paragraph > small { + font-size: smaller; +} + +/* Typography presets */ + +h1, +.h1.h1, +.text-block.h1 > * { + font-family: var(--font-h1--family); + font-style: var(--font-h1--style); + font-weight: var(--font-h1--weight); + font-size: var(--font-h1--size); + line-height: var(--font-h1--line-height); + letter-spacing: var(--font-h1--letter-spacing); + text-transform: var(--font-h1--case); + color: var(--color, var(--font-h1-color)); +} + +@media screen and (max-width: 1200px) { + input.h1.h1, + textarea.h1.h1, + select.h1.h1 { + font-size: max(1rem, var(--font-h1--size)); + } +} + +h2, +.h2.h2, +.text-block.h2 > * { + font-family: var(--font-h2--family); + font-style: var(--font-h2--style); + font-weight: var(--font-h2--weight); + font-size: var(--font-h2--size); + line-height: var(--font-h2--line-height); + letter-spacing: var(--font-h2--letter-spacing); + text-transform: var(--font-h2--case); + color: var(--color, var(--font-h2-color)); +} + +@media screen and (max-width: 1200px) { + input.h2.h2, + textarea.h2.h2, + select.h2.h2 { + font-size: max(1rem, var(--font-h2--size)); + } +} + +h3, +.h3, +.h3.h3, +.text-block.h3 > * { + font-family: var(--font-h3--family); + font-style: var(--font-h3--style); + font-weight: var(--font-h3--weight); + font-size: var(--font-h3--size); + line-height: var(--font-h3--line-height); + letter-spacing: var(--font-h3--letter-spacing); + text-transform: var(--font-h3--case); + color: var(--color, var(--font-h3-color)); +} + +@media screen and (max-width: 1200px) { + input.h3, + textarea.h3, + select.h3 { + font-size: max(1rem, var(--font-h3--size)); + } +} + +h4, +.h4.h4, +.text-block.h4 > * { + font-family: var(--font-h4--family); + font-style: var(--font-h4--style); + font-weight: var(--font-h4--weight); + font-size: var(--font-h4--size); + line-height: var(--font-h4--line-height); + letter-spacing: var(--font-h4--letter-spacing); + text-transform: var(--font-h4--case); + color: var(--color, var(--font-h4-color)); +} + +@media screen and (max-width: 1200px) { + input.h4.h4, + textarea.h4.h4, + select.h4.h4 { + font-size: max(1rem, var(--font-h4--size)); + } +} + +h5, +.h5.h5, +.text-block.h5 > * { + font-family: var(--font-h5--family); + font-style: var(--font-h5--style); + font-weight: var(--font-h5--weight); + font-size: var(--font-h5--size); + line-height: var(--font-h5--line-height); + letter-spacing: var(--font-h5--letter-spacing); + text-transform: var(--font-h5--case); + color: var(--color, var(--font-h5-color)); +} + +@media screen and (max-width: 1200px) { + input.h5.h5, + textarea.h5.h5, + select.h5.h5 { + font-size: max(1rem, var(--font-h5--size)); + } +} + +h6, +.h6.h6, +.text-block.h6 > * { + font-family: var(--font-h6--family); + font-style: var(--font-h6--style); + font-weight: var(--font-h6--weight); + font-size: var(--font-h6--size); + line-height: var(--font-h6--line-height); + letter-spacing: var(--font-h6--letter-spacing); + text-transform: var(--font-h6--case); + color: var(--color, var(--font-h6-color)); +} + +@media screen and (max-width: 1200px) { + input.h6.h6, + textarea.h6.h6, + select.h6.h6 { + font-size: max(1rem, var(--font-h6--size)); + } +} + +:first-child:is(.h1, .h2, .h3, .h4, .h5, .h6) { + margin-block-start: 0; +} + +:last-child:is(.h1, .h2, .h3, .h4, .h5, .h6) { + margin-block-end: 0; +} + +/* Links */ +a { + --button-color: var(--color, var(--color-primary)); + + color: var(--button-color); + text-decoration-color: transparent; + text-decoration-thickness: 0.075em; + text-underline-offset: 0.125em; + transition: text-decoration-color var(--animation-speed) var(--animation-easing), + color var(--animation-speed) var(--animation-easing); +} + +:is(h1, h2, h3, h4, h5, h6, p) > a:hover { + --button-color: var(--color, var(--color-primary-hover)); +} + +/* Add underline to text using our paragraph styles only. */ +p:not(.h1, .h2, .h3, .h4, .h5, .h6) a:where(:not(.button, .button-primary, .button-secondary)), +.rte + :is(p, ul, ol, table):not(.h1, .h2, .h3, .h4, .h5, .h6) + a:where(:not(.button, .button-primary, .button-secondary)) { + text-decoration-color: currentcolor; + + &:hover { + text-decoration-color: transparent; + color: var(--color-primary-hover); + } +} + +.container-background-image { + background-repeat: no-repeat; + background-size: cover; + background-position: center center; +} + +details[open] .summary-closed { + display: none; +} + +details:not([open]) .summary-open { + display: none; +} + +details[open] > summary .icon-animated > svg { + transform: rotate(180deg); +} + +/* iOS fix: hide the default arrow on the summary */ +summary::-webkit-details-marker { + display: none; +} + +/* Featured collection block */ +.featured-collection-block { + width: 100%; +} + +/* Product grid */ +.product-grid-container { + display: block; + width: 100%; + padding-block: var(--padding-block-start) var(--padding-block-end); + + @media screen and (min-width: 750px) { + display: grid; + } +} + +.product-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--product-grid-gap); + margin: auto; + padding: 0; + list-style: none; +} + +@media screen and (min-width: 750px) { + .product-grid { + grid-template-columns: var(--product-grid-columns-desktop); + } +} + +.product-grid :is(h3, p) { + margin: 0; +} + +.product-grid__item { + border: var(--product-card-border-width) solid rgb(var(--color-border-rgb) / var(--product-card-border-opacity)); +} + +.product-grid--organic[product-grid-view='default'] .product-grid__item { + height: fit-content; +} + +.product-grid__card.product-grid__card { + display: flex; + flex-flow: column nowrap; + gap: var(--product-card-gap); + align-items: var(--product-card-alignment); + text-decoration: none; + color: var(--color, var(--color-foreground)); + padding-block: var(--padding-block-start) var(--padding-block-end); + padding-inline: var(--padding-inline-start) var(--padding-inline-end); + overflow: hidden; +} + +[product-grid-view='zoom-out'] .product-grid__card { + row-gap: var(--padding-xs); +} + +[product-grid-view='default'] { + --product-grid-gap: 16px; + --padding-block-start: 24px; + --padding-block-end: 24px; + --padding-inline-start: 0px; + --padding-inline-end: 0px; +} + +[product-grid-view='default'] .product-grid__item { + padding-block: 0; +} + +[product-grid-view='mobile-single'], +.product-grid-mobile--large { + @media screen and (max-width: 749px) { + grid-template-columns: 1fr; + } +} + +.product-grid__card .group-block > * { + @media screen and (max-width: 749px) { + flex-direction: column; + } +} + +ul[product-grid-view='zoom-out'] .product-grid__card > * { + display: none; +} + +ul[product-grid-view='zoom-out'] .product-grid__card .card-gallery { + display: block; +} + +[product-grid-view='zoom-out'] + .card-gallery + > :is(quick-add-component, .product-badges, slideshow-component > slideshow-controls) { + display: none; +} + +ul[product-grid-view='zoom-out'] .card-gallery > img { + display: block; +} + +[product-grid-view='zoom-out'] { + --product-grid-columns-desktop: repeat( + 10, + minmax(clamp(50px, calc(100% - 9 * var(--product-grid-gap)) / 10, 80px), 1fr) + ); +} + +.product-grid-view-zoom-out--details { + display: none; +} + +.product-grid-view-zoom-out--details .h4, +.product-grid-view-zoom-out--details span, +.product-grid-view-zoom-out--details s { + font-size: var(--font-size--xs); + font-family: var(--font-paragraph--family); +} + +.product-grid-view-zoom-out--details span { + font-weight: 500; +} + +.product-grid-view-zoom-out--details .h4 { + line-height: 1.3; + font-weight: 400; +} + +.product-grid-view-zoom-out--details > span.h6, +.product-grid-view-zoom-out--details > div.h6 > product-price { + display: inline-block; + line-height: 0; + margin-top: var(--margin-2xs); +} + +.product-grid-view-zoom-out--details > span.h6 > *, +.product-grid-view-zoom-out--details > div.h6 > * > * { + line-height: 1.2; +} + +@media (prefers-reduced-motion: no-preference) { + :root:active-view-transition-type(product-grid) { + details[open] floating-panel-component { + view-transition-name: panel-content; + + .checkbox *, + .facets__pill-label { + transition: none; + } + + .facets--vertical & { + view-transition-name: none; + } + } + + .product-grid { + view-transition-name: product-grid; + } + + footer { + view-transition-name: footer; + } + + .product-grid__item, + floating-panel-component { + transition: none; + } + } +} + +::view-transition-group(panel-content) { + z-index: 1; +} + +::view-transition-new(product-grid) { + animation-delay: 150ms; + animation-name: fadeInUp; + animation-duration: var(--animation-speed); + animation-timing-function: var(--animation-easing); +} + +results-list[initialized] { + .product-grid__item { + transition: opacity var(--animation-speed) var(--animation-easing), + transform var(--animation-speed) var(--animation-easing); + + @starting-style { + opacity: 0; + transform: translateY(10px); + } + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Collection and product list cards have equal heights */ +:is(.product-grid__item, .resource-list__item) .product-card { + display: grid; + height: 100%; +} + +/* Video background */ +.video-background, +.video-background * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; +} + +.video-background--cover * { + object-fit: cover; +} + +.video-background--contain * { + object-fit: contain; +} + +.text-block { + width: 100%; +} + +.text-block > *:first-child, +.text-block > *:first-child:empty + * { + margin-block-start: 0; +} + +.text-block > *:last-child, +.text-block > *:has(+ *:last-child:empty) { + margin-block-end: 0; +} + +/* This is to deal with the margin applied to the p when custom styles are enabled. The p isn't the first child anymore due to the style tag */ +.text-block > style + * { + margin-block-start: 0; +} + +/* Dialog */ +.dialog-modal { + border: none; + box-shadow: var(--shadow-popover); + + @media screen and (min-width: 750px) { + border-radius: var(--style-border-radius-popover); + max-width: var(--normal-content-width); + } + + @media screen and (max-width: 749px) { + max-width: 100%; + max-height: 100%; + height: 100dvh; + width: 100dvw; + padding: var(--padding-md); + } +} + +.dialog-modal::backdrop { + transition: backdrop-filter var(--animation-speed) var(--animation-easing); + backdrop-filter: brightness(1); + background: rgb(var(--backdrop-color-rgb) / var(--backdrop-opacity)); +} + +.dialog-modal[open] { + animation: elementSlideInTop var(--animation-speed) var(--animation-easing) forwards; + + &::backdrop { + animation: backdropFilter var(--animation-speed) var(--animation-easing) forwards; + transition: opacity var(--animation-speed) var(--animation-easing); + } +} + +.dialog-modal.dialog-closing { + animation: elementSlideOutTop var(--animation-speed) var(--animation-easing) forwards; + + &::backdrop { + opacity: 0; + } +} + +/* stylelint-disable value-keyword-case */ +.dialog-drawer { + --dialog-drawer-opening-animation: slideInLeft; + --dialog-drawer-closing-animation: slideOutLeft; +} + +.dialog-drawer--right { + --dialog-drawer-opening-animation: slideInRight; + --dialog-drawer-closing-animation: slideOutRight; +} +/* stylelint-enable value-keyword-case */ + +.dialog-drawer[open] { + animation: var(--dialog-drawer-opening-animation) var(--animation-speed) var(--animation-easing) forwards; +} + +.dialog-drawer.dialog-closing { + animation: var(--dialog-drawer-closing-animation) var(--animation-speed) var(--animation-easing); +} + +/* Buttons */ +.button, +.button-secondary, +button.shopify-payment-button__button--unbranded { + --text-align: center; + + display: grid; + align-content: center; + text-decoration: none; + text-align: var(--text-align); + color: var(--button-color); + appearance: none; + background-color: var(--button-background-color); + border: none; + font-family: var(--font-paragraph--family); + font-style: var(--font-paragraph--style); + font-size: var(--font-paragraph--size); + line-height: var(--font-paragraph--line-height); + margin-block: 0; + transition: color var(--animation-speed) var(--animation-easing), + box-shadow var(--animation-speed) var(--animation-easing), + background-color var(--animation-speed) var(--animation-easing); + cursor: pointer; + width: fit-content; + box-shadow: inset 0 0 0 var(--button-border-width) var(--button-border-color); + padding-block: var(--button-padding-block); + padding-inline: var(--button-padding-inline); +} + +.button { + font-family: var(--button-font-family-primary); + font-weight: var(--button-font-weight-primary); + text-transform: var(--button-text-case-primary); + border-radius: var(--style-border-radius-buttons-primary); +} + +.button:not(.button-secondary, .button-unstyled) { + outline-color: var(--button-background-color); +} + +.button-secondary { + font-family: var(--button-font-family-secondary); + font-weight: var(--button-font-weight-secondary); + text-transform: var(--button-text-case-secondary); + border-radius: var(--style-border-radius-buttons-secondary); +} + +button.shopify-payment-button__button--unbranded { + font-family: var(--button-font-family-primary); + font-weight: var(--button-font-weight-primary); + text-transform: var(--button-text-case-primary); +} + +textarea, +input { + background-color: var(--color-input-background); + border-color: var(--color-input-border); +} + +textarea::placeholder, +input::placeholder { + color: var(--color-input-text); +} + +textarea:not(:placeholder-shown)::placeholder, +input:not(:placeholder-shown)::placeholder { + opacity: 0; +} + +/* The declaration above is messing with buttons that have an attribute of hidden as it overwrites the display value */ +.button[hidden] { + display: none; +} + +.button[aria-disabled='true'], +.button-secondary[aria-disabled='true'], +.button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.button, +button.shopify-payment-button__button--unbranded { + --button-color: var(--color-primary-button-text); + --button-background-color: var(--color-primary-button-background); + --button-border-color: var(--color-primary-button-border); + --button-border-width: var(--style-border-width-primary); +} + +.button:hover, +button.shopify-payment-button__button--unbranded:hover:not([disabled]) { + --button-color: var(--color-primary-button-hover-text); + --button-background-color: var(--color-primary-button-hover-background); + --button-border-color: var(--color-primary-button-hover-border); +} + +.button-secondary { + --button-color: var(--color-secondary-button-text); + --button-background-color: var(--color-secondary-button-background); + --button-border-color: var(--color-secondary-button-border); + --button-border-width: var(--style-border-width-secondary); +} + +.button-secondary:hover { + --button-color: var(--color-secondary-button-hover-text); + --button-background-color: var(--color-secondary-button-hover-background); + --button-border-color: var(--color-secondary-button-hover-border); +} + +/* Needed to override the default Shopify styles */ +button.shopify-payment-button__button--unbranded:hover:not([disabled]) { + background-color: var(--button-background-color); +} + +.button-unstyled { + display: block; + padding: 0; + background-color: inherit; + color: inherit; + border: 0; + border-radius: 0; + overflow: hidden; + box-shadow: none; + font-family: var(--font-paragraph--family); + font-style: var(--font-paragraph--style); + font-size: var(--font-paragraph--size); +} + +.button-unstyled:hover { + background-color: inherit; +} + +.button-unstyled--with-icon { + color: var(--color-foreground); + display: flex; + gap: var(--gap-2xs); + align-items: center; +} + +.button-unstyled--transparent { + background-color: transparent; + box-shadow: none; +} + +/* Show more */ + +.show-more__button { + color: var(--color-primary); + cursor: pointer; +} + +.show-more__button:hover { + @media screen and (min-width: 750px) { + color: var(--color-primary-hover); + } +} + +.show-more__label { + text-align: start; + font-size: var(--font-size--body-md); + font-family: var(--font-paragraph--family); +} + +.show-more__button .svg-wrapper { + width: var(--icon-size-xs); + height: var(--icon-size-xs); +} + +.show-more[data-expanded='true'] .show-more__label--more, +.show-more[data-expanded='false'] .show-more__label--less { + display: none; +} + +.link { + display: inline-block; + text-align: center; +} + +shopify-accelerated-checkout, +shopify-accelerated-checkout-cart { + --shopify-accelerated-checkout-button-border-radius: var(--style-border-radius-buttons-primary); + --shopify-accelerated-checkout-button-block-size: var(--height-buy-buttons); +} + +.product-form-buttons:has(.add-to-cart-button.button-secondary) + :is(shopify-accelerated-checkout, shopify-accelerated-checkout-cart) { + --shopify-accelerated-checkout-button-border-radius: var(--style-border-radius-buttons-secondary); + --shopify-accelerated-checkout-button-block-size: var(--height-buy-buttons); +} + +/* Collapsible row */ + +.icon-caret svg { + transition: transform var(--animation-speed) var(--animation-easing); +} + +.icon-caret--forward svg { + transform: rotate(-90deg); +} + +.icon-caret--backward svg { + transform: rotate(90deg); +} + +summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + padding-block: var(--padding-sm); +} + +summary:hover { + color: var(--color-primary-hover); +} + +summary .svg-wrapper { + margin-inline-start: auto; + height: var(--icon-size-xs); + width: var(--icon-size-xs); + transition: transform var(--animation-speed) var(--animation-easing); +} + +/* Shared plus/minus icon animations */ +summary .icon-plus :is(.horizontal, .vertical), +.show-more__button .icon-plus :is(.horizontal, .vertical) { + transition: transform var(--animation-speed) var(--animation-easing); + transform: rotate(0deg); + transform-origin: 50% 50%; + opacity: 1; +} + +details[open] > summary .icon-plus .horizontal, +.details-open > summary .icon-plus .horizontal, +.show-more:where([data-expanded='true']) .show-more__button .icon-plus .horizontal { + transform: rotate(90deg); +} + +details[open] > summary .icon-plus .vertical, +.details-open > summary .icon-plus .vertical, +.show-more:where([data-expanded='true']) .show-more__button .icon-plus .vertical { + transform: rotate(90deg); + opacity: 0; +} + +/* Product Media */ +media-gallery { + display: block; + width: 100%; +} + +:where(media-gallery, .product-grid__item) { + .media-gallery__grid { + grid-template-columns: 1fr; + gap: var(--image-gap); + } +} + +.product-media-gallery__slideshow--single-media slideshow-container { + @media screen and (max-width: 749px) { + grid-area: unset; + } +} + +:not(.dialog-zoomed-gallery) > .product-media-container { + /* width and overflow forces children to shrink to parent width */ + --slide-width: round(up, 100%, 1px); + + display: flex; + aspect-ratio: var(--gallery-aspect-ratio, var(--media-preview-ratio)); + max-height: var(--constrained-height); + width: 100%; + + /* Relative position needed for video and 3d models */ + position: relative; + overflow: hidden; + + &:where(.constrain-height) { + /* arbitrary offset value based on average theme spacing and header height */ + --viewport-offset: 400px; + --constrained-min-height: 300px; + --constrained-height: max(var(--constrained-min-height), calc(100vh - var(--viewport-offset))); + + margin-right: auto; + margin-left: auto; + } +} + +media-gallery:where(.media-gallery--grid) .media-gallery__grid { + display: none; +} + +.product-media :is(deferred-media, product-model) { + position: absolute; +} + +@media screen and (max-width: 749px) { + .product-media-container.constrain-height { + max-height: none; + } +} + +@media screen and (min-width: 750px) { + .product-media-container.constrain-height { + --viewport-offset: var(--header-height, 100px); + --constrained-min-height: 500px; + } + + .media-gallery--two-column .media-gallery__grid { + grid-template-columns: repeat(2, 1fr); + } + + .media-gallery--large-first-image .product-media-container:first-child, + .media-gallery--two-column .product-media-container:only-child { + /* First child spans 2 columns */ + grid-column: span 2; + } + + /* Display grid view as a carousel on mobile, grid on desktop */ + media-gallery:is(.media-gallery--grid) slideshow-component { + display: none; + } + + media-gallery:where(.media-gallery--grid) .media-gallery__grid { + display: grid; + } +} + +.product-media-container--model { + /* Usefull when view in your space is shown */ + flex-direction: column; +} + +.shopify-model-viewer-ui__controls-area { + bottom: calc(var(--minimum-touch-target) + var(--padding-sm)); +} + +.product-media-container img { + aspect-ratio: inherit; + object-fit: contain; + object-position: center center; +} + +.product-media-container.media-fit { + --product-media-fit: cover; + + img { + object-fit: var(--product-media-fit); + } +} + +/* Media gallery zoom dialog */ +.product-media-container__zoom-button { + position: absolute; + width: 100%; + height: 100%; + z-index: var(--layer-flat); + cursor: zoom-in; +} + +zoom-dialog dialog { + width: 100vw; + height: 100vh; + border: none; + margin: 0; + padding: 0; + max-width: 100%; + max-height: 100%; + background: white; + opacity: 0; + transition: opacity var(--animation-speed) var(--animation-easing); + scrollbar-width: none; + + &[open] { + opacity: 1; + } + + @media (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } + + &::backdrop { + background: transparent; + } +} + +/* Animate the UI elements in only after the view transition is complete */ +.close-button { + position: fixed; + top: var(--margin-lg); + right: var(--margin-lg); + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + z-index: var(--layer-flat); + background-color: transparent; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + animation: elementSlideInBottom var(--animation-speed) var(--animation-easing) forwards; + animation-delay: calc(var(--animation-speed) * 2); +} + +.dialog--closed .close-button { + animation: elementSlideOutBottom calc(var(--animation-speed) * 0.5) var(--animation-easing) forwards; +} + +.dialog-thumbnails-list-container { + position: fixed; + width: 100%; + bottom: 0; + display: flex; + z-index: var(--layer-raised); +} + +.dialog-thumbnails-list { + position: relative; + display: inline-flex; + flex-direction: row; + gap: 8px; + bottom: 0; + overflow-x: auto; + opacity: 0; + padding: var(--padding-lg); + margin-inline: auto; + scrollbar-width: none; + animation: thumbnailsSlideInBottom calc(var(--animation-speed) * 0.75) var(--animation-easing) forwards; + animation-delay: calc(var(--animation-speed) * 1.5); +} + +.dialog--closed .dialog-thumbnails-list { + animation: thumbnailsSlideOutBottom var(--animation-speed) var(--animation-easing) forwards; +} + +@media screen and (min-width: 750px) { + .dialog-thumbnails-list { + position: fixed; + flex-direction: column; + inset: 50% var(--margin-lg) auto auto; + right: 0; + max-height: calc(100vh - 200px); + overflow-y: auto; + animation: thumbnailsSlideInTop calc(var(--animation-speed) * 0.5) var(--animation-easing) forwards; + animation-delay: calc(var(--animation-speed) * 2); + } + + .dialog--closed .dialog-thumbnails-list { + animation: thumbnailsSlideOutTop var(--animation-speed) var(--animation-easing) forwards; + } +} + +.dialog-thumbnails-list__thumbnail { + width: var(--thumbnail-width); + height: auto; + transition: transform var(--animation-speed) var(--animation-easing); + flex-shrink: 0; + border-radius: var(--media-radius); + + img { + height: 100%; + object-fit: cover; + border-radius: var(--media-radius); + aspect-ratio: var(--aspect-ratio); + } + + &:is([aria-selected='true']) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: calc(var(--focus-outline-offset) / 2); + border: var(--style-border-width) solid rgb(var(--color-border-rgb) / var(--media-border-opacity)); + } +} + +.close-button:hover { + background-color: transparent; + opacity: 0.8; +} + +.close-button svg { + width: 20px; + height: 20px; +} + +/* Product media */ +.product-media { + display: flex; + flex: 1; +} + +/* If the product media is already providing an image cover, hide images provided by sibling deferred-media */ +.product-media__image ~ * .deferred-media__poster-image { + display: none; +} + +/* If the product media is playing, hide the preview image */ +.product-media-container:has(.deferred-media__playing) .product-media__image { + opacity: 0; + transition: opacity var(--animation-speed) var(--animation-easing); +} + +/* Deferred media & Product model */ +:is(product-model, deferred-media) { + /* Height needed to make sure when it's set to be stretched, it takes the full height */ + height: 100%; + width: 100%; + position: relative; +} + +product-model model-viewer, +/* Media that have a poster button sibling providing the size should be absolute-positioned. +Otherwise, it should be a block to rely on its own size */ +:is(deferred-media, product-model) > .deferred-media__poster-button ~ *:not(template) { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + + /* Required to make sure the absolute position respects the padding of the wrapper: */ + padding: inherit; +} + +slideshow-slide .shopify-model-viewer-ui__controls-area.shopify-model-viewer-ui__controls-area { + bottom: var(--padding-sm); + right: var(--padding-sm); +} + +.dialog-zoomed-gallery .shopify-model-viewer-ui__controls-area.shopify-model-viewer-ui__controls-area { + /* Move the controls above the thumbnails. Need to calculate the height of the thumbnails list */ + bottom: calc(var(--thumbnail-width) / calc(var(--media-preview-ratio)) + var(--padding-lg) * 2); + right: var(--padding-lg); +} + +@media screen and (max-width: 749px) { + slideshow-component:has(:not(.mobile\:hidden) :is(.slideshow-controls__dots, .slideshow-controls__counter)) + .shopify-model-viewer-ui__controls-area { + /* Position the controls just above the counter */ + bottom: calc(var(--minimum-touch-target) + var(--padding-sm)); + } +} + +@media screen and (min-width: 750px) { + slideshow-component:has(:not(.desktop\:hidden) :is(.slideshow-controls__dots, .slideshow-controls__counter)) + .shopify-model-viewer-ui__controls-area { + /* Position the controls just above the counter */ + bottom: calc(var(--minimum-touch-target) + var(--padding-sm)); + } + + .dialog-zoomed-gallery .shopify-model-viewer-ui__controls-area.shopify-model-viewer-ui__controls-area { + /* Move the controls up to match the padding on the thumbnails */ + bottom: var(--padding-lg); + + /* Move the controls to the left of the thumbnails list on the right */ + right: calc(var(--thumbnail-width) + var(--padding-lg) * 2); + } +} + +:is(deferred-media, .video-placeholder-wrapper).border-style { + /* Apply the border radius to the video */ + overflow: hidden; +} + +deferred-media { + /* The overflow hidden in the deferred-media won't let the button show the focus ring */ + &:has(:focus-visible) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + @supports not selector(:focus-visible) { + &:has(:focus) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + } +} + +.deferred-media__poster-button { + width: 100%; + height: 100%; + aspect-ratio: var(--video-aspect-ratio, auto); +} + +.deferred-media__poster-button.deferred-media__playing { + opacity: 0; + transition: opacity 0.3s ease; +} + +deferred-media img { + height: 100%; + object-fit: cover; + transition: opacity 0.3s ease; +} + +deferred-media iframe { + width: 100%; + height: 100%; + border: none; + aspect-ratio: var(--size-style-aspect-ratio, auto); +} + +deferred-media[data-media-loaded] img { + opacity: 0; +} + +.deferred-media__poster-icon, +.video-placeholder-wrapper__poster-icon { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +.deferred-media__poster-icon svg, +.video-placeholder-wrapper__poster-icon svg { + width: var(--button-size); + height: var(--button-size); + color: var(--color-white); + filter: drop-shadow(var(--shadow-button)); + + &:hover { + color: rgb(var(--color-white-rgb) / var(--opacity-80)); + } + + @media screen and (min-width: 750px) { + width: 4rem; + height: 4rem; + } +} + +deferred-media[class] :is(.deferred-media__poster-button img, .deferred-media__poster-button ~ video) { + /* only apply this on the video block not product media */ + object-fit: cover; + height: 100%; + aspect-ratio: var(--size-style-aspect-ratio, auto); +} + +.button-shopify-xr { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + padding: var(--padding-md); +} + +.button-shopify-xr > svg { + width: var(--icon-size-sm); + height: var(--icon-size-sm); + fill: currentcolor; + margin-inline-end: var(--margin-md); +} + +.button-shopify-xr[data-shopify-xr-hidden] { + display: none; +} + +/* Swatches */ +.swatch { + --color-border: rgb(var(--color-foreground-rgb) / var(--style-border-swatch-opacity)); + --min-width-unitless: 15.9999; /* want to avoid division by 0 */ + --min-height-unitless: 15.9999; /* want to avoid division by 0 */ + --min-height: 16px; + --min-width: 16px; + + /* mobile values */ + --scaling-factor: 0.5; + --max-swatch-size: 28px; + --max-pill-size: 20px; + --max-filter-size: 32px; + + /* From the settings */ + --offset-swatch-width: calc(var(--variant-picker-swatch-width-unitless) - var(--min-width-unitless)); + --offset-swatch-height: calc(var(--variant-picker-swatch-height-unitless) - var(--min-height-unitless)); + + /** + Offset values are obtained from the following formulas: + offset-width = width - min-width + offset-height = height - min-height + + The offset-scaled-width and heigth are obtained by extending the line from + [min,min] to [W,H] and taking the intersection with a square that starts at + [min,min] and ends at [max,max]. + + The extending line forms right angle triangles with the [min,min]->[max,max] + box that enable us to derive the following formulas + + We also want the result to always be smaller than the input (pdp > everywhere else) + by some scaling factor. + */ + --offset-scaled-width: calc( + var(--scaling-factor) * var(--offset-swatch-width) / var(--offset-swatch-height) * var(--offset-max-swatch-size) + ); + --offset-scaled-height: calc( + var(--scaling-factor) * var(--offset-swatch-height) / var(--offset-swatch-width) * var(--offset-max-swatch-size) + ); + --offset-max-swatch-size: calc(var(--max-swatch-size) - var(--min-width)); + + /* width = min(m + sU, (m + s * W'/H' * M'), M) */ + --swatch-width: min( + calc(var(--min-width) + calc(var(--scaling-factor) * var(--offset-swatch-width) * 1px)), + calc(var(--min-width) + var(--offset-scaled-width)), + var(--max-swatch-size) + ); + + /* height = min(m + sV, (m + s * H'/W' * M'), M) */ + --swatch-height: min( + calc(var(--min-height) + calc(var(--scaling-factor) * var(--offset-swatch-height) * 1px)), + calc(var(--min-height) + var(--offset-scaled-height)), + var(--max-swatch-size) + ); + + display: block; + background: var(--swatch-background); + background-position: var(--swatch-focal-point, center); + border-radius: var(--variant-picker-swatch-radius); + border: var(--style-border-swatch-width) var(--style-border-swatch-style) var(--color-border); + width: var(--swatch-width); + height: var(--swatch-height); + + /* This is different than `background-size: cover` because we use `box-sizing: border-box`, + * doing it like makes the background clip under the border without repeating. + */ + background-size: var(--swatch-width) var(--swatch-height); + + &.swatch--unavailable { + border-style: dashed; + } + + &.swatch--unscaled { + /* for when you want fixed sizing (e.g. pdp) */ + --swatch-width: var(--variant-picker-swatch-width); + --swatch-height: var(--variant-picker-swatch-height); + } + + &.swatch--filter { + --swatch-width: var(--max-filter-size); + --swatch-height: var(--max-filter-size); + + border-radius: var(--variant-picker-swatch-radius); + } + + &.swatch--pill { + --swatch-width: var(--max-pill-size); + --swatch-height: var(--max-pill-size); + + border-radius: var(--variant-picker-swatch-radius); + } + + /* swatches in filters and pills always have a border */ + &.swatch--filter, + &.swatch--pill { + --style-border-swatch-width: var(--variant-picker-border-width); + --style-border-swatch-style: var(--variant-picker-border-style); + --color-border: rgb(var(--color-foreground-rgb) / var(--variant-picker-border-opacity)); + } + + @media screen and (min-width: 750px) { + /* desktop values */ + --max-swatch-size: 32px; + --max-pill-size: 16px; + --max-filter-size: 28px; + --scaling-factor: 0.65; + } +} + +.variant-picker .variant-option--buttons label:has(.swatch) { + border-radius: var(--variant-picker-swatch-radius); +} + +.sticky-content { + position: sticky; + top: var(--sticky-header-offset, 0); + z-index: var(--layer-flat); +} + +@media screen and (min-width: 750px) { + .sticky-content--desktop, + .sticky-content--desktop.full-height--desktop > .group-block { + position: sticky; + top: var(--sticky-header-offset, 0); + z-index: var(--layer-flat); + } +} + +.price, +.compare-at-price, +.unit-price { + white-space: nowrap; +} + +.unit-price { + display: block; + font-size: 0.85em; + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); +} + +.compare-at-price { + opacity: 0.4; + text-decoration-line: line-through; + text-decoration-thickness: 1.5px; +} + +.tax-note, +.unit-price { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); +} + +.card-gallery { + position: relative; +} + +@media screen and (min-width: 750px) { + product-card:focus-within .quick-add__button, + .card-gallery:hover .quick-add__button { + display: grid; + will-change: margin, opacity; + animation: elementSlideInTop var(--animation-speed) var(--animation-easing); + } +} + +@container (max-width: 70px) { + .card-gallery:hover .quick-add__button { + display: none; + } +} + +/* Drawer */ +.drawer { + background-color: var(--color-background); + position: fixed; + top: 0; + left: 0; + bottom: 0; + width: var(--sidebar-width); + z-index: var(--layer-raised); + transform: translateX(-120%); + transition: transform var(--animation-speed) var(--animation-easing); +} + +.drawer[data-open='true'] { + transform: translateX(0); +} + +.drawer-toggle { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; +} + +.drawer__header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--drawer-header-block-padding) var(--drawer-inline-padding); +} + +.drawer__title { + font-size: var(--font-h2--size); + margin: 0; +} + +.drawer__close { + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); +} + +.drawer__content { + display: block; + padding: var(--drawer-content-block-padding) var(--drawer-inline-padding); + width: 100%; +} + +/* Background overlay */ +.background-overlay { + position: relative; + + &::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: var(--background-overlay-color, rgb(0 0 0 / 15%)); + } +} + +/* Spacing style */ +.spacing-style { + --spacing-scale: var(--spacing-scale-md); + + @media screen and (min-width: 990px) { + --spacing-scale: var(--spacing-scale-default); + } + + /* Must disable this, when you use these with calc and another unit type, things break — see logo.liquid */ + /* stylelint-disable length-zero-no-unit */ + --padding-block: 0px; + --padding-block-start: var(--padding-block, 0px); + --padding-block-end: var(--padding-block, 0px); + --padding-inline: 0px; + --padding-inline-start: var(--padding-inline, 0px); + --padding-inline-end: var(--padding-inline, 0px); + --margin-block: 0px; + --margin-block-start: var(--margin-block, 0px); + --margin-block-end: var(--margin-block, 0px); + --margin-inline: 0px; + --margin-inline-start: var(--margin-inline, 0px); + --margin-inline-end: var(--margin-inline, 0px); +} + +.spacing-style, +.inherit-spacing { + padding-block: calc(var(--padding-block-start) + var(--section-top-offset, 0px)) var(--padding-block-end); + padding-inline: var(--padding-inline-start) var(--padding-inline-end); + margin-block: var(--margin-block-start) var(--margin-block-end); + margin-inline: var(--margin-inline-start) var(--margin-inline-end); +} + +/* Size style */ +.size-style { + width: var(--size-style-width-mobile, var(--size-style-width)); + height: var(--size-style-height-mobile, var(--size-style-height)); + + @media screen and (min-width: 750px) { + width: var(--size-style-width); + height: var(--size-style-height); + } +} + +/* Custom Typography style */ +.custom-typography, +.custom-typography > * { + font-family: var(--font-family); + font-weight: var(--font-weight); + text-transform: var(--text-transform); + text-wrap: var(--text-wrap); + line-height: var(--line-height); + letter-spacing: var(--letter-spacing); +} + +.custom-typography { + h1 { + line-height: var(--line-height--display, var(--line-height)); + } + + h2, + h3, + h4 { + line-height: var(--line-height--heading, var(--line-height)); + } + + p { + line-height: var(--line-height--body, var(--line-height)); + } +} + +.custom-font-size, +.custom-font-size > * { + font-size: var(--font-size); +} + +.custom-font-weight, +.custom-font-weight > * { + font-weight: var(--weight); +} + +/* Border override style */ +.border-style { + border-width: var(--border-width); + border-style: var(--border-style); + border-color: var(--border-color); + border-radius: var(--border-radius); +} + +/* Gap scaling style */ +.gap-style, +.layout-panel-flex { + --gap-scale: var(--spacing-scale-md); + + @media screen and (min-width: 990px) { + --gap-scale: var(--spacing-scale-default); + } +} + +.layout-panel-flex { + display: flex; + gap: var(--gap); + height: 100%; +} + +.layout-panel-flex--row { + flex-flow: row var(--flex-wrap); + justify-content: var(--horizontal-alignment); + align-items: var(--vertical-alignment); +} + +.layout-panel-flex--column { + flex-flow: column var(--flex-wrap); + align-items: var(--horizontal-alignment); + justify-content: var(--vertical-alignment); +} + +@media screen and (max-width: 749px) { + .mobile-column { + flex-flow: column nowrap; + align-items: var(--horizontal-alignment); + justify-content: var(--vertical-alignment-mobile); + } + + .layout-panel-flex--row:not(.mobile-column) { + .text-block { + flex: 1 1 var(--max-width--display-tight); + } + + .image-block { + flex: 1 1 var(--size-style-width-mobile-min); + } + + .button { + flex: 0 0 fit-content; + } + } +} + +@media (min-width: 750px) { + .layout-panel-flex { + flex-direction: var(--flex-direction); + } +} + +/* Form fields */ +.field { + position: relative; + width: 100%; + display: flex; + transition: box-shadow var(--animation-speed) ease; +} + +.field__input { + flex-grow: 1; + text-align: left; + border-radius: var(--style-border-radius-inputs); + transition: box-shadow var(--animation-speed) ease, background-color var(--animation-speed) ease; + padding: var(--input-padding); + box-shadow: var(--input-box-shadow); + background-color: var(--color-input-background); + color: var(--color-input-text); + border: none; + outline: none; + + &:autofill { + background-color: var(--color-input-background); + color: var(--color-input-text); + } +} + +.field__input:is(:focus, :hover) { + box-shadow: var(--input-box-shadow-focus); + background-color: var(--color-input-hover-background); +} + +.field__input--button-radius { + border-radius: var(--style-border-radius-buttons-primary); +} + +.field__input--button-padding { + padding-inline: var(--padding-3xl); +} + +.field__label { + color: rgb(var(--color-input-text-rgb) / var(--opacity-80)); + font-size: var(--font-paragraph--size); + left: var(--input-padding-x); + top: 50%; + transform: translateY(-50%); + margin-bottom: 0; + pointer-events: none; + position: absolute; + transition: top var(--animation-speed) ease, font-size var(--animation-speed) ease; +} + +/* RTE styles */ +.rte, +.shopify-policy__title { + :is(h1, h2, h3, h4, h5, h6) { + margin-block: clamp(1.5rem, 1em * 3.3, 2.5rem) clamp(1rem, 1em * 0.25, 2rem); + } + + :first-child:is(p, h1, h2, h3, h4, h5, h6), + :first-child:empty + :is(p, h1, h2, h3, h4, h5, h6) { + margin-block-start: 0; + } + + ul, + ol { + margin-block-start: 0; + padding-inline-start: 1.5em; + } + + /* Only apply margin-block-end to the higher level list, not nested lists */ + :is(ul, ol):not(:is(ul, ol) :is(ul, ol)) { + margin-block-end: 1em; + } + + blockquote { + margin-inline: 1.5em 2.3em; + margin-block: 3.8em; + padding-inline-start: 0.8em; + border-inline-start: 1.5px solid rgb(var(--color-foreground-rgb) / var(--opacity-25)); + font-style: italic; + font-weight: 500; + } + + .rte-table-wrapper { + overflow-x: auto; + } + + table { + /* stylelint-disable-next-line declaration-no-important */ + width: 100% !important; + border-collapse: collapse; + } + + tr:not(:has(td)), + thead { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + font-weight: bold; + text-transform: uppercase; + } + + tr:has(td) { + border-bottom: 1px solid rgb(var(--color-foreground-rgb) / var(--opacity-10)); + } + + th, + td { + text-align: start; + padding-inline: var(--padding-md); + padding-block: var(--padding-sm); + } +} + +.shopify-policy__container { + padding-block: var(--padding-xl); +} + +.checkbox { + --checkbox-size: 22px; + --checkbox-top: 50%; + --checkbox-left: 1.5px; + --checkbox-offset: 3px; + --checkbox-border-radius: 7px; + --checkbox-label-padding: 8px; + --checkbox-path-opacity: 0; + --checkbox-cursor: pointer; + --checkbox-border: 1px solid rgb(var(--color-foreground-rgb) / var(--opacity-35-55)); + + position: relative; + display: flex; + align-items: center; + + @media screen and (min-width: 750px) { + --checkbox-size: 16px; + --checkbox-border-radius: 5px; + --checkbox-label-padding: 6px; + } + + &:has(.checkbox__input:checked) { + --checkbox-path-opacity: 1; + } + + &:has(.checkbox__input:disabled) { + --checkbox-cursor: not-allowed; + } +} + +.checkbox__input { + position: absolute; + opacity: 0; + margin: 0; + width: var(--checkbox-size); + height: var(--checkbox-size); + + /* Outline is on the SVG instead, to allow it to have border-radius */ + &:focus-visible { + outline: none; + } + + &:focus-visible + .checkbox__label .icon-checkmark { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + &:checked + .checkbox__label .icon-checkmark { + background-color: var(--color-foreground); + border-color: var(--color-foreground); + } + + &:disabled + .checkbox__label .icon-checkmark { + background-color: var(--input-disabled-background-color); + border-color: var(--input-disabled-border-color); + } +} + +.checkbox__label { + position: relative; + display: inline-flex; + cursor: var(--checkbox-cursor); + line-height: var(--checkbox-size); + min-width: var(--minimum-touch-target); +} + +.checkbox .icon-checkmark { + height: var(--checkbox-size); + width: var(--checkbox-size); + flex-shrink: 0; + border: var(--checkbox-border); + border-radius: var(--checkbox-border-radius); + background-color: var(--color-background); +} + +.checkbox__label-text { + padding-inline-start: var(--checkbox-label-padding); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.checkbox .icon-checkmark path { + stroke: var(--color-background); + opacity: var(--checkbox-path-opacity); + transition: opacity var(--animation-speed) var(--animation-easing); +} + +.checkbox__input:disabled + .checkbox__label { + color: var(--input-disabled-text-color); +} + +/* Add to cart button */ +.button[id^='BuyButtons-ProductSubmitButton-'] { + position: relative; + overflow: hidden; +} + +/* Cart bubble */ +.cart-bubble { + --cart-padding: 0.2em; + + position: relative; + width: 20px; + aspect-ratio: 1; + border-radius: 50%; + border-width: 0; + display: grid; + line-height: normal; + place-content: center; + color: var(--color-primary-button-text); + padding-inline: var(--cart-padding); +} + +.cart-bubble__background { + position: absolute; + inset: 0; + background-color: var(--color-primary-button-background); + border-radius: var(--style-border-radius-lg); +} + +.cart-bubble__text { + font-size: var(--font-size--2xs); + z-index: var(--layer-flat); + line-height: 1; + display: flex; + align-items: center; + justify-content: center; +} + +/* Quantity selector */ +.quantity-selector { + --quantity-selector-width: 124px; + + display: flex; + justify-content: space-between; + align-items: center; + color: var(--color-input-text); + background-color: var(--color-input-background); + border: var(--style-border-width-inputs) solid var(--color-input-border); + border-radius: var(--style-border-radius-inputs); + flex: 1 1 var(--quantity-selector-width); + align-self: stretch; + transition: background-color var(--animation-speed) var(--animation-easing); + + &:hover { + background-color: var(--color-input-hover-background); + } +} + +.product-form-buttons:has(.add-to-cart-button.button-secondary) .quantity-selector { + border-radius: var(--style-border-radius-buttons-secondary); +} + +.quantity-selector :is(.quantity-minus, .quantity-plus) { + /* Unset button styles */ + padding: 0; + background: transparent; + box-shadow: none; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + flex-shrink: 0; + color: var(--color-input-text); +} + +.quantity-selector .quantity-minus { + border-start-start-radius: var(--style-border-radius-inputs); + border-end-start-radius: var(--style-border-radius-inputs); +} + +.quantity-selector .quantity-plus { + border-start-end-radius: var(--style-border-radius-inputs); + border-end-end-radius: var(--style-border-radius-inputs); +} + +.product-details .quantity-selector { + border-radius: var(--style-border-radius-buttons-primary); +} + +.product-details .quantity-selector .quantity-minus { + border-start-start-radius: var(--style-border-radius-buttons-primary); + border-end-start-radius: var(--style-border-radius-buttons-primary); +} + +.product-details .quantity-selector .quantity-plus { + border-start-end-radius: var(--style-border-radius-buttons-primary); + border-end-end-radius: var(--style-border-radius-buttons-primary); +} + +.quantity-selector .svg-wrapper { + transition: transform var(--animation-speed) var(--animation-easing); +} + +.quantity-selector svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); +} + +:is(.quantity-minus, .quantity-plus):active .svg-wrapper { + transform: scale(0.9); +} + +.quantity-selector input[type='number'] { + margin: 0; + text-align: center; + border: none; + appearance: none; + max-width: calc(var(--quantity-selector-width) - var(--minimum-touch-target) * 2); + border-radius: var(--style-border-radius-buttons); + color: var(--color-input-text); + background-color: transparent; +} + +/* Chrome, Safari, Edge, Opera */ +.quantity-selector input[type='number']::-webkit-inner-spin-button, +.quantity-selector input[type='number']::-webkit-outer-spin-button { + appearance: none; +} + +/* Firefox */ +.quantity-selector input[type='number'] { + appearance: textfield; +} + +/* Pills (used in facets and predictive search) */ + +.pills__pill { + --pills-pill-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5-15)); + + color: var(--color-foreground); + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--gap-sm); + min-width: 48px; + padding: 6px 12px; + border-radius: var(--style-border-radius-pills); + cursor: pointer; + background-color: var(--pills-pill-background-color); + transition: background-color var(--animation-speed) var(--animation-easing); + + &:hover { + --pills-pill-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10-25)); + } + + @media screen and (max-width: 749px) { + padding: var(--padding-xs) var(--padding-md); + } +} + +.pills__pill > .svg-wrapper { + --close-icon-opacity: 0.4; + --icon-stroke-width: 1px; + + color: var(--color-foreground); +} + +.pills__pill--swatch { + @media screen and (max-width: 749px) { + padding-inline-start: var(--padding-sm); + } +} + +.pills__pill--swatch .swatch { + margin-right: -4px; +} + +.pills__pill--desktop-small { + @media screen and (min-width: 750px) { + font-size: var(--font-size--xs); + } +} + +/* Fly to cart animation */ +fly-to-cart { + position: fixed; + width: 40px; + height: 40px; + left: 0; + top: 0; + border-radius: 50%; + z-index: calc(infinity); + pointer-events: none; + opacity: 0; + overflow: hidden; + box-shadow: 0 4px 8px rgb(0 0 0 / 20%); + transition: opacity 0.3s ease; + background-position: center center; + background-size: cover; + background-repeat: no-repeat; + background-color: var(--color-foreground); + transform: translate(var(--x, 0), var(--y, 0)) scale(var(--scale, 1)); +} + +/* ------------------------------------------------------------------------------ */ + +/* ------------------------------------------------------------------------------ */ + +/* ------------------------------------------------------------------------------ */ + +/* Animation declarations - to be kept at the bottom of the file for ease of find */ +@keyframes grow { + 0% { + transform: scale(1); + } + + 50% { + transform: scale(1.2); + } + + 100% { + transform: scale(1); + } +} + +@keyframes slideInLeft { + from { + transform: translateX(var(--custom-transform-from, 100%)); + } + + to { + transform: translateX(var(--custom-transform-to, 0)); + } +} + +@keyframes slideInLeftViewTransition { + from { + transform: translateX(100px); + } +} + +@keyframes slideOutRight { + from { + transform: translateX(0); + } + + to { + transform: translateX(var(--custom-transform-to, -100%)); + } +} + +@keyframes slideInRight { + from { + transform: translateX(-100%); + } + + to { + transform: translateX(0); + } +} + +@keyframes slideOutLeft { + from { + transform: translateX(0); + } + + to { + transform: translateX(100%); + } +} + +@keyframes slideInTop { + from { + transform: translateY(100%); + } + + to { + transform: translateY(0); + } +} + +@keyframes slideInTopViewTransition { + from { + transform: translateY(100px); + } +} + +@keyframes slideOutBottom { + from { + transform: translateY(0); + } + + to { + transform: translateY(100%); + } +} + +@keyframes slideInBottom { + from { + transform: translateY(-100%); + } + + to { + transform: translateY(0); + } +} + +@keyframes slideOutTop { + from { + transform: translateY(0); + } + + to { + transform: translateY(-100%); + } +} + +@keyframes cartBubbleSlideIn { + from { + transform: translateY(-1em); + } + + to { + transform: translateY(0); + } +} + +@keyframes elementSlideInTop { + from { + margin-top: var(--padding-sm); + opacity: 0; + } + + to { + margin-top: 0; + opacity: 1; + } +} + +@keyframes elementSlideOutTop { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(var(--padding-sm)); + opacity: 0; + } +} + +@keyframes elementSlideInBottom { + from { + transform: translateY(calc(-1 * var(--padding-sm))); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes elementSlideOutBottom { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(calc(-1 * var(--padding-sm))); + opacity: 0; + } +} + +@keyframes thumbnailsSlideInTop { + from { + transform: translateY(calc(-50% + var(--margin-lg))); + opacity: 0; + } + + to { + transform: translateY(-50%); + opacity: 1; + } +} + +@keyframes thumbnailsSlideOutTop { + from { + transform: translateY(-50%); + opacity: 1; + } + + to { + transform: translateY(calc(-50% + var(--margin-lg))); + opacity: 0; + } +} + +@keyframes thumbnailsSlideInBottom { + from { + transform: translateY(100%); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes thumbnailsSlideOutBottom { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(100%); + opacity: 0; + } +} + +@keyframes search-element-slide-in-bottom { + 0% { + transform: translateY(20px); + opacity: 0; + } + + 100% { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes search-element-slide-out-bottom { + 0% { + transform: translateY(0); + opacity: 1; + } + + 100% { + transform: translateY(20px); + opacity: 0; + } +} + +@keyframes dialogZoom { + from { + opacity: 1; + transform: scale(1) translateY(0); + } + + to { + opacity: 0; + transform: scale(0.95) translateY(1em); + } +} + +@keyframes thumbnail-selected { + 0%, + 100% { + box-shadow: 0 0 0 2px transparent; + scale: 0.9; + } + + 50% { + box-shadow: 0 0 0 2px black; + scale: 1; + } +} + +@keyframes backdropFilter { + from { + backdrop-filter: brightness(1); + } + + to { + backdrop-filter: brightness(0.75); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes modalSlideInTop { + from { + transform: translateY(var(--padding-sm)); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes modalSlideOutTop { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(var(--padding-sm)); + opacity: 0; + } +} + +.bubble { + display: inline-flex; + height: calc(var(--variant-picker-swatch-height) / 1.5); + font-size: var(--font-size--xs); + border-radius: 20px; + min-width: 20px; + padding: 0 6px; + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10-25)); + color: var(--color-foreground); + align-items: center; + justify-content: center; +} + +.bubble svg { + width: 12px; + height: 12px; +} + +.top-shadow::before { + content: ''; + box-shadow: 0 0 10px var(--color-shadow); + position: absolute; + z-index: var(--layer-lowest); + inset: 0; + clip-path: inset(-50px 0 0 0); /* stylelint-disable-line */ +} + +@media (min-width: 750px) { + .top-shadow--mobile::before { + display: none; + } +} + +.bottom-shadow::before { + content: ''; + box-shadow: 0 0 10px var(--color-shadow); + position: absolute; + z-index: var(--layer-lowest); + inset: 0; + clip-path: inset(0 0 -50px 0); /* stylelint-disable-line */ +} + +@media (min-width: 750px) { + .bottom-shadow--mobile::before { + display: none; + } +} + +.video-placeholder-wrapper { + position: relative; + width: 100%; + height: 100%; + aspect-ratio: var(--size-style-aspect-ratio, auto); +} + +:not(deferred-media) > .video-placeholder-wrapper { + width: var(--video-placeholder-width); +} + +.video-placeholder-wrapper > * { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; +} + +/* + * Slideshow Component + */ +slideshow-component { + --cursor: grab; + + position: relative; + display: flex; + flex-direction: column; + timeline-scope: var(--slideshow-timeline); +} + +.slideshow--single-media { + --cursor: default; +} + +a slideshow-component { + --cursor: pointer; +} + +/* + * Slideshow Slides + */ +slideshow-slides { + width: 100%; + position: relative; + display: flex; + overflow-x: scroll; + scroll-snap-type: x mandatory; + scroll-behavior: smooth; + scrollbar-color: transparent transparent; + scrollbar-width: none; + gap: var(--slideshow-gap, 0); + cursor: var(--cursor); + + @media (prefers-reduced-motion) { + scroll-behavior: auto; + } + + &::-webkit-scrollbar { + width: 0; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + border: none; + } + + &[size='small'] { + min-height: 17.5rem; + } + + &[size='medium'] { + min-height: 21.25rem; + } + + &[size='large'] { + min-height: 25rem; + } + + @media screen and (min-width: 750px) { + &[size='small'] { + min-height: 26.25rem; + } + + &[size='medium'] { + min-height: 35rem; + } + + &[size='large'] { + min-height: 45rem; + } + } +} + +slideshow-component[disabled='true'] slideshow-slides { + overflow: hidden; +} + +slideshow-component[mobile-disabled] slideshow-slides { + @media screen and (max-width: 749px) { + overflow: hidden; + } +} + +slideshow-slide { + position: relative; + scroll-snap-align: start; + width: var(--slide-width, 100%); + max-height: 100%; + flex-shrink: 0; + view-timeline-axis: inline; + content-visibility: auto; + contain-intrinsic-size: auto none; + + slideshow-component[actioned] &, + &[aria-hidden='false'] { + content-visibility: visible; + } + + slideshow-component slideshow-slide:not([aria-hidden='false']) { + content-visibility: hidden; + } + + &[hidden]:not([reveal]) { + display: none; + } +} + +@media screen and (max-width: 749px) { + /* Media gallery has a peeking slide on the right side always, and on the left side when the current slide is the last one */ + .media-gallery--hint + :is( + slideshow-slide:has(+ slideshow-slide[aria-hidden='false']:last-of-type), + slideshow-slide[aria-hidden='false'] + slideshow-slide + ) { + content-visibility: auto; + + slideshow-component[actioned] & { + content-visibility: visible; + } + } +} + +/* + * Collection and Resource list carousels have peeking slides on both sides. + * Card galleries preview the next or previous images on 'pointerenter', so we + * try to kick load them beforehand (they are lazy loaded otherwise). + */ +:is(.resource-list__carousel, .card-gallery) + :is( + slideshow-slide:has(+ slideshow-slide[aria-hidden='false']), + slideshow-slide[aria-hidden='false'] + slideshow-slide + ) { + content-visibility: auto; + + slideshow-component[actioned] & { + content-visibility: visible; + } +} + +/* + * Be specific about HTML children structure to avoid targeting nested slideshows. + * Ensure that the content is 'visible' while scrolling instead of 'auto' to avoid issues in Safari. + */ +slideshow-component:is([dragging], [transitioning], :hover) > slideshow-container > slideshow-slides > slideshow-slide { + content-visibility: visible; +} + +slideshow-slides[gutters*='start'] { + padding-inline-start: var(--gutter-slide-width, 0); + scroll-padding-inline-start: var(--gutter-slide-width, 0); +} + +slideshow-slides[gutters*='end'] { + padding-inline-end: var(--gutter-slide-width, 0); +} + +slideshow-component[dragging] { + --cursor: grabbing; + + * { + pointer-events: none; + } +} + +slideshow-component[dragging] slideshow-arrows { + display: none; +} + +slideshow-container { + width: 100%; + display: block; + position: relative; + grid-area: container; + container-type: inline-size; +} + +/* + * Slideshow Controls + */ +slideshow-controls { + flex-shrink: 0; + display: flex; + justify-content: space-between; + scrollbar-width: none; + min-height: var(--minimum-touch-target); + grid-area: controls; + + &[controls-on-media] { + position: absolute; + bottom: 0; + } +} + +slideshow-controls::-webkit-scrollbar { + display: none; +} + +slideshow-controls button { + --color: rgb(var(--color-foreground-rgb) / var(--opacity-30)); + --color-active: var(--color-foreground); + --color-hover: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + + display: inline-block; + height: var(--minimum-touch-target); + width: var(--minimum-touch-target); + cursor: pointer; +} + +slideshow-controls .icon { + width: var(--icon-size-sm); + height: var(--icon-size-xs); +} + +slideshow-controls[pagination-position='center'] { + align-items: center; + justify-content: center; +} + +slideshow-controls[pagination-position='center'][thumbnails] { + width: 100%; +} + +slideshow-controls[pagination-position='center']:not([controls-on-media], [thumbnails], [icons-on-media]) { + justify-content: space-between; +} + +slideshow-component:has(slideshow-controls[thumbnails]) { + &:has(slideshow-controls[pagination-position='right']) { + display: grid; + grid-template: + 'container controls' auto + 'arrows controls' min-content + / 1fr auto; + } + + &:has(slideshow-controls[pagination-position='left']) { + display: grid; + grid-template: + 'controls container' auto + 'controls arrows' min-content + / auto 1fr; + } + + slideshow-controls[pagination-position='left'] { + order: -1; + } +} + +slideshow-controls[thumbnails]:is([pagination-position='right'], [pagination-position='left']) { + display: flex; + flex-direction: column; + height: 0; + min-height: 100%; + + .slideshow-controls__thumbnails-container { + overflow: hidden auto; + } + + &:not([controls-on-media]) { + .slideshow-controls__thumbnails-container { + position: sticky; + top: var(--sticky-header-offset, 0); + } + + .slideshow-controls__thumbnails { + padding-block-start: var(--focus-outline-offset); + } + } +} + +slideshow-controls:not([controls-on-media])[icons-on-media] { + &[pagination-position='right'] { + justify-content: flex-end; + } + + &[pagination-position='left'] { + justify-content: flex-start; + } +} + +slideshow-controls:not([controls-on-media]):is([pagination-position='left'], [pagination-position='right']) + .slideshow-controls__thumbnails { + padding-block: var(--padding-2xs); +} + +slideshow-controls:not([controls-on-media]) { + &:is([pagination-position='right']) { + .slideshow-controls__thumbnails { + padding-inline-end: var(--slideshow-thumbnails-padding-inline, var(--focus-outline-offset)); + } + } + + &:is([pagination-position='left']) { + .slideshow-controls__thumbnails { + padding-inline-start: var(--slideshow-thumbnails-padding-inline, var(--focus-outline-offset)); + } + } +} + +slideshow-controls[controls-on-media] { + z-index: var(--layer-raised); + + &:has(.slideshow-controls__dots, .slideshow-controls__counter) { + --color-foreground: #fff; + --color-foreground-rgb: var(--color-white-rgb); + } + + &[pagination-position='right'] { + right: 0; + } + + &[pagination-position='left'] { + left: 0; + } + + &[pagination-position='center'] { + width: 100%; + } + + &:not([thumbnails])[pagination-position='left'] { + width: fit-content; + align-self: flex-start; + } + + &:not([thumbnails])[pagination-position='right'] { + width: fit-content; + align-self: flex-end; + } +} + +slideshow-controls:is([pagination-position='right'], [pagination-position='left']) { + .slideshow-controls__thumbnails { + flex-direction: column; + } +} + +.slideshow-controls__arrows { + display: flex; + justify-content: space-between; + height: var(--minimum-touch-target); + grid-area: arrows; + + button { + padding: 0 var(--padding-xs); + } +} + +.slideshow-controls__dots, +.slideshow-controls__counter { + display: inline-flex; + justify-content: center; + align-items: center; + margin: 0; + list-style: none; + + button { + --color: rgb(var(--color-foreground-rgb) / var(--opacity-30)); + --color-active: var(--color-foreground); + --color-hover: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + } +} + +slideshow-controls:has(.slideshow-controls__dots), +slideshow-component[autoplay] slideshow-controls { + mix-blend-mode: difference; +} + +.slideshow-controls__dots { + gap: 0.6rem; + padding: var(--padding-sm) var(--padding-lg); + border-radius: 3rem; + overflow: hidden; + + button { + --size: 0.5rem; + + display: flex; + align-items: center; + justify-content: center; + width: calc(var(--size) * 2); + height: calc(var(--size) * 2); + margin: calc(var(--size) / -2); + font-size: 0; + border-radius: calc(var(--size)); + + &::after { + content: ''; + display: block; + background-color: var(--color); + height: var(--size); + width: var(--size); + + /* This is at --size / 2 to remove a visual regression on subpixel rendering displays */ + border-radius: calc(var(--size) / 2); + + @supports not (view-timeline-axis: inline) { + &[aria-selected='true'] { + --color: var(--color-active); + } + } + + &:hover { + --color: var(--color-hover); + } + } + + &[aria-selected='true'] { + --color: var(--color-active); + } + } +} + +.slideshow-controls__dots, +.slideshow-controls__counter { + &:only-child { + margin-inline: auto; + } +} + +.slideshow-controls__counter { + color: var(--color-foreground); + background-color: rgb(0 0 0 / 40%); + width: auto; + border-radius: 2rem; + padding: 0.3rem var(--padding-sm); + margin-inline: var(--margin-sm); + backdrop-filter: blur(10px); + font-variant-numeric: tabular-nums; + font-size: var(--font-size--xs); + + .slash { + color: rgb(var(--color-foreground-rgb) / var(--opacity-40)); + padding-inline: var(--padding-2xs); + margin-block-start: -0.1rem; + } +} + +.slideshow-control[disabled] { + opacity: 0.5; + cursor: not-allowed; +} + +.slideshow-control--large { + .icon-caret { + --icon-stroke-width: 1px; + } + + .icon-caret { + --icon-stroke-width: 1px; + } + + .svg-wrapper, + svg { + width: var(--slideshow-controls-icon); + height: var(--slideshow-controls-icon); + } +} + +/* Slideshow control shape styles */ +.button-unstyled.slideshow-control.slideshow-control--shape-square, +.button-unstyled.slideshow-control.slideshow-control--shape-circle { + display: flex; + align-items: center; + justify-content: center; + aspect-ratio: 1 / 1; + background-color: var(--color-primary-button-background); + color: var(--color-primary-button-text); +} + +.button-unstyled.slideshow-control.slideshow-control--shape-circle { + border-radius: 50%; +} + +.button-unstyled.slideshow-control.slideshow-control--shape-square { + border-radius: 0; +} + +.slideshow-control .icon-caret { + rotate: -90deg; +} + +/* Slideshow Thumbnails */ +.slideshow-controls__thumbnails-container { + display: flex; + width: 100%; + max-height: 100%; + overflow-x: scroll; + scrollbar-width: none; +} + +.slideshow-controls__thumbnails { + display: inline-flex; + padding-inline: var(--slideshow-thumbnails-padding-inline, var(--padding-sm)); + padding-block: var(--slideshow-thumbnails-padding-block, var(--padding-sm)); + gap: var(--gap-xs); + margin-inline: auto; + height: fit-content; + + .slideshow-control { + border-radius: var(--media-radius); + width: clamp(44px, 7vw, var(--thumbnail-width)); + height: auto; + aspect-ratio: var(--aspect-ratio); + + img { + height: 100%; + object-fit: cover; + border-radius: var(--media-radius); + } + + &:is([aria-selected='true']) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: calc(var(--focus-outline-offset) / 2); + border: var(--style-border-width) solid rgb(var(--color-border-rgb) / var(--media-border-opacity)); + } + } +} + +.slideshow-controls__thumbnail { + position: relative; +} + +.slideshow-controls__thumbnail-badge { + position: absolute; + top: var(--padding-2xs); + right: var(--padding-2xs); + width: clamp(16px, 10%, 20px); + height: clamp(16px, 10%, 20px); + background-color: var(--color-background); + border-radius: var(--style-border-radius-xs); + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 0 0 1px rgb(var(--color-foreground-rgb) / var(--opacity-5)); +} + +.slideshow-controls__thumbnail-badge svg { + width: 60%; + height: 60%; + fill: var(--color-foreground); + opacity: 0.6; +} + +/* Slideshow Play/Pause */ +.slideshow-control:is(.icon-pause, .icon-play) { + color: var(--color-active); + + &:hover { + color: var(--color-hover); + } + + svg { + display: none; + } +} + +slideshow-component:is([autoplay]) { + &:is([paused]) { + .icon-play > svg { + display: block; + } + } + + &:not([paused]) { + .icon-pause > svg { + display: block; + } + } +} + +/* Slideshow Arrows */ +slideshow-arrows { + --cursor-previous: w-resize; + --cursor-next: e-resize; + + position: absolute; + inset: 0; + display: flex; + z-index: var(--layer-heightened); + pointer-events: none; + mix-blend-mode: difference; + align-items: flex-end; + + &[position='left'] { + justify-content: flex-start; + padding-inline: var(--padding-xs); + } + + &[position='right'] { + justify-content: flex-end; + padding-inline: var(--padding-xs); + } + + &[position='center'] { + justify-content: space-between; + align-items: center; + } +} + +slideshow-arrows:has(.slideshow-control--shape-square), +slideshow-arrows:has(.slideshow-control--shape-circle) { + mix-blend-mode: normal; +} + +slideshow-component[disabled='true'] slideshow-arrows { + display: none; +} + +slideshow-arrows .slideshow-control { + pointer-events: auto; + opacity: 0; + min-height: var(--minimum-touch-target); + padding: 0 var(--padding-xs); + color: var(--color-white); +} + +slideshow-arrows .slideshow-control.slideshow-control--style-none { + display: none; +} + +.media-gallery--carousel slideshow-arrows .slideshow-control { + padding-inline: 0 var(--padding-md); +} + +.card-gallery slideshow-arrows .slideshow-control { + /* Align icons with quick-add button */ + padding-inline: var(--padding-xl); + + @container (max-width: 249px) { + padding-inline: 0 var(--padding-sm); + } +} + +.media-gallery--carousel slideshow-arrows .slideshow-control { + opacity: 1; +} + +:not(.media-gallery--carousel) + > :is(slideshow-component:hover, slideshow-component:focus-within):not(:has(slideshow-controls:hover)) + > slideshow-container + > slideshow-arrows + .slideshow-control { + animation: arrowsSlideIn var(--animation-speed) var(--animation-easing) forwards; +} + +@keyframes arrowsSlideIn { + from { + transform: translate(var(--padding-sm), 0); + opacity: 0; + } + + to { + opacity: 1; + } +} + +.block-resource-list { + display: flex; + flex-direction: column; + row-gap: var(--gap); + min-width: 0; + min-height: 0; + container-type: inline-size; + container-name: resource-list; +} + +.section-resource-list { + row-gap: var(--gap); +} + +.section-resource-list__content { + display: flex; + flex-direction: column; + align-items: var(--horizontal-alignment); + gap: var(--gap); + width: 100%; +} + +.section-resource-list__content:empty { + display: none; +} + +.section-resource-list__header:is(:empty, :has(.group-block-content:empty)), +.section-resource-list__content:empty { + display: none; +} + +.section-resource-list.section--full-width product-card-link > .group-block { + @media screen and (max-width: 749px) { + padding-inline: max(var(--padding-xs), var(--padding-inline-start)) + max(var(--padding-xs), var(--padding-inline-end)); + } +} + +.resource-list--carousel-mobile { + display: block; + + @media screen and (min-width: 750px) { + display: none; + } +} + +.resource-list { + --resource-list-mobile-gap-max: 9999px; + --resource-list-column-gap: min(var(--resource-list-column-gap-desktop), var(--resource-list-mobile-gap-max)); + --resource-list-row-gap: min(var(--resource-list-row-gap-desktop), var(--resource-list-mobile-gap-max)); + + width: 100%; + + @media screen and (max-width: 749px) { + --resource-list-mobile-gap-max: 12px; + } + + @container resource-list (max-width: 749px) { + --resource-list-mobile-gap-max: 12px; + } +} + +.resource-list--grid { + display: grid; + gap: var(--resource-list-row-gap) var(--resource-list-column-gap); + grid-template-columns: var(--resource-list-columns-mobile); + + @media screen and (min-width: 750px) { + grid-template-columns: var(--resource-list-columns); + } + + @container resource-list (max-width: 449px) { + grid-template-columns: var(--resource-list-columns-mobile); + } + + @container resource-list(min-width: 450px) and (max-width: 749px) { + --resource-list-columns-per-row: 3; + + grid-template-columns: repeat(var(--resource-list-columns-per-row), 1fr); + + /* Avoid orphan in last row when there are 4, 7, or 10 items */ + &:has(.resource-list__item:first-child:nth-last-child(3n + 1)), + /* Clean two full rows when there are 8 items */ + &:has(.resource-list__item:first-child:nth-last-child(8n)) { + --resource-list-columns-per-row: 4; + } + } + + @container resource-list (min-width: 750px) { + grid-template-columns: repeat(var(--resource-list-columns-per-row), 1fr); + + &:has(.resource-list__item:first-child:nth-last-child(n + 9)) { + --resource-list-columns-per-row: 5; + } + + &:has(.resource-list__item:first-child:nth-last-child(n + 7):nth-last-child(-n + 8)) { + --resource-list-columns-per-row: 4; + } + + &:has(.resource-list__item:first-child:nth-last-child(6)) { + --resource-list-columns-per-row: 3; + } + + &:has(.resource-list__item:first-child:nth-last-child(5)) { + --resource-list-columns-per-row: 5; + } + + &:has(.resource-list__item:first-child:nth-last-child(-n + 4)) { + --resource-list-columns-per-row: 4; + } + } + + @container resource-list (min-width: 1200px) { + &:has(.resource-list__item:first-child:nth-last-child(6)) { + --resource-list-columns-per-row: 6; + } + } +} + +.resource-list__item { + height: 100%; + color: var(--color-foreground); + text-decoration: none; +} + +.resource-list__carousel { + --slide-width: 60vw; + + width: 100%; + position: relative; + container-type: inline-size; + container-name: resource-list-carousel; + + .slideshow-control[disabled] { + display: none; + } + + .slideshow-control--next { + margin-inline-start: auto; + } +} + +@container resource-list-carousel (max-width: 749px) { + .resource-list__carousel .resource-list__slide { + --slide-width: clamp(150px, var(--mobile-card-size, 60cqw), var(--slide-width-max)); + } +} + +@container resource-list-carousel (min-width: 750px) { + .resource-list__carousel .resource-list__slide { + --section-slide-width: calc( + (100% - (var(--resource-list-column-gap) * (var(--column-count) - 1)) - var(--peek-next-slide-size)) / + var(--column-count) + ); + --fallback-slide-width: clamp(150px, var(--mobile-card-size, 60cqw), var(--slide-width-max)); + --slide-width: var(--section-slide-width, var(--fallback-slide-width)); + } +} + +.resource-list__carousel slideshow-slides { + gap: var(--resource-list-column-gap); + + /* Add padding to prevent hover animations from being clipped in slideshow + 15px accommodates: + - Scale effect (9px on each side from 1.03 scale) + - Lift effect (4px upward movement) + - Shadow (15px spread with -5px offset) + Using 16px for better alignment with our spacing scale */ + + margin-block: -16px; + padding-block: 16px; +} + +.resource-list__carousel slideshow-arrows { + padding-inline: var(--util-page-margin-offset); +} + +.resource-list__carousel .resource-list__slide { + width: var(--slide-width); + flex: 0 0 auto; + scroll-snap-align: start; + min-width: 0; +} + +/* Base styles */ +.group-block, +.group-block-content { + position: relative; +} + +.group-block:has(> video-background-component), +.group-block:has(> .background-image-container) { + overflow: hidden; +} + +.group-block-content { + height: 100%; + width: 100%; +} + +/* Container styles */ +.section-content-wrapper.section-content-wrapper:where(.layout-panel-flex) .group-block--fill { + flex: 1; +} + +/* Flex behavior for width variants */ +.layout-panel-flex--row > .group-block--width-fit { + flex: 0; +} + +.layout-panel-flex--row > .group-block--width-fill { + flex: 1; +} + +.layout-panel-flex--row > .group-block--width-custom { + flex-basis: var(--size-style-width); +} + +/* Dimension utilities - Height */ +.group-block--height-fit { + height: auto; +} + +.group-block--height-custom, +.group-block--height-fill { + height: var(--size-style-height); +} + +/* Flex behavior for height variants */ +.layout-panel-flex--column > .group-block--height-fit { + flex: 0 1 auto; +} + +.layout-panel-flex--column > .group-block--height-fill { + flex: 1; +} + +.layout-panel-flex--column > .group-block--height-custom { + flex-basis: var(--size-style-height); +} + +.search-input { + width: 100%; + color: var(--color-foreground); + padding-block: var(--padding-lg); + padding-inline: calc(var(--margin-lg) + var(--icon-size-lg)) 0; + background: transparent; + text-overflow: ellipsis; + overflow: hidden; + outline: none; + border: 0; + + &:focus-visible { + outline: none; + } +} + +.search-input:focus { + outline: none; +} + +.search-input::placeholder { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); +} + +accordion-custom { + details { + &::details-content, + .details-content { + block-size: 0; + overflow-y: clip; + opacity: 0; + interpolate-size: allow-keywords; + transition: content-visibility var(--animation-speed-slow) allow-discrete, + padding-block var(--animation-speed-slow) var(--animation-easing), + opacity var(--animation-speed-slow) var(--animation-easing), + block-size var(--animation-speed-slow) var(--animation-easing); + } + + &:not([open]) { + &::details-content, + .details-content { + padding-block: 0; + } + } + + &[open] { + &::details-content, + .details-content { + opacity: 1; + block-size: auto; + + @starting-style { + block-size: 0; + opacity: 0; + overflow-y: clip; + } + + &:focus-within { + overflow-y: visible; + } + } + } + } +} + +accordion-custom[data-disable-on-mobile='true'] summary { + @media screen and (max-width: 749px) { + cursor: auto; + } +} + +accordion-custom[data-disable-on-desktop='true'] summary { + @media screen and (min-width: 750px) { + cursor: auto; + } +} + +text-component { + --shimmer-text-color: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + --shimmer-color-light: rgb(var(--color-foreground-rgb) / var(--opacity-10)); + --shimmer-speed: 1.25s; + + display: inline-block; + position: relative; + transition: color var(--animation-speed-slow) ease; + line-height: 1; + + &::after { + content: attr(value); + position: absolute; + inset: 0; + color: transparent; + opacity: 0; + transition: opacity var(--animation-speed-slow) var(--animation-easing); + pointer-events: none; + background-image: linear-gradient( + -85deg, + var(--shimmer-text-color) 10%, + var(--shimmer-color-light) 50%, + var(--shimmer-text-color) 90% + ); + background-clip: text; + background-size: 200% 100%; + background-position: 100% 0; + place-content: center; + } + + &[shimmer] { + color: transparent; + + &::after { + opacity: 1; + animation: text-shimmer var(--shimmer-speed) infinite linear; + } + } +} + +@keyframes text-shimmer { + 0% { + background-position: 100% 0; + } + + 100% { + background-position: -100% 0; + } +} + +/* Animation transitions */ +.transition-background-color { + transition: background-color var(--animation-speed-medium) ease-in-out; +} + +.transition-transform { + transition: transform var(--animation-speed-medium) var(--animation-timing-bounce); +} + +.transition-border-color { + transition: border-color var(--animation-speed-medium) var(--animation-timing-hover); +} + +/* Global scrollbar styles */ + +/* Webkit browsers */ +::-webkit-scrollbar { + width: 20px; +} + +::-webkit-scrollbar-track { + background-color: transparent; +} + +::-webkit-scrollbar-thumb { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-40)); + border-radius: 20px; + border: 6px solid transparent; + background-clip: content-box; + transition: background-color 0.2s; +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-60)); +} + +@media (prefers-reduced-motion: no-preference) { + html { + scroll-behavior: smooth; + } +} + +/* Product card title truncation - applied only to zoom-out view */ +[product-grid-view='zoom-out'] :is(.product-card, .product-grid__card) :is(h4, .h4) { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 3; +} + +/* Product card title truncation - applied on mobile regardless of view */ +@media screen and (max-width: 749px) { + :is(.product-card, .product-grid__card) :is(h4, .h4) { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 3; + } +} + +.product-card:hover, +.collection-card:hover, +.resource-card:hover, +.predictive-search-results__card--product:hover, +.predictive-search-results__card:hover { + position: relative; + z-index: var(--layer-raised); + transition: transform var(--hover-transition-duration) var(--hover-transition-timing), + box-shadow var(--hover-transition-duration) var(--hover-transition-timing); +} + +.header .product-card:hover, +.header .collection-card:hover, +.header .resource-card:hover, +.header-drawer .product-card:hover, +.header-drawer .collection-card:hover, +.header-drawer .resource-card:hover { + z-index: auto; + transform: none; + box-shadow: none; +} + +/* Prevent iOS zoom on input focus by ensuring minimum 16px font size on mobile */ +@media screen and (max-width: 1200px) { + input, + textarea, + select, + /* Higher specificity to override type preset classes like .paragraph, .h1, etc. */ + .paragraph.paragraph input, + .paragraph.paragraph textarea, + .paragraph.paragraph select, + .h1.h1 input, + .h1.h1 textarea, + .h1.h1 select, + .h2.h2 input, + .h2.h2 textarea, + .h2.h2 select, + .h3.h3 input, + .h3.h3 textarea, + .h3.h3 select, + .h4.h4 input, + .h4.h4 textarea, + .h4.h4 select, + .h5.h5 input, + .h5.h5 textarea, + .h5.h5 select, + .h6.h6 input, + .h6.h6 textarea, + .h6.h6 select { + font-size: max(1rem, 100%); + } +} diff --git a/assets/blog-posts-list.js b/assets/blog-posts-list.js new file mode 100644 index 000000000..0ab0f879e --- /dev/null +++ b/assets/blog-posts-list.js @@ -0,0 +1,10 @@ +import PaginatedList from '@theme/paginated-list'; + +/** + * A custom element that renders a paginated blog posts list + */ +export default class BlogPostsList extends PaginatedList {} + +if (!customElements.get('blog-posts-list')) { + customElements.define('blog-posts-list', BlogPostsList); +} diff --git a/assets/cart-discount.js b/assets/cart-discount.js new file mode 100644 index 000000000..973badd8c --- /dev/null +++ b/assets/cart-discount.js @@ -0,0 +1,203 @@ +import { Component } from '@theme/component'; +import { morphSection } from '@theme/section-renderer'; +import { DiscountUpdateEvent } from '@theme/events'; +import { fetchConfig } from '@theme/utilities'; +import { cartPerformance } from '@theme/performance'; + +/** + * A custom element that applies a discount to the cart. + * + * @typedef {Object} CartDiscountComponentRefs + * @property {HTMLElement} cartDiscountError - The error element. + * @property {HTMLElement} cartDiscountErrorDiscountCode - The discount code error element. + * @property {HTMLElement} cartDiscountErrorShipping - The shipping error element. + */ + +/** + * @extends {Component} + */ +class CartDiscount extends Component { + requiredRefs = ['cartDiscountError', 'cartDiscountErrorDiscountCode', 'cartDiscountErrorShipping']; + + /** @type {AbortController | null} */ + #activeFetch = null; + + #createAbortController() { + if (this.#activeFetch) { + this.#activeFetch.abort(); + } + + const abortController = new AbortController(); + this.#activeFetch = abortController; + return abortController; + } + + /** + * Handles updates to the cart note. + * @param {SubmitEvent} event - The submit event on our form. + */ + applyDiscount = async (event) => { + const { cartDiscountError, cartDiscountErrorDiscountCode, cartDiscountErrorShipping } = this.refs; + + event.preventDefault(); + event.stopPropagation(); + + const form = event.target; + if (!(form instanceof HTMLFormElement)) return; + + const discountCode = form.querySelector('input[name="discount"]'); + if (!(discountCode instanceof HTMLInputElement) || typeof this.dataset.sectionId !== 'string') return; + + const discountCodeValue = discountCode.value; + + const abortController = this.#createAbortController(); + + try { + const existingDiscounts = this.#existingDiscounts(); + if (existingDiscounts.includes(discountCodeValue)) return; + + cartDiscountError.classList.add('hidden'); + cartDiscountErrorDiscountCode.classList.add('hidden'); + cartDiscountErrorShipping.classList.add('hidden'); + + const config = fetchConfig('json', { + body: JSON.stringify({ + discount: [...existingDiscounts, discountCodeValue].join(','), + sections: [this.dataset.sectionId], + }), + }); + + const response = await fetch(Theme.routes.cart_update_url, { + ...config, + signal: abortController.signal, + }); + + const data = await response.json(); + + if ( + data.discount_codes.find((/** @type {{ code: string; applicable: boolean; }} */ discount) => { + return discount.code === discountCodeValue && discount.applicable === false; + }) + ) { + discountCode.value = ''; + this.#handleDiscountError('discount_code'); + return; + } + + const newHtml = data.sections[this.dataset.sectionId]; + const parsedHtml = new DOMParser().parseFromString(newHtml, 'text/html'); + const section = parsedHtml.getElementById(`shopify-section-${this.dataset.sectionId}`); + const discountCodes = section?.querySelectorAll('.cart-discount__pill') || []; + if (section) { + const codes = Array.from(discountCodes) + .map((element) => (element instanceof HTMLLIElement ? element.dataset.discountCode : null)) + .filter(Boolean); + // Before morphing, we need to check if the shipping discount is applicable in the UI + // we check the liquid logic compared to the cart payload to assess whether we leveraged + // a valid shipping discount code. + if ( + codes.length === existingDiscounts.length && + codes.every((/** @type {string} */ code) => existingDiscounts.includes(code)) && + data.discount_codes.find((/** @type {{ code: string; applicable: boolean; }} */ discount) => { + return discount.code === discountCodeValue && discount.applicable === true; + }) + ) { + this.#handleDiscountError('shipping'); + discountCode.value = ''; + return; + } + } + + document.dispatchEvent(new DiscountUpdateEvent(data, this.id)); + morphSection(this.dataset.sectionId, newHtml); + } catch (error) { + } finally { + this.#activeFetch = null; + cartPerformance.measureFromEvent('discount-update:user-action', event); + } + }; + + /** + * Handles removing a discount from the cart. + * @param {MouseEvent | KeyboardEvent} event - The mouse or keyboard event in our pill. + */ + removeDiscount = async (event) => { + event.preventDefault(); + event.stopPropagation(); + + if ( + (event instanceof KeyboardEvent && event.key !== 'Enter') || + !(event instanceof MouseEvent) || + !(event.target instanceof HTMLElement) || + typeof this.dataset.sectionId !== 'string' + ) { + return; + } + + const pill = event.target.closest('.cart-discount__pill'); + if (!(pill instanceof HTMLLIElement)) return; + + const discountCode = pill.dataset.discountCode; + if (!discountCode) return; + + const existingDiscounts = this.#existingDiscounts(); + const index = existingDiscounts.indexOf(discountCode); + if (index === -1) return; + + existingDiscounts.splice(index, 1); + + const abortController = this.#createAbortController(); + + try { + const config = fetchConfig('json', { + body: JSON.stringify({ discount: existingDiscounts.join(','), sections: [this.dataset.sectionId] }), + }); + + const response = await fetch(Theme.routes.cart_update_url, { + ...config, + signal: abortController.signal, + }); + + const data = await response.json(); + + document.dispatchEvent(new DiscountUpdateEvent(data, this.id)); + morphSection(this.dataset.sectionId, data.sections[this.dataset.sectionId]); + } catch (error) { + } finally { + this.#activeFetch = null; + } + }; + + /** + * Handles the discount error. + * + * @param {'discount_code' | 'shipping'} type - The type of discount error. + */ + #handleDiscountError(type) { + const { cartDiscountError, cartDiscountErrorDiscountCode, cartDiscountErrorShipping } = this.refs; + const target = type === 'discount_code' ? cartDiscountErrorDiscountCode : cartDiscountErrorShipping; + cartDiscountError.classList.remove('hidden'); + target.classList.remove('hidden'); + } + + /** + * Returns an array of existing discount codes. + * @returns {string[]} + */ + #existingDiscounts() { + /** @type {string[]} */ + const discountCodes = []; + const discountPills = this.querySelectorAll('.cart-discount__pill'); + for (const pill of discountPills) { + if (pill instanceof HTMLLIElement && typeof pill.dataset.discountCode === 'string') { + discountCodes.push(pill.dataset.discountCode); + } + } + + return discountCodes; + } +} + +if (!customElements.get('cart-discount-component')) { + customElements.define('cart-discount-component', CartDiscount); +} diff --git a/assets/cart-drawer.js b/assets/cart-drawer.js new file mode 100644 index 000000000..bafb3409d --- /dev/null +++ b/assets/cart-drawer.js @@ -0,0 +1,46 @@ +import { DialogComponent } from '@theme/dialog'; +import { CartAddEvent } from '@theme/events'; + +/** + * A custom element that manages a cart drawer. + * + * @extends {DialogComponent} + */ +class CartDrawerComponent extends DialogComponent { + connectedCallback() { + super.connectedCallback(); + document.addEventListener(CartAddEvent.eventName, this.#handleCartAdd); + } + + disconnectedCallback() { + super.disconnectedCallback(); + document.removeEventListener(CartAddEvent.eventName, this.#handleCartAdd); + } + + #handleCartAdd = () => { + if (this.hasAttribute('auto-open')) { + this.showDialog(); + } + }; + + open() { + this.showDialog(); + + /** + * Close cart drawer when installments CTA is clicked to avoid overlapping dialogs + */ + customElements.whenDefined('shopify-payment-terms').then(() => { + const installmentsContent = document.querySelector('shopify-payment-terms')?.shadowRoot; + const cta = installmentsContent?.querySelector('#shopify-installments-cta'); + cta?.addEventListener('click', this.closeDialog, { once: true }); + }); + } + + close() { + this.closeDialog(); + } +} + +if (!customElements.get('cart-drawer-component')) { + customElements.define('cart-drawer-component', CartDrawerComponent); +} diff --git a/assets/cart-icon.js b/assets/cart-icon.js new file mode 100644 index 000000000..540db4a9e --- /dev/null +++ b/assets/cart-icon.js @@ -0,0 +1,108 @@ +import { Component } from '@theme/component'; +import { onAnimationEnd } from '@theme/utilities'; +import { ThemeEvents, CartUpdateEvent } from '@theme/events'; + +/** + * A custom element that displays a cart icon. + * + * @typedef {object} Refs + * @property {HTMLElement} cartBubble - The cart bubble element. + * @property {HTMLElement} cartBubbleText - The cart bubble text element. + * @property {HTMLElement} cartBubbleCount - The cart bubble count element. + * + * @extends {Component} + */ +class CartIcon extends Component { + requiredRefs = ['cartBubble', 'cartBubbleText', 'cartBubbleCount']; + + /** @type {number} */ + get currentCartCount() { + return parseInt(this.refs.cartBubbleCount.textContent ?? '0', 10); + } + + set currentCartCount(value) { + this.refs.cartBubbleCount.textContent = value < 100 ? String(value) : ''; + } + + connectedCallback() { + super.connectedCallback(); + + document.addEventListener(ThemeEvents.cartUpdate, this.onCartUpdate); + this.ensureCartBubbleIsCorrect(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + document.removeEventListener(ThemeEvents.cartUpdate, this.onCartUpdate); + } + + /** + * Handles the cart update event. + * @param {CartUpdateEvent} event - The cart update event. + */ + onCartUpdate = async (event) => { + const itemCount = event.detail.data?.itemCount ?? 0; + const comingFromProductForm = event.detail.data?.source === 'product-form-component'; + + this.renderCartBubble(itemCount, comingFromProductForm); + }; + + /** + * Renders the cart bubble. + * @param {number} itemCount - The number of items in the cart. + * @param {boolean} comingFromProductForm - Whether the cart update is coming from the product form. + */ + renderCartBubble = async (itemCount, comingFromProductForm, animate = true) => { + // If the cart update is coming from the product form, we add to the current cart count, otherwise we set the new cart count + + this.refs.cartBubbleCount.classList.toggle('hidden', itemCount === 0); + this.refs.cartBubble.classList.toggle('visually-hidden', itemCount === 0); + this.refs.cartBubble.classList.toggle('cart-bubble--animating', itemCount > 0 && animate); + + this.currentCartCount = comingFromProductForm ? this.currentCartCount + itemCount : itemCount; + + this.classList.toggle('header-actions__cart-icon--has-cart', itemCount > 0); + + sessionStorage.setItem( + 'cart-count', + JSON.stringify({ + value: String(this.currentCartCount), + timestamp: Date.now(), + }) + ); + + if (!animate) return; + await onAnimationEnd(this.refs.cartBubbleText); + + this.refs.cartBubble.classList.remove('cart-bubble--animating'); + }; + + /** + * Checks if the cart count is correct. + */ + ensureCartBubbleIsCorrect = () => { + const sessionStorageCount = sessionStorage.getItem('cart-count'); + const visibleCount = this.refs.cartBubbleCount.textContent; + + if (sessionStorageCount === visibleCount || sessionStorageCount === null) return; + + try { + const { value, timestamp } = JSON.parse(sessionStorageCount); + + if (Date.now() - timestamp < 10000) { + const count = parseInt(value, 10); + + if (count >= 0) { + this.renderCartBubble(count, false, false); + } + } + } catch (_) { + // no-op + } + }; +} + +if (!customElements.get('cart-icon')) { + customElements.define('cart-icon', CartIcon); +} diff --git a/assets/cart-note.js b/assets/cart-note.js new file mode 100644 index 000000000..36f7824db --- /dev/null +++ b/assets/cart-note.js @@ -0,0 +1,46 @@ +import { Component } from '@theme/component'; +import { debounce, fetchConfig } from '@theme/utilities'; +import { cartPerformance } from '@theme/performance'; + +/** + * A custom element that displays a cart note. + */ +class CartNote extends Component { + /** @type {AbortController | null} */ + #activeFetch = null; + + /** + * Handles updates to the cart note. + * @param {InputEvent} event - The input event in our text-area. + */ + updateCartNote = debounce(async (event) => { + if (!(event.target instanceof HTMLTextAreaElement)) return; + + const note = event.target.value; + if (this.#activeFetch) { + this.#activeFetch.abort(); + } + + const abortController = new AbortController(); + this.#activeFetch = abortController; + + try { + const config = fetchConfig('json', { + body: JSON.stringify({ note }), + }); + + await fetch(Theme.routes.cart_update_url, { + ...config, + signal: abortController.signal, + }); + } catch (error) { + } finally { + this.#activeFetch = null; + cartPerformance.measureFromEvent('note-update:user-action', event); + } + }, 200); +} + +if (!customElements.get('cart-note')) { + customElements.define('cart-note', CartNote); +} diff --git a/assets/collection-links.js b/assets/collection-links.js new file mode 100644 index 000000000..4fea71e4e --- /dev/null +++ b/assets/collection-links.js @@ -0,0 +1,195 @@ +import { Component } from '@theme/component'; +import { closest, clamp, center, getVisibleElements } from '@theme/utilities'; +import { SlideshowSelectEvent } from '@theme/events'; +import { Scroller } from '@theme/scrolling'; +import { cycleFocus } from '@theme/focus'; + +/** + * Collection links component + * + * @typedef {Object} Refs + * @property {HTMLElement} container + * @property {HTMLElement[]} [images] + * @property {HTMLElement[]} [links] + * @property {import('slideshow').Slideshow} slideshow + * + * @extends {Component} + */ +class CollectionLinks extends Component { + requiredRefs = ['container']; + + /** @type {Scroller} */ + #scroll; + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener('keydown', this.#handleKeydown); + this.addEventListener(SlideshowSelectEvent.eventName, this.#handleSlideshowSelect); + + this.#scroll = new Scroller(this.refs.container, { onScroll: this.#handleScroll }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + this.#scroll.destroy(); + } + + get links() { + return this.refs.links || []; + } + + get currentIndex() { + return this.links.findIndex((link) => link.getAttribute('aria-current') === 'true'); + } + + /** + * Public method to select a collection link + * + * @param {number} targetIndex + * @param {PointerEvent} [event] + */ + select(targetIndex, event) { + this.#updateSelectedLink(targetIndex); + this.refs.slideshow?.select(targetIndex, undefined, { animate: false }); + if (event) this.#revealImage(event); + } + + /** + * Update the selected link + * + * @param {number} index + */ + #updateSelectedLink(index) { + const { links } = this; + const selectedIndex = clamp(index, 0, links.length - 1); + + for (const [index, link] of links.entries()) { + link.setAttribute('aria-current', Boolean(index === selectedIndex).toString()); + } + } + + /** + * Handle slideshow select event + * + * @param {SlideshowSelectEvent} event + */ + #handleSlideshowSelect = async (event) => { + if (!event.detail.userInitiated) return; + + const { index } = event.detail; + if (index === this.currentIndex) return; + + const selectedLink = this.links[index]; + if (!selectedLink) return; + + this.#updateSelectedLink(index); + + this.#scroll.to(selectedLink); + }; + + /** + * Cycle focus to the next or previous link + * + * @param {KeyboardEvent} event + */ + #handleKeydown(event) { + let modifier = 0; + + switch (event.key) { + case 'ArrowRight': + case 'ArrowDown': + modifier = 1; + break; + case 'ArrowLeft': + case 'ArrowUp': + modifier = -1; + break; + } + + if (!modifier) return; + + event.preventDefault(); + cycleFocus(this.links, modifier); + } + + /** + * Handle scroll event + */ + #handleScroll = () => { + const { links } = this; + const { container } = this.refs; + const visibleLinks = getVisibleElements(this, links, 0.1); + + if (visibleLinks.length === 0) return; + const centers = visibleLinks.map((link) => center(link, 'x')); + const referencePoint = center(container, 'x'); + const closestCenter = closest(centers, referencePoint); + const closestVisibleLink = visibleLinks[centers.indexOf(closestCenter)]; + + if (!closestVisibleLink) return; + + const index = links.indexOf(closestVisibleLink); + + this.select(index); + }; + + /** + * Reveal an image + * + * @param {Event} event + */ + #revealImage(event) { + if (!(event instanceof PointerEvent)) return; + if (event.pointerType === 'touch') return; + + const { target } = event; + if (!(target instanceof HTMLElement)) return; + + const { images } = this.refs; + const index = this.links.indexOf(target); + const selectedImage = images?.[index]; + + if (!selectedImage) return; + + /** @param {PointerEvent} event */ + const updateImagePosition = (event) => { + const imageHeight = selectedImage.offsetHeight; + const imageWidth = selectedImage.offsetWidth; + const viewportHeight = window.innerHeight; + const viewportWidth = window.innerWidth; + const offset = 15; + + const wouldBeCutOff = event.clientY + imageHeight + offset > viewportHeight; + const yPos = wouldBeCutOff ? event.clientY - imageHeight - offset : event.clientY + offset; + + const xPos = Math.min(Math.max(offset, event.clientX + offset), viewportWidth - imageWidth - offset); + + selectedImage.style.setProperty('--x', `${xPos}px`); + selectedImage.style.setProperty('--y', `${yPos}px`); + }; + + const reset = () => { + selectedImage.removeAttribute('reveal'); + target.removeEventListener('mousemove', updateImagePosition); + }; + + updateImagePosition(event); + + for (const image of images) { + if (image === selectedImage) { + image.setAttribute('reveal', ''); + } else { + image.removeAttribute('reveal'); + } + } + + target.addEventListener('mousemove', updateImagePosition); + target.addEventListener('mouseleave', reset, { once: true }); + } +} + +if (!customElements.get('collection-links-component')) { + customElements.define('collection-links-component', CollectionLinks); +} diff --git a/assets/component-cart-items.js b/assets/component-cart-items.js new file mode 100644 index 000000000..0ae13c832 --- /dev/null +++ b/assets/component-cart-items.js @@ -0,0 +1,259 @@ +import { Component } from '@theme/component'; +import { fetchConfig, debounce, onAnimationEnd, prefersReducedMotion, resetShimmer } from '@theme/utilities'; +import { morphSection, sectionRenderer } from '@theme/section-renderer'; +import { + ThemeEvents, + CartUpdateEvent, + QuantitySelectorUpdateEvent, + CartAddEvent, + DiscountUpdateEvent, +} from '@theme/events'; +import { cartPerformance } from '@theme/performance'; + +/** @typedef {import('./utilities').TextComponent} TextComponent */ + +/** + * A custom element that displays a cart items component. + * + * @typedef {object} Refs + * @property {HTMLElement[]} quantitySelectors - The quantity selector elements. + * @property {HTMLTableRowElement[]} cartItemRows - The cart item rows. + * @property {TextComponent} cartTotal - The cart total. + * + * @extends {Component} + */ +class CartItemsComponent extends Component { + #debouncedOnChange = debounce(this.#onQuantityChange, 300).bind(this); + + connectedCallback() { + super.connectedCallback(); + + document.addEventListener(ThemeEvents.cartUpdate, this.#handleCartUpdate); + document.addEventListener(ThemeEvents.discountUpdate, this.handleDiscountUpdate); + document.addEventListener(ThemeEvents.quantitySelectorUpdate, this.#debouncedOnChange); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + document.removeEventListener(ThemeEvents.cartUpdate, this.#handleCartUpdate); + document.removeEventListener(ThemeEvents.quantitySelectorUpdate, this.#debouncedOnChange); + } + + /** + * Handles QuantitySelectorUpdateEvent change event. + * @param {QuantitySelectorUpdateEvent} event - The event. + */ + #onQuantityChange(event) { + const { quantity, cartLine: line } = event.detail; + + if (!line) return; + + if (quantity === 0) { + return this.onLineItemRemove(line); + } + + this.updateQuantity({ + line, + quantity, + action: 'change', + }); + const lineItemRow = this.refs.cartItemRows[line - 1]; + + if (!lineItemRow) return; + + const textComponent = /** @type {TextComponent | undefined} */ (lineItemRow.querySelector('text-component')); + textComponent?.shimmer(); + } + + /** + * Handles the line item removal. + * @param {number} line - The line item index. + */ + onLineItemRemove(line) { + this.updateQuantity({ + line, + quantity: 0, + action: 'clear', + }); + + const cartItemRowToRemove = this.refs.cartItemRows[line - 1]; + + if (!cartItemRowToRemove) return; + + const rowsToRemove = [ + cartItemRowToRemove, + // Get all nested lines of the row to remove + ...this.refs.cartItemRows.filter((row) => row.dataset.parentKey === cartItemRowToRemove.dataset.key), + ]; + + // Add class to the row to trigger the animation + rowsToRemove.forEach((row) => { + const remove = () => row.remove(); + + if (prefersReducedMotion()) return remove(); + + row.style.setProperty('--row-height', `${row.clientHeight}px`); + row.classList.add('removing'); + + // Remove the row after the animation ends + onAnimationEnd(row, remove); + }); + } + + /** + * Updates the quantity. + * @param {Object} config - The config. + * @param {number} config.line - The line. + * @param {number} config.quantity - The quantity. + * @param {string} config.action - The action. + */ + updateQuantity(config) { + const cartPerformaceUpdateMarker = cartPerformance.createStartingMarker(`${config.action}:user-action`); + + this.#disableCartItems(); + + const { line, quantity } = config; + const { cartTotal } = this.refs; + + const cartItemsComponents = document.querySelectorAll('cart-items-component'); + const sectionsToUpdate = new Set([this.sectionId]); + cartItemsComponents.forEach((item) => { + if (item instanceof HTMLElement && item.dataset.sectionId) { + sectionsToUpdate.add(item.dataset.sectionId); + } + }); + + const body = JSON.stringify({ + line: line, + quantity: quantity, + sections: Array.from(sectionsToUpdate).join(','), + sections_url: window.location.pathname, + }); + + cartTotal?.shimmer(); + + fetch(`${Theme.routes.cart_change_url}`, fetchConfig('json', { body })) + .then((response) => { + return response.text(); + }) + .then((responseText) => { + const parsedResponseText = JSON.parse(responseText); + + resetShimmer(this); + + if (parsedResponseText.errors) { + this.#handleCartError(line, parsedResponseText); + return; + } + + const newSectionHTML = new DOMParser().parseFromString( + parsedResponseText.sections[this.sectionId], + 'text/html' + ); + + // Grab the new cart item count from a hidden element + const newCartHiddenItemCount = newSectionHTML.querySelector('[ref="cartItemCount"]')?.textContent; + const newCartItemCount = newCartHiddenItemCount ? parseInt(newCartHiddenItemCount, 10) : 0; + + this.dispatchEvent( + new CartUpdateEvent({}, this.sectionId, { + itemCount: newCartItemCount, + source: 'cart-items-component', + sections: parsedResponseText.sections, + }) + ); + + morphSection(this.sectionId, parsedResponseText.sections[this.sectionId]); + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + this.#enableCartItems(); + cartPerformance.measureFromMarker(cartPerformaceUpdateMarker); + }); + } + + /** + * Handles the discount update. + * @param {DiscountUpdateEvent} event - The event. + */ + handleDiscountUpdate = (event) => { + this.#handleCartUpdate(event); + }; + + /** + * Handles the cart error. + * @param {number} line - The line. + * @param {Object} parsedResponseText - The parsed response text. + * @param {string} parsedResponseText.errors - The errors. + */ + #handleCartError = (line, parsedResponseText) => { + const quantitySelector = this.refs.quantitySelectors[line - 1]; + const quantityInput = quantitySelector?.querySelector('input'); + + if (!quantityInput) throw new Error('Quantity input not found'); + + quantityInput.value = quantityInput.defaultValue; + + const cartItemError = this.refs[`cartItemError-${line}`]; + const cartItemErrorContainer = this.refs[`cartItemErrorContainer-${line}`]; + + if (!(cartItemError instanceof HTMLElement)) throw new Error('Cart item error not found'); + if (!(cartItemErrorContainer instanceof HTMLElement)) throw new Error('Cart item error container not found'); + + cartItemError.textContent = parsedResponseText.errors; + cartItemErrorContainer.classList.remove('hidden'); + }; + + /** + * Handles the cart update. + * + * @param {DiscountUpdateEvent | CartUpdateEvent | CartAddEvent} event + */ + #handleCartUpdate = (event) => { + if (event instanceof DiscountUpdateEvent) { + sectionRenderer.renderSection(this.sectionId, { cache: false }); + return; + } + if (event.target === this) return; + + const cartItemsHtml = event.detail.data.sections?.[this.sectionId]; + if (cartItemsHtml) { + morphSection(this.sectionId, cartItemsHtml); + } else { + sectionRenderer.renderSection(this.sectionId, { cache: false }); + } + }; + + /** + * Disables the cart items. + */ + #disableCartItems() { + this.classList.add('cart-items-disabled'); + } + + /** + * Enables the cart items. + */ + #enableCartItems() { + this.classList.remove('cart-items-disabled'); + } + + /** + * Gets the section id. + * @returns {string} The section id. + */ + get sectionId() { + const { sectionId } = this.dataset; + + if (!sectionId) throw new Error('Section id missing'); + + return sectionId; + } +} + +if (!customElements.get('cart-items-component')) { + customElements.define('cart-items-component', CartItemsComponent); +} diff --git a/assets/component-quantity-selector.js b/assets/component-quantity-selector.js new file mode 100644 index 000000000..8fd8bd9d8 --- /dev/null +++ b/assets/component-quantity-selector.js @@ -0,0 +1,100 @@ +import { Component } from '@theme/component'; +import { QuantitySelectorUpdateEvent } from '@theme/events'; + +/** + * A custom element that allows the user to select a quantity. + * + * @typedef {Object} Refs + * @property {HTMLInputElement} quantityInput + * + * @extends {Component} + */ +class QuantitySelectorComponent extends Component { + /** + * Handles the quantity increase event. + * @param {Event} event - The event. + */ + increaseQuantity(event) { + if (!(event.target instanceof HTMLElement)) return; + + event.preventDefault(); + this.refs.quantityInput.stepUp(); + this.#onQuantityChange(); + } + + /** + * Handles the quantity decrease event. + * @param {Event} event - The event. + */ + decreaseQuantity(event) { + if (!(event.target instanceof HTMLElement)) return; + + event.preventDefault(); + this.refs.quantityInput.stepDown(); + this.#onQuantityChange(); + } + + /** + * When our input gets focused, we want to fully select the value. + * @param {FocusEvent} event + */ + selectInputValue(event) { + const { quantityInput } = this.refs; + if (!(event.target instanceof HTMLInputElement) || document.activeElement !== quantityInput) return; + + quantityInput.select(); + } + + /** + * Handles the quantity set event. + * @param {Event} event - The event. + */ + setQuantity(event) { + if (!(event.target instanceof HTMLElement)) return; + + event.preventDefault(); + if (event.target instanceof HTMLInputElement) { + this.refs.quantityInput.value = event.target.value; + } + this.#onQuantityChange(); + } + + /** + * Handles the quantity change event. + */ + #onQuantityChange() { + const { quantityInput } = this.refs; + + this.#checkQuantityRules(); + const newValue = parseInt(quantityInput.value); + + quantityInput.dispatchEvent(new QuantitySelectorUpdateEvent(newValue, Number(quantityInput.dataset.cartLine))); + } + + /** + * Checks the quantity rules are met + */ + #checkQuantityRules = () => { + const { quantityInput } = this.refs; + const { min, max, value: newValue } = quantityInput; + + if (newValue < min && min) quantityInput.value = min; + if (newValue > max && max) quantityInput.value = max; + }; + + /** + * Gets the quantity input. + * @returns {HTMLInputElement} The quantity input. + */ + get quantityInput() { + if (!this.refs.quantityInput) { + throw new Error('Missing inside '); + } + + return this.refs.quantityInput; + } +} + +if (!customElements.get('quantity-selector-component')) { + customElements.define('quantity-selector-component', QuantitySelectorComponent); +} diff --git a/assets/component.js b/assets/component.js new file mode 100644 index 000000000..cfe8a95a8 --- /dev/null +++ b/assets/component.js @@ -0,0 +1,330 @@ +import { requestIdleCallback } from '@theme/utilities'; + +/** + * @typedef {Record} Refs + */ + +/** + * @template {Refs} T + * @typedef {T & Refs} RefsType + */ + +/** + * Base class that powers our custom web components. + * + * Manages references to child elements with `ref` attributes and sets up mutation observers to keep + * the refs updated when the DOM changes. Also handles declarative event listeners using. + * + * @template {Refs} [T=Refs] + * @extends {DeclarativeShadowElement} + */ +export class Component extends DeclarativeShadowElement { + /** + * An object holding references to child elements with `ref` attributes. + * + * @type {RefsType} + */ + refs = /** @type {RefsType} */ ({}); + + /** + * An array of required refs. If a ref is not found, an error will be thrown. + * + * @type {string[] | undefined} + */ + requiredRefs; + + /** + * Gets the root node of the component, which is either its shadow root or the component itself. + * + * @returns {(ShadowRoot | Component)[]} The root nodes. + */ + get roots() { + return this.shadowRoot ? [this, this.shadowRoot] : [this]; + } + + /** + * Called when the element is connected to the document's DOM. + * + * Initializes event listeners and refs. + */ + connectedCallback() { + super.connectedCallback(); + registerEventListeners(); + + this.#updateRefs(); + + requestIdleCallback(() => { + for (const root of this.roots) { + this.#mutationObserver.observe(root, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['ref'], + attributeOldValue: true, + }); + } + }); + } + + /** + * Called when the element is re-rendered by the Section Rendering API. + */ + updatedCallback() { + this.#mutationObserver.takeRecords(); + this.#updateRefs(); + } + + /** + * Called when the element is disconnected from the document's DOM. + * + * Disconnects the mutation observer. + */ + disconnectedCallback() { + this.#mutationObserver.disconnect(); + } + + /** + * Updates the `refs` object by querying all descendant elements with `ref` attributes and storing references to them. + * + * This method is called to keep the `refs` object in sync with the DOM. + */ + #updateRefs() { + const refs = /** @type any */ ({}); + const elements = this.roots.reduce((acc, root) => { + for (const element of root.querySelectorAll('[ref]')) { + if (!this.#isDescendant(element)) continue; + acc.add(element); + } + + return acc; + }, /** @type {Set} */ (new Set())); + + for (const ref of elements) { + const refName = ref.getAttribute('ref') ?? ''; + const isArray = refName.endsWith('[]'); + const path = isArray ? refName.slice(0, -2) : refName; + + if (isArray) { + const array = Array.isArray(refs[path]) ? refs[path] : []; + + array.push(ref); + refs[path] = array; + } else { + refs[path] = ref; + } + } + + if (this.requiredRefs?.length) { + for (const ref of this.requiredRefs) { + if (!(ref in refs)) { + throw new MissingRefError(ref, this); + } + } + } + + this.refs = /** @type {RefsType} */ (refs); + } + + /** + * MutationObserver instance to observe changes in the component's DOM subtree and update refs accordingly. + * + * @type {MutationObserver} + */ + #mutationObserver = new MutationObserver((mutations) => { + if ( + mutations.some( + (m) => + (m.type === 'attributes' && this.#isDescendant(m.target)) || + (m.type === 'childList' && [...m.addedNodes, ...m.removedNodes].some(this.#isDescendant)) + ) + ) { + this.#updateRefs(); + } + }); + + /** + * Checks if a given node is a descendant of this component. + * + * @param {Node} node - The node to check. + * @returns {boolean} True if the node is a descendant of this component. + */ + #isDescendant = (node) => getClosestComponent(getAncestor(node)) === this; +} + +/** + * Get the ancestor of a given node. + * + * @param {Node} node - The node to get the ancestor of. + * @returns {Node | null} The ancestor of the node or null if none is found. + */ +function getAncestor(node) { + if (node.parentNode) return node.parentNode; + + const root = node.getRootNode(); + if (root instanceof ShadowRoot) return root.host; + + return null; +} + +/** + * Recursively finds the closest ancestor that is an instance of `Component`. + * + * @param {Node | null} node - The starting node to search from. + * @returns {HTMLElement | null} The closest ancestor `Component` instance or null if none is found. + */ +function getClosestComponent(node) { + if (!node) return null; + if (node instanceof Component) return node; + if (node instanceof HTMLElement && node.tagName.toLowerCase().endsWith('-component')) return node; + + const ancestor = getAncestor(node); + if (ancestor) return getClosestComponent(ancestor); + + return null; +} + +/** + * Initializes the event listeners for custom event handling. + * + * Sets up event listeners for specified events and delegates the handling of those events + * to methods defined on the closest `Component` instance, based on custom attributes. + */ +let initialized = false; + +function registerEventListeners() { + if (initialized) return; + initialized = true; + + const events = ['click', 'change', 'select', 'focus', 'blur', 'submit', 'input', 'keydown', 'keyup', 'toggle']; + const shouldBubble = ['focus', 'blur']; + const expensiveEvents = ['pointerenter', 'pointerleave']; + + for (const eventName of [...events, ...expensiveEvents]) { + const attribute = `on:${eventName}`; + + document.addEventListener( + eventName, + (event) => { + const element = getElement(event); + + if (!element) return; + + const proxiedEvent = + event.target !== element + ? new Proxy(event, { + get(target, property) { + if (property === 'target') return element; + + const value = Reflect.get(target, property); + + if (typeof value === 'function') { + return value.bind(target); + } + + return value; + }, + }) + : event; + + const value = element.getAttribute(attribute) ?? ''; + let [selector, method] = value.split('/'); + // Extract the last segment of the attribute value delimited by `?` or `/` + // Do not use lookback for Safari 16.0 compatibility + const matches = value.match(/([\/\?][^\/\?]+)([\/\?][^\/\?]+)$/); + const data = matches ? matches[2] : null; + const instance = selector + ? selector.startsWith('#') + ? document.querySelector(selector) + : element.closest(selector) + : getClosestComponent(element); + + if (!(instance instanceof Component) || !method) return; + + method = method.replace(/\?.*/, ''); + + const callback = /** @type {any} */ (instance)[method]; + + if (typeof callback === 'function') { + try { + /** @type {(Event | Data)[]} */ + const args = [proxiedEvent]; + + if (data) args.unshift(parseData(data)); + + callback.call(instance, ...args); + } catch (error) { + console.error(error); + } + } + }, + { capture: true } + ); + } + + /** @param {Event} event */ + function getElement(event) { + const target = event.composedPath?.()[0] ?? event.target; + + if (!(target instanceof Element)) return; + + if (target.hasAttribute(`on:${event.type}`)) { + return target; + } + + if (expensiveEvents.includes(event.type)) { + return null; + } + + return event.bubbles || shouldBubble.includes(event.type) ? target.closest(`[on\\:${event.type}]`) : null; + } +} + +/** + * Parses a string to extract data based on a delimiter. + * + * @param {string} str - The string to parse. + * @returns {Object|Array|string} The parsed data. + */ +function parseData(str) { + const delimiter = str[0]; + const data = str.slice(1); + + return delimiter === '?' + ? Object.fromEntries( + Array.from(new URLSearchParams(data).entries()).map(([key, value]) => [key, parseValue(value)]) + ) + : parseValue(data); +} + +/** + * @typedef {Object|Array|string} Data + */ + +/** + * Parses a string value to its appropriate type. + * + * @param {string} str - The string to parse. + * @returns {Data} The parsed value. + */ +function parseValue(str) { + if (str === 'true') return true; + if (str === 'false') return false; + + const maybeNumber = Number(str); + if (!isNaN(maybeNumber) && str.trim() !== '') return maybeNumber; + + return str; +} + +/** + * Throws a formatted error when a required ref is not found in the component. + */ +class MissingRefError extends Error { + /** + * @param {string} ref + * @param {Component} component + */ + constructor(ref, component) { + super(`Required ref "${ref}" not found in component ${component.tagName.toLowerCase()}`); + } +} diff --git a/assets/copy-to-clipboard.js b/assets/copy-to-clipboard.js new file mode 100644 index 000000000..99693ec8b --- /dev/null +++ b/assets/copy-to-clipboard.js @@ -0,0 +1,26 @@ +import { Component } from '@theme/component'; + +/** + * Handles copying text to clipboard, from an event like a click. + * Optionally, reveals a success message after copying. + * @extends {Component} + */ +class CopyToClipboardComponent extends Component { + copyToClipboard() { + const copyContent = this.getAttribute('text-to-copy'); + + if (!copyContent) return; + + navigator.clipboard.writeText(copyContent); + + const copySuccessMessage = this.refs.copySuccessMessage; + + if (copySuccessMessage instanceof Element) { + copySuccessMessage.classList.remove('visually-hidden'); + } + } +} + +if (!customElements.get('copy-to-clipboard-component')) { + customElements.define('copy-to-clipboard-component', CopyToClipboardComponent); +} diff --git a/assets/critical.js b/assets/critical.js new file mode 100644 index 000000000..eb216e05c --- /dev/null +++ b/assets/critical.js @@ -0,0 +1,464 @@ +/* + * Declarative shadow DOM is only initialized on the initial render of the page. + * If the component is mounted after the browser finishes the initial render, + * the shadow root needs to be manually hydrated. + */ +class DeclarativeShadowElement extends HTMLElement { + connectedCallback() { + if (!this.shadowRoot) { + const template = this.querySelector(':scope > template[shadowrootmode="open"]'); + + if (!(template instanceof HTMLTemplateElement)) return; + + const shadow = this.attachShadow({ mode: 'open' }); + shadow.append(template.content.cloneNode(true)); + } + } +} + +/** + * A custom ResizeObserver that only calls the callback when the element is resized. + * By default the ResizeObserver callback is called when the element is first observed. + */ +class ResizeNotifier extends ResizeObserver { + #initialized = false; + + /** + * @param {ResizeObserverCallback} callback + */ + constructor(callback) { + super((entries) => { + if (this.#initialized) return callback(entries, this); + this.#initialized = true; + }); + } + + disconnect() { + this.#initialized = false; + super.disconnect(); + } +} + +/** + * Event class for overflow minimum items updates + * @extends {Event} + */ +class OverflowMinimumEvent extends Event { + /** + * Creates a new OverflowMinimumEvent + * @param {boolean} minimumReached - Whether the minimum number of visible items has been reached + */ + constructor(minimumReached) { + super('overflowMinimum', { bubbles: true }); + this.detail = { + minimumReached, + }; + } +} + +class ReflowEvent extends Event { + /** + * @param {HTMLElement} lastVisibleElement - The element to move to the last visible position + */ + constructor(lastVisibleElement) { + super('reflow', { bubbles: true }); + this.detail = { lastVisibleElement }; + } +} + +/** + * A custom element that wraps a list of items and moves them to an overflow slot when they don't fit. + * This component is used in the header section, it needs to be render-blocking to avoid layout shifts. + * @attr {string | null} minimum-items When set, the element enters a 'minimum-reached' state when visible items are at or below this number. + * @example + * + * + * + */ +class OverflowList extends DeclarativeShadowElement { + static get observedAttributes() { + return ['disabled', 'minimum-items']; + } + + /** + * @param {string} name + * @param {string} oldValue + * @param {string} newValue + */ + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'disabled') { + if (newValue === 'true') { + this.#reset(); + } else { + this.#reflowItems(); + } + } + } + + connectedCallback() { + super.connectedCallback(); + const { shadowRoot } = this; + + if (!shadowRoot) throw new Error('Missing shadow root'); + + const defaultSlot = shadowRoot.querySelector('slot:not([name])'); + const overflowSlot = shadowRoot.querySelector('slot[name="overflow"]'); + const moreSlot = shadowRoot.querySelector('slot[name="more"]'); + const overflow = shadowRoot.querySelector('[part="overflow"]'); + const list = shadowRoot.querySelector('[part="list"]'); + const placeholder = shadowRoot.querySelector('[part="placeholder"]'); + + if ( + !(defaultSlot instanceof HTMLSlotElement) || + !(overflowSlot instanceof HTMLSlotElement) || + !(moreSlot instanceof HTMLSlotElement) || + !(overflow instanceof HTMLElement) || + !(list instanceof HTMLUListElement) || + !(placeholder instanceof HTMLLIElement) + ) { + throw new Error('Invalid element types in '); + } + + this.#refs = { + defaultSlot, + overflowSlot, + moreSlot, + overflow, + list, + placeholder, + }; + + // Add event listener for reflow requests + this.addEventListener( + 'reflow', + /** @param {ReflowEvent} event */ (event) => { + this.#reflowItems(event.detail.lastVisibleElement); + } + ); + + if (this.hasAttribute('defer')) { + const deferredReflow = () => { + // Remove attribute first to change layout before calculating the actual size + this.removeAttribute('defer'); + this.#reflowItems(); + }; + const { schedule } = this; + + const idleCallback = typeof requestIdleCallback === 'function' ? requestIdleCallback : setTimeout; + + idleCallback(() => schedule(deferredReflow)); + } else { + this.#reflowItems(); + } + } + + disconnectedCallback() { + this.#resizeObserver.disconnect(); + } + + get schedule() { + return typeof Theme?.utilities?.scheduler?.schedule === 'function' + ? Theme.utilities.scheduler.schedule + : /** @param {FrameRequestCallback} callback */ (callback) => requestAnimationFrame(callback); + } + + #scheduled = false; + + /** + * Get the minimum number of items before changing the minimum-reached state + * @returns {number | null} + */ + get minimumItems() { + const value = this.getAttribute('minimum-items'); + return value ? parseInt(value, 10) : null; + } + + get overflowSlot() { + const { overflowSlot } = this.#refs; + return overflowSlot; + } + + get defaultSlot() { + const { defaultSlot } = this.#refs; + return defaultSlot; + } + + /** + * @type {{width: number | null, height: number | null}} + */ + #lastDimensions = { + width: null, + height: null, + }; + + /** + * @type {ResizeObserverCallback & MutationCallback} + */ + #handleChange = (event) => { + if (this.#scheduled) return; + + let width = null; + let height = null; + let isResize = false; + + for (const [, entry] of event.entries()) { + if (!(entry instanceof ResizeObserverEntry)) break; + // There should only be one entry + isResize = true; + width = Math.round(entry.contentRect.width); + height = Math.round(entry.contentRect.height); + } + + if (isResize) { + if (!width || !height || (width === this.#lastDimensions.width && height === this.#lastDimensions.height)) { + // Skip reflow if dimensions are 0 or the same as the last reflow + return; + } + + this.#lastDimensions = { width: Math.round(width), height: Math.round(height) }; + } + + this.#scheduled = true; + + this.schedule(() => { + this.#reflowItems(); + this.#scheduled = false; + }); + }; + + /** + * Move all items to the default slot. + */ + #moveItemsToDefaultSlot() { + const { defaultSlot, overflowSlot } = this.#refs; + + for (const element of overflowSlot.assignedElements()) { + element.slot = defaultSlot.name; + } + } + + /** + * Reset the list to its initial state and disconnect the observers. + */ + #reset() { + const { list } = this.#refs; + + this.#mutationObserver.disconnect(); + this.#resizeObserver.disconnect(); + this.#moveItemsToDefaultSlot(); + + list.style.removeProperty('height'); + this.style.setProperty('--overflow-count', '0'); + } + + /** + * Sets the minimum-reached attribute and dispatches a custom event based on visible elements count + * @param {Element[]} visibleElements - The currently visible elements + */ + #updateMinimumReached(visibleElements) { + if (this.minimumItems !== null) { + const minimumReached = visibleElements.length < this.minimumItems; + + if (minimumReached) { + this.setAttribute('minimum-reached', ''); + } else { + this.removeAttribute('minimum-reached'); + } + + this.dispatchEvent(new OverflowMinimumEvent(minimumReached)); + } + } + + /** + * Show all items in the list. + */ + showAll() { + const { placeholder } = this.#refs; + + placeholder.style.setProperty('width', '0'); + placeholder.style.setProperty('display', 'none'); + this.setAttribute('disabled', 'true'); + } + + /** + * Reflow items based on available space within the list. + * @param {HTMLElement} [lastVisibleElement] Optional element to place in last visible position + */ + #reflowItems = (lastVisibleElement) => { + const { defaultSlot, overflowSlot, moreSlot, list, placeholder } = this.#refs; + + this.#resizeObserver.disconnect(); + this.#mutationObserver.disconnect(); + + // Avoid layout shifts while reflowing the list + const { height } = this.firstElementChild?.getBoundingClientRect() ?? {}; + + if (height) list.style.height = `${height}px`; + list.style.setProperty('overflow', 'hidden'); + + // Move all elements to the default slot so we can check which ones overflow + this.#moveItemsToDefaultSlot(); + + const elements = defaultSlot.assignedElements(); + + // Make sure the "More" item and placeholder are hidden + moreSlot.hidden = true; + placeholder.hidden = true; + + // First, check if all the items fit + const rootRect = list.getBoundingClientRect(); + + // Store the initial dimensions for comparison later + this.#lastDimensions = { width: Math.round(rootRect.width), height: Math.round(rootRect.height) }; + + const getVisibleElements = () => elements.filter((el) => el.getBoundingClientRect().top <= rootRect.top); + let visibleElements = getVisibleElements(); + + // If not all items fit or we have a lastVisibleElement, let's calculate with "More" button + if (visibleElements.length !== elements.length || lastVisibleElement) { + // Putting the "More" item (and lastVisibleElement, if provided) at the start of the list lets us see which items will fit on the same row + moreSlot.style.setProperty('order', '-1'); + moreSlot.hidden = false; + moreSlot.style.setProperty('height', `${height}px`); + + if (lastVisibleElement) { + lastVisibleElement.style.setProperty('order', '-1'); + } + + // Recalculate the visible elements + visibleElements = getVisibleElements(); + + // Reset the order + moreSlot.style.removeProperty('order'); + if (lastVisibleElement) { + lastVisibleElement.style.removeProperty('order'); + } + + // If we have a lastVisibleElement, ensure it's in the last visible position + if (lastVisibleElement) { + const visibleIndex = visibleElements.indexOf(lastVisibleElement); + if (visibleIndex !== -1) { + // Remove lastVisibleElement from its current position + visibleElements.splice(visibleIndex, 1); + // Add it to the end of visible elements + visibleElements.push(lastVisibleElement); + } + } + + moreSlot.style.setProperty('height', 'auto'); + } + + const overflowingElements = elements.filter((element) => !visibleElements.includes(element)); + const [firstOverflowingElement] = overflowingElements; + const hasOverflow = overflowingElements.length > 0; + const placeholderWidth = firstOverflowingElement ? firstOverflowingElement.clientWidth : 0; + + // Move the elements to the correct slot + for (const element of elements) { + element.slot = overflowingElements.includes(element) ? overflowSlot.name : defaultSlot.name; + } + + // If there are overflowing elements + // Show more button and placeholder if needed + moreSlot.hidden = !hasOverflow; + + if (hasOverflow) { + // Set the width and height of the placeholder so the list can grow if there is space + placeholder.style.width = `${placeholderWidth}px`; + placeholder.hidden = false; + } + + list.style.setProperty('counter-reset', `overflow-count ${overflowingElements.length}`); + this.style.setProperty('--overflow-count', `${overflowingElements.length}`); + list.style.removeProperty('overflow'); + + // Check if the minimum-reached state should be updated + hasOverflow && this.#updateMinimumReached(visibleElements); + + // Observe the list for changes in size + this.#resizeObserver.observe(this); + this.#mutationObserver.observe(this, { childList: true }); + }; + + /** + * @type {{ + * defaultSlot: HTMLSlotElement; + * overflowSlot: HTMLSlotElement; + * moreSlot: HTMLSlotElement; + * overflow: HTMLElement; + * list: HTMLUListElement; + * placeholder: HTMLLIElement; + * }} + */ + #refs; + + /** + * @type {ResizeObserver} + */ + #resizeObserver = new ResizeNotifier(this.#handleChange); + + /** + * @type {MutationObserver} + */ + #mutationObserver = new MutationObserver(this.#handleChange); +} + +if (!customElements.get('overflow-list')) { + customElements.define('overflow-list', OverflowList); +} + +// Function to calculate total height of header group children +function calculateHeaderGroupHeight( + header = document.querySelector('#header-component'), + headerGroup = document.querySelector('#header-group') +) { + if (!headerGroup) return 0; + + let totalHeight = 0; + const children = headerGroup.children; + for (let i = 0; i < children.length; i++) { + const element = children[i]; + if (element === header || !(element instanceof HTMLElement)) continue; + totalHeight += element.offsetHeight; + } + return totalHeight; +} + +/** + * Initialize and maintain header height CSS variables. + * This is critical for preventing layout shifts during page load. + * There is a `ResizeObserver` and `MutationObserver` that kicks in post hydration in header.js + * Note: header-group uses display: contents, so we must observe all children. + */ +(() => { + const header = document.querySelector('header-component'); + + // Early exit if no header - nothing to do + if (!(header instanceof HTMLElement)) return; + + // Calculate initial height(s + const headerHeight = header.offsetHeight; + const headerGroupHeight = calculateHeaderGroupHeight(header); + + document.body.style.setProperty('--header-height', `${headerHeight}px`); + document.body.style.setProperty('--header-group-height', `${headerGroupHeight}px`); +})(); + +/** + * Updates CSS custom properties for transparent header offset calculation + * Avoids expensive :has() selectors + */ +(() => { + const header = document.querySelector('#header-component'); + const headerGroup = document.querySelector('#header-group'); + const hasHeaderSection = headerGroup?.querySelector('.header-section'); + if (!hasHeaderSection || !header?.hasAttribute('transparent')) { + document.body.style.setProperty('--transparent-header-offset-boolean', '0'); + return; + } + + const hasImmediateSection = hasHeaderSection.nextElementSibling?.classList.contains('shopify-section'); + + const shouldApplyOffset = !hasImmediateSection ? '1' : '0'; + document.body.style.setProperty('--transparent-header-offset-boolean', shouldApplyOffset); +})(); diff --git a/assets/dialog.js b/assets/dialog.js new file mode 100644 index 000000000..fc013c69c --- /dev/null +++ b/assets/dialog.js @@ -0,0 +1,172 @@ +import { Component } from '@theme/component'; +import { debounce, isClickedOutside, onAnimationEnd } from '@theme/utilities'; + +/** + * A custom element that manages a dialog. + * + * @typedef {object} Refs + * @property {HTMLDialogElement} dialog – The dialog element. + * + * @extends Component + */ +export class DialogComponent extends Component { + requiredRefs = ['dialog']; + + connectedCallback() { + super.connectedCallback(); + + if (this.minWidth || this.maxWidth) { + window.addEventListener('resize', this.#handleResize); + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + if (this.minWidth || this.maxWidth) { + window.removeEventListener('resize', this.#handleResize); + } + } + + #handleResize = debounce(() => { + const { minWidth, maxWidth } = this; + + if (!minWidth && !maxWidth) return; + + const windowWidth = window.innerWidth; + if (windowWidth < minWidth || windowWidth > maxWidth) { + this.closeDialog(); + } + }, 50); + + /** + * Shows the dialog. + */ + showDialog() { + const { dialog } = this.refs; + + if (dialog.open) return; + + dialog.showModal(); + this.dispatchEvent(new DialogOpenEvent()); + + // Wait until the next tick to add the event listeners to avoid race condition + // when `showDialog` is called within a click event listener. + setTimeout(() => { + this.addEventListener('click', this.#handleClick); + this.addEventListener('keydown', this.#handleKeyDown); + }); + } + + /** + * Closes the dialog. + */ + closeDialog = async () => { + const { dialog } = this.refs; + + if (!dialog.open) return; + + this.removeEventListener('click', this.#handleClick); + this.removeEventListener('keydown', this.#handleKeyDown); + + dialog.classList.add('dialog-closing'); + + await onAnimationEnd(dialog, undefined, { + subtree: false, + }); + + dialog.close(); + dialog.classList.remove('dialog-closing'); + + this.dispatchEvent(new DialogCloseEvent()); + }; + + /** + * Toggles the dialog. + */ + toggleDialog = () => { + if (this.refs.dialog.open) { + this.closeDialog(); + } else { + this.showDialog(); + } + }; + + /** + * Closes the dialog when the user clicks outside of it. + * + * @param {MouseEvent} event - The mouse event. + */ + #handleClick(event) { + const { dialog } = this.refs; + + if (isClickedOutside(event, dialog)) { + this.closeDialog(); + } + } + + /** + * Closes the dialog when the user presses the escape key. + * + * @param {KeyboardEvent} event - The keyboard event. + */ + #handleKeyDown(event) { + if (event.key !== 'Escape') return; + + event.preventDefault(); + this.closeDialog(); + } + + /** + * Gets the minimum width of the dialog. + * + * @returns {number} The minimum width of the dialog. + */ + get minWidth() { + return Number(this.getAttribute('dialog-active-min-width')); + } + + /** + * Gets the maximum width of the dialog. + * + * @returns {number} The maximum width of the dialog. + */ + get maxWidth() { + return Number(this.getAttribute('dialog-active-max-width')); + } +} + +if (!customElements.get('dialog-component')) customElements.define('dialog-component', DialogComponent); + +export class DialogOpenEvent extends CustomEvent { + constructor() { + super(DialogOpenEvent.eventName); + } + + static eventName = 'dialog:open'; +} + +export class DialogCloseEvent extends CustomEvent { + constructor() { + super(DialogCloseEvent.eventName); + } + + static eventName = 'dialog:close'; +} + +document.addEventListener( + 'toggle', + (event) => { + if (event.target instanceof HTMLDialogElement || event.target instanceof HTMLDetailsElement) { + if (event.target.hasAttribute('scroll-lock')) { + const { open } = event.target; + + if (open) { + document.documentElement.setAttribute('scroll-lock', ''); + } else { + document.documentElement.removeAttribute('scroll-lock'); + } + } + } + }, + { capture: true } +); diff --git a/assets/drag-zoom-wrapper.js b/assets/drag-zoom-wrapper.js new file mode 100644 index 000000000..ffb59889d --- /dev/null +++ b/assets/drag-zoom-wrapper.js @@ -0,0 +1,352 @@ +import { clamp, preventDefault, isMobileBreakpoint } from './utilities.js'; + +const MIN_ZOOM = 1; +const MAX_ZOOM = 5; +const DEFAULT_ZOOM = 1.5; + +export class DragZoomWrapper extends HTMLElement { + #controller = new AbortController(); + /** @type {number} */ + #scale = DEFAULT_ZOOM; + /** @type {number} */ + #initialDistance = 0; + /** @type {number} */ + #startScale = DEFAULT_ZOOM; + /** @type {Point} */ + #translate = { x: 0, y: 0 }; + /** @type {Point} */ + #startPosition = { x: 0, y: 0 }; + /** @type {Point} */ + #startTranslate = { x: 0, y: 0 }; + /** @type {boolean} */ + #isDragging = false; + /** @type {boolean} */ + #initialized = false; + /** @type {number | null} */ + #animationFrame = null; + + get #image() { + return this.querySelector('img'); + } + + connectedCallback() { + if (!this.#image) return; + + this.#initResizeListener(); + if (!isMobileBreakpoint()) return; + + this.#initEventListeners(); + this.#updateTransform(); + } + + #initResizeListener() { + this.#resizeObserver.observe(this); + } + + #initEventListeners() { + if (this.#initialized) return; + this.#initialized = true; + const { signal } = this.#controller; + const options = { passive: false, signal }; + + this.addEventListener('touchstart', this.#handleTouchStart, options); + this.addEventListener('touchmove', this.#handleTouchMove, options); + this.addEventListener('touchend', this.#handleTouchEnd, options); + this.#image?.addEventListener('load', this.#updateTransform, { signal }); + } + + disconnectedCallback() { + this.#controller.abort(); + this.#resizeObserver.disconnect(); + this.#cancelAnimationFrame(); + } + + #handleResize = () => { + if (!this.#initialized && isMobileBreakpoint()) { + this.#initEventListeners(); + } + if (this.#initialized) { + this.#requestUpdateTransform(); + } + }; + + #resizeObserver = new ResizeObserver(this.#handleResize); + + /** + * @param {TouchEvent} event + */ + #handleTouchStart = (event) => { + preventDefault(event); + + if (event.touches.length === 2) { + const [point1, point2] = Array.from(event.touches).map(touchToPoint); + if (!point1 || !point2) return; + this.#startZoomGesture(point1, point2); + } else if (event.touches.length === 1) { + const point = touchToPoint(event.touches[0]); + if (!point) return; + + this.#startDragGesture(point); + } + }; + + /** + * Start a zoom gesture with two points + * @param {Point} point1 + * @param {Point} point2 + */ + #startZoomGesture(point1, point2) { + this.#initialDistance = getDistance(point1, point2); + this.#startScale = this.#scale; + this.#isDragging = false; + } + + /** + * Start a drag gesture with a single point + * @param {Point} point + */ + #startDragGesture(point) { + this.#startPosition = { x: point.x, y: point.y }; + this.#startTranslate = { x: this.#translate.x, y: this.#translate.y }; + this.#isDragging = true; + } + + /** + * @param {TouchEvent} event + */ + #handleTouchMove = (event) => { + preventDefault(event); + + const isZooming = event.touches.length === 2; + const isDragging = event.touches.length === 1 && this.#isDragging; + + if (isZooming) { + this.#processZoomGesture(event); + } else if (isDragging) { + this.#processDragGesture(event); + } + }; + + /** + * Process zoom gesture from touch event + * @param {TouchEvent} event + */ + #processZoomGesture(event) { + const [point1, point2] = Array.from(event.touches).map(touchToPoint); + if (!point1 || !point2) return; + + const currentMidpoint = getMidpoint(point1, point2); + const currentDistance = getDistance(point1, point2); + const oldScale = this.#scale; + + // Calculate and apply new scale + const newScale = (currentDistance / this.#initialDistance) * this.#startScale; + this.#scale = clamp(newScale, MIN_ZOOM, MAX_ZOOM); + + // Adjust translation to keep the pinch midpoint stationary + const containerCenter = { + x: this.clientWidth / 2, + y: this.clientHeight / 2, + }; + + const distanceFromCenter = { + x: currentMidpoint.x - containerCenter.x, + y: currentMidpoint.y - containerCenter.y, + }; + + // Calculate how the image position needs to change to keep the midpoint stationary + // The correction factor accounts for the change in scale + const scaleDelta = this.#scale / oldScale - 1.0; + + // Apply correction to prevent zooming on the opposite side of the midpoint + this.#translate.x -= (distanceFromCenter.x * scaleDelta) / this.#scale; + this.#translate.y -= (distanceFromCenter.y * scaleDelta) / this.#scale; + + this.#requestUpdateTransform(); + this.#isDragging = false; + } + + /** + * Process drag gesture from touch event + * @param {TouchEvent} event + */ + #processDragGesture(event) { + const point = touchToPoint(event.touches[0]); + if (!point) return; + + // Calculate new translation + this.#translate = { + x: this.#startTranslate.x + (point.x - this.#startPosition.x) / this.#scale, + y: this.#startTranslate.y + (point.y - this.#startPosition.y) / this.#scale, + }; + + this.#requestUpdateTransform(); + } + + /** + * @param {TouchEvent} event + */ + #handleTouchEnd = (event) => { + if (event.touches.length === 0) { + this.#isDragging = false; + this.#requestUpdateTransform(); + } + }; + + /** + * Get the minimum zoom for the image + * @returns {number | null} + */ + #getMinZoom = () => { + const containerWidth = this.clientWidth; + const containerHeight = this.clientHeight; + const imageDimensions = this.#getImageDimensions(); + if (!imageDimensions || !containerWidth || !containerHeight) return null; + const { width: imageWidth, height: imageHeight } = imageDimensions; + + // Calculate minimum zoom to make image fit container + // Add small buffer to avoid showing whitespace at edges + return Math.max(containerWidth / imageWidth, containerHeight / imageHeight) + 0.001; + }; + + /** + * Get the dimensions of the image + * @returns {{ width: number, height: number } | null} + */ + #getImageDimensions = () => { + const containerRect = this.getBoundingClientRect(); + if (!this.#image) return null; + const { naturalWidth, naturalHeight } = this.#image; + const containerWidth = this.clientWidth; + const containerHeight = this.clientHeight; + + if (!naturalWidth || !naturalHeight || !containerWidth || !containerHeight) return null; + + const containerAspect = containerRect.width / containerRect.height; + const naturalAspect = naturalWidth / naturalHeight; + + let imageWidth, imageHeight; + if (naturalAspect > containerAspect) { + // Image is wider than container (relative to height) + imageWidth = containerRect.width; + imageHeight = imageWidth / naturalAspect; + } else { + // Image is taller than container (relative to width) + imageHeight = containerRect.height; + imageWidth = imageHeight * naturalAspect; + } + + if (imageWidth === 0 || imageHeight === 0) return null; + + return { width: imageWidth, height: imageHeight }; + }; + + /** + * Constrain image translation to keep it within the viewport + */ + #constrainTranslation() { + const containerWidth = this.clientWidth; + const containerHeight = this.clientHeight; + if (!containerWidth || !containerHeight) return; + + const minZoom = this.#getMinZoom(); + if (!minZoom) return; + + this.#scale = clamp(this.#scale, minZoom, MAX_ZOOM); + + const imageDimensions = this.#getImageDimensions(); + if (!imageDimensions) return; + + const { width: imageWidth, height: imageHeight } = imageDimensions; + + const scaledWidth = imageWidth * this.#scale; + const scaledHeight = imageHeight * this.#scale; + + // Calculate how much the image extends beyond container + const excessWidth = Math.max(0, scaledWidth - containerWidth); + const excessHeight = Math.max(0, scaledHeight - containerHeight); + + const maxTranslateX = excessWidth / (2 * this.#scale); + const maxTranslateY = excessHeight / (2 * this.#scale); + + this.#translate.x = clamp(this.#translate.x, -maxTranslateX, maxTranslateX); + this.#translate.y = clamp(this.#translate.y, -maxTranslateY, maxTranslateY); + } + + /** + * Request an animation frame to update the transform + */ + #requestUpdateTransform = () => { + if (!this.#animationFrame) { + this.#animationFrame = requestAnimationFrame(this.#updateTransform); + } + }; + + /** + * Cancel any pending animation frame + */ + #cancelAnimationFrame() { + if (this.#animationFrame) { + cancelAnimationFrame(this.#animationFrame); + this.#animationFrame = null; + } + } + + #updateTransform = () => { + this.#animationFrame = null; + this.#constrainTranslation(); + this.style.setProperty('--drag-zoom-scale', this.#scale.toString()); + this.style.setProperty('--drag-zoom-translate-x', `${this.#translate.x}px`); + this.style.setProperty('--drag-zoom-translate-y', `${this.#translate.y}px`); + }; + + destroy() { + this.#controller.abort(); + this.#cancelAnimationFrame(); + } +} + +if (!customElements.get('drag-zoom-wrapper')) { + customElements.define('drag-zoom-wrapper', DragZoomWrapper); +} + +/** + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ + +/** + * Convert a Touch object to a Point object + * @param {Touch | undefined} touch + * @returns {Point | undefined} + */ +function touchToPoint(touch) { + if (!touch) return undefined; + return { x: touch.clientX, y: touch.clientY }; +} + +/** + * Calculate the distance between two points + * @param {Point} point1 - First point + * @param {Point} point2 - Second point + * @returns {number} The distance between the points + */ +function getDistance(point1, point2) { + const dx = point1.x - point2.x; + const dy = point1.y - point2.y; + return Math.sqrt(dx * dx + dy * dy); +} + +/** + * Calculate the midpoint between two points + * @param {Point} point1 - First point + * @param {Point} point2 - Second point + * @returns {Point} The midpoint + */ +function getMidpoint(point1, point2) { + return { + x: (point1.x + point2.x) / 2, + y: (point1.y + point2.y) / 2, + }; +} diff --git a/assets/events.js b/assets/events.js new file mode 100644 index 000000000..5cfde7965 --- /dev/null +++ b/assets/events.js @@ -0,0 +1,285 @@ +/** + * @namespace ThemeEvents + * @description A collection of theme-specific events that can be used to trigger and listen for changes anywhere in the theme. + * @example + * document.dispatchEvent(new VariantUpdateEvent(variant, sectionId, { html })); + * document.addEventListener(ThemeEvents.variantUpdate, (e) => { console.log(e.detail.variant) }); + */ +export class ThemeEvents { + /** @static @constant {string} Event triggered when a variant is selected */ + static variantSelected = 'variant:selected'; + /** @static @constant {string} Event triggered when a variant is changed */ + static variantUpdate = 'variant:update'; + /** @static @constant {string} Event triggered when the cart items or quantities are updated */ + static cartUpdate = 'cart:update'; + /** @static @constant {string} Event triggered when a cart update fails */ + static cartError = 'cart:error'; + /** @static @constant {string} Event triggered when a media (video, 3d model) is loaded */ + static mediaStartedPlaying = 'media:started-playing'; + // Event triggered when quantity-selector value is changed + static quantitySelectorUpdate = 'quantity-selector:update'; + /** @static @constant {string} Event triggered when a predictive search is expanded */ + static megaMenuHover = 'megaMenu:hover'; + /** @static @constant {string} Event triggered when a zoom dialog media is selected */ + static zoomMediaSelected = 'zoom-media:selected'; + /** @static @constant {string} Event triggered when a discount is applied */ + static discountUpdate = 'discount:update'; + /** @static @constant {string} Event triggered when changing collection filters */ + static FilterUpdate = 'filter:update'; +} + +/** + * Event fired when a variant is selected + * @extends {Event} + */ +export class VariantSelectedEvent extends Event { + /** + * Creates a new VariantSelectedEvent + * @param {Object} resource - The new variant object + * @param {string} resource.id - The id of the variant + */ + constructor(resource) { + super(ThemeEvents.variantSelected, { bubbles: true }); + this.detail = { + resource, + }; + } +} + +/** + * Event fired after a variant is updated + * @extends {Event} + */ +export class VariantUpdateEvent extends Event { + /** + * Creates a new VariantUpdateEvent + * @param {Object} resource - The new variant object + * @param {string} resource.id - The id of the variant + * @param {boolean} resource.available - Whether the variant is available + * @param {boolean} resource.inventory_management - Whether the variant has inventory management + * @param {Object} [resource.featured_media] - The featured media of the variant + * @param {string} [resource.featured_media.id] - The id of the featured media + * @param {Object} [resource.featured_media.preview_image] - The preview image of the featured media + * @param {string} [resource.featured_media.preview_image.src] - The src URL of the preview image + * @param {string} sourceId - The id of the element the action was triggered from + * @param {Object} data - Additional event data + * @param {Document} data.html - The new document fragment for the variant + * @param {string} data.productId - The product ID of the updated variant, used to ensure the correct product form is updated + * @param {Object} [data.newProduct] - If a new product was loaded as part of the variant update (combined listing) + * @param {string} data.newProduct.id - The id of the new product + * @param {string} data.newProduct.url - The url of the new product + */ + constructor(resource, sourceId, data) { + super(ThemeEvents.variantUpdate, { bubbles: true }); + this.detail = { + resource: resource || null, + sourceId, + data: { + html: data.html, + productId: data.productId, + newProduct: data.newProduct, + }, + }; + } +} + +/** + * Event class for cart additions + * @extends {Event} + */ +export class CartAddEvent extends Event { + /** + * Creates a new CartAddEvent + * @param {Object} [resource] - The new cart object + * @param {string} [sourceId] - The id of the element the action was triggered from + * @param {Object} [data] - Additional event data + * @param {boolean} [data.didError] - Whether the cart operation failed + * @param {string} [data.source] - The source of the cart update + * @param {string} [data.productId] - The id of the product card that was updated + * @param {number} [data.itemCount] - The number of items in the cart + * @param {string} [data.variantId] - The id of the product variant that was added + * @param {Record} [data.sections] - The sections affected by the cart operation + */ + constructor(resource, sourceId, data) { + super(CartAddEvent.eventName, { bubbles: true }); + this.detail = { + resource, + sourceId, + data: { + ...data, + }, + }; + } + + static eventName = ThemeEvents.cartUpdate; +} + +/** + * Event class for cart updates + * @extends {Event} + */ +export class CartUpdateEvent extends Event { + /** + * Creates a new CartUpdateEvent + * @param {Object} resource - The new cart object + * @param {string} sourceId - The id of the element the action was triggered from + * @param {Object} [data] - Additional event data + * @param {boolean} [data.didError] - Whether the cart operation failed + * @param {string} [data.source] - The source of the cart update + * @param {string} [data.productId] - The id of the product card that was updated + * @param {number} [data.itemCount] - The number of items in the cart + * @param {string} [data.variantId] - The id of the product variant that was updated + * @param {Record} [data.sections] - The sections affected by the cart operation + */ + constructor(resource, sourceId, data) { + super(ThemeEvents.cartUpdate, { bubbles: true }); + this.detail = { + resource, + sourceId, + data: { + ...data, + }, + }; + } +} + +/** + * Event class for cart errors + * @extends {Event} + */ +export class CartErrorEvent extends Event { + /** + * Creates a new CartErrorEvent + * @param {string} sourceId - The id of the element the action was triggered from + * @param {string} message - A message from the server response + */ + constructor(sourceId, message) { + super(ThemeEvents.cartError, { bubbles: true }); + this.detail = { + sourceId, + data: { + message, + }, + }; + } +} + +/** + * Event class for quantity-selector updates + * @extends {Event} + */ +export class QuantitySelectorUpdateEvent extends Event { + /** + * Creates a new QuantitySelectorUpdateEvent + * @param {number} quantity - Quantity value + * @param {number} [cartLine] - The id of the updated cart line + */ + constructor(quantity, cartLine) { + super(ThemeEvents.quantitySelectorUpdate, { bubbles: true }); + this.detail = { + quantity, + cartLine, + }; + } +} + +/** + * Event class for quantity-selector updates + * @extends {Event} + */ +export class DiscountUpdateEvent extends Event { + /** + * Creates a new DiscountUpdateEvent + * @param {Object} resource - The new cart object + * @param {string} sourceId - The id of the element the action was triggered from + */ + constructor(resource, sourceId) { + super(ThemeEvents.discountUpdate, { bubbles: true }); + this.detail = { + resource, + sourceId, + }; + } +} + +/** + * Event class for media playback starts + * @extends {Event} + */ +export class MediaStartedPlayingEvent extends Event { + /** + * Creates a new MediaStartedPlayingEvent + * @param {HTMLElement} resource - The element containing the video that emitted the event + */ + constructor(resource) { + super(ThemeEvents.mediaStartedPlaying, { bubbles: true }); + this.detail = { + resource, + }; + } +} + +/** + * @typedef {Object} SlideshowSelectEventData + * @property {number} index + * @property {string | null} id + * @property {Element} slide + * @property {number} previousIndex + * @property {boolean} userInitiated + * @property {'select' | 'scroll' | 'drag'} trigger + */ + +export class SlideshowSelectEvent extends Event { + /** @param {SlideshowSelectEventData} data */ + constructor(data) { + super(SlideshowSelectEvent.eventName, { bubbles: true }); + this.detail = data; + } + + /** @type {SlideshowSelectEventData} */ + detail; + + static eventName = 'slideshow:select'; +} + +/** + * Event class for zoom dialog media selection + * @extends {Event} + */ +export class ZoomMediaSelectedEvent extends Event { + /** + * Creates a new ZoomMediaSelectedEvent + * @param {number} index - The index of the selected media + */ + constructor(index) { + super(ThemeEvents.zoomMediaSelected, { bubbles: true }); + this.detail = { + index, + }; + } +} + +/** + * Event class for mega menu hover being hovered over + * @extends {Event} + */ +export class MegaMenuHoverEvent extends Event { + constructor() { + super(ThemeEvents.megaMenuHover, { bubbles: true }); + } +} + +/** Event class for facet filtering updates */ +export class FilterUpdateEvent extends Event { + /** @param {URLSearchParams} queryParams */ + constructor(queryParams) { + super(ThemeEvents.FilterUpdate, { bubbles: true }); + this.detail = { + queryParams, + }; + } + + shouldShowClearAll() { + return [...this.detail.queryParams.entries()].filter(([key]) => key.startsWith('filter.')).length > 0; + } +} diff --git a/assets/facets.js b/assets/facets.js new file mode 100644 index 000000000..6c9a7b2ee --- /dev/null +++ b/assets/facets.js @@ -0,0 +1,910 @@ +import { sectionRenderer } from '@theme/section-renderer'; +import { Component } from '@theme/component'; +import { FilterUpdateEvent, ThemeEvents } from '@theme/events'; +import { debounce, formatMoney, startViewTransition } from '@theme/utilities'; + +/** + * Search query parameter. + * @type {string} + */ +const SEARCH_QUERY = 'q'; + +/** + * Handles the main facets form functionality + * + * @typedef {Object} FacetsFormRefs + * @property {HTMLFormElement} facetsForm - The main facets form element + * @property {HTMLElement | undefined} facetStatus - The facet status element + * + * @extends {Component} + */ +class FacetsFormComponent extends Component { + requiredRefs = ['facetsForm']; + + /** + * Creates URL parameters from form data + * @param {FormData} [formData] - Optional form data to use instead of the main form + * @returns {URLSearchParams} The processed URL parameters + */ + createURLParameters(formData = new FormData(this.refs.facetsForm)) { + let newParameters = new URLSearchParams(/** @type any */ (formData)); + + if (newParameters.get('filter.v.price.gte') === '') newParameters.delete('filter.v.price.gte'); + if (newParameters.get('filter.v.price.lte') === '') newParameters.delete('filter.v.price.lte'); + + newParameters.delete('page'); + + const searchQuery = this.#getSearchQuery(); + if (searchQuery) newParameters.set(SEARCH_QUERY, searchQuery); + + return newParameters; + } + + /** + * Gets the search query parameter from the current URL + * @returns {string} The search query + */ + #getSearchQuery() { + const url = new URL(window.location.href); + return url.searchParams.get(SEARCH_QUERY) ?? ''; + } + + get sectionId() { + const id = this.getAttribute('section-id'); + if (!id) throw new Error('Section ID is required'); + return id; + } + + /** + * Updates the URL hash with current filter parameters + */ + #updateURLHash() { + const url = new URL(window.location.href); + const urlParameters = this.createURLParameters(); + + url.search = ''; + for (const [param, value] of urlParameters.entries()) { + url.searchParams.append(param, value); + } + + history.pushState({ urlParameters: urlParameters.toString() }, '', url.toString()); + } + + /** + * Updates filters and renders the section + */ + updateFilters = () => { + this.#updateURLHash(); + this.dispatchEvent(new FilterUpdateEvent(this.createURLParameters())); + this.#updateSection(); + }; + + /** + * Updates the section + */ + #updateSection() { + const viewTransition = !this.closest('dialog'); + + if (viewTransition) { + startViewTransition(() => sectionRenderer.renderSection(this.sectionId), ['product-grid']); + } else { + sectionRenderer.renderSection(this.sectionId); + } + } + + /** + * Updates filters based on a provided URL + * @param {string} url - The URL to update filters with + */ + updateFiltersByURL(url) { + history.pushState('', '', url); + this.dispatchEvent(new FilterUpdateEvent(this.createURLParameters())); + this.#updateSection(); + } +} + +if (!customElements.get('facets-form-component')) { + customElements.define('facets-form-component', FacetsFormComponent); +} + +/** + * @typedef {Object} FacetInputsRefs + * @property {HTMLInputElement[]} facetInputs - The facet input elements + */ + +/** + * Handles individual facet input functionality + * @extends {Component} + */ +class FacetInputsComponent extends Component { + get sectionId() { + const id = this.closest('.shopify-section')?.id; + if (!id) throw new Error('FacetInputs component must be a child of a section'); + return id; + } + + /** + * Updates filters and the selected facet summary + */ + updateFilters() { + const facetsForm = this.closest('facets-form-component'); + + if (!(facetsForm instanceof FacetsFormComponent)) return; + + facetsForm.updateFilters(); + this.#updateSelectedFacetSummary(); + } + + /** + * Handles keydown events for the facets form + * @param {KeyboardEvent} event - The keydown event + */ + handleKeyDown(event) { + if (!(event.target instanceof HTMLElement)) return; + const closestInput = event.target.querySelector('input'); + + if (!(closestInput instanceof HTMLInputElement)) return; + + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + closestInput.checked = !closestInput.checked; + this.updateFilters(); + } + } + + /** + * Handles mouseover events on facet labels + * @param {MouseEvent} event - The mouseover event + */ + prefetchPage = debounce((event) => { + if (!(event.target instanceof HTMLElement)) return; + + const form = this.closest('form'); + if (!form) return; + + const formData = new FormData(form); + const inputElement = event.target.querySelector('input'); + + if (!(inputElement instanceof HTMLInputElement)) return; + + if (!inputElement.checked) formData.append(inputElement.name, inputElement.value); + + const facetsForm = this.closest('facets-form-component'); + if (!(facetsForm instanceof FacetsFormComponent)) return; + + const urlParameters = facetsForm.createURLParameters(formData); + + const url = new URL(window.location.pathname, window.location.origin); + + for (const [key, value] of urlParameters) url.searchParams.append(key, value); + + if (inputElement.checked) url.searchParams.delete(inputElement.name, inputElement.value); + + sectionRenderer.getSectionHTML(this.sectionId, true, url); + }, 200); + + cancelPrefetchPage = () => this.prefetchPage.cancel(); + + /** + * Updates the selected facet summary + */ + #updateSelectedFacetSummary() { + if (!this.refs.facetInputs) return; + + const checkedInputElements = this.refs.facetInputs.filter((input) => input.checked); + const details = this.closest('details'); + const statusComponent = details?.querySelector('facet-status-component'); + + if (!(statusComponent instanceof FacetStatusComponent)) return; + + statusComponent.updateListSummary(checkedInputElements); + } +} + +if (!customElements.get('facet-inputs-component')) { + customElements.define('facet-inputs-component', FacetInputsComponent); +} + +/** + * @typedef {Object} PriceFacetRefs + * @property {HTMLInputElement} minInput - The minimum price input + * @property {HTMLInputElement} maxInput - The maximum price input + */ + +/** + * Handles price facet functionality + * @extends {Component} + */ +class PriceFacetComponent extends Component { + connectedCallback() { + super.connectedCallback(); + this.addEventListener('keydown', this.#onKeyDown); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.removeEventListener('keydown', this.#onKeyDown); + } + + /** + * Handles keydown events to restrict input to valid characters + * @param {KeyboardEvent} event - The keydown event + */ + #onKeyDown = (event) => { + if (event.metaKey) return; + + const pattern = /[0-9]|\.|,|'| |Tab|Backspace|Enter|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Delete|Escape/; + if (!event.key.match(pattern)) event.preventDefault(); + }; + + /** + * Updates price filter and results + */ + updatePriceFilterAndResults() { + const { minInput, maxInput } = this.refs; + + this.#adjustToValidValues(minInput); + this.#adjustToValidValues(maxInput); + + const facetsForm = this.closest('facets-form-component'); + if (!(facetsForm instanceof FacetsFormComponent)) return; + + facetsForm.updateFilters(); + this.#setMinAndMaxValues(); + this.#updateSummary(); + } + + /** + * Adjusts input values to be within valid range + * @param {HTMLInputElement} input - The input element to adjust + */ + #adjustToValidValues(input) { + if (input.value.trim() === '') return; + + const value = Number(input.value); + const min = Number(formatMoney(input.getAttribute('data-min') ?? '')); + const max = Number(formatMoney(input.getAttribute('data-max') ?? '')); + + if (value < min) input.value = min.toString(); + if (value > max) input.value = max.toString(); + } + + /** + * Sets min and max values for the inputs + */ + #setMinAndMaxValues() { + const { minInput, maxInput } = this.refs; + + if (maxInput.value) minInput.setAttribute('data-max', maxInput.value); + if (minInput.value) maxInput.setAttribute('data-min', minInput.value); + if (minInput.value === '') maxInput.setAttribute('data-min', '0'); + if (maxInput.value === '') minInput.setAttribute('data-max', maxInput.getAttribute('data-max') ?? ''); + } + + /** + * Updates the price summary + */ + #updateSummary() { + const { minInput, maxInput } = this.refs; + const details = this.closest('details'); + const statusComponent = details?.querySelector('facet-status-component'); + + if (!(statusComponent instanceof FacetStatusComponent)) return; + + statusComponent?.updatePriceSummary(minInput, maxInput); + } +} + +if (!customElements.get('price-facet-component')) { + customElements.define('price-facet-component', PriceFacetComponent); +} + +/** + * Handles clearing of facet filters + * @extends {Component} + */ +class FacetClearComponent extends Component { + requiredRefs = ['clearButton']; + + connectedCallback() { + super.connectedCallback(); + this.addEventListener('keyup', this.#handleKeyUp); + document.addEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + disconnectedCallback() { + super.disconnectedCallback(); + document.removeEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + /** + * Clears the filter + * @param {Event} event - The click event + */ + clearFilter(event) { + if (!(event.target instanceof HTMLElement)) return; + + if (event instanceof KeyboardEvent) { + if (event.key !== 'Enter' && event.key !== ' ') { + return; + } + event.preventDefault(); + } + + const container = event.target.closest('facet-inputs-component, price-facet-component'); + container?.querySelectorAll('[type="checkbox"]:checked, input').forEach((input) => { + if (input instanceof HTMLInputElement) { + input.checked = false; + input.value = ''; + } + }); + + const details = event.target.closest('details'); + const statusComponent = details?.querySelector('facet-status-component'); + + if (!(statusComponent instanceof FacetStatusComponent)) return; + + statusComponent.clearSummary(); + + const facetsForm = this.closest('facets-form-component'); + if (!(facetsForm instanceof FacetsFormComponent)) return; + + facetsForm.updateFilters(); + } + + /** + * Handles keyup events + * @param {KeyboardEvent} event - The keyup event + */ + #handleKeyUp = (event) => { + if (event.metaKey) return; + if (event.key === 'Enter') this.clearFilter(event); + }; + + /** + * Toggle clear button visibility when filters are applied. Happens before the + * Section Rendering Request resolves. + * + * @param {FilterUpdateEvent} event + */ + #handleFilterUpdate = (event) => { + const { clearButton } = this.refs; + if (clearButton instanceof Element) { + clearButton.classList.toggle('facets__clear--active', event.shouldShowClearAll()); + } + }; +} + +if (!customElements.get('facet-clear-component')) { + customElements.define('facet-clear-component', FacetClearComponent); +} + +/** + * @typedef {Object} FacetRemoveComponentRefs + * @property {HTMLInputElement | undefined} clearButton - The button to clear filters + */ + +/** + * Handles removal of individual facet filters + * @extends {Component} + */ +class FacetRemoveComponent extends Component { + connectedCallback() { + super.connectedCallback(); + document.addEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + disconnectedCallback() { + super.disconnectedCallback(); + document.removeEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + /** + * Removes the filter + * @param {Object} data - The data object + * @param {string} data.form - The form to remove the filter from + * @param {Event} event - The click event + */ + removeFilter({ form }, event) { + if (event instanceof KeyboardEvent) { + if (event.key !== 'Enter' && event.key !== ' ') { + return; + } + event.preventDefault(); + } + + const url = this.dataset.url; + if (!url) return; + + const facetsForm = form ? document.getElementById(form) : this.closest('facets-form-component'); + + if (!(facetsForm instanceof FacetsFormComponent)) return; + + facetsForm.updateFiltersByURL(url); + } + + /** + * Toggle clear button visibility when filters are applied. Happens before the + * Section Rendering Request resolves. + * + * @param {FilterUpdateEvent} event + */ + #handleFilterUpdate = (event) => { + const { clearButton } = this.refs; + if (clearButton instanceof Element) { + clearButton.classList.toggle('active', event.shouldShowClearAll()); + } + }; +} + +if (!customElements.get('facet-remove-component')) { + customElements.define('facet-remove-component', FacetRemoveComponent); +} + +/** + * Handles sorting filter functionality + * + * @typedef {Object} SortingFilterRefs + * @property {HTMLDetailsElement} details - The details element + * @property {HTMLElement} summary - The summary element + * @property {HTMLElement} listbox - The listbox element + * + * @extends {Component} + */ +class SortingFilterComponent extends Component { + requiredRefs = ['details', 'summary', 'listbox']; + + /** + * Handles keyboard navigation in the sorting dropdown + * @param {KeyboardEvent} event - The keyboard event + */ + handleKeyDown = (event) => { + const { listbox } = this.refs; + if (!(listbox instanceof Element)) return; + + const options = Array.from(listbox.querySelectorAll('[role="option"]')); + const currentFocused = options.find((option) => option instanceof HTMLElement && option.tabIndex === 0); + let newFocusIndex = currentFocused ? options.indexOf(currentFocused) : 0; + + switch (event.key) { + case 'ArrowDown': + event.preventDefault(); + newFocusIndex = Math.min(newFocusIndex + 1, options.length - 1); + this.#moveFocus(options, newFocusIndex); + break; + + case 'ArrowUp': + event.preventDefault(); + newFocusIndex = Math.max(newFocusIndex - 1, 0); + this.#moveFocus(options, newFocusIndex); + break; + + case 'Enter': + case ' ': + if (event.target instanceof Element) { + const targetOption = event.target.closest('[role="option"]'); + if (targetOption) { + event.preventDefault(); + this.#selectOption(targetOption); + } + } + break; + + case 'Escape': + event.preventDefault(); + this.#closeDropdown(); + break; + } + }; + + /** + * Handles details toggle event + */ + handleToggle = () => { + const { details, summary, listbox } = this.refs; + if (!(details instanceof HTMLDetailsElement) || !(summary instanceof HTMLElement)) return; + + const isOpen = details.open; + summary.setAttribute('aria-expanded', isOpen.toString()); + + if (isOpen && listbox instanceof Element) { + // Move focus to selected option when dropdown opens + const selectedOption = listbox.querySelector('[aria-selected="true"]'); + if (selectedOption instanceof HTMLElement) { + selectedOption.focus(); + } + } + }; + + /** + * Moves focus between options + * @param {Element[]} options - The option elements + * @param {number} newIndex - The index of the option to focus + */ + #moveFocus(options, newIndex) { + // Remove tabindex from all options + options.forEach((option) => { + if (option instanceof HTMLElement) { + option.tabIndex = -1; + } + }); + + // Set tabindex and focus on new option + const targetOption = options[newIndex]; + if (targetOption instanceof HTMLElement) { + targetOption.tabIndex = 0; + targetOption.focus(); + } + } + + /** + * Selects an option and triggers form submission + * @param {Element} option - The option element to select + */ + #selectOption(option) { + const input = option.querySelector('input[type="radio"]'); + if (input instanceof HTMLInputElement && option instanceof HTMLElement) { + // Update aria-selected states + this.querySelectorAll('[role="option"]').forEach((opt) => { + opt.setAttribute('aria-selected', 'false'); + }); + option.setAttribute('aria-selected', 'true'); + + // Trigger click on the input to ensure normal form behavior + input.click(); + + // Close dropdown and return focus (handles tabIndex reset) + this.#closeDropdown(); + } + } + + /** + * Closes the dropdown and returns focus to summary + */ + #closeDropdown() { + const { details, summary } = this.refs; + if (details instanceof HTMLDetailsElement) { + // Reset focus to match the actual selected option + const options = this.querySelectorAll('[role="option"]'); + const selectedOption = this.querySelector('[aria-selected="true"]'); + + options.forEach((opt) => { + if (opt instanceof HTMLElement) { + opt.tabIndex = -1; + } + }); + + if (selectedOption instanceof HTMLElement) { + selectedOption.tabIndex = 0; + } + + details.open = false; + if (summary instanceof HTMLElement) { + summary.focus(); + } + } + } + + /** + * Updates filter and sorting + * @param {Event} event - The change event + */ + updateFilterAndSorting(event) { + const facetsForm = + this.closest('facets-form-component') || this.closest('.shopify-section')?.querySelector('facets-form-component'); + + if (!(facetsForm instanceof FacetsFormComponent)) return; + const isMobile = window.innerWidth < 750; + + const shouldDisable = this.dataset.shouldUseSelectOnMobile === 'true'; + + // Because we have a select element on mobile and a bunch of radio buttons on desktop, + // we need to disable the input during "form-submission" to prevent duplicate entries. + if (shouldDisable) { + if (isMobile) { + const inputs = this.querySelectorAll('input[name="sort_by"]'); + inputs.forEach((input) => { + if (!(input instanceof HTMLInputElement)) return; + input.disabled = true; + }); + } else { + const selectElement = this.querySelector('select[name="sort_by"]'); + if (!(selectElement instanceof HTMLSelectElement)) return; + selectElement.disabled = true; + } + } + + facetsForm.updateFilters(); + this.updateFacetStatus(event); + + // Re-enable the input after the form-submission + if (shouldDisable) { + if (isMobile) { + const inputs = this.querySelectorAll('input[name="sort_by"]'); + inputs.forEach((input) => { + if (!(input instanceof HTMLInputElement)) return; + input.disabled = false; + }); + } else { + const selectElement = this.querySelector('select[name="sort_by"]'); + if (!(selectElement instanceof HTMLSelectElement)) return; + selectElement.disabled = false; + } + } + + // Close the details element when a value is selected + const { details } = this.refs; + if (!(details instanceof HTMLDetailsElement)) return; + details.open = false; + } + + /** + * Updates the facet status + * @param {Event} event - The change event + */ + updateFacetStatus(event) { + if (!(event.target instanceof HTMLSelectElement)) return; + + const details = this.querySelector('details'); + if (!details) return; + + const facetStatus = details.querySelector('facet-status-component'); + if (!(facetStatus instanceof FacetStatusComponent)) return; + + facetStatus.textContent = + event.target.value !== details.dataset.defaultSortBy ? event.target.dataset.optionName ?? '' : ''; + } +} + +if (!customElements.get('sorting-filter-component')) { + customElements.define('sorting-filter-component', SortingFilterComponent); +} + +/** + * @typedef {Object} FacetStatusRefs + * @property {HTMLElement} facetStatus - The facet status element + */ + +/** + * Handles facet status display + * @extends {Component} + */ +class FacetStatusComponent extends Component { + /** + * Updates the list summary + * @param {HTMLInputElement[]} checkedInputElements - The checked input elements + */ + updateListSummary(checkedInputElements) { + const checkedInputElementsCount = checkedInputElements.length; + + this.getAttribute('facet-type') === 'swatches' + ? this.#updateSwatchSummary(checkedInputElements, checkedInputElementsCount) + : this.#updateBubbleSummary(checkedInputElements, checkedInputElementsCount); + } + + /** + * Updates the swatch summary + * @param {HTMLInputElement[]} checkedInputElements - The checked input elements + * @param {number} checkedInputElementsCount - The number of checked inputs + */ + #updateSwatchSummary(checkedInputElements, checkedInputElementsCount) { + const { facetStatus } = this.refs; + facetStatus.classList.remove('bubble', 'facets__bubble'); + + if (checkedInputElementsCount === 0) { + facetStatus.innerHTML = ''; + return; + } + + if (checkedInputElementsCount > 3) { + facetStatus.innerHTML = checkedInputElementsCount.toString(); + facetStatus.classList.add('bubble', 'facets__bubble'); + return; + } + + facetStatus.innerHTML = Array.from(checkedInputElements) + .map((inputElement) => { + const swatch = inputElement.parentElement?.querySelector('span.swatch'); + return swatch?.outerHTML ?? ''; + }) + .join(''); + } + + /** + * Updates the bubble summary + * @param {HTMLInputElement[]} checkedInputElements - The checked input elements + * @param {number} checkedInputElementsCount - The number of checked inputs + */ + #updateBubbleSummary(checkedInputElements, checkedInputElementsCount) { + const { facetStatus } = this.refs; + facetStatus.classList.remove('bubble', 'facets__bubble'); + + if (checkedInputElementsCount === 0) { + facetStatus.innerHTML = ''; + return; + } + + if (checkedInputElementsCount === 1) { + facetStatus.innerHTML = checkedInputElements[0]?.dataset.label ?? ''; + return; + } + + facetStatus.innerHTML = checkedInputElementsCount.toString(); + facetStatus.classList.add('bubble', 'facets__bubble'); + } + + /** + * Updates the price summary + * @param {HTMLInputElement} minInput - The minimum price input + * @param {HTMLInputElement} maxInput - The maximum price input + */ + updatePriceSummary(minInput, maxInput) { + const minInputValue = minInput.value; + const maxInputValue = maxInput.value; + const { facetStatus } = this.refs; + + if (!minInputValue && !maxInputValue) { + facetStatus.innerHTML = ''; + return; + } + + const minInputNum = this.#parseCents(minInputValue, '0'); + const maxInputNum = this.#parseCents(maxInputValue, facetStatus.dataset.rangeMax); + facetStatus.innerHTML = `${this.#formatMoney(minInputNum)}–${this.#formatMoney(maxInputNum)}`; + } + + /** + * Parses a decimal number as cents + * @param {string} value - The stringified decimal number to parse + * @param {string} fallback - The fallback value in case `value` is invalid + * @returns {number} The money value in cents + */ + #parseCents(value, fallback = '0') { + const parts = value ? value.trim().split(/[^0-9]/) : (parseInt(fallback, 10) / 100).toString(); + const [wholeStr, fractionStr, ...rest] = parts; + if (typeof wholeStr !== 'string' || rest.length > 0) return parseInt(fallback, 10); + + const whole = parseInt(wholeStr, 10); + let fraction = parseInt(fractionStr || '0', 10); + + // Use two most-significant digits, e.g. 1 -> 10, 12 -> 12, 123 -> 12.3, 1234 -> 12.34, etc + fraction = fraction * Math.pow(10, 2 - fraction.toString().length); + + return whole * 100 + fraction; + } + + /** + * Formats money, replicated the implementation of the `money` liquid filters + * @param {number} moneyValue - The money value + * @returns {string} The formatted money value + */ + #formatMoney(moneyValue) { + if (!(this.refs.moneyFormat instanceof HTMLTemplateElement)) return ''; + + const template = this.refs.moneyFormat.content.textContent || '{{amount}}'; + const currency = this.refs.facetStatus.dataset.currency || ''; + + return template.replace(/{{\s*(\w+)\s*}}/g, (_, placeholder) => { + if (typeof placeholder !== 'string') return ''; + if (placeholder === 'currency') return currency; + + let thousandsSeparator = ','; + let decimalSeparator = '.'; + let precision = CURRENCY_DECIMALS[currency.toUpperCase()] ?? DEFAULT_CURRENCY_DECIMALS; + + if (placeholder === 'amount') { + // Check first since it's the most common, use defaults. + } else if (placeholder === 'amount_no_decimals') { + precision = 0; + } else if (placeholder === 'amount_with_comma_separator') { + thousandsSeparator = '.'; + decimalSeparator = ','; + } else if (placeholder === 'amount_no_decimals_with_comma_separator') { + // Weirdly, this is correct. It uses amount_with_comma_separator's + // behaviour but removes decimals, resulting in an unintuitive + // output that can't possibly include commas, despite the name. + thousandsSeparator = '.'; + precision = 0; + } else if (placeholder === 'amount_no_decimals_with_space_separator') { + thousandsSeparator = ' '; + precision = 0; + } else if (placeholder === 'amount_with_space_separator') { + thousandsSeparator = ' '; + decimalSeparator = ','; + } else if (placeholder === 'amount_with_period_and_space_separator') { + thousandsSeparator = ' '; + decimalSeparator = '.'; + } else if (placeholder === 'amount_with_apostrophe_separator') { + thousandsSeparator = "'"; + decimalSeparator = '.'; + } + + return this.#formatCents(moneyValue, thousandsSeparator, decimalSeparator, precision); + }); + } + + /** + * Formats money in cents + * @param {number} moneyValue - The money value in cents (hundredths of one major currency unit) + * @param {string} thousandsSeparator - The thousands separator + * @param {string} decimalSeparator - The decimal separator + * @param {number} precision - The precision + * @returns {string} The formatted money value + */ + #formatCents(moneyValue, thousandsSeparator, decimalSeparator, precision) { + const roundedNumber = (moneyValue / 100).toFixed(precision); + + let [a, b] = roundedNumber.split('.'); + if (!a) a = '0'; + if (!b) b = ''; + + // Split by groups of 3 digits + a = a.replace(/\d(?=(\d\d\d)+(?!\d))/g, (digit) => digit + thousandsSeparator); + + return precision <= 0 ? a : a + decimalSeparator + b.padEnd(precision, '0'); + } + + /** + * Clears the summary + */ + clearSummary() { + this.refs.facetStatus.innerHTML = ''; + } +} + +if (!customElements.get('facet-status-component')) { + customElements.define('facet-status-component', FacetStatusComponent); +} + +/** + * Default currency decimals used in most currenies + * @constant {number} + */ +const DEFAULT_CURRENCY_DECIMALS = 2; + +/** + * Decimal precision for currencies that have a non-default precision + * @type {Record} + */ +const CURRENCY_DECIMALS = { + BHD: 3, + BIF: 0, + BYR: 0, + CLF: 4, + CLP: 0, + DJF: 0, + GNF: 0, + IQD: 3, + ISK: 0, + JOD: 3, + JPY: 0, + KMF: 0, + KRW: 0, + KWD: 3, + LYD: 3, + MRO: 5, + OMR: 3, + PYG: 0, + RWF: 0, + TND: 3, + UGX: 0, + UYI: 0, + UYW: 4, + VND: 0, + VUV: 0, + XAF: 0, + XAG: 0, + XAU: 0, + XBA: 0, + XBB: 0, + XBC: 0, + XBD: 0, + XDR: 0, + XOF: 0, + XPD: 0, + XPF: 0, + XPT: 0, + XSU: 0, + XTS: 0, + XUA: 0, +}; diff --git a/assets/floating-panel.js b/assets/floating-panel.js new file mode 100644 index 000000000..741b76cbf --- /dev/null +++ b/assets/floating-panel.js @@ -0,0 +1,60 @@ +import { debounce, requestIdleCallback, viewTransition } from '@theme/utilities'; + +const OFFSET = 40; + +/** + * A custom element that manages a floating panel. + */ +export class FloatingPanelComponent extends HTMLElement { + #updatePosition = async () => { + // Wait for any view transitions to finish + if (viewTransition.current) await viewTransition.current; + + const rect = this.getBoundingClientRect(); + const viewportWidth = window.innerWidth; + + this.style.top = OFFSET + 'px'; + + if (rect.right > viewportWidth) { + const overflowAmount = rect.right - viewportWidth + OFFSET; + this.style.left = `-${overflowAmount}px`; + } + + if (rect.left < 0) { + const overflowAmount = Math.abs(rect.left) + OFFSET; + this.style.left = `${overflowAmount}px`; + } + + this.#mutationObserver.takeRecords(); + }; + + #mutationObserver = new MutationObserver(this.#updatePosition); + + #resizeListener = debounce(() => { + const parent = this.closest('details'); + const closeOnResize = this.dataset.closeOnResize === 'true'; + if (parent instanceof HTMLDetailsElement && closeOnResize) { + parent.open = false; + parent.removeAttribute('open'); + this.#updatePosition(); + } + }, 100); + + connectedCallback() { + window.addEventListener('resize', this.#resizeListener); + + requestIdleCallback(() => { + this.#updatePosition(); + this.#mutationObserver.observe(this, { attributes: true }); + }); + } + + disconnectedCallback() { + window.removeEventListener('resize', this.#resizeListener); + this.#mutationObserver.disconnect(); + } +} + +if (!customElements.get('floating-panel-component')) { + customElements.define('floating-panel-component', FloatingPanelComponent); +} diff --git a/assets/focus.js b/assets/focus.js new file mode 100644 index 000000000..68dbb2026 --- /dev/null +++ b/assets/focus.js @@ -0,0 +1,104 @@ +// Store references to our event handlers so we can remove them. +/** @type {Record void>} */ +const trapFocusHandlers = {}; + +/** + * Get all focusable elements within a container. + * @param {HTMLElement} container - The container to get focusable elements from. + * @returns {HTMLElement[]} An array of focusable elements. + */ +function getFocusableElements(container) { + return Array.from( + container.querySelectorAll( + "summary, a[href], button:enabled, [tabindex]:not([tabindex^='-']), [draggable], area, input:not([type=hidden]):enabled, select:enabled, textarea:enabled, object, iframe" + ) + ); +} + +/** + * Trap focus within the given container. + * @param {HTMLElement} container - The container to trap focus within. + */ +export function trapFocus(container) { + // Clean up any previously set traps. + removeTrapFocus(); + + // Gather focusable elements. + const focusable = getFocusableElements(container); + if (!focusable.length) { + // If nothing is focusable, just abort—no need to trap. + return; + } + + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + + // Keydown handler for cycling focus with Tab and Shift+Tab + /** @type {(event: KeyboardEvent) => void} */ + trapFocusHandlers.keydown = (event) => { + if (event.key !== 'Tab') return; + + const activeEl = document.activeElement; + + // If on the last focusable and tabbing forward, go to first + if (!event.shiftKey && activeEl === last) { + event.preventDefault(); + first?.focus(); + } + // If on the first (or the container) and shift-tabbing, go to last + else if (event.shiftKey && (activeEl === first || activeEl === container)) { + event.preventDefault(); + last?.focus(); + } + }; + + // Focusin (capturing) handler to forcibly keep focus in the container + /** @type {(event: FocusEvent) => void} */ + trapFocusHandlers.focusin = (event) => { + // If the newly focused element isn't inside the container, redirect focus back. + if (event.target instanceof Node && !container.contains(event.target)) { + event.stopPropagation(); + // E.g., refocus the first focusable element: + first?.focus(); + } + }; + + // Attach the handlers + document.addEventListener('keydown', trapFocusHandlers.keydown, true); + // Use capture phase for focusin so we can catch it before it lands outside + document.addEventListener('focusin', trapFocusHandlers.focusin, true); + + // Finally, put focus where you want it. + container.focus(); +} + +/** + * Remove focus trap and optionally refocus another element. + */ +export function removeTrapFocus() { + trapFocusHandlers.keydown && document.removeEventListener('keydown', trapFocusHandlers.keydown, true); + trapFocusHandlers.focusin && document.removeEventListener('focusin', trapFocusHandlers.focusin, true); +} + +/** + * Cycle focus to the next or previous link + * + * @param {HTMLElement[]} items + * @param {number} increment + */ +export function cycleFocus(items, increment) { + const currentIndex = items.findIndex((item) => item.matches(':focus')); + let targetIndex = currentIndex + increment; + + if (targetIndex >= items.length) { + targetIndex = 0; + } else if (targetIndex < 0) { + targetIndex = items.length - 1; + } + + const targetItem = items[targetIndex]; + + if (!targetItem) return; + + targetItem.focus(); +} diff --git a/assets/global.d.ts b/assets/global.d.ts new file mode 100644 index 000000000..1040e5054 --- /dev/null +++ b/assets/global.d.ts @@ -0,0 +1,72 @@ +export {}; + +declare global { + interface Shopify { + country: string; + currency: { + active: string; + rate: string; + }; + designMode: boolean; + locale: string; + shop: string; + loadFeatures(features: ShopifyFeature[], callback?: LoadCallback): void; + ModelViewerUI?: ModelViewer; + visualPreviewMode: boolean; + } + + interface Theme { + translations: Record; + placeholders: { + general: string[]; + product: string[]; + }; + routes: { + cart_add_url: string; + cart_change_url: string; + cart_update_url: string; + cart_url: string; + predictive_search_url: string; + search_url: string; + }; + utilities: { + scheduler: { + schedule: (task: () => void) => void; + }; + }; + template: { + name: string; + }; + } + + interface Window { + Shopify: Shopify; + } + + declare const Shopify: Shopify; + declare const Theme: Theme; + + type LoadCallback = (error: Error | undefined) => void; + + // Refer to https://github.com/Shopify/shopify/blob/main/areas/core/shopify/app/assets/javascripts/storefront/load_feature/load_features.js + interface ShopifyFeature { + name: string; + version: string; + onLoad?: LoadCallback; + } + + // Refer to https://github.com/Shopify/model-viewer-ui/blob/main/src/js/model-viewer-ui.js + interface ModelViewer { + new ( + element: Element, + options?: { + focusOnPlay?: boolean; + } + ): ModelViewer; + play(): void; + pause(): void; + toggleFullscreen(): void; + zoom(amount: number): void; + destroy(): void; + } +} diff --git a/assets/header-drawer.js b/assets/header-drawer.js new file mode 100644 index 000000000..04bf5961d --- /dev/null +++ b/assets/header-drawer.js @@ -0,0 +1,155 @@ +import { Component } from '@theme/component'; +import { trapFocus, removeTrapFocus } from '@theme/focus'; +import { onAnimationEnd } from '@theme/utilities'; + +/** + * A custom element that manages the main menu drawer. + * + * @typedef {object} Refs + * @property {HTMLDetailsElement} details - The details element. + * + * @extends {Component} + */ +class HeaderDrawer extends Component { + requiredRefs = ['details']; + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener('keyup', this.#onKeyUp); + this.#setupAnimatedElementListeners(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.removeEventListener('keyup', this.#onKeyUp); + } + + /** + * Close the main menu drawer when the Escape key is pressed + * @param {KeyboardEvent} event + */ + #onKeyUp = (event) => { + if (event.key !== 'Escape') return; + + this.#close(this.#getDetailsElement(event)); + }; + + /** + * @returns {boolean} Whether the main menu drawer is open + */ + get isOpen() { + return this.refs.details.hasAttribute('open'); + } + + /** + * Get the closest details element to the event target + * @param {Event | undefined} event + * @returns {HTMLDetailsElement} + */ + #getDetailsElement(event) { + if (!(event?.target instanceof Element)) return this.refs.details; + + return event.target.closest('details') ?? this.refs.details; + } + + /** + * Toggle the main menu drawer + */ + toggle() { + return this.isOpen ? this.close() : this.open(); + } + + /** + * Open the closest drawer or the main menu drawer + * @param {Event} [event] + */ + open(event) { + const details = this.#getDetailsElement(event); + const summary = details.querySelector('summary'); + + if (!summary) return; + + summary.setAttribute('aria-expanded', 'true'); + requestAnimationFrame(() => details.classList.add('menu-open')); + + trapFocus(details); + } + + /** + * Go back or close the main menu drawer + * @param {Event} [event] + */ + back(event) { + this.#close(this.#getDetailsElement(event)); + } + + /** + * Close the main menu drawer + */ + close() { + this.#close(this.refs.details); + } + + /** + * Close the closest menu or submenu that is open + * + * @param {HTMLDetailsElement} details + */ + #close(details) { + const summary = details.querySelector('summary'); + + if (!summary) return; + + summary.setAttribute('aria-expanded', 'false'); + details.classList.remove('menu-open'); + + onAnimationEnd(details, () => { + reset(details); + + if (details === this.refs.details) { + removeTrapFocus(); + const openDetails = this.querySelectorAll('details[open]'); + openDetails.forEach(reset); + } else { + trapFocus(this.refs.details); + } + }); + } + + /** + * Attach animationend event listeners to all animated elements to remove will-change after animation + * to remove the stacking context and allow submenus to be positioned correctly + */ + #setupAnimatedElementListeners() { + /** + * @param {AnimationEvent} event + */ + function removeWillChangeOnAnimationEnd(event) { + const target = event.target; + if (target && target instanceof HTMLElement) { + target.style.setProperty('will-change', 'unset'); + target.removeEventListener('animationend', removeWillChangeOnAnimationEnd); + } + } + const allAnimated = this.querySelectorAll('.menu-drawer__animated-element'); + allAnimated.forEach((element) => { + element.addEventListener('animationend', removeWillChangeOnAnimationEnd); + }); + } +} + +if (!customElements.get('header-drawer')) { + customElements.define('header-drawer', HeaderDrawer); +} + +/** + * Reset an open details element to its original state + * + * @param {HTMLDetailsElement} element + */ +function reset(element) { + element.classList.remove('menu-open'); + element.removeAttribute('open'); + element.querySelector('summary')?.setAttribute('aria-expanded', 'false'); +} diff --git a/assets/header-menu.js b/assets/header-menu.js new file mode 100644 index 000000000..5ae9c6a81 --- /dev/null +++ b/assets/header-menu.js @@ -0,0 +1,214 @@ +import { Component } from '@theme/component'; +import { debounce, onDocumentReady } from '@theme/utilities'; +import { MegaMenuHoverEvent } from '@theme/events'; + +const ACTIVATE_DELAY = 0; +const DEACTIVATE_DELAY = 350; + +/** + * A custom element that manages a header menu. + * + * @typedef {Object} State + * @property {HTMLElement | null} activeItem - The currently active menu item. + * + * @typedef {object} Refs + * @property {HTMLElement} overflowMenu - The overflow menu. + * @property {HTMLElement[]} [submenu] - The submenu in each respective menu item. + * + * @extends {Component} + */ +class HeaderMenu extends Component { + requiredRefs = ['overflowMenu']; + + #abortController = new AbortController(); + + connectedCallback() { + super.connectedCallback(); + + this.overflowMenu?.addEventListener('pointerleave', () => this.#debouncedDeactivate(), { + signal: this.#abortController.signal, + }); + + onDocumentReady(this.#preloadImages); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#abortController.abort(); + } + + /** + * @type {State} + */ + #state = { + activeItem: null, + }; + + /** + * Time to allow for a closing animation between initiating a deactivation and actually deactivating the active item. + * @returns {number} + */ + get animationDelay() { + const value = this.dataset.animationDelay; + return value ? parseInt(value, 10) : 0; + } + + /** + * Get the overflow menu + */ + get overflowMenu() { + return /** @type {HTMLElement | null} */ (this.refs.overflowMenu?.shadowRoot?.querySelector('[part="overflow"]')); + } + + /** + * Whether the overflow menu is hovered + * @returns {boolean} + */ + get overflowHovered() { + return this.refs.overflowMenu?.matches(':hover') ?? false; + } + + /** + * Activate the selected menu item immediately + * @param {PointerEvent | FocusEvent} event + */ + activate = (event) => { + this.#debouncedDeactivate.cancel(); + this.#debouncedActivateHandler.cancel(); + + this.#debouncedActivateHandler(event); + }; + + /** + * Activate the selected menu item with a delay + * @param {PointerEvent | FocusEvent} event + */ + #activateHandler = (event) => { + this.#debouncedDeactivate.cancel(); + + this.dispatchEvent(new MegaMenuHoverEvent()); + + this.removeAttribute('data-animating'); + + if (!(event.target instanceof Element)) return; + + let item = findMenuItem(event.target); + + if (!item || item == this.#state.activeItem) return; + + const isDefaultSlot = event.target.slot === ''; + + this.dataset.overflowExpanded = (!isDefaultSlot).toString(); + + const previouslyActiveItem = this.#state.activeItem; + + if (previouslyActiveItem) { + previouslyActiveItem.ariaExpanded = 'false'; + } + + this.#state.activeItem = item; + this.ariaExpanded = 'true'; + item.ariaExpanded = 'true'; + + let submenu = findSubmenu(item); + let overflowMenuHeight = this.overflowMenu?.offsetHeight ?? 0; + + if (!submenu && !isDefaultSlot) { + submenu = this.overflowMenu; + } + + const submenuHeight = submenu ? Math.max(submenu.offsetHeight, overflowMenuHeight) : 0; + + this.style.setProperty('--submenu-height', `${submenuHeight}px`); + this.style.setProperty('--submenu-opacity', '1'); + }; + + #debouncedActivateHandler = debounce(this.#activateHandler, ACTIVATE_DELAY); + + /** + * Deactivate the active item after a delay + * @param {PointerEvent | FocusEvent} event + */ + deactivate(event) { + this.#debouncedActivateHandler.cancel(); + + if (!(event.target instanceof Element)) return; + + const item = findMenuItem(event.target); + + // Make sure the item to be deactivated is still the active one. Ideally + // we cancelled the debounce before the item was changed, but just in case. + if (item === this.#state.activeItem) { + this.#debouncedDeactivate(); + } + } + + /** + * Deactivate the active item immediately + * @param {HTMLElement | null} [item] + */ + #deactivate = (item = this.#state.activeItem) => { + if (!item || item != this.#state.activeItem) return; + if (this.overflowHovered) return; + + this.style.setProperty('--submenu-height', '0px'); + this.style.setProperty('--submenu-opacity', '0'); + this.dataset.overflowExpanded = 'false'; + + this.#state.activeItem = null; + this.ariaExpanded = 'false'; + item.ariaExpanded = 'false'; + item.setAttribute('data-animating', ''); + + setTimeout( + () => { + item.removeAttribute('data-animating'); + }, + Math.max(0, this.animationDelay - 150) + ); // Start header transition 150ms before submenu finishes + }; + + /** + * Deactivate the active item after a delay + * @param {PointerEvent | FocusEvent} event + */ + #debouncedDeactivate = debounce(this.#deactivate, DEACTIVATE_DELAY); + + /** + * Preload images that are set to load lazily. + */ + #preloadImages = () => { + const images = this.querySelectorAll('img[loading="lazy"]'); + images?.forEach((image) => image.removeAttribute('loading')); + }; +} + +if (!customElements.get('header-menu')) { + customElements.define('header-menu', HeaderMenu); +} + +/** + * Find the closest menu item. + * @param {Element | null | undefined} element + * @returns {HTMLElement | null} + */ +function findMenuItem(element) { + if (!(element instanceof Element)) return null; + + if (element?.matches('[slot="more"')) { + // Select the first overflowing menu item when hovering over the "More" item + return findMenuItem(element.parentElement?.querySelector('[slot="overflow"]')); + } + + return element?.querySelector('[ref="menuitem"]'); +} + +/** + * Find the closest submenu. + * @param {Element | null | undefined} element + * @returns {HTMLElement | null} + */ +function findSubmenu(element) { + const submenu = element?.parentElement?.querySelector('[ref="submenu[]"]'); + return submenu instanceof HTMLElement ? submenu : null; +} diff --git a/assets/header.js b/assets/header.js new file mode 100644 index 000000000..aed8bf779 --- /dev/null +++ b/assets/header.js @@ -0,0 +1,245 @@ +import { Component } from '@theme/component'; +import { onDocumentReady, changeMetaThemeColor } from '@theme/utilities'; + +/** + * @typedef {Object} HeaderComponentRefs + * @property {HTMLDivElement} headerDrawerContainer - The header drawer container element + * @property {HTMLElement} headerMenu - The header menu element + * @property {HTMLElement} headerRowTop - The header top row element + */ + +/** + * @typedef {CustomEvent<{ minimumReached: boolean }>} OverflowMinimumEvent + */ + +/** + * A custom element that manages the site header. + * + * @extends {Component} + */ + +class HeaderComponent extends Component { + requiredRefs = ['headerDrawerContainer', 'headerMenu', 'headerRowTop']; + + /** + * Width of window when header drawer was hidden + * @type {number | null} + */ + #menuDrawerHiddenWidth = null; + + /** + * An intersection observer for monitoring sticky header position + * @type {IntersectionObserver | null} + */ + #intersectionObserver = null; + + /** + * Whether the header has been scrolled offscreen, when sticky behavior is 'scroll-up' + * @type {boolean} + */ + #offscreen = false; + + /** + * The last recorded scrollTop of the document, when sticky behavior is 'scroll-up + * @type {number} + */ + #lastScrollTop = 0; + + /** + * A timeout to allow for hiding animation, when sticky behavior is 'scroll-up' + * @type {number | null} + */ + #timeout = null; + + /** + * The duration to wait for hiding animation, when sticky behavior is 'scroll-up' + * @constant {number} + */ + #animationDelay = 150; + + /** + * Keeps the global `--header-height` custom property up to date, + * which other theme components can then consume + */ + #resizeObserver = new ResizeObserver(([entry]) => { + if (!entry) return; + + const { height } = entry.target.getBoundingClientRect(); + document.body.style.setProperty('--header-height', `${height}px`); + + // Check if the menu drawer should be hidden in favor of the header menu + if (this.#menuDrawerHiddenWidth && window.innerWidth > this.#menuDrawerHiddenWidth) { + this.#updateMenuVisibility(false); + } + }); + + /** + * Observes the header while scrolling the viewport to track when its actively sticky + * @param {Boolean} alwaysSticky - Determines if we need to observe when the header is offscreen + */ + #observeStickyPosition = (alwaysSticky = true) => { + if (this.#intersectionObserver) return; + + const config = { + threshold: alwaysSticky ? 1 : 0, + }; + + this.#intersectionObserver = new IntersectionObserver(([entry]) => { + if (!entry) return; + + const { isIntersecting } = entry; + + if (alwaysSticky) { + this.dataset.stickyState = isIntersecting ? 'inactive' : 'active'; + changeMetaThemeColor(this.refs.headerRowTop); + } else { + this.#offscreen = !isIntersecting || this.dataset.stickyState === 'active'; + } + }, config); + + this.#intersectionObserver.observe(this); + }; + + /** + * Handles the overflow minimum event from the header menu + * @param {OverflowMinimumEvent} event + */ + #handleOverflowMinimum = (event) => { + this.#updateMenuVisibility(event.detail.minimumReached); + }; + + /** + * Updates the visibility of the menu and drawer + * @param {boolean} hideMenu - Whether to hide the menu and show the drawer + */ + #updateMenuVisibility(hideMenu) { + if (hideMenu) { + this.refs.headerDrawerContainer.classList.remove('desktop:hidden'); + this.#menuDrawerHiddenWidth = window.innerWidth; + this.refs.headerMenu.classList.add('hidden'); + } else { + this.refs.headerDrawerContainer.classList.add('desktop:hidden'); + this.#menuDrawerHiddenWidth = null; + this.refs.headerMenu.classList.remove('hidden'); + } + } + + #handleWindowScroll = () => { + const stickyMode = this.getAttribute('sticky'); + if (!this.#offscreen && stickyMode !== 'always') return; + + const scrollTop = document.scrollingElement?.scrollTop ?? 0; + const isScrollingUp = scrollTop < this.#lastScrollTop; + if (this.#timeout) { + clearTimeout(this.#timeout); + this.#timeout = null; + } + + if (stickyMode === 'always') { + if (isScrollingUp) { + if (this.getBoundingClientRect().top >= 0) { + this.dataset.scrollDirection = 'none'; + } else { + this.dataset.scrollDirection = 'up'; + } + } else { + this.dataset.scrollDirection = 'down'; + } + + this.#lastScrollTop = scrollTop; + return; + } + + if (isScrollingUp) { + this.removeAttribute('data-animating'); + + if (this.getBoundingClientRect().top >= 0) { + // reset sticky state when header is scrolled up to natural position + this.#offscreen = false; + this.dataset.stickyState = 'inactive'; + this.dataset.scrollDirection = 'none'; + } else { + // show sticky header when scrolling up + this.dataset.stickyState = 'active'; + this.dataset.scrollDirection = 'up'; + } + } else if (this.dataset.stickyState === 'active') { + this.dataset.scrollDirection = 'none'; + // delay transitioning to idle hidden state for hiding animation + this.setAttribute('data-animating', ''); + + this.#timeout = setTimeout(() => { + this.dataset.stickyState = 'idle'; + this.removeAttribute('data-animating'); + }, this.#animationDelay); + } else { + this.dataset.scrollDirection = 'none'; + this.dataset.stickyState = 'idle'; + } + + this.#lastScrollTop = scrollTop; + }; + + connectedCallback() { + super.connectedCallback(); + this.#resizeObserver.observe(this); + this.addEventListener('overflowMinimum', this.#handleOverflowMinimum); + + const stickyMode = this.getAttribute('sticky'); + if (stickyMode) { + this.#observeStickyPosition(stickyMode === 'always'); + + if (stickyMode === 'scroll-up' || stickyMode === 'always') { + document.addEventListener('scroll', this.#handleWindowScroll); + } + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#resizeObserver.disconnect(); + this.#intersectionObserver?.disconnect(); + this.removeEventListener('overflowMinimum', this.#handleOverflowMinimum); + document.removeEventListener('scroll', this.#handleWindowScroll); + document.body.style.setProperty('--header-height', '0px'); + } +} + +if (!customElements.get('header-component')) { + customElements.define('header-component', HeaderComponent); +} + +onDocumentReady(() => { + const header = document.querySelector('#header-component'); + const headerGroup = document.querySelector('#header-group'); + + // Update header group height on resize of any child + if (headerGroup) { + const resizeObserver = new ResizeObserver(() => calculateHeaderGroupHeight(header, headerGroup)); + + // Observe all children of the header group + const children = headerGroup.children; + for (let i = 0; i < children.length; i++) { + const element = children[i]; + if (element === header || !(element instanceof HTMLElement)) continue; + resizeObserver.observe(element); + } + + // Also observe the header group itself for child changes + const mutationObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.type === 'childList') { + // Re-observe all children when the list changes + const children = headerGroup.children; + for (let i = 0; i < children.length; i++) { + const element = children[i]; + if (element === header || !(element instanceof HTMLElement)) continue; + resizeObserver.observe(element); + } + } + } + }); + + mutationObserver.observe(headerGroup, { childList: true }); + } +}); diff --git a/assets/icon-account.svg b/assets/icon-account.svg new file mode 100644 index 000000000..c808d3969 --- /dev/null +++ b/assets/icon-account.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-add-to-cart.svg b/assets/icon-add-to-cart.svg new file mode 100644 index 000000000..1c0d45bd9 --- /dev/null +++ b/assets/icon-add-to-cart.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-arrow.svg b/assets/icon-arrow.svg new file mode 100644 index 000000000..16f6d5713 --- /dev/null +++ b/assets/icon-arrow.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-available.svg b/assets/icon-available.svg new file mode 100644 index 000000000..7f2c4d0f4 --- /dev/null +++ b/assets/icon-available.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-caret.svg b/assets/icon-caret.svg new file mode 100644 index 000000000..801553ab3 --- /dev/null +++ b/assets/icon-caret.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-cart.svg b/assets/icon-cart.svg new file mode 100644 index 000000000..a9a2fb206 --- /dev/null +++ b/assets/icon-cart.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-checkmark.svg b/assets/icon-checkmark.svg new file mode 100644 index 000000000..3c12fa0b9 --- /dev/null +++ b/assets/icon-checkmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-close.svg b/assets/icon-close.svg new file mode 100644 index 000000000..399230076 --- /dev/null +++ b/assets/icon-close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-delete.svg b/assets/icon-delete.svg new file mode 100644 index 000000000..c85af510a --- /dev/null +++ b/assets/icon-delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-discount.svg b/assets/icon-discount.svg new file mode 100644 index 000000000..096c64219 --- /dev/null +++ b/assets/icon-discount.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-error.svg b/assets/icon-error.svg new file mode 100644 index 000000000..a282b048b --- /dev/null +++ b/assets/icon-error.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icon-external.svg b/assets/icon-external.svg new file mode 100644 index 000000000..fbd780b89 --- /dev/null +++ b/assets/icon-external.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-filter.svg b/assets/icon-filter.svg new file mode 100644 index 000000000..060a5d3f1 --- /dev/null +++ b/assets/icon-filter.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-filters-close.svg b/assets/icon-filters-close.svg new file mode 100644 index 000000000..fde33377e --- /dev/null +++ b/assets/icon-filters-close.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icon-grid-default.svg b/assets/icon-grid-default.svg new file mode 100644 index 000000000..ee6db80d9 --- /dev/null +++ b/assets/icon-grid-default.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icon-grid-dense.svg b/assets/icon-grid-dense.svg new file mode 100644 index 000000000..804805035 --- /dev/null +++ b/assets/icon-grid-dense.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icon-inventory.svg b/assets/icon-inventory.svg new file mode 100644 index 000000000..d0b3c462d --- /dev/null +++ b/assets/icon-inventory.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icon-menu.svg b/assets/icon-menu.svg new file mode 100644 index 000000000..2c5098734 --- /dev/null +++ b/assets/icon-menu.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-minus.svg b/assets/icon-minus.svg new file mode 100644 index 000000000..423ebbac1 --- /dev/null +++ b/assets/icon-minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-one-col-mobile.svg b/assets/icon-one-col-mobile.svg new file mode 100644 index 000000000..efd2fe341 --- /dev/null +++ b/assets/icon-one-col-mobile.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-orders.svg b/assets/icon-orders.svg new file mode 100644 index 000000000..e78ac475c --- /dev/null +++ b/assets/icon-orders.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-pause.svg b/assets/icon-pause.svg new file mode 100644 index 000000000..7255cacbc --- /dev/null +++ b/assets/icon-pause.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-play.svg b/assets/icon-play.svg new file mode 100644 index 000000000..a979b2f45 --- /dev/null +++ b/assets/icon-play.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon-plus.svg b/assets/icon-plus.svg new file mode 100644 index 000000000..b845e454d --- /dev/null +++ b/assets/icon-plus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icon-reset.svg b/assets/icon-reset.svg new file mode 100644 index 000000000..182ed125e --- /dev/null +++ b/assets/icon-reset.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-search.svg b/assets/icon-search.svg new file mode 100644 index 000000000..83af677e1 --- /dev/null +++ b/assets/icon-search.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-shopify.svg b/assets/icon-shopify.svg new file mode 100644 index 000000000..b6a58bf8d --- /dev/null +++ b/assets/icon-shopify.svg @@ -0,0 +1 @@ + diff --git a/assets/icon-unavailable.svg b/assets/icon-unavailable.svg new file mode 100644 index 000000000..73dfbc913 --- /dev/null +++ b/assets/icon-unavailable.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/jsconfig.json b/assets/jsconfig.json new file mode 100644 index 000000000..a3b03770a --- /dev/null +++ b/assets/jsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "checkJs": true, + "target": "ES2020", + "noImplicitAny": true, + "noUncheckedIndexedAccess": true, + "strictNullChecks": true, + "types": ["./global.d.ts"], + "paths": { + "@theme/*": ["./*"] + } + } +} diff --git a/assets/jumbo-text.js b/assets/jumbo-text.js new file mode 100644 index 000000000..1e04eb3ee --- /dev/null +++ b/assets/jumbo-text.js @@ -0,0 +1,151 @@ +import { prefersReducedMotion } from '@theme/utilities'; + +/** + * A custom element that automatically sizes text to fit its container width. + */ +class JumboText extends HTMLElement { + connectedCallback() { + // Initial calculation + requestAnimationFrame(this.#handleResize); + if (this.dataset.textEffect && this.dataset.textEffect !== 'none' && !prefersReducedMotion()) { + this.#setIntersectionObserver(); + } + } + + disconnectedCallback() { + this.#resizeObserver.disconnect(); + if (this.dataset.textEffect && this.dataset.textEffect !== 'none' && !prefersReducedMotion()) { + this.intersectionObserver?.disconnect(); + } + } + + /** + * Sets the intersection observer to calculate the optimal font size when the text is in view + */ + #setIntersectionObserver() { + // The threshold could be different based on the repetition of the animation. + this.intersectionObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + this.classList.add('jumbo-text-visible'); + if (this.dataset.animationRepeat === 'false') { + this.intersectionObserver.unobserve(entry.target); + } + } else { + this.classList.remove('jumbo-text-visible'); + } + }); + }, + { threshold: 0.3 } + ); + + this.intersectionObserver.observe(this); + } + + /** + * Calculates the optimal font size to make the text fit the container width + */ + #calculateOptimalFontSize = () => { + // Check for empty text + if (!this.textContent?.trim()) { + return; + } + + // Hide text during calculation + this.classList.remove('ready'); + + if (this.offsetWidth <= 0) return; + + // Disconnect the resize observer + this.#resizeObserver.disconnect(); + + // Start with a minimal font size + this.style.fontSize = '1px'; + + // Find the optimal font size + const fontSize = findOptimalFontSize(this, this.offsetWidth); + + // Apply the final size + this.style.fontSize = `${fontSize}px`; + + // Reconnect the resize observer + this.#resizeObserver.observe(this); + + // Show the text + this.classList.add('ready'); + }; + + #handleResize = () => { + this.#calculateOptimalFontSize(); + + // Calculate distance from bottom of page, when the jumb text is close to the bottom of the page then force it + // to use `cap text` instead of `cap alphabetic` to not cause any extra padding below the bottom of the page. + const rect = this.getBoundingClientRect(); + const bottom = rect.bottom + window.scrollY; + const distanceFromBottom = document.documentElement.offsetHeight - bottom; + this.dataset.capText = (distanceFromBottom <= 100).toString(); + }; + + #resizeObserver = new ResizeNotifier(this.#handleResize); +} + +/** + * Checks if text with the given font size overflows the container + * @param {HTMLElement} element - The element to check + * @param {number} containerWidth - The width of the container + * @param {number} size - Font size to check + * @returns {boolean} - True if text overflows + */ +function checkTextOverflow(element, containerWidth, size) { + element.style.fontSize = `${size}px`; + return element.scrollWidth > containerWidth; +} + +/** + * Find optimal font size using binary search + * @param {HTMLElement} element - The text element + * @param {number} containerWidth - Available width + * @returns {number} - The optimal font size + */ +function findOptimalFontSize(element, containerWidth) { + // Binary search parameters + let minSize = 1; + let maxSize = 500; + const precision = 0.5; + + // Initial guess based on container width and text length + const textLength = element.textContent?.length || 0; + let fontSize = Math.min(maxSize, Math.sqrt(containerWidth) * (15 / Math.sqrt(Math.max(1, textLength)))); + + // Adjust initial bounds based on first check + if (checkTextOverflow(element, containerWidth, fontSize)) { + maxSize = fontSize; + } else { + minSize = fontSize; + } + + // Binary search implementation + let iterations = 0; + const MAX_ITERATIONS = 30; + + while (maxSize - minSize > precision && iterations < MAX_ITERATIONS) { + fontSize = (minSize + maxSize) / 2; + + if (checkTextOverflow(element, containerWidth, fontSize)) { + maxSize = fontSize; + } else { + minSize = fontSize; + } + + iterations++; + } + + // Add a small safety margin + return minSize * 0.99; +} + +// Register once +if (!customElements.get('jumbo-text')) { + customElements.define('jumbo-text', JumboText); +} diff --git a/assets/local-pickup.js b/assets/local-pickup.js new file mode 100644 index 000000000..4200446d7 --- /dev/null +++ b/assets/local-pickup.js @@ -0,0 +1,79 @@ +import { Component } from '@theme/component'; +import { morph } from '@theme/morph'; +import { ThemeEvents, VariantUpdateEvent } from '@theme/events'; + +class LocalPickup extends Component { + /** @type {AbortController | undefined} */ + #activeFetch; + + connectedCallback() { + super.connectedCallback(); + + const closestSection = this.closest(`.shopify-section, dialog`); + + /** @type {(event: VariantUpdateEvent) => void} */ + const variantUpdated = (event) => { + if (event.detail.data.newProduct) { + this.dataset.productUrl = event.detail.data.newProduct.url; + } + + const variantId = event.detail.resource ? event.detail.resource.id : null; + const variantAvailable = event.detail.resource ? event.detail.resource.available : null; + if (variantId !== this.dataset.variantId) { + if (variantId && variantAvailable) { + this.removeAttribute('hidden'); + this.dataset.variantId = variantId; + this.#fetchAvailability(variantId); + } else { + this.setAttribute('hidden', ''); + } + } + }; + + closestSection?.addEventListener(ThemeEvents.variantUpdate, variantUpdated); + + this.disconnectedCallback = () => { + closestSection?.removeEventListener(ThemeEvents.variantUpdate, variantUpdated); + }; + } + + #createAbortController() { + if (this.#activeFetch) this.#activeFetch.abort(); + this.#activeFetch = new AbortController(); + return this.#activeFetch; + } + + /** + * Fetches the availability of a variant. + * @param {string} variantId - The ID of the variant to fetch availability for. + */ + #fetchAvailability = (variantId) => { + if (!variantId) return; + + const abortController = this.#createAbortController(); + + const url = this.dataset.productUrl; + fetch(`${url}?variant=${variantId}§ion_id=${this.dataset.sectionId}`, { + signal: abortController.signal, + }) + .then((response) => response.text()) + .then((text) => { + if (abortController.signal.aborted) return; + + const html = new DOMParser().parseFromString(text, 'text/html'); + const wrapper = html.querySelector(`local-pickup[data-variant-id="${variantId}"]`); + if (wrapper) { + this.removeAttribute('hidden'); + morph(this, wrapper); + } else this.setAttribute('hidden', ''); + }) + .catch((_e) => { + if (abortController.signal.aborted) return; + this.setAttribute('hidden', ''); + }); + }; +} + +if (!customElements.get('local-pickup')) { + customElements.define('local-pickup', LocalPickup); +} diff --git a/assets/localization.js b/assets/localization.js new file mode 100644 index 000000000..aaefbe36f --- /dev/null +++ b/assets/localization.js @@ -0,0 +1,548 @@ +import { Component } from '@theme/component'; +import { isClickedOutside, normalizeString, onAnimationEnd } from '@theme/utilities'; + +/** + * A custom element that displays a localization form. + * + * @typedef {object} FormRefs + * @property {HTMLDivElement} countryList - The country list element. + * @property {HTMLInputElement} countryInput - The country input element. + * @property {HTMLUListElement[]} countryListItems - The country list items element. + * @property {HTMLFormElement} form - The form element. + * @property {HTMLDivElement} liveRegion - The live region element. + * @property {HTMLSelectElement} languageInput - The language input element. + * @property {HTMLSpanElement} noResultsMessage - The no results message element. + * @property {HTMLUListElement} popularCountries - The popular countries element. + * @property {HTMLInputElement} search - The search input element. + * @property {HTMLButtonElement} resetButton - The reset button element. + * + * @extends {Component} + */ +class LocalizationFormComponent extends Component { + connectedCallback() { + super.connectedCallback(); + + this.refs.search && this.refs.search.addEventListener('keydown', this.#onSearchKeyDown); + this.refs.countryList && this.refs.countryList.addEventListener('keydown', this.#onContainerKeyDown); + this.refs.countryList && this.refs.countryList.addEventListener('scroll', this.#onCountryListScroll); + + this.resizeLanguageInput(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.refs.search && this.refs.search.removeEventListener('keydown', this.#onSearchKeyDown); + this.refs.countryList && this.refs.countryList.removeEventListener('keydown', this.#onContainerKeyDown); + this.refs.countryList && this.refs.countryList.removeEventListener('scroll', this.#onCountryListScroll); + } + + /** + * Handles the keydown event for the container. + * + * @param {KeyboardEvent} event - The event object. + */ + #onContainerKeyDown = (event) => { + const { countryInput, countryListItems, form } = this.refs; + + switch (event.key) { + case 'ArrowUp': + event.preventDefault(); + event.stopPropagation(); + this.#changeCountryFocus('UP'); + break; + case 'ArrowDown': + event.preventDefault(); + event.stopPropagation(); + this.#changeCountryFocus('DOWN'); + break; + case 'Enter': + event.preventDefault(); + event.stopPropagation(); + const focusedItem = countryListItems.find((item) => item.getAttribute('aria-selected') === 'true'); + + if (focusedItem) { + countryInput.value = focusedItem.dataset.value ?? ''; + form.submit(); + } + break; + } + + if (!this.refs.search) return; + + setTimeout(() => { + const focusableItems = this.refs.countryListItems.filter((item) => !item.hasAttribute('hidden')); + const focusedItemIndex = focusableItems.findIndex((item) => item === document.activeElement); + const focusedItem = focusableItems[focusedItemIndex]; + + if (focusedItem) { + this.refs.search.setAttribute('aria-activedescendant', focusedItem.id); + } else { + this.refs.search.setAttribute('aria-activedescendant', ''); + } + }); + }; + + /** + * Selects a country. + * + * @param {string} countryName - The name of the country to select. + * @param {Event} event - The event object. + */ + selectCountry = (countryName, event) => { + event.preventDefault(); + const { countryInput, form } = this.refs; + + countryInput.value = countryName; + form?.submit(); + }; + + /** + * Changes the language of the localization form. + * + * @param {Event} event - The event object. + */ + changeLanguage(event) { + const { form, languageInput } = this.refs; + const value = event.target instanceof HTMLSelectElement ? event.target.value : null; + + if (value) { + languageInput.value = value; + this.resizeLanguageInput(); + form.submit(); + } + } + + resizeLanguageInput() { + const { languageInput } = this.refs; + + if (!languageInput) return; + + // Hide all options except the selected option + for (const option of languageInput.options) { + if (!option.selected) { + option.dataset.optionLabel = option.textContent || ''; + option.innerText = ''; + } + } + + // Calculate the width of the select element (which is based on the width of the widest option) + languageInput.style.width = 'fit-content'; + const originalElementWidth = `${Math.ceil(languageInput.offsetWidth) + 1}px`; + + // Fix the width of the select element + if (languageInput.offsetWidth > 0) { + languageInput.style.width = originalElementWidth; + } + + // Add back all option labels + for (const option of languageInput.options) { + if (option.dataset.optionLabel) { + option.textContent = option.dataset.optionLabel; + delete option.dataset.optionLabel; + } + } + } + + /** + * Finds matches for a given search value in a country element. + * + * @typedef {Object} Options + * @property {boolean} [matchLabel] - Whether to match the label. + * @property {boolean} [matchAlias] - Whether to match the alias. + * @property {boolean} [matchIso] - Whether to match the iso. + * @property {boolean} [matchCurrency] - Whether to match the currency. + * @property {boolean} [labelMatchStart] - Whether to match the label start. + * @property {boolean} [aliasExactMatch] - Whether to match the alias exact match. + * + * @typedef {Object} MatchTypes + * @property {boolean} [label] - Whether the label matches the search value. + * @property {boolean} [alias] - Whether the alias matches the search value. + * @property {boolean} [iso] - Whether the iso matches the search value. + * @property {boolean} [currency] - Whether the currency matches the search value. + * + * @param {string} searchValue - The search value to find matches for. + * @param {HTMLElement} countryEl - The country element to find matches in. + * @param {Options} options - The options for the search. + * @returns {MatchTypes} The matches found in the country element. + */ + #findMatches( + searchValue, + countryEl, + options = { + // Which data types (label, alias, iso) to match against + matchLabel: true, + matchAlias: true, + matchIso: true, + matchCurrency: true, + // If true, the search value must match the start of the label + labelMatchStart: false, + // If true, a result will not display unless the search value equals an alias in its entirety + aliasExactMatch: false, + } + ) { + let matchTypes = {}; + const { aliases, value: iso } = countryEl.dataset; + + if (options.matchLabel) { + const countryName = normalizeString(countryEl.querySelector('.country')?.textContent ?? ''); + + if (!countryName) return matchTypes; + + matchTypes.label = options.labelMatchStart + ? countryName.startsWith(searchValue) + : countryName.includes(searchValue); + } + + if (options.matchCurrency) { + const currency = normalizeString(countryEl.querySelector('.localization-form__currency')?.textContent ?? ''); + matchTypes.currency = currency.includes(searchValue); + } + + if (options.matchIso) { + matchTypes.iso = normalizeString(iso ?? '') == searchValue; + } + + if (options.matchAlias) { + const countryAliases = aliases?.split(',').map((alias) => normalizeString(alias)); + + if (!countryAliases) return matchTypes; + + matchTypes.alias = + countryAliases.length > 0 && + countryAliases.find((alias) => + options.aliasExactMatch ? alias === searchValue : alias.startsWith(searchValue) + ) !== undefined; + } + + return matchTypes; + } + + /** + * Highlights matching text in a string by wrapping it in tags. + * + * @param {string | null} text - The text to highlight. + * @param {string} searchValue - The search value to highlight. + * @returns {string} The text with matching parts wrapped in tags. + */ + #highlightMatches(text, searchValue) { + if (!text || !searchValue) return text ?? ''; + + const normalizedText = normalizeString(text); + const normalizedSearch = normalizeString(searchValue); + const startIndex = normalizedText.indexOf(normalizedSearch); + + if (startIndex === -1) return text; + + const endIndex = startIndex + normalizedSearch.length; + const before = text.slice(0, startIndex); + const match = text.slice(startIndex, endIndex); + const after = text.slice(endIndex); + + let result = ''; + if (before) { + result += `${before}`; + } + result += match; + if (after) { + result += `${after}`; + } + return result; + } + + /** + * Filters the countries based on the search value. + */ + filterCountries() { + const { countryList, countryListItems, liveRegion, noResultsMessage, popularCountries, resetButton, search } = + this.refs; + const { labelResultsCount } = this.dataset; + const searchValue = normalizeString(search.value); + let countVisibleCountries = 0; + + resetButton.toggleAttribute('hidden', !searchValue); + + if (popularCountries) { + popularCountries.toggleAttribute('hidden', Boolean(searchValue)); + } + + const wrapper = this.querySelector('.country-selector-form__wrapper'); + if (wrapper) { + wrapper.classList.toggle('is-searching', !!searchValue); + } + + for (const countryEl of countryListItems) { + if (searchValue === '') { + countryEl.removeAttribute('hidden'); + const countrySpan = countryEl.querySelector('.country'); + if (countrySpan) { + countrySpan.textContent = countrySpan.textContent; + } + countVisibleCountries++; + } else { + const matches = this.#findMatches(searchValue, countryEl); + + // In the future, we could reorder/rank filtered results based on the match types + if (matches.label || matches.alias || matches.iso || matches.currency) { + countryEl.removeAttribute('hidden'); + const countrySpan = countryEl.querySelector('.country'); + if (countrySpan) { + countrySpan.innerHTML = this.#highlightMatches(countrySpan.textContent, searchValue); + } + countVisibleCountries++; + } else { + countryEl.setAttribute('hidden', ''); + } + } + } + + if (liveRegion && labelResultsCount) { + liveRegion.innerText = labelResultsCount.replace('[count]', `${countVisibleCountries}`); + } + + noResultsMessage.hidden = countVisibleCountries > 0; + countryList.scrollTop = 0; + } + + /** + * Changes the focus of the country list items. + * + * @param {string} direction - The direction to change the focus. + */ + #changeCountryFocus(direction) { + const { countryListItems } = this.refs; + const focusableItems = countryListItems.filter((item) => !item.hasAttribute('hidden')); + const focusedItemIndex = focusableItems.findIndex((item) => item === document.activeElement); + const focusedItem = focusableItems[focusedItemIndex]; + let itemToFocus; + + if (direction === 'UP') { + itemToFocus = + focusedItemIndex > 0 ? focusableItems[focusedItemIndex - 1] : focusableItems[focusableItems.length - 1]; + } else { + itemToFocus = + focusedItemIndex < focusableItems.length - 1 ? focusableItems[focusedItemIndex + 1] : focusableItems[0]; + } + + if (focusedItem) { + focusedItem.setAttribute('aria-selected', 'false'); + } + itemToFocus?.setAttribute('aria-selected', 'true'); + itemToFocus?.focus(); + } + + /** + * Resets the countries filter. + * + * @param {Event} event - The event object. + */ + resetCountriesFilter(event) { + const { search } = this.refs; + + event.stopPropagation(); + search.value = ''; + this.filterCountries(); + search.setAttribute('aria-activedescendant', ''); + search.focus(); + } + + /** + * Handles the keydown event for the search input. + * + * @param {KeyboardEvent} event - The event object. + */ + #onSearchKeyDown = (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + return; + } + this.#onContainerKeyDown(event); + }; + + /** + * Resets the form. + */ + resetForm() { + const { search } = this.refs; + + if (!search) return; + + if (search.value != '') { + search.value = ''; + this.filterCountries(); + search.setAttribute('aria-activedescendant', ''); + } + } + + /** + * Focuses the search input. + */ + focusSearchInput = () => { + const { search } = this.refs; + + search?.focus(); + }; + + /** + * Handles the scroll event on the country list. + * + * @param {Event} event - The scroll event object. + */ + #onCountryListScroll = (event) => { + const countryFilter = this.querySelector('.country-filter'); + const countryList = event.target instanceof HTMLElement ? event.target : null; + + if (countryFilter && countryList) { + const shouldShowBorder = countryList.scrollTop > 0; + countryFilter.classList.toggle('is-scrolled', shouldShowBorder); + } + }; +} + +/** + * A custom element that displays a dropdown localization form. + * + * @typedef {object} DropdownRefs + * @property {HTMLButtonElement} button - The button element. + * @property {HTMLDivElement} panel - The panel element. + * @property {LocalizationFormComponent} localizationForm - The localization form component. + * + * @extends {Component} + */ +class DropdownLocalizationComponent extends Component { + get isHidden() { + return this.refs.panel.hasAttribute('hidden'); + } + + /** + * Toggles the panel. + */ + toggleSelector() { + return this.isHidden ? this.showPanel() : this.hidePanel(); + } + + /** + * Shows the panel. + */ + showPanel() { + if (!this.isHidden) return; + + this.addEventListener('keyup', this.#handleKeyUp); + document.addEventListener('click', this.#handleClickOutside); + + this.refs.panel.removeAttribute('hidden'); + this.refs.button.setAttribute('aria-expanded', 'true'); + + onAnimationEnd(this.refs.panel, () => { + this.#updateWidth(); + this.refs.localizationForm?.focusSearchInput(); + }); + } + + /** + * Hides the panel. + */ + hidePanel = () => { + if (this.isHidden) return; + + this.removeEventListener('keyup', this.#handleKeyUp); + document.removeEventListener('click', this.#handleClickOutside); + + this.refs.button?.setAttribute('aria-expanded', 'false'); + this.refs.panel.setAttribute('hidden', ''); + this.refs.localizationForm?.resetForm(); + }; + + /** + * Handles the click outside event. + * + * @param {PointerEvent} event - The event object. + */ + #handleClickOutside = (event) => { + if (isClickedOutside(event, this)) { + this.hidePanel(); + } + }; + + /** + * Updates the width of the panel. + */ + #updateWidth() { + this.style.setProperty('--width', `${this.refs.localizationForm.offsetWidth}px`); + } + + /** + * Handles the keyup event. + * + * @param {KeyboardEvent} event - The event object. + */ + #handleKeyUp = (event) => { + switch (event.key) { + case 'Escape': + this.hidePanel(); + event.stopPropagation(); + this.refs.button?.focus(); + break; + } + }; +} + +/** + * A custom element that displays a drawer localization form. + * + * @typedef {object} DrawerRefs + * @property {HTMLDialogElement} dialog - The dialog element. + * @property {LocalizationFormComponent} localizationForm - The localization form component. + * + * @extends {Component} + */ +class DrawerLocalizationComponent extends Component { + /** + * Toggles the dialog. + * + * @param {ToggleEvent} event - The event object. + */ + toggle(event) { + const { target } = event; + const { localizationForm } = this.refs; + + if (!localizationForm || !(target instanceof HTMLDetailsElement)) return; + + const countryList = localizationForm.querySelector('.country-selector-form__wrapper'); + + if (target.open) { + if (countryList) countryList.addEventListener('scroll', this.#onCountryListScroll); + onAnimationEnd(target, localizationForm.focusSearchInput); + } else { + countryList?.removeEventListener('scroll', this.#onCountryListScroll); + localizationForm.resetForm(); + } + } + + /** + * Handles the scroll event on the country list. + * + * @param {Event} event - The scroll event object. + */ + #onCountryListScroll = (event) => { + const countryFilter = this.querySelector('.country-filter'); + const countryList = event.target instanceof HTMLElement ? event.target : null; + + if (countryFilter && countryList) { + const shouldShowBorder = countryList.scrollTop > 0; + countryFilter.classList.toggle('is-scrolled', shouldShowBorder); + } + }; +} + +if (!customElements.get('localization-form-component')) { + customElements.define('localization-form-component', LocalizationFormComponent); +} + +if (!customElements.get('dropdown-localization-component')) { + customElements.define('dropdown-localization-component', DropdownLocalizationComponent); +} + +if (!customElements.get('drawer-localization-component')) { + customElements.define('drawer-localization-component', DrawerLocalizationComponent); +} diff --git a/assets/marquee.js b/assets/marquee.js new file mode 100644 index 000000000..d0f22b39a --- /dev/null +++ b/assets/marquee.js @@ -0,0 +1,221 @@ +import { Component } from '@theme/component'; +import { debounce } from '@theme/utilities'; + +const ANIMATION_OPTIONS = { + duration: 500, +}; + +/** + * A custom element that displays a marquee. + * + * @typedef {object} Refs + * @property {HTMLElement} wrapper - The wrapper element. + * @property {HTMLElement} content - The content element. + * + * @extends Component + */ +class MarqueeComponent extends Component { + requiredRefs = ['wrapper', 'content']; + + connectedCallback() { + super.connectedCallback(); + + const { content } = this.refs; + if (content.firstElementChild?.children.length === 0) return; + + this.#addRepeatedItems(); + this.#duplicateContent(); + this.#setSpeed(); + + window.addEventListener('resize', this.#handleResize); + this.addEventListener('pointerenter', this.#slowDown); + this.addEventListener('pointerleave', this.#speedUp); + } + + disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener('resize', this.#handleResize); + this.removeEventListener('pointerenter', this.#slowDown); + this.removeEventListener('pointerleave', this.#speedUp); + } + + /** + * @type {{ cancel: () => void, current: number } | null} + */ + #animation = null; + + #slowDown = debounce(() => { + if (this.#animation) return; + + const animation = this.refs.wrapper.getAnimations()[0]; + + if (!animation) return; + + this.#animation = animateValue({ + ...ANIMATION_OPTIONS, + from: 1, + to: 0, + onUpdate: (value) => animation.updatePlaybackRate(value), + onComplete: () => { + this.#animation = null; + }, + }); + }, ANIMATION_OPTIONS.duration); + + #speedUp() { + this.#slowDown.cancel(); + + const animation = this.refs.wrapper.getAnimations()[0]; + + if (!animation || animation.playbackRate === 1) return; + + const from = this.#animation?.current ?? 0; + this.#animation?.cancel(); + + this.#animation = animateValue({ + ...ANIMATION_OPTIONS, + from, + to: 1, + onUpdate: (value) => animation.updatePlaybackRate(value), + onComplete: () => { + this.#animation = null; + }, + }); + } + + get clonedContent() { + const { content, wrapper } = this.refs; + const lastChild = wrapper.lastElementChild; + + return content !== lastChild ? lastChild : null; + } + + #setSpeed(value = this.#calculateSpeed()) { + this.style.setProperty('--marquee-speed', `${value}s`); + } + + #calculateSpeed() { + const speedFactor = Number(this.getAttribute('data-speed-factor')); + const marqueeWidth = this.offsetWidth; + const speed = Math.ceil(marqueeWidth / speedFactor / 2); + return speed; + } + + #handleResize = debounce(() => { + const { content } = this.refs; + const newNumberOfCopies = this.#calculateNumberOfCopies(); + const currentNumberOfCopies = content.children.length; + + if (newNumberOfCopies > currentNumberOfCopies) { + this.#addRepeatedItems(newNumberOfCopies - currentNumberOfCopies); + } else if (newNumberOfCopies < currentNumberOfCopies) { + this.#removeRepeatedItems(currentNumberOfCopies - newNumberOfCopies); + } + + this.#duplicateContent(); + this.#setSpeed(); + this.#restartAnimation(); + }, 250); + + #restartAnimation() { + const animations = this.refs.wrapper.getAnimations(); + + requestAnimationFrame(() => { + for (const animation of animations) { + animation.currentTime = 0; + } + }); + } + + #duplicateContent() { + this.clonedContent?.remove(); + + const clone = /** @type {HTMLElement} */ (this.refs.content.cloneNode(true)); + + clone.setAttribute('aria-hidden', 'true'); + clone.removeAttribute('ref'); + + this.refs.wrapper.appendChild(clone); + } + + #addRepeatedItems(numberOfCopies = this.#calculateNumberOfCopies()) { + const { content } = this.refs; + const wrapper = content.firstElementChild; + + if (!wrapper) return; + + for (let i = 0; i < numberOfCopies - 1; i++) { + const clone = wrapper.cloneNode(true); + content.appendChild(clone); + } + } + + #removeRepeatedItems(numberOfCopies = this.#calculateNumberOfCopies()) { + const { content } = this.refs; + + for (let i = 0; i < numberOfCopies; i++) { + content.lastElementChild?.remove(); + } + } + + #calculateNumberOfCopies() { + const { content } = this.refs; + const marqueeWidth = this.offsetWidth; + const marqueeRepeatedItemWidth = + content.firstElementChild instanceof HTMLElement ? content.firstElementChild.offsetWidth : 1; + + return marqueeRepeatedItemWidth === 0 ? 1 : Math.ceil(marqueeWidth / marqueeRepeatedItemWidth); + } +} + +// Define the animateValue function +/** + * Animate a numeric property smoothly. + * @param {Object} params - The parameters for the animation. + * @param {number} params.from - The starting value. + * @param {number} params.to - The ending value. + * @param {number} params.duration - The duration of the animation in milliseconds. + * @param {function(number): void} params.onUpdate - The function to call on each update. + * @param {function(number): number} [params.easing] - The easing function. + * @param {function(): void} [params.onComplete] - The function to call when the animation completes. + */ +function animateValue({ from, to, duration, onUpdate, easing = (t) => t * t * (3 - 2 * t), onComplete }) { + const startTime = performance.now(); + let cancelled = false; + let currentValue = from; + + /** + * @param {number} currentTime - The current time in milliseconds. + */ + function animate(currentTime) { + if (cancelled) return; + + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + const easedProgress = easing(progress); + currentValue = from + (to - from) * easedProgress; + + onUpdate(currentValue); + + if (progress < 1) { + requestAnimationFrame(animate); + } else if (typeof onComplete === 'function') { + onComplete(); + } + } + + requestAnimationFrame(animate); + + return { + get current() { + return currentValue; + }, + cancel() { + cancelled = true; + }, + }; +} + +if (!customElements.get('marquee-component')) { + customElements.define('marquee-component', MarqueeComponent); +} diff --git a/assets/media-gallery.js b/assets/media-gallery.js new file mode 100644 index 000000000..8b7f75f12 --- /dev/null +++ b/assets/media-gallery.js @@ -0,0 +1,84 @@ +import { Component } from '@theme/component'; +import { ThemeEvents, VariantUpdateEvent, ZoomMediaSelectedEvent } from '@theme/events'; + +/** + * A custom element that renders a media gallery. + * + * @typedef {object} Refs + * @property {import('./zoom-dialog').ZoomDialog} [zoomDialogComponent] - The zoom dialog component. + * @property {import('./slideshow').Slideshow} [slideshow] - The slideshow component. + * @property {HTMLElement[]} [media] - The media elements. + * + * @extends Component + */ +export class MediaGallery extends Component { + connectedCallback() { + super.connectedCallback(); + + const { signal } = this.#controller; + const target = this.closest('.shopify-section, dialog'); + + target?.addEventListener(ThemeEvents.variantUpdate, this.#handleVariantUpdate, { signal }); + this.refs.zoomDialogComponent?.addEventListener(ThemeEvents.zoomMediaSelected, this.#handleZoomMediaSelected, { + signal, + }); + } + + #controller = new AbortController(); + + disconnectedCallback() { + super.disconnectedCallback(); + + this.#controller.abort(); + } + + /** + * Handles a variant update event by replacing the current media gallery with a new one. + * + * @param {VariantUpdateEvent} event - The variant update event. + */ + #handleVariantUpdate = (event) => { + const source = event.detail.data.html; + + if (!source) return; + const newMediaGallery = source.querySelector('media-gallery'); + + if (!newMediaGallery) return; + + this.replaceWith(newMediaGallery); + }; + + /** + * Handles the 'zoom-media:selected' event. + * @param {ZoomMediaSelectedEvent} event - The zoom-media:selected event. + */ + #handleZoomMediaSelected = async (event) => { + this.slideshow?.select(event.detail.index, undefined, { animate: false }); + }; + + /** + * Zooms the media gallery. + * + * @param {number} index - The index of the media to zoom. + * @param {PointerEvent} event - The pointer event. + */ + zoom(index, event) { + this.refs.zoomDialogComponent?.open(index, event); + } + + get slideshow() { + return this.refs.slideshow; + } + + get media() { + return this.refs.media; + } + + get presentation() { + return this.dataset.presentation; + } +} + +if (!customElements.get('media-gallery')) { + customElements.define('media-gallery', MediaGallery); +} diff --git a/assets/media.js b/assets/media.js new file mode 100644 index 000000000..cb10bd14e --- /dev/null +++ b/assets/media.js @@ -0,0 +1,248 @@ +import { Component } from '@theme/component'; +import { ThemeEvents, MediaStartedPlayingEvent } from '@theme/events'; +import { DialogCloseEvent } from '@theme/dialog'; + +/** + * A deferred media element + * @typedef {Object} Refs + * @property {HTMLElement} deferredMediaPlayButton - The button to show the deferred media content + * @property {HTMLElement} toggleMediaButton - The button to toggle the media + * + * @extends {Component} + */ +class DeferredMedia extends Component { + /** @type {boolean} */ + isPlaying = false; + + #abortController = new AbortController(); + + connectedCallback() { + super.connectedCallback(); + const signal = this.#abortController.signal; + // If we're to use deferred media for images, we will need to run this only when it's not an image type media + document.addEventListener(ThemeEvents.mediaStartedPlaying, this.pauseMedia.bind(this), { signal }); + window.addEventListener(DialogCloseEvent.eventName, this.pauseMedia.bind(this), { signal }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#abortController.abort(); + } + + /** + * Updates the visual hint for play/pause state + * @param {boolean} isPlaying - Whether the video is currently playing + */ + updatePlayPauseHint(isPlaying) { + const toggleMediaButton = this.refs.toggleMediaButton; + if (toggleMediaButton instanceof HTMLElement) { + toggleMediaButton.classList.remove('hidden'); + const playIcon = toggleMediaButton.querySelector('.icon-play'); + if (playIcon) playIcon.classList.toggle('hidden', isPlaying); + const pauseIcon = toggleMediaButton.querySelector('.icon-pause'); + if (pauseIcon) pauseIcon.classList.toggle('hidden', !isPlaying); + } + } + + /** + * Shows the deferred media content + */ + showDeferredMedia = () => { + this.loadContent(true); + this.isPlaying = true; + this.updatePlayPauseHint(this.isPlaying); + }; + + /** + * Loads the content + * @param {boolean} [focus] - Whether to focus the content + */ + loadContent(focus = true) { + if (this.getAttribute('data-media-loaded')) return; + + this.dispatchEvent(new MediaStartedPlayingEvent(this)); + + const content = this.querySelector('template')?.content.firstElementChild?.cloneNode(true); + + if (!content) return; + + this.setAttribute('data-media-loaded', 'true'); + this.appendChild(content); + + if (focus && content instanceof HTMLElement) { + content.focus(); + } + + this.refs.deferredMediaPlayButton?.classList.add('deferred-media__playing'); + + if (content instanceof HTMLVideoElement && content.getAttribute('autoplay')) { + // force autoplay for safari + content.play(); + } + } + + /** + * Toggle play/pause state of the media + */ + toggleMedia() { + if (this.isPlaying) { + this.pauseMedia(); + } else { + this.playMedia(); + } + } + + playMedia() { + /** @type {HTMLIFrameElement | null} */ + const iframe = this.querySelector('iframe[data-video-type]'); + if (iframe) { + iframe.contentWindow?.postMessage( + iframe.dataset.videoType === 'youtube' + ? '{"event":"command","func":"playVideo","args":""}' + : '{"method":"play"}', + '*' + ); + } else { + this.querySelector('video')?.play(); + } + this.isPlaying = true; + this.updatePlayPauseHint(this.isPlaying); + } + + /** + * Pauses the media + */ + pauseMedia() { + /** @type {HTMLIFrameElement | null} */ + const iframe = this.querySelector('iframe[data-video-type]'); + + if (iframe) { + iframe.contentWindow?.postMessage( + iframe.dataset.videoType === 'youtube' + ? '{"event":"command","func":"' + 'pauseVideo' + '","args":""}' + : '{"method":"pause"}', + '*' + ); + } else { + this.querySelector('video')?.pause(); + } + this.isPlaying = false; + + // If we've already revealed the deferred media, we should toggle the play/pause hint + if (this.getAttribute('data-media-loaded')) { + this.updatePlayPauseHint(this.isPlaying); + } + } +} + +if (!customElements.get('deferred-media')) { + customElements.define('deferred-media', DeferredMedia); +} + +/** + * A product model + */ +class ProductModel extends DeferredMedia { + #abortController = new AbortController(); + + loadContent() { + super.loadContent(); + + Shopify.loadFeatures([ + { + name: 'model-viewer-ui', + version: '1.0', + onLoad: this.setupModelViewerUI.bind(this), + }, + ]); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#abortController.abort(); + } + + pauseMedia() { + super.pauseMedia(); + this.modelViewerUI?.pause(); + } + + playMedia() { + super.playMedia(); + this.modelViewerUI?.play(); + } + + /** + * @param {Error[]} errors + */ + async setupModelViewerUI(errors) { + if (errors) return; + + if (!Shopify.ModelViewerUI) { + await this.#waitForModelViewerUI(); + } + + if (!Shopify.ModelViewerUI) return; + + const element = this.querySelector('model-viewer'); + if (!element) return; + + const signal = this.#abortController.signal; + + this.modelViewerUI = new Shopify.ModelViewerUI(element); + if (!this.modelViewerUI) return; + + this.playMedia(); + + // Track pointer events to detect taps + let pointerStartX = 0; + let pointerStartY = 0; + + element.addEventListener( + 'pointerdown', + (/** @type {PointerEvent} */ event) => { + pointerStartX = event.clientX; + pointerStartY = event.clientY; + }, + { signal } + ); + + element.addEventListener( + 'click', + (/** @type {PointerEvent} */ event) => { + const distanceX = Math.abs(event.clientX - pointerStartX); + const distanceY = Math.abs(event.clientY - pointerStartY); + const totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); + + // Try to ensure that this is a tap, not a drag. + if (totalDistance < 10) { + // When the model is paused, it has its own button overlay for playing the model again. + // If we're receiving a click event, it means the model is playing, all we can do is pause it. + this.pauseMedia(); + } + }, + { signal } + ); + } + + /** + * Waits for Shopify.ModelViewerUI to be defined. + * This seems to be necessary for Safari since Shopify.ModelViewerUI is always undefined on the first try. + * @returns {Promise} + */ + async #waitForModelViewerUI() { + const maxAttempts = 10; + const interval = 50; + + for (let i = 0; i < maxAttempts; i++) { + if (Shopify.ModelViewerUI) { + return; + } + await new Promise((resolve) => setTimeout(resolve, interval)); + } + } +} + +if (!customElements.get('product-model')) { + customElements.define('product-model', ProductModel); +} diff --git a/assets/morph.js b/assets/morph.js new file mode 100644 index 000000000..d5cbffaac --- /dev/null +++ b/assets/morph.js @@ -0,0 +1,469 @@ +import { Component } from '@theme/component'; + +/** + * @typedef {Object} Options + * @property {boolean} [childrenOnly] - Only update children + * @property {(node: Node | undefined) => string|number|undefined} [getNodeKey] - Get node key for matching + * @property {(oldNode: Node, newNode: Node) => void} [onBeforeUpdate] - Pre-update hook + * @property {(node: Node) => void} [onAfterUpdate] - Post-update hook + * @property {(oldNode: Node, newNode: Node) => boolean} [reject] - Reject a node from being morphed + */ + +/** + * The options for the morph + * @type {Options} + */ +const MORPH_OPTIONS = { + childrenOnly: true, + reject(oldNode, newNode) { + if (newNode.nodeType === Node.TEXT_NODE && newNode.nodeValue?.trim() === '') { + return true; + } + + if ( + newNode instanceof HTMLTemplateElement && + newNode.shadowRootMode === 'open' && + oldNode.parentElement && + newNode.parentElement && + oldNode.parentElement.tagName === newNode.parentElement.tagName && + oldNode.parentElement?.shadowRoot != null + ) { + // Ignore template elements of components that are already initialized + return true; + } + + if (newNode.nodeType === Node.COMMENT_NODE && newNode.nodeValue === 'shopify:rendered_by_section_api') { + // Remove a comment node injected by the Section Rendering API in the Theme Editor + return true; + } + + return false; + }, + onBeforeUpdate(oldNode, newNode) { + if (oldNode instanceof Element && newNode instanceof Element) { + const attributes = ['product-grid-view']; + + for (const attribute of attributes) { + const oldValue = oldNode.getAttribute(attribute); + const newValue = newNode.getAttribute(attribute); + + if (oldValue && oldValue !== newValue) { + newNode.setAttribute(attribute, oldValue); + } + } + + // Special case for elements that need to keep their style + const elements = ['floating-panel-component']; + + for (const element of elements) { + const tagName = element.toUpperCase(); + if (oldNode.tagName === tagName && newNode.tagName === tagName) { + const oldStyle = oldNode.getAttribute('style'); + + if (oldStyle) newNode.setAttribute('style', oldStyle); + } + } + + // Preserve temporary view transition name + if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement && oldNode.style.viewTransitionName) { + newNode.style.viewTransitionName = oldNode.style.viewTransitionName; + } + } + }, + onAfterUpdate(node) { + if (node instanceof Component) { + queueMicrotask(() => node.updatedCallback()); + } + }, +}; + +/** + * Morphs one DOM tree into another by comparing nodes and applying minimal changes + * @param {Node} oldTree - The existing DOM tree + * @param {Node | string} newTree - The new DOM tree to morph to + * @param {Options} [options] - Configuration options + * @returns {Node} The morphed DOM tree + */ +export function morph(oldTree, newTree, options = MORPH_OPTIONS) { + if (!oldTree || !newTree) { + throw new Error('Both oldTree and newTree must be provided'); + } + + if (typeof newTree === 'string') { + const parsedNewTree = new DOMParser().parseFromString(newTree, 'text/html').body.firstChild; + if (!parsedNewTree) { + throw new Error('newTree string is not valid HTML'); + } + newTree = parsedNewTree; + } + + if (options.childrenOnly) { + updateChildren(newTree, oldTree, options); + return oldTree; + } + + if (newTree.nodeType === 11) { + throw new Error('newTree should have one root node (not a DocumentFragment)'); + } + + return walk(newTree, oldTree, options); +} + +/** + * Walk and morph a dom tree + * @param {Node} newNode - The new node to morph to + * @param {Node} oldNode - The old node to morph from + * @param {Options} options - The options object + * @returns {Node} The new node or the morphed old node + */ +function walk(newNode, oldNode, options) { + // Skip morphing if there is no old or new node + if (!oldNode) return newNode; + if (!newNode) return oldNode; + + // Skip morphing if nodes are identical + if (newNode.isSameNode?.(oldNode)) return oldNode; + + // Check node type and tag name first + if (newNode.nodeType !== oldNode.nodeType) return newNode; + if (newNode instanceof Element && oldNode instanceof Element) { + // Skip morphing if the node is shopify-accelerated-checkout-cart https://shopify.dev/docs/storefronts/themes/pricing-payments/accelerated-checkout#implement-accelerated-checkout-buttons-on-cart + if (oldNode.tagName === 'SHOPIFY-ACCELERATED-CHECKOUT-CART') return oldNode; + + if (newNode.tagName !== oldNode.tagName) return newNode; + + // Only check keys for elements, and only if both nodes have keys + const newKey = getNodeKey(newNode, options); + const oldKey = getNodeKey(oldNode, options); + if (newKey && oldKey && newKey !== oldKey) return newNode; + } + + // We can morph, update the node and its children + if ( + oldNode instanceof Element && + oldNode.hasAttribute('data-skip-node-update') && + newNode instanceof Element && + newNode.hasAttribute('data-skip-node-update') + ) { + // This is a special case where we don't want to morph the node, but we want to morph the children + updateChildren(newNode, oldNode, options); + } else { + updateNode(newNode, oldNode, options); + updateChildren(newNode, oldNode, options); + } + + options.onAfterUpdate?.(newNode); + + return oldNode; +} + +/** + * Core morphing function that updates attributes and special elements + * @param {Node} newNode - Source node with desired state + * @param {Node} oldNode - Target node to update + * @param {Options} options - The options object + */ +function updateNode(newNode, oldNode, options) { + options.onBeforeUpdate?.(oldNode, newNode); + + if ( + (newNode instanceof HTMLDetailsElement && oldNode instanceof HTMLDetailsElement) || + (newNode instanceof HTMLDialogElement && oldNode instanceof HTMLDialogElement) + ) { + if (!newNode.hasAttribute('declarative-open')) { + newNode.open = oldNode.open; + } + } + + if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement) { + for (const attr of ['slot', 'sizes']) { + const oldValue = oldNode.getAttribute(attr); + const newValue = newNode.getAttribute(attr); + + if (oldValue !== newValue) { + oldValue == null ? newNode.removeAttribute(attr) : newNode.setAttribute(attr, oldValue); + } + } + } + + if (newNode instanceof Element && oldNode instanceof Element) { + if (!oldNode.isEqualNode(newNode)) { + copyAttributes(newNode, oldNode); + } + } else if (newNode instanceof Text || newNode instanceof Comment) { + if (oldNode.nodeValue !== newNode.nodeValue) { + oldNode.nodeValue = newNode.nodeValue; + } + } + + // Handle special elements + if (newNode instanceof HTMLInputElement && oldNode instanceof HTMLInputElement) { + updateInput(newNode, oldNode); + } else if (newNode instanceof HTMLOptionElement && oldNode instanceof HTMLOptionElement) { + updateAttribute(newNode, oldNode, 'selected'); + } else if (newNode instanceof HTMLTextAreaElement && oldNode instanceof HTMLTextAreaElement) { + updateTextarea(newNode, oldNode); + } +} + +/** + * Gets a node's key using the getNodeKey option if provided + * @param {Node | undefined} node - The node to get the key from + * @param {Options} [options] - The options object that may contain getNodeKey + * @returns {string|number|undefined} The node's key if one exists + */ +function getNodeKey(node, options) { + return options?.getNodeKey?.(node) ?? (node instanceof Element ? node.id : undefined); +} + +/** + * Updates a boolean attribute and its corresponding property on an element + * @param {any} newNode - The new element + * @param {any} oldNode - The existing element to update + * @param {string} name - The name of the attribute/property to update + */ +function updateAttribute(newNode, oldNode, name) { + if (newNode[name] !== oldNode[name]) { + oldNode[name] = newNode[name]; + if (newNode[name] != null) { + oldNode.setAttribute(name, ''); + } else { + oldNode.removeAttribute(name); + } + } +} + +/** + * Copies attributes from a new node to an old node, handling namespaced attributes + * @param {Element} newNode - The new node to copy attributes from + * @param {Element} oldNode - The existing node to update attributes on + */ +function copyAttributes(newNode, oldNode) { + const oldAttrs = oldNode.attributes; + const newAttrs = newNode.attributes; + + // Update or add new attributes + for (const attr of Array.from(newAttrs)) { + const { name: attrName, namespaceURI: attrNamespaceURI, value: attrValue } = attr; + const localName = attr.localName || attrName; + + if (attrName === 'src' || attrName === 'href' || attrName === 'srcset' || attrName === 'poster') { + // Skip updating resource attributes when the value hasn't changed + // to prevent unnecessary network requests + if (oldNode.getAttribute(attrName) === attrValue) continue; + } + + if (attrNamespaceURI) { + const fromValue = oldNode.getAttributeNS(attrNamespaceURI, localName); + if (fromValue !== attrValue) { + oldNode.setAttributeNS(attrNamespaceURI, localName, attrValue); + } + } else { + if (!oldNode.hasAttribute(attrName)) { + oldNode.setAttribute(attrName, attrValue); + } else { + const fromValue = oldNode.getAttribute(attrName); + if (fromValue !== attrValue) { + if (attrValue === 'null' || attrValue === 'undefined') { + oldNode.removeAttribute(attrName); + } else { + oldNode.setAttribute(attrName, attrValue); + } + } + } + } + } + + // Remove old attributes not present in new node + for (const attr of Array.from(oldAttrs)) { + if (attr.specified === false) continue; + + const { name: attrName, namespaceURI: attrNamespaceURI } = attr; + const localName = attr.localName || attrName; + + if (attrNamespaceURI) { + if (!newNode.hasAttributeNS(attrNamespaceURI, localName)) { + oldNode.removeAttributeNS(attrNamespaceURI, localName); + } + } else if (!newNode.hasAttribute(attrName)) { + oldNode.removeAttribute(attrName); + } + } +} + +/** + * Updates special properties and attributes on input elements + * Handles checked, disabled, indeterminate states and value + * @param {HTMLInputElement} newNode - The new input element + * @param {HTMLInputElement} oldNode - The existing input element to update + */ +function updateInput(newNode, oldNode) { + const newValue = newNode.value; + + updateAttribute(newNode, oldNode, 'checked'); + updateAttribute(newNode, oldNode, 'disabled'); + + // Handle indeterminate state (cannot be set via HTML attribute) + if (newNode.indeterminate !== oldNode.indeterminate) { + oldNode.indeterminate = newNode.indeterminate; + } + + // Skip file inputs since they can't be changed programmatically + if (oldNode.type === 'file') return; + + if (newValue !== oldNode.value) { + oldNode.setAttribute('value', newValue); + oldNode.value = newValue; + } + + if (newValue === 'null') { + oldNode.value = ''; + oldNode.removeAttribute('value'); + } + + if (!newNode.hasAttributeNS(null, 'value')) { + oldNode.removeAttribute('value'); + } else if (oldNode.type === 'range') { + // Update range input UI + oldNode.value = newValue; + } +} + +/** + * Updates the value of a textarea element + * @param {HTMLTextAreaElement} newNode - The new textarea element + * @param {HTMLTextAreaElement} oldNode - The existing textarea element to update + */ +function updateTextarea(newNode, oldNode) { + const newValue = newNode.value; + if (newValue !== oldNode.value) { + oldNode.value = newValue; + } + + const firstChild = oldNode.firstChild; + if (firstChild?.nodeType === Node.TEXT_NODE) { + if (newValue === '' && firstChild.nodeValue === oldNode.placeholder) { + return; + } + firstChild.nodeValue = newValue; + } +} + +/** + * Update the children of elements + * @param {Node} newNode - The new node to update children on + * @param {Node} oldNode - The existing node to update children on + * @param {Options} options - The options object + */ +function updateChildren(newNode, oldNode, options) { + if ( + oldNode instanceof Element && + oldNode.hasAttribute('data-skip-subtree-update') && + newNode instanceof Element && + newNode.hasAttribute('data-skip-subtree-update') + ) { + return; + } + + let oldChild, newChild, morphed, oldMatch; + let offset = 0; + + for (let i = 0; ; i++) { + oldChild = oldNode.childNodes[i]; + newChild = newNode.childNodes[i - offset]; + + // Both nodes are empty, do nothing + if (!oldChild && !newChild) { + break; + } + + // There is no new child, remove old + if (!newChild) { + oldChild && oldNode.removeChild(oldChild); + i--; + continue; + } + + // There is no old child, add new + if (!oldChild) { + oldNode.appendChild(newChild); + offset++; + continue; + } + + // Both nodes are the same, morph + if (same(newChild, oldChild, options)) { + morphed = walk(newChild, oldChild, options); + if (morphed !== oldChild) { + oldNode.replaceChild(morphed, oldChild); + offset++; + } + continue; + } + + if (options.reject?.(oldChild, newChild)) { + newNode.removeChild(newChild); + i--; + continue; + } + + // Try to find a matching node to reorder + oldMatch = null; + for (let j = i; j < oldNode.childNodes.length; j++) { + const potentialOldNode = oldNode.childNodes[j]; + + if (potentialOldNode && same(potentialOldNode, newChild, options)) { + oldMatch = potentialOldNode; + break; + } + } + + if (oldMatch) { + morphed = walk(newChild, oldMatch, options); + if (morphed !== oldMatch) offset++; + oldNode.insertBefore(morphed, oldChild); + } else if (!getNodeKey(newChild, options) && !getNodeKey(oldChild, options)) { + // Safe to morph in-place if neither has a key + morphed = walk(newChild, oldChild, options); + if (morphed !== oldChild) { + oldNode.replaceChild(morphed, oldChild); + offset++; + } + } else { + // Insert the node if we couldn't morph or find a match + oldNode.insertBefore(newChild, oldChild); + offset++; + } + } +} + +/** + * Check if two nodes are the same + * @param {Node} a - The first node + * @param {Node} b - The second node + * @param {Options} options - The options object + * @returns {boolean} True if the nodes are the same, false otherwise + */ +function same(a, b, options) { + // If node types don't match, they're not the same + if (a.nodeType !== b.nodeType) return false; + + // For elements, check tag name first + if (a.nodeType === Node.ELEMENT_NODE) { + if (a instanceof Element && b instanceof Element && a.tagName !== b.tagName) return false; + + // Only compare keys if both nodes have them + const aKey = getNodeKey(a, options); + const bKey = getNodeKey(b, options); + if (aKey && bKey && aKey !== bKey) return false; + } + + // For text/comment nodes, compare content + if (a.nodeType === Node.TEXT_NODE && b.nodeType === Node.TEXT_NODE) + // Trim whitespace to avoid false negatives + return a.nodeValue?.trim() === b.nodeValue?.trim(); + if (a.nodeType === Node.COMMENT_NODE && b.nodeType === Node.COMMENT_NODE) return a.nodeValue === b.nodeValue; + + // If we get here and nodes are elements with same tag (and compatible keys), they're the same + return true; +} diff --git a/assets/overflow-list.css b/assets/overflow-list.css new file mode 100644 index 000000000..83fa98f18 --- /dev/null +++ b/assets/overflow-list.css @@ -0,0 +1,58 @@ +:host { + display: grid; + width: 100%; +} + +[part='list'] { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: var(--overflow-list-alignment); + column-gap: 1rem; + + @media (max-width: 749px) { + justify-content: var(--overflow-list-alignment-mobile); + } +} + +[part='list'], +[part='overflow-list'], +[part='placeholder'] { + margin: 0; + padding: 0; + list-style: none; +} + +/* Make sure the "more" slot can be measured */ +slot[name='more']:not([hidden]) { + display: block; +} + +slot[name='more'] .button { + cursor: pointer; + border: none; + background: none; + padding: 0; + margin: 0; + font-family: var(--font-paragraph-family); + font-size: var(--font-paragraph-size); + text-transform: var(--text-transform); + color: currentcolor; + text-align: start; +} + +[part='overflow'] { + display: none; +} + +[part='placeholder'] { + visibility: hidden; + width: 0; + height: 0; +} + +:host([disabled]) { + slot[name='more'] { + display: none; + } +} diff --git a/assets/paginated-list.js b/assets/paginated-list.js new file mode 100644 index 000000000..d67ecd11e --- /dev/null +++ b/assets/paginated-list.js @@ -0,0 +1,503 @@ +import { Component } from '@theme/component'; +import { sectionRenderer } from '@theme/section-renderer'; +import { requestIdleCallback, viewTransition } from '@theme/utilities'; +import { ThemeEvents } from '@theme/events'; + +/** + * A custom element that renders a paginated list of items. + * + * @typedef {object} Refs + * @property {HTMLUListElement} [grid] - The grid element. + * @property {HTMLSpanElement} [viewMorePrevious] - The view more previous button. + * @property {HTMLSpanElement} [viewMoreNext] - The view more next button. + * @property {HTMLElement[]} [cards] - The cards elements. + * + * @extends Component + */ +export default class PaginatedList extends Component { + /** + * @type {Map} + */ + pages = new Map(); + + /** @type {IntersectionObserver | undefined} */ + infinityScrollObserver; + + /** @type {((value: void) => void) | null} */ + #resolveNextPagePromise = null; + + /** @type {((value: void) => void) | null} */ + #resolvePreviousPagePromise = null; + + /** @type {string | null} */ + #imageRatioSetting = null; + + connectedCallback() { + super.connectedCallback(); + + this.#storeImageRatioSettings(); + + this.#fetchPage('next'); + this.#fetchPage('previous'); + this.#observeViewMore(); + + // Listen for filter updates to clear cached pages + document.addEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + /** + * Store the image ratio from the first product card for later use + */ + #storeImageRatioSettings() { + const firstCardGallery = this.querySelector('[ref="cardGallery"]'); + if (!firstCardGallery) return; + + this.#imageRatioSetting = firstCardGallery.getAttribute('data-image-ratio'); + } + + disconnectedCallback() { + super.disconnectedCallback(); + if (this.infinityScrollObserver) { + this.infinityScrollObserver.disconnect(); + } + // Remove the filter update listener + document.removeEventListener(ThemeEvents.FilterUpdate, this.#handleFilterUpdate); + } + + #observeViewMore() { + const { viewMorePrevious, viewMoreNext } = this.refs; + + // Return if neither element exists + if (!viewMorePrevious && !viewMoreNext) return; + + // Create observer if it doesn't exist + if (!this.infinityScrollObserver) { + this.infinityScrollObserver = new IntersectionObserver( + async (entries) => { + // Wait for any in-progress view transitions to finish + if (viewTransition.current) await viewTransition.current; + + for (const entry of entries) { + if (entry.isIntersecting) { + // Use current refs to check which element triggered + const { viewMorePrevious, viewMoreNext } = this.refs; + + if (entry.target === viewMorePrevious) { + this.#renderPreviousPage(); + } else if (entry.target === viewMoreNext) { + this.#renderNextPage(); + } + } + } + }, + { + rootMargin: '100px', + } + ); + } + + // Observe the view more elements + if (viewMorePrevious) { + this.infinityScrollObserver.observe(viewMorePrevious); + } + + if (viewMoreNext) { + this.infinityScrollObserver.observe(viewMoreNext); + } + } + + /** + * @param {{ page: number, url?: URL } | undefined} pageInfo - The page info + * @returns {boolean} Whether to use the page + */ + #shouldUsePage(pageInfo) { + if (!pageInfo) return false; + + const { grid } = this.refs; + const lastPage = grid?.dataset.lastPage; + + if (!lastPage || pageInfo.page < 1 || pageInfo.page > Number(lastPage)) return false; + + return true; + } + + /** + * @param {"previous" | "next"} type + */ + async #fetchPage(type) { + const page = this.#getPage(type); + + // Always resolve the promise, even if we can't fetch the page + const resolvePromise = () => { + if (type === 'next') { + this.#resolveNextPagePromise?.(); + this.#resolveNextPagePromise = null; + } else { + this.#resolvePreviousPagePromise?.(); + this.#resolvePreviousPagePromise = null; + } + }; + + if (!page || !this.#shouldUsePage(page)) { + // Resolve the promise even if we can't fetch + resolvePromise(); + return; + } + + await this.#fetchSpecificPage(page.page, page.url); + resolvePromise(); + } + + /** + * @param {number} pageNumber - The page number to fetch + * @param {URL} [url] - Optional URL, will be constructed if not provided + */ + async #fetchSpecificPage(pageNumber, url = undefined) { + const pageInfo = { page: pageNumber, url }; + + if (!url) { + const newUrl = new URL(window.location.href); + newUrl.searchParams.set('page', pageNumber.toString()); + newUrl.hash = ''; + pageInfo.url = newUrl; + } + + if (!this.#shouldUsePage(pageInfo)) return; + const pageContent = await sectionRenderer.getSectionHTML(this.sectionId, true, pageInfo.url); + this.pages.set(pageNumber, pageContent); + } + + async #renderNextPage() { + const { grid } = this.refs; + + if (!grid) return; + + const nextPage = this.#getPage('next'); + + if (!nextPage || !this.#shouldUsePage(nextPage)) return; + let nextPageItemElements = this.#getGridForPage(nextPage.page); + + if (!nextPageItemElements) { + const promise = new Promise((res) => { + this.#resolveNextPagePromise = res; + }); + + // Trigger the fetch for this page + this.#fetchPage('next'); + + await promise; + nextPageItemElements = this.#getGridForPage(nextPage.page); + if (!nextPageItemElements) return; + } + + grid.append(...nextPageItemElements); + + this.#processNewElements(); + + history.pushState('', '', nextPage.url.toString()); + + requestIdleCallback(() => { + this.#fetchPage('next'); + }); + } + + async #renderPreviousPage() { + const { grid } = this.refs; + + if (!grid) return; + + const previousPage = this.#getPage('previous'); + if (!previousPage || !this.#shouldUsePage(previousPage)) return; + + let previousPageItemElements = this.#getGridForPage(previousPage.page); + if (!previousPageItemElements) { + const promise = new Promise((res) => { + this.#resolvePreviousPagePromise = res; + }); + + // Trigger the fetch for this page + this.#fetchPage('previous'); + + await promise; + previousPageItemElements = this.#getGridForPage(previousPage.page); + if (!previousPageItemElements) return; + } + + // Store the current scroll position and height of the first element + const scrollTop = window.scrollY; + const firstElement = grid.firstElementChild; + const oldHeight = firstElement ? firstElement.getBoundingClientRect().top + window.scrollY : 0; + + // Prepend the new elements + grid.prepend(...previousPageItemElements); + + this.#processNewElements(); + + history.pushState('', '', previousPage.url.toString()); + + // Calculate and adjust scroll position to maintain the same view + if (firstElement) { + const newHeight = firstElement.getBoundingClientRect().top + window.scrollY; + const heightDiff = newHeight - oldHeight; + window.scrollTo({ + top: scrollTop + heightDiff, + behavior: 'instant', + }); + } + + requestIdleCallback(() => { + this.#fetchPage('previous'); + }); + } + + /** + * Process newly added elements and apply correct aspect ratios + */ + #processNewElements() { + // Wait for the DOM to update + requestAnimationFrame(() => { + this.#imageRatioSetting === 'adapt' ? this.#fixAdaptiveAspectRatios() : this.#applyFixedAspectRatio(); + }); + } + + /** + * Get all unprocessed card galleries + * @returns {NodeListOf} List of unprocessed galleries + */ + #getUnprocessedGalleries() { + return this.querySelectorAll('.card-gallery:not([data-aspect-ratio-applied])'); + } + + /** + * Mark gallery as processed + * @param {HTMLElement} gallery - The gallery element to mark as processed + */ + #markAsProcessed(gallery) { + if (!(gallery instanceof HTMLElement)) return; + gallery.setAttribute('data-aspect-ratio-applied', 'true'); + } + + /** + * Calculate a safe aspect ratio value from image dimensions + * Ensures the ratio stays within reasonable bounds and has consistent decimal places + * @param {number} width - Natural width of the image + * @param {number} height - Natural height of the image + * @returns {string} Normalized aspect ratio as a string + */ + #getSafeImageAspectRatio(width, height) { + const rawRatio = width / height; + return Math.max(0.1, Math.min(10, rawRatio)).toFixed(3); + } + + /** + * Apply an aspect ratio to a gallery and all its media containers + * @param {HTMLElement} gallery - The gallery element + * @param {string} aspectRatio - The aspect ratio to apply + */ + #applyAspectRatioToGallery(gallery, aspectRatio) { + if (!(gallery instanceof HTMLElement)) return; + + gallery.style.setProperty('--gallery-aspect-ratio', aspectRatio); + + const mediaContainers = gallery.querySelectorAll('.product-media-container'); + mediaContainers.forEach((container) => { + if (container instanceof HTMLElement) { + container.style.aspectRatio = aspectRatio; + } + }); + + this.#markAsProcessed(gallery); + } + + /** + * Fix adaptive aspect ratios for newly added cards + * For the 'adapt' setting, each product should use its own image's aspect ratio + */ + #fixAdaptiveAspectRatios() { + const newCardGalleries = this.#getUnprocessedGalleries(); + if (!newCardGalleries.length) return; + + const productRatioCache = new Map(); + + newCardGalleries.forEach((gallery) => { + if (!(gallery instanceof HTMLElement)) return; + + const productId = gallery.getAttribute('data-product-id'); + if (productId && productRatioCache.has(productId)) { + this.#applyAspectRatioToGallery(gallery, productRatioCache.get(productId)); + return; + } + + const img = gallery.querySelector('img'); + if (!img) { + this.#applyAspectRatioToGallery(gallery, '1'); + return; + } + + const loadAndSetRatio = () => { + if (!img.naturalWidth || !img.naturalHeight) return; + + const imgRatio = this.#getSafeImageAspectRatio(img.naturalWidth, img.naturalHeight); + + if (productId) { + productRatioCache.set(productId, imgRatio); + } + + this.#applyAspectRatioToGallery(gallery, imgRatio); + }; + + if (img.complete) { + loadAndSetRatio(); + } else { + img.addEventListener('load', loadAndSetRatio, { once: true }); + } + }); + } + + /** + * Apply a fixed aspect ratio to all card-gallery and media container elements + * Only used for non-adaptive modes (square, portrait, landscape) + */ + #applyFixedAspectRatio() { + if (!this.#imageRatioSetting) return; + + const aspectRatio = this.#getAspectRatioValue(this.#imageRatioSetting); + if (!aspectRatio) return; + + const newCardGalleries = this.#getUnprocessedGalleries(); + if (!newCardGalleries.length) return; + + // Batch DOM operations for better performance + requestAnimationFrame(() => { + newCardGalleries.forEach((gallery) => { + if (!(gallery instanceof HTMLElement)) return; + this.#applyAspectRatioToGallery(gallery, aspectRatio); + }); + }); + } + + /** + * Aspect ratio values matching the theme's standardized values + * @type {Object.} + */ + static ASPECT_RATIOS = { + square: '1', + portrait: '0.8', + landscape: '1.778', + }; + + /** + * Get aspect ratio value based on setting + * @param {string} ratioSetting - The ratio setting name + * @returns {string|null} - The aspect ratio value or null + */ + #getAspectRatioValue(ratioSetting) { + return PaginatedList.ASPECT_RATIOS[ratioSetting] || null; + } + + /** + * @param {"previous" | "next"} type + * @returns {{ page: number, url: URL } | undefined} + */ + #getPage(type) { + const { cards } = this.refs; + const isPrevious = type === 'previous'; + + if (!Array.isArray(cards)) return; + + const targetCard = cards[isPrevious ? 0 : cards.length - 1]; + + if (!targetCard) return; + + const currentCardPage = Number(targetCard.dataset.page); + const page = isPrevious ? currentCardPage - 1 : currentCardPage + 1; + + const url = new URL(window.location.href); + url.searchParams.set('page', page.toString()); + url.hash = ''; + + return { + page, + url, + }; + } + + /** + * @param {number} page + * @returns {NodeListOf | undefined} + */ + #getGridForPage(page) { + const pageHTML = this.pages.get(page); + + if (!pageHTML) return; + + const parsedPage = new DOMParser().parseFromString(pageHTML, 'text/html'); + const gridElement = parsedPage.querySelector('[ref="grid"]'); + if (!gridElement) return; + return gridElement.querySelectorAll(':scope > [ref="cards[]"]'); + } + + get sectionId() { + const id = this.getAttribute('section-id'); + + if (!id) throw new Error('The section-id attribute is required'); + + return id; + } + + /** + * Handle filter updates by clearing cached pages + */ + #handleFilterUpdate = () => { + this.pages.clear(); + + // Resolve any pending promises to unblock waiting renders + this.#resolveNextPagePromise?.(); + this.#resolvePreviousPagePromise?.(); + + this.#resolveNextPagePromise = null; + this.#resolvePreviousPagePromise = null; + + // Store the current lastPage value to detect when it changes + const currentLastPage = this.refs.grid?.dataset.lastPage; + + // We need to wait for the DOM to be updated with the new filtered content + // Using mutation observer to detect when the grid actually updates + const observer = new MutationObserver(() => { + // Check if data-last-page changed + const newLastPage = this.refs.grid?.dataset.lastPage; + + if (newLastPage !== currentLastPage) { + observer.disconnect(); + + // Check if component is still connected + if (!this.isConnected) { + return; + } + + // Now the DOM has been updated with the new filtered content + this.#observeViewMore(); + + // Fetch the next page + this.#fetchPage('next'); + } + }); + + // Observe the grid for changes + const { grid } = this.refs; + if (grid) { + observer.observe(grid, { + attributes: true, + attributeFilter: ['data-last-page'], + childList: true, // Also watch for child changes in case the whole grid is replaced + }); + + // Set a timeout as a fallback in case the mutation never fires + setTimeout(() => { + if (observer) { + observer.disconnect(); + } + }, 3000); + } + }; +} diff --git a/assets/performance.js b/assets/performance.js new file mode 100644 index 000000000..31a63d376 --- /dev/null +++ b/assets/performance.js @@ -0,0 +1,75 @@ + +class ThemePerformance { + /** + * @param {string} metricPrefix + */ + constructor(metricPrefix) { + this.metricPrefix = metricPrefix; + } + + /** + * @param {string} benchmarkName + * @returns {PerformanceMark} + */ + createStartingMarker(benchmarkName) { + const metricName = `${this.metricPrefix}:${benchmarkName}` + return performance.mark(`${metricName}:start`); + } + + /** + * @param {string} benchmarkName + * @param {Event} event + * @returns {void} + */ + measureFromEvent(benchmarkName, event) { + const metricName = `${this.metricPrefix}:${benchmarkName}` + const startMarker = performance.mark(`${metricName}:start`, { + startTime: event.timeStamp + }); + + performance.mark(`${metricName}:end`); + + performance.measure( + metricName, + `${metricName}:start`, + `${metricName}:end` + ); + } + + /** + * @param {PerformanceMark} startMarker + * @returns {void} + */ + measureFromMarker(startMarker) { + const metricName = startMarker.name.replace(/:start$/, ''); + const endMarker = performance.mark(`${metricName}:end`); + + performance.measure( + metricName, + startMarker.name, + endMarker.name + ); + } + + /** + * @param {string} benchmarkName + * @param {Function} callback + * @returns {void} + */ + measure(benchmarkName, callback) { + const metricName = `${this.metricPrefix}:${benchmarkName}` + performance.mark(`${metricName}:start`); + + callback(); + + performance.mark(`${metricName}:end`); + + performance.measure( + benchmarkName, + `${metricName}:start`, + `${metricName}:end` + ); + } +} + +export const cartPerformance = new ThemePerformance('cart-performance'); diff --git a/assets/predictive-search.js b/assets/predictive-search.js new file mode 100644 index 000000000..599afbb4d --- /dev/null +++ b/assets/predictive-search.js @@ -0,0 +1,476 @@ +import { Component } from '@theme/component'; +import { debounce, onAnimationEnd, prefersReducedMotion, onDocumentReady } from '@theme/utilities'; +import { sectionRenderer } from '@theme/section-renderer'; +import { morph } from '@theme/morph'; +import { ThemeEvents } from '@theme/events'; +import { RecentlyViewed } from '@theme/recently-viewed-products'; +import { DialogCloseEvent, DialogComponent } from '@theme/dialog'; + +/** + * A custom element that allows the user to search for resources available on the store. + * + * @typedef {object} Refs + * @property {HTMLInputElement} searchInput - The search input element. + * @property {HTMLElement} predictiveSearchResults - The predictive search results container. + * @property {HTMLElement} resetButton - The reset button element. + * @property {HTMLElement[]} [resultsItems] - The search results items elements. + * @property {HTMLElement} [recentlyViewedWrapper] - The recently viewed products wrapper. + * @property {HTMLElement[]} [recentlyViewedTitle] - The recently viewed title elements. + * @property {HTMLElement[]} [recentlyViewedItems] - The recently viewed product items. + * @extends {Component} + */ +class PredictiveSearchComponent extends Component { + requiredRefs = ['searchInput', 'predictiveSearchResults', 'resetButton']; + + #controller = new AbortController(); + + /** + * @type {AbortController | null} + */ + #activeFetch = null; + + #resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + this.style.setProperty('--predictive-search-results-height', `${entry.contentRect.height}px`); + } + }); + + /** + * Get the dialog component. + * @returns {DialogComponent | null} The dialog component. + */ + get dialog() { + return this.closest('dialog-component'); + } + + connectedCallback() { + super.connectedCallback(); + + const { dialog } = this; + const { signal } = this.#controller; + + if (this.refs.searchInput.value.length > 0) { + this.#showResetButton(); + } + + if (dialog) { + document.addEventListener('keydown', this.#handleKeyboardShortcut, { signal }); + dialog.addEventListener(DialogCloseEvent.eventName, this.#handleDialogClose, { signal }); + + this.addEventListener('click', this.#handleModalClick, { signal }); + } else { + document.addEventListener(ThemeEvents.megaMenuHover, this.#blurSearch, { signal }); + } + + onDocumentReady(this.#getRecentlyViewed); + + const results = this.refs.predictiveSearchResults.firstElementChild; + + if (results) { + this.#resizeObserver.observe(results); + } + } + + /** + * Handles clicks within the predictive search modal to maintain focus on the input + * @param {MouseEvent} event - The mouse event + */ + #handleModalClick = (event) => { + const target = /** @type {HTMLElement} */ (event.target); + const isInteractiveElement = + target instanceof HTMLButtonElement || + target instanceof HTMLAnchorElement || + target instanceof HTMLInputElement || + target.closest('button') || + target.closest('a') || + target.closest('input'); + + if (!isInteractiveElement && this.refs.searchInput) { + this.refs.searchInput.focus(); + } + }; + + disconnectedCallback() { + super.disconnectedCallback(); + this.#controller.abort(); + this.#resizeObserver.disconnect(); + } + + /** + * Handles the CMD+K key combination. + * @param {KeyboardEvent} event - The keyboard event. + */ + #handleKeyboardShortcut = (event) => { + if (event.metaKey && event.key === 'k') { + this.dialog?.toggleDialog(); + } + }; + + /** + * Handles the dialog close event. + */ + #handleDialogClose = () => { + this.#resetSearch(); + }; + + expandSearch = () => { + // Add the expanded class to the search component + this.classList.add('predictive-search--expanded'); + if (this.dataset.activeColorScheme) { + const target = this.dialog ?? this; + target.classList.add(`color-${this.dataset.activeColorScheme}`); + } + }; + + get #allResultsItems() { + const containers = Array.from( + this.querySelectorAll( + '.predictive-search-results__wrapper-queries, ' + + '.predictive-search-results__wrapper-products, ' + + '.predictive-search-results__list' + ) + ); + + const allItems = containers + .flatMap((container) => { + if (container.classList.contains('predictive-search-results__wrapper-products')) { + return Array.from(container.querySelectorAll('.predictive-search-results__card')); + } + return Array.from(container.querySelectorAll('[ref="resultsItems[]"], .predictive-search-results__card')); + }) + .filter((item) => item instanceof HTMLElement); + + return /** @type {HTMLElement[]} */ (allItems); + } + + /** + * Track whether the last interaction was keyboard-based + * @type {boolean} + */ + #isKeyboardNavigation = false; + + get #currentIndex() { + return this.#allResultsItems?.findIndex((item) => item.getAttribute('aria-selected') === 'true') ?? -1; + } + + set #currentIndex(index) { + if (!this.#allResultsItems?.length) return; + + this.#allResultsItems.forEach((item) => { + item.classList.remove('keyboard-focus'); + }); + + for (const [itemIndex, item] of this.#allResultsItems.entries()) { + if (itemIndex === index) { + item.setAttribute('aria-selected', 'true'); + + if (this.#isKeyboardNavigation) { + item.classList.add('keyboard-focus'); + } + item.scrollIntoView({ behavior: prefersReducedMotion() ? 'instant' : 'smooth', block: 'nearest' }); + } else { + item.removeAttribute('aria-selected'); + } + } + this.refs.searchInput.focus(); + } + + get #currentItem() { + return this.#allResultsItems?.[this.#currentIndex]; + } + + /** + * Navigate through the predictive search results using arrow keys or close them with the Escape key. + * @param {KeyboardEvent} event - The keyboard event. + */ + onSearchKeyDown = (event) => { + if (event.key === 'Escape') { + this.#resetSearch(); + return; + } + + if (!this.#allResultsItems?.length || event.key === 'ArrowLeft' || event.key === 'ArrowRight') { + return; + } + + const currentIndex = this.#currentIndex; + const totalItems = this.#allResultsItems.length; + + switch (event.key) { + case 'ArrowDown': + this.#isKeyboardNavigation = true; + event.preventDefault(); + this.#currentIndex = currentIndex < totalItems - 1 ? currentIndex + 1 : 0; + break; + + case 'Tab': + if (event.shiftKey) { + this.#isKeyboardNavigation = true; + event.preventDefault(); + this.#currentIndex = currentIndex > 0 ? currentIndex - 1 : totalItems - 1; + } else { + this.#isKeyboardNavigation = true; + event.preventDefault(); + this.#currentIndex = currentIndex < totalItems - 1 ? currentIndex + 1 : 0; + } + break; + + case 'ArrowUp': + this.#isKeyboardNavigation = true; + event.preventDefault(); + this.#currentIndex = currentIndex > 0 ? currentIndex - 1 : totalItems - 1; + break; + + case 'Enter': + const singleResultContainer = this.refs.predictiveSearchResults.querySelector('[data-single-result-url]'); + if (singleResultContainer instanceof HTMLElement && singleResultContainer.dataset.singleResultUrl) { + event.preventDefault(); + window.location.href = singleResultContainer.dataset.singleResultUrl; + return; + } + + if (this.#currentIndex >= 0) { + event.preventDefault(); + this.#currentItem?.querySelector('a')?.click(); + } else { + const searchUrl = new URL(Theme.routes.search_url, location.origin); + searchUrl.searchParams.set('q', this.refs.searchInput.value); + window.location.href = searchUrl.toString(); + } + break; + } + }; + + /** + * Clears the recently viewed products. + * @param {Event} event - The event. + */ + clearRecentlyViewedProducts(event) { + event.stopPropagation(); + + RecentlyViewed.clearProducts(); + + const { recentlyViewedItems, recentlyViewedTitle, recentlyViewedWrapper } = this.refs; + + const allRecentlyViewedElements = [...(recentlyViewedItems || []), ...(recentlyViewedTitle || [])]; + + if (allRecentlyViewedElements.length === 0) { + return; + } + + if (recentlyViewedWrapper) { + recentlyViewedWrapper.classList.add('removing'); + + onAnimationEnd(recentlyViewedWrapper, () => { + recentlyViewedWrapper.remove(); + }); + } + } + + /** + * Reset the search state. + * @param {boolean} [keepFocus=true] - Whether to keep focus on input after reset + */ + resetSearch = debounce((keepFocus = true) => { + if (keepFocus) { + this.refs.searchInput.focus(); + } + this.#resetSearch(); + }, 100); + + /** + * Debounce the search handler to fetch and display search results based on the input value. + * Reset the current selection index and close results if the search term is empty. + */ + search = debounce((event) => { + // If the input is not a text input (like using the Escape key), don't search + if (!event.inputType) return; + + const searchTerm = this.refs.searchInput.value.trim(); + this.#currentIndex = -1; + + if (!searchTerm.length) { + this.#resetSearch(); + return; + } + + this.#showResetButton(); + this.#getSearchResults(searchTerm); + }, 200); + + /** + * Resets scroll positions for search results containers + */ + #resetScrollPositions() { + requestAnimationFrame(() => { + const resultsInner = this.refs.predictiveSearchResults.querySelector('.predictive-search-results__inner'); + if (resultsInner instanceof HTMLElement) { + resultsInner.scrollTop = 0; + } + + const formContent = this.querySelector('.predictive-search-form__content'); + if (formContent instanceof HTMLElement) { + formContent.scrollTop = 0; + } + }); + } + + /** + * Fetch search results using the section renderer and update the results container. + * @param {string} searchTerm - The term to search for + */ + async #getSearchResults(searchTerm) { + if (!this.dataset.sectionId) return; + + const url = new URL(Theme.routes.predictive_search_url, location.origin); + url.searchParams.set('q', searchTerm); + url.searchParams.set('resources[limit_scope]', 'each'); + + const { predictiveSearchResults } = this.refs; + + const abortController = this.#createAbortController(); + + sectionRenderer + .getSectionHTML(this.dataset.sectionId, false, url) + .then((resultsMarkup) => { + if (!resultsMarkup) return; + + if (abortController.signal.aborted) return; + + morph(predictiveSearchResults, resultsMarkup); + + this.#resetScrollPositions(); + }) + .catch((error) => { + if (abortController.signal.aborted) return; + throw error; + }); + } + + /** + * Fetch the markup for the recently viewed products. + * @returns {Promise} The markup for the recently viewed products. + */ + async #getRecentlyViewedProductsMarkup() { + if (!this.dataset.sectionId) return null; + + const viewedProducts = RecentlyViewed.getProducts(); + if (viewedProducts.length === 0) return null; + + const url = new URL(Theme.routes.search_url, location.origin); + url.searchParams.set('q', viewedProducts.map(/** @param {string} id */ (id) => `id:${id}`).join(' OR ')); + url.searchParams.set('resources[type]', 'product'); + + return sectionRenderer.getSectionHTML(this.dataset.sectionId, false, url); + } + + /** + * Fetch recently viewed products using the section renderer and update the results container. + */ + #getRecentlyViewed = async () => { + const { predictiveSearchResults } = this.refs; + // Get the initial height before the results are rendered + const abortController = this.#createAbortController(); + + const resultsMarkup = await this.#getRecentlyViewedProductsMarkup(); + if (!resultsMarkup) return; + + const parsedNextPage = new DOMParser().parseFromString(resultsMarkup, 'text/html'); + const recentlyViewedProductsHtml = parsedNextPage.getElementById('predictive-search-products'); + if (!recentlyViewedProductsHtml) return; + + for (const child of recentlyViewedProductsHtml.children) { + if (child instanceof HTMLElement) { + child.setAttribute('ref', 'recentlyViewedWrapper'); + } + } + + const collectionElement = predictiveSearchResults.querySelector('#predictive-search-products'); + if (!collectionElement) return; + + if (this.refs.recentlyViewedWrapper) { + this.refs.recentlyViewedWrapper.remove(); + } + + if (abortController.signal.aborted) return; + // Prepend the recently viewed products to the collection + collectionElement.prepend(...recentlyViewedProductsHtml.children); + }; + + #hideResetButton() { + const { resetButton } = this.refs; + + resetButton.hidden = true; + } + + #showResetButton() { + const { resetButton } = this.refs; + + resetButton.hidden = false; + } + + #createAbortController() { + const abortController = new AbortController(); + if (this.#activeFetch) { + this.#activeFetch.abort(); + } + this.#activeFetch = abortController; + return abortController; + } + + #resetSearch = async () => { + const { predictiveSearchResults, searchInput } = this.refs; + const emptySectionId = 'predictive-search-empty'; + + this.#currentIndex = -1; + searchInput.value = ''; + this.#hideResetButton(); + + const abortController = this.#createAbortController(); + const emptySectionMarkup = await sectionRenderer.getSectionHTML(emptySectionId, false); + const parsedEmptySectionMarkup = new DOMParser() + .parseFromString(emptySectionMarkup, 'text/html') + .querySelector('.predictive-search-empty-section'); + + if (!parsedEmptySectionMarkup) throw new Error('No empty section markup found'); + + /** This needs to be awaited and not .then so the DOM is already morphed + * when #closeResults is called and therefore the height is animated */ + const viewedProducts = RecentlyViewed.getProducts(); + + if (viewedProducts.length > 0) { + const recentlyViewedMarkup = await this.#getRecentlyViewedProductsMarkup(); + if (!recentlyViewedMarkup) return; + + const parsedRecentlyViewedMarkup = new DOMParser().parseFromString(recentlyViewedMarkup, 'text/html'); + const recentlyViewedProductsHtml = parsedRecentlyViewedMarkup.getElementById('predictive-search-products'); + if (!recentlyViewedProductsHtml) return; + + for (const child of recentlyViewedProductsHtml.children) { + if (child instanceof HTMLElement) { + child.setAttribute('ref', 'recentlyViewedWrapper'); + } + } + + const collectionElement = parsedEmptySectionMarkup.querySelector('#predictive-search-products'); + if (!collectionElement) return; + collectionElement.prepend(...recentlyViewedProductsHtml.children); + } + + if (abortController.signal.aborted) return; + + morph(predictiveSearchResults, parsedEmptySectionMarkup); + this.#resetScrollPositions(); + }; + + /** + * Closes the predictive search. + */ + #blurSearch = () => { + this.refs.searchInput.blur(); + }; +} + +if (!customElements.get('predictive-search-component')) { + customElements.define('predictive-search-component', PredictiveSearchComponent); +} diff --git a/assets/product-card-link.js b/assets/product-card-link.js new file mode 100644 index 000000000..6a3d86144 --- /dev/null +++ b/assets/product-card-link.js @@ -0,0 +1,68 @@ +// Create a new custom element for product links with images for transitions to PDP +class ProductCardLink extends HTMLElement { + connectedCallback() { + this.addEventListener('click', (event) => setTimeout(() => this.#handleClick(event), 0)); + } + + disconnectedCallback() { + this.removeEventListener('click', this.#handleClick); + } + + get productTransitionEnabled() { + return this.getAttribute('data-product-transition') === 'true'; + } + + get featuredMediaUrl() { + return this.getAttribute('data-featured-media-url'); + } + + /** + * Handles the click event for the product link + * @param {Event} event + */ + #handleClick = (event) => { + // If the event has been prevented, don't do anything, another component is handling the click or if it's an input (swatches) + if (event.defaultPrevented || event.target instanceof HTMLInputElement) return; + + const gallery = this.querySelector('[data-view-transition-to-main-product]'); + if (!this.productTransitionEnabled || !(gallery instanceof HTMLElement)) return; + + // Check on the current active image, whether it's a product card image or a resource card image + const activeImage = + gallery.querySelector('slideshow-slide[aria-hidden="false"] [transitionToProduct="true"]') || + gallery.querySelector('[transitionToProduct="true"]:last-child'); + + if (activeImage instanceof HTMLImageElement) this.#setImageSrcset(activeImage); + + gallery.setAttribute('data-view-transition-type', 'product-image-transition'); + gallery.setAttribute('data-view-transition-triggered', 'true'); + }; + + /** + * Sets the srcset for the image + * @param {HTMLImageElement} image + */ + #setImageSrcset(image) { + if (!this.featuredMediaUrl) return; + + const currentImageUrl = new URL(image.currentSrc); + + // Deliberately not using origin, as it includes the protocol, which is usually skipped for featured media + const currentImageRawUrl = currentImageUrl.host + currentImageUrl.pathname; + + if (!this.featuredMediaUrl.includes(currentImageRawUrl)) { + const imageFade = image.animate([{ opacity: 0.8 }, { opacity: 1 }], { + duration: 125, + easing: 'ease-in-out', + }); + + imageFade.onfinish = () => { + image.srcset = this.featuredMediaUrl ?? ''; + }; + } + } +} + +if (!customElements.get('product-card-link')) { + customElements.define('product-card-link', ProductCardLink); +} diff --git a/assets/product-card.js b/assets/product-card.js new file mode 100644 index 000000000..05d5e7fbb --- /dev/null +++ b/assets/product-card.js @@ -0,0 +1,502 @@ +import VariantPicker from '@theme/variant-picker'; +import { Component } from '@theme/component'; +import { debounce, isDesktopBreakpoint, mediaQueryLarge, requestYieldCallback } from '@theme/utilities'; +import { ThemeEvents, VariantSelectedEvent, VariantUpdateEvent, SlideshowSelectEvent } from '@theme/events'; +import { morph } from '@theme/morph'; + +/** + * A custom element that displays a product card. + * + * @typedef {object} Refs + * @property {HTMLAnchorElement} productCardLink - The product card link element. + * @property {import('slideshow').Slideshow} [slideshow] - The slideshow component. + * @property {import('quick-add').QuickAddComponent} [quickAdd] - The quick add component. + * @property {HTMLElement} [cardGallery] - The card gallery component. + * + * @extends {Component} + */ +export class ProductCard extends Component { + requiredRefs = ['productCardLink']; + + get productPageUrl() { + return this.refs.productCardLink.href; + } + + #fetchProductPageHandler = () => { + if (!this.refs.quickAdd?.cachedProductHtml) { + this.refs.quickAdd?.fetchProductPage(this.productPageUrl); + } + }; + + /** + * Navigates to a URL link. Respects modifier keys for opening in new tab/window. + * @param {Event} event - The event that triggered the navigation. + * @param {URL} url - The URL to navigate to. + */ + #navigateToURL = (event, url) => { + // Check for modifier keys that should open in new tab/window (only for mouse events) + const shouldOpenInNewTab = + event instanceof MouseEvent && (event.metaKey || event.ctrlKey || event.shiftKey || event.button === 1); + + if (shouldOpenInNewTab) { + event.preventDefault(); + window.open(url.href, '_blank'); + return; + } else { + window.location.href = url.href; + } + }; + + connectedCallback() { + super.connectedCallback(); + + const link = this.refs.productCardLink; + if (!(link instanceof HTMLAnchorElement)) throw new Error('Product card link not found'); + this.#handleQuickAdd(); + + this.addEventListener(ThemeEvents.variantUpdate, this.#handleVariantUpdate); + this.addEventListener(ThemeEvents.variantSelected, this.#handleVariantSelected); + this.addEventListener(SlideshowSelectEvent.eventName, this.#handleSlideshowSelect); + mediaQueryLarge.addEventListener('change', this.#handleQuickAdd); + + this.addEventListener('click', this.navigateToProduct); + + // Preload the next image on the slideshow to avoid white flashes on previewImage + setTimeout(() => { + if (this.refs.slideshow?.isNested) { + this.#preloadNextPreviewImage(); + } + }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.removeEventListener('click', this.navigateToProduct); + } + + #preloadNextPreviewImage() { + const currentSlide = this.refs.slideshow?.slides?.[this.refs.slideshow?.current]; + currentSlide?.nextElementSibling?.querySelector('img[loading="lazy"]')?.removeAttribute('loading'); + } + + /** + * Handles the quick add event. + */ + #handleQuickAdd = () => { + this.removeEventListener('pointerenter', this.#fetchProductPageHandler); + this.removeEventListener('focusin', this.#fetchProductPageHandler); + + if (isDesktopBreakpoint()) { + this.addEventListener('pointerenter', this.#fetchProductPageHandler); + this.addEventListener('focusin', this.#fetchProductPageHandler); + } + }; + + /** + * Handles the variant selected event. + * @param {VariantSelectedEvent} event - The variant selected event. + */ + #handleVariantSelected = (event) => { + if (event.target !== this.variantPicker) { + this.variantPicker?.updateSelectedOption(event.detail.resource.id); + } + }; + + /** + * Handles the variant update event. + * Updates price, checks for unavailable variants, and updates product URL. + * @param {VariantUpdateEvent} event - The variant update event. + */ + #handleVariantUpdate = (event) => { + // Stop the event from bubbling up to the section, variant updates triggered from product cards are fully handled + // by this component and should not affect anything outside the card. + event.stopPropagation(); + + this.updatePrice(event); + this.#isUnavailableVariantSelected(event); + this.#updateProductUrl(event); + this.refs.quickAdd?.fetchProductPage(this.productPageUrl); + + if (event.target !== this.variantPicker) { + this.variantPicker?.updateVariantPicker(event.detail.data.html); + } + + this.#updateVariantImages(); + this.#previousSlideIndex = null; + + // Remove attribute after re-rendering since a variant selection has been made + this.removeAttribute('data-no-swatch-selected'); + + // Force overflow list to reflow after variant update + // This fixes an issue where the overflow counter doesn't update properly in some browsers + this.#updateOverflowList(); + }; + + /** + * Forces the overflow list to recalculate by dispatching a reflow event. + * This ensures the overflow counter displays correctly after variant updates. + */ + #updateOverflowList() { + // Find the overflow list in the variant picker + const overflowList = this.querySelector('swatches-variant-picker-component overflow-list'); + const isActiveOverflowList = overflowList?.querySelector('[slot="overflow"]') ? true : false; + if (!overflowList || !isActiveOverflowList) return; + + // Use requestAnimationFrame to ensure DOM has been updated + requestAnimationFrame(() => { + // Dispatch a reflow event to trigger recalculation + overflowList.dispatchEvent( + new CustomEvent('reflow', { + bubbles: true, + detail: {}, + }) + ); + }); + } + + /** + * Updates the DOM with a new price. + * @param {VariantUpdateEvent} event - The variant update event. + */ + updatePrice(event) { + const priceContainer = this.querySelectorAll(`product-price [ref='priceContainer']`)[1]; + const newPriceElement = event.detail.data.html.querySelector(`product-price [ref='priceContainer']`); + + if (newPriceElement && priceContainer) { + morph(priceContainer, newPriceElement); + } + } + + /** + * Updates the product URL based on the variant update event. + * @param {VariantUpdateEvent} event - The variant update event. + */ + #updateProductUrl(event) { + const anchorElement = event.detail.data.html?.querySelector('product-card a'); + const featuredMediaUrl = event.detail.data.html + ?.querySelector('product-card-link') + ?.getAttribute('data-featured-media-url'); + + // If the product card is inside a product link, update the product link's featured media URL + if (featuredMediaUrl && this.closest('product-card-link')) + this.closest('product-card-link')?.setAttribute('data-featured-media-url', featuredMediaUrl); + + if (anchorElement instanceof HTMLAnchorElement) { + // If the href is empty, don't update the product URL eg: unavailable variant + if (anchorElement.getAttribute('href')?.trim() === '') return; + + this.refs.productCardLink.href = anchorElement.href; + } + } + + /** + * Checks if an unavailable variant is selected. + * @param {VariantUpdateEvent} event - The variant update event. + */ + #isUnavailableVariantSelected(event) { + const allVariants = /** @type {NodeListOf} */ ( + event.detail.data.html.querySelectorAll('input:checked') + ); + + for (const variant of allVariants) { + this.#toggleAddToCartButton(variant.dataset.optionAvailable === 'true'); + } + } + + /** + * Toggles the add to cart button state. + * @param {boolean} enable - Whether to enable or disable the button. + */ + #toggleAddToCartButton(enable) { + const addToCartButton = this.querySelector('.add-to-cart__button button'); + + if (addToCartButton instanceof HTMLButtonElement) { + addToCartButton.disabled = !enable; + } + } + + /** + * Hide the variant images that are not for the selected variant. + */ + #updateVariantImages() { + const { slideshow } = this.refs; + if (!this.variantPicker?.selectedOption) { + return; + } + + const selectedImageId = this.variantPicker?.selectedOption.dataset.optionMediaId; + + if (slideshow && selectedImageId) { + const { slides = [] } = slideshow.refs; + + for (const slide of slides) { + if (slide.getAttribute('variant-image') == null) continue; + + slide.hidden = slide.getAttribute('slide-id') !== selectedImageId; + } + + slideshow.select({ id: selectedImageId }, undefined, { animate: false }); + } + } + + /** + * Gets all variant inputs. + * @returns {NodeListOf} All variant input elements. + */ + get allVariants() { + return this.querySelectorAll('input[data-variant-id]'); + } + + /** + * Gets the variant picker component. + * @returns {VariantPicker | null} The variant picker component. + */ + get variantPicker() { + return this.querySelector('swatches-variant-picker-component'); + } + /** @type {number | null} */ + #previousSlideIndex = null; + + /** + * Handles the slideshow select event. + * @param {SlideshowSelectEvent} event - The slideshow select event. + */ + #handleSlideshowSelect = (event) => { + if (event.detail.userInitiated) { + this.#previousSlideIndex = event.detail.index; + } + }; + + /** + * Previews a variant. + * @param {string} id - The id of the variant to preview. + */ + previewVariant(id) { + const { slideshow } = this.refs; + + if (!slideshow) return; + + this.resetVariant.cancel(); + slideshow.select({ id }, undefined, { animate: false }); + } + + /** + * Previews the next image. + * @param {PointerEvent} event - The pointer event. + */ + previewImage(event) { + if (event.pointerType !== 'mouse') return; + + const { slideshow } = this.refs; + + if (!slideshow) return; + + this.resetVariant.cancel(); + + if (this.#previousSlideIndex != null && this.#previousSlideIndex > 0) { + slideshow.select(this.#previousSlideIndex, undefined, { animate: false }); + } else { + slideshow.next(undefined, { animate: false }); + setTimeout(() => this.#preloadNextPreviewImage()); + } + } + + /** + * Resets the image to the variant image. + * @param {PointerEvent} event - The pointer event. + */ + resetImage(event) { + if (event.pointerType !== 'mouse') return; + + const { slideshow } = this.refs; + + if (!this.variantPicker) { + if (!slideshow) return; + slideshow.previous(undefined, { animate: false }); + } else { + this.#resetVariant(); + } + } + + /** + * Resets the image to the variant image. + */ + #resetVariant = () => { + const { slideshow } = this.refs; + + if (!slideshow) return; + + // If we have a selected variant, always use its image + if (this.variantPicker?.selectedOption) { + const id = this.variantPicker.selectedOption.dataset.optionMediaId; + if (id) { + slideshow.select({ id }, undefined, { animate: false }); + return; + } + } + + // No variant selected - use initial slide if it's valid + const initialSlide = slideshow.initialSlide; + const slideId = initialSlide?.getAttribute('slide-id'); + if (initialSlide && slideshow.slides?.includes(initialSlide) && slideId) { + slideshow.select({ id: slideId }, undefined, { animate: false }); + return; + } + + // No valid initial slide or selected variant - go to previous + slideshow.previous(undefined, { animate: false }); + }; + + /** + * Intercepts the click event on the product card anchor, we want + * to use this to add an intermediate state to the history. + * This intermediate state captures the page we were on so that we + * navigate back to the same page when the user navigates back. + * In addition to that, it captures the product card anchor so that we + * have the specific product card in view. + * + * A product card can have other interactive elements like variant picker, + * so we do not navigate if the click was on one of those elements. + * + * @param {Event} event + */ + navigateToProduct = (event) => { + if (!(event.target instanceof Element)) return; + + // Don't navigate if this product card is marked as no-navigation (e.g., in theme editor) + if (this.hasAttribute('data-no-navigation')) return; + + const interactiveElement = event.target.closest('button, input, label, select, a, [tabindex="1"]'); + + // If the click was on an interactive element which is not the main link, do nothing. + if (interactiveElement && interactiveElement !== this.refs.productCardLink) { + return; + } + + const link = this.refs.productCardLink; + if (!link.href) return; + const linkURL = new URL(link.href); + + const productCardAnchor = link.getAttribute('id'); + if (!productCardAnchor) return; + + const url = new URL(window.location.href); + const parent = this.closest('li'); + url.hash = productCardAnchor; + if (parent && parent.dataset.page) { + url.searchParams.set('page', parent.dataset.page); + } + + if (!window.Shopify.designMode) { + requestYieldCallback(() => { + history.replaceState({}, '', url.toString()); + }); + } + + this.#navigateToURL(event, linkURL); + }; + + /** + * Resets the variant. + */ + resetVariant = debounce(this.#resetVariant, 100); +} + +if (!customElements.get('product-card')) { + customElements.define('product-card', ProductCard); +} + +/** + * A custom element that displays a variant picker with swatches. + * + * @typedef {object} SwatchesRefs + * @property {HTMLElement} overflowList + * + * @extends {VariantPicker} + */ +class SwatchesVariantPickerComponent extends VariantPicker { + connectedCallback() { + super.connectedCallback(); + + // Cache the parent product card + this.parentProductCard = this.closest('product-card'); + + // Listen for variant updates to apply pending URL changes + this.addEventListener(ThemeEvents.variantUpdate, this.#handleCardVariantUrlUpdate.bind(this)); + } + + /** + * Updates the card URL when a variant is selected. + */ + #handleCardVariantUrlUpdate() { + if (this.pendingVariantId && this.parentProductCard instanceof ProductCard) { + const currentUrl = new URL(this.parentProductCard.refs.productCardLink.href); + currentUrl.searchParams.set('variant', this.pendingVariantId); + this.parentProductCard.refs.productCardLink.href = currentUrl.toString(); + this.pendingVariantId = null; + } + } + + /** + * Override the variantChanged method to handle unavailable swatches with available alternatives. + * @param {Event} event - The variant change event. + */ + variantChanged(event) { + if (!(event.target instanceof HTMLElement)) return; + + // Check if this is a swatch input + const isSwatchInput = event.target instanceof HTMLInputElement && event.target.name?.includes('-swatch'); + const clickedSwatch = event.target; + const availableCount = parseInt(clickedSwatch.dataset.availableCount || '0'); + const firstAvailableVariantId = clickedSwatch.dataset.firstAvailableOrFirstVariantId; + + // For swatch inputs, check if we need special handling + if (isSwatchInput && availableCount > 0 && firstAvailableVariantId) { + // If this is an unavailable variant but there are available alternatives + // Prevent the default handling + event.stopPropagation(); + + // Update the selected option visually + this.updateSelectedOption(clickedSwatch); + + // Build request URL with the first available variant + const productUrl = this.dataset.productUrl?.split('?')[0]; + + if (!productUrl) return; + + const url = new URL(productUrl, window.location.origin); + url.searchParams.set('variant', firstAvailableVariantId); + url.searchParams.set('section_id', 'section-rendering-product-card'); + + const requestUrl = url.href; + + // Store the variant ID we want to apply to the URL + this.pendingVariantId = firstAvailableVariantId; + + // Use parent's fetch method + this.fetchUpdatedSection(requestUrl); + return; + } + + // For all other cases, use the default behavior + super.variantChanged(event); + } + + /** + * Shows all swatches. + * @param {Event} [event] - The event that triggered the show all swatches. + */ + showAllSwatches(event) { + event?.preventDefault(); + + const { overflowList } = this.refs; + + if (overflowList instanceof OverflowList) { + overflowList.showAll(); + } + } +} + +if (!customElements.get('swatches-variant-picker-component')) { + customElements.define('swatches-variant-picker-component', SwatchesVariantPickerComponent); +} diff --git a/assets/product-form.js b/assets/product-form.js new file mode 100644 index 000000000..7205a3668 --- /dev/null +++ b/assets/product-form.js @@ -0,0 +1,448 @@ +import { Component } from '@theme/component'; +import { fetchConfig, onAnimationEnd, preloadImage } from '@theme/utilities'; +import { ThemeEvents, CartAddEvent, CartErrorEvent, VariantUpdateEvent } from '@theme/events'; +import { cartPerformance } from '@theme/performance'; +import { morph } from '@theme/morph'; + +export const ADD_TO_CART_TEXT_ANIMATION_DURATION = 2000; + +/** + * A custom element that manages an add to cart button. + * + * @typedef {object} AddToCartRefs + * @property {HTMLButtonElement} addToCartButton - The add to cart button. + * @extends Component + */ +export class AddToCartComponent extends Component { + requiredRefs = ['addToCartButton']; + + /** @type {number | undefined} */ + #animationTimeout; + + /** @type {number | undefined} */ + #cleanupTimeout; + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener('pointerenter', this.#preloadImage); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + if (this.#animationTimeout) clearTimeout(this.#animationTimeout); + if (this.#cleanupTimeout) clearTimeout(this.#cleanupTimeout); + this.removeEventListener('pointerenter', this.#preloadImage); + } + + /** + * Disables the add to cart button. + */ + disable() { + this.refs.addToCartButton.disabled = true; + } + + /** + * Enables the add to cart button. + */ + enable() { + this.refs.addToCartButton.disabled = false; + } + + /** + * Handles the click event for the add to cart button. + * @param {MouseEvent & {target: HTMLElement}} event - The click event. + */ + handleClick(event) { + this.animateAddToCart(); + + if (!event.target.closest('.quick-add-modal')) this.#animateFlyToCart(); + } + + #preloadImage = () => { + const image = this.dataset.productVariantMedia; + + if (!image) return; + + preloadImage(image); + }; + + /** + * Animates the fly to cart animation. + */ + #animateFlyToCart() { + const { addToCartButton } = this.refs; + const cartIcon = document.querySelector('.header-actions__cart-icon'); + + const image = this.dataset.productVariantMedia; + + if (!cartIcon || !addToCartButton || !image) return; + + const flyToCartElement = /** @type {FlyToCart} */ (document.createElement('fly-to-cart')); + + flyToCartElement.style.setProperty('background-image', `url(${image})`); + flyToCartElement.source = addToCartButton; + flyToCartElement.destination = cartIcon; + + document.body.appendChild(flyToCartElement); + } + + /** + * Animates the add to cart button. + */ + animateAddToCart() { + const { addToCartButton } = this.refs; + + if (this.#animationTimeout) clearTimeout(this.#animationTimeout); + if (this.#cleanupTimeout) clearTimeout(this.#cleanupTimeout); + + if (!addToCartButton.classList.contains('atc-added')) { + addToCartButton.classList.add('atc-added'); + } + + this.#animationTimeout = setTimeout(() => { + this.#cleanupTimeout = setTimeout(() => { + this.refs.addToCartButton.classList.remove('atc-added'); + }, 10); + }, ADD_TO_CART_TEXT_ANIMATION_DURATION); + } +} + +if (!customElements.get('add-to-cart-component')) { + customElements.define('add-to-cart-component', AddToCartComponent); +} + +/** + * A custom element that manages a product form. + * + * @typedef {object} ProductFormRefs + * @property {HTMLInputElement} variantId - The form input for submitting the variant ID. + * @property {AddToCartComponent | undefined} addToCartButtonContainer - The add to cart button container element. + * @property {HTMLElement | undefined} addToCartTextError - The add to cart text error. + * @property {HTMLElement | undefined} acceleratedCheckoutButtonContainer - The accelerated checkout button container element. + * @property {HTMLElement} liveRegion - The live region. + * + * @extends Component + */ +class ProductFormComponent extends Component { + requiredRefs = ['variantId', 'liveRegion']; + #abortController = new AbortController(); + + /** @type {number | undefined} */ + #timeout; + + connectedCallback() { + super.connectedCallback(); + + const { signal } = this.#abortController; + const target = this.closest('.shopify-section, dialog, product-card'); + target?.addEventListener(ThemeEvents.variantUpdate, this.#onVariantUpdate, { signal }); + target?.addEventListener(ThemeEvents.variantSelected, this.#onVariantSelected, { signal }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + this.#abortController.abort(); + } + + /** + * Handles the submit event for the product form. + * + * @param {Event} event - The submit event. + */ + handleSubmit(event) { + const { addToCartTextError } = this.refs; + // Stop default behaviour from the browser + event.preventDefault(); + + if (this.#timeout) clearTimeout(this.#timeout); + + // Check if the add to cart button is disabled and do an early return if it is + if (this.refs.addToCartButtonContainer?.refs.addToCartButton?.getAttribute('disabled') === 'true') return; + + // Send the add to cart information to the cart + const form = this.querySelector('form'); + + if (!form) throw new Error('Product form element missing'); + + const formData = new FormData(form); + + const cartItemsComponents = document.querySelectorAll('cart-items-component'); + let cartItemComponentsSectionIds = []; + cartItemsComponents.forEach((item) => { + if (item instanceof HTMLElement && item.dataset.sectionId) { + cartItemComponentsSectionIds.push(item.dataset.sectionId); + } + formData.append('sections', cartItemComponentsSectionIds.join(',')); + }); + + const fetchCfg = fetchConfig('javascript', { body: formData }); + + fetch(Theme.routes.cart_add_url, { + ...fetchCfg, + headers: { + ...fetchCfg.headers, + Accept: 'text/html', + }, + }) + .then((response) => response.json()) + .then((response) => { + if (response.status) { + window.dispatchEvent(new CartErrorEvent(this.id, response.message)); + + if (!addToCartTextError) return; + addToCartTextError.classList.remove('hidden'); + + // Reuse the text node if the user is spam-clicking + const textNode = addToCartTextError.childNodes[2]; + if (textNode) { + textNode.textContent = response.message; + } else { + const newTextNode = document.createTextNode(response.message); + addToCartTextError.appendChild(newTextNode); + } + + // Create or get existing error live region for screen readers + this.#setLiveRegionText(response.message); + + this.#timeout = setTimeout(() => { + if (!addToCartTextError) return; + addToCartTextError.classList.add('hidden'); + + // Clear the announcement + this.#clearLiveRegionText(); + }, 10000); + + // When we add more than the maximum amount of items to the cart, we need to dispatch a cart update event + // because our back-end still adds the max allowed amount to the cart. + this.dispatchEvent( + new CartAddEvent({}, this.id, { + didError: true, + source: 'product-form-component', + itemCount: Number(formData.get('quantity')) || Number(this.dataset.quantityDefault), + productId: this.dataset.productId, + }) + ); + + return; + } else { + const id = formData.get('id'); + + if (addToCartTextError) { + addToCartTextError.classList.add('hidden'); + addToCartTextError.removeAttribute('aria-live'); + } + + if (!id) throw new Error('Form ID is required'); + + // Add aria-live region to inform screen readers that the item was added + if (this.refs.addToCartButtonContainer?.refs.addToCartButton) { + const addToCartButton = this.refs.addToCartButtonContainer.refs.addToCartButton; + const addedTextElement = addToCartButton.querySelector('.add-to-cart-text--added'); + const addedText = addedTextElement?.textContent?.trim() || Theme.translations.added; + + this.#setLiveRegionText(addedText); + + setTimeout(() => { + this.#clearLiveRegionText(); + }, 5000); + } + + this.dispatchEvent( + new CartAddEvent({}, id.toString(), { + source: 'product-form-component', + itemCount: Number(formData.get('quantity')) || Number(this.dataset.quantityDefault), + productId: this.dataset.productId, + sections: response.sections, + }) + ); + } + }) + .catch((error) => { + console.error(error); + }) + .finally(() => { + // add more thing to do in here if needed. + cartPerformance.measureFromEvent('add:user-action', event); + }); + } + + /** + * @param {*} text + */ + #setLiveRegionText(text) { + const liveRegion = this.refs.liveRegion; + liveRegion.textContent = text; + } + + #clearLiveRegionText() { + const liveRegion = this.refs.liveRegion; + liveRegion.textContent = ''; + } + + /** + * @param {VariantUpdateEvent} event + */ + #onVariantUpdate = (event) => { + if (event.detail.data.newProduct) { + this.dataset.productId = event.detail.data.newProduct.id; + } else if (event.detail.data.productId !== this.dataset.productId) { + return; + } + + const { variantId, addToCartButtonContainer } = this.refs; + + const currentAddToCartButton = addToCartButtonContainer?.refs.addToCartButton; + const newAddToCartButton = event.detail.data.html.querySelector('[ref="addToCartButton"]'); + + if (!currentAddToCartButton) return; + + // Update the button state + if (event.detail.resource == null || event.detail.resource.available == false) { + addToCartButtonContainer.disable(); + this.refs.acceleratedCheckoutButtonContainer?.setAttribute('hidden', 'true'); + } else { + addToCartButtonContainer.enable(); + this.refs.acceleratedCheckoutButtonContainer?.removeAttribute('hidden'); + } + + // Update the add to cart button text and icon + if (newAddToCartButton) { + morph(currentAddToCartButton, newAddToCartButton); + } + + // Update the variant ID + variantId.value = event.detail.resource.id ?? ''; + + // Set the data attribute for the add to cart button to the product variant media if it exists + if (event.detail.resource) { + const productVariantMedia = event.detail.resource.featured_media?.preview_image?.src; + productVariantMedia && + addToCartButtonContainer?.setAttribute('data-product-variant-media', productVariantMedia + '&width=100'); + } + }; + + /** + * Disable the add to cart button while the UI is updating before #onVariantUpdate is called. + * Accelerated checkout button is also disabled via its own event listener not exposed to the theme. + */ + #onVariantSelected = () => { + this.refs.addToCartButtonContainer?.disable(); + }; +} + +if (!customElements.get('product-form-component')) { + customElements.define('product-form-component', ProductFormComponent); +} + +class FlyToCart extends HTMLElement { + /** @type {Element} */ + source; + + /** @type {Element} */ + destination; + + connectedCallback() { + this.#animate(); + } + + #animate() { + const rect = this.getBoundingClientRect(); + const sourceRect = this.source.getBoundingClientRect(); + const destinationRect = this.destination.getBoundingClientRect(); + + //Define bezier curve points + // Maybe add half of the size of the flying thingy to the x and y to make it center properly + const offset = { + x: rect.width / 2, + y: rect.height / 2, + }; + const startPoint = { + x: sourceRect.left + sourceRect.width / 2 - offset.x, + y: sourceRect.top + sourceRect.height / 2 - offset.y, + }; + + const endPoint = { + x: destinationRect.left + destinationRect.width / 2 - offset.x, + y: destinationRect.top + destinationRect.height / 2 - offset.y, + }; + + //Calculate the control points + const controlPoint1 = { x: startPoint.x, y: startPoint.y - 200 }; // Go up 200px + const controlPoint2 = { x: endPoint.x - 300, y: endPoint.y - 100 }; // Go left 300px and up 100px + + //Animation variables + /** @type {number | null} */ + let startTime = null; + const duration = 600; // 600ms + + this.style.opacity = '1'; + + /** + * Animates the flying thingy along the bezier curve. + * @param {number} currentTime - The current time. + */ + const animate = (currentTime) => { + if (!startTime) startTime = currentTime; + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // Calculate current position along the bezier curve + const position = bezierPoint(progress, startPoint, controlPoint1, controlPoint2, endPoint); + + //Update the position of the flying thingy + this.style.setProperty('--x', `${position.x}px`); + this.style.setProperty('--y', `${position.y}px`); + + // Scale down as it approaches the cart + const scale = 1 - progress * 0.5; + this.style.setProperty('--scale', `${scale}`); + + //Continue the animation if not finished + if (progress < 1) { + requestAnimationFrame(animate); + } else { + //Fade out the flying thingy + this.style.opacity = '0'; + onAnimationEnd(this, () => this.remove()); + } + }; + + // Position the flying thingy back to the start point + this.style.setProperty('--x', `${startPoint.x}px`); + this.style.setProperty('--y', `${startPoint.y}px`); + + //Start the animation + requestAnimationFrame(animate); + } +} + +/** + * Calculates a point on a cubic Bézier curve. + * @param {number} t - The parameter value (0 <= t <= 1). + * @param {{x: number, y: number}} p0 - The starting point (x, y). + * @param {{x: number, y: number}} p1 - The first control point (x, y). + * @param {{x: number, y: number}} p2 - The second control point (x, y). + * @param {{x: number, y: number}} p3 - The ending point (x, y). + * @returns {{x: number, y: number}} The point on the curve. + */ +function bezierPoint(t, p0, p1, p2, p3) { + const cX = 3 * (p1.x - p0.x); + const bX = 3 * (p2.x - p1.x) - cX; + const aX = p3.x - p0.x - cX - bX; + + const cY = 3 * (p1.y - p0.y); + const bY = 3 * (p2.y - p1.y) - cY; + const aY = p3.y - p0.y - cY - bY; + + const x = aX * Math.pow(t, 3) + bX * Math.pow(t, 2) + cX * t + p0.x; + const y = aY * Math.pow(t, 3) + bY * Math.pow(t, 2) + cY * t + p0.y; + + return { x, y }; +} + +if (!customElements.get('fly-to-cart')) { + customElements.define('fly-to-cart', FlyToCart); +} diff --git a/assets/product-inventory.js b/assets/product-inventory.js new file mode 100644 index 000000000..447ccafd2 --- /dev/null +++ b/assets/product-inventory.js @@ -0,0 +1,36 @@ +import { ThemeEvents, VariantUpdateEvent } from '@theme/events'; +import { morph } from '@theme/morph'; + +class ProductInventory extends HTMLElement { + connectedCallback() { + const closestSection = this.closest('.shopify-section, dialog'); + closestSection?.addEventListener(ThemeEvents.variantUpdate, this.updateInventory); + } + + disconnectedCallback() { + const closestSection = this.closest('.shopify-section, dialog'); + closestSection?.removeEventListener(ThemeEvents.variantUpdate, this.updateInventory); + } + + /** + * Updates the inventory. + * @param {VariantUpdateEvent} event - The variant update event. + */ + updateInventory = (event) => { + if (event.detail.data.newProduct) { + this.dataset.productId = event.detail.data.newProduct.id; + } else if (event.target instanceof HTMLElement && event.target.dataset.productId !== this.dataset.productId) { + return; + } + + const newInventory = event.detail.data.html.querySelector('product-inventory'); + + if (!newInventory) return; + + morph(this, newInventory, { childrenOnly: true }); + }; +} + +if (!customElements.get('product-inventory')) { + customElements.define('product-inventory', ProductInventory); +} diff --git a/assets/product-price.js b/assets/product-price.js new file mode 100644 index 000000000..2468387d3 --- /dev/null +++ b/assets/product-price.js @@ -0,0 +1,47 @@ +import { ThemeEvents, VariantUpdateEvent } from '@theme/events'; + +/** + * A custom element that displays a product price. + * This component listens for variant update events and updates the price display accordingly. + * It handles price updates from two different sources: + * 1. Variant picker (in quick add modal or product page) + * 2. Swatches variant picker (in product cards) + */ +class ProductPrice extends HTMLElement { + connectedCallback() { + const closestSection = this.closest('.shopify-section, dialog'); + if (!closestSection) return; + closestSection.addEventListener(ThemeEvents.variantUpdate, this.updatePrice); + } + + disconnectedCallback() { + const closestSection = this.closest('.shopify-section, dialog'); + if (!closestSection) return; + closestSection.removeEventListener(ThemeEvents.variantUpdate, this.updatePrice); + } + + /** + * Updates the price. + * @param {VariantUpdateEvent} event - The variant update event. + */ + updatePrice = (event) => { + if (event.detail.data.newProduct) { + this.dataset.productId = event.detail.data.newProduct.id; + } else if (event.target instanceof HTMLElement && event.target.dataset.productId !== this.dataset.productId) { + return; + } + + const newPrice = event.detail.data.html.querySelector('product-price [ref="priceContainer"]'); + const currentPrice = this.querySelector('[ref="priceContainer"]'); + + if (!newPrice || !currentPrice) return; + + if (currentPrice.innerHTML !== newPrice.innerHTML) { + currentPrice.replaceWith(newPrice); + } + }; +} + +if (!customElements.get('product-price')) { + customElements.define('product-price', ProductPrice); +} diff --git a/assets/product-recommendations.js b/assets/product-recommendations.js new file mode 100644 index 000000000..0f07fdbc5 --- /dev/null +++ b/assets/product-recommendations.js @@ -0,0 +1,144 @@ +class ProductRecommendations extends HTMLElement { + /** + * The observer for the product recommendations + * @type {IntersectionObserver} + */ + #intersectionObserver = new IntersectionObserver( + (entries, observer) => { + if (!entries[0]?.isIntersecting) return; + + observer.disconnect(); + this.#loadRecommendations(); + }, + { rootMargin: '0px 0px 400px 0px' } + ); + + /** + * Observing changes to the elements attributes + * @type {MutationObserver} + */ + #mutationObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + // Only attribute changes are interesting + if (mutation.target !== this || mutation.type !== 'attributes') continue; + + // Ignore when the data-recommendations-performed attribute has been set to 'true' + if ( + mutation.attributeName === 'data-recommendations-performed' && + this.dataset.recommendationsPerformed === 'true' + ) + continue; + + // All other attribute changes trigger a reload + this.#loadRecommendations(); + break; + } + }); + + /** + * The cached recommendations + * @type {Record} + */ + #cachedRecommendations = {}; + + /** + * An abort controller for the active fetch (if there is one) + * @type {AbortController | null} + */ + #activeFetch = null; + + connectedCallback() { + this.#intersectionObserver.observe(this); + this.#mutationObserver.observe(this, { attributes: true }); + } + + /** + * Load the product recommendations + */ + #loadRecommendations() { + const { productId, recommendationsPerformed, sectionId, intent } = this.dataset; + const id = this.id; + + if (!productId || !id) { + throw new Error('Product ID and an ID attribute are required'); + } + + // If the recommendations have already been loaded, accounts for the case where the Theme Editor + // is loaded the section from the editor's visual preview context. + if (recommendationsPerformed === 'true') { + return; + } + + this.#fetchCachedRecommendations(productId, sectionId, intent) + .then((result) => { + if (!result.success) { + // The Theme Editor will place a section element element in the DOM whose section_id is not available + // to the Section Renderer API. In this case, we can safely ignore the error. + if (!Shopify.designMode) { + this.#handleError(new Error(`Server returned ${result.status}`)); + } + return; + } + + const html = document.createElement('div'); + html.innerHTML = result.data || ''; + const recommendations = html.querySelector(`product-recommendations[id="${id}"]`); + + if (recommendations?.innerHTML && recommendations.innerHTML.trim().length) { + this.dataset.recommendationsPerformed = 'true'; + this.innerHTML = recommendations.innerHTML; + } else { + this.#handleError(new Error('No recommendations available')); + } + }) + .catch((e) => { + this.#handleError(e); + }); + } + + /** + * Fetches the recommendations and cached the result for future use + * @param {string} productId + * @param {string | undefined} sectionId + * @param {string | undefined} intent + * @returns {Promise<{ success: true, data: string } | { success: false, status: number }>} + */ + async #fetchCachedRecommendations(productId, sectionId, intent) { + const url = `${this.dataset.url}&product_id=${productId}§ion_id=${sectionId}&intent=${intent}`; + + const cachedResponse = this.#cachedRecommendations[url]; + if (cachedResponse) { + return { success: true, data: cachedResponse }; + } + + this.#activeFetch?.abort(); + this.#activeFetch = new AbortController(); + + try { + const response = await fetch(url, { signal: this.#activeFetch.signal }); + if (!response.ok) { + return { success: false, status: response.status }; + } + + const text = await response.text(); + this.#cachedRecommendations[url] = text; + return { success: true, data: text }; + } finally { + this.#activeFetch = null; + } + } + + /** + * Handle errors in a consistent way + * @param {Error} error + */ + #handleError(error) { + console.error('Product recommendations error:', error); + this.classList.add('hidden'); + this.dataset.error = 'Error loading product recommendations'; + } +} + +if (!customElements.get('product-recommendations')) { + customElements.define('product-recommendations', ProductRecommendations); +} diff --git a/assets/product-title-truncation.js b/assets/product-title-truncation.js new file mode 100644 index 000000000..70d43b5dc --- /dev/null +++ b/assets/product-title-truncation.js @@ -0,0 +1,86 @@ +import { Component } from '@theme/component'; + +/** @typedef {typeof globalThis} Window */ + +/** + * A component that handles title truncation with responsive behavior + * + * @typedef {Object} Refs + * @property {HTMLElement} [text] - The text element to truncate (optional) + * + * @extends {Component} + */ +class ProductTitle extends Component { + constructor() { + super(); + } + + connectedCallback() { + super.connectedCallback(); + this.#initializeTruncation(); + } + + /** + * Initialize the title truncation + */ + #initializeTruncation() { + if ('ResizeObserver' in window) { + this.resizeObserver = new ResizeObserver(() => { + this.#calculateTruncation(); + }); + + this.resizeObserver.observe(this); + this.#calculateTruncation(); + } else { + /** @type {Window} */ + (window).addEventListener('resize', this.#handleResize.bind(this)); + this.#calculateTruncation(); + } + } + + /** + * Calculate truncation for the title + */ + #calculateTruncation() { + /** @type {HTMLElement} */ + const textElement = this.refs.text || this.querySelector('.title-text') || this; + if (!textElement.textContent) return; + + const containerHeight = this.clientHeight; + + const computedStyle = window.getComputedStyle(this); + const lineHeight = parseFloat(computedStyle.lineHeight); + const paddingTop = parseFloat(computedStyle.paddingTop); + const paddingBottom = parseFloat(computedStyle.paddingBottom); + + const availableHeight = containerHeight - paddingTop - paddingBottom; + const maxLines = Math.max(1, Math.floor(availableHeight / lineHeight)); + + textElement.style.display = '-webkit-box'; + textElement.style.webkitBoxOrient = 'vertical'; + textElement.style.overflow = 'hidden'; + textElement.style.textOverflow = 'ellipsis'; + textElement.style.webkitLineClamp = String(maxLines); + } + + /** + * Handle window resize events + */ + #handleResize() { + this.#calculateTruncation(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + } + window.removeEventListener('resize', this.#handleResize); + } +} + +if (!customElements.get('product-title')) { + customElements.define('product-title', ProductTitle); +} + +export default ProductTitle; diff --git a/assets/qr-code-generator.js b/assets/qr-code-generator.js new file mode 100644 index 000000000..1fc1ff896 --- /dev/null +++ b/assets/qr-code-generator.js @@ -0,0 +1,1665 @@ +/* eslint-disable no-redeclare */ + +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ + +const QRMode = { MODE_NUMBER: 1 << 0, MODE_ALPHA_NUM: 1 << 1, MODE_8BIT_BYTE: 1 << 2, MODE_KANJI: 1 << 3 }; +const QRErrorCorrectLevel = { + L: 1, + M: 0, + Q: 3, + H: 2, +}; + +const QRMaskPattern = { + PATTERN000: 0, + PATTERN001: 1, + PATTERN010: 2, + PATTERN011: 3, + PATTERN100: 4, + PATTERN101: 5, + PATTERN110: 6, + PATTERN111: 7, +}; + +//--------------------------------------------------------------------- +// QRCode for JavaScript +// +// Copyright (c) 2009 Kazuhiko Arase +// +// URL: http://www.d-project.com/ +// +// Licensed under the MIT license: +// http://www.opensource.org/licenses/mit-license.php +// +// The word "QR Code" is registered trademark of +// DENSO WAVE INCORPORATED +// http://www.denso-wave.com/qrcode/faqpatent-e.html +// +//--------------------------------------------------------------------- + +/** + * QR8bitByte constructor + * + * @param {string} data + */ +function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE; + this.data = data; + this.parsedData = []; + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = []; + var code = this.data.charCodeAt(i); + + if (code > 0x10000) { + byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18); + byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12); + byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6); + byteArray[3] = 0x80 | (code & 0x3f); + } else if (code > 0x800) { + byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12); + byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6); + byteArray[2] = 0x80 | (code & 0x3f); + } else if (code > 0x80) { + byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6); + byteArray[1] = 0x80 | (code & 0x3f); + } else { + byteArray[0] = code; + } + + this.parsedData.push(byteArray); + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData); + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191); + this.parsedData.unshift(187); + this.parsedData.unshift(239); + } +} + +QR8bitByte.prototype = { + /** + * @returns {number} + */ + getLength: function () { + return this.parsedData.length; + }, + + /** + * @param {QRBitBuffer} buffer + */ + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8); + } + }, +}; + +/** + * @param {number} typeNumber + * @param {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} errorCorrectLevel + */ +function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + /** @type {(boolean|null)[][]|null} */ + this.modules = null; + this.moduleCount = 0; + /** @type {number[]|null} */ + this.dataCache = null; + /** @type {QR8bitByte[]} */ + this.dataList = []; +} + +QRCodeModel.prototype = { + /** + * Add data + * + * @param {string} data + */ + addData: function (data) { + var newData = new QR8bitByte(data); + this.dataList.push(newData); + this.dataCache = null; + }, + + /** + * Check if a module is dark + * + * @param {number} row + * @param {number} col + * @returns {boolean} + */ + isDark: function (row, col) { + if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) { + throw new Error(row + ',' + col); + } + if (this.modules == null) { + return false; + } + return this.modules[row]?.[col] ?? false; + }, + getModuleCount: function () { + return this.moduleCount; + }, + make: function () { + this.makeImpl(false, this.getBestMaskPattern()); + }, + + /** + * @param {boolean} test + * @param {number} maskPattern + */ + makeImpl: function (test, maskPattern) { + this.moduleCount = this.typeNumber * 4 + 17; + this.modules = Array.from({ length: this.moduleCount }, () => Array.from({ length: this.moduleCount }, () => null)); + + this.setupPositionProbePattern(0, 0); + this.setupPositionProbePattern(this.moduleCount - 7, 0); + this.setupPositionProbePattern(0, this.moduleCount - 7); + this.setupPositionAdjustPattern(); + this.setupTimingPattern(); + this.setupTypeInfo(test, maskPattern); + if (this.typeNumber >= 7) { + this.setupTypeNumber(test); + } + if (this.dataCache == null) { + this.dataCache = QRCodeModel.createData(this.typeNumber, this.errorCorrectLevel, this.dataList); + } + this.mapData(this.dataCache, maskPattern); + }, + + /** + * @param {number} row + * @param {number} col + */ + setupPositionProbePattern: function (row, col) { + if (this.modules == null) { + return; + } + for (var r = -1; r <= 7; r++) { + if (row + r <= -1 || this.moduleCount <= row + r) continue; + const rowR = this.modules[row + r]; + if (rowR === undefined) continue; + for (var c = -1; c <= 7; c++) { + if (col + c <= -1 || this.moduleCount <= col + c) continue; + if ( + (0 <= r && r <= 6 && (c == 0 || c == 6)) || + (0 <= c && c <= 6 && (r == 0 || r == 6)) || + (2 <= r && r <= 4 && 2 <= c && c <= 4) + ) { + rowR[col + c] = true; + } else { + rowR[col + c] = false; + } + } + } + }, + getBestMaskPattern: function () { + var minLostPoint = 0; + var pattern = 0; + for (var i = 0; i < 8; i++) { + this.makeImpl(true, i); + var lostPoint = QRUtil.getLostPoint(this); + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint; + pattern = i; + } + } + return pattern; + }, + setupTimingPattern: function () { + if (this.modules == null) { + return; + } + for (var r = 8; r < this.moduleCount - 8; r++) { + const rowR = this.modules[r]; + if (rowR === undefined) continue; + if (rowR[6] != null) { + continue; + } + rowR[6] = r % 2 == 0; + } + for (var c = 8; c < this.moduleCount - 8; c++) { + const rowN = this.modules[6]; + if (rowN === undefined) continue; + if (rowN[c] != null) { + continue; + } + rowN[c] = c % 2 == 0; + } + }, + setupPositionAdjustPattern: function () { + if (this.modules == null) { + return; + } + var pos = QRUtil.getPatternPosition(this.typeNumber); + for (var i = 0; i < pos.length; i++) { + for (var j = 0; j < pos.length; j++) { + var row = pos[i]; + var col = pos[j]; + if (row === undefined || col === undefined) continue; + if (this.modules[row]?.[col] != null) { + continue; + } + for (var r = -2; r <= 2; r++) { + const rowR = this.modules[row + r]; + if (rowR === undefined) continue; + for (var c = -2; c <= 2; c++) { + if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) { + rowR[col + c] = true; + } else { + rowR[col + c] = false; + } + } + } + } + } + }, + + /** + * @param {boolean} test + */ + setupTypeNumber: function (test) { + if (this.modules == null) { + return; + } + var bits = QRUtil.getBCHTypeNumber(this.typeNumber); + for (var i = 0; i < 18; i++) { + var mod = !test && ((bits >> i) & 1) == 1; + var row = this.modules[Math.floor(i / 3)]; + if (row === undefined) continue; + row[(i % 3) + this.moduleCount - 8 - 3] = mod; + } + for (var i = 0; i < 18; i++) { + var mod = !test && ((bits >> i) & 1) == 1; + var row = this.modules[(i % 3) + this.moduleCount - 8 - 3]; + if (row === undefined) continue; + row[Math.floor(i / 3)] = mod; + } + }, + + /** + * @param {boolean} test + * @param {number} maskPattern + */ + setupTypeInfo: function (test, maskPattern) { + if (this.modules == null) { + return; + } + var data = (this.errorCorrectLevel << 3) | maskPattern; + var bits = QRUtil.getBCHTypeInfo(data); + for (var i = 0; i < 15; i++) { + var mod = !test && ((bits >> i) & 1) == 1; + if (i < 6) { + var row = this.modules[i]; + if (row === undefined) continue; + row[8] = mod; + } else if (i < 8) { + var row = this.modules[i + 1]; + if (row === undefined) continue; + row[8] = mod; + } else { + var row = this.modules[this.moduleCount - 15 + i]; + if (row === undefined) continue; + row[8] = mod; + } + } + for (var i = 0; i < 15; i++) { + var mod = !test && ((bits >> i) & 1) == 1; + var row = this.modules[8]; + if (row === undefined) continue; + if (i < 8) { + row[this.moduleCount - i - 1] = mod; + } else if (i < 9) { + row[15 - i - 1 + 1] = mod; + } else { + row[15 - i - 1] = mod; + } + } + var row = this.modules[this.moduleCount - 8]; + if (row === undefined) return; + row[8] = !test; + }, + + /** + * @param {number[]} data + * @param {number} maskPattern + */ + mapData: function (data, maskPattern) { + if (this.modules == null) { + return; + } + var inc = -1; + var row = this.moduleCount - 1; + var bitIndex = 7; + var byteIndex = 0; + for (var col = this.moduleCount - 1; col > 0; col -= 2) { + if (col == 6) col--; + while (true) { + for (var c = 0; c < 2; c++) { + if (this.modules[row]?.[col - c] == null) { + var dark = false; + if (byteIndex < data.length) { + var dataR = data[byteIndex]; + if (dataR !== undefined) { + dark = ((dataR >>> bitIndex) & 1) == 1; + } + } + var mask = QRUtil.getMask(maskPattern, row, col - c); + if (mask) { + dark = !dark; + } + var rowR = this.modules[row]; + if (rowR !== undefined) { + rowR[col - c] = dark; + } + bitIndex--; + if (bitIndex == -1) { + byteIndex++; + bitIndex = 7; + } + } + } + row += inc; + if (row < 0 || this.moduleCount <= row) { + row -= inc; + inc = -inc; + break; + } + } + } + }, +}; +QRCodeModel.PAD0 = 0xec; +QRCodeModel.PAD1 = 0x11; + +/** + * @param {number} typeNumber + * @param {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} errorCorrectLevel + * @param {QR8bitByte[]} dataList + */ +QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) { + var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); + var buffer = new QRBitBuffer(); + for (var i = 0; i < dataList.length; i++) { + var data = dataList[i]; + if (data === undefined) continue; + buffer.put(data.mode, 4); + buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber)); + data.write(buffer); + } + var totalDataCount = 0; + for (var i = 0; i < rsBlocks.length; i++) { + var rsBlock = rsBlocks[i]; + if (rsBlock === undefined) continue; + totalDataCount += rsBlock.dataCount; + } + if (buffer.getLengthInBits() > totalDataCount * 8) { + throw new Error('code length overflow. (' + buffer.getLengthInBits() + '>' + totalDataCount * 8 + ')'); + } + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { + buffer.put(0, 4); + } + while (buffer.getLengthInBits() % 8 != 0) { + buffer.putBit(false); + } + while (true) { + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(QRCodeModel.PAD0, 8); + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(QRCodeModel.PAD1, 8); + } + return QRCodeModel.createBytes(buffer, rsBlocks); +}; + +/** + * @param {QRBitBuffer} buffer + * @param {QRRSBlock[]} rsBlocks + */ +QRCodeModel.createBytes = function (buffer, rsBlocks) { + var offset = 0; + var maxDcCount = 0; + var maxEcCount = 0; + var dcdata = new Array(rsBlocks.length); + var ecdata = new Array(rsBlocks.length); + for (var r = 0; r < rsBlocks.length; r++) { + var rsBlock = rsBlocks[r]; + if (rsBlock === undefined) continue; + var dcCount = rsBlock.dataCount; + var ecCount = rsBlock.totalCount - dcCount; + maxDcCount = Math.max(maxDcCount, dcCount); + maxEcCount = Math.max(maxEcCount, ecCount); + dcdata[r] = new Array(dcCount); + for (var i = 0; i < dcdata[r].length; i++) { + var dataR = buffer.buffer[i + offset]; + if (dataR !== undefined) { + dcdata[r][i] = 0xff & dataR; + } + } + offset += dcCount; + var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); + var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1); + var modPoly = rawPoly.mod(rsPoly); + ecdata[r] = new Array(rsPoly.getLength() - 1); + for (var i = 0; i < ecdata[r].length; i++) { + var modIndex = i + modPoly.getLength() - ecdata[r].length; + ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0; + } + } + var totalCodeCount = 0; + for (var i = 0; i < rsBlocks.length; i++) { + var rsBlock = rsBlocks[i]; + if (rsBlock === undefined) continue; + totalCodeCount += rsBlock.totalCount; + } + var data = new Array(totalCodeCount); + var index = 0; + for (var i = 0; i < maxDcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < dcdata[r].length) { + data[index++] = dcdata[r][i]; + } + } + } + for (var i = 0; i < maxEcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < ecdata[r].length) { + data[index++] = ecdata[r][i]; + } + } + } + return data; +}; + +var QRUtil = { + PATTERN_POSITION_TABLE: [ + [], + [6, 18], + [6, 22], + [6, 26], + [6, 30], + [6, 34], + [6, 22, 38], + [6, 24, 42], + [6, 26, 46], + [6, 28, 50], + [6, 30, 54], + [6, 32, 58], + [6, 34, 62], + [6, 26, 46, 66], + [6, 26, 48, 70], + [6, 26, 50, 74], + [6, 30, 54, 78], + [6, 30, 56, 82], + [6, 30, 58, 86], + [6, 34, 62, 90], + [6, 28, 50, 72, 94], + [6, 26, 50, 74, 98], + [6, 30, 54, 78, 102], + [6, 28, 54, 80, 106], + [6, 32, 58, 84, 110], + [6, 30, 58, 86, 114], + [6, 34, 62, 90, 118], + [6, 26, 50, 74, 98, 122], + [6, 30, 54, 78, 102, 126], + [6, 26, 52, 78, 104, 130], + [6, 30, 56, 82, 108, 134], + [6, 34, 60, 86, 112, 138], + [6, 30, 58, 86, 114, 142], + [6, 34, 62, 90, 118, 146], + [6, 30, 54, 78, 102, 126, 150], + [6, 24, 50, 76, 102, 128, 154], + [6, 28, 54, 80, 106, 132, 158], + [6, 32, 58, 84, 110, 136, 162], + [6, 26, 54, 82, 110, 138, 166], + [6, 30, 58, 86, 114, 142, 170], + ], + G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0), + G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0), + G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), + + /** + * @param {number} data + * @returns {number} + */ + getBCHTypeInfo: function (data) { + var d = data << 10; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { + d ^= QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)); + } + return ((data << 10) | d) ^ QRUtil.G15_MASK; + }, + + /** + * @param {number} data + * @returns {number} + */ + getBCHTypeNumber: function (data) { + var d = data << 12; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { + d ^= QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)); + } + return (data << 12) | d; + }, + + /** + * @param {number} data + * @returns {number} + */ + getBCHDigit: function (data) { + var digit = 0; + while (data != 0) { + digit++; + data >>>= 1; + } + return digit; + }, + + /** + * @param {number} typeNumber + * @returns {number[]} + */ + getPatternPosition: function (typeNumber) { + return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1] ?? []; + }, + + /** + * @param {number} maskPattern + * @param {number} i + * @param {number} j + * @returns {boolean} + */ + getMask: function (maskPattern, i, j) { + switch (maskPattern) { + case QRMaskPattern.PATTERN000: + return (i + j) % 2 == 0; + case QRMaskPattern.PATTERN001: + return i % 2 == 0; + case QRMaskPattern.PATTERN010: + return j % 3 == 0; + case QRMaskPattern.PATTERN011: + return (i + j) % 3 == 0; + case QRMaskPattern.PATTERN100: + return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0; + case QRMaskPattern.PATTERN101: + return ((i * j) % 2) + ((i * j) % 3) == 0; + case QRMaskPattern.PATTERN110: + return (((i * j) % 2) + ((i * j) % 3)) % 2 == 0; + case QRMaskPattern.PATTERN111: + return (((i * j) % 3) + ((i + j) % 2)) % 2 == 0; + default: + throw new Error('bad maskPattern:' + maskPattern); + } + }, + + /** + * @param {number} errorCorrectLength + * @returns {QRPolynomial} + */ + getErrorCorrectPolynomial: function (errorCorrectLength) { + var a = new QRPolynomial([1], 0); + for (var i = 0; i < errorCorrectLength; i++) { + a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)); + } + return a; + }, + + /** + * @param {typeof QRMode[keyof typeof QRMode]} mode + * @param {number} type + * @returns {number} + */ + getLengthInBits: function (mode, type) { + if (1 <= type && type < 10) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 10; + case QRMode.MODE_ALPHA_NUM: + return 9; + case QRMode.MODE_8BIT_BYTE: + return 8; + case QRMode.MODE_KANJI: + return 8; + default: + throw new Error('mode:' + mode); + } + } else if (type < 27) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 12; + case QRMode.MODE_ALPHA_NUM: + return 11; + case QRMode.MODE_8BIT_BYTE: + return 16; + case QRMode.MODE_KANJI: + return 10; + default: + throw new Error('mode:' + mode); + } + } else if (type < 41) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 14; + case QRMode.MODE_ALPHA_NUM: + return 13; + case QRMode.MODE_8BIT_BYTE: + return 16; + case QRMode.MODE_KANJI: + return 12; + default: + throw new Error('mode:' + mode); + } + } else { + throw new Error('type:' + type); + } + }, + + /** + * @param {QRCodeModel} qrCode + * @returns {number} + */ + getLostPoint: function (qrCode) { + var moduleCount = qrCode.getModuleCount(); + var lostPoint = 0; + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount; col++) { + var sameCount = 0; + var dark = qrCode.isDark(row, col); + for (var r = -1; r <= 1; r++) { + if (row + r < 0 || moduleCount <= row + r) { + continue; + } + for (var c = -1; c <= 1; c++) { + if (col + c < 0 || moduleCount <= col + c) { + continue; + } + if (r == 0 && c == 0) { + continue; + } + if (dark == qrCode.isDark(row + r, col + c)) { + sameCount++; + } + } + } + if (sameCount > 5) { + lostPoint += 3 + sameCount - 5; + } + } + } + for (var row = 0; row < moduleCount - 1; row++) { + for (var col = 0; col < moduleCount - 1; col++) { + var count = 0; + if (qrCode.isDark(row, col)) count++; + if (qrCode.isDark(row + 1, col)) count++; + if (qrCode.isDark(row, col + 1)) count++; + if (qrCode.isDark(row + 1, col + 1)) count++; + if (count == 0 || count == 4) { + lostPoint += 3; + } + } + } + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount - 6; col++) { + if ( + qrCode.isDark(row, col) && + !qrCode.isDark(row, col + 1) && + qrCode.isDark(row, col + 2) && + qrCode.isDark(row, col + 3) && + qrCode.isDark(row, col + 4) && + !qrCode.isDark(row, col + 5) && + qrCode.isDark(row, col + 6) + ) { + lostPoint += 40; + } + } + } + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount - 6; row++) { + if ( + qrCode.isDark(row, col) && + !qrCode.isDark(row + 1, col) && + qrCode.isDark(row + 2, col) && + qrCode.isDark(row + 3, col) && + qrCode.isDark(row + 4, col) && + !qrCode.isDark(row + 5, col) && + qrCode.isDark(row + 6, col) + ) { + lostPoint += 40; + } + } + } + var darkCount = 0; + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount; row++) { + if (qrCode.isDark(row, col)) { + darkCount++; + } + } + } + var ratio = Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5; + lostPoint += ratio * 10; + return lostPoint; + }, +}; +var QRMath = { + /** + * Get the log + * + * @param {number} n + * @returns {number} + */ + glog: function (n) { + if (n < 1) { + throw new Error('glog(' + n + ')'); + } + return QRMath.LOG_TABLE[n]; + }, + + /** + * Get the exp + * + * @param {number} n + * @returns {number} + */ + gexp: function (n) { + while (n < 0) { + n += 255; + } + while (n >= 256) { + n -= 255; + } + return QRMath.EXP_TABLE[n]; + }, + EXP_TABLE: new Array(256), + LOG_TABLE: new Array(256), +}; +for (var i = 0; i < 8; i++) { + QRMath.EXP_TABLE[i] = 1 << i; +} +for (var i = 8; i < 256; i++) { + QRMath.EXP_TABLE[i] = + QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8]; +} +for (var i = 0; i < 255; i++) { + QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i; +} + +/** + * @param {number[]} num + * @param {number} shift + */ +function QRPolynomial(num, shift) { + if (num.length == undefined) { + throw new Error(num.length + '/' + shift); + } + var offset = 0; + while (offset < num.length && num[offset] == 0) { + offset++; + } + this.num = new Array(num.length - offset + shift); + for (var i = 0; i < num.length - offset; i++) { + this.num[i] = num[i + offset]; + } +} +QRPolynomial.prototype = { + /** + * @param {number} index + * @returns {number} + */ + get: function (index) { + return this.num[index]; + }, + + getLength: function () { + return this.num.length; + }, + + /** + * @param {QRPolynomial} e + * @returns {QRPolynomial} + */ + multiply: function (e) { + var num = new Array(this.getLength() + e.getLength() - 1); + for (var i = 0; i < this.getLength(); i++) { + for (var j = 0; j < e.getLength(); j++) { + num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))); + } + } + return new QRPolynomial(num, 0); + }, + + /** + * @param {QRPolynomial} e + * @returns {QRPolynomial} + */ + mod: function (e) { + if (this.getLength() - e.getLength() < 0) { + return this; + } + var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0)); + var num = new Array(this.getLength()); + for (var i = 0; i < this.getLength(); i++) { + num[i] = this.get(i); + } + for (var i = 0; i < e.getLength(); i++) { + num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio); + } + return new QRPolynomial(num, 0).mod(e); + }, +}; + +/** + * @param {number} totalCount + * @param {number} dataCount + */ +function QRRSBlock(totalCount, dataCount) { + this.totalCount = totalCount; + this.dataCount = dataCount; +} +QRRSBlock.RS_BLOCK_TABLE = [ + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + [4, 101, 81], + [1, 80, 50, 4, 81, 51], + [4, 50, 22, 4, 51, 23], + [3, 36, 12, 8, 37, 13], + [2, 116, 92, 2, 117, 93], + [6, 58, 36, 2, 59, 37], + [4, 46, 20, 6, 47, 21], + [7, 42, 14, 4, 43, 15], + [4, 133, 107], + [8, 59, 37, 1, 60, 38], + [8, 44, 20, 4, 45, 21], + [12, 33, 11, 4, 34, 12], + [3, 145, 115, 1, 146, 116], + [4, 64, 40, 5, 65, 41], + [11, 36, 16, 5, 37, 17], + [11, 36, 12, 5, 37, 13], + [5, 109, 87, 1, 110, 88], + [5, 65, 41, 5, 66, 42], + [5, 54, 24, 7, 55, 25], + [11, 36, 12], + [5, 122, 98, 1, 123, 99], + [7, 73, 45, 3, 74, 46], + [15, 43, 19, 2, 44, 20], + [3, 45, 15, 13, 46, 16], + [1, 135, 107, 5, 136, 108], + [10, 74, 46, 1, 75, 47], + [1, 50, 22, 15, 51, 23], + [2, 42, 14, 17, 43, 15], + [5, 150, 120, 1, 151, 121], + [9, 69, 43, 4, 70, 44], + [17, 50, 22, 1, 51, 23], + [2, 42, 14, 19, 43, 15], + [3, 141, 113, 4, 142, 114], + [3, 70, 44, 11, 71, 45], + [17, 47, 21, 4, 48, 22], + [9, 39, 13, 16, 40, 14], + [3, 135, 107, 5, 136, 108], + [3, 67, 41, 13, 68, 42], + [15, 54, 24, 5, 55, 25], + [15, 43, 15, 10, 44, 16], + [4, 144, 116, 4, 145, 117], + [17, 68, 42], + [17, 50, 22, 6, 51, 23], + [19, 46, 16, 6, 47, 17], + [2, 139, 111, 7, 140, 112], + [17, 74, 46], + [7, 54, 24, 16, 55, 25], + [34, 37, 13], + [4, 151, 121, 5, 152, 122], + [4, 75, 47, 14, 76, 48], + [11, 54, 24, 14, 55, 25], + [16, 45, 15, 14, 46, 16], + [6, 147, 117, 4, 148, 118], + [6, 73, 45, 14, 74, 46], + [11, 54, 24, 16, 55, 25], + [30, 46, 16, 2, 47, 17], + [8, 132, 106, 4, 133, 107], + [8, 75, 47, 13, 76, 48], + [7, 54, 24, 22, 55, 25], + [22, 45, 15, 13, 46, 16], + [10, 142, 114, 2, 143, 115], + [19, 74, 46, 4, 75, 47], + [28, 50, 22, 6, 51, 23], + [33, 46, 16, 4, 47, 17], + [8, 152, 122, 4, 153, 123], + [22, 73, 45, 3, 74, 46], + [8, 53, 23, 26, 54, 24], + [12, 45, 15, 28, 46, 16], + [3, 147, 117, 10, 148, 118], + [3, 73, 45, 23, 74, 46], + [4, 54, 24, 31, 55, 25], + [11, 45, 15, 31, 46, 16], + [7, 146, 116, 7, 147, 117], + [21, 73, 45, 7, 74, 46], + [1, 53, 23, 37, 54, 24], + [19, 45, 15, 26, 46, 16], + [5, 145, 115, 10, 146, 116], + [19, 75, 47, 10, 76, 48], + [15, 54, 24, 25, 55, 25], + [23, 45, 15, 25, 46, 16], + [13, 145, 115, 3, 146, 116], + [2, 74, 46, 29, 75, 47], + [42, 54, 24, 1, 55, 25], + [23, 45, 15, 28, 46, 16], + [17, 145, 115], + [10, 74, 46, 23, 75, 47], + [10, 54, 24, 35, 55, 25], + [19, 45, 15, 35, 46, 16], + [17, 145, 115, 1, 146, 116], + [14, 74, 46, 21, 75, 47], + [29, 54, 24, 19, 55, 25], + [11, 45, 15, 46, 46, 16], + [13, 145, 115, 6, 146, 116], + [14, 74, 46, 23, 75, 47], + [44, 54, 24, 7, 55, 25], + [59, 46, 16, 1, 47, 17], + [12, 151, 121, 7, 152, 122], + [12, 75, 47, 26, 76, 48], + [39, 54, 24, 14, 55, 25], + [22, 45, 15, 41, 46, 16], + [6, 151, 121, 14, 152, 122], + [6, 75, 47, 34, 76, 48], + [46, 54, 24, 10, 55, 25], + [2, 45, 15, 64, 46, 16], + [17, 152, 122, 4, 153, 123], + [29, 74, 46, 14, 75, 47], + [49, 54, 24, 10, 55, 25], + [24, 45, 15, 46, 46, 16], + [4, 152, 122, 18, 153, 123], + [13, 74, 46, 32, 75, 47], + [48, 54, 24, 14, 55, 25], + [42, 45, 15, 32, 46, 16], + [20, 147, 117, 4, 148, 118], + [40, 75, 47, 7, 76, 48], + [43, 54, 24, 22, 55, 25], + [10, 45, 15, 67, 46, 16], + [19, 148, 118, 6, 149, 119], + [18, 75, 47, 31, 76, 48], + [34, 54, 24, 34, 55, 25], + [20, 45, 15, 61, 46, 16], +]; + +/** + * @param {number} typeNumber + * @param {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} errorCorrectLevel + * @returns {QRRSBlock[]} + */ +QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) { + var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); + if (rsBlock == undefined) { + throw new Error('bad rs block @ typeNumber:' + typeNumber + '/errorCorrectLevel:' + errorCorrectLevel); + } + var length = rsBlock.length / 3; + var list = []; + for (var i = 0; i < length; i++) { + var count = rsBlock[i * 3 + 0]; + var totalCount = rsBlock[i * 3 + 1]; + var dataCount = rsBlock[i * 3 + 2]; + if (count === undefined || totalCount === undefined || dataCount === undefined) { + throw new Error('bad rs block @ typeNumber:' + typeNumber + '/errorCorrectLevel:' + errorCorrectLevel); + } + for (var j = 0; j < count; j++) { + list.push(new QRRSBlock(totalCount, dataCount)); + } + } + return list; +}; + +/** + * @param {number} typeNumber + * @param {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} errorCorrectLevel + */ +QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) { + switch (errorCorrectLevel) { + case QRErrorCorrectLevel.L: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; + case QRErrorCorrectLevel.M: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; + case QRErrorCorrectLevel.Q: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; + case QRErrorCorrectLevel.H: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; + default: + return undefined; + } +}; +function QRBitBuffer() { + /** @type {number[]} */ + this.buffer = []; + /** @type {number} */ + this.length = 0; +} +QRBitBuffer.prototype = { + /** + * @param {number} index + * @returns {boolean} + */ + get: function (index) { + var bufIndex = Math.floor(index / 8); + const bufferAtIndex = this.buffer[bufIndex]; + if (bufferAtIndex === undefined) { + throw new Error('buffer index out of bounds'); + } + return ((bufferAtIndex >>> (7 - (index % 8))) & 1) == 1; + }, + /** + * @param {number} num + * @param {number} length + */ + put: function (num, length) { + for (var i = 0; i < length; i++) { + this.putBit(((num >>> (length - i - 1)) & 1) == 1); + } + }, + getLengthInBits: function () { + return this.length; + }, + /** + * @param {boolean} bit + */ + putBit: function (bit) { + var bufIndex = Math.floor(this.length / 8); + if (this.buffer.length <= bufIndex) { + this.buffer.push(0); + } + if (bit) { + const bufferAtIndex = this.buffer[bufIndex]; + if (bufferAtIndex === undefined) { + throw new Error('buffer index out of bounds'); + } + this.buffer[bufIndex] = bufferAtIndex | (0x80 >>> this.length % 8); + } + this.length++; + }, +}; +var QRCodeLimitLength = [ + [17, 14, 11, 7], + [32, 26, 20, 14], + [53, 42, 32, 24], + [78, 62, 46, 34], + [106, 84, 60, 44], + [134, 106, 74, 58], + [154, 122, 86, 64], + [192, 152, 108, 84], + [230, 180, 130, 98], + [271, 213, 151, 119], + [321, 251, 177, 137], + [367, 287, 203, 155], + [425, 331, 241, 177], + [458, 362, 258, 194], + [520, 412, 292, 220], + [586, 450, 322, 250], + [644, 504, 364, 280], + [718, 560, 394, 310], + [792, 624, 442, 338], + [858, 666, 482, 382], + [929, 711, 509, 403], + [1003, 779, 565, 439], + [1091, 857, 611, 461], + [1171, 911, 661, 511], + [1273, 997, 715, 535], + [1367, 1059, 751, 593], + [1465, 1125, 805, 625], + [1528, 1190, 868, 658], + [1628, 1264, 908, 698], + [1732, 1370, 982, 742], + [1840, 1452, 1030, 790], + [1952, 1538, 1112, 842], + [2068, 1628, 1168, 898], + [2188, 1722, 1228, 958], + [2303, 1809, 1283, 983], + [2431, 1911, 1351, 1051], + [2563, 1989, 1423, 1093], + [2699, 2099, 1499, 1139], + [2809, 2213, 1579, 1219], + [2953, 2331, 1663, 1273], +]; + +function isSupportCanvas() { + return typeof CanvasRenderingContext2D != 'undefined'; +} + +var svgDrawer = (function () { + /** + * @param {Element} el + * @param {QRCodeOptions} htOption + */ + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * @param {QRCodeModel} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + + this.clear(); + + /** + * @param {string} tag + * @param {Record} attrs + * @returns {SVGElement} + */ + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) { + if (attrs.hasOwnProperty(k)) { + const value = attrs[k]; + if (value !== undefined) { + el.setAttribute(k, value); + } + } + } + return el; + } + + var svg = makeSVG('svg', { + viewBox: '0 0 ' + String(nCount) + ' ' + String(nCount), + width: '100%', + height: '100%', + fill: _htOption.colorLight, + }); + svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'); + _el.appendChild(svg); + + svg.appendChild(makeSVG('rect', { fill: _htOption.colorLight, width: '100%', height: '100%' })); + svg.appendChild(makeSVG('rect', { fill: _htOption.colorDark, width: '1', height: '1', id: 'template' })); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG('use', { x: String(col), y: String(row) }); + child.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#template'); + svg.appendChild(child); + } + } + } + }; + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes() && this._el.lastChild) this._el.removeChild(this._el.lastChild); + }; + + /** + * @type {null|(() => void)} + */ + Drawing.prototype.makeImage = null; + return Drawing; +})(); + +var useSVG = document.documentElement.tagName.toLowerCase() === 'svg'; + +// Drawing in DOM by using Table tag +var Drawing = useSVG + ? svgDrawer + : !isSupportCanvas() + ? (function () { + /** + * @param {Element} el + * @param {QRCodeOptions} htOption + */ + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * @param {QRCodeModel} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + var aHTML = ['']; + + for (var row = 0; row < nCount; row++) { + aHTML.push(''); + + for (var col = 0; col < nCount; col++) { + aHTML.push( + '' + ); + } + + aHTML.push(''); + } + + aHTML.push('
'); + _el.innerHTML = aHTML.join(''); + + // Fix the margin values as real size. + var elTable = _el.childNodes[0]; + if (elTable instanceof HTMLElement) { + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + 'px ' + nLeftMarginTable + 'px'; + } + } + }; + + Drawing.prototype.clear = function () { + this._el.innerHTML = ''; + }; + + /** + * @type {null|(() => void)} + */ + Drawing.prototype.makeImage = null; + return Drawing; + })() + : (function () { + // Drawing in Canvas + function onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL('image/png'); + this._elImage.style.display = 'block'; + this._elCanvas.style.display = 'none'; + } + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {QRCodeOptions} htOption + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false; + + this._htOption = htOption; + this._elCanvas = document.createElement('canvas'); + this._elCanvas.width = htOption.width; + this._elCanvas.height = htOption.height; + el.appendChild(this._elCanvas); + this._el = el; + this._oContext = this._elCanvas.getContext('2d'); + if (!this._oContext) { + throw new Error('Canvas is not supported'); + } + this._bIsPainted = false; + this._elImage = document.createElement('img'); + this._elImage.alt = htOption.alt; + this._elImage.style.display = 'none'; + this._el.appendChild(this._elImage); + /** @type {boolean|null} */ + this._bSupportDataURI = null; + }; + + /** + * Draw the QRCode + * + * @param {QRCodeModel} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage; + var _oContext = this._oContext; + var _htOption = this._htOption; + + var nCount = oQRCode.getModuleCount(); + var nWidth = _htOption.width / nCount; + var nHeight = _htOption.height / nCount; + var nRoundedWidth = Math.round(nWidth); + var nRoundedHeight = Math.round(nHeight); + + _elImage.style.display = 'none'; + this.clear(); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col); + var nLeft = col * nWidth; + var nTop = row * nHeight; + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 1; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.fillRect(nLeft, nTop, nWidth, nHeight); + + // Anti-aliasing prevention processing + _oContext.strokeRect(Math.floor(nLeft) + 0.5, Math.floor(nTop) + 0.5, nRoundedWidth, nRoundedHeight); + + _oContext.strokeRect(Math.ceil(nLeft) - 0.5, Math.ceil(nTop) - 0.5, nRoundedWidth, nRoundedHeight); + } + } + + this._bIsPainted = true; + }; + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + this.safeSetDataURI.call(this, onMakeImage); + } + }; + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted; + }; + + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); + this._bIsPainted = false; + }; + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber; + } + + return Math.floor(nNumber * 1000) / 1000; + }; + + /** + * Check whether the user's browser supports Data URI or not + * + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + Drawing.prototype.safeSetDataURI = function (fSuccess, fFail) { + var self = this; + self._fFail = fFail; + self._fSuccess = fSuccess; + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement('img'); + var fOnError = function () { + self._bSupportDataURI = false; + + if (self._fFail) { + self._fFail.call(self); + } + }; + var fOnSuccess = function () { + self._bSupportDataURI = true; + + if (self._fSuccess) { + self._fSuccess.call(self); + } + }; + + el.onabort = fOnError; + el.onerror = fOnError; + el.onload = fOnSuccess; + el.src = + 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; // the Image contains 1px data. + return; + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self); + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self); + } + }; + + return Drawing; + })(); + +/** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} nCorrectLevel + * @return {Number} type + */ +function getTypeNumber(sText, nCorrectLevel) { + var nType = 1; + var length = getUTF8Length(sText); + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + const QRCodeLimitLengthAtIndex = QRCodeLimitLength[i]; + if (QRCodeLimitLengthAtIndex === undefined) { + throw new Error('QRCodeLimitLength index out of bounds'); + } + + /** @type {number|undefined} */ + var nLimit = 0; + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L: + nLimit = QRCodeLimitLengthAtIndex[0]; + break; + case QRErrorCorrectLevel.M: + nLimit = QRCodeLimitLengthAtIndex[1]; + break; + case QRErrorCorrectLevel.Q: + nLimit = QRCodeLimitLengthAtIndex[2]; + break; + case QRErrorCorrectLevel.H: + nLimit = QRCodeLimitLengthAtIndex[3]; + break; + } + + if (nLimit === undefined) { + throw new Error('QRCodeLimitLength index out of bounds'); + } + + if (length <= nLimit) { + break; + } else { + nType++; + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error('Too long data'); + } + + return nType; +} + +/** + * @param {string} sText + * @returns {number} + */ +function getUTF8Length(sText) { + const replacedText = encodeURI(sText) + .toString() + .replace(/\%[0-9a-fA-F]{2}/g, 'a'); + + // If the encoded and replaced text length differs from original, + // it means we have non-ASCII characters, so add 3 bytes for UTF-8 BOM + const bomLength = replacedText.length !== sText.length ? 3 : 0; + + return replacedText.length + bomLength; +} + +/** + * @param {String} sText link data + */ +QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel); + this._oQRCode.addData(sText); + this._oQRCode.make(); + this._el.title = sText; + this._oDrawing.draw(this._oQRCode); + this.makeImage(); +}; + +/** + * Make the Image from Canvas element + * - It occurs automatically + */ +QRCode.prototype.makeImage = function () { + // The makeImage method exists only in the canvas-based Drawing implementation but not in the SVG or table-based implementations + const drawing = this._oDrawing; + if (typeof drawing.makeImage == 'function') { + drawing.makeImage(); + } +}; + +QRCode.prototype.clear = function () { + this._oDrawing.clear(); +}; + +/** + * @name QRCode.CorrectLevel + */ +QRCode.CorrectLevel = QRErrorCorrectLevel; + +/** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @typedef {Object} QRCodeOptions + * @property {string} text QRCode link data + * @property {number} width + * @property {number} height + * @property {string} alt + * @property {number} typeNumber + * @property {string} colorDark + * @property {string} colorLight + * @property {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} correctLevel + * @property {boolean} useSVG + * + * QRCodeOptions, but with properties optional so its easier to pass in only the properties you want to change + * @typedef {Object} QRCodePartialOptions + * @property {string} [text] QRCode link data + * @property {number} [width] + * @property {number} [height] + * @property {string} [alt] + * @property {number} [typeNumber] + * @property {string} [colorDark] + * @property {string} [colorLight] + * @property {typeof QRErrorCorrectLevel[keyof typeof QRErrorCorrectLevel]} [correctLevel] + * @property {boolean} [useSVG] + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {QRCodePartialOptions|String} vOption + */ +export function QRCode(el, vOption) { + /** + * @type {QRCodeOptions} + */ + const defaultOptions = { + text: '', + alt: '', + width: 256, + height: 256, + typeNumber: 4, + colorDark: '#000000', + colorLight: '#ffffff', + correctLevel: QRErrorCorrectLevel.H, + useSVG: false, + }; + + /** + * @type {QRCodeOptions} + */ + this._htOption = { + ...defaultOptions, + ...(typeof vOption === 'string' ? { text: vOption } : vOption), + }; + + if (typeof el == 'string') { + const element = document.getElementById(el); + if (!element) { + throw new Error(`Element with id ${el} not found`); + } + el = element; + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer; + } + + this._el = el; + this._oQRCode = null; + this._oDrawing = new Drawing(this._el, this._htOption); + + if (this._htOption.text) { + this.makeCode(this._htOption.text); + } +} diff --git a/assets/qr-code-image.js b/assets/qr-code-image.js new file mode 100644 index 000000000..fe87065d9 --- /dev/null +++ b/assets/qr-code-image.js @@ -0,0 +1,33 @@ +import { QRCode } from '@theme/qr-code-generator'; +/** + * A custom element that displays a QR code image. + * + * @extends {HTMLElement} + */ +class QRCodeImage extends HTMLElement { + /** @type {number} */ + #width = 72; + /** @type {number} */ + #height = 72; + /** @type {string} */ + #alt = ''; + + connectedCallback() { + const widthAttribute = this.getAttribute('width') ?? ''; + this.#width = isNaN(parseInt(widthAttribute)) ? this.#width : parseInt(widthAttribute); + const heightAttribute = this.getAttribute('height') ?? ''; + this.#height = isNaN(parseInt(heightAttribute)) ? this.#height : parseInt(heightAttribute); + this.#alt = this.getAttribute('alt') ?? this.#alt; + + new QRCode(this, { + text: this.getAttribute('data-identifier') || '', + width: this.#width, + height: this.#height, + alt: this.#alt, + }); + } +} + +if (!customElements.get('qr-code-image')) { + customElements.define('qr-code-image', QRCodeImage); +} diff --git a/assets/quick-add.js b/assets/quick-add.js new file mode 100644 index 000000000..fb8b4d384 --- /dev/null +++ b/assets/quick-add.js @@ -0,0 +1,229 @@ +import { morph } from '@theme/morph'; +import { Component } from '@theme/component'; +import { CartUpdateEvent, ThemeEvents } from '@theme/events'; +import { DialogComponent, DialogCloseEvent } from '@theme/dialog'; +import { mediaQueryLarge, isMobileBreakpoint, getIOSVersion } from '@theme/utilities'; + +export class QuickAddComponent extends Component { + /** @type {AbortController | null} */ + #abortController = null; + /** @type {Document | null} */ + #cachedProductHtml = null; + + get cachedProductHtml() { + return this.#cachedProductHtml; + } + + get productPageUrl() { + return /** @type {HTMLAnchorElement} */ (this.closest('product-card')?.querySelector('a[ref="productCardLink"]')) + ?.href; + } + + connectedCallback() { + super.connectedCallback(); + + mediaQueryLarge.addEventListener('change', this.#closeQuickAddModal); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + mediaQueryLarge.removeEventListener('change', this.#closeQuickAddModal); + } + + /** + * Handles quick add button click + * @param {Event} event - The click event + */ + handleClick = async (event) => { + event.preventDefault(); + + if (!this.#cachedProductHtml) { + await this.fetchProductPage(this.productPageUrl); + } + + if (this.#cachedProductHtml) { + // Create a fresh copy of the cached HTML to avoid modifying the original + const freshHtmlCopy = new DOMParser().parseFromString( + this.#cachedProductHtml.documentElement.outerHTML, + 'text/html' + ); + + await this.updateQuickAddModal(freshHtmlCopy); + } + + this.#openQuickAddModal(); + }; + + /** @param {QuickAddDialog} dialogComponent */ + #stayVisibleUntilDialogCloses(dialogComponent) { + this.toggleAttribute('stay-visible', true); + + dialogComponent.addEventListener(DialogCloseEvent.eventName, () => this.toggleAttribute('stay-visible', false), { + once: true, + }); + } + + #openQuickAddModal = () => { + const dialogComponent = document.getElementById('quick-add-dialog'); + if (!(dialogComponent instanceof QuickAddDialog)) return; + + this.#stayVisibleUntilDialogCloses(dialogComponent); + + dialogComponent.showDialog(); + }; + + #closeQuickAddModal = () => { + const dialogComponent = document.getElementById('quick-add-dialog'); + if (!(dialogComponent instanceof QuickAddDialog)) return; + + dialogComponent.closeDialog(); + }; + + /** + * Fetches the product page content + * @param {string} productPageUrl - The URL of the product page to fetch + * @returns {Promise} + * @throws {Error} If the fetch request fails or returns a non-200 response + */ + async fetchProductPage(productPageUrl) { + if (!productPageUrl) return; + + // We use this to abort the previous fetch request if it's still pending. + this.#abortController?.abort(); + this.#abortController = new AbortController(); + + try { + const response = await fetch(productPageUrl, { + signal: this.#abortController.signal, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch product page: HTTP error ${response.status}`); + } + + const responseText = await response.text(); + const html = new DOMParser().parseFromString(responseText, 'text/html'); + + // Store the HTML for later use + this.#cachedProductHtml = html; + } catch (error) { + if (error.name === 'AbortError') { + return; + } else { + throw error; + } + } finally { + this.#abortController = null; + } + } + + /** + * Re-renders the variant picker. + * @param {Document} newHtml - The new HTML. + */ + async updateQuickAddModal(newHtml) { + const productGrid = newHtml.querySelector('[data-product-grid-content]'); + const modalContent = document.getElementById('quick-add-modal-content'); + + if (!productGrid || !modalContent) return; + + if (isMobileBreakpoint()) { + const productDetails = productGrid.querySelector('.product-details'); + if (!productDetails) return; + const productFormComponent = productGrid.querySelector('product-form-component'); + const variantPicker = productGrid.querySelector('variant-picker'); + const productPrice = productGrid.querySelector('product-price'); + const productTitle = document.createElement('a'); + productTitle.textContent = this.dataset.productTitle || ''; + + // Make product title as a link to the product page + productTitle.href = this.productPageUrl; + + if (!productFormComponent || !variantPicker || !productPrice || !productTitle) return; + + const productHeader = document.createElement('div'); + productHeader.classList.add('product-header'); + + productHeader.appendChild(productTitle); + productHeader.appendChild(productPrice); + productGrid.appendChild(productHeader); + productGrid.appendChild(variantPicker); + productGrid.appendChild(productFormComponent); + productDetails.remove(); + } + + morph(modalContent, productGrid); + } +} + +if (!customElements.get('quick-add-component')) { + customElements.define('quick-add-component', QuickAddComponent); +} + +class QuickAddDialog extends DialogComponent { + #abortController = new AbortController(); + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener(ThemeEvents.cartUpdate, this.handleCartUpdate, { signal: this.#abortController.signal }); + this.addEventListener(ThemeEvents.variantUpdate, this.#updateProductTitleLink); + + this.addEventListener(DialogCloseEvent.eventName, this.#handleDialogClose); + } + + disconnectedCallback() { + super.disconnectedCallback(); + + this.#abortController.abort(); + this.removeEventListener(DialogCloseEvent.eventName, this.#handleDialogClose); + } + + /** + * Closes the dialog + * @param {CartUpdateEvent} event - The cart update event + */ + handleCartUpdate = (event) => { + if (event.detail.data.didError) return; + this.closeDialog(); + }; + + #updateProductTitleLink = (/** @type {CustomEvent} */ event) => { + const anchorElement = /** @type {HTMLAnchorElement} */ ( + event.detail.data.html?.querySelector('.view-product-title a') + ); + const viewMoreDetailsLink = /** @type {HTMLAnchorElement} */ (this.querySelector('.view-product-title a')); + const mobileProductTitle = /** @type {HTMLAnchorElement} */ (this.querySelector('.product-header a')); + + if (!anchorElement) return; + + if (viewMoreDetailsLink) viewMoreDetailsLink.href = anchorElement.href; + if (mobileProductTitle) mobileProductTitle.href = anchorElement.href; + }; + + #handleDialogClose = () => { + const iosVersion = getIOSVersion(); + /** + * This is a patch to solve an issue with the UI freezing when the dialog is closed. + * To reproduce it, use iOS 16.0. + */ + if (!iosVersion || iosVersion.major >= 17 || (iosVersion.major === 16 && iosVersion.minor >= 4)) return; + + requestAnimationFrame(() => { + /** @type {HTMLElement | null} */ + const grid = document.querySelector('#ResultsList [product-grid-view]'); + if (grid) { + const currentWidth = grid.getBoundingClientRect().width; + grid.style.width = `${currentWidth - 1}px`; + requestAnimationFrame(() => { + grid.style.width = ''; + }); + } + }); + }; +} + +if (!customElements.get('quick-add-dialog')) { + customElements.define('quick-add-dialog', QuickAddDialog); +} diff --git a/assets/recently-viewed-products.js b/assets/recently-viewed-products.js new file mode 100644 index 000000000..71050aae4 --- /dev/null +++ b/assets/recently-viewed-products.js @@ -0,0 +1,35 @@ +/** + * Updates the recently viewed products in localStorage. + */ +export class RecentlyViewed { + /** @static @constant {string} The key used to store the viewed products in session storage */ + static #STORAGE_KEY = 'viewedProducts'; + /** @static @constant {number} The maximum number of products to store */ + static #MAX_PRODUCTS = 4; + + /** + * Adds a product to the recently viewed products list. + * @param {string} productId - The ID of the product to add. + */ + static addProduct(productId) { + let viewedProducts = this.getProducts(); + + viewedProducts = viewedProducts.filter((/** @type {string} */ id) => id !== productId); + viewedProducts.unshift(productId); + viewedProducts = viewedProducts.slice(0, this.#MAX_PRODUCTS); + + localStorage.setItem(this.#STORAGE_KEY, JSON.stringify(viewedProducts)); + } + + static clearProducts() { + localStorage.removeItem(this.#STORAGE_KEY); + } + + /** + * Retrieves the list of recently viewed products from session storage. + * @returns {string[]} The list of viewed products. + */ + static getProducts() { + return JSON.parse(localStorage.getItem(this.#STORAGE_KEY) || '[]'); + } +} diff --git a/assets/results-list.js b/assets/results-list.js new file mode 100644 index 000000000..7e3c72f6d --- /dev/null +++ b/assets/results-list.js @@ -0,0 +1,78 @@ +import { mediaQueryLarge, requestIdleCallback, startViewTransition } from '@theme/utilities'; +import PaginatedList from '@theme/paginated-list'; + +/** + * A custom element that renders a pagniated results list + */ +export default class ResultsList extends PaginatedList { + connectedCallback() { + super.connectedCallback(); + + mediaQueryLarge.addEventListener('change', this.#handleMediaQueryChange); + this.setAttribute('initialized', ''); + } + + disconnectedCallback() { + mediaQueryLarge.removeEventListener('change', this.#handleMediaQueryChange); + } + + /** + * Updates the layout. + * + * @param {Event} event + */ + updateLayout({ target }) { + if (!(target instanceof HTMLInputElement)) return; + + this.#animateLayoutChange(target.value); + } + + /** + * Sets the layout. + * + * @param {string} value + */ + #animateLayoutChange = async (value) => { + const { grid } = this.refs; + + if (!grid) return; + + await startViewTransition(() => this.#setLayout(value), ['product-grid']); + + requestIdleCallback(() => { + const viewport = mediaQueryLarge.matches ? 'desktop' : 'mobile'; + sessionStorage.setItem(`product-grid-view-${viewport}`, value); + }); + }; + + /** + * Animates the layout change. + * + * @param {string} value + */ + #setLayout(value) { + const { grid } = this.refs; + if (!grid) return; + grid.setAttribute('product-grid-view', value); + } + + /** + * Handles the media query change event. + * + * @param {MediaQueryListEvent} event + */ + #handleMediaQueryChange = (event) => { + const targetElement = event.matches + ? this.querySelector('[data-grid-layout="desktop-default-option"]') + : this.querySelector('[data-grid-layout="mobile-option"]'); + + if (!(targetElement instanceof HTMLInputElement)) return; + + targetElement.checked = true; + this.#setLayout('default'); + }; +} + +if (!customElements.get('results-list')) { + customElements.define('results-list', ResultsList); +} diff --git a/assets/rte-formatter.js b/assets/rte-formatter.js new file mode 100644 index 000000000..9083652ab --- /dev/null +++ b/assets/rte-formatter.js @@ -0,0 +1,26 @@ +/** + * A custom element that formats rte content for easier styling + */ +class RTEFormatter extends HTMLElement { + connectedCallback() { + this.querySelectorAll('table').forEach(this.#formatTable); + } + + /** + * Formats a table for easier styling + * @param {HTMLTableElement} table + */ + #formatTable(table) { + const wrapper = document.createElement('div'); + wrapper.classList.add('rte-table-wrapper'); + const parent = table.parentNode; + if (parent) { + parent.insertBefore(wrapper, table); + wrapper.appendChild(table); + } + } +} + +if (!customElements.get('rte-formatter')) { + customElements.define('rte-formatter', RTEFormatter); +} diff --git a/assets/scrolling.js b/assets/scrolling.js new file mode 100644 index 000000000..a896a14d4 --- /dev/null +++ b/assets/scrolling.js @@ -0,0 +1,404 @@ +import { debounce, throttle, prefersReducedMotion } from '@theme/utilities'; + +/** + * Timeout duration (in milliseconds) after which scroll is considered to have ended. + * @constant {number} + */ +const SCROLL_END_TIMEOUT = 50; + +/** + * Class representing a Scroller that handles smooth scrolling and detects scroll end events. + * + * @class + */ +export class Scroller { + /** + * The element to apply scrolling to. + * @type {HTMLElement} + */ + element; + + /** + * Promise that resolves when scrolling ends. + * @type {Promise|undefined} + */ + #promise = undefined; + + /** + * Function to resolve the scroll end promise. + * @type {Function|undefined} + */ + #resolve = undefined; + + /** + * Callback function to call while user is scrolling, throttled every 50ms. + * @type {() => void} + */ + #throttledCallback; + + /** + * Callback function invoked after user scroll ends. + * @type {() => void} + */ + #endCallback; + + /** + * Callback function invoked when scrolling starts, regardless of whether it was triggered by a user event. + * @type {(() => void) | undefined} + */ + #onScrollInit; + + /** + * Callback function invoked when scrolling ends, regardless of whether it was triggered by a user event. + * @type {(() => void) | undefined} + */ + #onScrollEnd; + + /** + * Whether the scroll was triggered by a user event. + * @type {boolean} + */ + #userEvent = true; + + /** + * Whether the next scroll event should be ignored. + * @type {boolean} + */ + #ignore = false; + + /** + * Whether the element is currently scrolling. + * @type {boolean} + */ + #isScrolling = false; + + /** + * Creates a Scroller instance. + * + * @param {HTMLElement} element - The element to apply scrolling to. + * @param {Object} options - The options for the scroller. + * @param {() => void} options.onScroll - Function to call while scrolling and after scrolling ends. + * @param {() => void} [options.onScrollStart] - Function to call when scrolling starts. + * @param {() => void} [options.onScrollEnd] - Function to call after scrolling ends. + */ + constructor(element, options) { + this.#throttledCallback = throttle(options.onScroll, SCROLL_END_TIMEOUT); + this.#endCallback = options.onScroll; + + this.#onScrollInit = options.onScrollStart; + this.#onScrollEnd = options.onScrollEnd; + + this.element = element; + this.element.addEventListener('scroll', this.#handleScroll); + } + + /** + * Scrolls to a specific position or element. + * @param {number | HTMLElement} input - The position in pixels or an element to scroll to. + * @param {Object} [options] - Options for the scroll. + * @param {boolean} [options.instant] - Whether to scroll instantly. + */ + async to(input, options) { + let value; + + if (input instanceof HTMLElement) { + const paddingStart = calculatePaddingStart(this.element, this.axis); + value = input[`offset${this.#edge}`] - paddingStart; + } else { + value = input; + } + + const currentPosition = this.element[`scroll${this.#edge}`]; + const willChange = currentPosition !== value; + + if (willChange) { + this.#scroll({ ...options, method: 'scrollTo', value }); + } else if (this.#isScrolling) { + // If the scroll has started but then it's released in the same original position, + // the scroll event will not fire, so we need to manually trigger the scroll end. + this.#handleScrollEnd(false); + } + } + + /** + * Scrolls by a certain number of pixels. + * @param {number} value - The number of pixels to scroll by. + * @param {Object} [options] - Options for the scroll. + * @param {boolean} [options.instant] - Whether to scroll instantly. + */ + by(value, options) { + this.#scroll({ ...options, method: 'scrollBy', value }); + } + + /** + * Scrolls the element. + * @param {Object} options - The options for the scroll. + * @param {'scrollTo' | 'scrollBy'} options.method - The method to use to scroll. + * @param {number} options.value - The value to scroll to. + * @param {boolean} [options.instant] - Whether to scroll instantly. + */ + #scroll(options) { + const { method, value, instant = prefersReducedMotion() } = options; + + this.#reset(); + this.#ignore = instant; + this.#userEvent = false; + + // Check if we need to scroll at all + const currentPosition = this.element[`scroll${this.#edge}`]; + const targetPosition = method === 'scrollBy' ? currentPosition + value : value; + const scrollDistance = Math.abs(targetPosition - currentPosition); + + // If the distance is negligible, don't scroll and resolve immediately + if (scrollDistance < 1) { + return Promise.resolve(); + } + + if (!instant) this.#setup(); + + this.element[method]({ + [this.#edge.toLowerCase()]: value, + behavior: instant ? 'instant' : 'smooth', + }); + } + + /** + * Gets the scrolling axis ('x' or 'y') based on the element's dimensions. + * @type {'x' | 'y'} + * @readonly + */ + get axis() { + return getScrollAxis(this.element); + } + + /** + * Promise that resolves when scrolling ends. + * @type {Promise} + * @readonly + */ + get finished() { + return this.#promise ?? Promise.resolve(); + } + + /** + * Gets the scroll edge property ('Left' or 'Top') based on the axis. + * @returns {'Left' | 'Top'} + */ + get #edge() { + return this.axis === 'x' ? 'Left' : 'Top'; + } + + /** + * Sets up the scroll end promise if not already set. + */ + #setup() { + if (this.#promise) { + return; + } + + this.#promise = new Promise((resolve) => (this.#resolve = resolve)); + } + + #reset = () => { + this.#handleScrollEnd.cancel(); + this.#resolve?.(); + + this.#promise = undefined; + this.#resolve = undefined; + this.#userEvent = true; + this.#ignore = false; + }; + + /** + * Event handler for the 'scroll' event. + */ + #handleScroll = () => { + if (!this.#isScrolling) { + this.#onScrollInit?.(); + this.#isScrolling = true; + } + + if (this.#ignore) { + this.#reset(); + this.#handleScrollEnd(false); + return; + } + + const userEvent = this.#userEvent; + + this.#setup(); + if (userEvent) this.#throttledCallback(); + this.#handleScrollEnd(userEvent); + }; + + /** + * Handler called when scrolling has ended. + */ + #handleScrollEnd = debounce( + /** + * @param {boolean} userEvent + */ + (userEvent) => { + this.#resolve?.(); + if (userEvent) this.#endCallback(); + this.#reset(); + + if (this.#isScrolling) { + this.#onScrollEnd?.(); + this.#isScrolling = false; + } + }, + SCROLL_END_TIMEOUT + ); + + /** + * Sets the scroll snap behavior of the element. + * @param {boolean} value - Whether to enable scroll snap. + */ + set snap(value) { + // Changing the snap behavior will trigger a scroll event, which we should ignore + this.#ignore = true; + this.element.style.setProperty('scroll-snap-type', value ? `${this.axis} mandatory` : 'none'); + } + + /** + * Destroys the Scroller instance. + */ + destroy() { + this.element.removeEventListener('scroll', this.#handleScroll); + } +} + +/** + * Gets the scroll axis ('x' or 'y') based on the element's dimensions. + * @param {HTMLElement} el - The element to get the scroll axis of. + * @returns {'x' | 'y'} + */ +function getScrollAxis(el) { + if (el.scrollHeight > el.clientHeight && el.scrollWidth === el.clientWidth) { + return 'y'; + } + + if (el.scrollWidth > el.clientWidth && el.scrollHeight === el.clientHeight) { + return 'x'; + } + + return el.scrollWidth > el.scrollHeight ? 'x' : 'y'; +} + +/** + * Calculates the padding-start around an element to update the scroll offset. + * @param {HTMLElement} element - The element to calculate the padding-start of. + * @param {'x' | 'y'} axis - The axis to calculate the padding-start of. + * @returns {number} The padding-start in pixels. + */ +function calculatePaddingStart(element, axis) { + const computedStyle = getComputedStyle(element); + const value = axis === 'x' ? computedStyle.paddingInlineStart : computedStyle.paddingBlockStart; + + return parseFloat(value); +} + +/** + * Scrolls an element into view. + * @param {Element} element - The element to scroll into view. + * @param {Object} options - The options for the scroll. + * @param {ScrollBehavior} [options.behavior='smooth'] - The behavior of the scroll. + * @param {'start' | 'center' | 'end'} [options.block='start'] - The block alignment of the element. + * @param {'start' | 'center' | 'end'} [options.inline='start'] - The inline alignment of the element. + * @param {Element} [options.ancestor] - The ancestor element to scroll into view. + */ +export function scrollIntoView(element, { ancestor, behavior = 'smooth', block = 'start', inline = 'start' } = {}) { + if (!ancestor) { + return element.scrollIntoView({ behavior, block, inline }); + } + + const elemRect = element.getBoundingClientRect(); + const ancestorRect = ancestor.getBoundingClientRect(); + + /** + * Calculates the scroll offset for an element. + * @param {'start' | 'center' | 'end'} alignment - The alignment of the element. + * @param {number} ancestorStart - The start of the ancestor element. + * @param {number} ancestorLength - The length of the ancestor element. + * @param {number} elemStart - The start of the element. + * @param {number} elemLength - The length of the element. + * @param {number} currentScroll - The current scroll position. + * @returns {number} The scroll offset. + */ + const calculateScrollOffset = (alignment, ancestorStart, ancestorLength, elemStart, elemLength, currentScroll) => { + switch (alignment) { + case 'start': + return currentScroll + elemStart - ancestorStart; + case 'center': + return currentScroll + elemStart - ancestorStart - ancestorLength / 2 + elemLength / 2; + case 'end': + return currentScroll + elemStart - ancestorStart - ancestorLength + elemLength; + default: + return currentScroll; + } + }; + + const scrollTop = + ancestor.scrollHeight > ancestor.clientHeight + ? calculateScrollOffset( + block, + ancestorRect.top, + ancestor.clientHeight, + elemRect.top, + elemRect.height, + ancestor.scrollTop + ) + : ancestor.scrollTop; + + const scrollLeft = + ancestor.scrollWidth > ancestor.clientWidth + ? calculateScrollOffset( + inline, + ancestorRect.left, + ancestor.clientWidth, + elemRect.left, + elemRect.width, + ancestor.scrollLeft + ) + : ancestor.scrollLeft; + + ancestor.scrollTo({ top: scrollTop, left: scrollLeft, behavior }); +} + +class ScrollHint extends HTMLElement { + connectedCallback() { + this.addEventListener('scroll', this.#update); + this.#resizeObserver.observe(this); + } + + disconnectedCallback() { + this.removeEventListener('scroll', this.#update); + this.#resizeObserver.disconnect(); + } + + #update = () => { + const { scrollTop, scrollHeight, clientHeight, scrollLeft, scrollWidth, clientWidth } = this; + const scrollDirection = scrollWidth > clientWidth ? 'horizontal' : 'vertical'; + const scrollPercentage = + scrollDirection === 'vertical' + ? scrollTop / (scrollHeight - clientHeight) + : scrollLeft / (scrollWidth - clientWidth); + + this.style.maskImage = Number.isNaN(scrollPercentage) + ? '' + : `linear-gradient( + to ${scrollDirection === 'vertical' ? 'bottom' : 'right'}, + transparent ${scrollPercentage > 0 ? 1 : 0}%, + black ${scrollPercentage < 0.1 ? scrollPercentage * 100 : 10}%, + black ${scrollPercentage > 0.9 ? scrollPercentage * 100 : 90}%, + transparent 100% + )`; + }; + + #resizeObserver = new ResizeObserver(this.#update); +} + +if (!customElements.get('scroll-hint')) { + customElements.define('scroll-hint', ScrollHint); +} diff --git a/assets/search-page-input.js b/assets/search-page-input.js new file mode 100644 index 000000000..284e91798 --- /dev/null +++ b/assets/search-page-input.js @@ -0,0 +1,58 @@ +import { Component } from '@theme/component'; +import { debounce } from '@theme/utilities'; + +/** + * A custom element that allows the user to clean a search input. + * + * @typedef {object} Refs + * @property {HTMLInputElement} searchPageInput - The search input element. + * @extends {Component} + */ +class SearchPageInputComponent extends Component { + requiredRefs = ['searchPageInput']; + + /** + * Handles the click event on the clear button and submits an empty search. + * This clears the search input and resubmits the form if the page is not + * already in an empty state. + */ + handleClearClick() { + this.#submitEmptySearch(); + } + + /** + * Handles the keydown event on the search input and resets the search when + * empty and Escape is pressed. + * + * @param {KeyboardEvent} event - The keyboard event. + */ + handleKeyDown = debounce((event) => { + const value = this.refs.searchPageInput.value.trim(); + + if (event.key === 'Escape' && value === '') { + this.#submitEmptySearch(); + } + }, 100); + + #submitEmptySearch() { + const searchInput = this.refs.searchPageInput; + + searchInput.focus(); + searchInput.value = ''; + + if (this.#isEmptyState()) return; + + searchInput.form?.submit(); + } + + #isEmptyState = () => { + const url = new URL(window.location.href); + const queryParam = url.searchParams.get('q') ?? ''; + + return queryParam.trim() === ''; + }; +} + +if (!customElements.get('search-page-input-component')) { + customElements.define('search-page-input-component', SearchPageInputComponent); +} diff --git a/assets/section-renderer.js b/assets/section-renderer.js new file mode 100644 index 000000000..f5a659b49 --- /dev/null +++ b/assets/section-renderer.js @@ -0,0 +1,180 @@ +import { morph } from '@theme/morph'; + +/** + * A class to re-render sections using the Section Rendering API + */ +class SectionRenderer { + /** + * The cache of section HTML + * @type {Map} + */ + #cache = new Map(); + + /** + * The abort controllers by section ID + * @type {Map} + */ + #abortControllersBySectionId = new Map(); + + /** + * The pending promises + * @type {Map>} + */ + #pendingPromises = new Map(); + + constructor() { + window.addEventListener('load', this.#cachePageSections.bind(this)); + } + + /** + * Renders a section + * @param {string} sectionId - The section ID + * @param {Object} [options] - The options + * @param {boolean} [options.cache] - Whether to use the cache + * @returns {Promise} The rendered section HTML + */ + async renderSection(sectionId, options) { + const { cache = !Shopify.designMode } = options ?? {}; + + this.#abortPendingMorph(sectionId); + + const abortController = new AbortController(); + this.#abortControllersBySectionId.set(sectionId, abortController); + + const sectionHTML = await this.getSectionHTML(sectionId, cache); + + if (!abortController.signal.aborted) { + this.#abortControllersBySectionId.delete(sectionId); + + morphSection(sectionId, sectionHTML); + } + + return sectionHTML; + } + + /** + * Aborts an existing morph for a section + * @param {string} sectionId - The section ID + */ + #abortPendingMorph(sectionId) { + const existingAbortController = this.#abortControllersBySectionId.get(sectionId); + if (existingAbortController) { + existingAbortController.abort(); + } + } + + /** + * Gets the HTML for a section + * @param {string} sectionId - The section ID + * @param {boolean} useCache - Whether to use the cache + * @param {URL} url - The URL to render the section for + * @returns {Promise} The rendered section HTML + */ + async getSectionHTML(sectionId, useCache = true, url = new URL(window.location.href)) { + const sectionUrl = buildSectionRenderingURL(sectionId, url); + + let pendingPromise = this.#pendingPromises.get(sectionUrl); + if (pendingPromise) return pendingPromise; + + if (useCache) { + const cachedHTML = this.#cache.get(sectionUrl); + + if (cachedHTML) return cachedHTML; + } + + pendingPromise = fetch(sectionUrl).then((response) => { + return response.text(); + }); + + this.#pendingPromises.set(sectionUrl, pendingPromise); + + const sectionHTML = await pendingPromise; + this.#pendingPromises.delete(sectionUrl); + + this.#cache.set(sectionUrl, sectionHTML); + return sectionHTML; + } + + /** + * Caches the page sections + */ + #cachePageSections() { + for (const section of document.querySelectorAll('.shopify-section')) { + const url = buildSectionRenderingURL(section.id); + if (this.#cache.get(url)) return; + if (containsShadowRoot(section)) return; + + this.#cache.set(url, section.outerHTML); + } + } +} + +const SECTION_ID_PREFIX = 'shopify-section-'; + +/** + * Builds a section rendering URL + * @param {string} sectionId - The section ID + * @param {URL} url - The URL to render the section for + * @returns {string} The section rendering URL + */ +function buildSectionRenderingURL(sectionId, url = new URL(window.location.href)) { + url.searchParams.set('section_id', normalizeSectionId(sectionId)); + url.searchParams.sort(); + + return url.toString(); +} + +/** + * Builds a section selector + * @param {string} sectionId - The section ID + * @returns {string} The section selector + */ +function buildSectionSelector(sectionId) { + return `${SECTION_ID_PREFIX}${sectionId}`; +} + +/** + * Normalizes a section ID + * @param {string} sectionId - The section ID + * @returns {string} The normalized section ID + */ +function normalizeSectionId(sectionId) { + return sectionId.replace(new RegExp(`^${SECTION_ID_PREFIX}`), ''); +} + +/** + * Checks if an element contains a shadow root + * @param {Element} element - The element to check + * @returns {boolean} Whether the element contains a shadow root + */ +function containsShadowRoot(element) { + return !!element.shadowRoot || Array.from(element.children).some(containsShadowRoot); +} + +/** + * @typedef {(previousElement: HTMLElement, newElement: HTMLElement) => void} UpdateCallback + */ + +/** + * Morphs the existing section element with the new section contents + * + * @param {string} sectionId - The section ID + * @param {string} html - The new markup the section should morph into + */ +export async function morphSection(sectionId, html) { + const fragment = new DOMParser().parseFromString(html, 'text/html'); + const existingElement = document.getElementById(buildSectionSelector(sectionId)); + const newElement = fragment.getElementById(buildSectionSelector(sectionId)); + + if (!existingElement) { + throw new Error(`Section ${sectionId} not found`); + } + + if (!newElement) { + throw new Error(`Section ${sectionId} not found in the section rendering response`); + } + + morph(existingElement, newElement); +} + +export const sectionRenderer = new SectionRenderer(); diff --git a/assets/show-more.js b/assets/show-more.js new file mode 100644 index 000000000..1b11e645b --- /dev/null +++ b/assets/show-more.js @@ -0,0 +1,162 @@ +import { Component } from '@theme/component'; +import { isMobileBreakpoint } from '@theme/utilities'; + +/** + * @typedef {Object} ShowMoreRefs + * @property {HTMLElement} showMoreButton - The button to toggle visibility of the items + * @property {HTMLElement[]} showMoreItems - The hidden items to show and hide + * @property {HTMLElement} showMoreContent - The content container to measure and animate + */ + +/** + * A custom element that manages the showing and hiding excess content items + * + * @extends {Component} + */ + +class ShowMoreComponent extends Component { + requiredRefs = ['showMoreButton', 'showMoreItems', 'showMoreContent']; + + /** + * @type {boolean} + */ + #expanded = false; + + /** + * @type {boolean} + */ + #disableOnDesktop = false; + + /** + * @type {number} + */ + #collapsedHeight = 0; + + /** + * @type {'mobile:hidden' | 'hidden'} + */ + #disabledClass = 'hidden'; + + /** + * @type {'MOBILE' | 'DESKTOP'} + */ + get #currentBreakpoint() { + return isMobileBreakpoint() ? 'MOBILE' : 'DESKTOP'; + } + + /** + * @type {Animation | undefined} + */ + #animation; + + /** + * @constant {number} + */ + #animationSpeed = 300; + + connectedCallback() { + super.connectedCallback(); + this.#updateBreakpointState(); + } + + /** + * Updates the current breakpoint and apprpropriate disabled class + */ + #updateBreakpointState = () => { + this.#disableOnDesktop = this.dataset.disableOnDesktop === 'true'; + this.#disabledClass = this.#disableOnDesktop ? 'mobile:hidden' : 'hidden'; + }; + + /** + * Handles expanding the content + * @returns {{startHeight: number, endHeight: number}} + */ + #expand = () => { + const { showMoreItems, showMoreContent } = this.refs; + + this.#collapsedHeight = showMoreContent.offsetHeight; + const startHeight = this.#collapsedHeight; + + showMoreItems?.forEach((item) => item.classList.remove(this.#disabledClass)); + + return { + startHeight, + endHeight: showMoreContent.scrollHeight, + }; + }; + + /** + * Handles collapsing the content + * @returns {{startHeight: number, endHeight: number}} + */ + #collapse = () => { + const { showMoreContent } = this.refs; + const startHeight = showMoreContent.offsetHeight; + const endHeight = this.#collapsedHeight; + + return { startHeight, endHeight }; + }; + + /** + * Initializes a height transition + * @param {number} startHeight + * @param {number} endHeight + */ + #animateHeight = (startHeight, endHeight) => { + const { showMoreContent } = this.refs; + + showMoreContent.style.overflow = 'hidden'; + this.#animation?.cancel(); + + this.#animation = showMoreContent.animate( + { + height: [`${startHeight}px`, `${endHeight}px`], + }, + { + duration: this.#animationSpeed, + easing: 'ease-in-out', + } + ); + + this.#animation.onfinish = () => this.#onAnimationFinish(); + }; + + /** + * Handles the animation finish event. + */ + #onAnimationFinish() { + const { showMoreContent, showMoreItems } = this.refs; + + if (this.#expanded) { + showMoreItems.forEach((item) => item.classList.add(this.#disabledClass)); + } + + showMoreContent.style.removeProperty('height'); + showMoreContent.style.overflow = ''; + this.#expanded = !this.#expanded; + } + + /** + * Toggles the expansion state of the content. + * + * @param {Event} event - The click event + */ + toggle = (event) => { + event.preventDefault(); + + this.#updateBreakpointState(); + + if (this.#currentBreakpoint === 'DESKTOP' && this.#disableOnDesktop) return; + + const { startHeight, endHeight } = !this.#expanded ? this.#expand() : this.#collapse(); + + this.dataset.expanded = this.#expanded ? 'false' : 'true'; + this.refs.showMoreButton.setAttribute('aria-expanded', this.dataset.expanded); + + this.#animateHeight(startHeight, endHeight); + }; +} + +if (!customElements.get('show-more-component')) { + customElements.define('show-more-component', ShowMoreComponent); +} diff --git a/assets/slideshow.js b/assets/slideshow.js new file mode 100644 index 000000000..962ebd255 --- /dev/null +++ b/assets/slideshow.js @@ -0,0 +1,750 @@ +import { Component } from '@theme/component'; +import { + center, + closest, + clamp, + getVisibleElements, + mediaQueryLarge, + prefersReducedMotion, + preventDefault, + viewTransition, + scheduler, +} from '@theme/utilities'; +import { Scroller, scrollIntoView } from '@theme/scrolling'; +import { SlideshowSelectEvent } from '@theme/events'; + +// The threshold for determining visibility of slides. +const SLIDE_VISIBLITY_THRESHOLD = 0.7; + +/** + * Slideshow custom element that allows sliding between content. + * + * @typedef {Object} Refs + * @property {HTMLElement} scroller + * @property {HTMLElement} slideshowContainer + * @property {HTMLElement[]} [slides] + * @property {HTMLElement} [current] + * @property {HTMLElement[]} [thumbnails] + * @property {HTMLElement[]} [dots] + * @property {HTMLButtonElement} [previous] + * @property {HTMLButtonElement} [next] + * + * @extends {Component} + */ +export class Slideshow extends Component { + static get observedAttributes() { + return ['initial-slide']; + } + + /** + * @param {string} name + * @param {string} oldValue + * @param {string} newValue + */ + attributeChangedCallback(name, oldValue, newValue) { + // Collection page filtering will Morph slideshow galleries in place, updating + // the slideshow[initial-slide] and slideshow-slide[hidden] attributes. + // We need to re-select() the slide after the morph is complete, but not before + // slideshow-slide elements have their [hidden] attribute updated. + if (name === 'initial-slide' && oldValue !== newValue) { + queueMicrotask(() => { + // Only select if the component is connected and initialized + if (!this.isConnected || !this.#scroll || !this.refs.slides) return; + const index = parseInt(newValue, 10) || 0; + const slide_id = this.refs.slides[index]?.getAttribute('slide-id'); + if (slide_id) { + this.select({ id: slide_id }, undefined, { animate: false }); + } + }); + } + } + + requiredRefs = ['scroller']; + + async connectedCallback() { + super.connectedCallback(); + + // Wait for any in-progress view transitions to finish + if (viewTransition.current) { + await viewTransition.current; + // It's possible that the slideshow was disconnected before the view transition finished + if (!this.isConnected) return; + } + + const { scroller } = this.refs; + this.#scroll = new Scroller(scroller, { + onScroll: this.#handleScroll, + onScrollStart: this.#onTransitionInit, + onScrollEnd: this.#onTransitionEnd, + }); + + scroller.addEventListener('mousedown', this.#handleMouseDown); + + this.addEventListener('mouseenter', this.suspend); + this.addEventListener('mouseleave', this.resume); + this.addEventListener('pointerenter', this.#handlePointerEnter); + document.addEventListener('visibilitychange', this.#handleVisibilityChange); + + this.#updateControlsVisibility(); + + this.disabled = this.isNested || this.disabled; + + this.resume(); + + this.current = this.initialSlideIndex; + + // Batch reads and writes to the DOM + scheduler.schedule(() => { + let visibleSlidesAmount = 0; + const initialSlideId = this.initialSlide?.getAttribute('slide-id'); + if (this.initialSlideIndex !== 0 && initialSlideId) { + this.select({ id: initialSlideId }, undefined, { animate: false }); + visibleSlidesAmount = 1; + } else { + visibleSlidesAmount = this.#updateVisibleSlides(); + if (visibleSlidesAmount === 0) { + this.select(0, undefined, { animate: false }); + visibleSlidesAmount = 1; + } + } + + this.#resizeObserver = new ResizeObserver(async () => { + if (viewTransition.current) await viewTransition.current; + + if (visibleSlidesAmount > 1) { + this.#updateVisibleSlides(); + } + + if (this.hasAttribute('auto-hide-controls')) { + this.#updateControlsVisibility(); + } + }); + + this.#resizeObserver.observe(this.refs.slideshowContainer); + }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + const { scroller } = this.refs; + + scroller.removeEventListener('mousedown', this.#handleMouseDown); + this.removeEventListener('mouseenter', this.suspend); + this.removeEventListener('mouseleave', this.resume); + this.removeEventListener('pointerenter', this.#handlePointerEnter); + document.removeEventListener('visibilitychange', this.#handleVisibilityChange); + this.#scroll?.destroy(); + + if (this.#resizeObserver) { + this.#resizeObserver.disconnect(); + } + } + + /** Indicates whether the slideshow is nested inside another slideshow. */ + get isNested() { + return this.parentElement?.closest('slideshow-component') !== null; + } + + get initialSlide() { + return this.refs.slides?.[this.initialSlideIndex]; + } + + /** + * Selects a slide based on the input index. + * @param {number|string|{id: string}} input - The index or id of the slide to select. + * @param {Event} [event] - The event that triggered the selection. + * @param {Object} [options] - The options for the selection. + * @param {boolean} [options.animate=true] - Whether to animate the selection. + */ + async select(input, event, options = {}) { + if (this.#disabled || !this.refs.slides?.length) return; + + for (const slide of this.refs.slides) { + if (slide.hasAttribute('reveal')) { + slide.removeAttribute('reveal'); + slide.setAttribute('aria-hidden', 'true'); + } + } + + // Figure out the raw desired index (could be -1 if user is on first slide and clicks prev) + let requestedIndex = (() => { + if (typeof input === 'number') return input; + if (typeof input === 'string') return parseInt(input, 10); + if ('id' in input) { + const requestedSlide = this.refs.slides.find((slide) => slide.getAttribute('slide-id') == input.id); + + if (!requestedSlide || !this.slides) return; + + // Force the slide to be revealed if it is hidden + if (requestedSlide.hasAttribute('hidden')) { + requestedSlide.setAttribute('reveal', ''); + requestedSlide.setAttribute('aria-hidden', 'false'); + } + + return this.slides.indexOf(requestedSlide); + } + })(); + + const { current } = this; + + // Guard if invalid + if (requestedIndex === undefined || isNaN(requestedIndex) || requestedIndex === current) return; + + const { slides } = this; + + if (!slides?.length) return; + if (!this.infinite) requestedIndex = clamp(requestedIndex, 0, slides.length - 1); + + event?.preventDefault(); + + const { animate = true } = options; + const lastIndex = slides.length - 1; + + // Decide the actual target index (clamp for infinite loop) + let index = requestedIndex; + if (requestedIndex < 0) index = lastIndex; + else if (requestedIndex > lastIndex) index = 0; + + const isAdjacentSlide = Math.abs(index - current) <= 1 && requestedIndex >= 0 && requestedIndex <= lastIndex; + const { visibleSlides } = this; + const instant = prefersReducedMotion() || !animate; + + // If jump is more than 1 or we looped, do the placeholder + reorder trick + if (!instant && !isAdjacentSlide && visibleSlides.length === 1) { + this.#disabled = true; + await this.#scroll.finished; // ensure we're not mid-scroll + + const targetSlide = slides[index]; + const currentSlide = slides[current]; + if (!targetSlide || !currentSlide) return; + + // Create a placeholder in the original DOM position of targetSlide + const placeholder = document.createElement('slideshow-slide'); + targetSlide.before(placeholder); + + // Decide whether targetSlide goes before or after currentSlide + // so that we scroll a short distance in the correct direction + if (requestedIndex < current) { + currentSlide.before(targetSlide); + } else { + currentSlide.after(targetSlide); + } + + if (current === 0) this.#scroll.to(currentSlide, { instant: true }); + + // Once that scroll finishes, restore the DOM + queueMicrotask(async () => { + await this.#scroll.finished; + this.#disabled = false; + + // Restore the slide back to its original position. This triggers a scroll event. + placeholder.replaceWith(targetSlide); + + // Instantly scroll to the target slide as its position will have changed + this.#scroll.to(targetSlide, { instant: true }); + }); + } + + const slide = slides[index]; + if (!slide) return; + + const previousIndex = this.current; + + slide.setAttribute('aria-hidden', 'false'); + this.#scroll.to(slide, { instant }); + this.current = this.slides?.indexOf(slide) || 0; + + this.#centerSelectedThumbnail(index, instant ? 'instant' : 'smooth'); + + this.dispatchEvent( + new SlideshowSelectEvent({ + index, + previousIndex, + userInitiated: event != null, + trigger: 'select', + slide, + id: slide.getAttribute('slide-id'), + }) + ); + } + + /** + * Advances to the next slide. + * @param {Event} [event] - The event that triggered the next slide. + * @param {Object} [options] - The options for the next slide. + * @param {boolean} [options.animate=true] - Whether to animate the next slide. + */ + next(event, options) { + event?.preventDefault(); + this.select(this.nextIndex, event, options); + } + + /** + * Goes back to the previous slide. + * @param {Event} [event] - The event that triggered the previous slide. + * @param {Object} [options] - The options for the previous slide. + * @param {boolean} [options.animate=true] - Whether to animate the previous slide. + */ + previous(event, options) { + event?.preventDefault(); + this.select(this.previousIndex, event, options); + } + + /** + * Starts automatic slide playback. + * @param {number} [interval] - The time interval in seconds between slides. + */ + play(interval = this.autoplayInterval) { + if (this.#interval) return; + + this.paused = false; + + this.#interval = setInterval(() => { + if (this.matches(':hover') || document.hidden) return; + + this.next(); + }, interval); + } + + /** + * Pauses automatic slide playback. + */ + pause() { + this.paused = true; + this.suspend(); + } + + get paused() { + return this.hasAttribute('paused'); + } + + set paused(value) { + if (value) { + this.setAttribute('paused', ''); + } else { + this.removeAttribute('paused'); + } + } + + /** + * Suspends automatic slide playback. + */ + suspend() { + clearInterval(this.#interval); + this.#interval = undefined; + } + + /** + * Resumes automatic slide playback if autoplay is enabled. + */ + resume() { + if (!this.autoplay || this.paused) return; + + this.pause(); + this.play(); + } + + get autoplay() { + return Boolean(this.autoplayInterval); + } + + get autoplayInterval() { + const interval = this.getAttribute('autoplay'); + const value = parseInt(`${interval}`, 10); + + if (Number.isNaN(value)) return undefined; + + return value * 1000; + } + + /** + * The current slide index. + * @type {number} + */ + #current = 0; + + get current() { + return this.#current; + } + + /** + * Sets the current slide index and update the DOM + * @type {number} + */ + set current(value) { + const { current, thumbnails, dots, slides, previous, next } = this.refs; + + this.#current = value; + + if (current) current.textContent = `${value + 1}`; + + for (const controls of [thumbnails, dots]) { + controls?.forEach((el, i) => el.setAttribute('aria-selected', `${i === value}`)); + } + + if (previous) previous.disabled = Boolean(!this.infinite && value === 0); + if (next) next.disabled = Boolean(!this.infinite && slides && this.nextIndex >= slides.length); + } + + get infinite() { + return this.getAttribute('infinite') != null; + } + + get visibleSlides() { + return getVisibleElements(this.refs.scroller, this.slides, SLIDE_VISIBLITY_THRESHOLD, 'x'); + } + + get previousIndex() { + const { current, visibleSlides } = this; + const modifier = visibleSlides.length > 1 ? visibleSlides.length : 1; + + return current - modifier; + } + + get nextIndex() { + const { current, visibleSlides } = this; + const modifier = visibleSlides.length > 1 ? visibleSlides.length : 1; + + return current + modifier; + } + + get atStart() { + const { current, slides } = this; + + return slides?.length ? current === 0 : false; + } + + get atEnd() { + const { current, slides } = this; + + return slides?.length ? current === slides.length - 1 : false; + } + + /** + * Sets the disabled attribute. + * @param {boolean} value - The value to set the disabled attribute to. + */ + set disabled(value) { + this.setAttribute('disabled', String(value)); + } + /** + * Whether the slideshow is disabled. + * @type {boolean} + */ + get disabled() { + return ( + this.getAttribute('disabled') === 'true' || (this.hasAttribute('mobile-disabled') && !mediaQueryLarge.matches) + ); + } + + /** + * Indicates whether the slideshow is temporarily disabled (e.g., during infinite loop transition). + * @type {boolean} + */ + #disabled = false; + + /** + * The interval ID for automatic playback. + * @type {number|undefined} + */ + #interval = undefined; + + /** + * The Scroller instance that manages scrolling. + * @type {Scroller} + */ + #scroll; + + /** + * The ResizeObserver instance for monitoring scroller size changes + * @type {ResizeObserver} + */ + #resizeObserver; + + /** + * Callback invoked on user initiated scroll to sync the current slide index + * and emit a slide change event if the index has changed. + */ + #handleScroll = () => { + const previousIndex = this.#current; + const index = this.#sync(); + + if (index === previousIndex) return; + + const slide = this.slides?.[index]; + if (!slide) return; + + this.dispatchEvent( + new SlideshowSelectEvent({ + index, + previousIndex, + userInitiated: true, + trigger: 'scroll', + slide, + id: slide.getAttribute('slide-id'), + }) + ); + }; + + #onTransitionInit = () => { + this.setAttribute('transitioning', ''); + }; + + #onTransitionEnd = () => { + this.#updateVisibleSlides(); + this.removeAttribute('transitioning'); + }; + + /** + * Synchronizes the scroll position and updates the current slide index. + * @returns {number} The index of the current slide. + */ + #sync = () => { + const { slides } = this; + if (!slides) return (this.current = 0); + + const visibleSlides = this.visibleSlides; + + if (!visibleSlides.length) return this.current; + + const { axis } = this.#scroll; + const { scroller } = this.refs; + const centers = visibleSlides.map((slide) => center(slide, axis)); + const referencePoint = visibleSlides.length > 1 ? scroller.getBoundingClientRect()[axis] : center(scroller, axis); + const closestCenter = closest(centers, referencePoint); + const closestVisibleSlide = visibleSlides[centers.indexOf(closestCenter)]; + + if (!closestVisibleSlide) return (this.current = 0); + + const index = slides.indexOf(closestVisibleSlide); + + return (this.current = index); + }; + + #dragging = false; + + /** + * Handles the 'mousedown' event to start dragging slides. + * @param {MouseEvent} event - The mousedown event. + */ + #handleMouseDown = (event) => { + const { slides } = this; + + if (!slides || slides.length <= 1) return; + if (!(event.target instanceof Element)) return; + if (this.disabled || this.#dragging) return; + + // Check if the event target is within a 3D model interactive element + // This prevents the slideshow from capturing drag events when interacting with 3D models + if (event.target.closest('model-viewer')) { + return; + } + + event.preventDefault(); + // Store initial position but don't start handling yet + const { axis } = this.#scroll; + const startPosition = event[axis]; + + const controller = new AbortController(); + const { signal } = controller; + const startTime = performance.now(); + let previous = startPosition; + let velocity = 0; + let moved = false; + let distanceTravelled = 0; + + this.#dragging = true; + + /** + * Handles the 'pointermove' event to update the scroll position. + * @param {PointerEvent} event - The pointermove event. + */ + const onPointerMove = (event) => { + const current = event[axis]; + const initialDelta = startPosition - current; + + if (!initialDelta) return; + + if (!moved) { + moved = true; + this.setPointerCapture(event.pointerId); + + // Prevent clicks once the user starts dragging + document.addEventListener('click', preventDefault, { once: true, signal }); + + const movingRight = initialDelta < 0; + const movingLeft = initialDelta > 0; + + // Check if the current slideshow should handle this drag + const closestSlideshow = this.parentElement?.closest('slideshow-component'); + const isNested = closestSlideshow instanceof Slideshow && closestSlideshow !== this; + const cannotMoveInDirection = (movingRight && this.atStart) || (movingLeft && this.atEnd); + + // Abort and let the parent slideshow handle the drag if we're moving in a direction where nested slideshow can't move + if (isNested && cannotMoveInDirection) { + controller.abort(); + return; + } + + this.pause(); + this.setAttribute('dragging', ''); + } + + // Stop the event from bubbling up to parent slideshow components + event.stopImmediatePropagation(); + + const delta = previous - current; + const timeDelta = performance.now() - startTime; + velocity = Math.round((delta / timeDelta) * 1000); + previous = current; + distanceTravelled += Math.abs(delta); + + this.#scroll.by(delta, { instant: true }); + }; + + /** + * Handles the 'pointerup' event to stop dragging slides. + * @param {PointerEvent} event - The pointerup event. + */ + const onPointerUp = async (event) => { + controller.abort(); + const { current, slides } = this; + const { scroller } = this.refs; + + this.#dragging = false; + + if (!slides?.length || !scroller) return; + + const direction = Math.sign(velocity); + const next = this.#sync(); + + const modifier = current !== next || Math.abs(velocity) < 10 || distanceTravelled < 10 ? 0 : direction; + const newIndex = clamp(next + modifier, 0, slides.length - 1); + + const newSlide = slides[newIndex]; + const currentIndex = this.current; + + if (!newSlide) throw new Error(`Slide not found at index ${newIndex}`); + + this.#scroll.to(newSlide); + + this.removeAttribute('dragging'); + this.releasePointerCapture(event.pointerId); + + this.#centerSelectedThumbnail(newIndex); + + this.dispatchEvent( + new SlideshowSelectEvent({ + index: newIndex, + previousIndex: currentIndex, + userInitiated: true, + trigger: 'drag', + slide: newSlide, + id: newSlide.getAttribute('slide-id'), + }) + ); + + this.current = newIndex; + + await this.#scroll.finished; + + // It's possible that the user started dragging again before the scroll finished + if (this.#dragging) return; + + this.#scroll.snap = true; + this.resume(); + }; + + this.#scroll.snap = false; + + document.addEventListener('pointermove', onPointerMove, { signal }); + document.addEventListener('pointerup', onPointerUp, { signal }); + /** + * pointerDown calls onPointerUp to fix an issue where the first tap-and-drag + * on the zoom dialog is captured by the pointerMove/pointerUp listeners, + * sometimes causing the slideshow to change slides unexpectedly + */ + document.addEventListener('pointerdown', onPointerUp, { signal }); + document.addEventListener('pointercancel', onPointerUp, { signal }); + document.addEventListener('pointercapturelost', onPointerUp, { signal }); + }; + + #handlePointerEnter = () => { + this.setAttribute('actioned', ''); + }; + + get slides() { + return this.refs.slides?.filter((slide) => !slide.hasAttribute('hidden') || slide.hasAttribute('reveal')); + } + + /** + * The initial slide index. + * @type {number} + */ + get initialSlideIndex() { + const initialSlide = this.getAttribute('initial-slide'); + if (initialSlide == null) return 0; + + return parseInt(initialSlide, 10); + } + + /** + * Pause the slideshow when the page is hidden. + */ + #handleVisibilityChange = () => (document.hidden ? this.pause() : this.resume()); + + #updateControlsVisibility() { + if (!this.hasAttribute('auto-hide-controls')) return; + + const { scroller, slideshowControls } = this.refs; + + if (!(slideshowControls instanceof HTMLElement)) return; + + slideshowControls.hidden = scroller.scrollWidth <= scroller.offsetWidth; + } + + /** + * Centers the selected thumbnail in the thumbnails container + * @param {number} index - The index of the selected thumbnail + * @param {ScrollBehavior} [behavior] - The scroll behavior. + */ + #centerSelectedThumbnail(index, behavior = 'smooth') { + const selectedThumbnail = this.refs.thumbnails?.[index]; + if (!selectedThumbnail) return; + + const { thumbnailsContainer } = this.refs; + if (!thumbnailsContainer || !(thumbnailsContainer instanceof HTMLElement)) return; + + const { slideshowControls } = this.refs; + if (!slideshowControls || !(slideshowControls instanceof HTMLElement)) return; + + scrollIntoView(selectedThumbnail, { + ancestor: thumbnailsContainer, + behavior, + block: 'center', + inline: 'center', + }); + } + + #updateVisibleSlides() { + const { slides } = this; + if (!slides || !slides.length) return 0; + + const visibleSlides = this.visibleSlides; + + // Batch writes to the DOM + scheduler.schedule(() => { + // Update aria-hidden based on visibility + slides.forEach((slide) => { + const isVisible = visibleSlides.includes(slide); + slide.setAttribute('aria-hidden', `${!isVisible}`); + }); + }); + + return visibleSlides.length; + } +} + +if (!customElements.get('slideshow-component')) { + customElements.define('slideshow-component', Slideshow); +} diff --git a/assets/template-giftcard.css b/assets/template-giftcard.css new file mode 100644 index 000000000..7d9c1c905 --- /dev/null +++ b/assets/template-giftcard.css @@ -0,0 +1,137 @@ +.gift-card { + padding-block: var(--padding-4xl); + padding-inline: var(--padding-lg); + + --buttons-max-width: min(16rem, 100%); + --gift-card-image-max-width: var(--max-width--heading-normal); + --gift-card-image-max-height: 35rem; + --gift-card-image-max-width: 21rem; + + @media only screen and (min-width: 750px) { + padding-block: var(--padding-6xl) var(--padding-5xl); + padding-inline: var(--padding-6xl); + } +} + +.gift-card__main { + display: flex; + flex-direction: column; +} + +.gift-card__image-wrapper { + display: flex; + width: 100%; + aspect-ratio: 5 / 3; + padding: var(--padding-4xl); + margin-block: var(--padding-4xl); + margin-inline: auto; + max-width: var(--gift-card-image-max-width); + border: 1px solid var(--color-border); + border-radius: var(--style-border-radius-lg); +} + +.gift-card__image-wrapper:has(.gift-card__image-generic) { + padding: 0; + border: none; +} + +.gift-card__price { + display: flex; + flex-wrap: wrap; + gap: 0 var(--gap-lg); + align-items: center; + justify-content: center; +} + +.gift-card__code, +.gift-card__text-wrapper h1, +.gift-card__price h2 { + font-family: var(--font-paragraph--family); + font-style: var(--font-paragraph--style); + font-weight: var(--font-paragraph--weight); + text-align: center; + margin-block-end: var(--margin-xl); +} + +.gift-card__code, +.gift-card__text-wrapper h1 { + font-size: var(--font-size--2xl); + margin-block-end: 0; +} + +.gift-card__price h2 { + font-size: var(--font-size--5xl); + margin-block-end: var(--padding-4xl); +} + +.gift-card__text-wrapper { + text-align: center; + max-width: var(--max-width--body-normal); + margin: 0 auto; +} + +.gift-card__badge { + border: 1px solid var(--color-border); + border-radius: var(--style-border-radius-buttons); + display: inline-block; + line-height: 0.25; + padding: var(--padding-md); + text-align: center; + background-color: rgb(var(--color-background)); + border-color: rgb(var(--color-foreground), var(--opacity-5)); + color: rgb(var(--color-foreground)); + margin-block: 0; +} + +.gift-card__badge--expired { + opacity: var(--disabled-opacity); +} + +.gift-card__qr-code { + margin: var(--margin-4xl) 0; +} + +.gift-card__qr-code img { + margin: 0 auto; + width: auto; +} + +.gift-card__buttons { + display: flex; + flex-flow: column wrap; + width: var(--buttons-max-width); + margin: 0 auto; + align-items: center; + gap: var(--gap-sm); +} + +.gift-card__buttons-full-width { + width: 100%; +} + +.gift-card__buttons .button { + width: 100%; + justify-content: center; +} + +.gift-card__copy-button { + position: relative; +} + +.form__message { + display: flex; + justify-content: center; + position: absolute; + top: calc(var(--padding-lg) * -1); + left: 0; + right: 0; + transition: opacity var(--animation-speed) var(--animation-easing), + transform var(--animation-speed) var(--animation-easing); + opacity: 0; + transform: translateY(var(--padding-md)); +} + +.form__message:not(.visually-hidden) { + opacity: 1; + transform: translateY(0); +} diff --git a/assets/theme-editor.js b/assets/theme-editor.js new file mode 100644 index 000000000..d96153d24 --- /dev/null +++ b/assets/theme-editor.js @@ -0,0 +1,268 @@ +// Theme editor specific logic + +/** + * @param {Event} event + */ +document.addEventListener('shopify:block:select', function (event) { + if (event.target instanceof HTMLElement) { + // Check if the selected element is specifically a product-card block itself + // Not a child block within the product card + + // First, remove data-no-navigation from any previously selected product cards + document.querySelectorAll('product-card[data-no-navigation]').forEach((card) => { + if (card instanceof HTMLElement) { + card.removeAttribute('data-no-navigation'); + } + }); + + if (event.target.tagName === 'PRODUCT-CARD') { + const section = event.target.closest('.shopify-section'); + + if (section) { + const productCardsInSection = section.querySelectorAll('product-card'); + + productCardsInSection.forEach((card) => { + if (card instanceof HTMLElement) { + card.setAttribute('data-no-navigation', 'true'); + } + }); + } + } + + const slide = event.target.closest('slideshow-slide'); + + if (slide) { + /** @type {import('./slideshow').Slideshow | null} */ + const slideshow = slide.closest('slideshow-component'); + + if (slideshow) { + const index = Array.from(slide.parentElement?.children ?? []).indexOf(slide); + + if (index !== -1) { + // Pause autoplay + slideshow.pause(); + slideshow.select(index); + } + } + } + } +}); + +document.addEventListener('shopify:block:deselect', function (event) { + if (event.target instanceof HTMLElement) { + // Remove data-no-navigation when product card is deselected + if (event.target.tagName === 'PRODUCT-CARD') { + event.target.removeAttribute('data-no-navigation'); + } + + /** @type {import('./slideshow').Slideshow | null} */ + const slideshow = event.target.closest('slideshow-component'); + + if (slideshow) { + // Resume playback + slideshow.resume(); + } + } +}); + +/** + * When in the theme editor, it can be frustrating to be tweaking the design of features that are implemented as a dialog + * or any sort of overlay, because the theme editor will refresh the page and close the dialog. + * + * This script is used to save the state of these features and restore it when the page is refreshed, to make things a little more seamless. + */ +if (window.Shopify?.designMode) { + (function editorStateManager() { + const EDITOR_PREFIX = 'editor-save-state'; + + /** + * @param {string} name + */ + function getEditorState(name) { + const state = sessionStorage.getItem(`${EDITOR_PREFIX}-${name}`); + return state ? JSON.parse(state) : null; + } + + /** + * @param {string} name + * @param {boolean} isOpen + * @param {string | undefined} instanceId + */ + function saveEditorState(name, isOpen, instanceId) { + sessionStorage.setItem(`${EDITOR_PREFIX}-${name}`, JSON.stringify({ isOpen, instanceId })); + } + + /** @type {{name: string, selector: string, matches: (el: Element) => boolean, isOpen: (el: Element) => boolean, open: (el: Element, instanceId?: string) => void, getInstanceId?: (el: Element) => string | undefined}[]} */ + const features = [ + { + name: 'account-popover', + selector: '.account-popover', + matches(el) { + return el.matches(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el) => el.setAttribute('open', ''), + }, + { + name: 'account-drawer', + selector: '.account-drawer', + matches(el) { + return !!el.closest(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + // @ts-ignore + open: (el) => el.showDialog(), + }, + { + name: 'localization-dropdown', + selector: 'dropdown-localization-component', + matches(el) { + return !!el.closest(this.selector); + }, + isOpen: (el) => el.getAttribute('aria-expanded') === 'true', + // @ts-ignore + open: (el) => el.showPanel(), + }, + { + name: 'search-modal', + selector: '.search-modal', + matches(el) { + return !!el.closest(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + // @ts-ignore + open: (el) => el.showDialog(), + }, + { + name: 'cart-drawer', + selector: 'cart-drawer-component', + matches(el) { + return !!el.closest(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el) => { + // @ts-ignore + el.open(); + }, + }, + { + name: 'header-drawer', + selector: 'header-drawer', + matches(el) { + return !!el.closest(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el) => { + // @ts-ignore + el.open(); + // @ts-ignore + el.refs.details.setAttribute('open', ''); + }, + }, + { + name: 'local-pickup-modal', + selector: '.pickup-location__dialog', + matches(el) { + return el.matches(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el) => { + // @ts-ignore + el.closest('dialog-component').toggleDialog(); + }, + }, + { + name: 'quick-add-modal', + getInstanceId: (el) => { + // @ts-ignore + return el.querySelector('product-price')?.dataset?.productId; + }, + selector: '.quick-add-modal', + matches(el) { + return el.matches(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el, instanceId) => { + const button = document.querySelector( + `product-form-component[data-product-id="${instanceId}"] .quick-add__button--choose` + ); + + // @ts-ignore + button?.click(); + }, + }, + { + name: 'floating-panel-component', + getInstanceId: (el) => { + return el.id; + }, + selector: '.facets__panel', + matches(el) { + return el.matches(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el, instanceId) => document.querySelector(`#${instanceId}`)?.setAttribute('open', ''), + }, + { + name: 'facets-panel', + selector: '.facets--drawer', + matches(el) { + return el.matches(this.selector); + }, + isOpen: (el) => el.getAttribute('open') != null, + open: (el) => el?.setAttribute('open', ''), + }, + ]; + + // On page load, restore the state of the features + features.forEach((feature) => { + const el = document.querySelector(feature.selector); + if (!el) return; + + const state = getEditorState(feature.name); + const shouldBeOpen = state?.isOpen; + const instanceId = state?.instanceId; + + if (shouldBeOpen) { + // Prevents race condition with the open methods not always being available immediately + setTimeout(() => { + feature.open(el, instanceId); + }); + } + }); + + /** @param {Element} el */ + const update = (el) => { + const feature = features.find((f) => f.matches(el)); + if (!feature) return; + + const isOpen = feature.isOpen(el); + const instanceId = feature.getInstanceId?.(el); + + saveEditorState(feature.name, isOpen, instanceId); + }; + + const trackedAttributes = ['open', 'aria-expanded']; + + // Track state changes via attribute changes + const observer = new MutationObserver((list) => { + for (const mutation of list) { + if ( + mutation.type === 'attributes' && + mutation.attributeName && + trackedAttributes.includes(mutation.attributeName) + ) { + const element = /** @type {Element} */ (mutation.target); + update(element); + } + } + }); + + observer.observe(document.body, { + childList: true, + attributes: true, + attributeFilter: trackedAttributes, + subtree: true, + }); + })(); +} diff --git a/assets/utilities.js b/assets/utilities.js new file mode 100644 index 000000000..0e949be5a --- /dev/null +++ b/assets/utilities.js @@ -0,0 +1,603 @@ +/** + * Request an idle callback or fallback to setTimeout + * @returns {function} The requestIdleCallback function + */ +export const requestIdleCallback = + typeof window.requestIdleCallback == 'function' ? window.requestIdleCallback : setTimeout; + +/** + * Executes a callback in a separate task after the next frame. + * Using to defer non-critical tasks until after the interaction is complete. + * @see https://web.dev/articles/optimize-inp#yield_to_allow_rendering_work_to_occur_sooner + * @param {() => any} callback - The callback to execute + */ +export const requestYieldCallback = (callback) => { + requestAnimationFrame(() => { + setTimeout(callback, 0); + }); +}; + +/** + * Check if the browser supports View Transitions API + * @returns {boolean} True if the browser supports View Transitions API, false otherwise + */ +export function supportsViewTransitions() { + return typeof document.startViewTransition === 'function'; +} + +/** + * The current view transition + * @type {{ current: Promise | undefined }} + */ +export const viewTransition = { + current: undefined, +}; + +/** + * Functions to run when a view transition of a given type is started + * @type {{ [key: string]: () => Promise<(() => void) | undefined> }} + */ +const viewTransitionTypes = { + 'product-grid': async () => { + const grid = document.querySelector('.product-grid'); + const productCards = /** @type {HTMLElement[]} */ ([ + ...document.querySelectorAll('.product-grid .product-grid__item'), + ]); + + if (!grid || !productCards.length) return; + + await new Promise((resolve) => + requestIdleCallback(() => { + const cardsToAnimate = getCardsToAnimate(grid, productCards); + + productCards.forEach((card, index) => { + if (index < cardsToAnimate) { + card.style.setProperty('view-transition-name', `product-card-${card.dataset.productId}`); + } else { + card.style.setProperty('content-visibility', 'hidden'); + } + }); + + resolve(null); + }) + ); + + return () => + productCards.forEach((card) => { + card.style.removeProperty('view-transition-name'); + card.style.removeProperty('content-visibility'); + }); + }, +}; + +/** + * Starts a view transition + * @param {() => void} callback The callback to call when the view transition starts + * @param {string[]} [types] The types of view transition to use + * @returns {Promise} A promise that resolves when the view transition finishes + */ +export function startViewTransition(callback, types) { + return new Promise(async (resolve) => { + // Check if View Transitions API is supported + if (supportsViewTransitions() && !prefersReducedMotion()) { + let cleanupFunctions = []; + + if (types) { + for (const type of types) { + if (viewTransitionTypes[type]) { + const cleanupFunction = await viewTransitionTypes[type](); + if (cleanupFunction) cleanupFunctions.push(cleanupFunction); + } + } + } + + const transition = document.startViewTransition(callback); + + if (!viewTransition.current) { + viewTransition.current = transition.finished; + } + + if (types) types.forEach((type) => transition.types.add(type)); + + transition.finished.then(() => { + viewTransition.current = undefined; + cleanupFunctions.forEach((cleanupFunction) => cleanupFunction()); + resolve(); + }); + + return; + } + + // Fallback for browsers that don't support this API yet + callback(); + resolve(); + }); +} + +/** + * @typedef {{ [key: string]: string | undefined }} Headers + */ + +/** + * @typedef {Object} FetchConfig + * @property {string} method + * @property {Headers} headers + * @property {string | FormData | undefined} [body] + */ + +/** + * Creates a fetch configuration object + * @param {string} [type] The type of response to expect + * @param {Object} [config] The config of the request + * @param {FetchConfig['body']} [config.body] The body of the request + * @param {FetchConfig['headers']} [config.headers] The headers of the request + * @returns {RequestInit} The fetch configuration object + */ +export function fetchConfig(type = 'json', config = {}) { + /** @type {Headers} */ + const headers = { 'Content-Type': 'application/json', Accept: `application/${type}`, ...config.headers }; + + if (type === 'javascript') { + headers['X-Requested-With'] = 'XMLHttpRequest'; + delete headers['Content-Type']; + } + + return { + method: 'POST', + headers: /** @type {HeadersInit} */ (headers), + body: config.body, + }; +} + +/** + * Creates a debounced function that delays calling the provided function (fn) + * until after wait milliseconds have elapsed since the last time + * the debounced function was invoked. The returned function has a .cancel() + * method to cancel any pending calls. + * + * @template {(...args: any[]) => any} T + * @param {T} fn The function to debounce + * @param {number} wait The time (in milliseconds) to wait before calling fn + * @returns {T & { cancel(): void }} A debounced version of fn with a .cancel() method + */ +export function debounce(fn, wait) { + /** @type {number | undefined} */ + let timeout; + + /** @param {...any} args */ + function debounced(...args) { + clearTimeout(timeout); + timeout = setTimeout(() => fn.apply(this, args), wait); + } + + // Add the .cancel method: + debounced.cancel = () => { + clearTimeout(timeout); + }; + + return /** @type {T & { cancel(): void }} */ (debounced); +} + +/** + * Creates a throttled function that calls the provided function (fn) at most once per every wait milliseconds + * + * @template {(...args: any[]) => any} T + * @param {T} fn The function to throttle + * @param {number} delay The time (in milliseconds) to wait before calling fn + * @returns {T & { cancel(): void }} A throttled version of fn with a .cancel() method + */ +export function throttle(fn, delay) { + let lastCall = 0; + + /** @param {...any} args */ + function throttled(...args) { + const now = performance.now(); + // If the time since the last call exceeds the delay, execute the callback + if (now - lastCall >= delay) { + lastCall = now; + fn.apply(this, args); + } + } + + throttled.cancel = () => { + lastCall = performance.now(); + }; + + return /** @type {T & { cancel(): void }} */ (throttled); +} + +/** + * A media query for reduced motion + * @type {MediaQueryList} + */ +const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)'); + +/** + * Check if the user prefers reduced motion + * @returns {boolean} True if the user prefers reduced motion, false otherwise + */ +export function prefersReducedMotion() { + return reducedMotion.matches; +} + +/** + * Normalize a string + * @param {string} str The string to normalize + * @returns {string} The normalized string + */ +export function normalizeString(str) { + return str + .normalize('NFD') + .replace(/\p{Diacritic}/gu, '') + .toLowerCase(); +} + +/** + * Format a money value + * @param {string} value The value to format + * @returns {string} The formatted value + */ +export function formatMoney(value) { + let valueWithNoSpaces = value.replace(' ', ''); + if (valueWithNoSpaces.indexOf(',') === -1) return valueWithNoSpaces; + if (valueWithNoSpaces.indexOf(',') < valueWithNoSpaces.indexOf('.')) return valueWithNoSpaces.replace(',', ''); + if (valueWithNoSpaces.indexOf('.') < valueWithNoSpaces.indexOf(',')) + return valueWithNoSpaces.replace('.', '').replace(',', '.'); + if (valueWithNoSpaces.indexOf(',') !== -1) return valueWithNoSpaces.replace(',', '.'); + + return valueWithNoSpaces; +} + +/** + * Check if the document is ready and call the callback when it is. + * @param {() => void} callback The function to call when the document is ready. + */ +export function onDocumentReady(callback) { + if (document.readyState === 'complete') { + callback(); + } else { + window.addEventListener('load', callback); + } +} + +/** + * Wait for all animations to finish before calling the callback. + * @param {Element | Element[]} elements The element(s) whose animations to wait for. + * @param {() => void} [callback] The function to call when all animations are finished. + * @param {Object} [options] The options to pass to `Element.getAnimations`. + * @returns {Promise} A promise that resolves when all animations are finished. + */ +export function onAnimationEnd(elements, callback, options = { subtree: true }) { + const animations = Array.isArray(elements) + ? elements.flatMap((element) => element.getAnimations(options)) + : elements.getAnimations(options); + const animationPromises = animations.reduce((acc, animation) => { + // Ignore ViewTimeline animations + if (animation.timeline instanceof DocumentTimeline) { + acc.push(animation.finished); + } + + return acc; + }, /** @type {Promise[]} */ ([])); + + return Promise.allSettled(animationPromises).then(callback); +} + +/** + * Check if the click is outside the element. + * @param {MouseEvent} event The mouse event. + * @param {Element} element The element to check. + * @returns {boolean} True if the click is outside the element, false otherwise. + */ +export function isClickedOutside(event, element) { + if (event.target instanceof HTMLDialogElement || !(event.target instanceof Element)) { + return !isPointWithinElement(event.clientX, event.clientY, element); + } + + return !element.contains(event.target); +} + +/** + * Check if a point is within an element. + * @param {number} x The x coordinate of the point. + * @param {number} y The y coordinate of the point. + * @param {Element} element The element to check. + * @returns {boolean} True if the point is within the element, false otherwise. + */ +export function isPointWithinElement(x, y, element) { + const { left, right, top, bottom } = element.getBoundingClientRect(); + + return x >= left && x <= right && y >= top && y <= bottom; +} + +/** + * A media query for large screens + * @type {MediaQueryList} + */ +export const mediaQueryLarge = matchMedia('(min-width: 750px)'); + +/** + * Check if the current breakpoint is mobile + * @returns {boolean} True if the current breakpoint is mobile, false otherwise + */ +export function isMobileBreakpoint() { + return !mediaQueryLarge.matches; +} + +/** + * Check if the current breakpoint is desktop + * @returns {boolean} True if the current breakpoint is desktop, false otherwise + */ +export function isDesktopBreakpoint() { + return mediaQueryLarge.matches; +} + +/** + * Clamps a number between a minimum and maximum value. + * @param {number} value - The input number to clamp. + * @param {number} min - The minimum value. + * @param {number} max - The maximum value. + * @returns {number} The clamped value. + */ +export function clamp(value, min, max) { + return Math.max(min, Math.min(value, max)); +} + +/** + * Calculates the center point of an element along the specified axis. + * @param {Element} element - The DOM element to find the center of. + * @param {'x' | 'y'} [axis] - The axis ('x' or 'y') to get the center for. If not provided, returns both axes. + * @template {('x' | 'y')} T + * @param {T} [axis] + * @returns {T extends ('x' | 'y') ? number : {x: number, y: number}} The center point along the axis or an object with x and y coordinates. + */ +export function center(element, axis) { + const { left, width, top, height } = element.getBoundingClientRect(); + const point = { + x: left + width / 2, + y: top + height / 2, + }; + + if (axis) return /** @type {any} */ (point[axis]); + + return /** @type {any} */ (point); +} + +/** + * Calculates the start point of an element along the specified axis. + * @param {Element} element - The DOM element to find the start of. + * @param {'x' | 'y'} [axis] - The axis ('x' or 'y') to get the start for. If not provided, returns both axes. + * @returns {number | {x: number, y: number}} The start point along the axis or an object with x and y coordinates. + */ +export function start(element, axis) { + const { left, top } = element.getBoundingClientRect(); + const point = { x: left, y: top }; + + if (axis) return /** @type {any} */ (point[axis]); + + return /** @type {any} */ (point); +} + +/** + * Finds the value in an array that is closest to a target value. + * @param {number[]} values - An array of numbers. + * @param {number} target - The target number to find the closest value to. + * @returns {number} The value from the array closest to the target. + */ +export function closest(values, target) { + return values.reduce(function (prev, curr) { + return Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev; + }); +} + +/** + * Prevents the default action of an event. + * @param {Event} event - The event to prevent the default action of. + */ +export function preventDefault(event) { + event.preventDefault(); +} + +/** + * Get the visible elements within a root element. + * @template {Element} T + * @param {Element} root - The element within which elements should be visible. + * @param {T[] | undefined} elements - The elements to check for visibility. + * @param {number} [ratio=1] - The minimum percentage of the element that must be visible. + * @param {'x' | 'y'} [axis] - Whether to only check along 'x' axis, 'y' axis, or both if undefined. + * @returns {T[]} An array containing the visible elements. + */ +export function getVisibleElements(root, elements, ratio = 1, axis) { + if (!elements?.length) return []; + const rootRect = root.getBoundingClientRect(); + + return elements.filter((element) => { + const { width, height, top, right, left, bottom } = element.getBoundingClientRect(); + + if (ratio < 1) { + const intersectionLeft = Math.max(rootRect.left, left); + const intersectionRight = Math.min(rootRect.right, right); + const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft); + + if (axis === 'x') { + return width > 0 && intersectionWidth / width >= ratio; + } + + const intersectionTop = Math.max(rootRect.top, top); + const intersectionBottom = Math.min(rootRect.bottom, bottom); + const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop); + + if (axis === 'y') { + return height > 0 && intersectionHeight / height >= ratio; + } + + const intersectionArea = intersectionWidth * intersectionHeight; + const elementArea = width * height; + + // Check that at least the specified ratio of the element is visible + return elementArea > 0 && intersectionArea / elementArea >= ratio; + } + + const isWithinX = left >= rootRect.left && right <= rootRect.right; + if (axis === 'x') { + return isWithinX; + } + + const isWithinY = top >= rootRect.top && bottom <= rootRect.bottom; + if (axis === 'y') { + return isWithinY; + } + + return isWithinX && isWithinY; + }); +} + +export function getIOSVersion() { + const { userAgent } = navigator; + const isIOS = /(iPhone|iPad)/i.test(userAgent); + + if (!isIOS) return null; + + const version = userAgent.match(/OS ([\d_]+)/)?.[1]; + const [major, minor] = version?.split('_') || []; + if (!version || !major) return null; + + return { + fullString: version.replace('_', '.'), + major: parseInt(major, 10), + minor: minor ? parseInt(minor, 10) : 0, + }; +} + +/** + * Determines which grid items should be animated during a transition. + * It makes an estimation based on the zoom-out card size because it's + * the common denominator for both transition states. I.e. transitioning either + * from 10 to 20 cards the other way around, both need 20 cards to be animated. + * @param {Element} grid - The grid element + * @param {Element[]} cards - The cards to animate + * @returns {number} - Number of cards that should be animated + */ +function getCardsToAnimate(grid, cards) { + if (!grid || !cards || cards.length === 0) return 0; + + const itemSample = cards[0]; + if (!itemSample) return 0; + + // Calculate the visible area of the grid for the Y axis. Assume X is always fully visible: + const gridRect = grid.getBoundingClientRect(); + const visibleArea = { + top: Math.max(0, gridRect.top), + bottom: Math.min(window.innerHeight, gridRect.bottom), + }; + + const visibleHeight = Math.round(visibleArea.bottom - visibleArea.top); + if (visibleHeight <= 0) return 0; + + /** @type {import('product-card').ProductCard | null} */ + const cardSample = itemSample.querySelector('product-card'); + const gridStyle = getComputedStyle(grid); + + const galleryAspectRatio = cardSample?.refs?.cardGallery?.style.getPropertyValue('--gallery-aspect-ratio') || ''; + let aspectRatio = parseFloat(galleryAspectRatio) || 0.5; + if (galleryAspectRatio?.includes('/')) { + const [width = '1', height = '2'] = galleryAspectRatio.split('/'); + aspectRatio = parseInt(width, 10) / parseInt(height, 10); + } + + const cardGap = parseInt(cardSample?.refs?.productCardLink?.style.getPropertyValue('--product-card-gap') || '') || 12; + const gridGap = parseInt(gridStyle.getPropertyValue('--product-grid-gap')) || 12; + + // Assume only a couple of lines of text in the card details (title and price). + // If the title wraps into more lines, we might just animate more cards, but that's fine. + const detailsSize = ((parseInt(gridStyle.fontSize) || 16) + 2) * 2; + + const isMobile = window.innerWidth < 750; + + // Always use the zoom-out state card width + const cardWidth = isMobile ? Math.round((gridRect.width - gridGap) / 2) : 100; + const cardHeight = Math.round(cardWidth / aspectRatio) + cardGap + detailsSize; + + // Calculate the number of cards that fit in the visible area: + // - The width estimation is pretty accurate, we can ignore decimals. + // - The height estimation needs to account for peeking rows, so we round up. + const columnsInGrid = isMobile ? 2 : Math.floor((gridRect.width + gridGap) / (cardWidth + gridGap)); + const rowsInGrid = Math.ceil((visibleHeight - gridGap) / (cardHeight + gridGap)); + + return columnsInGrid * rowsInGrid; +} + +/** + * Preloads an image + * @param {string} src - The source of the image to preload + */ +export function preloadImage(src) { + const image = new Image(); + image.src = src; +} + +export class TextComponent extends HTMLElement { + shimmer() { + this.setAttribute('shimmer', ''); + } +} + +if (!customElements.get('text-component')) { + customElements.define('text-component', TextComponent); +} + +/** + * Resets the shimmer attribute on all elements in the container. + * @param {Element} [container] - The container to reset the shimmer attribute on. + */ +export function resetShimmer(container = document.body) { + const shimmer = container.querySelectorAll('[shimmer]'); + shimmer.forEach((item) => item.removeAttribute('shimmer')); +} + +/** + * Change the meta theme color of the header. + * @param {Element} colorSourceElement - The HTML element whose background-color will determine the new theme-color. + */ +export function changeMetaThemeColor(colorSourceElement) { + const metaThemeColor = document.head.querySelector('meta[name="theme-color"]'); + const containerStyle = window.getComputedStyle(colorSourceElement); + if (metaThemeColor) metaThemeColor.setAttribute('content', containerStyle.backgroundColor); +} + +class Scheduler { + /** @type {Set<() => void>} */ + #queue = new Set(); + /** @type {boolean} */ + #scheduled = false; + + /** @param {() => void} task */ + schedule = async (task) => { + this.#queue.add(task); + + if (!this.#scheduled) { + this.#scheduled = true; + + // Wait for any in-progress view transitions to finish + if (viewTransition.current) await viewTransition.current; + + requestAnimationFrame(this.flush); + } + }; + + flush = () => { + for (const task of this.#queue) { + task(); + } + + this.#queue.clear(); + this.#scheduled = false; + }; +} + +export const scheduler = new Scheduler(); + +Theme.utilities = { + ...Theme.utilities, + scheduler: scheduler, +}; diff --git a/assets/variant-picker.js b/assets/variant-picker.js new file mode 100644 index 000000000..071b97d80 --- /dev/null +++ b/assets/variant-picker.js @@ -0,0 +1,296 @@ +import { Component } from '@theme/component'; +import { VariantSelectedEvent, VariantUpdateEvent } from '@theme/events'; +import { morph } from '@theme/morph'; +import { requestYieldCallback } from '@theme/utilities'; + +/** + * A custom element that manages a variant picker. + * + * @template {import('@theme/component').Refs} [Refs = {}] + * + * @extends Component + */ +export default class VariantPicker extends Component { + /** @type {string | undefined} */ + #pendingRequestUrl; + + /** @type {AbortController | undefined} */ + #abortController; + + connectedCallback() { + super.connectedCallback(); + + this.addEventListener('change', this.variantChanged.bind(this)); + } + + /** + * Handles the variant change event. + * @param {Event} event - The variant change event. + */ + variantChanged(event) { + if (!(event.target instanceof HTMLElement)) return; + + this.updateSelectedOption(event.target); + this.dispatchEvent(new VariantSelectedEvent({ id: event.target.dataset.optionValueId ?? '' })); + + const isOnProductPage = + this.dataset.templateProductMatch === 'true' && + !event.target.closest('product-card') && + !event.target.closest('quick-add-dialog'); + + // Morph the entire main content for combined listings child products, because changing the product + // might also change other sections depending on recommendations, metafields, etc. + const currentUrl = this.dataset.productUrl?.split('?')[0]; + const newUrl = event.target.dataset.connectedProductUrl; + const loadsNewProduct = isOnProductPage && !!newUrl && newUrl !== currentUrl; + + this.fetchUpdatedSection(this.buildRequestUrl(event.target), loadsNewProduct); + + const url = new URL(window.location.href); + + let variantId; + + if (event.target instanceof HTMLInputElement && event.target.type === 'radio') { + variantId = event.target.dataset.variantId || null; + } else if (event.target instanceof HTMLSelectElement) { + const selectedOption = event.target.options[event.target.selectedIndex]; + variantId = selectedOption?.dataset.variantId || null; + } + + if (isOnProductPage) { + if (variantId) { + url.searchParams.set('variant', variantId); + } else { + url.searchParams.delete('variant'); + } + } + + // Change the path if the option is connected to another product via combined listing. + if (loadsNewProduct) { + url.pathname = newUrl; + } + + if (url.href !== window.location.href) { + requestYieldCallback(() => { + history.replaceState({}, '', url.toString()); + }); + } + } + + /** + * Updates the selected option. + * @param {string | Element} target - The target element. + */ + updateSelectedOption(target) { + if (typeof target === 'string') { + const targetElement = this.querySelector(`[data-option-value-id="${target}"]`); + + if (!targetElement) throw new Error('Target element not found'); + + target = targetElement; + } + + if (target instanceof HTMLInputElement) { + target.checked = true; + } + + if (target instanceof HTMLSelectElement) { + const newValue = target.value; + const newSelectedOption = Array.from(target.options).find((option) => option.value === newValue); + + if (!newSelectedOption) throw new Error('Option not found'); + + for (const option of target.options) { + option.removeAttribute('selected'); + } + + newSelectedOption.setAttribute('selected', 'selected'); + } + } + + /** + * Builds the request URL. + * @param {HTMLElement} selectedOption - The selected option. + * @param {string | null} [source] - The source. + * @param {string[]} [sourceSelectedOptionsValues] - The source selected options values. + * @returns {string} The request URL. + */ + buildRequestUrl(selectedOption, source = null, sourceSelectedOptionsValues = []) { + // this productUrl and pendingRequestUrl will be useful for the support of combined listing. It is used when a user changes variant quickly and those products are using separate URLs (combined listing). + // We create a new URL and abort the previous fetch request if it's still pending. + let productUrl = selectedOption.dataset.connectedProductUrl || this.#pendingRequestUrl || this.dataset.productUrl; + this.#pendingRequestUrl = productUrl; + const params = []; + + if (this.selectedOptionsValues.length && !source) { + params.push(`option_values=${this.selectedOptionsValues.join(',')}`); + } else if (source === 'product-card') { + if (this.selectedOptionsValues.length) { + params.push(`option_values=${sourceSelectedOptionsValues.join(',')}`); + } else { + params.push(`option_values=${selectedOption.dataset.optionValueId}`); + } + } + + // If variant-picker is a child of quick-add-component or swatches-variant-picker-component, we need to append section_id=section-rendering-product-card to the URL + if (this.closest('quick-add-component') || this.closest('swatches-variant-picker-component')) { + if (productUrl?.includes('?')) { + productUrl = productUrl.split('?')[0]; + } + return `${productUrl}?section_id=section-rendering-product-card&${params.join('&')}`; + } + return `${productUrl}?${params.join('&')}`; + } + + /** + * Fetches the updated section. + * @param {string} requestUrl - The request URL. + * @param {boolean} shouldMorphMain - If the entire main content should be morphed. By default, only the variant picker is morphed. + */ + fetchUpdatedSection(requestUrl, shouldMorphMain = false) { + // We use this to abort the previous fetch request if it's still pending. + this.#abortController?.abort(); + this.#abortController = new AbortController(); + + fetch(requestUrl, { signal: this.#abortController.signal }) + .then((response) => response.text()) + .then((responseText) => { + this.#pendingRequestUrl = undefined; + const html = new DOMParser().parseFromString(responseText, 'text/html'); + // Defer is only useful for the initial rendering of the page. Remove it here. + html.querySelector('overflow-list[defer]')?.removeAttribute('defer'); + + const textContent = html.querySelector(`variant-picker script[type="application/json"]`)?.textContent; + if (!textContent) return; + + if (shouldMorphMain) { + this.updateMain(html); + } else { + const newProduct = this.updateVariantPicker(html); + + // We grab the variant object from the response and dispatch an event with it. + if (this.selectedOptionId) { + this.dispatchEvent( + new VariantUpdateEvent(JSON.parse(textContent), this.selectedOptionId, { + html, + productId: this.dataset.productId ?? '', + newProduct, + }) + ); + } + } + }) + .catch((error) => { + if (error.name === 'AbortError') { + console.warn('Fetch aborted by user'); + } else { + console.error(error); + } + }); + } + + /** + * @typedef {Object} NewProduct + * @property {string} id + * @property {string} url + */ + + /** + * Re-renders the variant picker. + * @param {Document} newHtml - The new HTML. + * @returns {NewProduct | undefined} Information about the new product if it has changed, otherwise undefined. + */ + updateVariantPicker(newHtml) { + /** @type {NewProduct | undefined} */ + let newProduct; + + const newVariantPickerSource = newHtml.querySelector(this.tagName.toLowerCase()); + + if (!newVariantPickerSource) { + throw new Error('No new variant picker source found'); + } + + // For combined listings, the product might have changed, so update the related data attribute. + if (newVariantPickerSource instanceof HTMLElement) { + const newProductId = newVariantPickerSource.dataset.productId; + const newProductUrl = newVariantPickerSource.dataset.productUrl; + + if (newProductId && newProductUrl && this.dataset.productId !== newProductId) { + newProduct = { id: newProductId, url: newProductUrl }; + } + + this.dataset.productId = newProductId; + this.dataset.productUrl = newProductUrl; + } + + morph(this, newVariantPickerSource); + + return newProduct; + } + + /** + * Re-renders the entire main content. + * @param {Document} newHtml - The new HTML. + */ + updateMain(newHtml) { + const main = document.querySelector('main'); + const newMain = newHtml.querySelector('main'); + + if (!main || !newMain) { + throw new Error('No new main source found'); + } + + morph(main, newMain); + } + + /** + * Gets the selected option. + * @returns {HTMLInputElement | HTMLOptionElement | undefined} The selected option. + */ + get selectedOption() { + const selectedOption = this.querySelector('select option[selected], fieldset input:checked'); + + if (!(selectedOption instanceof HTMLInputElement || selectedOption instanceof HTMLOptionElement)) { + return undefined; + } + + return selectedOption; + } + + /** + * Gets the selected option ID. + * @returns {string | undefined} The selected option ID. + */ + get selectedOptionId() { + const { selectedOption } = this; + if (!selectedOption) return undefined; + const { optionValueId } = selectedOption.dataset; + + if (!optionValueId) { + throw new Error('No option value ID found'); + } + + return optionValueId; + } + + /** + * Gets the selected options values. + * @returns {string[]} The selected options values. + */ + get selectedOptionsValues() { + /** @type HTMLElement[] */ + const selectedOptions = Array.from(this.querySelectorAll('select option[selected], fieldset input:checked')); + + return selectedOptions.map((option) => { + const { optionValueId } = option.dataset; + + if (!optionValueId) throw new Error('No option value ID found'); + + return optionValueId; + }); + } +} + +if (!customElements.get('variant-picker')) { + customElements.define('variant-picker', VariantPicker); +} diff --git a/assets/video-background.js b/assets/video-background.js new file mode 100644 index 000000000..959d70a7a --- /dev/null +++ b/assets/video-background.js @@ -0,0 +1,32 @@ +import { Component } from '@theme/component'; + +/** + * A custom element that renders a video background. + * + * @typedef {object} Refs + * @property {HTMLElement[]} videoSources - The video sources. + * @property {HTMLVideoElement} videoElement - The video element. + * + * @extends Component + */ +export class VideoBackgroundComponent extends Component { + requiredRefs = ['videoSources', 'videoElement']; + + connectedCallback() { + super.connectedCallback(); + + const { videoSources, videoElement } = this.refs; + + for (const source of videoSources) { + const { videoSource } = source.dataset; + + if (videoSource) source.setAttribute('src', videoSource); + } + + videoElement.load(); + } +} + +if (!customElements.get('video-background-component')) { + customElements.define('video-background-component', VideoBackgroundComponent); +} diff --git a/assets/view-transitions.js b/assets/view-transitions.js new file mode 100644 index 000000000..c81a570da --- /dev/null +++ b/assets/view-transitions.js @@ -0,0 +1,87 @@ +(function () { + //Remove the view transition render blocker if the user has reduced motion enabled + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { + const viewTransitionRenderBlocker = document.getElementById('view-transition-render-blocker'); + if (viewTransitionRenderBlocker) viewTransitionRenderBlocker.remove(); + } + + const idleCallback = typeof requestIdleCallback === 'function' ? requestIdleCallback : setTimeout; + + /** + * @param {PageSwapEvent} event + */ + window.addEventListener('pageswap', async (event) => { + if (!hasViewTransition(event)) return; + + const { viewTransition } = event; + + // Cancel view transition on user interaction to improve INP (Interaction to Next Paint) + ['pointerdown', 'keydown'].forEach(eventName => { + document.addEventListener(eventName, () => { + viewTransition.skipTransition(); + }, { once: true }); + }); + + // Clean in case you landed on the pdp first. We want to remove the default transition type on the PDP media gallery so there is no duplicate transition name + document + .querySelectorAll('[data-view-transition-type]:not([data-view-transition-triggered])') + .forEach((element) => { + element.removeAttribute('data-view-transition-type'); + }); + + const transitionTriggered = document.querySelector('[data-view-transition-triggered]'); + const transitionType = transitionTriggered?.getAttribute('data-view-transition-type'); + + if (transitionType) { + viewTransition.types.clear(); + viewTransition.types.add(transitionType); + sessionStorage.setItem('custom-transition-type', transitionType); + } else { + viewTransition.types.clear(); + viewTransition.types.add('page-navigation'); + sessionStorage.removeItem('custom-transition-type'); + } + }); + + /** + * @param {PageRevealEvent} event + */ + window.addEventListener('pagereveal', async (event) => { + if (!hasViewTransition(event)) return; + + const { viewTransition } = event; + const customTransitionType = sessionStorage.getItem('custom-transition-type'); + + if (customTransitionType) { + viewTransition.types.clear(); + viewTransition.types.add(customTransitionType); + + await viewTransition.finished; + + viewTransition.types.clear(); + viewTransition.types.add('page-navigation'); + + idleCallback(() => { + sessionStorage.removeItem('custom-transition-type'); + document.querySelectorAll('[data-view-transition-type]').forEach((element) => { + element.removeAttribute('data-view-transition-type'); + }); + }); + } else { + viewTransition.types.clear(); + viewTransition.types.add('page-navigation'); + } + }); + + /** + * Checks whether an Event object is carrying a `viewTransition` property + * (as used by the View Transition API) and narrows the type accordingly. + * + * @template {Event} T + * @param {T} event + * @returns {event is T & { viewTransition: ViewTransition }} + */ + function hasViewTransition(event) { + return 'viewTransition' in event && event.viewTransition instanceof ViewTransition; + } +})(); diff --git a/assets/zoom-dialog.js b/assets/zoom-dialog.js new file mode 100644 index 000000000..af201bac4 --- /dev/null +++ b/assets/zoom-dialog.js @@ -0,0 +1,276 @@ +import { Component } from '@theme/component'; +import { + supportsViewTransitions, + startViewTransition, + onAnimationEnd, + prefersReducedMotion, + debounce, + preloadImage, +} from '@theme/utilities'; +import { scrollIntoView } from '@theme/scrolling'; +import { ZoomMediaSelectedEvent } from '@theme/events'; +import { DialogCloseEvent } from '@theme/dialog'; +/** + * A custom element that renders a zoom dialog. + * + * @typedef {object} Refs + * @property {HTMLDialogElement} dialog - The dialog element. + * @property {HTMLElement[]} media - The media elements. + * @property {HTMLElement} thumbnails - The thumbnails elements. + * + * @extends Component + */ +export class ZoomDialog extends Component { + requiredRefs = ['dialog', 'media', 'thumbnails']; + + #highResImagesLoaded = /** @type {Set} */ (new Set()); + + connectedCallback() { + super.connectedCallback(); + this.refs.dialog.addEventListener('scroll', this.handleScroll); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.refs.dialog.removeEventListener('scroll', this.handleScroll); + } + + /** + * Opens the zoom dialog. + * + * @param {number} index - The index of the media to zoom. + * @param {PointerEvent} event - The pointer event. + */ + async open(index, event) { + event.preventDefault(); + + const { dialog, media, thumbnails } = this.refs; + const targetImage = media[index]; + const targetThumbnail = thumbnails.children[index]; + + const open = () => { + dialog.showModal(); + + for (const target of [targetThumbnail, targetImage]) { + target?.scrollIntoView({ behavior: 'instant' }); + } + }; + + /** @type {HTMLElement | null} */ + const sourceImage = event.target instanceof Element ? event.target.closest('li,slideshow-slide') : null; + + if (!supportsViewTransitions || !sourceImage || !targetImage) return open(); + + const transitionName = `gallery-item`; + sourceImage.style.setProperty('view-transition-name', transitionName); + + await startViewTransition(() => { + open(); + sourceImage.style.removeProperty('view-transition-name'); + targetImage.style.setProperty('view-transition-name', transitionName); + }); + + targetImage.style.removeProperty('view-transition-name'); + + this.selectThumbnail(index, { behavior: 'instant' }); + } + + /** + * Loads a high-resolution image for a specific media container + * @param {HTMLElement} mediaContainer - The media container element + */ + #loadHighResolutionImage(mediaContainer) { + if (!mediaContainer.classList.contains('product-media-container--image')) return false; + + const image = mediaContainer.querySelector('img.product-media__image'); + if (!image || !(image instanceof HTMLImageElement)) return false; + + const highResolutionUrl = image.getAttribute('data_max_resolution'); + if (!highResolutionUrl || this.#highResImagesLoaded.has(highResolutionUrl)) return false; + + preloadImage(highResolutionUrl); + + const newImage = new Image(); + newImage.className = image.className; + newImage.alt = image.alt; + newImage.setAttribute('data_max_resolution', highResolutionUrl); + + // When the high-resolution image loads, replace the existing image + newImage.onload = () => { + image.replaceWith(newImage); + this.#highResImagesLoaded.add(highResolutionUrl); + }; + + newImage.src = highResolutionUrl; + } + + /** + * Handles the scroll event of the dialog, which is used to update the active thumbnail when the corresponding image is visible in the main view. + * @param {Event} event - The scroll event. + */ + handleScroll = debounce(async () => { + const { media, thumbnails } = this.refs; + + const mostVisibleElement = await getMostVisibleElement(media); + const activeIndex = media.indexOf(mostVisibleElement); + const targetThumbnail = thumbnails.children[activeIndex]; + + if (!targetThumbnail || !(targetThumbnail instanceof HTMLElement)) return; + + Array.from(thumbnails.querySelectorAll('button')).forEach((button, i) => { + button.setAttribute('aria-selected', `${i === activeIndex}`); + }); + + this.#loadHighResolutionImage(mostVisibleElement); + this.dispatchEvent(new ZoomMediaSelectedEvent(activeIndex)); + }, 50); + + /** + * Closes the zoom dialog. + */ + async close() { + const { dialog, media } = this.refs; + + if (!supportsViewTransitions) return this.closeDialog(); + + // Find the most visible image using IntersectionObserver + const mostVisibleElement = await getMostVisibleElement(media); + + // Get the index and set up transition + const activeIndex = media.indexOf(mostVisibleElement); + const transitionName = `gallery-item`; + + const mediaGallery = /** @type {import('./media-gallery').MediaGallery | undefined} */ ( + this.closest('media-gallery') + ); + + const slideshowActive = mediaGallery?.presentation === 'carousel'; + + const slide = slideshowActive ? mediaGallery.slideshow?.slides?.[activeIndex] : mediaGallery?.media?.[activeIndex]; + + if (!slide) return this.closeDialog(); + + dialog.classList.add('dialog--closed'); + + await onAnimationEnd(this.refs.thumbnails); + + mostVisibleElement.style.setProperty('view-transition-name', transitionName); + + await startViewTransition(() => { + mostVisibleElement.style.removeProperty('view-transition-name'); + slide.style.setProperty('view-transition-name', transitionName); + this.closeDialog(); + }); + + slide.style.removeProperty('view-transition-name'); + dialog.classList.remove('dialog--closed'); + } + + closeDialog() { + const { dialog } = this.refs; + dialog.close(); + window.dispatchEvent(new DialogCloseEvent()); + } + + /** + * Closes the dialog when the user presses the escape key. + * + * @param {KeyboardEvent} event - The keyboard event. + */ + handleKeyDown(event) { + if (event.key !== 'Escape') return; + + event.preventDefault(); + this.close(); + } + + /** + * Handles the click event of a thumbnail. + * @param {number} index - The index of the thumbnail to select. + */ + async handleThumbnailClick(index) { + const behavior = prefersReducedMotion() ? 'instant' : 'smooth'; + this.selectThumbnail(index, { behavior }); + } + + /** + * Handles the pointer enter event of a thumbnail. + * @param {number} index - The index of the thumbnail to load the high-resolution image for. + */ + async handleThumbnailPointerEnter(index) { + const { media } = this.refs; + if (!media[index]) return; + + this.#loadHighResolutionImage(media[index]); + } + + /** + * Handles the selection of a thumbnail. + * @param {number} index - The index of the thumbnail to select. + * @param {Object} options - The options for the selection. + * @param {ScrollBehavior} options.behavior - The behavior of the scroll. + */ + async selectThumbnail(index, options = { behavior: 'smooth' }) { + if (!this.refs.thumbnails || !this.refs.thumbnails.children.length) return; + + // Guard if invalid + if (isNaN(index) || index < 0 || index >= this.refs.thumbnails.children.length) return; + + const { media, thumbnails } = this.refs; + const targetThumbnail = thumbnails.children[index]; + + if (!targetThumbnail || !(targetThumbnail instanceof HTMLElement)) return; + + Array.from(thumbnails.querySelectorAll('button')).forEach((button, i) => { + button.setAttribute('aria-selected', `${i === index}`); + }); + + scrollIntoView(targetThumbnail, { + ancestor: thumbnails, + behavior: options.behavior, + block: 'center', + inline: 'center', + }); + + const targetImage = media[index]; + + if (targetImage) { + targetImage.scrollIntoView({ + behavior: options.behavior, + }); + + this.#loadHighResolutionImage(targetImage); + } + this.dispatchEvent(new ZoomMediaSelectedEvent(index)); + } +} + +if (!customElements.get('zoom-dialog')) { + customElements.define('zoom-dialog', ZoomDialog); +} + +/** + * Get the most visible element from a list of elements. + * @param {HTMLElement[]} elements - The elements to get the most visible element from. + * @returns {Promise} A promise that resolves to the most visible element. + */ +function getMostVisibleElement(elements) { + return new Promise((resolve) => { + const observer = new IntersectionObserver( + (entries) => { + const mostVisible = entries.reduce((prev, current) => + current.intersectionRatio > prev.intersectionRatio ? current : prev + ); + observer.disconnect(); + resolve(/** @type {HTMLElement} */ (mostVisible.target)); + }, + { + threshold: Array.from({ length: 100 }, (_, i) => i / 100), + } + ); + + for (const element of elements) { + observer.observe(element); + } + }); +} diff --git a/blocks/_accordion-row.liquid b/blocks/_accordion-row.liquid new file mode 100644 index 000000000..a55cf7a1d --- /dev/null +++ b/blocks/_accordion-row.liquid @@ -0,0 +1,351 @@ +{% # import schema from '../schemas/blocks/_accordion-row.js' %} + + +
+ + {% render 'icon-or-image', + icon: block.settings.icon, + image_upload: block.settings.image_upload, + width: block.settings.width, + class_name: 'details__icon' + %} + {{ block.settings.heading }} + + {{- 'icon-caret.svg' | inline_asset_content -}} + + + {{- 'icon-plus.svg' | inline_asset_content -}} + + + +
+ {% content_for 'blocks' %} +
+
+
+ +{% stylesheet %} + .details__icon { + height: auto; + margin-inline-end: var(--margin-xs); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.accordion_row", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "text", + "id": "heading", + "label": "t:settings.heading", + "default": "t:text_defaults.accordion_heading" + }, + { + "type": "checkbox", + "id": "open_by_default", + "label": "t:settings.open_row_by_default", + "default": false + }, + { + "type": "header", + "content": "t:content.icon" + }, + { + "type": "select", + "id": "icon", + "label": "t:settings.icon", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "apple", + "label": "t:options.apple" + }, + { + "value": "arrow", + "label": "t:options.arrow" + }, + { + "value": "banana", + "label": "t:options.banana" + }, + { + "value": "bottle", + "label": "t:options.bottle" + }, + { + "value": "box", + "label": "t:options.box" + }, + { + "value": "carrot", + "label": "t:options.carrot" + }, + { + "value": "chat_bubble", + "label": "t:options.chat_bubble" + }, + { + "value": "check_box", + "label": "t:options.check_box" + }, + { + "value": "clipboard", + "label": "t:options.clipboard" + }, + { + "value": "dairy", + "label": "t:options.dairy" + }, + { + "value": "dairy_free", + "label": "t:options.dairy_free" + }, + { + "value": "dryer", + "label": "t:options.dryer" + }, + { + "value": "eye", + "label": "t:options.eye" + }, + { + "value": "fire", + "label": "t:options.fire" + }, + { + "value": "gluten_free", + "label": "t:options.gluten_free" + }, + { + "value": "heart", + "label": "t:options.heart" + }, + { + "value": "iron", + "label": "t:options.iron" + }, + { + "value": "leaf", + "label": "t:options.leaf" + }, + { + "value": "leather", + "label": "t:options.leather" + }, + { + "value": "lightning_bolt", + "label": "t:options.lightning_bolt" + }, + { + "value": "lipstick", + "label": "t:options.lipstick" + }, + { + "value": "lock", + "label": "t:options.lock" + }, + { + "value": "map_pin", + "label": "t:options.map_pin" + }, + { + "value": "nut_free", + "label": "t:options.nut_free" + }, + { + "value": "pants", + "label": "t:options.pants" + }, + { + "value": "paw_print", + "label": "t:options.paw_print" + }, + { + "value": "pepper", + "label": "t:options.pepper" + }, + { + "value": "perfume", + "label": "t:options.perfume" + }, + { + "value": "plane", + "label": "t:options.plane" + }, + { + "value": "plant", + "label": "t:options.plant" + }, + { + "value": "price_tag", + "label": "t:options.price_tag" + }, + { + "value": "question_mark", + "label": "t:options.question_mark" + }, + { + "value": "recycle", + "label": "t:options.recycle" + }, + { + "value": "return", + "label": "t:options.return" + }, + { + "value": "ruler", + "label": "t:options.ruler" + }, + { + "value": "serving_dish", + "label": "t:options.serving_dish" + }, + { + "value": "shirt", + "label": "t:options.shirt" + }, + { + "value": "shoe", + "label": "t:options.shoe" + }, + { + "value": "silhouette", + "label": "t:options.silhouette" + }, + { + "value": "bluesky", + "label": "t:options.social_bluesky" + }, + { + "value": "facebook", + "label": "t:options.social_facebook" + }, + { + "value": "instagram", + "label": "t:options.social_instagram" + }, + { + "value": "linkedin", + "label": "t:options.social_linkedin" + }, + { + "value": "pinterest", + "label": "t:options.social_pinterest" + }, + { + "value": "snapchat", + "label": "t:options.social_snapchat" + }, + { + "value": "spotify", + "label": "t:options.social_spotify" + }, + { + "value": "threads", + "label": "t:options.social_threads" + }, + { + "value": "tiktok", + "label": "t:options.social_tiktok" + }, + { + "value": "tumblr", + "label": "t:options.social_tumblr" + }, + { + "value": "twitter", + "label": "t:options.social_twitter" + }, + { + "value": "vimeo", + "label": "t:options.social_vimeo" + }, + { + "value": "youtube", + "label": "t:options.social_youtube" + }, + { + "value": "whatsapp", + "label": "t:options.social_whatsapp" + }, + { + "value": "snowflake", + "label": "t:options.snowflake" + }, + { + "value": "star", + "label": "t:options.star" + }, + { + "value": "stopwatch", + "label": "t:options.stopwatch" + }, + { + "value": "truck", + "label": "t:options.truck" + }, + { + "value": "washing", + "label": "t:options.washing" + } + ], + "default": "none" + }, + { + "type": "image_picker", + "id": "image_upload", + "label": "t:settings.image_icon" + }, + { + "type": "range", + "id": "width", + "label": "t:settings.width", + "min": 12, + "max": 200, + "step": 2, + "unit": "px", + "default": 20 + } + ], + "presets": [ + { + "name": "t:names.accordion_row", + "blocks": { + "text-1": { + "type": "text", + "settings": { + "text": "

We will work quickly to ship your order as soon as possible. Once your order has shipped, you will receive an email with further information. Delivery times vary depending on your location.

", + "width": "100%" + } + } + }, + "block_order": ["text-1"], + "settings": { + "heading": "When will I get my order?" + } + } + ] +} +{% endschema %} diff --git a/blocks/_announcement.liquid b/blocks/_announcement.liquid new file mode 100644 index 000000000..8c922fd8f --- /dev/null +++ b/blocks/_announcement.liquid @@ -0,0 +1,330 @@ +{% # import schema from '../schemas/blocks/_announcement' %} + +{% assign plain_text = block.settings.text | strip_newlines | strip_html | strip %} +{%- assign block_index = section.blocks | find_index: 'id', block.id -%} + +{%- unless plain_text == '' -%} + +

+ {{ block.settings.text }} +

+ + {% if block.settings.link != blank %} + + + {{ block.settings.text | strip_html }} + + + {% endif %} +
+{%- endunless -%} + +{% stylesheet %} + .text-block { + width: var(--width); + max-width: 100%; + } + + .text-block > * { + width: var(--width); + max-width: var(--max-width, 100%); + text-align: var(--text-align); + } + + .text-block:not(.text-block--full-width).rte, + .text-block:not(.text-block--full-width).paragraph { + /* Safari doesn't support pretty, so fallback to balance */ + text-wrap: balance; + text-wrap: pretty; + } + + .text-block:not(.text-block--full-width).h1, + .text-block:not(.text-block--full-width).h2, + .text-block:not(.text-block--full-width).h3, + .text-block:not(.text-block--full-width).h4, + .text-block:not(.text-block--full-width).h5, + .text-block:not(.text-block--full-width).h6 { + text-wrap: balance; + } + + /* Hide underline unless text is using paragraph styles. */ + .text-block:is(.h1, .h2, .h3, .h4, .h5, .h6) a { + text-decoration-color: transparent; + } + + .text-block h1, + .text-block.h1 > * { + margin-block: var(--font-h1--spacing); + } + + .text-block h2, + .text-block.h2 > * { + margin-block: var(--font-h2--spacing); + } + + .text-block h3, + .text-block.h3 > * { + margin-block: var(--font-h3--spacing); + } + + .text-block h4, + .text-block.h4 > * { + margin-block: var(--font-h4--spacing); + } + + .text-block h5, + .text-block.h5 > * { + margin-block: var(--font-h5--spacing); + } + + .text-block h6, + .text-block.h6 > * { + margin-block: var(--font-h6--spacing); + } + + .text-block > *:first-child { + margin-block-start: 0; + } + + .text-block > *:last-child { + margin-block-end: 0; + } + + .text-block--align-center, + .text-block--align-center > * { + margin-inline: auto; + } + + .text-block--align-right, + .text-block--align-right > * { + margin-inline-start: auto; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.announcement", + "tag": null, + "settings": [ + { + "type": "inline_richtext", + "id": "text", + "label": "t:settings.text", + "default": "t:text_defaults.shop_our_latest_arrivals" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem" + }, + { + "type": "select", + "id": "weight", + "label": "t:settings.weight", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "100", + "label": "t:options.thin" + }, + { + "value": "300", + "label": "t:options.light" + }, + { + "value": "400", + "label": "t:options.regular" + }, + { + "value": "500", + "label": "t:options.medium" + }, + { + "value": "600", + "label": "t:options.semibold" + }, + { + "value": "700", + "label": "t:options.bold" + }, + { + "value": "900", + "label": "t:options.black" + } + ], + "default": "" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ], + "presets": [ + { + "name": "t:names.announcement" + } + ] +} +{% endschema %} diff --git a/blocks/_blog-post-card.liquid b/blocks/_blog-post-card.liquid new file mode 100644 index 000000000..806496bb6 --- /dev/null +++ b/blocks/_blog-post-card.liquid @@ -0,0 +1,118 @@ +{% # import schema from '../schemas/blocks/_blog-post-card' %} + +{% capture title %} + {% content_for 'block', id: 'heading', type: '_heading', text: article.title %} +{% endcapture %} + +{% capture details %} + {% content_for 'block', + id: 'blog-post-details', + type: '_blog-post-info-text', + alignment: block.settings.alignment, + article: article + %} +{% endcapture %} + +{% capture description %} + {% content_for 'block', id: 'content', type: '_blog-post-description', article: article %} +{% endcapture %} + +
+ {%- if article.image -%} +
+ + {% content_for 'block', id: 'image', type: '_blog-post-image', image: article.image %} + +
+ {%- endif -%} + +
+ {{ title }} + + {{ details }} + + {{ description }} +
+
+ +{% stylesheet %} + .blog-post-card { + display: flex; + flex-direction: column; + text-align: var(--text-align); + } + + .blog-post-item .blog-post-card__image-container, + .blog-post-item .blog-post-card__content { + width: 100%; + } + + .blog-post-item:first-child .blog-post-card { + flex-direction: row; + + @media screen and (max-width: 749px) { + flex-direction: column; + } + } + + .blog-post-item:first-child .blog-post-card__image-container { + width: 70%; + + @media screen and (max-width: 749px) { + width: 100%; + } + } + + .blog-post-item:first-child:has(.blog-post-card__image-container) .blog-post-card__content { + padding-inline-start: var(--columns-gap); + width: 30%; + + @media screen and (max-width: 749px) { + padding-inline-start: 0; + width: 100%; + } + } + + .blog-post-card__content { + padding-block-start: 0.4rem; + display: flex; + flex-direction: column; + } + + .blog-post-card__content a { + display: block; + text-wrap: pretty; + text-decoration: none; + padding-block-start: 0.75rem; + } + + .blog-post-card__content a:hover, + .blog-post-card__content a:hover [style*='--color: var(--color-primary)'] { + color: var(--color-primary-hover); + } + + .blog-post-card__content a:hover [style*='--color: var(--color-foreground-heading)'] { + color: rgb(var(--color-foreground-heading-rgb) / var(--opacity-subdued-text)); + } + + .blog-post-card__content a:hover [style*='--color: var(--color-foreground)'] { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.blog_post", + "settings": [ + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left" + } + ] +} +{% endschema %} diff --git a/blocks/_blog-post-content.liquid b/blocks/_blog-post-content.liquid new file mode 100644 index 000000000..d2041aa3c --- /dev/null +++ b/blocks/_blog-post-content.liquid @@ -0,0 +1,26 @@ +{% # import schema from '../schemas/blocks/_blog-post-content' %} + +
+ + {{ article.content }} + +
+ +{% stylesheet %} + .blog-post-content { + max-width: var(--normal-content-width); + margin: 0 auto; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.content", + "settings": [], + "presets": [ + { + "name": "t:names.content" + } + ] +} +{% endschema %} diff --git a/blocks/_blog-post-description.liquid b/blocks/_blog-post-description.liquid new file mode 100644 index 000000000..a1d21d6d4 --- /dev/null +++ b/blocks/_blog-post-description.liquid @@ -0,0 +1,356 @@ +{% liquid + assign content = article.excerpt | default: article.content + + if block.settings.type_preset == 'rte' or block.settings.type_preset == 'paragraph' + assign is_rte = true + endif + + capture text_block_classes + if block.settings.type_preset == 'custom' + echo ' custom-typography ' + if block.settings.font_size != '' + echo ' custom-font-size ' + endif + if block.settings.color != '' + echo ' custom-color ' + endif + endif + if is_rte + echo ' rte ' + endif + endcapture +%} + +{% capture attributes %} + class="blog-post-card__content-text spacing-style text-block text-block--{{ block.id }} {{ block.settings.type_preset }} + {{ text_block_classes }} + " + + style=" + {% render 'spacing-padding', settings: block.settings %} + {% render 'typography-style', settings: block.settings %} + {% if block.settings.color != '' %} + --color: {{ block.settings.color }}; + {% endif %} + " + + {{ block.shopify_attributes }} +{% endcapture %} + +{% if content %} + {% assign truncatewords = 30 %} + {% unless article.image %} + {% assign truncatewords = 90 %} + {% endunless %} + + {% liquid + assign element = 'div' + if is_rte + assign element = 'rte-formatter' + endif + %} + + <{{ element }} {{ attributes }}> + {{ content | strip_html | truncatewords: truncatewords }} + {{ 'content.read_more' | t }} + +{% endif %} + +{% stylesheet %} + .blog-post-card__content-text a { + color: var(--color-primary); + } + + .custom-color, + .custom-color > :is(h1, h2, h3, h4, h5, h6, p, *) { + color: var(--color); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.description", + "settings": [ + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.description" + } + ] +} +{% endschema %} diff --git a/blocks/_blog-post-image.liquid b/blocks/_blog-post-image.liquid new file mode 100644 index 000000000..d4255d2f0 --- /dev/null +++ b/blocks/_blog-post-image.liquid @@ -0,0 +1,127 @@ +{% # import schema from '../schemas/blocks/_blog-post-image' %} + +{%- doc -%} + Renders the blog post image block. + + @param {object} image - The image object +{%- enddoc -%} + +{{ image.alt | escape }} + +{% stylesheet %} + .blog-post-card__image { + width: 100%; + object-fit: cover; + object-position: center center; + height: calc(var(--blog-post-card-img-height) * var(--blog-post-card-scale)); + } + + .blog-post-card__image--small { + --blog-post-card-img-height: 280px; + } + + .blog-post-card__image--medium { + --blog-post-card-img-height: 340px; + } + + .blog-post-card__image--large { + --blog-post-card-img-height: 400px; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.image", + "blocks": [], + "settings": [ + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + } + ], + "default": "large" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.border", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.corner_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_blog-post-info-text.liquid b/blocks/_blog-post-info-text.liquid new file mode 100644 index 000000000..b3667ca8a --- /dev/null +++ b/blocks/_blog-post-info-text.liquid @@ -0,0 +1,155 @@ +{% # import schema from '../schemas/blocks/_blog-post-info-text' %} +{%- doc -%} + Renders the blog post info text block. + + @param {object} [article] - The article object + @param {string} [alignment] - The alignment of the text. Defaults to the block's alignment setting. +{%- enddoc -%} + +{% assign alignment = alignment | default: block.settings.alignment %} + +{%- if block.settings.show_date or block.settings.show_author -%} +
+ {%- if block.settings.show_date -%} + {{- article.published_at | time_tag: format: 'date' -}} + {%- endif -%} + + {%- if block.settings.show_date and block.settings.show_author -%} + {{ 'content.blog_details_separator' | t }} + {%- endif -%} + + {%- if block.settings.show_author -%} + {{ article.author }} + {%- endif -%} +
+{% endif %} + +{% stylesheet %} + .blog-post-details { + display: flex; + gap: var(--gap-sm); + font-size: var(--font-size--paragraph); + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + white-space: nowrap; + } + + .blog-post-details > span { + text-overflow: clip; + overflow: hidden; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.details", + "settings": [ + { + "type": "checkbox", + "id": "show_date", + "label": "t:settings.show_date", + "default": true + }, + { + "type": "checkbox", + "id": "show_author", + "label": "t:settings.show_author", + "default": true + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "visible_if": "{{ block.settings.show_alignment != false }}" + }, + { + "type": "checkbox", + "id": "show_alignment", + "label": "t:settings.show_alignment", + "default": true, + "visible_if": "{{ false }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.details" + } + ] +} +{% endschema %} diff --git a/blocks/_cart-products.liquid b/blocks/_cart-products.liquid new file mode 100644 index 000000000..9ee47a7a3 --- /dev/null +++ b/blocks/_cart-products.liquid @@ -0,0 +1,117 @@ +{% # import schema from '../schemas/blocks/_cart-products.js' %} + +{% render 'cart-products' %} + +{% stylesheet %} + .cart-page--empty .cart-items__wrapper { + display: flex; + flex-direction: column; + align-items: center; + margin-block-start: 0; + text-align: center; + } + + .cart-page__title + .cart-page__items { + margin-block-start: var(--margin-lg); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.cart_products", + "tag": null, + "settings": [ + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 8, + "max": 36, + "step": 4, + "unit": "px", + "default": 24 + }, + { + "type": "select", + "id": "image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "adapt", + "label": "t:settings.aspect_ratio" + }, + { + "type": "checkbox", + "id": "dividers", + "label": "t:settings.dividers", + "default": true + }, + { + "type": "checkbox", + "id": "vendor", + "label": "t:settings.vendor", + "default": false + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.cart_items" + } + ] +} +{% endschema %} diff --git a/blocks/_cart-summary.liquid b/blocks/_cart-summary.liquid new file mode 100644 index 000000000..db64a1d28 --- /dev/null +++ b/blocks/_cart-summary.liquid @@ -0,0 +1,249 @@ +{% # import schema from '../schemas/blocks/_cart-summary.js' %} + +{%- capture cart_summary_inner_class -%} + cart__summary-inner + {% if block.settings.extend_summary == false and block.settings.inherit_color_scheme == false -%} + color-{{ block.settings.color_scheme }} inherit-parent-scheme--mobile + {%- endif %} + {% if block.settings.extend_summary == false and block.settings.border_radius > 0 -%} + has-border-radius + {%- endif -%} +{%- endcapture -%} + +{% if block.settings.extend_summary %} +
+{% endif %} +
+
+ {% render 'cart-summary' %} +
+
+ +{% stylesheet %} + .cart__summary-item { + display: flex; + align-items: center; + justify-content: space-between; + } + + .cart__summary-item.tax-note { + font-size: var(--cart-font-size--sm); + } + + .cart__discount-label { + display: flex; + align-items: center; + gap: var(--gap-2xs); + } + + .cart__total { + align-items: baseline; + font-weight: var(--font-weight-bold); + } + + .cart__tax-note { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .cart__discount-label svg { + width: var(--icon-size-sm); + height: var(--icon-size-sm); + display: inline-block; + } + + .cart__summary-inner { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--gap-2xl); + container-type: inline-size; + padding: 0; + position: sticky; + top: 0; + align-self: start; + + @media screen and (min-width: 750px) { + padding: var(--padding-5xl); + grid-row: 1 / -1; + } + } + + body:has(> #header-group .header[sticky]) .cart__summary-inner { + top: var(--header-height, 0); + } + + .cart__summary-container { + @media screen and (max-width: 749px) { + border: none; + } + + @media screen and (min-width: 750px) { + display: grid; + grid-template-rows: subgrid; + grid-row: 1 / -1; + } + } + + .cart__summary-container:not(.cart__container--extend), + .cart__summary-container:not(.cart__container--extend) .cart__summary-inner { + height: auto; + } + + .cart__container--extend { + height: 100%; + + @media screen and (min-width: 750px) { + border-right: none; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + } + + /* If extend is on, only include top and bottom borders when the border radius is 0. */ + .cart__container--extend:not(.has-border-radius) { + @media screen and (min-width: 750px) { + border-top: none; + border-bottom: none; + } + } + + .cart__container--extend .cart__summary-inner { + height: 100%; + padding: var(--padding-md) 0 var(--padding-4xl); + + @media screen and (min-width: 750px) { + grid-row: 2 / -1; + padding-inline: var(--page-margin); + width: var(--sidebar-width); + } + } + + /* If extend is off, apply the border radius to the inner summary container */ + .cart__summary-inner.has-border-radius { + border-radius: var(--border-radius); + } + + @media screen and (max-width: 749px) { + .inherit-parent-scheme--mobile { + --color-background: inherit; + --color-background-rgb: inherit; + --color-foreground: inherit; + --color-foreground-rgb: inherit; + --color-primary: inherit; + --color-primary-rgb: inherit; + --color-primary-hover: inherit; + --color-primary-hover-rgb: inherit; + --color-border: inherit; + --color-border-rgb: inherit; + --color-shadow: inherit; + --color-shadow-rgb: inherit; + --color-foreground-heading: inherit; + --color-primary-button-text: inherit; + --color-primary-button-background: inherit; + --color-primary-button-border: inherit; + --color-primary-button-hover-text: inherit; + --color-primary-button-hover-background: inherit; + --color-primary-button-hover-border: inherit; + --color-secondary-button-text: inherit; + --color-secondary-button-background: inherit; + --color-secondary-button-border: inherit; + --color-secondary-button-hover-text: inherit; + --color-secondary-button-hover-background: inherit; + --color-secondary-button-hover-border: inherit; + --color-input-text: inherit; + --color-input-text-rgb: inherit; + --color-input-background: inherit; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.summary", + "tag": null, + "settings": [ + { + "type": "checkbox", + "id": "extend_summary", + "label": "t:settings.extend_summary", + "default": true + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": false + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-3", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.summary" + } + ] +} +{% endschema %} diff --git a/blocks/_cart-title.liquid b/blocks/_cart-title.liquid new file mode 100644 index 000000000..6f27e551d --- /dev/null +++ b/blocks/_cart-title.liquid @@ -0,0 +1,171 @@ +{% # import schema from '../schemas/blocks/_cart-title' %} + +
+

+ {%- if cart.empty? -%} + {{ 'content.your_cart_is_empty' | t }} + {%- else -%} + {{ block.settings.title }} + {%- if block.settings.show_count -%}{% render 'cart-bubble' %}{%- endif -%} + {%- endif -%} +

+
+ +{% stylesheet %} + .cart-title h1 { + margin-block-end: 0; + display: inline-flex; + align-items: center; + gap: var(--gap-sm); + } + + .cart-title .cart-bubble { + width: fit-content; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--style-border-radius-buttons-primary); + aspect-ratio: auto; + padding: var(--cart-padding); + } + + .cart-title .cart-bubble[data-maintain-ratio] { + aspect-ratio: 1; + min-width: 26px; + } + + .cart-title .cart-bubble__background { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10-25)); + } + + .cart-title .cart-bubble__text { + color: var(--color-foreground); + font-family: var(--font-paragraph--family); + font-size: clamp(var(--cart-font-size--2xs), 0.7lh, var(--cart-font-size--xs)); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.title", + "tag": null, + "settings": [ + { + "type": "inline_richtext", + "id": "title", + "label": "t:settings.cart_title", + "default": "Cart" + }, + { + "type": "checkbox", + "id": "show_count", + "label": "t:settings.cart_count", + "default": true + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.title" + } + ] +} +{% endschema %} diff --git a/blocks/_collection-card-image.liquid b/blocks/_collection-card-image.liquid new file mode 100644 index 000000000..ff3e52cf9 --- /dev/null +++ b/blocks/_collection-card-image.liquid @@ -0,0 +1,267 @@ +{% # import schema from '../schemas/blocks/_collection-card-image' %} + +{%- doc -%} + Display an image of a collection inside a collection card. + Intended for collection-card.liquid block. + + @param {string} parent_block_id - The block.id of the collection-card block + + @example + {% content_for 'block', type: '_collection-card-image', id: 'collection-card-image', parent_block_id: block.id %} +{%- enddoc -%} + +{% liquid + assign collection = closest.collection +-%} + +{% liquid + assign image_source = collection.image + if image_source == blank + assign image_source = collection.products.first.featured_image + endif + + assign ratio = 1 + + case block.settings.image_ratio + when 'landscape' + assign ratio = '16 / 9' + when 'portrait' + assign ratio = '4 / 5' + when 'adapt' + assign ratio = image_source.aspect_ratio + endcase + + if ratio == 0 or ratio == null + assign ratio = 1 + endif +%} + +{% liquid + assign sizes = '(min-width: 750px) 50vw, 100vw' + assign lazy_sizes = 'auto, ' | append: sizes + assign loading = 'eager' + + # when _collection-card-image is inside a Collection List section, specific layout types + # can determine the `sizes` and `loading` attributes + + case section.settings.layout_type + when 'grid', 'carousel' + assign calculated_width = 100 | divided_by: section.settings.columns | append: 'vw' + assign sizes = '(min-width: 750px) [calc-width], 100vw' | replace: '[calc-width]', calculated_width + when 'editorial', 'bento' + assign loading = 'lazy' + assign sizes = lazy_sizes + endcase + + assign widths = '300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2000, 2500, 3000, 3500, 4000, 5000' +%} + +{% style %} + .collection-card[data-block-id="{{ parent_block_id }}"] { + --ratio: {{ ratio }}; + } +{% endstyle %} + +{% if image_source != blank %} +
+ {%- if block.settings.toggle_overlay -%} + {% render 'overlay', settings: block.settings %} + {%- endif -%} + + {{ + image_source + | image_url: width: 3840 + | image_tag: + width: block.settings.image.width, + widths: widths, + height: block.settings.image.height, + class: 'image-block__image', + sizes: sizes, + loading: loading + }} +
+{% else %} +
+ {% liquid + # Simple rotation through collection apparel placeholders (1-4) + # Extract index from parent block ID (e.g., "collection-card-3" -> "3") + assign block_parts = parent_block_id | split: '-' + assign collection_index = block_parts.last | default: 0 + assign variant = collection_index | modulo: 4 | plus: 1 + assign placeholder_name = 'collection-apparel-' | append: variant + %} + {{ placeholder_name | placeholder_svg_tag }} +
+{% endif %} + +{% stylesheet %} + .collection-card__image { + position: relative; + display: flex; + width: 100%; + max-width: 100%; + max-height: 100%; + aspect-ratio: var(--ratio); + z-index: var(--layer-base); + overflow: hidden; + } + + .collection-card__image--placeholder { + width: 100%; + height: 100%; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.collection_card_image", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_card_image" + }, + { + "type": "select", + "id": "image_ratio", + "label": "t:settings.aspect_ratio", + "info": "t:info.aspect_ratio_adjusted", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "landscape", + "label": "t:options.landscape" + } + ], + "default": "portrait" + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.media_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ block.settings.toggle_overlay and block.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_collection-card.liquid b/blocks/_collection-card.liquid new file mode 100644 index 000000000..ee8269917 --- /dev/null +++ b/blocks/_collection-card.liquid @@ -0,0 +1,196 @@ +{% # import schema from '../schemas/blocks/_collection-card' %} + +{% assign collection = closest.collection %} + +{% style %} + {% if request.visual_preview_mode %} + .collection-card { + min-width: 250px; + } + {% endif %} +{% endstyle %} + +{% capture card_image %} + {% content_for 'block', + type: '_collection-card-image', + id: 'collection-card-image', + closest.collection: collection, + parent_block_id: block.id %} +{% endcapture %} + +{% capture children %} + {% content_for 'blocks', closest.collection: collection %} +{% endcapture %} + +{% render 'collection-card', + card_image: card_image, + children: children, + block: block, + collection: collection, + section: section +%} + +{% schema %} +{ + "name": "t:names.collection_card", + "blocks": [ + { + "type": "text" + }, + { + "type": "spacer" + }, + { + "type": "button" + }, + { + "type": "group" + }, + { + "type": "collection-title" + } + ], + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_card" + }, + { + "type": "header", + "content": "t:content.text" + }, + { + "type": "select", + "id": "placement", + "label": "t:settings.placement", + "options": [ + { + "value": "on_image", + "label": "t:options.on_image" + }, + { + "value": "below_image", + "label": "t:options.below_image" + } + ] + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.placement == \"on_image\" }}" + }, + { + "type": "range", + "id": "collection_card_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_collection-image.liquid b/blocks/_collection-image.liquid new file mode 100644 index 000000000..8d6aed74a --- /dev/null +++ b/blocks/_collection-image.liquid @@ -0,0 +1,168 @@ +{% # import schema from '../schemas/blocks/_collection-image' %} + +{% if block.settings.image_ratio == 'custom' %} + {% assign image_width = block.settings.collection_image_width | at_most: 100 %} + {% assign image_height = block.settings.collection_image_height %} +{% endif %} + +{% liquid + assign ratio = 1 + assign block_ratio = block.settings.image_ratio + + if block.settings.collection.image and block_ratio == 'portrait' + assign ratio = 0.8 + elsif block.settings.collection.image and block_ratio == 'adapt' + assign ratio = block.settings.collection.image.aspect_ratio + endif + + if ratio == 0 or ratio == null + assign ratio = 1 + endif + + if block.settings.image_ratio == 'custom' + assign ratio = image_width | append: ' / ' | append: image_height + endif +%} + +{% if block.settings.collection.featured_image %} +
+ {% liquid + assign media_width_desktop = 100 | divided_by: 2 | append: 'vw' + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2000, 2500, 3000, 3500, 4000, 5000' + %} + + {{ + block.settings.collection.featured_image + | image_url: width: 1000 + | image_tag: preload: true, class: 'collection-image__featured-image', widths: widths, sizes: sizes + }} +
+{% endif %} + +{% stylesheet %} + .collection-image { + width: var(--image-width); + } + + .collection-image .collection-image__featured-image { + aspect-ratio: var(--ratio); + object-fit: cover; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.collection_image", + "tag": null, + "settings": [ + { + "type": "collection", + "id": "collection", + "label": "t:settings.collection" + }, + { + "type": "select", + "id": "image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "square", + "label": "t:settings.aspect_ratio" + }, + { + "type": "range", + "id": "collection_image_width", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.image_ratio == 'custom' }}" + }, + { + "type": "range", + "id": "collection_image_height", + "label": "t:settings.height", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.image_ratio == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collection_image", + "settings": { + "collection": "{{ closest.collection }}" + } + } + ] +} +{% endschema %} diff --git a/blocks/_collection-info.liquid b/blocks/_collection-info.liquid new file mode 100644 index 000000000..5dcf7f51a --- /dev/null +++ b/blocks/_collection-info.liquid @@ -0,0 +1,166 @@ +{% # import schema from '../schemas/blocks/_collection-info.js' %} +
+
+ {% content_for 'blocks' %} +
+ +
+ {%- render 'slideshow-controls', icon_style: block.settings.icons_style, shape: block.settings.background_style -%} +
+
+ +{% schema %} +{ + "name": "t:names.collection_info", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "select", + "id": "placement", + "label": "t:settings.placement", + "options": [ + { + "label": "t:options.above_carousel", + "value": "above-carousel" + }, + { + "label": "t:options.next_to_carousel", + "value": "next-to-carousel" + } + ] + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme" + }, + { + "type": "header", + "content": "t:content.arrows" + }, + { + "type": "select", + "id": "navigation", + "label": "t:settings.navigation", + "options": [ + { + "label": "t:options.above_carousel", + "value": "above-carousel" + }, + { + "label": "t:options.inside_carousel", + "value": "inside-carousel" + } + ], + "visible_if": "{{ block.settings.placement == 'above-carousel' }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icons", + "options": [ + { + "value": "arrows", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.large_arrows" + }, + { + "value": "chevron_large", + "label": "t:options.large_chevrons" + }, + { + "value": "none", + "label": "t:options.none" + } + ] + }, + { + "type": "select", + "id": "background_style", + "label": "t:settings.background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ] + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collection_info" + } + ] +} +{% endschema %} diff --git a/blocks/_collection-link.liquid b/blocks/_collection-link.liquid new file mode 100644 index 000000000..b42ed86b8 --- /dev/null +++ b/blocks/_collection-link.liquid @@ -0,0 +1,166 @@ +{% # import schema from '../schemas/blocks/_collection-link' %} + +{%- doc -%} + Renders a collection link block. + + @param {number} index + @param {boolean} [current] + @param {boolean} [image_only] +{%- enddoc -%} + +{% unless current %} + {% assign loading = 'lazy' %} +{% endunless %} + +{% if block.settings.show_count %} + {% assign count = closest.collection.all_products_count %} + {%- capture count -%} +  {{ count }} + {%- endcapture -%} + + {% if closest.collection == empty %} + {%- capture count -%} +  5 + {%- endcapture -%} + {% endif %} +{% endif %} + +{% capture title_block %} + {% content_for 'block', type: '_inline-collection-title', id: 'title', suffix: count %} +{% endcapture %} + +{% capture image_block %} + {%- liquid + assign placeholder_variant = index | modulo: 4 | plus: 1 + assign placeholder_name = 'collection-apparel-' | append: placeholder_variant + -%} + {% content_for 'block', type: '_image', id: 'image', loading: loading, placeholder: placeholder_name %} +{% endcapture %} + +{% if image_only %} + + {{ image_block }} + +{% else %} + + {{ title_block }} + + {% if section.settings.layout == 'text' %} + + {% endif %} + +{% endif %} + +{% stylesheet %} + .collection-links__link { + --min-font-size: var(--font-size--4xl); + --max-font-size: var(--font-size--6xl); + + display: flex; + color: inherit; + text-decoration: none; + text-wrap: pretty; + font-size: clamp(var(--min-font-size), 4.5vw, var(--max-font-size)); + + @media (hover: hover) { + opacity: var(--disabled-opacity); + } + + [layout='spotlight'] & { + opacity: var(--disabled-opacity); + } + + &[aria-current='true'] { + opacity: 1; + } + + .text-block { + display: inline-block; + } + + @media (max-width: 749px) { + --min-font-size: var(--font-size--3xl); + --max-font-size: var(--font-size--5xl); + + [layout='spotlight'] & { + white-space: nowrap; + scroll-snap-align: start; + + span { + text-wrap: nowrap; + } + } + } + } + + .collection-links__count { + font-size: 0.5em; + opacity: var(--disabled-opacity); + font-weight: var(--font-paragraph--weight); + } + + .collection-links__image { + align-items: center; + justify-content: center; + + &:not([hidden]) { + display: flex; + } + + &[reveal] { + --offset: 15px; + + position: fixed; + top: 0; + left: 0; + z-index: var(--layer-temporary); + display: block; + translate: calc(var(--x) + var(--offset)) calc(var(--y) + var(--offset)); + pointer-events: none; + width: auto; + + image-block { + --image-height-basis: 5rem; + + height: var(--image-height); + } + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.collection", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_card" + }, + { + "type": "checkbox", + "id": "show_count", + "label": "t:settings.show_count", + "default": true + } + ] +} +{% endschema %} diff --git a/blocks/_content-without-appearance.liquid b/blocks/_content-without-appearance.liquid new file mode 100644 index 000000000..4ddb23ef1 --- /dev/null +++ b/blocks/_content-without-appearance.liquid @@ -0,0 +1,117 @@ +{% # import schema from '../schemas/blocks/_content-without-appearance' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'group', + class: 'media-with-content__content', + children: children, + settings: block.settings, + shopify_attributes: block.shopify_attributes +%} + +{% schema %} +{ + "name": "t:names.content", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "center" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + } + ], + "presets": [ + { + "name": "t:names.group", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/_content.liquid b/blocks/_content.liquid new file mode 100644 index 000000000..817de1982 --- /dev/null +++ b/blocks/_content.liquid @@ -0,0 +1,162 @@ +{% # import schema from '../schemas/blocks/_content' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %} + +{% schema %} +{ + "name": "t:names.content", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "center" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.group", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/_divider.liquid b/blocks/_divider.liquid new file mode 100644 index 000000000..977902ea2 --- /dev/null +++ b/blocks/_divider.liquid @@ -0,0 +1,79 @@ +{% # import schema from '../schemas/blocks/_divider.js' %} + +{% render 'divider', id: block.id, settings: block.settings, attributes: true %} + +{% schema %} +{ + "name": "t:names.divider", + "tag": null, + "settings": [ + { + "type": "range", + "id": "thickness", + "label": "t:settings.thickness", + "min": 0.5, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 1 + }, + { + "type": "select", + "id": "corner_radius", + "label": "t:settings.border_radius", + "options": [ + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "rounded", + "label": "t:options.rounded" + } + ], + "default": "square", + "visible_if": "{{ block.settings.thickness > 1 }}" + }, + { + "type": "range", + "id": "width_percent", + "label": "t:settings.length", + "min": 5, + "max": 100, + "step": 1, + "unit": "%", + "default": 100 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.divider", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/_featured-product-gallery.liquid b/blocks/_featured-product-gallery.liquid new file mode 100644 index 000000000..d7bc0159d --- /dev/null +++ b/blocks/_featured-product-gallery.liquid @@ -0,0 +1,61 @@ +{% # import schema from '../schemas/blocks/_featured-product-gallery' %} + +{% render 'card-gallery' %} + +{% schema %} +{ + "name": "t:names.product_media", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_media" + }, + { + "type": "select", + "id": "image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "landscape", + "label": "t:options.landscape" + } + ], + "default": "adapt", + "label": "t:settings.aspect_ratio" + }, + { + "type": "select", + "id": "constrain_to_viewport", + "options": [ + { + "value": "", + "label": "t:options.off" + }, + { + "value": "contain", + "label": "t:options.maintain_aspect_ratio" + }, + { + "value": "cover", + "label": "t:options.crop_to_fit" + } + ], + "default": "contain", + "label": "t:settings.limit_media_to_screen_height", + "visible_if": "{{ block.settings.image_ratio == 'adapt' }}" + } + ] +} +{% endschema %} diff --git a/blocks/_featured-product-price.liquid b/blocks/_featured-product-price.liquid new file mode 100644 index 000000000..e93bc386d --- /dev/null +++ b/blocks/_featured-product-price.liquid @@ -0,0 +1,109 @@ +{% # import schema from '../schemas/blocks/_featured-product-price.js' %} + +{% liquid + assign product = closest.product + + if settings.currency_code_enabled_product_cards + assign price_min = product.price_min | money_with_currency + else + assign price_min = product.price_min | money + endif + + if product.price_varies + assign display_price = 'content.price_from' | t: price: price_min + endif + + assign has_swatches_only = false + + if product.options.size == 1 + assign first_product_option_value = product.options_with_values.first.values.first + + if first_product_option_value.swatch != blank + assign has_swatches_only = true + endif + endif +%} + + + {% if product.price_varies and has_swatches_only == false and price_min != blank %} + {{ display_price }} + {% else %} + {% render 'price', + show_unit_price: true, + show_sale_price_first: block.settings.show_sale_price_first, + product_resource: product + %} + {% endif %} + + +{% schema %} +{ + "name": "t:names.product_price", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_price" + }, + { + "type": "paragraph", + "content": "t:content.edit_price_in_theme_settings" + }, + { + "type": "checkbox", + "id": "show_sale_price_first", + "label": "t:settings.show_sale_price_first", + "default": true + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.type_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "info": "t:info.edit_presets_in_theme_settings" + } + ] +} +{% endschema %} diff --git a/blocks/_featured-product.liquid b/blocks/_featured-product.liquid new file mode 100644 index 000000000..ec28d53fd --- /dev/null +++ b/blocks/_featured-product.liquid @@ -0,0 +1,41 @@ +{% # import schema from '../schemas/blocks/_featured-product-block' %} + +{% capture product_card_children %} + + {% content_for 'block', type: '_featured-product-gallery', id: 'featured-product-gallery' %} + +{% endcapture %} + +{% render 'product-card', children: product_card_children, product: closest.product, product_card_gap: 8 %} + +{% stylesheet %} + .featured-product-content-top { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: var(--gap-sm); + } + + .featured-product-content-bottom:not(:has(product-swatches)) { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_card" + } + ] +} +{% endschema %} diff --git a/blocks/_footer-copyright.liquid b/blocks/_footer-copyright.liquid new file mode 100644 index 000000000..91ff1402e --- /dev/null +++ b/blocks/_footer-copyright.liquid @@ -0,0 +1,74 @@ +{% # import schema from '../schemas/blocks/_footer-copyright.js' %} + + + +{% schema %} +{ + "name": "t:names.copyright", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.copyright_info" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + } + ], + "default": "0.75rem" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] +} +{% endschema %} diff --git a/blocks/_footer-policy-list.liquid b/blocks/_footer-policy-list.liquid new file mode 100644 index 000000000..ee4b7d32b --- /dev/null +++ b/blocks/_footer-policy-list.liquid @@ -0,0 +1,96 @@ +{% # import schema from '../schemas/blocks/_footer-policy-list.js' %} + + + +{% stylesheet %} + .policy_list { + display: flex; + gap: var(--gap-2xs) var(--gap-sm); + + /* Depending on the content, some smaller desktop layouts will need to wrap the items to fit everything */ + flex-wrap: wrap; + justify-content: center; + + @media screen and (min-width: 750px) { + justify-content: flex-start; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.policy_list", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.manage_policies" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + } + ], + "default": "0.75rem" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] +} +{% endschema %} diff --git a/blocks/_footer-social-icons.liquid b/blocks/_footer-social-icons.liquid new file mode 100644 index 000000000..2e093e55d --- /dev/null +++ b/blocks/_footer-social-icons.liquid @@ -0,0 +1,34 @@ +{% # import schema from '../schemas/blocks/_footer-social-icons.js' %} + + + +{% stylesheet %} + .social-icons__wrapper { + display: flex; + gap: var(--gap-sm); + flex-wrap: wrap; + justify-content: center; + + @media screen and (min-width: 750px) { + flex-wrap: nowrap; + justify-content: flex-start; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.social_media_links", + "tag": null, + "blocks": [ + { + "type": "_social-link" + } + ] +} +{% endschema %} diff --git a/blocks/_header-logo.liquid b/blocks/_header-logo.liquid new file mode 100644 index 000000000..2aa983bc6 --- /dev/null +++ b/blocks/_header-logo.liquid @@ -0,0 +1,233 @@ +{% # import schema from '../schemas/blocks/_header-logo.js' %} + +{% liquid + assign use_inverse_logo = false + + if section.settings.enable_transparent_header_home and template.name == 'index' and section.settings.home_color_scheme == 'inverse' + assign use_inverse_logo = true + elsif section.settings.enable_transparent_header_product and template.name == 'product' and section.settings.product_color_scheme == 'inverse' + assign use_inverse_logo = true + elsif section.settings.enable_transparent_header_collection and template.name == 'collection' and section.settings.collection_color_scheme == 'inverse' + assign use_inverse_logo = true + endif + + if use_inverse_logo + if settings.logo_inverse != blank + assign inverse_logo = settings.logo_inverse + else + assign inverse_logo = settings.logo + endif + endif +%} + +{% comment %} + Output all logo variants, use CSS to hide/show the appropriate one + based on the .header[transparent] selector +{% endcomment %} + + +{% stylesheet %} + .header-logo { + display: flex; + height: 100%; + font-size: var(--font-size--md); + font-family: var(--font-family); + font-weight: var(--font-weight); + font-style: var(--font-style); + color: var(--color-foreground); + justify-content: center; + align-items: center; + text-decoration: none; + + /* Make sure the logo visually hugs the left edge of the column when it is the first item in the left column */ + margin-inline: calc(-1 * var(--padding-inline-start)); + + &[data-hidden-on-home-page] { + display: none; + + #header-component:is( + [sticky='always']:not([data-scroll-direction='none']), + [sticky='scroll-up'][data-scroll-direction='up'] + ) + & { + display: flex; + } + } + + @media screen and (max-width: 749px) { + padding: 0; + } + + @media screen and (min-width: 750px) { + flex-shrink: 0; + } + + &:hover { + text-decoration: none; + } + } + + .header-logo__image { + object-fit: contain; + height: var(--header-logo-image-height-mobile); + width: var(--header-logo-image-width-mobile); + + @media screen and (min-width: 750px) { + height: var(--header-logo-image-height); + width: var(--header-logo-image-width); + } + } + + .header-logo:has(.header-logo__image-container--inverse) .header-logo__image-container--original { + display: var(--header-logo-display, block); + } + + .header-logo__image-container--inverse { + display: var(--header-logo-inverse-display, none); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.logo", + "tag": null, + "class": "header-logo", + "settings": [ + { + "type": "paragraph", + "content": "t:content.edit_logo_in_theme_settings" + }, + { + "type": "header", + "content": "t:content.visibility" + }, + { + "type": "checkbox", + "id": "hide_logo_on_home_page", + "label": "t:settings.hide_logo_on_home_page" + }, + { + "type": "header", + "content": "t:content.size", + "visible_if": "{{ settings.logo != blank }}" + }, + { + "type": "range", + "id": "custom_height", + "label": "t:settings.desktop_height", + "min": 12, + "max": 100, + "step": 1, + "unit": "px", + "default": 20, + "visible_if": "{{ settings.logo != blank }}" + }, + { + "type": "range", + "id": "custom_height_mobile", + "label": "t:settings.mobile_height", + "min": 12, + "max": 100, + "step": 1, + "unit": "px", + "default": 20, + "visible_if": "{{ settings.logo != blank }}" + }, + { + "type": "header", + "content": "t:content.padding_desktop" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_header-menu.liquid b/blocks/_header-menu.liquid new file mode 100644 index 000000000..aa24b27d6 --- /dev/null +++ b/blocks/_header-menu.liquid @@ -0,0 +1,995 @@ +{% # import schema from '../schemas/blocks/_header-menu.js' %} +{%- doc -%} + Renders a header menu block. + + @param {string} [variant] - What version of the menu to render. Defaults to header menu. + @param {string} [transparent] - Show a transparent menu +{%- enddoc -%} + +{% liquid + assign animation_speed = 200 + + if block.settings.menu_style == 'featured_products' and block.settings.product_title_case == 'uppercase' + assign title_case_style = ' --title-case: uppercase;' + elsif block.settings.menu_style == 'featured_collections' and block.settings.collection_title_case == 'uppercase' + assign title_case_style = ' --title-case: uppercase;' + elsif block.settings.menu_style == 'collection_images' and block.settings.collection_title_case == 'uppercase' + assign title_case_style = ' --title-case: uppercase;' + endif +%} + +{% case variant %} + {% when 'mobile' %} +
+ {% render 'header-drawer', + class: 'header__drawer--mobile', + linklist: block.settings.menu, + data_header_drawer_type: 'mobile-drawer' + %} +
+ + {% when 'navigation_bar' %} + {% if block.settings.navigation_bar == true %} + + {% endif %} + {% else %} + +
+ {%- render 'header-menu' %} +
+ + +
+{% endcase %} + +{% stylesheet %} + .menu-list--mobile { + &.menu-list { + display: grid; + } + + & .menu-list__list { + width: max-content; + margin-inline: auto; + gap: var(--menu-horizontal-gap); + } + + & li { + width: max-content; + padding-block: var(--padding-sm); + } + + & li:first-of-type { + padding-inline-start: var(--menu-horizontal-gap); + } + + & li:last-of-type { + padding-inline-end: var(--menu-horizontal-gap); + } + + & a { + color: var(--color-foreground); + } + } + + .menu-list__scroll-container { + position: relative; + overflow-x: auto; + mask-image: linear-gradient(to right, transparent, black 20px, black calc(100% - 20px), transparent); + padding-block: var(--padding-2xs); + } + + header-menu { + width: 100%; + } + + /* Drawer menu featured content */ + .menu-drawer__featured-content { + z-index: var(--layer-base); + container-type: inline-size; + } + + .menu-drawer__featured-content--childlist { + z-index: var(--layer-flat); + } + + .menu-drawer__featured-content-list { + display: flex; + gap: 1em; + overflow-x: auto; + padding-block-end: var(--padding-lg); + } + + .menu-drawer__featured-content-list-item { + flex: 0 0 auto; + } + + .menu-drawer__featured-content-list-item--product { + width: 35cqi; + } + + .menu-drawer__featured-content-list-item--collection img.resource-card__image { + width: 80cqi; + } + + .menu-drawer__featured-content-list-item:first-child { + margin-inline-start: var(--margin-xl); + } + + .menu-drawer__featured-content-list-item:last-child { + margin-inline-end: var(--margin-xl); + } + + /* Apply title case to drawer menu featured content */ + .menu-drawer__featured-content-list-item--product .resource-card__title, + .menu-drawer__featured-content-list-item--collection .resource-card__title { + text-transform: var(--title-case); + } + + .menu-list { + --menu-horizontal-gap: var(--gap-xl); + --menu-vertical-gap: var(--gap-xl); + + display: flex; + } + + .menu-list__list { + display: flex; + justify-content: var(--grid-area-alignment); + } + + .menu-list__list-item { + flex-shrink: 0; + white-space: nowrap; + } + + .menu-list__list-item[aria-hidden='true'] { + visibility: hidden; + } + + .menu-list__link { + font-family: var(--menu-top-level-font-family); + font-style: var(--menu-top-level-font-style); + font-weight: var(--menu-top-level-font-weight); + font-size: var(--menu-top-level-font-size); + line-height: var(--menu-top-level-font-line-height); + text-transform: var(--menu-top-level-font-case); + color: var(--menu-top-level-font-color); + transition: color var(--animation-speed) var(--animation-easing); + text-decoration: none; + display: flex; + min-height: var(--minimum-touch-target); + align-items: center; + + &:hover, + &:focus { + color: var(--menu-top-level-font-color); + } + + @media screen and (min-width: 750px) { + font-size: var(--menu-top-level-font-size-desktop); + } + } + + /* + High specificity selectors to subdue non-hovered links without javascript. + If the need for js-generated `hovered` and `focused` classes arises for another reason we can simplify these. + */ + .menu-list:where(:has(.menu-list__list-item:hover)), + .menu-list:where(:has(.menu-list__list-item:focus-within)), + .menu-list:where(:has(.menu-list__list-item:not([aria-hidden='true']) .menu-list__link--active)) { + .menu-list__link { + color: rgb(var(--menu-top-level-font-color-rgb) / var(--opacity-subdued-text)); + } + } + + /* stylelint-disable-next-line selector-max-specificity */ + .menu-list:not(:has(.menu-list__list-item:hover)) .menu-list__link--active, + .menu-list .menu-list__list-item:where(:hover, :focus-within) .menu-list__link, + .menu-list .menu-list__list-item[slot='overflow'] .menu-list__link[aria-expanded='true'] { + color: var(--menu-top-level-font-color); + } + + .overflow-menu::part(list) { + /* Make sure focus outline is not cut off by overflow hidden */ + --focus-outline-size: calc(var(--focus-outline-offset) + var(--focus-outline-width)); + + gap: 0 var(--menu-horizontal-gap); + } + + .overflow-menu { + background-color: transparent; + padding: var(--focus-outline-size); + margin: calc(-1 * var(--focus-outline-size)); + } + + /* the submenu background element to animate */ + .overflow-menu::after { + content: ''; + position: absolute; + top: calc(100% - 1px + var(--border-bottom-width)); + left: 0; + width: 100%; + height: var(--submenu-height); + background-color: var(--color-background); + box-shadow: var(--shadow-popover); + clip-path: inset(0.5px 0 -100px 0); /* stylelint-disable-line */ + opacity: var(--submenu-opacity, 1); + transition: height var(--submenu-animation-speed) var(--ease-out-cubic), + opacity var(--animation-speed-slow) var(--ease-out-cubic) var(--animation-speed-fast); + z-index: calc(var(--layer-header-menu) - 1); + } + + /** mega menu **/ + .menu-list__submenu, + .overflow-menu::part(overflow) { + --submenu-padding-block-start: var(--padding-3xl); + --submenu-padding-block-end: var(--padding-3xl); + + background-color: transparent; + } + + .header__row[style*='--border-bottom-width: 0px'] { + .menu-list__submenu.color-scheme-matches-parent, + .overflow-menu.color-scheme-matches-parent::part(overflow) { + --submenu-padding-block-start: 0px; + } + } + + .menu-list__list-item:where(:not([slot='overflow'])) > .menu-list__submenu, + .overflow-menu::part(overflow) { + --submenu-content-opacity: 0; + --submenu-content-animation: opacity calc(var(--submenu-animation-speed) * 0.75) var(--animation-easing); + + box-shadow: var(--shadow-drawer); + visibility: hidden; + background-color: var(--color-background); + position: absolute; + width: 100%; + left: 0; + top: calc(100% - 1px + var(--border-bottom-width)); + z-index: var(--layer-header-menu); + padding-inline: var(--padding-inline); + clip-path: rect(0 100% var(--submenu-height) 0); /* stylelint-disable-line */ + transition: clip-path var(--submenu-animation-speed) var(--ease-out-cubic); + } + + /* Show the submenus on hover */ + .menu-list__list-item:has([aria-expanded='true']) > .menu-list__submenu, + /* Show the overflow menu when a menu item is hovered */ + .overflow-menu:has([slot="overflow"] [aria-expanded='true'])::part(overflow), + /* Keep the submenus open when they are hovered */ + .menu-list__submenu:is(:hover), + .overflow-menu::part(overflow):hover { + --submenu-content-opacity: 1; + + visibility: visible; + } + + .menu-list__list-item:has([data-animating]) > .menu-list__submenu { + --submenu-content-opacity: 0; + + visibility: visible; + + &::before { + height: 0; + } + } + + .menu-list__submenu-inner, + .overflow-menu::part(overflow-list) { + grid-column: 2; + padding-block-start: var(--submenu-padding-block-start); + padding-block-end: var(--submenu-padding-block-end); + padding-inline: var(--section-padding-inline); + } + + .overflow-menu::part(overflow) { + --menu-top-level-font-size: var(--font-size--xlarge); + + display: grid; + grid-template-columns: var(--full-page-grid-with-margins); + } + + .overflow-menu::part(overflow-list) { + --submenu-content-opacity: 0; + + position: relative; + display: grid; + grid-template-columns: minmax(auto, 200px) 1fr; + grid-template-areas: 'left right'; + grid-template-rows: max-content; + grid-gap: 0; + } + + .menu-list__list-item:is([slot='overflow']) { + --menu-top-level-font-color: var(--color-foreground); + --menu-top-level-font-color-rgb: var(--color-foreground-rgb); + + display: contents; + white-space: normal; + + .menu-list__link { + --submenu-content-opacity: 0; + + grid-area: left; + grid-row: auto; + height: min-content; + font-size: var(--font-size--xl); + opacity: var(--submenu-content-opacity); + transition: var(--submenu-content-animation); + } + + .menu-list__submenu { + visibility: hidden; + grid-row: 1; + grid-area: right; + grid-row-end: span calc(var(--overflow-count) + 1); + padding-inline-start: var(--menu-horizontal-gap); + + .menu-list__submenu-inner { + padding-block-start: 0; + grid-column: unset; + } + } + + .menu-list__link[aria-expanded='true'] + .menu-list__submenu { + visibility: visible; + } + } + + .header-menu[data-overflow-expanded='true'] .menu-list__list-item:where([slot='overflow']) .menu-list__link { + --submenu-content-opacity: 1; + } + + .menu-list__list-item:where([slot='overflow']):has([data-animating]) > .menu-list__link { + --submenu-content-opacity: 0; + } + + .menu-list__submenu-inner { + position: relative; + display: flex; + justify-content: space-between; + flex-wrap: wrap; + opacity: var(--submenu-content-opacity); + transition: var(--submenu-content-animation); + } + + .mega-menu__link { + font-family: var(--menu-child-font-family); + font-style: var(--menu-child-font-style); + font-weight: var(--menu-child-font-weight); + font-size: var(--menu-child-font-size); + line-height: var(--menu-child-font-line-height); + text-transform: var(--menu-child-font-case); + color: var(--menu-child-font-color); + white-space: normal; + text-decoration: none; + display: inline-flex; + padding: var(--padding-2xs) 0; + transition: color var(--animation-speed) var(--animation-easing); + + &:hover { + color: var(--menu-child-active-font-color); + } + } + + .mega-menu__link--parent { + font-family: var(--menu-parent-font-family); + font-style: var(--menu-parent-font-style); + font-weight: var(--menu-parent-font-weight); + font-size: var(--menu-parent-font-size); + line-height: var(--menu-parent-font-line-height); + text-transform: var(--menu-parent-font-case); + color: var(--menu-parent-font-color); + + &:hover { + color: var(--menu-parent-active-font-color); + } + } + + @media screen and (max-width: 989px) { + .mega-menu__content-list-item--hidden-tablet { + display: none; + } + } + + .mega-menu__link:has(.mega-menu__link-image) { + display: flex; + flex-direction: column; + padding-inline: 0; + padding-block: var(--padding-sm) 0; + } + + .mega-menu__link-image { + width: 100%; + position: relative; + aspect-ratio: 16 / 9; + margin-bottom: var(--padding-sm); + object-fit: cover; + border-radius: var(--menu-image-border-radius); + } + + /* Fix alignment for collection image mode links without images */ + /* Target only top-level links (direct children of column > div) in collection image mode */ + .mega-menu__grid:has(.mega-menu__link-image) + .mega-menu__column + > div + > .mega-menu__link:not(:has(.mega-menu__link-image)) { + display: flex; + flex-direction: column; + padding-inline: 0; + padding-block: var(--padding-sm) 0; + } + + .mega-menu__grid:has(.mega-menu__link-image) + .mega-menu__column + > div + > .mega-menu__link:not(:has(.mega-menu__link-image))::before { + content: ''; + display: block; + width: 100%; + aspect-ratio: 16 / 9; + margin-bottom: var(--padding-sm); + background-color: var(--color-foreground-muted); + opacity: 0.1; + border-radius: var(--menu-image-border-radius); + } + + .mega-menu__grid { + display: grid; + grid-template-columns: repeat(var(--menu-columns-tablet), minmax(0, 1fr)); + gap: var(--menu-vertical-gap) var(--menu-horizontal-gap); + width: 100%; + + @media screen and (min-width: 990px) { + grid-template-columns: repeat(var(--menu-columns-desktop), minmax(0, 1fr)); + } + } + + .mega-menu__column { + grid-column: span 1; + } + + .mega-menu__column--span-2 { + grid-column: span 2; + } + + .mega-menu__column--span-3 { + grid-column: span 3; + } + + .mega-menu__column--span-4 { + grid-column: span 4; + } + + .mega-menu__column--collection-image { + grid-column: span 1; + + @media screen and (min-width: 990px) { + grid-column: span 2; + } + } + + .mega-menu__column--collection-image .mega-menu__link { + text-transform: var(--title-case); + } + + .mega-menu__submenu .mega-menu__column--collection-image { + grid-column: span 1; + } + + /* Apply title case to featured products and collections */ + .mega-menu__content-list--products .resource-card__title, + .mega-menu__content-list--collections .resource-card__title { + text-transform: var(--title-case); + } + + .mega-menu__content-list { + display: grid; + justify-content: end; + gap: var(--menu-vertical-gap) var(--menu-horizontal-gap); + } + + .mega-menu__content-list--products { + grid-template-columns: repeat(var(--menu-content-columns-tablet), minmax(0, 1fr)); + + @media screen and (min-width: 990px) { + grid-template-columns: repeat(var(--menu-content-columns-desktop), minmax(0, 1fr)); + } + } + + .mega-menu__content-list--collections { + grid-template-columns: repeat(var(--menu-content-columns-tablet), minmax(0, 300px)); + + @media screen and (min-width: 990px) { + grid-template-columns: repeat(var(--menu-content-columns-desktop), minmax(0, 300px)); + } + } + + .mega-menu__list { + display: grid; + grid-template-columns: subgrid; + grid-column: span var(--menu-columns-tablet); + gap: var(--menu-vertical-gap) var(--menu-horizontal-gap); + + @media screen and (min-width: 990px) { + grid-column: span var(--menu-columns-desktop); + } + } + + .mega-menu__content { + grid-column: span var(--menu-content-columns-tablet) / -1; + + @media screen and (min-width: 990px) { + grid-column: span var(--menu-content-columns-desktop) / -1; + } + } + + .menu-list__list-item[slot='overflow'] .section { + grid-template-columns: 1fr; + } + + .menu-list__list-item[slot='overflow'] .section .mega-menu__grid { + grid-column: 1; + } + + .mega-menu__content-list li { + white-space: normal; + } + + /* mega more menu */ + .mega-menu__more-list { + --menu-child-font-size: var(--font-size--xl); + + width: 200px; + } + + .mega-menu__more-list-item .mega-menu__link { + color: rgb(var(--menu-top-level-font-color-rgb) / var(--opacity-subdued-text)); + } + + .mega-menu__more-list-item:where(:hover, .active) .mega-menu__link { + color: var(--menu-top-level-font-color); + } + + .mega-menu__more-list-item[aria-hidden='true'] { + display: none; + } + + .mega-menu__submenu { + /* preserves the inherited grid layout when this submenu wrapper is used */ + display: contents; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.menu", + "tag": null, + "settings": [ + { + "type": "link_list", + "id": "menu", + "label": "t:settings.menu", + "default": "main-menu" + }, + { + "type": "select", + "id": "menu_style", + "label": "t:settings.style", + "options": [ + { + "value": "text", + "label": "t:options.text_only" + }, + { + "value": "collection_images", + "label": "t:options.collection_images" + }, + { + "value": "featured_products", + "label": "t:options.featured_products" + }, + { + "value": "featured_collections", + "label": "t:options.featured_collections" + } + ], + "default": "collection_images" + }, + { + "type": "select", + "id": "featured_products_aspect_ratio", + "label": "t:settings.image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "4 / 5", + "label": "t:options.portrait" + }, + { + "value": "1 / 1", + "label": "t:options.square" + } + ], + "default": "4 / 5", + "visible_if": "{{ block.settings.menu_style == 'featured_products' }}" + }, + { + "type": "select", + "id": "featured_collections_aspect_ratio", + "label": "t:settings.image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "16 / 9", + "label": "t:options.landscape" + }, + { + "value": "1 / 1", + "label": "t:options.square" + } + ], + "default": "16 / 9", + "visible_if": "{{ block.settings.menu_style == 'featured_collections' }}" + }, + { + "type": "range", + "id": "image_border_radius", + "label": "t:settings.image_border_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0, + "visible_if": "{{ block.settings.menu_style != 'text' }}" + }, + { + "type": "select", + "id": "product_title_case", + "label": "t:settings.product_title_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default", + "visible_if": "{{ block.settings.menu_style == 'featured_products' }}" + }, + { + "type": "select", + "id": "collection_title_case", + "label": "t:settings.collection_title_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default", + "visible_if": "{{ block.settings.menu_style == 'featured_collections' or block.settings.menu_style == 'collection_images' }}" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "primary" + }, + { + "type": "select", + "id": "menu_font_style", + "label": "t:settings.text_hierarchy", + "options": [ + { + "value": "regular", + "label": "t:options.classic" + }, + { + "value": "inverse", + "label": "t:options.inverse" + }, + { + "value": "inverse_large", + "label": "t:options.inverse_large" + } + ], + "default": "inverse" + }, + { + "type": "header", + "content": "t:content.typography_primary" + }, + { + "type": "select", + "id": "type_font_primary_link", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading" + }, + { + "type": "select", + "id": "type_font_primary_size", + "label": "t:settings.size", + "options": [ + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem" + }, + { + "type": "select", + "id": "type_case_primary_link", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:content.typography_secondary" + }, + { + "type": "select", + "id": "type_font_secondary_link", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "subheading" + }, + { + "type": "select", + "id": "type_case_secondary_link", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:content.typography_tertiary" + }, + { + "type": "select", + "id": "type_font_tertiary_link", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "body" + }, + { + "type": "select", + "id": "type_case_tertiary_link", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:content.mobile_layout" + }, + { + "type": "checkbox", + "id": "navigation_bar", + "label": "t:settings.navigation_bar" + }, + { + "type": "color_scheme", + "id": "color_scheme_navigation_bar", + "label": "t:settings.navigation_bar_color_scheme", + "default": "primary", + "visible_if": "{{ block.settings.navigation_bar }}" + }, + { + "type": "checkbox", + "id": "drawer_accordion", + "label": "t:settings.accordion", + "default": false + }, + { + "type": "checkbox", + "id": "drawer_accordion_expand_first", + "label": "t:settings.expand_first_group", + "default": false, + "visible_if": "{{ block.settings.drawer_accordion == true }}" + }, + { + "type": "checkbox", + "id": "drawer_dividers", + "label": "t:settings.dividers", + "default": false + } + ] +} +{% endschema %} diff --git a/blocks/_heading.liquid b/blocks/_heading.liquid new file mode 100644 index 000000000..72b99be16 --- /dev/null +++ b/blocks/_heading.liquid @@ -0,0 +1,339 @@ +{% # import schema from '../schemas/blocks/_heading' %} + +{%- doc -%} + Renders a heading block. + + @param {string} text +{%- enddoc -%} + +{% render 'text', width: '100%', block: block, fallback_text: text %} + +{% # theme-check-disable %} +{% schema %} +{ + "name": "t:names.heading", + "tag": null, + "settings": [ + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "richtext", + "id": "text", + "label": "t:settings.text", + "default": "t:html_defaults.share_information_about_your", + "visible_if": "{{ block.settings.read_only != true }}" + }, + { + "type": "checkbox", + "id": "read_only", + "label": "t:settings.read_only", + "visible_if": "{{ false }}", + "default": false + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.show_alignment != false }}" + }, + { + "type": "checkbox", + "id": "show_alignment", + "label": "t:settings.show_alignment", + "default": true, + "visible_if": "{{ false }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} +{% # theme-check-enable %} diff --git a/blocks/_image.liquid b/blocks/_image.liquid new file mode 100644 index 000000000..fffbe3662 --- /dev/null +++ b/blocks/_image.liquid @@ -0,0 +1,170 @@ +{% # import schema from '../schemas/blocks/_image' %} + +{%- doc -%} + Renders an image block. + + @param {string} [loading] - The html loading attribute + @param {string} [placeholder] - The placeholder image name to use when no image is provided, defaults to 'hero-apparel-2' +{%- enddoc -%} + +{% assign image = closest.collection.featured_image | default: closest.product.featured_image %} +{% assign alt = closest.collection.title | default: closest.product.title %} + +{% liquid + assign width = '100%' + assign media_width_desktop = '100vw' + assign media_width_mobile = '100vw' + assign sizes = 'auto, (min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '450, 750, 1200, 1800, 2000' +%} + +{% if image %} + + {{ + image + | image_url: width: 2000 + | image_tag: width: width, widths: widths, sizes: sizes, loading: loading, alt: alt + }} + +{% else %} + + {{ placeholder | default: 'hero-apparel-2' | placeholder_svg_tag: 'hero__image' }} + +{% endif %} + +{% stylesheet %} + image-block { + --image-height-basis: 10rem; + --image-height-small: calc(var(--image-height-basis) * 2); + --image-height-medium: calc(var(--image-height-basis) * 3); + --image-height-large: calc(var(--image-height-basis) * 4); + + display: flex; + align-items: center; + justify-content: center; + aspect-ratio: var(--ratio); + width: 100%; + max-width: calc(var(--image-height) * var(--ratio)); + height: var(--image-height); + overflow: hidden; + + @media screen and (min-width: 750px) { + --image-height-small: calc(var(--image-height-basis) * 2.5); + --image-height-medium: calc(var(--image-height-basis) * 3.5); + --image-height-large: calc(var(--image-height-basis) * 4.5); + } + + @media screen and (max-width: 749px) { + height: auto; + } + + &[height='small'] { + --image-height: var(--image-height-small); + } + + &[height='medium'] { + --image-height: var(--image-height-medium); + } + + &[height='large'] { + --image-height: var(--image-height-large); + } + + &[ratio='portrait'] { + --ratio: 4 / 5; + } + + &[ratio='square'] { + --ratio: 1 / 1; + + @media screen and (min-width: 750px) { + max-width: var(--image-height); + } + } + + &[ratio='landscape'] { + --ratio: 16 / 9; + } + + img { + object-fit: cover; + width: 100%; + height: auto; + aspect-ratio: var(--ratio); + border-radius: var(--border-radius); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.image", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_card_image" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + } + ], + "default": "large" + }, + { + "type": "select", + "id": "ratio", + "label": "t:settings.ratio", + "options": [ + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "landscape", + "label": "t:options.landscape" + } + ], + "default": "portrait" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_inline-collection-title.liquid b/blocks/_inline-collection-title.liquid new file mode 100644 index 000000000..964444c76 --- /dev/null +++ b/blocks/_inline-collection-title.liquid @@ -0,0 +1,165 @@ +{% # import schema from '../schemas/blocks/_inline-collection-title' %} +{%- doc -%} + @param {string} [suffix] - The suffix to add to the collection title +{%- enddoc -%} + +{% if closest.collection == blank %} + {% assign collection_title = 'placeholders.collection_title' | t %} +{% elsif closest.collection != blank %} + {% assign collection_title = closest.collection.title %} +{% endif %} + +{% assign plain_text = collection_title | strip_newlines | strip_html | strip %} + +{% # We need to make sure the wrapper is rendered even if the text element is empty in the theme editor to allow live text editing %} +{%- if plain_text != '' or request.design_mode -%} + + {{ collection_title }}{{ suffix }} + +{%- endif -%} + +{% schema %} +{ + "name": "t:names.collection_title", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_title" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)" + }, + { + "type": "select", + "id": "weight", + "label": "t:settings.weight", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "100", + "label": "t:options.thin" + }, + { + "value": "300", + "label": "t:options.light" + }, + { + "value": "400", + "label": "t:options.regular" + }, + { + "value": "500", + "label": "t:options.medium" + }, + { + "value": "600", + "label": "t:options.semibold" + }, + { + "value": "700", + "label": "t:options.bold" + }, + { + "value": "900", + "label": "t:options.black" + } + ], + "default": "" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] +} +{% endschema %} diff --git a/blocks/_inline-text.liquid b/blocks/_inline-text.liquid new file mode 100644 index 000000000..e0d7c6aea --- /dev/null +++ b/blocks/_inline-text.liquid @@ -0,0 +1,163 @@ +{% # import schema from '../schemas/blocks/_inline-text' %} + +{%- doc -%} + Renders an inline text block. + + @param {string} suffix +{%- enddoc -%} + +{% assign plain_text = block.settings.text | strip_newlines | strip_html | strip %} + +{% # We need to make sure the wrapper is rendered even if the text element is empty in the theme editor to allow live text editing %} +{%- if plain_text != '' or request.design_mode -%} + + {{ block.settings.text }}{{ suffix }} + +{%- endif -%} + +{% schema %} +{ + "name": "t:names.text", + "tag": null, + "settings": [ + { + "type": "text", + "id": "text", + "label": "t:settings.text" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)" + }, + { + "type": "select", + "id": "weight", + "label": "t:settings.weight", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "100", + "label": "t:options.thin" + }, + { + "value": "300", + "label": "t:options.light" + }, + { + "value": "400", + "label": "t:options.regular" + }, + { + "value": "500", + "label": "t:options.medium" + }, + { + "value": "600", + "label": "t:options.semibold" + }, + { + "value": "700", + "label": "t:options.bold" + }, + { + "value": "900", + "label": "t:options.black" + } + ], + "default": "" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] +} +{% endschema %} diff --git a/blocks/_marquee.liquid b/blocks/_marquee.liquid new file mode 100644 index 000000000..7837f0f83 --- /dev/null +++ b/blocks/_marquee.liquid @@ -0,0 +1,212 @@ +{% # import schema from '../schemas/blocks/_marquee' %} + + + +{% assign gap_between_elements = block.settings.gap_between_elements %} + + +
+
+
+ {% content_for 'blocks' %} +
+
+
+
+ +{% stylesheet %} + marquee-component { + display: block; + width: 100%; + overflow: hidden; + background-color: var(--color-background); + } + + .marquee__wrapper { + display: flex; + gap: var(--marquee-gap); + width: fit-content; + white-space: nowrap; + } + + .marquee__content { + min-width: max-content; + display: flex; + gap: var(--marquee-gap); + } + + .marquee__content :is(p, h1, h2, h3, h4, h5, h6) { + white-space: nowrap; + } + + .marquee__content .marquee__repeated-items * { + max-width: none; + } + + .marquee__repeated-items { + min-width: max-content; + display: flex; + gap: var(--marquee-gap); + align-items: center; + justify-content: center; + } + + .marquee__repeated-items > * { + align-content: center; + } + + .hero__content-wrapper.layout-panel-flex--column marquee-component { + --margin-inline: var(--full-page-margin-inline-offset); + + width: -webkit-fill-available; + min-height: max-content; + } + + @media (prefers-reduced-motion: no-preference) { + marquee-component:not([data-disabled]) .marquee__wrapper { + animation: marquee-motion var(--marquee-speed) linear infinite var(--marquee-direction); + } + } + + @keyframes marquee-motion { + to { + transform: translate3d(calc(-50% - (var(--marquee-gap) / 2)), 0, 0); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.marquee", + "tag": null, + "blocks": [ + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "select", + "id": "movement_direction", + "label": "t:settings.motion_direction", + "options": [ + { + "value": "reverse", + "label": "t:options.forward" + }, + { + "value": "normal", + "label": "t:options.reverse" + } + ], + "default": "normal" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "checkbox", + "id": "transparent_background", + "label": "t:settings.transparent_background", + "default": true + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "range", + "id": "gap_between_elements", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + } + ], + "presets": [ + { + "name": "t:names.marquee", + "category": "t:categories.decorative", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

We make things that work better and last longer.

", + "type_preset": "custom", + "font": "var(--font-body--family)", + "font_size": "var(--font-size--h2)", + "line_height": "tight", + "letter_spacing": "tight", + "case": "none", + "wrap": "nowrap", + "width": "fit-content" + } + } + }, + "block_order": ["text"] + } + ] +} +{% endschema %} diff --git a/blocks/_media-without-appearance.liquid b/blocks/_media-without-appearance.liquid new file mode 100644 index 000000000..44387741e --- /dev/null +++ b/blocks/_media-without-appearance.liquid @@ -0,0 +1,105 @@ +{% # import schema from '../schemas/blocks/_media-without-appearance' %} +{% liquid + assign unset_image_tag = false + if block.settings.image_position == 'contain' + assign unset_image_tag = true + endif +%} + +{% render 'media', unset_image_tag: unset_image_tag, section_id: section.id %} + +{% schema %} +{ + "name": "t:names.media", + "tag": null, + "settings": [ + { + "type": "select", + "id": "media_type", + "label": "t:settings.type", + "options": [ + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "image" + }, + { + "type": "image_picker", + "id": "image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.media_type == 'image' }}" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link", + "visible_if": "{{ block.settings.media_type == 'image' }}" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "checkbox", + "id": "video_loop", + "label": "t:settings.loop", + "default": true, + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "checkbox", + "id": "video_autoplay", + "label": "t:settings.autoplay", + "default": false, + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "select", + "id": "image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain ", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.media_type == 'image' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.media_type == 'video' }}" + } + ], + "presets": [ + { + "name": "t:names.media" + } + ] +} +{% endschema %} diff --git a/blocks/_media.liquid b/blocks/_media.liquid new file mode 100644 index 000000000..c6c019f3e --- /dev/null +++ b/blocks/_media.liquid @@ -0,0 +1,136 @@ +{% # import schema from '../schemas/blocks/_media' %} + +{% render 'media', section_id: section.id %} + +{% schema %} +{ + "name": "t:names.media", + "tag": null, + "settings": [ + { + "type": "select", + "id": "media_type", + "label": "t:settings.type", + "options": [ + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "image" + }, + { + "type": "image_picker", + "id": "image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.media_type == 'image' }}" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link", + "visible_if": "{{ block.settings.media_type == 'image' }}" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "checkbox", + "id": "video_loop", + "label": "t:settings.loop", + "default": true, + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "checkbox", + "id": "video_autoplay", + "label": "t:settings.autoplay", + "default": false, + "visible_if": "{{ block.settings.media_type == 'video' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.media" + } + ] +} +{% endschema %} diff --git a/blocks/_product-card-gallery.liquid b/blocks/_product-card-gallery.liquid new file mode 100644 index 000000000..e3dde5683 --- /dev/null +++ b/blocks/_product-card-gallery.liquid @@ -0,0 +1,177 @@ +{% # import schema from '../schemas/blocks/_product-card-gallery' %} + +{% assign has_applied_colour_filter = false %} +{% if collection.filters %} + {% for filter in collection.filters %} + {% if filter.type == 'list' and filter.param_name contains 'color' %} + {% if filter.active_values.size > 0 %} + {% assign has_applied_colour_filter = true %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} + +{% capture children %} + {% unless closest.product == blank %} + {% render 'product-card-badges', product: closest.product %} + {% if settings.quick_add or settings.mobile_quick_add %} + {% render 'quick-add', product: closest.product, section_id: section.id %} + {% endif %} + {% endunless %} +{% endcapture %} + +{% render 'card-gallery', children: children, has_applied_colour_filter: has_applied_colour_filter %} + +{% # Title and price for the zoomed out grid view %} +
+ {% if closest.product == blank %} +

{{ 'content.product_card_placeholder' | t }}

+ {% else %} +

{{ closest.product.title }}

+
+ + {% render 'price', product_resource: closest.product, show_unit_price: false %} + +
+ {% endif %} +
+ +{% schema %} +{ + "name": "t:names.product_image", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_media" + }, + { + "type": "select", + "id": "image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "landscape", + "label": "t:options.landscape" + } + ], + "default": "portrait", + "label": "t:settings.aspect_ratio", + "info": "t:info.aspect_ratio_adjusted" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_card_media", + "category": "t:categories.product" + } + ] +} +{% endschema %} diff --git a/blocks/_product-card-group.liquid b/blocks/_product-card-group.liquid new file mode 100644 index 000000000..aacc9a8d7 --- /dev/null +++ b/blocks/_product-card-group.liquid @@ -0,0 +1,517 @@ +{% # import schema from '../schemas/blocks/_product-card-group' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %} + +{% schema %} +{ + "name": "t:names.group", + "tag": null, + "blocks": [ + { + "type": "text" + }, + { + "type": "image" + }, + { + "type": "price" + }, + { + "type": "review" + }, + { + "type": "swatches" + }, + { + "type": "_product-card-group" + }, + { + "type": "product-title" + }, + { + "type": "custom-liquid" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ block.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "fit", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit" + }, + { + "type": "range", + "id": "custom_height", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.background_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ block.settings.toggle_overlay and block.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.group", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/_product-card.liquid b/blocks/_product-card.liquid new file mode 100644 index 000000000..03d8dcedd --- /dev/null +++ b/blocks/_product-card.liquid @@ -0,0 +1,174 @@ +{% # import schema from '../schemas/blocks/_product-card.js' %} + +{% liquid + assign product = closest.product +-%} + +{% capture children %} + {% content_for 'blocks', closest.product: product %} +{% endcapture %} + +{% render 'product-card', children: children, product: product %} + +{% schema %} +{ + "name": "t:names.product_card", + "blocks": [ + { + "type": "_product-card-group" + }, + { + "type": "text" + }, + { + "type": "image" + }, + { + "type": "buy-buttons" + }, + { + "type": "price" + }, + { + "type": "review" + }, + { + "type": "swatches" + }, + { + "type": "_product-card-gallery" + }, + { + "type": "product-title" + }, + { + "type": "custom-liquid" + } + ], + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_card" + }, + { + "type": "range", + "id": "product_card_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 32, + "step": 1, + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/blocks/_product-details.liquid b/blocks/_product-details.liquid new file mode 100644 index 000000000..922af61ad --- /dev/null +++ b/blocks/_product-details.liquid @@ -0,0 +1,708 @@ +{% # import schema from '../schemas/blocks/_product-details' %} + +
+ {% capture children %} + + {% content_for 'blocks' %} + {% endcapture %} + + {% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %} +
+ +{% stylesheet %} + /* Clear padding on mobile, if not full-width */ + @media screen and (max-width: 749px) { + .product-information.section--page-width .product-details > .group-block { + padding-inline: 0; + } + } + + .view-product-title { + display: none; + } + + /* Container styles */ + .product-details { + display: flex; + align-self: start; + justify-content: center; + } + + @media screen and (min-width: 750px) { + .product-details > .group-block { + height: min-content; + } + + .full-height--desktop { + height: 100%; + max-height: calc(100vh - var(--header-group-height, 0)); + min-height: fit-content; + } + + .full-height--desktop .group-block { + align-self: var(--details-position, 'flex-start'); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.details", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "accordion" + }, + { + "type": "product-recommendations" + }, + { + "type": "price" + }, + { + "type": "variant-picker" + }, + { + "type": "buy-buttons" + }, + { + "type": "product-description" + }, + { + "type": "review" + }, + { + "type": "accelerated-checkout" + }, + { + "type": "_divider" + }, + { + "type": "product-inventory" + } + ], + "tag": null, + "settings": [ + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "fit", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + } + ], + "default": "fit" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "details_position", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.height == \"fill\" }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "checkbox", + "id": "sticky_details_desktop", + "label": "t:settings.make_details_sticky_desktop", + "default": false + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.details", + "settings": { + "width": "custom", + "custom_width": 100, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0, + "gap": 12, + "inherit_color_scheme": true, + "color_scheme": "", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100 + }, + "blocks": { + "text_TMtYp8": { + "type": "text", + "settings": { + "text": "

Home → Shirts

", + "alignment": "left", + "padding-block-start": 16, + "padding-inline-end": 0, + "padding-block-end": 0, + "padding-inline-start": 0 + } + }, + "heading_m7KmQQ": { + "type": "text", + "settings": { + "text": "

{{ closest.product.title }}

", + "type_preset": "h2", + "alignment": "left" + } + }, + "text_GMQR8L": { + "type": "text", + "settings": { + "text": "

★★★★★ 368 Reviews

", + "alignment": "left" + } + }, + "price_a7krng": { + "type": "price", + "settings": { + "show_tax_info": true, + "type_preset": "h4", + "alignment": "left" + } + }, + "variant_picker_R3rGDr": { + "type": "variant-picker", + "settings": { + "variant_style": "pills", + "padding-block-start": 0, + "padding-block-end": 8, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "buy_buttons_eYQEYi": { + "type": "buy-buttons", + "settings": { + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "add-to-cart": { + "type": "add-to-cart", + "static": true, + "settings": { + "style_class": "button-secondary" + } + }, + "accelerated-checkout": { + "type": "accelerated-checkout", + "static": true + } + }, + "block_order": [] + }, + "group_Q4eVWb": { + "type": "group", + "settings": { + "width": "custom", + "custom_width": 100, + "padding-block-start": 8, + "padding-block-end": 4, + "padding-inline-start": 0, + "padding-inline-end": 0, + "content_direction": "column", + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 8, + "inherit_color_scheme": true, + "color_scheme": "", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100 + }, + "blocks": { + "group_Hrq6NU": { + "type": "group", + "settings": { + "width": "custom", + "custom_width": 100, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0, + "content_direction": "row", + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "inherit_color_scheme": true, + "color_scheme": "", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100 + }, + "blocks": { + "icon_bBpnME": { + "type": "icon", + "settings": { + "icon": "truck", + "width": 16 + } + }, + "text_83R7CQ": { + "type": "text", + "settings": { + "text": "

Free shipping over $50

", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["icon_bBpnME", "text_83R7CQ"] + }, + "group_WbpVdV": { + "type": "group", + "settings": { + "width": "custom", + "custom_width": 100, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0, + "content_direction": "row", + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "inherit_color_scheme": true, + "color_scheme": "", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100 + }, + "blocks": { + "icon_FVd3C4": { + "type": "icon", + "settings": { + "icon": "return", + "width": 16 + } + }, + "text_EmGGUV": { + "type": "text", + "settings": { + "text": "

Free 30-day returns

", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["icon_FVd3C4", "text_EmGGUV"] + } + }, + "block_order": ["group_Hrq6NU", "group_WbpVdV"] + }, + "accordion": { + "type": "accordion", + "settings": {}, + "blocks": { + "accordion-row-1": { + "type": "_accordion-row", + "settings": { + "heading": "Materials" + }, + "blocks": { + "text": { + "type": "text" + } + }, + "block_order": ["text"] + }, + "accordion-row-2": { + "type": "_accordion-row", + "settings": { + "heading": "Care instructions" + }, + "blocks": { + "text": { + "type": "text" + } + }, + "block_order": ["text"] + }, + "accordion-row-3": { + "type": "_accordion-row", + "settings": { + "heading": "Fit" + }, + "blocks": { + "text": { + "type": "text" + } + }, + "block_order": ["text"] + } + }, + "block_order": ["accordion-row-1", "accordion-row-2", "accordion-row-3"] + }, + "complementary_products": { + "type": "product-recommendations", + "settings": { + "recommendation_type": "complementary" + }, + "blocks": { + "recommendations-header": { + "type": "text", + "settings": { + "text": "

Styled with

", + "type_preset": "h5" + } + } + }, + "block_order": ["recommendations-header"] + } + }, + "block_order": [ + "text_TMtYp8", + "heading_m7KmQQ", + "text_GMQR8L", + "price_a7krng", + "variant_picker_R3rGDr", + "buy_buttons_eYQEYi", + "group_Q4eVWb", + "accordion", + "complementary_products" + ] + } + ] +} +{% endschema %} diff --git a/blocks/_product-list-button.liquid b/blocks/_product-list-button.liquid new file mode 100644 index 000000000..c37eab72a --- /dev/null +++ b/blocks/_product-list-button.liquid @@ -0,0 +1,121 @@ +{% # import schema from '../schemas/blocks/_product-list-button' %} + +{% assign button_collection = closest.collection %} +{% assign button_url = button_collection.url %} + +{% if button_collection.products.size > section.settings.max_products %} + {% render 'button', link: button_url %} +{% endif %} + +{% schema %} +{ + "name": "t:names.product_list_button", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.visible_if_collection_has_more_products" + }, + { + "type": "text", + "id": "label", + "label": "t:settings.label", + "default": "t:text_defaults.button_label" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + }, + { + "type": "select", + "id": "style_class", + "label": "t:settings.style", + "options": [ + { + "value": "button", + "label": "t:options.primary" + }, + { + "value": "button-secondary", + "label": "t:options.secondary" + }, + { + "value": "link", + "label": "t:options.link" + } + ], + "default": "button" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width_desktop", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == \"custom\" }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == \"custom\" }}" + } + ], + "presets": [ + { + "name": "t:names.product_list_button", + "category": "t:categories.collection", + "settings": { + "label": "View all", + "style_class": "button-secondary" + } + } + ] +} +{% endschema %} diff --git a/blocks/_product-list-content.liquid b/blocks/_product-list-content.liquid new file mode 100644 index 000000000..50f17039e --- /dev/null +++ b/blocks/_product-list-content.liquid @@ -0,0 +1,456 @@ +{% # import schema from '../schemas/blocks/_product-list-content' %} + +{%- capture children -%} + {%- content_for 'blocks' -%} +{%- endcapture -%} + +{%- render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes -%} + +{% schema %} +{ + "name": "t:names.header", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "button" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + }, + { + "type": "_product-list-text" + }, + { + "type": "_product-list-button" + } + ], + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ block.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "fit", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit" + }, + { + "type": "range", + "id": "custom_height", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.group", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/_product-list-text.liquid b/blocks/_product-list-text.liquid new file mode 100644 index 000000000..6c3307157 --- /dev/null +++ b/blocks/_product-list-text.liquid @@ -0,0 +1,400 @@ +{% # import schema from '../schemas/blocks/_product-list-text' %} + +{% assign placeholder = 'content.featured_products' | t %} +{% assign placeholder = '

' | append: placeholder | append: '

' %} + +{% render 'text', fallback_text: placeholder, block: block %} + +{% schema %} +{ + "name": "t:names.collection_title", + "tag": null, + "settings": [ + { + "type": "richtext", + "id": "text", + "label": "t:settings.text", + "default": "t:html_defaults.share_information_about_your" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "fit-content" + }, + { + "type": "select", + "id": "max_width", + "label": "t:settings.max_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "normal" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width == '100%' }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "range", + "id": "corner_radius", + "label": "t:settings.corner_radius", + "default": 0, + "min": 0, + "max": 50, + "step": 1, + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collection_title", + "category": "t:categories.collection", + "settings": { + "text": "

{{ closest.collection.title }}

" + } + } + ] +} +{% endschema %} diff --git a/blocks/_product-media-gallery.liquid b/blocks/_product-media-gallery.liquid new file mode 100644 index 000000000..ae6677459 --- /dev/null +++ b/blocks/_product-media-gallery.liquid @@ -0,0 +1,906 @@ +{% # import schema from '../schemas/blocks/_product-media-gallery.js' %} + +{%- if block.settings.zoom -%} + +{%- endif -%} + +{%- liquid + assign selected_product = closest.product + assign selected_variant_media = selected_product.selected_or_first_available_variant.featured_media + assign first_3d_model = selected_product.media | where: 'media_type', 'model' | first + + if block.settings.hide_variants + assign variant_images = selected_product.media | where: 'attached_to_variant?', true | map: 'src' + endif + + if block.settings.slideshow_controls_style == 'thumbnails' + assign controls_on_media = false + else + assign controls_on_media = true + endif + + assign render_slideshow_controls = false + + if block.settings.media_presentation == 'carousel' or block.settings.slideshow_controls_style == block.settings.slideshow_mobile_controls_style + assign render_slideshow_controls = true + endif + + assign render_mobile_slideshow_controls = false + + if block.settings.slideshow_controls_style != block.settings.slideshow_mobile_controls_style + assign slideshow_controls_class = 'mobile:hidden' + + if block.settings.slideshow_mobile_controls_style != 'hint' + assign render_mobile_slideshow_controls = true + endif + endif + + assign slideshow_controls_style = block.settings.slideshow_controls_style + # Use a counter instead of dots when there are many images to avoid cropping/overflow. + if slideshow_controls_style == 'dots' and selected_product.media.size > 15 + assign slideshow_controls_style = 'counter' + endif + + assign render_slideshow_arrows = false + + if selected_product.media.size <= 1 + assign slideshow_class = 'product-media-gallery__slideshow--single-media slideshow--single-media' + else + assign slideshow_class = '' + + if block.settings.media_presentation == 'carousel' + assign render_slideshow_arrows = true + endif + endif + + if slideshow_controls_style == 'thumbnails' + assign pagination_position = block.settings.thumbnail_position + else + assign pagination_position = 'center' + endif + + # correct discrepancy between position settings for thumbnails and other controls + if pagination_position == 'bottom' + assign pagination_position = 'center' + endif + + assign icons_position = 'center' + + # Put the icons on the opposite side of the pagination controls + if block.settings.slideshow_controls_position == 'on_media' + if pagination_position == 'left' + assign icons_position = 'right' + elsif pagination_position == 'right' + assign icons_position = 'left' + endif + endif +-%} + +{%- liquid + assign sorted_media = '' | split: ',' + if selected_variant_media + assign sorted_media = sorted_media | concat: selected_product.media | where: 'id', selected_variant_media.id + + for media in selected_product.media + if block.settings.hide_variants and variant_images contains media.src and sorted_media.size > 0 + continue + endif + + if media.id != selected_variant_media.id + assign found_media = selected_product.media | where: 'id', media.id + assign sorted_media = sorted_media | concat: found_media + endif + endfor + else + assign sorted_media = selected_product.media + endif + assign has_image_drop = sorted_media | has: 'media_type', 'image' + + # Determine if we're in single column mode (carousel or grid with one column) + assign is_single_column = false + if block.settings.media_presentation == 'carousel' or sorted_media.size == 1 or block.settings.media_presentation == 'grid' and block.settings.media_columns == 'one' + assign is_single_column = true + endif + + # Check if we need both sizes (for large first image in two-column grid) + assign needs_both_sizes = false + if block.settings.media_presentation == 'grid' and block.settings.media_columns == 'two' and block.settings.large_first_image + assign needs_both_sizes = true + endif + + # Calculate sizes using utility snippet + if needs_both_sizes + # Calculate sizes for single column (first image) + capture sizes_single + render 'util-product-media-sizes-attr', block: block, section: section, settings: settings, is_first_image: true, is_single_column: true, needs_both_sizes: true + endcapture + assign sizes_single = sizes_single | strip + endif + + # Calculate sizes value for regular grid/carousel items + capture sizes + render 'util-product-media-sizes-attr', block: block, section: section, settings: settings, is_first_image: false, is_single_column: is_single_column, needs_both_sizes: needs_both_sizes + endcapture + assign sizes = sizes | strip +-%} +{%- if has_image_drop -%} + +{%- endif -%} + +{% style %} + {% unless block.settings.aspect_ratio == 'adapt' %} + .product-media-container { + --media-preview-ratio: {{ block.settings.aspect_ratio }}; + } + {% endunless %} + + {% if block.settings.aspect_ratio == 'adapt' and block.settings.constrain_to_viewport %} + .media-fit-{{ block.settings.media_fit }} { + --product-media-fit: {{ block.settings.media_fit }}; + } + + /* Media fit for all media elements */ + .media-fit-{{ block.settings.media_fit }} :is(img, video, iframe, .deferred-media__poster-image) { + object-fit: {{ block.settings.media_fit }}; + width: 100%; + height: 100%; + } + + /* 3D Models (no object-fit support, just sizing) */ + .media-fit-{{ block.settings.media_fit }} model-viewer { + width: 100%; + height: 100%; + } + {% endif %} + + {% unless block.settings.aspect_ratio == 'adapt' and block.settings.constrain_to_viewport %} + .media-fit-cover { + --product-media-fit: cover; + } + + /* Media fit for all media elements - default to cover */ + .media-fit-cover :is(img, video, iframe, .deferred-media__poster-image) { + object-fit: cover; + width: 100%; + height: 100%; + } + + /* 3D Models (no object-fit support, just sizing) */ + .media-fit-cover model-viewer { + width: 100%; + height: 100%; + } + {% endunless %} + + {% if block.settings.media_fit == 'contain' %} + /* Add background color so carousel arrows' mix-blend-mode works correctly even on transparent areas. */ + .media-fit-contain :is(img, .deferred-media__poster-image) { + background-color: var(--color-background); + } + {% endif %} +{% endstyle %} + + + {% capture slides %} + {% for media in sorted_media %} + {% capture children %} + {%- liquid + if needs_both_sizes and forloop.first + assign media_sizes = sizes_single + else + assign media_sizes = sizes + endif + -%} + {%- render 'product-media', media: media, sizes: media_sizes, is_main_product_media: forloop.first -%} + {% endcapture %} + {% capture class %} + product-media-container product-media-container--{{ media.media_type }}{% if block.settings.constrain_to_viewport %} constrain-height{% endif %}{% if block.settings.aspect_ratio == 'adapt' and block.settings.constrain_to_viewport %} media-fit-{{ block.settings.media_fit }}{% else %} media-fit-cover{% endif %}{% if block.settings.zoom %} product-media-container--zoomable{% endif %} + {% endcapture %} + {% if block.settings.aspect_ratio == 'adapt' %} + {% capture style %} + --media-preview-ratio: {{ media.preview_image.aspect_ratio | default: 1.0 }}; + {% endcapture %} + {% endif %} + {% if block.settings.zoom and media.media_type == 'model' %} + {%- capture attributes -%}"{% if settings.transition_to_main_product and forloop.first %} data-view-transition-type="product-image-transition"{% endif %}{% endcapture -%} + {% elsif block.settings.zoom %} + {%- capture attributes -%}on:click="#zoom-dialog-{{ block.id }}/open/{{ forloop.index0 }}"{% if settings.transition_to_main_product and forloop.first %} data-view-transition-type="product-image-transition"{% endif %}{% endcapture -%} + {% endif %} + + {% render 'slideshow-slide', + index: forloop.index0, + children: children, + class: class, + style: style, + attributes: attributes, + media_fit: block.settings.media_fit, + %} + {% endfor %} + {% endcapture %} + + {% if sorted_media.size > 1 %} + {% capture controls %} + {% if render_slideshow_controls %} + {%- render 'slideshow-controls', + class: slideshow_controls_class, + style: slideshow_controls_style, + item_count: sorted_media.size, + thumbnails: sorted_media, + controls_on_media: controls_on_media, + pagination_position: pagination_position, + aspect_ratio: block.settings.aspect_ratio + -%} + {% endif %} + + {% if render_mobile_slideshow_controls %} + {%- render 'slideshow-controls', + class: 'desktop:hidden media-gallery__mobile-controls', + style: block.settings.slideshow_mobile_controls_style, + item_count: sorted_media.size, + controls_on_media: true, + pagination_position: 'center', + -%} + {% endif %} + {% endcapture %} + {% endif %} + + {% if render_slideshow_arrows %} + {% capture slideshow_arrows %} + {% render 'slideshow-arrows', class: 'mobile:hidden', icon_style: block.settings.icons_style, icon_shape: settings.icons_shape %} + {% endcapture %} + {% endif %} + + {% render 'slideshow', + ref: 'slideshow', + class: slideshow_class, + slides: slides, + slide_count: sorted_media.size, + slideshow_arrows: slideshow_arrows, + arrows_position: icons_position, + controls: controls + %} + + {% if block.settings.media_presentation == 'grid' %} + + {% endif %} + + {%- if block.settings.zoom -%} + + + +
+ + {% if sorted_media.size > 1 %} + {%- for media in sorted_media -%} + {% liquid + assign aspect_ratio = block.settings.aspect_ratio + if block.settings.aspect_ratio == 'adapt' + assign aspect_ratio = media.preview_image.aspect_ratio | default: 1.0 + endif + %} + + {%- endfor -%} + {% endif %} + +
+ +
+
+ {%- endif -%} + + {%- if first_3d_model -%} + + + {%- endif -%} +
+ +{% stylesheet %} + .dialog-zoomed-gallery { + cursor: zoom-out; + } + + .dialog--preloading { + opacity: 0; + } + + .product-media__drag-zoom-wrapper { + aspect-ratio: inherit; + min-height: inherit; + min-width: inherit; + display: inherit; + flex: inherit; + } + + @media screen and (max-width: 749px) { + .dialog-zoomed-gallery { + /* Prevent scroll wheel or swipe scrolling */ + overscroll-behavior: none; + scrollbar-width: none; + display: flex; + scroll-snap-type: x mandatory; + overflow-x: hidden; + scroll-behavior: smooth; + height: 100%; + + &::-webkit-scrollbar { + display: none; + } + } + + .dialog-zoomed-gallery .product-media-container { + flex: 0 0 100%; + scroll-snap-align: start; + position: relative; + } + + .dialog-zoomed-gallery .product-media-container--image .product-media { + aspect-ratio: auto; + height: 100%; + width: 100%; + overflow: hidden; + } + + .dialog-zoomed-gallery .product-media-container--video, + .dialog-zoomed-gallery .product-media-container--external_video { + align-content: center; + } + + .dialog-zoomed-gallery + :is(.product-media-container--video, .product-media-container--external_video, .product-media-container--model) + .product-media { + aspect-ratio: auto; + align-items: center; + height: 100%; + + .product-media__image { + height: 100%; + } + } + + .product-media__drag-zoom-wrapper { + display: flex; + aspect-ratio: auto; + height: 100%; + width: 100%; + overflow: scroll; + scrollbar-width: none; + justify-content: center; + + &::-webkit-scrollbar { + display: none; + } + } + + .product-media__drag-zoom-wrapper .product-media__image { + --product-media-fit: contain; + + object-fit: var(--product-media-fit); + overflow: hidden; + transform: scale(var(--drag-zoom-scale)) + translate(var(--drag-zoom-translate-x, 0), var(--drag-zoom-translate-y, 0)); + } + + .media-gallery--hint { + --slideshow-gap: var(--gap-2xs); + + :not(.dialog-zoomed-gallery) > .product-media-container:not(:only-child) { + width: 90%; + + .product-media img { + object-fit: cover; + } + } + } + } + + .dialog-zoomed-gallery__close-button { + border-radius: 50%; + color: white; + mix-blend-mode: difference; + z-index: var(--layer-raised); + } + + .media-gallery__mobile-controls { + grid-area: auto; + } + + .dialog-zoomed-gallery .product-media-container--zoomable.product-media-container--image { + cursor: zoom-out; + } + + .product-media-container--zoomable.product-media-container--image { + cursor: zoom-in; + } + + .dialog-zoomed-gallery .product-media-container--video deferred-media, + .dialog-zoomed-gallery .product-media-container--external_video deferred-media { + height: auto; + aspect-ratio: var(--ratio); + } + + .dialog-zoomed-gallery .product-media-container--model .product-media__image { + /* Make the height match the height of the model-viewer */ + height: 100vh; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_media", + "tag": null, + "settings": [ + { + "type": "select", + "id": "media_presentation", + "label": "t:settings.type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + } + ], + "default": "grid", + "info": "t:info.carousel_layout_on_mobile" + }, + { + "type": "header", + "content": "t:content.grid", + "visible_if": "{{ block.settings.media_presentation == 'grid' }}" + }, + { + "type": "select", + "id": "media_columns", + "label": "t:settings.columns", + "options": [ + { + "value": "one", + "label": "t:options.one_number" + }, + { + "value": "two", + "label": "t:options.two_number" + } + ], + "default": "one", + "visible_if": "{{ block.settings.media_presentation == 'grid' }}" + }, + { + "type": "range", + "id": "image_gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "unit": "px", + "step": 1, + "default": 0, + "visible_if": "{{ block.settings.media_presentation == 'grid' }}" + }, + { + "type": "checkbox", + "id": "large_first_image", + "label": "t:settings.full_width_first_image", + "default": false, + "visible_if": "{{ block.settings.media_presentation == 'grid' and block.settings.media_columns == 'two' }}" + }, + { + "type": "header", + "content": "t:content.carousel" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icons", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.large_arrows" + }, + { + "value": "chevron_large", + "label": "t:options.large_chevrons" + } + ], + "default": "arrow", + "visible_if": "{{ block.settings.media_presentation == 'carousel' }}" + }, + { + "type": "select", + "id": "slideshow_controls_style", + "label": "t:settings.pagination", + "options": [ + { + "value": "dots", + "label": "t:options.dots" + }, + { + "value": "counter", + "label": "t:options.counter" + }, + { + "value": "thumbnails", + "label": "t:options.thumbnails" + } + ], + "visible_if": "{{ block.settings.media_presentation == 'carousel' }}" + }, + { + "type": "select", + "id": "slideshow_mobile_controls_style", + "label": "t:settings.mobile_pagination", + "options": [ + { + "value": "dots", + "label": "t:options.dots" + }, + { + "value": "counter", + "label": "t:options.counter" + }, + { + "value": "hint", + "label": "t:options.hint" + } + ] + }, + { + "type": "header", + "content": "t:content.thumbnails", + "visible_if": "{{ block.settings.media_presentation == 'carousel' and block.settings.slideshow_controls_style == 'thumbnails' }}" + }, + { + "type": "select", + "id": "thumbnail_position", + "label": "t:settings.position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "bottom", + "label": "t:options.bottom" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "bottom", + "visible_if": "{{ block.settings.media_presentation == 'carousel' and block.settings.slideshow_controls_style == 'thumbnails' }}" + }, + { + "type": "range", + "id": "thumbnail_width", + "label": "t:settings.width", + "min": 44, + "max": 72, + "step": 1, + "unit": "px", + "default": 64, + "visible_if": "{{ block.settings.media_presentation == 'carousel' and block.settings.slideshow_controls_style == 'thumbnails' }}" + }, + { + "type": "header", + "content": "t:content.media" + }, + { + "type": "select", + "id": "aspect_ratio", + "label": "t:settings.aspect_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "1/1.25", + "label": "t:options.portrait" + }, + { + "value": "1", + "label": "t:options.square" + }, + { + "value": "2/1", + "label": "t:options.landscape" + } + ], + "default": "adapt" + }, + { + "type": "checkbox", + "id": "constrain_to_viewport", + "label": "t:settings.limit_media_to_screen_height", + "default": false + }, + { + "type": "select", + "id": "media_fit", + "label": "t:settings.media_fit", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.aspect_ratio == 'adapt' and block.settings.constrain_to_viewport == true }}" + }, + { + "type": "range", + "id": "media_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 4 + }, + { + "type": "checkbox", + "id": "extend_media", + "label": "t:settings.extend_media_to_screen_edge", + "default": true, + "visible_if": "{{ section.settings.content_width == 'content-center-aligned' }}" + }, + { + "type": "checkbox", + "id": "zoom", + "label": "t:settings.enable_zoom", + "default": true + }, + { + "type": "checkbox", + "id": "video_loop", + "label": "t:settings.enable_video_looping", + "default": false + }, + { + "type": "checkbox", + "id": "hide_variants", + "default": false, + "label": "t:settings.hide_unselected_variant_media" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_media" + } + ] +} +{% endschema %} diff --git a/blocks/_search-input.liquid b/blocks/_search-input.liquid new file mode 100644 index 000000000..69fe6c135 --- /dev/null +++ b/blocks/_search-input.liquid @@ -0,0 +1,249 @@ +{% # import schema from '../schemas/blocks/_search-input' %} + + + +{% if block.settings.inherit_color_scheme == false %} + {% assign color_scheme = block.settings.color_scheme | prepend: ' color-' %} +{% endif %} + + + +{% stylesheet %} + .search-page-input { + width: 100%; + color: var(--color-input-text); + background-color: var(--color-input-background); + padding-block: var(--padding-lg); + padding-inline: calc(var(--icon-size-lg) + var(--margin-xl) * 1.5); + text-overflow: ellipsis; + overflow: hidden; + border-radius: var(--style-border-radius-inputs); + border: var(--style-border-width-inputs) solid var(--color-input-border); + + @media screen and (max-width: 749px) { + padding-inline: calc(var(--margin-xs) + var(--icon-size-lg) + var(--padding-md)); + } + } + + .search-page-input::placeholder { + color: rgb(var(--color-input-text-rgb) / var(--opacity-subdued-text)); + } + + .search-page-input__parent { + display: flex; + flex-direction: column; + align-items: var(--horizontal-alignment); + } + + .search-results__no-results { + opacity: var(--opacity-subdued-text); + } + + search-page-input-component { + position: relative; + width: 100%; + display: flex; + top: 0; + max-width: var(--size-style-width); + align-items: center; + background-color: var(--color-background); + margin: var(--margin-2xl) 0 var(--margin-md); + + @media screen and (max-width: 749px) { + max-width: 100%; + } + } + + search-page-input-component .search__icon, + search-page-input-component .search__icon:hover, + search-page-input-component .search__reset-button, + search-page-input-component .search__reset-button:hover { + background: transparent; + position: absolute; + top: auto; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + } + + search-page-input-component .search__icon svg, + search-page-input-component .search__reset-button svg { + width: var(--icon-size-md); + height: var(--icon-size-md); + } + + search-page-input-component .search__icon svg { + color: var(--color-input-text); + } + + search-page-input-component .search__icon { + left: var(--margin-lg); + + @media screen and (max-width: 749px) { + left: var(--margin-md); + } + } + + search-page-input-component .search__reset-button { + border-radius: 100%; + color: var(--color-input-text); + right: var(--margin-lg); + cursor: pointer; + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: opacity var(--animation-speed) var(--animation-easing), + visibility var(--animation-speed) var(--animation-easing); + + @media screen and (max-width: 749px) { + right: var(--margin-md); + } + } + + search-page-input-component:has(.search-page-input:not(:placeholder-shown)) .search__reset-button { + opacity: 1; + visibility: visible; + pointer-events: auto; + } + + search-page-input-component .search__reset-button-icon { + vertical-align: middle; + display: flex; + align-items: center; + justify-content: center; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + transition: transform var(--animation-speed) var(--animation-easing); + } + + search-page-input-component .search__reset-button:active .search__reset-button-icon { + transform: scale(0.9); + } + + search-page-input-component .search__reset-button-icon svg { + width: var(--icon-size-md); + height: var(--icon-size-md); + } + + search-page-input-component .search__reset-button--hidden { + cursor: default; + opacity: 0; + transition: opacity var(--animation-speed) var(--animation-easing); + pointer-events: none; + visibility: hidden; + } + + search-page-input-component .search__reset-button-text { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.search_input", + "tag": null, + "settings": [ + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "custom" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 50, + "visible_if": "{{ block.settings.width == \"custom\" }}" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + } + ], + "presets": [] +} +{% endschema %} diff --git a/blocks/_slide.liquid b/blocks/_slide.liquid new file mode 100644 index 000000000..54555fa90 --- /dev/null +++ b/blocks/_slide.liquid @@ -0,0 +1,500 @@ +{% # import schema from '../schemas/blocks/_slide' %} + +{%- assign block_index = section.blocks | find_index: 'id', block.id -%} +{%- assign section_index = section.index -%} + +{% capture children %} + {% liquid + assign preview_image = block.settings.image_1 + if block.settings.media_type_1 == 'video' + assign preview_image = block.settings.video_1.preview_image + endif + %} + {% if section.settings.slide_height == 'adapt_image' and block_index == 0 and preview_image != blank %} + {% + # Great example of why it can be helpful for a section to be able to read the settings of its direct child blocks. + # In this case, we want the section to be able to read the image aspect ratio of the first slide and apply it to the slideshow slides and slides. + %} + {% style %} + .shopify-section-{{ section.id }} slideshow-slides, + .shopify-section-{{ section.id }} slideshow-slide { + min-height: {{ 1 | divided_by: preview_image.aspect_ratio | times: 100 }}vw; + } + {% endstyle %} + {% endif %} + +
+ {%- if block.settings.toggle_overlay -%} + {% render 'overlay', settings: block.settings %} + {%- endif -%} + {%- if preview_image -%} + {%- liquid + assign height = preview_image.width | divided_by: preview_image.aspect_ratio | round + assign media_width_desktop = '100vw' + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign lazy_sizes = 'auto, ' | append: sizes + assign widths = '832, 1200, 1600, 1920, 2560, 3840' + %} + + {%- if block.settings.media_type_1 == 'image' -%} + {%- if block_index == 0 and section_index == 1 -%} + {{ + block.settings.image_1 + | image_url: width: 3840 + | image_tag: height: height, sizes: sizes, widths: widths, loading: 'eager', class: 'slide__image', fetchpriority: 'high' + }} + {%- else -%} + {{ + block.settings.image_1 + | image_url: width: 3840 + | image_tag: height: height, widths: widths, loading: 'lazy', class: 'slide__image', sizes: lazy_sizes + }} + {%- endif -%} + {%- else -%} + {%- if block.settings.video_1.preview_image -%} + {% liquid + assign loading_poster = 'lazy' + assign fetch_priority_poster = false + if block_index == 0 and section.index == 1 + assign loading_poster = 'eager' + assign fetch_priority_poster = 'high' + endif + %} + {{ + block.settings.video_1.preview_image + | image_url: width: 3840 + | image_tag: + height: height, + sizes: sizes, + widths: widths, + loading: loading_poster, + class: 'slide__video-poster', + fetchpriority: fetch_priority_poster + }} + {%- endif -%} + {{ + block.settings.video_1 + | video_tag: poster: nil, autoplay: true, loop: true, controls: false, muted: true, class: 'slide__video' + }} + {%- endif -%} + {%- else -%} + {%- liquid + assign modulo_result = block_index | modulo: 2 + assign placeholder_variant = 2 | minus: modulo_result + assign placeholder_name = 'hero-apparel-' | append: placeholder_variant + -%} + {{ placeholder_name | placeholder_svg_tag: 'slide__image' }} + {%- endif -%} +
+
+
+ {% content_for 'blocks' %} +
+
+{% endcapture %} + +{%- capture class -%} + {%- if block.settings.inherit_color_scheme == false -%} + color-{{ block.settings.color_scheme }} + {%- endif -%} +{%- endcapture -%} + +{% render 'slideshow-slide', + index: block_index, + class: class, + children: children, + attributes: block.shopify_attributes +%} + +{% stylesheet %} + .slide__content { + height: 100%; + position: relative; + z-index: var(--layer-flat); + } + + .slide__content > * { + margin: auto; + } + + .slide__content.background-transparent { + background-color: transparent; + } + + slideshow-slide > .slide__image-container { + display: flex; + width: 100%; + height: 100%; + overflow: hidden; + position: absolute; + } + + .slide__image-container > placeholder-image, + .slide__image-container > placeholder-image > img { + width: 100%; + } + + .slide__image-container > .slide__image, + .slide__image-container > .slide__video, + .slide__image-container > .slide__video-poster { + position: relative; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center center; + } + + .slide__image-container > .slide__video-poster { + position: absolute; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.slide", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "select", + "id": "media_type_1", + "label": "t:settings.type", + "options": [ + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "image" + }, + { + "type": "image_picker", + "id": "image_1", + "label": "t:settings.image", + "visible_if": "{{ block.settings.media_type_1 == 'image' }}" + }, + { + "type": "video", + "id": "video_1", + "label": "t:settings.video", + "visible_if": "{{ block.settings.media_type_1 == 'video' }}" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ block.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.media_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ block.settings.toggle_overlay and block.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.slide", + "settings": { + "horizontal_alignment_flex_direction_column": "center" + }, + "blocks": { + "group": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "width": "custom", + "custom_width": 50, + "width_mobile": "custom", + "inherit_color_scheme": false, + "color_scheme": "scheme-6", + "custom_width_mobile": 85, + "padding-inline-start": 48, + "padding-inline-end": 48, + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

New arrivals

" + } + }, + "text": { + "type": "text", + "settings": { + "text": "

Introducing our latest products, made especially for the season. Shop your favorites before they're gone!

", + "padding-block-end": 20 + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["heading", "text", "button"] + } + }, + "block_order": ["group"] + } + ] +} +{% endschema %} diff --git a/blocks/_social-link.liquid b/blocks/_social-link.liquid new file mode 100644 index 000000000..349ee6e19 --- /dev/null +++ b/blocks/_social-link.liquid @@ -0,0 +1,115 @@ +{% # import schema from '../schemas/blocks/_social-link.js' %} + +{% liquid + if block.settings.link != blank + # Extract domain from URL + assign platform = block.settings.link | split: '//' | last | remove: 'www.' | split: '.' | first + + # Check if URL has a profile path (more than just the domain) + assign url_parts = block.settings.link | split: '//' | last | split: '/' + assign has_profile = false + + if url_parts.size > 1 and url_parts[1] != '' + assign has_profile = true + endif + endif +%} + +{% comment %} + Only render the social icon if: + 1. In editor mode (always show, but may be disabled) + 2. On storefront AND has a valid profile link +{% endcomment %} +{% if request.design_mode or has_profile %} + +{% endif %} + +{% stylesheet %} + .social-icons__icon-wrapper { + display: flex; + align-items: center; + justify-content: center; + height: var(--icon-size-lg); + } + + .social-icons__icon { + display: flex; + fill: currentColor; + flex-shrink: 0; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + } + + .social-icons__icon { + display: none; + } + + .social-icons__icon-wrapper:has(.social-icons__icon path) { + width: var(--icon-size-lg); + + .social-icons__icon { + display: block; + } + + .social-icons__icon-label { + display: none; + } + } + + /* Disabled state for editor */ + .shopify-design-mode .social-icons__icon-wrapper--disabled { + opacity: var(--disabled-opacity, 0.5); + cursor: not-allowed; + } + + .shopify-design-mode .social-icons__icon-wrapper--disabled a { + pointer-events: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.social_link", + "tag": null, + "settings": [ + { + "type": "url", + "id": "link", + "label": "t:settings.link" + } + ], + "presets": [ + { + "name": "t:names.social_link", + "category": "t:categories.footer" + } + ] +} +{% endschema %} diff --git a/blocks/accelerated-checkout.liquid b/blocks/accelerated-checkout.liquid new file mode 100644 index 000000000..dd4d42707 --- /dev/null +++ b/blocks/accelerated-checkout.liquid @@ -0,0 +1,65 @@ +{% # import schema from '../schemas/blocks/accelerated-checkout.js' %} + +{%- doc -%} + This block is used to display the accelerated checkout button. + Intended for product-form.liquid block. + + @param {string} can_add_to_cart - Whether the product can be added to the cart + + @example + {% content_for 'block', type: 'accelerated-checkout', id: 'accelerated-checkout', can_add_to_cart: can_add_to_cart %} +{%- enddoc -%} + +{% liquid + assign product = closest.product + if request.visual_preview_mode and product == blank + assign product = collections.all.products.first + endif +%} + + + +{% stylesheet %} + .accelerated-checkout-block[data-shopify-visual-preview] { + width: 300px; + } + + more-payment-options-link { + font-size: smaller; + } + + more-payment-options-link a { + --button-color: var(--color-primary); + } + + more-payment-options-link a:hover { + --button-color: var(--color-primary-hover); + } + + .shopify-payment-button__more-options[aria-hidden='true'] { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.accelerated_checkout", + "tag": null +} +{% endschema %} diff --git a/blocks/accordion.liquid b/blocks/accordion.liquid new file mode 100644 index 000000000..5db8410a9 --- /dev/null +++ b/blocks/accordion.liquid @@ -0,0 +1,312 @@ +{% # import schema from '../schemas/blocks/accordion' %} + +
+ {% content_for 'blocks' %} +
+ +{% stylesheet %} + .accordion { + flex: 1; + width: 100%; + } + + .accordion--dividers accordion-custom:not(:first-child) .details { + border-block-start: var(--style-border-width) solid var(--color-border); + } + + /* When accordion borders are not set, show fallback borders */ + .accordion--dividers { + /* stylelint-disable-next-line declaration-property-value-disallowed-list */ + --show-fallback-borders: 0; + } + + .accordion--dividers:not([class*='color-'])[style*='--border-width: 0'], + .accordion--dividers:not([class*='color-'])[style*='--border-style: none'] { + --show-fallback-borders: 1; + } + + .accordion--dividers accordion-custom:first-child .details { + border-block-start: calc(var(--style-border-width) * var(--show-fallback-borders)) solid var(--color-border); + } + + .accordion--dividers accordion-custom:last-child .details { + border-block-end: calc(var(--style-border-width) * var(--show-fallback-borders)) solid var(--color-border); + } + + .accordion--dividers .details-content { + padding-block-end: var(--padding-sm); + } + + .accordion--caret .icon-plus, + .accordion--plus .icon-caret { + display: none; + } + + /* because we can't pass apply a specific class on a block based on its parent block setting */ + .accordion .details__header { + font-family: var(--summary-font-family); + font-style: var(--summary-font-style); + font-weight: var(--summary-font-weight); + font-size: var(--summary-font-size); + line-height: var(--summary-font-line-height); + text-transform: var(--summary-font-case); + min-height: var(--minimum-touch-target); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.accordion", + "tag": null, + "class": "accordion", + "blocks": [ + { + "type": "_accordion-row" + } + ], + "settings": [ + { + "type": "select", + "id": "icon", + "label": "t:settings.icon", + "options": [ + { + "value": "caret", + "label": "t:options.caret" + }, + { + "value": "plus", + "label": "t:options.plus" + } + ], + "default": "caret" + }, + { + "type": "checkbox", + "id": "dividers", + "label": "t:settings.dividers", + "default": true + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.heading_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "h6", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != \"none\" }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != \"none\" }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.accordion", + "category": "t:categories.layout", + "blocks": { + "row-1": { + "type": "_accordion-row", + "settings": { + "open_by_default": true, + "heading": "Return policy" + }, + "blocks": { + "text-1": { + "type": "text", + "settings": { + "text": "

Our goal is for every customer to be totally satisfied with their purchase. If this isn't the case, let us know and we'll do our best to work with you to make it right.

", + "width": "100%" + } + } + }, + "block_order": ["text-1"] + }, + "row-2": { + "type": "_accordion-row", + "settings": { + "heading": "Shipping" + }, + "blocks": { + "text-1": { + "type": "text", + "settings": { + "text": "

We will work quickly to ship your order as soon as possible. Once your order has shipped, you will receive an email with further information. Delivery times vary depending on your location.

", + "width": "100%" + } + } + }, + "block_order": ["text-1"] + }, + "row-3": { + "type": "_accordion-row", + "settings": { + "heading": "Manufacturing" + }, + "blocks": { + "text-1": { + "type": "text", + "settings": { + "text": "

Our products are manufactured both locally and globally. We carefully select our manufacturing partners to ensure our products are high quality and a fair value.

", + "width": "100%" + } + } + }, + "block_order": ["text-1"] + } + }, + "block_order": ["row-1", "row-2", "row-3"] + } + ] +} +{% endschema %} diff --git a/blocks/add-to-cart.liquid b/blocks/add-to-cart.liquid new file mode 100644 index 000000000..0d3ac06ee --- /dev/null +++ b/blocks/add-to-cart.liquid @@ -0,0 +1,52 @@ +{% # import schema from '../schemas/blocks/add-to-cart.js' %} + +{%- doc -%} + This block is used to display the add to cart button. + Intended for product-form.liquid block. + + @param {string} can_add_to_cart - Whether the product can be added to the cart + @param {string} add_to_cart_text - The text of the add to cart button +{%- enddoc -%} + +{% liquid + assign class = 'add-to-cart-button ' | append: block.settings.style_class + assign id = 'BuyButtons-ProductSubmitButton-' | append: block.id +%} + + + {% render 'add-to-cart-button', + id: id, + class: class, + can_add_to_cart: can_add_to_cart, + product: closest.product, + add_to_cart_text: add_to_cart_text + %} + + +{% schema %} +{ + "name": "t:names.add_to_cart", + "tag": null, + "settings": [ + { + "type": "select", + "id": "style_class", + "label": "t:settings.style", + "options": [ + { + "value": "button", + "label": "t:options.primary" + }, + { + "value": "button-secondary", + "label": "t:options.secondary" + } + ], + "default": "button-secondary" + } + ] +} +{% endschema %} diff --git a/blocks/button.liquid b/blocks/button.liquid new file mode 100644 index 000000000..4fd4b2d98 --- /dev/null +++ b/blocks/button.liquid @@ -0,0 +1,115 @@ +{% # import schema from '../schemas/blocks/button' %} +{% render 'button', link: block.settings.link %} + +{% schema %} +{ + "name": "t:names.button", + "tag": null, + "settings": [ + { + "type": "text", + "id": "label", + "label": "t:settings.label", + "default": "t:text_defaults.button_label" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + }, + { + "type": "select", + "id": "style_class", + "label": "t:settings.style", + "options": [ + { + "value": "button", + "label": "t:options.primary" + }, + { + "value": "button-secondary", + "label": "t:options.secondary" + }, + { + "value": "link", + "label": "t:options.link" + } + ], + "default": "button" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width_desktop", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == \"custom\" }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == \"custom\" }}" + } + ], + "presets": [ + { + "name": "t:names.button", + "category": "t:categories.basic", + "settings": { + "link": "shopify://collections/all" + } + } + ] +} +{% endschema %} diff --git a/blocks/buy-buttons.liquid b/blocks/buy-buttons.liquid new file mode 100644 index 000000000..e06bfcecc --- /dev/null +++ b/blocks/buy-buttons.liquid @@ -0,0 +1,475 @@ +{% # import schema from '../schemas/blocks/buy-buttons.js' %} +{% liquid + assign product = closest.product + if request.visual_preview_mode and product == blank + assign product = collections.all.products.first + endif + + assign variant = closest.product.selected_or_first_available_variant + assign inventory_quantity = variant.inventory_quantity + assign inventory_policy = variant.inventory_policy + + if variant.inventory_management == 'shopify' + assign inventory_managed = true + endif + + if variant.quantity_rule.min > variant.inventory_quantity and inventory_managed and inventory_policy == 'deny' + assign quantity_rule_soldout = true + endif + + if inventory_managed + if inventory_quantity <= 0 and inventory_policy == 'deny' or quantity_rule_soldout + assign can_add_to_cart = false + assign add_to_cart_text = 'products.product.sold_out' | t + else + assign can_add_to_cart = true + assign add_to_cart_text = 'products.product.add_to_cart' | t + endif + else + if closest.product.selected_or_first_available_variant != null + assign can_add_to_cart = true + assign add_to_cart_text = 'products.product.add_to_cart' | t + else + assign can_add_to_cart = false + assign add_to_cart_text = 'products.product.unavailable' | t + endif + endif +%} + + + {%- if product != blank -%} + {%- assign product_form_id = 'BuyButtons-ProductForm-' | append: block.id -%} + +
+ {%- form 'product', product, id: product_form_id, novalidate: 'novalidate', data-type: 'add-to-cart-form' -%} + +
+ {% content_for 'block', type: 'quantity', id: 'quantity' %} + + {% content_for 'block', + type: 'add-to-cart', + id: 'add-to-cart', + can_add_to_cart: can_add_to_cart, + add_to_cart_text: add_to_cart_text + %} + + {% content_for 'block', + type: 'accelerated-checkout', + id: 'accelerated-checkout', + can_add_to_cart: can_add_to_cart + %} +
+ {%- endform -%} +
+ {%- else -%} +
+ +
+ {%- endif -%} +
+ +{% if block.settings.show_pickup_availability %} + + + {%- assign pick_up_availabilities = closest.product.selected_or_first_available_variant.store_availabilities + | where: 'pick_up_enabled', true + -%} + + +{% endif %} + +{% stylesheet %} + .buy-buttons-block { + width: 100%; + } + + .product-form-buttons { + display: flex; + flex-wrap: wrap; + gap: calc(var(--gap-sm) / 2); + + @media screen and (min-width: 750px) { + gap: var(--gap-sm); + } + } + + .product-form-buttons > *:not(.quantity-selector) { + flex: 1; + min-width: 185px; + } + + .product-form-buttons--stacked > *:not(.quantity-selector) { + flex-basis: 51%; /* Force the buttons to be on separate rows */ + } + + .quantity-selector { + flex-grow: 0; + } + + .product-form-buttons button { + width: 100%; + padding-inline: var(--padding-4xl); + padding-block: var(--padding-lg); + } + + .add-to-cart-button { + text-transform: var(--button-text-case-primary); + } + + .add-to-cart-button.button-secondary { + text-transform: var(--button-text-case-secondary); + } + + .product-form-buttons .shopify-payment-button__button { + width: 100%; + min-height: var(--minimum-touch-target); + } + + .quantity-selector, + .add-to-cart-button { + height: var(--height-buy-buttons); + } + + .product__pickup-availabilities { + width: 100%; + } + + .pickup-availability__column { + display: flex; + flex-direction: column; + justify-content: flex-start; + } + + .pickup-availability__row { + display: flex; + gap: var(--padding-xs); + } + + .pickup-availability__dialog-row { + display: flex; + justify-content: space-between; + align-items: flex-start; + } + + .pickup-availability__header-container { + padding-block-end: var(--padding-2xl); + } + + .pickup-location__wrapper { + display: flex; + flex-direction: column; + padding-block: var(--padding-2xl); + border-top: 1px solid var(--color-border); + gap: var(--padding-xs); + } + + .pickup-location__address-wrapper { + display: flex; + flex-direction: column; + gap: var(--padding-md); + } + + .pickup-location__dialog { + padding: var(--padding-2xl); + position: fixed; + border-radius: 0; + width: var(--sidebar-width); + max-width: 95vw; + height: 100%; + margin: 0 0 0 auto; + border: var(--style-border-drawer); + box-shadow: var(--shadow-drawer); + background-color: var(--color-background); + } + + .pickup-location__dialog:modal { + max-height: 100dvh; + } + + .pickup-location__text-sm { + font-size: var(--font-size--sm); + margin: 0; + } + + .pickup-location__text-xs { + font-size: var(--font-size--xs); + margin: 0; + } + + .product-form-text__error { + display: flex; + align-items: flex-start; + gap: var(--gap-xs); + } + + .pickup-location__button { + width: fit-content; + color: var(--color-primary); + font-size: var(--font-size--xs); + font-family: var(--font-body--family); + padding: 0; + cursor: pointer; + margin-block: var(--margin-xs); + } + + .pickup-location__button:hover { + color: var(--color-primary-hover); + } + + .pickup-location__h4 { + margin: 0; + } + + .pickup-location__text-bold { + font-size: var(--font-size--md); + font-weight: 600; + margin: 0; + } + + .pickup-location__availability-wrapper { + display: flex; + align-items: center; + gap: var(--gap-xs); + font-family: var(--font-paragraph--family); + } + + .pickup-location__address { + font-style: normal; + } + + .pickup-location__close-button { + position: absolute; + top: calc(var(--padding-2xl) - (var(--icon-size-xs) / 2)); + right: calc(var(--padding-2xl) - var(--icon-size-xs)); + height: var(--minimum-touch-target); + width: var(--minimum-touch-target); + } + + .pickup-location__close-button svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_buy_buttons", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product" + }, + { + "type": "checkbox", + "id": "stacking", + "label": "t:settings.always_stack_buttons", + "default": false + }, + { + "type": "checkbox", + "id": "show_pickup_availability", + "label": "t:settings.show_pickup_availability", + "default": true + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_buy_buttons", + "category": "t:categories.product", + "blocks": { + "quantity": { + "type": "quantity", + "static": true + }, + "add-to-cart": { + "type": "add-to-cart", + "static": true, + "settings": { + "style_class": "button-secondary" + } + }, + "accelerated-checkout": { + "type": "accelerated-checkout", + "static": true + } + } + } + ] +} +{% endschema %} diff --git a/blocks/collection-card.liquid b/blocks/collection-card.liquid new file mode 100644 index 000000000..0b4aae882 --- /dev/null +++ b/blocks/collection-card.liquid @@ -0,0 +1,220 @@ +{% # import schema from '../schemas/blocks/collection-card' %} + +{% assign collection = block.settings.collection %} + +{% style %} + {% if request.visual_preview_mode %} + .collection-card { + min-width: 250px; + } + {% endif %} +{% endstyle %} + +{% capture card_image %} + {% content_for 'block', + type: '_collection-card-image', + id: 'collection-card-image', + closest.collection: collection, + parent_block_id: block.id %} +{% endcapture %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'collection-card', + card_image: card_image, + children: children, + block: block, + collection: collection, + section: section +%} + +{% schema %} +{ + "name": "t:names.collection_card", + "blocks": [ + { + "type": "text" + }, + { + "type": "spacer" + }, + { + "type": "button" + }, + { + "type": "group" + }, + { + "type": "collection-title" + } + ], + "tag": null, + "settings": [ + { + "type": "collection", + "id": "collection", + "label": "t:settings.collection" + }, + { + "type": "header", + "content": "t:content.text" + }, + { + "type": "select", + "id": "placement", + "label": "t:settings.placement", + "options": [ + { + "value": "on_image", + "label": "t:options.on_image" + }, + { + "value": "below_image", + "label": "t:options.below_image" + } + ] + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.placement == \"on_image\" }}" + }, + { + "type": "range", + "id": "collection_card_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collection_card", + "category": "t:categories.collection", + "settings": { + "collection": "", + "placement": "below_image" + }, + "blocks": { + "collection-card-image": { + "type": "_collection-card-image", + "static": true + }, + "collection-title": { + "type": "collection-title", + "settings": { + "type_preset": "h4" + } + } + }, + "block_order": ["collection-title"] + } + ] +} +{% endschema %} diff --git a/blocks/collection-title.liquid b/blocks/collection-title.liquid new file mode 100644 index 000000000..04d34feb2 --- /dev/null +++ b/blocks/collection-title.liquid @@ -0,0 +1,399 @@ +{% # import schema from '../schemas/blocks/collection-title' %} + +{% if closest.collection == blank %} + {% assign text = 'placeholders.collection_title' | t %} + {% assign collection_title = '

' | append: text | append: '

' %} + {% render 'text', fallback_text: collection_title, block: block %} +{% elsif closest.collection != blank %} + {% assign collection_title = '

' | append: closest.collection.title | append: '

' %} + {% render 'text', fallback_text: collection_title, block: block %} +{% endif %} + +{% schema %} +{ + "name": "t:names.collection_title", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_collection_title" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "fit-content" + }, + { + "type": "select", + "id": "max_width", + "label": "t:settings.max_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "normal" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width == '100%' }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "range", + "id": "corner_radius", + "label": "t:settings.corner_radius", + "default": 0, + "min": 0, + "max": 50, + "step": 1, + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collection_title", + "category": "t:categories.collection" + } + ] +} +{% endschema %} diff --git a/blocks/contact-form-submit-button.liquid b/blocks/contact-form-submit-button.liquid new file mode 100644 index 000000000..9da867d55 --- /dev/null +++ b/blocks/contact-form-submit-button.liquid @@ -0,0 +1,106 @@ +{% # import schema from '../schemas/blocks/contact-form-submit-button' %} + + + +{% stylesheet %} + .submit-button { + min-width: max-content; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.submit_button", + "tag": null, + "settings": [ + { + "type": "text", + "id": "label", + "label": "t:settings.label", + "default": "t:text_defaults.contact_form_button_label" + }, + { + "type": "select", + "id": "style_class", + "label": "t:settings.style", + "options": [ + { + "value": "button", + "label": "t:options.primary" + }, + { + "value": "button-secondary", + "label": "t:options.secondary" + } + ], + "default": "button" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width_desktop", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + } + ], + "presets": [] +} +{% endschema %} diff --git a/blocks/contact-form.liquid b/blocks/contact-form.liquid new file mode 100644 index 000000000..b1029b0ed --- /dev/null +++ b/blocks/contact-form.liquid @@ -0,0 +1,133 @@ +{% # import schema from '../schemas/blocks/contact-form' %} + +{% capture submit_button %} + {% content_for 'block', type: 'contact-form-submit-button', id: 'submit-button' %} +{% endcapture %} + +{% render 'contact-form', settings: block.settings, submit_button: submit_button %} + +{% schema %} +{ + "name": "t:names.contact_form", + "tag": null, + "settings": [ + { + "type": "select", + "id": "width", + "label": "t:settings.width_desktop", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit-content" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.contact_form", + "category": "t:categories.forms" + } + ] +} +{% endschema %} diff --git a/blocks/custom-liquid.liquid b/blocks/custom-liquid.liquid new file mode 100644 index 000000000..d33b0e9d6 --- /dev/null +++ b/blocks/custom-liquid.liquid @@ -0,0 +1,26 @@ +{% # import schema from '../schemas/blocks/custom-liquid' %} + +
+ {{ block.settings.custom_liquid }} +
+ +{% schema %} +{ + "name": "t:names.custom_liquid", + "tag": null, + "settings": [ + { + "type": "liquid", + "id": "custom_liquid", + "label": "t:settings.custom_liquid", + "info": "t:info.custom_liquid" + } + ], + "presets": [ + { + "name": "t:names.custom_liquid", + "category": "t:categories.custom" + } + ] +} +{% endschema %} diff --git a/blocks/email-signup.liquid b/blocks/email-signup.liquid new file mode 100644 index 000000000..71b015b88 --- /dev/null +++ b/blocks/email-signup.liquid @@ -0,0 +1,569 @@ +{% # import schema from '../schemas/blocks/email-signup' %} + + + +{% stylesheet %} + .email-signup-block { + @media screen and (max-width: 749px) { + width: 100%; + } + } + + .email-signup__form { + display: flex; + flex-direction: column; + } + + .email-signup__input-group { + position: relative; + display: grid; + grid-template-columns: 1fr auto; + background-color: transparent; + } + + .email-signup__input-group:not(:has(.email-signup__button--integrated)) { + gap: var(--gap-xs); + } + + .email-signup__input-group:not(:has(.email-signup__button--arrow)) { + @media screen and (max-width: 749px) { + grid-template-columns: 1fr; + } + } + + .email-signup__input { + width: 100%; + border-width: var(--border-width); + border-radius: var(--border-radius); + border-style: solid; + border-color: var(--color-input-border); + } + + .email-signup__input.paragraph { + color: var(--color-input-text); + outline-color: var(--color-input-background); + } + + .email-signup__button { + white-space: nowrap; + padding: 0; + + @media screen and (max-width: 749px) { + width: 100%; + } + } + + .email-signup__input, + .email-signup__button--text { + padding: var(--padding-lg) var(--padding-3xl); + } + + .email-signup__input-group .email-signup__input--underline { + --box-shadow-color: var(--color-input-border); + --box-shadow-multiplier: 1; + + color: var(--color-input-text); + background-color: transparent; + padding: 12px 0; + border: none; + border-radius: 0; + box-shadow: 0 calc(var(--border-width) * var(--box-shadow-multiplier)) 0 var(--box-shadow-color); + transition: box-shadow var(--animation-values); + + &:focus-visible { + --box-shadow-multiplier: 1.75; + --box-shadow-color: var(--color-input-text); + + outline: none; + } + } + + .email-signup__input::placeholder { + color: rgb(var(--color-input-text-rgb) / var(--opacity-70)); + } + + .email-signup__input-group .email-signup__input--none { + color: var(--color-input-text); + background-color: var(--color-input-background); + border: none; + } + + .email-signup__input:has(+ .email-signup__button--arrow), + .email-signup__input:has(+ .email-signup__button--integrated) { + @media screen and (max-width: 749px) { + text-align: left; + } + } + + .email-signup__button-icon { + fill: currentcolor; + padding: 5px; + + @media screen and (max-width: 749px) { + padding: 0; + align-self: center; + justify-self: center; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + } + } + + .email-signup__button--arrow { + aspect-ratio: 1; + padding-inline: var(--padding-xs); + + &:not(.email-signup__button--integrated) { + width: auto; + } + } + + .email-signup__button--integrated { + --button-offset: var(--margin-xs); + + position: absolute; + height: calc(100% - (var(--button-offset) * 2) - (var(--border-width) * 2)); + right: calc(var(--button-offset) + var(--border-width)); + top: calc(var(--button-offset) + var(--border-width)); + + @media screen and (max-width: 749px) { + width: fit-content; + } + + &.email-signup__button--text { + padding: 0 var(--padding-3xl); + } + + &.email-signup__button--text.button-unstyled { + padding: 0 var(--padding-xl); + } + + &.button-unstyled { + border-radius: var(--border-radius); + } + + > .email-signup__button-icon { + padding: 0; + } + } + + .email-signup__input--underline + .email-signup__button--integrated { + --button-offset: calc(10% - var(--border-width)); + + right: 0; + + &.email-signup__button--text.button-unstyled { + padding: 0; + } + + &.button-unstyled { + border-radius: 0; + } + } + + .email-signup__button:not(.button-unstyled) { + background-color: var(--button-background-color); + color: var(--button-color); + font-weight: var(--button-font-weight-primary); + text-transform: var(--button-text-case-primary); + } + + .email-signup__button.button-secondary { + font-weight: var(--button-font-weight-secondary); + text-transform: var(--button-text-case-secondary); + } + + .email-signup__button.button-unstyled { + background-color: transparent; + color: var(--color-input-text); + } + + .email-signup__button.button-unstyled:hover { + color: rgb(var(--color-input-text-rgb) / var(--opacity-70)); + cursor: pointer; + } + + .email-signup__message { + display: flex; + align-items: center; + gap: var(--gap-xs); + } + + .email-signup__message-text { + margin: 0; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.email_signup", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.email_signups_create_customer_profiles" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == \"custom\" }}" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "primary", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.input" + }, + { + "type": "select", + "id": "border_style", + "label": "t:settings.border", + "options": [ + { + "value": "all", + "label": "t:options.all" + }, + { + "value": "underline", + "label": "t:options.underline" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "all" + }, + { + "type": "range", + "id": "border_width", + "label": "t:settings.border_width", + "min": 0, + "max": 4, + "step": 0.5, + "unit": "px", + "default": 1, + "visible_if": "{{ block.settings.border_style != \"none\" }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 100, + "visible_if": "{{ block.settings.border_style != \"underline\" }}" + }, + { + "type": "select", + "id": "input_type_preset", + "label": "t:settings.type_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "paragraph", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "header", + "content": "t:content.submit_button" + }, + { + "type": "select", + "id": "style_class", + "label": "t:settings.style", + "options": [ + { + "value": "button", + "label": "t:options.primary" + }, + { + "value": "button-secondary", + "label": "t:options.secondary" + }, + { + "value": "button-unstyled", + "label": "t:options.link" + } + ], + "default": "button" + }, + { + "type": "select", + "id": "display_type", + "label": "t:settings.display", + "options": [ + { + "value": "text", + "label": "t:options.text" + }, + { + "value": "arrow", + "label": "t:options.arrow" + } + ], + "default": "text" + }, + { + "type": "text", + "id": "label", + "label": "t:settings.label", + "default": "t:text_defaults.sign_up", + "visible_if": "{{ block.settings.display_type == \"text\" }}" + }, + { + "type": "checkbox", + "id": "integrated_button", + "label": "t:settings.integrated_button", + "default": false, + "visible_if": "{{ block.settings.border_style != \"underline\" }}" + }, + { + "type": "select", + "id": "button_type_preset", + "label": "t:settings.type_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "paragraph", + "info": "t:info.edit_presets_in_theme_settings", + "visible_if": "{{ block.settings.display_type == \"text\" }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.email_signup", + "category": "t:categories.forms" + } + ] +} +{% endschema %} diff --git a/blocks/featured-collection.liquid b/blocks/featured-collection.liquid new file mode 100644 index 000000000..7e6b82089 --- /dev/null +++ b/blocks/featured-collection.liquid @@ -0,0 +1,31 @@ +{% # import schema from '../schemas/blocks/featured-collection.js' %} + + + +{% schema %} +{ + "name": "t:names.featured_collection", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "collection", + "id": "collection", + "label": "t:settings.collection" + } + ], + "presets": [] +} +{% endschema %} diff --git a/blocks/filters.liquid b/blocks/filters.liquid new file mode 100644 index 000000000..49f522cae --- /dev/null +++ b/blocks/filters.liquid @@ -0,0 +1,1236 @@ +{% # import schema from '../schemas/blocks/filters' %} +{%- doc -%} + Renders the facet filtering component + + @param {object} results - The search results object + @param {number} results_size - The number of products in the search results + @param {object} [filters] - The filters object +{%- enddoc -%} + + + +{%- liquid + assign products_count = results_size + assign sort_by = results.sort_by | default: results.default_sort_by + assign filters = filters | default: results.filters + assign total_active_values = 0 + + # Calculate facets margin style + capture facets_margin_style + echo '--facets-margin: 0px ' + if block.settings.filter_style == 'vertical' + echo block.settings.facets_margin_right | append: 'px' | append: ' 0px' + else + echo ' 0px ' | append: block.settings.facets_margin_bottom | append: 'px' + endif + echo ' 0px;' + endcapture + + for filter in filters + case filter.type + when 'price_range' + if filter.min_value.value != null or filter.max_value.value != null + assign total_active_values = total_active_values | plus: 1 + endif + when 'boolean' + if filter.active_values[0].value + assign total_active_values = total_active_values | plus: 1 + endif + else + assign active_value_count = filter.active_values | size + assign total_active_values = total_active_values | plus: active_value_count + endcase + endfor + + if results.url + assign results_url = results.url + else + assign terms = results.terms | escape + assign results_url = '?q=' | append: terms | append: '&options%5Bprefix%5D=last&sort_by=' | append: sort_by + endif + + assign is_active = false + assign should_show_pane = true + if block.settings.filter_style == 'vertical' + assign should_show_pane = block.settings.enable_filtering + endif + + assign should_use_select_on_mobile = true + if block.settings.enable_filtering == false and block.settings.enable_sorting + assign should_use_select_on_mobile = false + endif + + assign should_show_vertical_clear_all = true + if block.settings.filter_style == 'vertical' + assign should_show_vertical_clear_all = false + endif +-%} + +{% if block.settings.enable_filtering or block.settings.enable_sorting or block.settings.enable_grid_density %} + {% if block.settings.filter_style == 'vertical' %} + {% # These elements are always rendered in the horizontal bar that's why we apply the .facets--horizontal class %} +
+ {% if block.settings.enable_filtering %} +

{{ 'content.filters' | t }}

+ {% endif %} + +
+ + {{- 'content.item_count' | t: count: products_count -}} + +
+ + {% if block.settings.enable_sorting %} + {% render 'sorting', + results: results, + sort_by: sort_by, + filter_style: block.settings.filter_style, + suffix: 'desktop', + sort_position: 'desktop', + should_use_select_on_mobile: false, + section_id: section.id + %} + {% endif %} + + {% if block.settings.enable_grid_density %} + {% render 'grid-density-controls', viewport: 'desktop' %} + {% endif %} +
+ {% endif %} + + + +
+ {% if block.settings.enable_filtering %} +
+ +
+ {% endif %} + +
+ {% if block.settings.enable_filtering == false and block.settings.enable_sorting %} + +
+ {% render 'sorting', + results: results, + sort_by: sort_by, + filter_style: block.settings.filter_style, + sort_position: 'mobile', + should_use_select_on_mobile: should_use_select_on_mobile, + section_id: section.id + %} +
+
+ {% endif %} + {% if block.settings.enable_grid_density %} + {% render 'grid-density-controls', viewport: 'mobile' %} + {% endif %} +
+
+{% else %} +
+{% endif %} + +{% if block.settings.enable_filtering %} + + + {% assign form_component = 'FacetFiltersFormComponent--' | append: section.id | append: '-overflow' %} + + +
+
+

+ {{ 'blocks.filter' | t }} + + {% if total_active_values > 0 %} + + + {{ 'accessibility.filter_count' | t: count: total_active_values }} + + {% endif %} +

+ +
+ + {% if block.settings.enable_filtering %} + {% render 'filter-remove-buttons', + filters: filters, + results_url: results_url, + show_filter_label: block.settings.show_filter_label, + should_show_clear_all: false + %} + +
+ {% assign total_active_values = 0 %} + {% assign is_active = false %} + + {%- for filter in filters -%} + {%- liquid + assign should_autofocus = false + if forloop.first and total_active_values == 0 + assign should_autofocus = true + endif + %} + {% case filter.type %} + {% when 'price_range' %} + {%- liquid + if filter.min_value.value != null or filter.max_value.value != null + assign total_active_values = total_active_values | plus: 1 + assign is_active = true + endif + + render 'price-filter', filter: filter, filter_style: 'vertical', should_render_clear: false, autofocus: should_autofocus + -%} + {% else %} + {% liquid + if filter.active_values.size > 0 + assign is_active = true + endif + + assign active_value_count = filter.active_values | size + assign total_active_values = total_active_values | plus: active_value_count + render 'list-filter', filter: filter, filter_style: 'vertical', active_value_count: active_value_count, should_render_clear: false, autofocus: should_autofocus, in_drawer: true, sectionId: section.id + %} + {% endcase %} + {%- endfor -%} +
+ {% endif %} + + {% if block.settings.enable_sorting %} + {% render 'sorting', + results: results, + sort_by: sort_by, + filter_style: block.settings.filter_style, + suffix: 'overflow', + should_use_select_on_mobile: should_use_select_on_mobile, + section_id: section.id + %} + {% endif %} +
+
+ + {% render 'facets-actions', + results_url: results_url, + is_active: is_active, + products_count: products_count, + form_component: form_component, + should_show_clear_all: true + %} +
+
+{% endif %} + +{% stylesheet %} + .collection-wrapper { + @media screen and (min-width: 750px) { + --facets-vertical-col-width: 6; + } + + @media screen and (min-width: 990px) { + --facets-vertical-col-width: 5; + } + } + + .facets-block-wrapper { + @media screen and (min-width: 750px) { + margin: var(--facets-margin); + grid-column: var(--grid-column--desktop); + } + } + + .facets-block-wrapper--vertical { + @media screen and (min-width: 750px) { + grid-column: var(--grid-column--desktop); + } + } + + .facets-block-wrapper--vertical + .facets-toggle { + @media screen and (max-width: 749px) { + margin: 0; + } + } + + .facets-mobile-wrapper { + display: flex; + align-items: center; + gap: var(--gap-sm); + justify-content: flex-end; + } + + .facets-mobile-wrapper:has(> :nth-child(2)) { + justify-content: space-between; + } + + dialog-component.facets-block-wrapper:not(:has(.facets--drawer[open])) { + @media screen and (min-width: 750px) { + display: none; + } + } + + .variant-option__swatch-wrapper { + position: relative; + overflow: visible; + border-radius: var(--options-border-radius); + } + + .variant-option--swatches-disabled .variant-option__swatch-wrapper { + overflow: hidden; + } + + .facets { + --facets-form-horizontal-gap: 20px; + --facets-horizontal-max-input-wrapper-height: 230px; + --facets-upper-z-index: var(--layer-raised); + --facets-open-z-index: var(--layer-heightened); + --facets-sticky-z-index: var(--layer-sticky); + --facets-panel-min-width: 120px; + --facets-panel-height: 300px; + --facets-grid-panel-width: 300px; + --facets-clear-padding: var(--padding-md); + --facets-clear-shadow: 0 -4px 14px 0 rgb(var(--color-foreground-rgb) / var(--facets-low-opacity)); + --facets-input-label-color: rgb(var(--color-input-text-rgb) / var(--opacity-60)); + --facets-clear-all-min-width: 120px; + --facets-see-results-min-width: 55%; + --facets-mobile-gap: 22px; + --facets-low-opacity: 10%; + --facets-hover-opacity: 75%; + + top: auto; + bottom: 0; + height: var(--drawer-height); + max-height: var(--drawer-height); + width: var(--drawer-width); + max-width: var(--drawer-max-width); + box-shadow: none; + padding-block: 0; + + &:not(.facets--drawer) { + @media screen and (min-width: 750px) { + padding-inline: var(--padding-inline-start) var(--padding-inline-end); + width: 100%; + max-width: 100%; + } + } + } + + .facets--horizontal { + display: none; + + @media screen and (min-width: 750px) { + padding-block: var(--padding-block-start) var(--padding-block-end); + display: flex; + align-items: center; + position: relative; + z-index: var(--facets-upper-z-index); + border: none; + height: auto; + top: initial; + bottom: initial; + max-height: none; + width: auto; + overflow: visible; + } + } + + .facets--vertical { + display: none; + + @media screen and (min-width: 750px) { + padding-block: 0 var(--padding-block-end); + display: block; + position: static; + top: auto; + bottom: auto; + height: auto; + max-height: none; + width: auto; + overflow: visible; + } + } + + .collection-wrapper:has(.collection-wrapper--full-width) .facets--vertical:not(.facets--drawer) { + @media screen and (min-width: 750px) { + padding-inline-start: max(var(--padding-sm), var(--padding-inline-start)); + } + } + + .facets--drawer { + border-radius: 0; + border-right: var(--style-border-drawer); + box-shadow: var(--shadow-drawer); + padding-inline: 0; + } + + .facets--drawer[open] { + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .facets.facets-controls-wrapper { + @media screen and (min-width: 750px) { + grid-column: column-1 / column-12; + color: rgb(var(--color-foreground-rgb) / var(--opacity-70)); + gap: 0 var(--facets-form-horizontal-gap); + padding-bottom: var(--padding-xs); + } + } + + .collection-wrapper:has(.product-grid-mobile--large) .facets-mobile-wrapper.facets-controls-wrapper { + @media screen and (max-width: 749px) { + display: none; + } + } + + .facets__inputs { + display: flex; + flex-direction: column; + gap: var(--padding-lg); + width: 100%; + } + + :is(.facets--drawer, .facets--vertical) .facets__inputs:not(:has(.show-more)) { + padding-block-end: var(--padding-sm); + } + + /* Facets - Form */ + .facets__form-wrapper { + display: flex; + flex-direction: column; + color: var(--color-foreground-muted); + width: 100%; + } + + .facets--horizontal .facets__form-wrapper { + @media screen and (min-width: 750px) { + flex-direction: row; + height: auto; + } + } + + .facets__form { + display: flex; + flex-flow: column; + width: 100%; + height: 100%; + } + + .facets--horizontal .facets__form { + @media screen and (min-width: 750px) { + flex-flow: row nowrap; + height: auto; + } + } + + .facets:not(.facets--drawer) .facets__filters-wrapper { + @media screen and (min-width: 750px) { + margin-inline-end: var(--margin-md); + } + } + + .facets--horizontal .facets__filters-wrapper { + @media screen and (min-width: 750px) { + max-width: 60%; + display: flex; + flex-wrap: wrap; + column-gap: var(--gap-xl); + margin-inline-end: 0; + } + } + + /* Facets - Summary */ + .facets__summary { + --variant-picker-swatch-width: 32px; + --variant-picker-swatch-height: 32px; + --icon-opacity: 0.5; + + @media screen and (min-width: 750px) { + --variant-picker-swatch-width: 26px; + --variant-picker-swatch-height: 26px; + } + + font-size: var(--font-h4--size); + display: flex; + justify-content: space-between; + + &:hover { + --icon-opacity: 1; + } + } + + .facets__filters-wrapper:hover .facets__summary, + .facets__filters-wrapper:has(.facets__panel[open]) .facets__summary { + opacity: var(--facets-hover-opacity); + } + + .facets__filters-wrapper .facets__summary:hover, + .facets__filters-wrapper .facets__panel[open] .facets__summary { + opacity: 1; + } + + .facets--horizontal .facets__summary { + @media screen and (min-width: 750px) { + font-size: var(--font-paragraph--size); + justify-content: flex-start; + height: var(--minimum-touch-target); + } + } + + .facets__summary .icon-caret { + height: var(--icon-size-xs); + width: var(--icon-size-xs); + color: rgb(var(--color-foreground-rgb) / var(--icon-opacity)); + margin-block: var(--margin-2xs); + transition: color var(--animation-speed) var(--animation-easing); + } + + .facets--drawer .facets__summary .icon-caret { + margin-inline-start: var(--margin-2xs); + } + + /* Facets - Bubble */ + .facets__bubble { + display: inline-flex; + font-family: var(--font-paragraph--family); + font-weight: var(--font-paragraph--weight); + aspect-ratio: 1 / 1; + } + + /* Facets - Inputs */ + .facets__inputs-wrapper { + margin-block: var(--padding-xs) var(--padding-xs); + } + + .facets__inputs .show-more { + display: flex; + flex-direction: column; + gap: var(--gap-xl); + margin-block-end: var(--padding-xl); + } + + .facets:not(.facets--drawer) .facets__inputs-wrapper { + @media screen and (min-width: 750px) { + gap: var(--gap-sm); + } + } + + .facets--horizontal .facets__inputs .show-more { + @media screen and (min-width: 750px) { + display: contents; + } + } + + .facets--horizontal .facets__inputs-wrapper { + @media screen and (min-width: 750px) { + max-height: var(--facets-horizontal-max-input-wrapper-height); + scrollbar-width: none; + -ms-overflow-style: none; + overflow-x: auto; + padding: var(--padding-md); + margin-block: 0; + } + } + + .facets--vertical .facets__inputs:has(.show-more) .facets__inputs-wrapper { + padding-block: var(--padding-sm); + padding-inline: var(--padding-sm); + margin-block: calc(var(--padding-sm) * -1); + margin-inline: calc(var(--padding-sm) * -1); + } + + @media screen and (max-width: 749px) { + .facets__inputs:has(.show-more) .facets__inputs-wrapper { + padding-block: var(--padding-sm); + padding-inline: var(--padding-sm); + margin-block: calc(var(--padding-sm) * -1); + margin-inline: calc(var(--padding-sm) * -1); + } + } + + .facets__inputs-wrapper:not(:has(.facets__inputs-list)), + .facets__inputs-wrapper .facets__inputs-list { + display: flex; + gap: var(--facets-mobile-gap); + flex-direction: column; + + @media screen and (min-width: 750px) { + gap: var(--gap-sm); + } + } + + @media screen and (min-width: 750px) { + .facets--vertical .facets__inputs-wrapper .facets__inputs-list--swatches { + gap: var(--gap-sm); + } + + .facets--horizontal + .facets__inputs-wrapper + .facets__inputs-list--swatches:not(.facets__inputs-list--swatches-grid) { + display: grid; + grid-template-columns: repeat(var(--swatch-columns, 4), 1fr); + } + } + + .facets__inputs-wrapper .facets__inputs-list--swatches { + --facets-mobile-gap: var(--gap-sm); + } + + .facets__inputs-wrapper .facets__inputs-list--grid { + --min-column-width: 20%; + + display: grid; + grid-template-columns: repeat(auto-fit, minmax(var(--min-column-width), 1fr)); + gap: var(--gap-sm); + + @media screen and (min-width: 750px) { + --min-column-width: 50px; + } + } + + .facets-block-wrapper:not(.facets-block-wrapper--vertical) .facets__inputs-list--grid { + @media screen and (min-width: 750px) { + width: var(--facets-grid-panel-width); + } + } + + .facets__inputs-wrapper--row:not(:has(.facets__inputs-list)), + .facets__inputs-wrapper--row .facets__inputs-list { + flex-wrap: wrap; + flex-direction: row; + } + + .facets__inputs .show-more__button { + --show-more-icon-size: 22px; + --show-more-gap: 8px; + + gap: var(--show-more-gap); + + @media screen and (min-width: 750px) { + --show-more-icon-size: 16px; + --show-more-gap: 6px; + } + } + + .facets__inputs .show-more__button .icon-plus { + width: var(--show-more-icon-size); + height: var(--show-more-icon-size); + + svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + } + + /* Facets - Panel */ + .facets__panel { + padding: 0 var(--drawer-padding); + } + + .facets:not(.facets--drawer) .facets__panel, + .facets-controls-wrapper .facets__panel { + @media screen and (min-width: 750px) { + padding: 0; + } + } + + .facets--horizontal .facets__panel { + @media screen and (min-width: 750px) { + position: relative; + } + } + + .facets-mobile-wrapper .facets__panel-content { + border-radius: var(--style-border-radius-popover); + } + + .facets-mobile-wrapper { + --facets-upper-z-index: var(--layer-raised); + --facets-panel-min-width: 120px; + --facets-panel-height: 300px; + } + + .facets--horizontal .facets__panel-content, + .sorting-filter__options { + @media screen and (min-width: 750px) { + border-radius: var(--style-border-radius-popover); + position: absolute; + top: 100%; + width: max-content; + min-width: var(--facets-panel-min-width); + max-width: var(--facets-panel-width); + max-height: var(--facets-panel-height); + z-index: var(--facets-upper-z-index); + box-shadow: var(--shadow-popover); + border: var(--style-border-popover); + background-color: var(--color-background); + overflow-y: hidden; + gap: 0; + } + } + + :is(.facets--drawer, .facets--vertical) :is(.facets__item, .sorting-filter)::before { + content: ''; + display: block; + height: 0; + width: calc(100% - var(--drawer-padding) * 2); + border-top: var(--style-border-width) solid var(--color-border); + margin: 0 auto; + } + + @media screen and (min-width: 750px) { + .facets:not(.facets--drawer) :is(.facets__item, .sorting-filter)::before { + width: 100%; + } + + .facets--horizontal .facets__item:not(:first-of-type)::before, + .facets--horizontal .sorting-filter::before { + content: none; + } + } + + @media screen and (min-width: 750px) { + .facets--vertical .facets__item:not(:first-of-type)::before, + .facets--vertical .sorting-filter::before { + content: ''; + } + } + + /* Facets - Text */ + .facets__label, + .facets__clear-all, + .clear-filter { + text-decoration-color: transparent; + text-decoration-thickness: 0.075em; + text-underline-offset: 0.125em; + transition: text-decoration-color var(--animation-speed) var(--animation-easing); + } + + .facets__label, + .products-count-wrapper { + text-transform: var(--facet-label-transform); + } + + .clear-filter { + background-color: transparent; + box-shadow: none; + padding: 0; + } + + /* Facets - Label */ + .facets__label { + color: var(--color-foreground); + cursor: pointer; + + @media screen and (min-width: 750px) { + margin-inline-end: var(--margin-2xs); + } + } + + /* Products count */ + .products-count-wrapper { + display: none; + } + + .facets--horizontal .products-count-wrapper { + @media screen and (min-width: 750px) { + display: flex; + margin-left: auto; + flex-shrink: 0; + align-items: center; + height: var(--minimum-touch-target); + } + } + + /* Mobile specific components */ + .facets__title-wrapper { + background-color: var(--color-background); + color: var(--color-foreground); + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + padding-block: var(--padding-xs); + padding-inline-start: var(--drawer-padding); + padding-inline-end: var(--padding-2xs); + z-index: var(--facets-sticky-z-index); + } + + :is(.facets--horizontal, .facets--vertical) .facets__title-wrapper { + @media screen and (min-width: 750px) { + display: none; + } + } + + .facets-drawer__title { + --variant-picker-swatch-width: 32px; + --variant-picker-swatch-height: 32px; + + margin: 0; + display: flex; + align-items: center; + gap: var(--gap-xs); + + @media screen and (min-width: 750px) { + --variant-picker-swatch-width: 26px; + --variant-picker-swatch-height: 26px; + } + } + + .facets-drawer__close { + display: flex; + align-items: center; + justify-content: center; + padding: 0; + background-color: transparent; + border: none; + cursor: pointer; + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + box-shadow: none; + } + + /* Status */ + .facets__status:not(:empty) { + width: max-content; + display: flex; + margin-inline-start: auto; + font-weight: 500; + color: var(--color-foreground); + } + + .facets__panel[open] .facets__status { + display: none; + } + + .facets--filters-title { + margin-block-end: 0; + color: var(--color-foreground); + height: fit-content; + + @media screen and (max-width: 749px) { + display: none; + } + } + + .facets--horizontal .facets__panel .facets__status:has(:not(:empty)) { + @media screen and (min-width: 750px) { + display: flex; + margin-inline-start: var(--margin-xs); + margin-inline-end: var(--margin-xs); + } + } + + /* Horizontal filter style */ + .facets--horizontal .facets__form { + @media screen and (min-width: 750px) { + gap: 0 var(--facets-form-horizontal-gap); + } + } + + .collection-wrapper:has(> .facets--horizontal) .facets__panel[open] { + @media screen and (min-width: 750px) { + z-index: var(--facets-open-z-index); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.filters", + "tag": null, + "settings": [ + { + "type": "checkbox", + "id": "enable_filtering", + "label": "t:settings.enable_filtering", + "info": "t:info.enable_filtering_info", + "default": false + }, + { + "type": "select", + "id": "filter_style", + "label": "t:settings.direction", + "options": [ + { + "value": "horizontal", + "label": "t:options.horizontal" + }, + { + "value": "vertical", + "label": "t:options.vertical" + } + ], + "default": "horizontal", + "visible_if": "{{ block.settings.enable_filtering == true }}" + }, + { + "type": "select", + "id": "filter_width", + "label": "t:settings.width", + "options": [ + { + "value": "centered", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "centered", + "visible_if": "{{ block.settings.enable_filtering == true and block.settings.filter_style == 'horizontal' }}" + }, + { + "type": "select", + "id": "text_label_case", + "label": "t:settings.text_label_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default", + "visible_if": "{{ block.settings.enable_filtering == true }}" + }, + { + "type": "checkbox", + "id": "show_swatch_label", + "label": "t:settings.show_swatch_label", + "default": false, + "visible_if": "{{ block.settings.enable_filtering == true }}" + }, + { + "type": "checkbox", + "id": "show_filter_label", + "label": "t:settings.show_filter_label", + "default": false, + "visible_if": "{{ block.settings.enable_filtering == true }}" + }, + { + "type": "checkbox", + "id": "enable_sorting", + "label": "t:settings.enable_sorting", + "default": true + }, + { + "type": "checkbox", + "id": "enable_grid_density", + "label": "t:settings.enable_grid_density", + "default": true + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.margin" + }, + { + "type": "range", + "id": "facets_margin_bottom", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ block.settings.filter_style == 'horizontal' }}" + }, + { + "type": "range", + "id": "facets_margin_right", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 20, + "visible_if": "{{ block.settings.filter_style == 'vertical' }}" + } + ] +} +{% endschema %} diff --git a/blocks/follow-on-shop.liquid b/blocks/follow-on-shop.liquid new file mode 100644 index 000000000..bc8c29cf2 --- /dev/null +++ b/blocks/follow-on-shop.liquid @@ -0,0 +1,74 @@ +{% # import schema from '../schemas/blocks/follow-on-shop' %} + +{%- if shop.features.follow_on_shop? -%} +
+ {{ shop | login_button: action: 'follow' }} +
+{%- endif -%} + +{% schema %} +{ + "name": "t:names.follow_on_shop", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.follow_on_shop_eligiblity" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.follow_on_shop", + "category": "t:categories.footer" + } + ] +} +{% endschema %} diff --git a/blocks/footer-utilities.liquid b/blocks/footer-utilities.liquid new file mode 100644 index 000000000..7125f2433 --- /dev/null +++ b/blocks/footer-utilities.liquid @@ -0,0 +1,124 @@ +{% # import schema from '../schemas/blocks/footer-utilities.js' %} + + + +{% stylesheet %} + .footer-utilities { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--gap-lg); + text-wrap: nowrap; + border-top: var(--border-width) solid var(--color-border); + color: var(--color-foreground-muted); + + @media screen and (min-width: 750px) { + flex-direction: row; + justify-content: space-between; + gap: var(--gap-md); + align-items: center; + text-align: left; + } + } + + .footer-utilities a { + color: var(--color-foreground-muted); + } + + .footer-utilities__group { + width: 100%; + display: flex; + flex: 1 1 max-content; + text-align: center; + flex-direction: column; + align-items: center; + flex-wrap: wrap; + gap: var(--gap-md); + + @media screen and (min-width: 750px) { + flex-direction: row; + align-items: baseline; + gap: var(--gap-2xs) var(--gap-xl); + text-align: left; + } + } + + .footer-utilities__group--right { + @media screen and (min-width: 750px) { + justify-content: flex-end; + } + } + + .footer-utilities__group:empty { + @media screen and (max-width: 749px) { + display: none; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.footer_utilities", + "tag": null, + "settings": [ + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "range", + "id": "divider_thickness", + "label": "t:settings.divider_thickness", + "min": 0, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 1 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 20 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 20 + } + ], + "presets": [ + { + "name": "t:names.footer_utilities", + "category": "t:categories.footer" + } + ] +} +{% endschema %} diff --git a/blocks/group.liquid b/blocks/group.liquid new file mode 100644 index 000000000..cebc3255a --- /dev/null +++ b/blocks/group.liquid @@ -0,0 +1,505 @@ +{% # import schema from '../schemas/blocks/group' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %} + +{% schema %} +{ + "name": "t:names.group", + "tag": null, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ block.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ block.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ block.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "fit", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fit" + }, + { + "type": "range", + "id": "custom_height", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ block.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "text", + "id": "placeholder", + "label": "t:settings.image", + "visible_if": "{{ false }}" + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.background_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ block.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ block.settings.toggle_overlay and block.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.group", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/icon.liquid b/blocks/icon.liquid new file mode 100644 index 000000000..0eff4b673 --- /dev/null +++ b/blocks/icon.liquid @@ -0,0 +1,327 @@ +{% # import schema from '../schemas/blocks/icon.js' %} + +{% assign icon_block_class = 'icon-block__media icon-block-' | append: block.id %} + +{% capture icon %} + {% render 'icon-or-image', + icon: block.settings.icon, + image_upload: block.settings.image_upload, + width: block.settings.width, + class_name: icon_block_class, + attributes: block.shopify_attributes + %} +{% endcapture %} + +{%- if block.settings.link != blank -%} + + {{ icon }} + +{%- else -%} + {{ icon }} +{%- endif -%} + +{% stylesheet %} + .icon-block { + display: flex; + fill: currentcolor; + flex-shrink: 0; + } + + .icon-block__media { + height: auto; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.icon", + "class": "icon-block", + "settings": [ + { + "type": "select", + "id": "icon", + "label": "t:settings.icon", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "apple", + "label": "t:options.apple" + }, + { + "value": "arrow", + "label": "t:options.arrow" + }, + { + "value": "banana", + "label": "t:options.banana" + }, + { + "value": "bottle", + "label": "t:options.bottle" + }, + { + "value": "box", + "label": "t:options.box" + }, + { + "value": "carrot", + "label": "t:options.carrot" + }, + { + "value": "chat_bubble", + "label": "t:options.chat_bubble" + }, + { + "value": "check_box", + "label": "t:options.check_box" + }, + { + "value": "clipboard", + "label": "t:options.clipboard" + }, + { + "value": "dairy", + "label": "t:options.dairy" + }, + { + "value": "dairy_free", + "label": "t:options.dairy_free" + }, + { + "value": "dryer", + "label": "t:options.dryer" + }, + { + "value": "eye", + "label": "t:options.eye" + }, + { + "value": "fire", + "label": "t:options.fire" + }, + { + "value": "gluten_free", + "label": "t:options.gluten_free" + }, + { + "value": "heart", + "label": "t:options.heart" + }, + { + "value": "iron", + "label": "t:options.iron" + }, + { + "value": "leaf", + "label": "t:options.leaf" + }, + { + "value": "leather", + "label": "t:options.leather" + }, + { + "value": "lightning_bolt", + "label": "t:options.lightning_bolt" + }, + { + "value": "lipstick", + "label": "t:options.lipstick" + }, + { + "value": "lock", + "label": "t:options.lock" + }, + { + "value": "map_pin", + "label": "t:options.map_pin" + }, + { + "value": "nut_free", + "label": "t:options.nut_free" + }, + { + "value": "pants", + "label": "t:options.pants" + }, + { + "value": "paw_print", + "label": "t:options.paw_print" + }, + { + "value": "pepper", + "label": "t:options.pepper" + }, + { + "value": "perfume", + "label": "t:options.perfume" + }, + { + "value": "plane", + "label": "t:options.plane" + }, + { + "value": "plant", + "label": "t:options.plant" + }, + { + "value": "price_tag", + "label": "t:options.price_tag" + }, + { + "value": "question_mark", + "label": "t:options.question_mark" + }, + { + "value": "recycle", + "label": "t:options.recycle" + }, + { + "value": "return", + "label": "t:options.return" + }, + { + "value": "ruler", + "label": "t:options.ruler" + }, + { + "value": "serving_dish", + "label": "t:options.serving_dish" + }, + { + "value": "shirt", + "label": "t:options.shirt" + }, + { + "value": "shoe", + "label": "t:options.shoe" + }, + { + "value": "silhouette", + "label": "t:options.silhouette" + }, + { + "value": "bluesky", + "label": "t:options.social_bluesky" + }, + { + "value": "facebook", + "label": "t:options.social_facebook" + }, + { + "value": "instagram", + "label": "t:options.social_instagram" + }, + { + "value": "linkedin", + "label": "t:options.social_linkedin" + }, + { + "value": "pinterest", + "label": "t:options.social_pinterest" + }, + { + "value": "snapchat", + "label": "t:options.social_snapchat" + }, + { + "value": "spotify", + "label": "t:options.social_spotify" + }, + { + "value": "threads", + "label": "t:options.social_threads" + }, + { + "value": "tiktok", + "label": "t:options.social_tiktok" + }, + { + "value": "tumblr", + "label": "t:options.social_tumblr" + }, + { + "value": "twitter", + "label": "t:options.social_twitter" + }, + { + "value": "vimeo", + "label": "t:options.social_vimeo" + }, + { + "value": "youtube", + "label": "t:options.social_youtube" + }, + { + "value": "whatsapp", + "label": "t:options.social_whatsapp" + }, + { + "value": "snowflake", + "label": "t:options.snowflake" + }, + { + "value": "star", + "label": "t:options.star" + }, + { + "value": "stopwatch", + "label": "t:options.stopwatch" + }, + { + "value": "truck", + "label": "t:options.truck" + }, + { + "value": "washing", + "label": "t:options.washing" + } + ], + "default": "apple" + }, + { + "type": "image_picker", + "id": "image_upload", + "label": "t:settings.image_icon" + }, + { + "type": "range", + "id": "width", + "label": "t:settings.width", + "min": 12, + "max": 200, + "step": 2, + "unit": "px", + "default": 24 + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + } + ], + "presets": [ + { + "name": "t:names.icon", + "category": "t:categories.basic", + "settings": { + "icon": "price_tag" + } + } + ] +} +{% endschema %} diff --git a/blocks/image.liquid b/blocks/image.liquid new file mode 100644 index 000000000..89d3dbdd1 --- /dev/null +++ b/blocks/image.liquid @@ -0,0 +1,337 @@ +{% # import schema from '../schemas/blocks/image' %} + +{% liquid + assign ratio = 1 + + case block.settings.image_ratio + when 'landscape' + assign ratio = '16 / 9' + when 'portrait' + assign ratio = '4 / 5' + when 'adapt' + assign ratio = block.settings.image.aspect_ratio + endcase + + if ratio == 0 or ratio == null + assign ratio = 1 + endif +%} + +{% capture class %} + image-block image-block--{{ block.id }} image-block--height-{{ block.settings.height }} spacing-style size-style +{% endcapture %} + +{% capture style %} + --ratio: {{ ratio }}; + {% render 'size-style', settings: block.settings %} + {% render 'spacing-style', settings: block.settings %} +{% endcapture %} + +{% capture image_border_style %} + --ratio: {{ ratio }}; + {% render 'border-override', settings: block.settings %} +{% endcapture %} + +{% liquid + assign media_width_desktop = '100vw' + assign media_width_mobile = '100vw' + assign sizes = 'auto, (min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2000, 2500, 3000, 3500, 4000, 5000' +%} + +{% capture image %} + {%- if block.settings.image -%} + {{ + block.settings.image + | image_url: width: 3840 + | image_tag: + width: block.settings.image.width, + widths: widths, + height: block.settings.image.height, + class: 'image-block__image border-style', + style: image_border_style, + sizes: sizes + }} + {%- else -%} +
+ {{ 'detailed-apparel-1' | placeholder_svg_tag: 'hero__image' }} +
+ {%- endif -%} +{% endcapture %} + +{% if block.settings.link == blank %} +
+ {{ image }} +
+{% else %} + + {{ image }} + +{% endif %} + +{% stylesheet %} + .placeholder-image { + position: relative; + aspect-ratio: var(--ratio); + overflow: hidden; + } + + placeholder-image img { + width: 100%; + height: 100%; + aspect-ratio: var(--ratio); + } + + .image-block { + display: flex; + + /* When the image is nested in a group, section, etc, respect the parent's horizontal alignment */ + justify-content: var(--horizontal-alignment, 'inline-start'); + } + + .image-block--height-fill .image-block__image { + height: 100%; + } + + .image-block__image { + object-fit: cover; + aspect-ratio: var(--ratio); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.image", + "tag": null, + "settings": [ + { + "type": "image_picker", + "id": "image", + "label": "t:settings.image" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "image_ratio", + "options": [ + { + "value": "adapt", + "label": "t:options.auto" + }, + { + "value": "portrait", + "label": "t:options.portrait" + }, + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "landscape", + "label": "t:options.landscape" + } + ], + "default": "adapt", + "label": "t:settings.aspect_ratio" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width_desktop", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width == 'custom' }}" + }, + { + "type": "select", + "id": "width_mobile", + "label": "t:settings.width_mobile", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "fill" + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.custom_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.width_mobile == 'custom' }}" + }, + { + "type": "select", + "id": "height", + "label": "t:settings.height", + "options": [ + { + "value": "fit", + "label": "t:options.fit_content" + }, + { + "value": "fill", + "label": "t:options.fill" + } + ], + "default": "fit", + "visible_if": "{{ block.settings.image_ratio == 'adapt' }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.image", + "category": "t:categories.basic" + } + ] +} +{% endschema %} diff --git a/blocks/jumbo-text.liquid b/blocks/jumbo-text.liquid new file mode 100644 index 000000000..476c64f68 --- /dev/null +++ b/blocks/jumbo-text.liquid @@ -0,0 +1,137 @@ +{% # import schema from '../schemas/blocks/jumbo-text' %} + +{% render 'jumbo-text' %} + +{% schema %} +{ + "name": "t:names.jumbo_text", + "tag": null, + "settings": [ + { + "id": "text", + "type": "textarea", + "label": "t:settings.text", + "default": "t:text_defaults.be_bold" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "0.8", + "label": "t:options.tight" + }, + { + "value": "1", + "label": "t:options.normal" + }, + { + "value": "1.2", + "label": "t:options.loose" + } + ], + "default": "0.8" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "-0.03em", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "0.03em", + "label": "t:options.loose" + } + ], + "default": "-0.03em" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "select", + "id": "text_effect", + "label": "t:settings.effects", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "blur", + "label": "t:options.blur" + }, + { + "value": "reveal", + "label": "t:options.reveal" + } + ], + "default": "none" + }, + { + "type": "checkbox", + "id": "animation_repeat", + "label": "t:settings.animation_repeat", + "default": false, + "visible_if": "{{ block.settings.text_effect == \"blur\" or block.settings.text_effect == \"reveal\" }}" + } + ], + "presets": [ + { + "name": "t:names.jumbo_text", + "category": "t:categories.decorative" + } + ] +} +{% endschema %} diff --git a/blocks/logo.liquid b/blocks/logo.liquid new file mode 100644 index 000000000..8b05757c4 --- /dev/null +++ b/blocks/logo.liquid @@ -0,0 +1,291 @@ +{% # import schema from '../schemas/blocks/logo' %} + +{% liquid + assign image = settings.logo + + if block.settings.inverse and settings.logo_inverse + assign image = settings.logo_inverse + endif +%} + +{%- if image -%} + {% capture logo_image %} + {{- + image + | image_url: width: 3840 + | image_tag: + width: image.width, + widths: '375, 550, 750, 1100, 1500, 1780, 2000, 3000, 3840', + height: image.height, + class: 'logo-block__image', + alt: shop.name, + sizes: '(min-width: 750px) calc(var(--logo-width)), 100vw' + -}} + {% endcapture %} +{%- endif -%} + +
+ {% if logo_image %} +
+ {{ logo_image }} +
+ {% else %} + {% render 'jumbo-text', text: shop.name %} + {% endif %} +
+ +{% stylesheet %} + .logo-block { + width: calc(var(--logo-width) + var(--padding-inline-start) + var(--padding-inline-end)); + max-width: 100%; + max-height: calc(var(--logo-height, 100%) + var(--padding-block-start) + var(--padding-block-end)); + font-size: var(--logo-height); + display: flex; + + @media screen and (max-width: 750px) { + max-height: calc( + var(--logo-height-mobile, var(--logo-height, 100%)) + var(--padding-block-start) + var(--padding-block-end) + ); + font-size: var(--logo-height-mobile, var(--logo-height)); + width: calc( + var(--logo-width-mobile, var(--logo-width)) + var(--padding-inline-start) + var(--padding-inline-end) + ); + } + } + + .logo-block__image-wrapper { + display: flex; + width: 100%; + max-width: 100%; + max-height: 100%; + } + + .logo-block__image { + object-fit: contain; + width: 100%; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.logo", + "tag": null, + "settings": [ + { + "type": "checkbox", + "label": "t:settings.use_inverse_logo", + "id": "inverse", + "default": false, + "visible_if": "{{ settings.logo_inverse }}" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading", + "visible_if": "{{ settings.logo == blank and settings.logo_inverse == blank or block.settings.inverse == false }}" + }, + { + "type": "paragraph", + "content": "t:content.edit_logo_in_theme_settings" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "unit", + "label": "t:settings.unit", + "options": [ + { + "value": "pixel", + "label": "t:options.pixel" + }, + { + "value": "percent", + "label": "t:options.percent" + } + ], + "default": "percent" + }, + { + "type": "range", + "id": "percent_width", + "label": "t:settings.width", + "min": 10, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.unit == 'percent' }}" + }, + { + "type": "range", + "id": "pixel_height", + "label": "t:settings.height", + "min": 16, + "max": 320, + "step": 8, + "unit": "px", + "default": 48, + "visible_if": "{{ block.settings.unit == 'pixel' }}" + }, + { + "type": "checkbox", + "id": "custom_mobile_size", + "label": "t:settings.custom_mobile_size", + "default": false + }, + { + "type": "header", + "content": "t:content.mobile_size", + "visible_if": "{{ block.settings.custom_mobile_size == true }}" + }, + { + "type": "select", + "id": "unit_mobile", + "label": "t:settings.unit", + "options": [ + { + "value": "pixel", + "label": "t:options.pixel" + }, + { + "value": "percent", + "label": "t:options.percent" + } + ], + "default": "percent", + "visible_if": "{{ block.settings.custom_mobile_size == true }}" + }, + { + "type": "range", + "id": "percent_width_mobile", + "label": "t:settings.width", + "min": 10, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.unit_mobile == 'percent' and block.settings.custom_mobile_size == true}}" + }, + { + "type": "range", + "id": "pixel_height_mobile", + "label": "t:settings.height", + "min": 16, + "max": 160, + "step": 8, + "unit": "px", + "default": 120, + "visible_if": "{{ block.settings.unit_mobile == 'pixel' and block.settings.custom_mobile_size == true}}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.logo", + "category": "t:categories.basic", + "settings": { + "unit": "pixel", + "pixel_height": 48 + } + } + ] +} +{% endschema %} diff --git a/blocks/menu.liquid b/blocks/menu.liquid new file mode 100644 index 000000000..e82d66523 --- /dev/null +++ b/blocks/menu.liquid @@ -0,0 +1,341 @@ +{% # import schema from '../schemas/blocks/menu.js' %} + +{% liquid + assign menu = block.settings.menu + assign heading = block.settings.heading + assign color_scheme = block.settings.color_scheme + assign show_as_accordion = block.settings.show_as_accordion + if show_as_accordion == true and block.settings.accordion_dividers == true + assign dividers_enabled = true + endif +%} + +{% if menu != blank or heading != blank %} + + + +{% endif %} + +{% stylesheet %} + .menu { + width: 100%; + } + + .menu:not(:has(.menu__heading--empty)) .details-content { + margin-block-start: var(--spacing--size); + } + + .menu__item + .menu__item { + margin-block-start: var(--spacing--size); + } + + .menu .menu__heading--empty { + display: none; + } + + .menu__heading__default { + display: contents; + } + + .menu__heading__accordion { + display: none; + } + + @media screen and (max-width: 749px) { + /* Always show the fallback heading on mobile when accordion is enabled */ + .menu--accordion .menu__heading--empty { + display: flex; + } + + .menu--accordion .menu__heading__accordion { + display: contents; + } + + .menu--accordion .menu__heading__default { + display: none; + } + + .menu--accordion .details-content { + margin-block-start: var(--spacing--size); + } + + .menu--accordion .menu__details { + padding-inline: 0; + } + + .menu--dividers .menu__details { + border-block-end: var(--style-border-width) solid var(--color-border); + } + + .menu--dividers .details-content { + padding-block-end: var(--padding-sm); + } + } + + .menu--caret .icon-plus, + .menu--plus .icon-caret { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.menu", + "tag": null, + "settings": [ + { + "type": "link_list", + "id": "menu", + "label": "t:settings.menu", + "default": "main-menu" + }, + { + "type": "text", + "id": "heading", + "label": "t:settings.heading" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "range", + "id": "menu_spacing", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "checkbox", + "id": "show_as_accordion", + "label": "t:settings.show_as_accordion", + "default": false + }, + { + "type": "select", + "id": "accordion_icon", + "label": "t:settings.icon", + "options": [ + { + "value": "caret", + "label": "t:options.caret" + }, + { + "value": "plus", + "label": "t:options.plus" + } + ], + "default": "caret", + "visible_if": "{{ block.settings.show_as_accordion == true }}" + }, + { + "type": "checkbox", + "id": "accordion_dividers", + "label": "t:settings.dividers", + "default": false, + "visible_if": "{{ block.settings.show_as_accordion == true }}" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "heading_preset", + "label": "t:settings.heading_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "h3" + }, + { + "type": "select", + "id": "link_preset", + "label": "t:settings.link_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "paragraph" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.menu", + "category": "t:categories.links" + } + ] +} +{% endschema %} diff --git a/blocks/page-content.liquid b/blocks/page-content.liquid new file mode 100644 index 000000000..4547257da --- /dev/null +++ b/blocks/page-content.liquid @@ -0,0 +1,12 @@ +{% # import schema from '../schemas/blocks/page-content.js' %} + + + {{ page.content }} + + +{% schema %} +{ + "name": "t:names.page_content", + "class": "rte" +} +{% endschema %} diff --git a/blocks/page.liquid b/blocks/page.liquid new file mode 100644 index 000000000..29a4f0cb3 --- /dev/null +++ b/blocks/page.liquid @@ -0,0 +1,142 @@ +{% # import schema from '../schemas/blocks/page.js' %} + +
+ {%- if block.settings.page != blank -%} + {%- if block.settings.page.title != blank -%} +

{{ block.settings.page.title }}

+ {%- endif -%} + {%- if block.settings.page.content != blank -%} +
+ {{ block.settings.page.content }} +
+ {%- endif -%} + {%- else -%} +

{{ 'content.page_placeholder_title' | t }}

+
+ {{ 'content.page_placeholder_content' | t }} +
+ {%- endif -%} +
+ +{% stylesheet %} + .page-block { + display: flex; + flex-direction: column; + max-width: 100%; + max-height: 100%; + width: 100%; + height: auto; + align-items: flex-start; + } + + .page-title { + margin-bottom: var(--margin-xl); + } + + .placeholder-image { + position: relative; + aspect-ratio: var(--ratio); + overflow: hidden; + } + + .page-placeholder { + width: 100%; + height: 100%; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.page", + "settings": [ + { + "type": "page", + "id": "page", + "label": "t:settings.page" + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.page", + "category": "t:categories.basic" + } + ] +} +{% endschema %} diff --git a/blocks/payment-icons.liquid b/blocks/payment-icons.liquid new file mode 100644 index 000000000..65de24caa --- /dev/null +++ b/blocks/payment-icons.liquid @@ -0,0 +1,140 @@ +{% # import schema from '../schemas/blocks/payment-icons.js' %} + +
+ {{ 'blocks.payment_methods' | t }} +
    + {%- for type in shop.enabled_payment_types -%} +
  • + {{ type | payment_type_svg_tag: class: 'icon icon--full-color' }} +
  • + {%- endfor -%} +
+
+ +{% stylesheet %} + .payment-icons { + width: 100%; + } + + .payment-icons__list { + display: flex; + align-items: center; + justify-content: var(--alignment); + flex-wrap: wrap; + gap: var(--icon-gap); + margin: 0; + padding: 0; + } + + .payment-icons__item { + display: flex; + align-items: center; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.payment_icons", + "tag": null, + "settings": [ + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 10 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.payment_icons", + "category": "t:categories.footer" + } + ] +} +{% endschema %} diff --git a/blocks/popup-link.liquid b/blocks/popup-link.liquid new file mode 100644 index 000000000..354e423fc --- /dev/null +++ b/blocks/popup-link.liquid @@ -0,0 +1,265 @@ +{% # import schema from '../schemas/blocks/popup-link' %} + + + + + + + + + + + + +{% stylesheet %} + .popup-link__button svg { + display: inline-block; + position: relative; + top: var(--margin-2xs); + } + + .popup-link__content { + box-shadow: var(--shadow-popover); + border: var(--style-border-popover); + border-radius: var(--style-border-radius-popover); + background-color: var(--color-background); + padding: var(--padding-4xl) var(--padding-xl) var(--padding-xl); + max-width: var(--normal-content-width); + max-height: var(--modal-max-height); + + @media screen and (min-width: 750px) { + padding: var(--padding-5xl); + } + } + + .popup-link__content[open] { + animation: modalSlideInTop var(--animation-speed) var(--animation-easing) forwards; + } + + .popup-link__content.dialog-closing { + animation: modalSlideOutTop var(--animation-speed) var(--animation-easing) forwards; + } + + .popup-link__content--drawer { + position: fixed; + border-radius: 0; + width: var(--sidebar-width); + max-width: 95vw; + height: 100%; + margin: 0 0 0 auto; + } + + /* Needed to ensure the drawer is full height */ + .popup-link__content--drawer:modal { + max-height: 100dvh; + } + + .popup-link__close { + position: absolute; + top: var(--margin-2xs); + right: var(--margin-2xs); + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + color: var(--color-foreground); + background-color: transparent; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + } + + .popup-link__close { + background-color: transparent; + opacity: 0.8; + } + + .popup-link__close svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.popup_link", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "tag": null, + "settings": [ + { + "type": "header", + "content": "t:content.popup" + }, + { + "type": "select", + "id": "behavior", + "label": "t:settings.behavior", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "drawer", + "label": "t:options.drawer" + } + ], + "default": "default" + }, + { + "type": "header", + "content": "t:content.link" + }, + { + "type": "text", + "id": "heading", + "label": "t:settings.text", + "default": "t:text_defaults.popup_link" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "header", + "content": "t:content.link_padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.popup_link", + "category": "t:categories.links", + "settings": { + "heading": "Learn more" + }, + "blocks": { + "text_pexwUk": { + "type": "text", + "settings": { + "text": "

What is the return policy?

", + "alignment": "left", + "padding-block-end": 16 + } + }, + "text_g7mEh7": { + "type": "text", + "settings": { + "text": "

Our goal is for every customer to be totally satisfied with their purchase. If this isn’t the case, let us know and we’ll do our best to work with you to make it right.

", + "alignment": "left" + } + } + }, + "block_order": ["text_pexwUk", "text_g7mEh7"] + } + ] +} +{% endschema %} diff --git a/blocks/price.liquid b/blocks/price.liquid new file mode 100644 index 000000000..6671989a5 --- /dev/null +++ b/blocks/price.liquid @@ -0,0 +1,438 @@ +{% # import schema from '../schemas/blocks/price.js' %} + +{%- liquid + assign product_resource = closest.product + assign selected_variant = product_resource.selected_or_first_available_variant +-%} + +{% liquid + if block.settings.type_preset == 'rte' or block.settings.type_preset == 'paragraph' + assign is_rte = true + endif + + capture text_block_classes + if block.settings.width == '100%' + echo 'text-block--align-' | append: block.settings.alignment + if block.settings.max_width == 'none' + echo ' text-block--full-width' + endif + endif + if block.settings.type_preset == 'custom' + echo ' custom-typography' + if block.settings.font_size != '' + echo ' custom-font-size' + endif + if block.settings.color != '' + echo ' custom-color' + endif + endif + if block.settings.background + echo ' text-block--background' + endif + if is_rte + echo ' rte' + endif + endcapture +%} + + + {% render 'price', + show_unit_price: true, + product_resource: product_resource, + show_sale_price_first: block.settings.show_sale_price_first + %} + + {% if block.settings.show_tax_info %} +
+ {%- if cart.duties_included and cart.taxes_included -%} + {{ 'content.duties_and_taxes_included' | t }} + {%- elsif cart.taxes_included -%} + {{ 'content.taxes_included' | t }} + {%- elsif cart.duties_included -%} + {{ 'content.duties_included' | t }} + {%- endif -%} + + {%- if shop.shipping_policy.body != blank -%} + {{ 'content.shipping_policy' | t }} + {%- endif -%} +
+ {% endif %} + + {%- if selected_variant != blank and block.settings.show_installments -%} +
+ {%- assign product_form_installment_id = 'product-form-installment-' | append: block.id -%} + {%- form 'product', product_resource, id: product_form_installment_id, class: 'payment-terms' -%} + + {{ form | payment_terms }} + {%- endform -%} +
+ {%- endif -%} +
+ +{% # theme-check-disable %} +{% stylesheet %} + .tax-note:empty { + display: none; + } + + form.payment-terms { + padding-top: 0.5em; + } + + .installments:not(:has(shopify-payment-terms)) { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_price", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_price" + }, + { + "type": "paragraph", + "content": "t:content.edit_price_in_theme_settings" + }, + { + "type": "checkbox", + "id": "show_sale_price_first", + "label": "t:settings.show_sale_price_first", + "default": true + }, + { + "type": "checkbox", + "id": "show_installments", + "label": "t:settings.installments", + "default": false + }, + { + "type": "checkbox", + "id": "show_tax_info", + "label": "t:settings.show_tax_info", + "default": false + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit_content" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "100%" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width != 'fit-content' }}" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_price", + "category": "t:categories.product" + } + ] +} +{% endschema %} +{% # theme-check-enable %} diff --git a/blocks/product-card.liquid b/blocks/product-card.liquid new file mode 100644 index 000000000..090b292a0 --- /dev/null +++ b/blocks/product-card.liquid @@ -0,0 +1,247 @@ +{% # import schema from '../schemas/blocks/product-card.js' %} + +{% liquid + assign product = block.settings.product +-%} + +{% capture children %} + {% content_for 'blocks', closest.product: product %} +{% endcapture %} + +{% render 'product-card', children: children, product: product %} + +{% schema %} +{ + "name": "t:names.product_card", + "blocks": [ + { + "type": "_product-card-group" + }, + { + "type": "text" + }, + { + "type": "image" + }, + { + "type": "price" + }, + { + "type": "review" + }, + { + "type": "swatches" + }, + { + "type": "_product-card-gallery" + }, + { + "type": "product-title" + }, + { + "type": "custom-liquid" + }, + { + "type": "@app" + } + ], + "tag": null, + "settings": [ + { + "type": "product", + "id": "product", + "label": "t:settings.product" + }, + { + "type": "range", + "id": "product_card_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "checkbox", + "id": "inherit_color_scheme", + "label": "t:settings.inherit_color_scheme", + "default": true + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1", + "visible_if": "{{ block.settings.inherit_color_scheme == false }}" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 32, + "step": 1, + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_card", + "category": "t:categories.product", + "settings": { + "product_card_gap": 4 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + ] +} +{% endschema %} diff --git a/blocks/product-description.liquid b/blocks/product-description.liquid new file mode 100644 index 000000000..814d595ae --- /dev/null +++ b/blocks/product-description.liquid @@ -0,0 +1,405 @@ +{% # import schema from '../schemas/blocks/product-description' %} + +{% liquid + assign product = block.settings.product + if request.visual_preview_mode and product == blank + assign product = collections.all.products.first + assign text = product.description + endif +%} + +{% render 'text', fallback_text: text, block: block %} + +{% schema %} +{ + "name": "t:names.text", + "tag": null, + "settings": [ + { + "type": "richtext", + "id": "text", + "label": "t:settings.text", + "default": "t:html_defaults.share_information_about_your" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "fit-content" + }, + { + "type": "select", + "id": "max_width", + "label": "t:settings.max_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "normal" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width == '100%' }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "range", + "id": "corner_radius", + "label": "t:settings.corner_radius", + "default": 0, + "min": 0, + "max": 50, + "step": 1, + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_description", + "category": "t:categories.product", + "settings": { + "text": "{{ closest.product.description }}" + } + } + ] +} +{% endschema %} diff --git a/blocks/product-inventory.liquid b/blocks/product-inventory.liquid new file mode 100644 index 000000000..2ddb4b0c0 --- /dev/null +++ b/blocks/product-inventory.liquid @@ -0,0 +1,184 @@ +{% # import schema from '../schemas/blocks/product-inventory' %} + +{%- liquid + assign variant = closest.product.selected_or_first_available_variant + if variant.inventory_management == 'shopify' + assign inventory_managed = true + endif + assign inventory_quantity = variant.inventory_quantity + assign inventory_policy = variant.inventory_policy + assign threshold = block.settings.inventory_threshold + + if inventory_managed + if inventory_quantity > 0 + if inventory_quantity <= threshold + assign status = 'low' + assign show_quantity = block.settings.show_inventory_quantity + if show_quantity == false + assign translation_key = 'content.inventory_low_stock' + endif + else + assign status = 'in_stock' + assign translation_key = 'content.inventory_in_stock' + endif + else + if inventory_policy == 'continue' + assign status = 'in_stock' + assign translation_key = 'content.inventory_in_stock' + else + assign status = 'out_of_stock' + assign translation_key = 'content.inventory_out_of_stock' + endif + endif + else + if closest.product.selected_or_first_available_variant != null + assign status = 'in_stock' + assign translation_key = 'content.inventory_in_stock' + else + assign status = 'out_of_stock' + assign translation_key = 'content.inventory_out_of_stock' + endif + endif +-%} + + + + + {{ 'icon-inventory.svg' | inline_asset_content }} + + + {%- if show_quantity -%} + {{ 'content.inventory_low_stock_show_count' | t: count: inventory_quantity }} + {%- else -%} + {{- translation_key | t -}} + {%- endif -%} + + + + +{% stylesheet %} + .product-inventory__status { + display: flex; + align-items: center; + font-size: var(--font-paragraph--size); + line-height: var(--font-paragraph--line-height); + gap: var(--padding-xs); + } + + .product-inventory__icon, + .product-inventory__icon svg { + width: var(--icon-size-sm); + height: var(--icon-size-sm); + } + + .product-inventory__icon-low { + color: var(--color-lowstock); + } + + .product-inventory__icon-in_stock { + color: var(--color-instock); + } + + .product-inventory__icon-out_of_stock { + color: var(--color-outofstock); + } + + .product-inventory__icon circle:first-of-type { + opacity: 0.3; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_inventory", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_inventory" + }, + { + "type": "range", + "id": "inventory_threshold", + "label": "t:settings.inventory_threshold", + "min": 0, + "max": 100, + "step": 1, + "default": 10 + }, + { + "type": "checkbox", + "id": "show_inventory_quantity", + "label": "t:settings.show_inventory_quantity", + "default": true + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_inventory", + "category": "t:categories.product" + } + ] +} +{% endschema %} diff --git a/blocks/product-recommendations.liquid b/blocks/product-recommendations.liquid new file mode 100644 index 000000000..fa840d28d --- /dev/null +++ b/blocks/product-recommendations.liquid @@ -0,0 +1,476 @@ +{% # import schema from '../schemas/blocks/product-recommendations.js' %} + +{%- doc -%} + Renders product recommendations. + {section.id} - identifies the parent section for the Section Rendering API + + https://shopify.dev/docs/api/section-rendering-api +{%- enddoc -%} + + + +{% liquid + case block.settings.layout_type + when 'grid' + assign classes = 'resource-list--grid' + when 'carousel' + assign classes = 'resource-list--carousel' + endcase +%} + +{% comment %} + [data-section-id] {section.id} - used to fetch the product recommendations from the Section Rendering API +{% endcomment %} + + +
+
+ {% content_for 'blocks' %} +
+ + {%- if recommendations.performed or closest.product == blank -%} + {% liquid + assign products = recommendations.products + + if closest.product == blank + # Onboarding mode: Show placeholder products + for i in (1..block.settings.max_products) + assign products = products | append: ', ' + assign products = products | split: ',' + endfor + elsif recommendations.performed and recommendations.products_count == 0 + # No recommendations found, pull from catalog + if block.settings.recommendation_type == 'related' + assign products = collections.all.products | reject: 'id', closest.product.id + elsif block.settings.recommendation_type == 'complementary' + # Do not recommend the All collection as complementary products + assign products = null + endif + else + assign products = recommendations.products + endif + %} + {% capture list_items %} + {% for product in products limit: block.settings.max_products %} +
+ {% content_for 'block', + type: '_product-card', + id: 'static-product-card', + closest.product: product + %} +
+ {% if block.settings.layout_type == 'carousel' or block.settings.carousel_on_mobile %} + {% unless forloop.last %} + + {% endunless %} + {% endif %} + {% endfor %} + {% endcapture %} + + {% liquid + # Create an array from the list items to be used in the carousel + assign slide_content = list_items | strip + assign slides = slide_content | split: '' + + if products != blank and products.size > 0 + assign has_recommendations = 'true' + else + assign has_recommendations = 'false' + endif + %} + +
+ {% case block.settings.layout_type %} + {% when 'grid' %} + {{ list_items }} + {% when 'carousel' %} + {% render 'resource-list-carousel', + ref: 'resourceListCarousel', + slides: slides, + slide_count: recommendations.products.size, + settings: block.settings + %} + {% endcase %} +
+ + {% if block.settings.carousel_on_mobile and block.settings.layout_type != 'carousel' %} + {% liquid + assign mobile_carousel_gap = block.settings.columns_gap + %} +
+ {% render 'resource-list-carousel', + ref: 'resourceListCarouselMobile', + slides: slides, + slide_count: recommendations.products.size, + settings: block.settings + %} +
+ {% endif %} + {%- else -%} +
+ {% for i in (1..block.settings.max_products) %} +
+ {% endfor %} +
+ {%- endif -%} +
+
+ +{% stylesheet %} + .product-recommendations-wrapper { + width: 100%; + } + + .product-recommendations-wrapper:has(product-recommendations[data-shopify-editor-preview]) { + width: 100vw; + } + + .product-recommendations { + display: block; + } + + .product-recommendations__skeleton-item { + aspect-ratio: 3 / 4; + background-color: var(--color-foreground); + opacity: var(--skeleton-opacity); + border-radius: 4px; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_recommendations", + "class": "product-recommendations-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + } + ], + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_recommendations" + }, + { + "type": "select", + "id": "recommendation_type", + "label": "t:settings.type", + "options": [ + { + "value": "related", + "label": "t:options.related" + }, + { + "value": "complementary", + "label": "t:options.complementary" + } + ], + "default": "related" + }, + { + "type": "paragraph", + "content": "t:content.complementary_products" + }, + { + "type": "header", + "content": "t:content.cards_layout" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.layout_style", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + } + ], + "default": "grid" + }, + { + "type": "checkbox", + "id": "carousel_on_mobile", + "label": "t:settings.carousel_on_mobile", + "default": true, + "visible_if": "{{ block.settings.layout_type == 'grid' }}" + }, + { + "type": "range", + "id": "max_products", + "label": "t:settings.product_count", + "min": 2, + "max": 10, + "step": 1, + "default": 4 + }, + { + "type": "range", + "id": "columns_gap", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16, + "visible_if": "{{ block.settings.layout_type == 'grid' or block.settings.layout_type == 'carousel' }}" + }, + { + "type": "range", + "id": "rows_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16, + "visible_if": "{{ block.settings.layout_type == 'grid' }}" + }, + { + "type": "header", + "content": "t:content.carousel_navigation", + "visible_if": "{{ block.settings.layout_type == 'carousel' or block.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icon", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.arrows_large" + }, + { + "value": "chevron_large", + "label": "t:options.chevron_large" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrow", + "visible_if": "{{ block.settings.layout_type == 'carousel' or block.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_shape", + "label": "t:settings.icon_background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "none", + "visible_if": "{{ block.settings.icons_style != 'none' and block.settings.layout_type == 'carousel' or block.settings.carousel_on_mobile == true }}" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_recommendations", + "category": "t:categories.product", + "settings": { + "recommendation_type": "related" + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

You may also like

" + } + }, + "static-product-card": { + "type": "_product-card", + "static": true, + "settings": { + "product_card_gap": 4 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + }, + "block_order": ["heading"] + } + ] +} +{% endschema %} diff --git a/blocks/product-title.liquid b/blocks/product-title.liquid new file mode 100644 index 000000000..98e18716e --- /dev/null +++ b/blocks/product-title.liquid @@ -0,0 +1,399 @@ +{% # import schema from '../schemas/blocks/product-title' %} + +{% if closest.product == blank %} + {% assign text = 'placeholders.product_title' | t %} + {% assign product_title = '

' | append: text | append: '

' %} + {% render 'text', fallback_text: product_title, block: block %} +{% elsif closest.product != blank %} + {% assign product_title = '

' | append: closest.product.title | append: '

' %} + {% render 'text', fallback_text: product_title, block: block %} +{% endif %} + +{% schema %} +{ + "name": "t:names.product_title", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_title" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "fit-content" + }, + { + "type": "select", + "id": "max_width", + "label": "t:settings.max_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "normal" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width == '100%' }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "range", + "id": "corner_radius", + "label": "t:settings.corner_radius", + "default": 0, + "min": 0, + "max": 50, + "step": 1, + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.title", + "category": "t:categories.product" + } + ] +} +{% endschema %} diff --git a/blocks/quantity.liquid b/blocks/quantity.liquid new file mode 100644 index 000000000..fd53e8506 --- /dev/null +++ b/blocks/quantity.liquid @@ -0,0 +1,10 @@ +{% # import schema from '../schemas/blocks/quantity.js' %} + +{% render 'quantity-selector', product: closest.product %} + +{% schema %} +{ + "name": "t:names.quantity", + "tag": null +} +{% endschema %} diff --git a/blocks/review.liquid b/blocks/review.liquid new file mode 100644 index 000000000..204c18e4b --- /dev/null +++ b/blocks/review.liquid @@ -0,0 +1,269 @@ +{% # import schema from '../schemas/blocks/review.js' %} + +{% liquid + assign product = closest.product + assign rating = product.metafields.reviews.rating.value.rating + assign scale_max = product.metafields.reviews.rating.value.scale_max + assign rating_count = product.metafields.reviews.rating_count + + if request.visual_preview_mode and product == blank + assign product = collections.all.products.first + assign rating = product.metafields.reviews.rating.value | default: 4 + assign scale_max = product.metafields.reviews.rating.value.scale_max | default: 5 + assign rating_count = product.metafields.reviews.rating_count | default: 3 + endif +-%} + +{%- if rating != blank -%} + {% liquid + assign star_count_rating = scale_max + assign decimal_rating = 0 + assign decimal = rating | modulo: 1 + + if decimal >= 0.3 and decimal <= 0.7 + assign decimal_rating = 0.5 + elsif decimal > 0.7 + assign decimal_rating = 1 + endif + + # this is used so I can tell how many stars I need to fill. When the decimal rating above is 0.5 or 1 I count it as one as the half star is dealt with with a SVG linear gradient. + assign decimal_rounded = decimal_rating | ceil + + assign svg_filled_stars = rating | floor | plus: decimal_rounded + %} + +
+ + + + + + + + + + + + +
+ {% if block.settings.stars_style == 'single' %} + + + + {% else %} + {%- for star in (1..star_count_rating) -%} + + + {% if block.settings.stars_style == "outline" %} + + {% endif %} + + {%- endfor -%} + {% endif %} +
+ + {%- if block.settings.show_number or block.settings.stars_style == 'single' -%} +

+ {%- if block.settings.stars_style == 'single' -%} + + {%- endif -%} + {%- if block.settings.stars_style == 'single' and block.settings.show_number -%} + | + {%- endif -%} + {%- if block.settings.show_number -%} + {{- rating_count }} + {{ 'content.reviews' | t }} + {%- endif -%} +

+ {%- endif -%} +
+{%- endif -%} + +{% stylesheet %} + .rating-wrapper { + width: 100%; + gap: var(--gap-xs); + flex-wrap: wrap; + } + + .rating-color--primary { + --star-fill-color: var(--color-primary); + --star-fill-color-rgb: var(--color-primary-rgb); + } + + .rating-color--foreground { + --star-fill-color: var(--color-foreground); + --star-fill-color-rgb: var(--color-foreground-rgb); + } + + .rating-wrapper, + .rating { + display: flex; + align-items: center; + } + + .rating-wrapper.justify-right { + flex-direction: row-reverse; + } + + .rating { + gap: var(--gap-3xs); + } + + .rating-wrapper .rating-text, + .rating-wrapper .rating-count, + .rating-wrapper .rating-count-separator { + color: var(--star-fill-color); + margin: 0; + white-space: nowrap; + } + + .rating-count-separator { + opacity: var(--opacity-20); + padding-left: calc(var(--padding-xs) / 2); + padding-right: var(--padding-xs); + } + + .stars { + height: var(--star-size); + fill: var(--empty-star-fill-color); + } + + .filled-star { + fill: var(--star-fill-color); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_review_stars", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_review" + }, + { + "type": "paragraph", + "content": "t:content.app_required_for_ratings" + }, + { + "type": "select", + "id": "stars_style", + "label": "t:settings.style", + "options": [ + { + "value": "outline", + "label": "t:options.outline" + }, + { + "value": "shaded", + "label": "t:options.shaded" + }, + { + "value": "single", + "label": "t:options.single" + } + ], + "default": "shaded" + }, + { + "type": "checkbox", + "id": "show_number", + "label": "t:settings.review_count", + "default": true + }, + { + "type": "select", + "id": "rating_color", + "label": "t:settings.color", + "options": [ + { + "value": "foreground", + "label": "t:options.text" + }, + { + "value": "primary", + "label": "t:options.body" + } + ], + "default": "primary" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "paragraph" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left" + } + ], + "presets": [ + { + "name": "t:names.product_review_stars", + "category": "t:categories.product" + } + ] +} +{% endschema %} diff --git a/blocks/spacer.liquid b/blocks/spacer.liquid new file mode 100644 index 000000000..3baaa9df6 --- /dev/null +++ b/blocks/spacer.liquid @@ -0,0 +1,184 @@ +{% # import schema from '../schemas/blocks/spacer' %} + +
+ +{% stylesheet %} + /* Fill opposite direction */ + .layout-panel-flex--column > .spacer-block { + width: 100%; + } + + .layout-panel-flex--row > .spacer-block { + height: 100%; + } + + /* Flex - Percent */ + :is(.layout-panel-flex--row, .layout-panel-flex--column) > .spacer-block--size-percent { + flex: var(--spacer-size); + } + + /* Flex - Pixel */ + .layout-panel-flex--row > .spacer-block--size-pixel { + width: var(--spacer-size); + } + + .layout-panel-flex--column > .spacer-block--size-pixel { + height: var(--spacer-size); + } + + /* Mobile */ + @media screen and (max-width: 750px) { + /* Percent */ + .layout-panel-flex--row:not(.mobile-column) > .spacer-block--size-mobile-percent { + flex: var(--spacer-size-mobile); + height: 100%; + } + + .layout-panel-flex--column > .spacer-block--size-mobile-percent, + .mobile-column > .spacer-block--size-percent:not(.spacer-block--size-mobile-pixel) { + width: 100%; + flex: var(--spacer-size-mobile); + } + + /* Pixel */ + .layout-panel-flex--row:not(.mobile-column) > .spacer-block--size-mobile-pixel { + width: var(--spacer-size-mobile); + height: 100%; + } + + .layout-panel-flex--column > .spacer-block--size-mobile-pixel, + .mobile-column > .spacer-block--size-mobile-pixel { + width: 100%; + flex: 0; + height: var(--spacer-size-mobile); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.spacer", + "tag": null, + "settings": [ + { + "type": "select", + "id": "size", + "label": "t:settings.unit", + "options": [ + { + "value": "pixel", + "label": "t:options.pixel" + }, + { + "value": "percent", + "label": "t:options.percent" + } + ], + "default": "percent" + }, + { + "type": "range", + "id": "percent_size", + "label": "t:settings.size", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.size == 'percent' }}" + }, + { + "type": "range", + "id": "pixel_size", + "label": "t:settings.size", + "min": 0, + "max": 400, + "step": 4, + "unit": "px", + "default": 120, + "visible_if": "{{ block.settings.size == 'pixel' }}" + }, + { + "type": "checkbox", + "id": "custom_mobile_size", + "label": "t:settings.custom_mobile_size", + "default": false + }, + { + "type": "header", + "content": "t:content.mobile_size", + "visible_if": "{{ block.settings.custom_mobile_size == true }}" + }, + { + "type": "select", + "id": "size_mobile", + "label": "t:settings.unit", + "options": [ + { + "value": "pixel", + "label": "t:options.pixel" + }, + { + "value": "percent", + "label": "t:options.percent" + } + ], + "default": "percent", + "visible_if": "{{ block.settings.custom_mobile_size == true }}" + }, + { + "type": "range", + "id": "percent_size_mobile", + "label": "t:settings.size", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100, + "visible_if": "{{ block.settings.size_mobile == 'percent' and block.settings.custom_mobile_size == true}}" + }, + { + "type": "range", + "id": "pixel_size_mobile", + "label": "t:settings.size", + "min": 0, + "max": 400, + "step": 4, + "unit": "px", + "default": 120, + "visible_if": "{{ block.settings.size_mobile == 'pixel' and block.settings.custom_mobile_size == true}}" + } + ], + "presets": [ + { + "name": "t:names.spacer", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/blocks/swatches.liquid b/blocks/swatches.liquid new file mode 100644 index 000000000..52c65e260 --- /dev/null +++ b/blocks/swatches.liquid @@ -0,0 +1,216 @@ +{% # import schema from '../schemas/blocks/swatches.js' %} + +{%- liquid + for product_option in closest.product.options_with_values + assign swatch_count = product_option.values | map: 'swatch' | compact | size + + if swatch_count > 0 + assign product_has_swatches = true + endif + endfor +-%} + +{% if product_has_swatches %} + + {% render 'variant-swatches', product_resource: closest.product %} + +{% endif %} + +{% # theme-check-disable %} +{% stylesheet %} + product-swatches { + width: 100%; + display: flex; + justify-content: var(--product-swatches-alignment); + flex-direction: row; + position: relative; + overflow: hidden; + gap: 0; + flex-shrink: 0; + + @media (max-width: 749px) { + justify-content: var(--product-swatches-alignment-mobile); + } + } + + swatches-variant-picker-component { + display: flex; + width: 100%; + flex-direction: row; + } + + swatches-variant-picker-component .variant-option--swatches { + padding-block: calc( + var(--product-swatches-padding-block-start) + var(--focus-outline-offset) + var(--focus-outline-width) + ) + calc(var(--product-swatches-padding-block-end) + var(--focus-outline-offset) + var(--focus-outline-width)); + padding-inline: calc( + var(--product-swatches-padding-inline-start) + var(--focus-outline-offset) + (1.5 * var(--focus-outline-width)) + ) + calc(var(--product-swatches-padding-inline-end) + var(--focus-outline-offset) + var(--focus-outline-width)); + } + + .variant-option--swatches { + overflow-list::part(list) { + gap: var(--gap-sm); + } + + overflow-list[defer]::part(list) { + flex-wrap: nowrap; + } + } + + .hidden-swatches__count { + display: flex; + align-self: center; + align-items: center; + justify-content: center; + color: rgb(var(--color-foreground-rgb) / var(--opacity-40-60)); + background-color: transparent; + padding: 0; + border: 0; + border-radius: 0; + + &::before { + /* This doesn't work in Safari without the counter-reset. https://stackoverflow.com/a/40179718 */ + counter-reset: overflow-count var(--overflow-count); + content: '+' counter(overflow-count); + line-height: 1; + cursor: pointer; + } + } + + .hidden-swatches__count:hover { + color: var(--color-foreground-rgb); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.swatches", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_swatches" + }, + { + "type": "select", + "id": "product_swatches_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "select", + "id": "product_swatches_alignment_mobile", + "label": "t:settings.alignment_mobile", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "header", + "content": "t:content.padding", + "visible_if": "{{ block.settings.hide_padding == false }}" + }, + { + "type": "checkbox", + "id": "hide_padding", + "label": "t:settings.hide_padding", + "default": false, + "visible_if": "{{ false }}" + }, + { + "type": "range", + "id": "product_swatches_padding_top", + "label": "t:settings.top", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 4, + "visible_if": "{{ block.settings.hide_padding == false }}" + }, + { + "type": "range", + "id": "product_swatches_padding_bottom", + "label": "t:settings.bottom", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0, + "visible_if": "{{ block.settings.hide_padding == false }}" + }, + { + "type": "range", + "id": "product_swatches_padding_left", + "label": "t:settings.left", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0, + "visible_if": "{{ block.settings.hide_padding == false }}" + }, + { + "type": "range", + "id": "product_swatches_padding_right", + "label": "t:settings.right", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 0, + "visible_if": "{{ block.settings.hide_padding == false }}" + } + ], + "presets": [ + { + "name": "t:names.swatches", + "category": "t:categories.product" + } + ] +} +{% endschema %} +{% # theme-check-enable %} diff --git a/blocks/text.liquid b/blocks/text.liquid new file mode 100644 index 000000000..4f565a1af --- /dev/null +++ b/blocks/text.liquid @@ -0,0 +1,404 @@ +{% # import schema from '../schemas/blocks/text' %} + +{% render 'text', block: block %} + +{% schema %} +{ + "name": "t:names.text", + "tag": null, + "settings": [ + { + "type": "richtext", + "id": "text", + "label": "t:settings.text", + "default": "t:html_defaults.share_information_about_your" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "width", + "label": "t:settings.width", + "options": [ + { + "value": "fit-content", + "label": "t:options.fit" + }, + { + "value": "100%", + "label": "t:options.fill" + } + ], + "default": "fit-content" + }, + { + "type": "select", + "id": "max_width", + "label": "t:settings.max_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "normal" + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left", + "visible_if": "{{ block.settings.width == '100%' }}" + }, + { + "type": "header", + "content": "t:content.typography" + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.preset", + "options": [ + { + "value": "rte", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "rte", + "info": "t:info.edit_presets_in_theme_settings" + }, + { + "type": "select", + "id": "font", + "label": "t:settings.font", + "options": [ + { + "value": "var(--font-body--family)", + "label": "t:options.body" + }, + { + "value": "var(--font-subheading--family)", + "label": "t:options.subheading" + }, + { + "value": "var(--font-heading--family)", + "label": "t:options.heading" + }, + { + "value": "var(--font-accent--family)", + "label": "t:options.accent" + } + ], + "default": "var(--font-body--family)", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "font_size", + "label": "t:settings.size", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + }, + { + "value": "1.25rem", + "label": "20px" + }, + { + "value": "1.5rem", + "label": "24px" + }, + { + "value": "2rem", + "label": "32px" + }, + { + "value": "2.5rem", + "label": "40px" + }, + { + "value": "3rem", + "label": "48px" + }, + { + "value": "3.5rem", + "label": "56px" + }, + { + "value": "4.5rem", + "label": "72px" + }, + { + "value": "5.5rem", + "label": "88px" + }, + { + "value": "7.5rem", + "label": "120px" + }, + { + "value": "9.5rem", + "label": "152px" + }, + { + "value": "11.5rem", + "label": "184px" + } + ], + "default": "1rem", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "line_height", + "label": "t:settings.line_height", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "letter_spacing", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "tight", + "label": "t:options.tight" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "loose", + "label": "t:options.loose" + } + ], + "default": "normal", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "case", + "label": "t:settings.case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none", + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "wrap", + "label": "t:settings.wrap", + "options": [ + { + "value": "pretty", + "label": "t:options.pretty" + }, + { + "value": "balance", + "label": "t:options.balance" + }, + { + "value": "nowrap", + "label": "t:options.none" + } + ], + "visible_if": "{{ block.settings.type_preset == 'custom' }}" + }, + { + "type": "select", + "id": "color", + "label": "t:settings.color", + "options": [ + { + "value": "var(--color-foreground)", + "label": "t:options.text" + }, + { + "value": "var(--color-foreground-heading)", + "label": "t:options.heading" + }, + { + "value": "var(--color-primary)", + "label": "t:options.link" + } + ], + "default": "var(--color-foreground)", + "visible_if": "{{ block.settings.type_preset != 'rte' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "checkbox", + "id": "background", + "label": "t:settings.background", + "default": false + }, + { + "type": "color", + "id": "background_color", + "label": "t:settings.background_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "range", + "id": "corner_radius", + "label": "t:settings.corner_radius", + "default": 0, + "min": 0, + "max": 50, + "step": 1, + "visible_if": "{{ block.settings.background }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.text", + "category": "t:categories.basic", + "settings": { + "text": "

We make things that work better and last longer. Our products solve real problems with clean design and honest materials.

" + } + }, + { + "name": "t:names.heading", + "category": "t:categories.basic", + "settings": { + "text": "

New arrivals

" + } + } + ] +} +{% endschema %} diff --git a/blocks/variant-picker.liquid b/blocks/variant-picker.liquid new file mode 100644 index 000000000..2812cf2b7 --- /dev/null +++ b/blocks/variant-picker.liquid @@ -0,0 +1,105 @@ +{% # import schema from '../schemas/blocks/variant-picker.js' %} + +{% liquid + assign product_resource = closest.product + if request.visual_preview_mode and product_resource == blank + assign product_resource = collections.all.products.first + endif +-%} + +{% render 'variant-main-picker', product_resource: product_resource %} + +{% schema %} +{ + "name": "t:names.product_variant_picker", + "tag": null, + "settings": [ + { + "type": "paragraph", + "content": "t:content.resource_reference_product_variant_picker" + }, + { + "type": "paragraph", + "content": "t:content.edit_variants_in_theme_settings" + }, + { + "type": "select", + "id": "variant_style", + "label": "t:settings.style", + "options": [ + { + "value": "dropdowns", + "label": "t:options.dropdowns" + }, + { + "value": "buttons", + "label": "t:options.buttons" + } + ], + "default": "buttons" + }, + { + "type": "checkbox", + "id": "show_swatches", + "label": "t:settings.swatches", + "default": true + }, + { + "type": "text_alignment", + "id": "alignment", + "label": "t:settings.alignment", + "default": "left" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_variant_picker", + "category": "t:categories.product" + } + ] +} +{% endschema %} diff --git a/blocks/video.liquid b/blocks/video.liquid new file mode 100644 index 000000000..c73303a33 --- /dev/null +++ b/blocks/video.liquid @@ -0,0 +1,254 @@ +{% # import schema from '../schemas/blocks/video.js' %} + +{% capture video_style %} + {% render 'spacing-style', settings: block.settings %} + {% render 'border-override', settings: block.settings %} + --size-style-width: {{ block.settings.custom_width }}%; --size-style-width-mobile: {{ block.settings.custom_width_mobile }}%; + --size-style-aspect-ratio: {% if block.settings.source == 'uploaded' %}{{ block.settings.video.aspect_ratio | default: 'auto' }}{% elsif block.settings.cover_image == blank %}{{ block.settings.aspect_ratio }}{% else %}auto{% endif %}; +{% endcapture %} + +{% if block.settings.source == 'uploaded' %} + {% render 'video', + video: block.settings.video, + video_class: 'spacing-style size-style border-style', + video_loop: block.settings.video_loop, + video_style: video_style, + video_preview_image: block.settings.video.preview_image, + additional_attributes: block.shopify_attributes, + section_id: section.id + %} +{% else %} + {% render 'video', + video_from_url: true, + video: block.settings.video_url.id, + video_class: 'spacing-style size-style border-style', + video_type: block.settings.video_url.type, + video_style: video_style, + video_alt: block.settings.alt, + video_preview_image: block.settings.cover_image, + additional_attributes: block.shopify_attributes, + section_id: section.id + %} +{% endif %} + +{% stylesheet %} + .placeholder-video { + aspect-ratio: 5 / 3; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.video", + "tag": null, + "settings": [ + { + "type": "select", + "id": "source", + "label": "t:settings.video_source", + "options": [ + { + "value": "uploaded", + "label": "t:options.video_uploaded" + }, + { + "value": "url", + "label": "t:options.video_external_url" + } + ], + "default": "uploaded" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ block.settings.source == 'uploaded' }}" + }, + { + "type": "video_url", + "id": "video_url", + "label": "t:settings.video_external_url", + "info": "t:info.video_external", + "accept": ["youtube", "vimeo"], + "visible_if": "{{ block.settings.source == 'url' }}" + }, + { + "type": "checkbox", + "id": "video_autoplay", + "label": "t:settings.video_autoplay", + "info": "t:info.video_autoplay", + "default": false + }, + { + "type": "checkbox", + "id": "video_loop", + "label": "t:settings.video_loop", + "default": true + }, + { + "type": "image_picker", + "id": "cover_image", + "label": "t:settings.cover_image", + "visible_if": "{{ block.settings.source == 'url' and block.settings.video_autoplay == false }}" + }, + { + "type": "text", + "id": "alt", + "label": "t:settings.video_alt_text", + "info": "t:info.video_alt_text", + "visible_if": "{{ block.settings.source == 'url' }}" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "range", + "id": "custom_width", + "label": "t:settings.width", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100 + }, + { + "type": "range", + "id": "custom_width_mobile", + "label": "t:settings.width_mobile", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 100 + }, + { + "type": "select", + "id": "aspect_ratio", + "label": "t:settings.aspect_ratio", + "visible_if": "{{ block.settings.source == 'url' and block.settings.cover_image == blank }}", + "options": [ + { + "value": "auto", + "label": "t:options.auto" + }, + { + "value": "9/16", + "label": "t:options.portrait" + }, + { + "value": "1/1", + "label": "t:options.square" + }, + { + "value": "16/9", + "label": "t:options.landscape" + } + ], + "default": "auto" + }, + { + "type": "header", + "content": "t:content.borders" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.thickness", + "default": 1, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.opacity", + "default": 100, + "visible_if": "{{ block.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.video", + "category": "t:categories.basic" + } + ] +} +{% endschema %} diff --git a/config/settings_data.json b/config/settings_data.json new file mode 100644 index 000000000..dd30bff28 --- /dev/null +++ b/config/settings_data.json @@ -0,0 +1,420 @@ +{ + "current": { + "type_line_height_h1": "display-tight", + "type_letter_spacing_h1": "heading-tight", + "type_font_h1": "heading", + "type_case_h1": "none", + "type_font_h2": "heading", + "type_case_h2": "none", + "type_font_h3": "heading", + "type_line_height_h3": "heading-tight", + "type_letter_spacing_h3": "heading-tight", + "type_case_h3": "none", + "type_size_h5": "14", + "type_size_h6": "14", + "type_size_paragraph": "14", + "page_width": "wide", + "primary_button_border_width": 0, + "button_border_radius_primary": 37, + "secondary_button_border_width": 1, + "button_border_radius_secondary": 37, + "variant_swatch_width": 24, + "variant_swatch_height": 24, + "variant_swatch_radius": 24, + "variant_button_border_width": 1, + "variant_button_radius": 0, + "variant_button_width": "equal-width-buttons", + "input_border_width": 1, + "inputs_border_radius": 8, + "icon_stroke": "thin", + "badge_position": "top-right", + "badge_corner_radius": 2, + "badge_sale_color_scheme": "scheme-5", + "badge_sold_out_color_scheme": "scheme-3", + "badge_text_transform": "none", + "cart_type": "drawer", + "currency_code_enabled_product_pages": false, + "currency_code_enabled_product_cards": false, + "currency_code_enabled_cart_items": false, + "empty_state_collection": "featured-products-4", + "popover_border_radius": 12, + "popover_border": "none", + "page_transition_type": "dissolve", + "badge_padding_block": 2, + "badge_padding_inline": 8, + "variant_button_style": "variant-button-style-outline", + "content_for_index": [], + "color_schemes": { + "scheme-1": { + "settings": { + "background": "#ffffff", + "foreground_heading": "#000000", + "foreground": "#000000", + "primary": "#000f9f", + "primary_hover": "#000000", + "border": "#00000030", + "shadow": "#000000", + "primary_button_background": "#000000", + "primary_button_text": "#ffffff", + "primary_button_border": "#000000", + "primary_button_hover_background": "#000000", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_border": "#000000", + "secondary_button_background": "#ffffff", + "secondary_button_text": "#000000", + "secondary_button_border": "#000000", + "secondary_button_hover_background": "#dedede", + "secondary_button_hover_text": "#000000", + "secondary_button_hover_border": "#000000", + "input_background": "#0000000d", + "input_text_color": "#000000", + "input_border_color": "rgba(0,0,0,0)", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-2": { + "settings": { + "background": "#ffffff", + "foreground_heading": "#000000", + "foreground": "#000000", + "primary": "#000000", + "primary_hover": "#000000", + "border": "#e6e6e6", + "shadow": "#000000", + "primary_button_background": "#000000", + "primary_button_text": "#ffffff", + "primary_button_border": "#000000", + "primary_button_hover_background": "#000f9f", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_border": "#000f9f", + "secondary_button_background": "#ffffff", + "secondary_button_text": "#000000", + "secondary_button_border": "#000000", + "secondary_button_hover_background": "#ffffff", + "secondary_button_hover_text": "#000f9f", + "secondary_button_hover_border": "#000f9f", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-3": { + "settings": { + "background": "#f7f7f7", + "foreground_heading": "#000000", + "foreground": "#000000", + "primary": "#000f9f", + "primary_hover": "#000000", + "border": "#d6d4d3", + "shadow": "#000000", + "primary_button_background": "#000000", + "primary_button_text": "#ffffff", + "primary_button_border": "#000000", + "primary_button_hover_background": "#000000", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_border": "#000000", + "secondary_button_background": "#000000", + "secondary_button_text": "#000f9f", + "secondary_button_border": "#000f9f", + "secondary_button_hover_background": "#efefef", + "secondary_button_hover_text": "#000000", + "secondary_button_hover_border": "#000000", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-4": { + "settings": { + "background": "#000f9f", + "foreground_heading": "#ffffff", + "foreground": "#ffffff", + "primary": "#ffffff", + "primary_hover": "#b6baff", + "border": "#535dbc", + "shadow": "#000000", + "primary_button_background": "#ffffff", + "primary_button_text": "#000f9f", + "primary_button_border": "#ffffff", + "primary_button_hover_background": "#dee0ff", + "primary_button_hover_text": "#000f9f", + "primary_button_hover_border": "#dee0ff", + "secondary_button_background": "#000000", + "secondary_button_text": "#ffffff", + "secondary_button_border": "#ffffff", + "secondary_button_hover_background": "#000f9f", + "secondary_button_hover_text": "#b6baff", + "secondary_button_hover_border": "#b6baff", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-5": { + "settings": { + "background": "#000000cf", + "foreground_heading": "#ffffff", + "foreground": "#ffffff", + "primary": "#ffffff", + "primary_hover": "#acacac", + "border": "#666666", + "shadow": "#000000", + "primary_button_background": "#ffffff", + "primary_button_text": "#000000", + "primary_button_border": "#ffffff", + "primary_button_hover_background": "#dedede", + "primary_button_hover_text": "#000000", + "primary_button_hover_border": "#dedede", + "secondary_button_background": "#000000", + "secondary_button_text": "#ffffff", + "secondary_button_border": "#ffffff", + "secondary_button_hover_background": "#000000", + "secondary_button_hover_text": "#acacac", + "secondary_button_hover_border": "#acacac", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-6": { + "settings": { + "background": "rgba(0,0,0,0)", + "foreground_heading": "#ffffff", + "foreground": "#ffffff", + "primary": "#ffffff", + "primary_hover": "#acacac", + "border": "rgba(0,0,0,0)", + "shadow": "rgba(0,0,0,0)", + "primary_button_background": "#ffffff", + "primary_button_text": "#000000", + "primary_button_border": "#ffffff", + "primary_button_hover_background": "#dedede", + "primary_button_hover_text": "#000000", + "primary_button_hover_border": "#dedede", + "secondary_button_background": "rgba(0,0,0,0)", + "secondary_button_text": "#ffffff", + "secondary_button_border": "#ffffff", + "secondary_button_hover_background": "rgba(0,0,0,0)", + "secondary_button_hover_text": "#acacac", + "secondary_button_hover_border": "#acacac", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + }, + "scheme-58084d4c-a86e-4d0a-855e-a0966e5043f7": { + "settings": { + "background": "#00000008", + "foreground_heading": "#000000", + "foreground": "#000000", + "primary": "#000000", + "primary_hover": "#000000", + "border": "#e6e6e6", + "shadow": "#000000", + "primary_button_background": "#000000", + "primary_button_text": "#ffffff", + "primary_button_border": "#000000", + "primary_button_hover_background": "#000000cc", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_border": "#000000cf", + "secondary_button_background": "#efefef", + "secondary_button_text": "#000000", + "secondary_button_border": "#000f9f", + "secondary_button_hover_background": "#dedede", + "secondary_button_hover_text": "#000000", + "secondary_button_hover_border": "#000000", + "input_background": "#ffffff", + "input_text_color": "#000000", + "input_border_color": "#000000", + "variant_background_color": "#ffffff", + "variant_text_color": "#000000", + "variant_border_color": "#e6e6e6", + "selected_variant_background_color": "#000000", + "selected_variant_text_color": "#ffffff", + "selected_variant_border_color": "#000000" + } + } + } + }, + "presets": { + "Default": { + "color_schemes": { + "scheme-1": { + "settings": { + "background": "#ffffff", + "foreground": "#000000", + "foreground_heading": "#000000", + "primary": "#000f9f", + "border": "#E6E6E6", + "divider": "#E6E6E6", + "primary_button_text": "#ffffff", + "primary_button_background": "#000f9f", + "primary_button_border": "#000f9f", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_background": "#000000", + "primary_button_hover_border": "#000000", + "secondary_button_text": "#000f9f", + "secondary_button_background": "#ffffff", + "secondary_button_border": "#000f9f", + "secondary_button_hover_text": "#000000", + "secondary_button_hover_background": "#ffffff", + "secondary_button_hover_border": "#000000" + } + }, + "scheme-2": { + "settings": { + "background": "#ffffff", + "foreground": "#000000", + "foreground_heading": "#000000", + "primary": "#000000", + "primary_hover": "#000f9f", + "border": "#E6E6E6", + "divider": "#E6E6E6", + "shadow": "#000000", + "primary_button_text": "#ffffff", + "primary_button_background": "#000000", + "primary_button_border": "#000000", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_background": "#000f9f", + "primary_button_hover_border": "#000f9f", + "secondary_button_text": "#000000", + "secondary_button_background": "#ffffff", + "secondary_button_border": "#000000", + "secondary_button_hover_text": "#000f9f", + "secondary_button_hover_background": "#ffffff", + "secondary_button_hover_border": "#000f9f" + } + }, + "scheme-3": { + "settings": { + "background": "#F5F5F5", + "foreground": "#000000", + "foreground_heading": "#000000", + "primary": "#000F9F", + "primary_hover": "#000000", + "border": "#D0D0D0", + "divider": "#D0D0D0", + "shadow": "#000000", + "primary_button_text": "#ffffff", + "primary_button_background": "#000f9f", + "primary_button_border": "#000f9f", + "primary_button_hover_text": "#ffffff", + "primary_button_hover_background": "#000000", + "primary_button_hover_border": "#000000", + "secondary_button_text": "#000f9f", + "secondary_button_background": "#efefef", + "secondary_button_border": "#000f9f", + "secondary_button_hover_text": "#000000", + "secondary_button_hover_background": "#efefef", + "secondary_button_hover_border": "#000000" + } + }, + "scheme-4": { + "settings": { + "foreground": "#FFFFFF", + "foreground_heading": "#FFFFFF", + "primary": "#FFFFFF", + "primary_hover": "#B6BAFF", + "border": "#535DBC", + "divider": "#535DBC", + "shadow": "#000000", + "primary_button_text": "#000F9F", + "primary_button_background": "#ffffff", + "primary_button_border": "#ffffff", + "primary_button_hover_text": "#000F9F", + "primary_button_hover_background": "#DEE0FF", + "primary_button_hover_border": "#DEE0FF", + "secondary_button_text": "#ffffff", + "secondary_button_background": "000F9F", + "secondary_button_border": "#ffffff", + "secondary_button_hover_text": "#B6BAFF", + "secondary_button_hover_background": "#000F9F", + "secondary_button_hover_border": "#B6BAFF" + } + }, + "scheme-5": { + "settings": { + "background": "#000000", + "foreground": "#ffffff", + "foreground_heading": "#ffffff", + "primary": "#ffffff", + "primary_hover": "#ACACAC", + "border": "#666666", + "divider": "#666666", + "shadow": "#000000", + "primary_button_text": "#000000", + "primary_button_background": "#ffffff", + "primary_button_border": "#ffffff", + "primary_button_hover_text": "#000000", + "primary_button_hover_background": "#DEDEDE", + "primary_button_hover_border": "#DEDEDE", + "secondary_button_text": "#ffffff", + "secondary_button_background": "#000000", + "secondary_button_border": "#ffffff", + "secondary_button_hover_text": "#ACACAC", + "secondary_button_hover_background": "#000000", + "secondary_button_hover_border": "#ACACAC" + } + }, + "scheme-6": { + "settings": { + "foreground": "#FFFFFF", + "foreground_heading": "#FFFFFF", + "primary": "#FFFFFF", + "primary_hover": "#ACACAC", + "border": "rgba(0,0,0,0)", + "divider": "rgba(0,0,0,0)", + "shadow": "#000000", + "primary_button_text": "#000000", + "primary_button_background": "#ffffff", + "primary_button_border": "#ffffff", + "primary_button_hover_text": "#000000", + "primary_button_hover_background": "#DEDEDE", + "primary_button_hover_border": "#DEDEDE", + "secondary_button_text": "#ffffff", + "secondary_button_background": "rgba(0,0,0,0)", + "secondary_button_border": "#ffffff", + "secondary_button_hover_text": "#ACACAC", + "secondary_button_hover_background": "rgba(0,0,0,0)", + "secondary_button_hover_border": "#ACACAC" + } + } + } + } + } +} \ No newline at end of file diff --git a/config/settings_schema.json b/config/settings_schema.json new file mode 100644 index 000000000..b848975a1 --- /dev/null +++ b/config/settings_schema.json @@ -0,0 +1,2317 @@ +[ + { + "name": "theme_info", + "theme_name": "Horizon", + "theme_version": "2.0.2", + "theme_author": "Shopify", + "theme_documentation_url": "https://help.shopify.com/manual/online-store/themes", + "theme_support_url": "https://support.shopify.com/" + }, + { + "name": "t:names.logo_and_favicon", + "settings": [ + { + "type": "paragraph", + "content": "t:content.manage_store_name" + }, + { + "type": "image_picker", + "id": "logo", + "label": "t:settings.default_logo" + }, + { + "type": "image_picker", + "id": "logo_inverse", + "label": "t:settings.inverse_logo", + "info": "t:content.inverse_logo_info" + }, + { + "type": "image_picker", + "id": "favicon", + "label": "t:settings.favicon" + } + ] + }, + { + "name": "t:names.colors", + "settings": [ + { + "type": "color_scheme_group", + "id": "color_schemes", + "definition": [ + { + "type": "color", + "id": "background", + "label": "t:settings.background", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "foreground_heading", + "label": "t:settings.headings", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "foreground", + "label": "t:settings.text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "primary", + "label": "t:settings.primary_color", + "default": "#000F9F", + "alpha": true + }, + { + "type": "color", + "id": "primary_hover", + "label": "t:settings.primary_hover_color", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "border", + "label": "t:settings.borders", + "default": "#E6E6E6", + "alpha": true + }, + { + "type": "color", + "id": "shadow", + "label": "t:settings.shadow_color", + "default": "#000000", + "alpha": true + }, + { + "type": "header", + "content": "t:names.primary_button" + }, + { + "type": "color", + "id": "primary_button_background", + "label": "t:settings.background", + "default": "#000F9F", + "alpha": true + }, + { + "type": "color", + "id": "primary_button_text", + "label": "t:settings.text", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "primary_button_border", + "label": "t:settings.borders", + "default": "#000F9F", + "alpha": true + }, + { + "type": "color", + "id": "primary_button_hover_background", + "label": "t:settings.hover_background", + "default": "#000F9F", + "alpha": true + }, + { + "type": "color", + "id": "primary_button_hover_text", + "label": "t:settings.hover_text", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "primary_button_hover_border", + "label": "t:settings.hover_borders", + "default": "#000F9F", + "alpha": true + }, + { + "type": "header", + "content": "t:names.secondary_button" + }, + { + "type": "color", + "id": "secondary_button_background", + "label": "t:settings.background", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "secondary_button_text", + "label": "t:settings.text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "secondary_button_border", + "label": "t:settings.borders", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "secondary_button_hover_background", + "label": "t:settings.hover_background", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "secondary_button_hover_text", + "label": "t:settings.hover_text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "secondary_button_hover_border", + "label": "t:settings.hover_borders", + "default": "#000000", + "alpha": true + }, + { + "type": "header", + "content": "t:names.inputs" + }, + { + "type": "color", + "id": "input_background", + "label": "t:settings.background", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "input_text_color", + "label": "t:settings.text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "input_border_color", + "label": "t:settings.borders", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "input_hover_background", + "label": "t:settings.hover_background", + "default": "#F5F5F5", + "alpha": true + }, + { + "type": "header", + "content": "t:names.variants" + }, + { + "type": "color", + "id": "variant_background_color", + "label": "t:settings.background", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "variant_text_color", + "label": "t:settings.text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "variant_border_color", + "label": "t:settings.borders", + "default": "#E6E6E6", + "alpha": true + }, + { + "type": "color", + "id": "variant_hover_background_color", + "label": "t:settings.hover_background", + "default": "#F5F5F5", + "alpha": true + }, + { + "type": "color", + "id": "variant_hover_text_color", + "label": "t:settings.hover_text", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "variant_hover_border_color", + "label": "t:settings.hover_borders", + "default": "#E6E6E6", + "alpha": true + }, + { + "type": "header", + "content": "t:names.selected_variants" + }, + { + "type": "color", + "id": "selected_variant_background_color", + "label": "t:settings.background", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "selected_variant_text_color", + "label": "t:settings.text", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "selected_variant_border_color", + "label": "t:settings.borders", + "default": "#000000", + "alpha": true + }, + { + "type": "color", + "id": "selected_variant_hover_background_color", + "label": "t:settings.hover_background", + "default": "#1A1A1A", + "alpha": true + }, + { + "type": "color", + "id": "selected_variant_hover_text_color", + "label": "t:settings.hover_text", + "default": "#FFFFFF", + "alpha": true + }, + { + "type": "color", + "id": "selected_variant_hover_border_color", + "label": "t:settings.hover_borders", + "default": "#1A1A1A", + "alpha": true + } + ], + "role": { + "text": "foreground", + "background": "background", + "links": "primary", + "icons": "foreground", + "primary_button": "primary_button_background", + "on_primary_button": "primary_button_text", + "primary_button_border": "primary_button_border", + "secondary_button": "secondary_button_background", + "on_secondary_button": "secondary_button_text", + "secondary_button_border": "secondary_button_border" + } + } + ] + }, + { + "name": "t:names.typography", + "settings": [ + { + "type": "header", + "content": "t:content.fonts" + }, + { + "type": "font_picker", + "id": "type_body_font", + "default": "work_sans_n4", + "label": "t:options.body" + }, + { + "type": "font_picker", + "id": "type_subheading_font", + "default": "work_sans_n5", + "label": "t:options.subheading" + }, + { + "type": "font_picker", + "id": "type_heading_font", + "default": "anonymous_pro_n4", + "label": "t:options.heading" + }, + { + "type": "font_picker", + "id": "type_accent_font", + "default": "anonymous_pro_n4", + "label": "t:options.accent" + }, + { + "type": "header", + "content": "t:content.text_presets" + }, + { + "type": "paragraph", + "content": "t:content.responsive_font_sizes" + }, + { + "type": "header", + "content": "t:content.paragraph" + }, + { + "type": "select", + "id": "type_size_paragraph", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + } + ], + "default": "14" + }, + { + "type": "select", + "id": "type_line_height_paragraph", + "label": "t:settings.line_height", + "options": [ + { + "value": "body-tight", + "label": "t:options.tight" + }, + { + "value": "body-normal", + "label": "t:options.normal" + }, + { + "value": "body-loose", + "label": "t:options.loose" + } + ], + "default": "body-normal" + }, + { + "type": "header", + "content": "t:options.h1" + }, + { + "type": "select", + "id": "type_font_h1", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading" + }, + { + "type": "select", + "id": "type_size_h1", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "72" + }, + { + "type": "select", + "id": "type_line_height_h1", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h1", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h1", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:options.h2" + }, + { + "type": "select", + "id": "type_font_h2", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading" + }, + { + "type": "select", + "id": "type_size_h2", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "48" + }, + { + "type": "select", + "id": "type_line_height_h2", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h2", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h2", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:options.h3" + }, + { + "type": "select", + "id": "type_font_h3", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "body", + "label": "t:options.body" + } + ], + "default": "heading" + }, + { + "type": "select", + "id": "type_size_h3", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "32" + }, + { + "type": "select", + "id": "type_line_height_h3", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h3", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h3", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:options.h4" + }, + { + "type": "select", + "id": "type_font_h4", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "body", + "label": "t:options.body" + } + ], + "default": "subheading" + }, + { + "type": "select", + "id": "type_size_h4", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "24" + }, + { + "type": "select", + "id": "type_line_height_h4", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h4", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h4", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:options.h5" + }, + { + "type": "select", + "id": "type_font_h5", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "body", + "label": "t:options.body" + } + ], + "default": "subheading" + }, + { + "type": "select", + "id": "type_size_h5", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "18" + }, + { + "type": "select", + "id": "type_line_height_h5", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h5", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h5", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + }, + { + "type": "header", + "content": "t:options.h6" + }, + { + "type": "select", + "id": "type_font_h6", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "body", + "label": "t:options.body" + } + ], + "default": "subheading" + }, + { + "type": "select", + "id": "type_size_h6", + "label": "t:settings.size", + "options": [ + { + "value": "10", + "label": "10px" + }, + { + "value": "12", + "label": "12px" + }, + { + "value": "14", + "label": "14px" + }, + { + "value": "16", + "label": "16px" + }, + { + "value": "18", + "label": "18px" + }, + { + "value": "20", + "label": "20px" + }, + { + "value": "24", + "label": "24px" + }, + { + "value": "32", + "label": "32px" + }, + { + "value": "40", + "label": "40px" + }, + { + "value": "48", + "label": "48px" + }, + { + "value": "56", + "label": "56px" + }, + { + "value": "72", + "label": "72px" + }, + { + "value": "88", + "label": "88px" + }, + { + "value": "120", + "label": "120px" + }, + { + "value": "152", + "label": "152px" + }, + { + "value": "184", + "label": "184px" + } + ], + "default": "16" + }, + { + "type": "select", + "id": "type_line_height_h6", + "label": "t:settings.line_height", + "options": [ + { + "value": "display-tight", + "label": "t:options.tight" + }, + { + "value": "display-normal", + "label": "t:options.normal" + }, + { + "value": "display-loose", + "label": "t:options.loose" + } + ], + "default": "display-normal" + }, + { + "type": "select", + "id": "type_letter_spacing_h6", + "label": "t:settings.letter_spacing", + "options": [ + { + "value": "heading-tight", + "label": "t:options.tight" + }, + { + "value": "heading-normal", + "label": "t:options.normal" + }, + { + "value": "heading-loose", + "label": "t:options.loose" + } + ], + "default": "heading-normal" + }, + { + "type": "select", + "id": "type_case_h6", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] + }, + { + "name": "t:names.page_layout", + "settings": [ + { + "type": "select", + "id": "page_width", + "label": "t:settings.page_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "normal", + "label": "t:options.normal" + }, + { + "value": "wide", + "label": "t:options.wide" + } + ], + "default": "narrow" + } + ] + }, + { + "name": "t:names.animations", + "settings": [ + { + "type": "checkbox", + "id": "page_transition_enabled", + "label": "t:settings.page_transition_enabled", + "default": true + }, + { + "type": "checkbox", + "id": "transition_to_main_product", + "label": "t:settings.transition_to_main_product", + "default": true + }, + { + "type": "select", + "id": "card_hover_effect", + "label": "t:settings.card_hover_effect", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "lift", + "label": "t:options.lift" + }, + { + "value": "scale", + "label": "t:options.scale" + }, + { + "value": "subtle-zoom", + "label": "t:options.subtle_zoom" + } + ], + "default": "lift", + "info": "t:info.hover_effects" + } + ] + }, + { + "name": "t:names.badges", + "settings": [ + { + "type": "select", + "id": "badge_position", + "options": [ + { + "value": "bottom-left", + "label": "t:options.bottom_left" + }, + { + "value": "top-left", + "label": "t:options.top_left" + }, + { + "value": "top-right", + "label": "t:options.top_right" + } + ], + "default": "top-left", + "label": "t:settings.badge_position" + }, + { + "type": "range", + "id": "badge_corner_radius", + "min": 0, + "max": 100, + "step": 2, + "unit": "px", + "label": "t:settings.badge_corner_radius", + "default": 40 + }, + { + "type": "header", + "content": "t:settings.colors" + }, + { + "type": "color_scheme", + "id": "badge_sale_color_scheme", + "label": "t:settings.badge_sale_color_scheme", + "default": "scheme-4" + }, + { + "type": "color_scheme", + "id": "badge_sold_out_color_scheme", + "label": "t:settings.badge_sold_out_color_scheme", + "default": "scheme-5" + }, + { + "type": "header", + "content": "t:names.typography" + }, + { + "type": "select", + "id": "badge_font_family", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "body" + }, + { + "type": "select", + "id": "badge_text_transform", + "label": "t:settings.text_case", + "options": [ + { + "value": "none", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "none" + } + ] + }, + { + "name": "t:names.buttons", + "settings": [ + { + "type": "header", + "content": "t:options.button_primary" + }, + { + "type": "range", + "id": "primary_button_border_width", + "min": 0, + "max": 4, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 0 + }, + { + "type": "range", + "id": "button_border_radius_primary", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.border_radius", + "default": 100 + }, + { + "type": "select", + "id": "type_font_button_primary", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "body" + }, + { + "type": "select", + "id": "button_font_weight_primary", + "label": "t:settings.button_text_weight", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "100", + "label": "t:options.thin" + }, + { + "value": "300", + "label": "t:options.light" + }, + { + "value": "400", + "label": "t:options.regular" + }, + { + "value": "500", + "label": "t:options.medium" + }, + { + "value": "600", + "label": "t:options.semibold" + }, + { + "value": "700", + "label": "t:options.bold" + }, + { + "value": "900", + "label": "t:options.black" + } + ], + "default": "default" + }, + { + "type": "select", + "id": "button_text_case_primary", + "label": "t:settings.button_text_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default" + }, + { + "type": "header", + "content": "t:options.button_secondary" + }, + { + "type": "range", + "id": "secondary_button_border_width", + "min": 0, + "max": 4, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1 + }, + { + "type": "range", + "id": "button_border_radius_secondary", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.border_radius", + "default": 100 + }, + { + "type": "select", + "id": "type_font_button_secondary", + "label": "t:settings.font", + "options": [ + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "body" + }, + { + "type": "select", + "id": "button_font_weight_secondary", + "label": "t:settings.button_text_weight", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "100", + "label": "t:options.thin" + }, + { + "value": "300", + "label": "t:options.light" + }, + { + "value": "400", + "label": "t:options.regular" + }, + { + "value": "500", + "label": "t:options.medium" + }, + { + "value": "600", + "label": "t:options.semibold" + }, + { + "value": "700", + "label": "t:options.bold" + }, + { + "value": "900", + "label": "t:options.black" + } + ], + "default": "default" + }, + { + "type": "select", + "id": "button_text_case_secondary", + "label": "t:settings.button_text_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default" + }, + { + "type": "header", + "content": "t:names.pills" + }, + { + "type": "paragraph", + "content": "t:info.pills_usage" + }, + { + "type": "range", + "id": "pills_border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 40, + "step": 1, + "unit": "px", + "default": 40 + } + ] + }, + { + "name": "t:names.cart", + "settings": [ + { + "type": "select", + "id": "cart_type", + "label": "t:settings.cart_type", + "options": [ + { + "value": "page", + "label": "t:options.page" + }, + { + "value": "drawer", + "label": "t:options.drawer" + } + ], + "default": "page" + }, + { + "type": "select", + "id": "product_title_case", + "label": "t:settings.product_title_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default" + }, + { + "type": "select", + "id": "cart_price_font", + "label": "t:settings.font_price", + "options": [ + { + "value": "primary", + "label": "t:options.body" + }, + { + "value": "secondary", + "label": "t:options.subheading" + }, + { + "value": "tertiary", + "label": "t:options.tertiary" + } + ], + "default": "secondary" + }, + { + "type": "checkbox", + "id": "auto_open_cart_drawer", + "label": "t:settings.auto_open_cart_drawer", + "default": false, + "visible_if": "{{ settings.cart_type == 'drawer' }}" + }, + { + "type": "checkbox", + "id": "show_cart_note", + "label": "t:settings.seller_note", + "default": false + }, + { + "type": "checkbox", + "id": "show_add_discount_code", + "label": "t:settings.add_discount_code", + "default": true + }, + { + "type": "checkbox", + "id": "show_installments", + "label": "t:settings.installments", + "default": true + }, + { + "type": "checkbox", + "id": "show_accelerated_checkout_buttons", + "label": "t:settings.checkout_buttons", + "info": "t:info.checkout_buttons", + "default": true + }, + { + "type": "header", + "content": "t:content.product_media" + }, + { + "type": "select", + "id": "cart_thumbnail_border", + "label": "t:settings.style", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "cart_thumbnail_border_width", + "min": 0, + "max": 10, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ settings.cart_thumbnail_border != 'none' }}" + }, + { + "type": "range", + "id": "cart_thumbnail_border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 50, + "visible_if": "{{ settings.cart_thumbnail_border != 'none' }}" + }, + { + "type": "range", + "id": "cart_thumbnail_border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] + }, + { + "name": "t:names.drawers", + "settings": [ + { + "type": "color_scheme", + "id": "drawer_color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "drawer_border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "drawer_border_width", + "min": 0, + "max": 10, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ settings.drawer_border != 'none' }}" + }, + { + "type": "range", + "id": "drawer_border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 50, + "visible_if": "{{ settings.drawer_border != 'none' }}" + }, + { + "type": "checkbox", + "id": "drawer_drop_shadow", + "label": "t:settings.drop_shadow", + "default": false + } + ] + }, + { + "name": "t:names.icons", + "settings": [ + { + "type": "select", + "id": "icon_stroke", + "label": "t:settings.stroke", + "options": [ + { + "value": "thin", + "label": "t:options.thin" + }, + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "heavy", + "label": "t:options.heavy" + } + ], + "default": "default" + } + ] + }, + { + "name": "t:names.input_fields", + "settings": [ + { + "type": "range", + "id": "input_border_width", + "min": 0, + "max": 4, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1 + }, + { + "type": "range", + "id": "inputs_border_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "label": "t:settings.border_radius", + "default": 8 + }, + { + "type": "select", + "id": "type_preset", + "label": "t:settings.type_preset", + "options": [ + { + "value": "", + "label": "t:options.default" + }, + { + "value": "paragraph", + "label": "t:options.paragraph" + }, + { + "value": "h1", + "label": "t:options.h1" + }, + { + "value": "h2", + "label": "t:options.h2" + }, + { + "value": "h3", + "label": "t:options.h3" + }, + { + "value": "h4", + "label": "t:options.h4" + }, + { + "value": "h5", + "label": "t:options.h5" + }, + { + "value": "h6", + "label": "t:options.h6" + } + ], + "default": "paragraph" + } + ] + }, + { + "name": "t:names.popovers", + "settings": [ + { + "type": "color_scheme", + "id": "popover_color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "range", + "id": "popover_border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 16, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "select", + "id": "popover_border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "solid" + }, + { + "type": "range", + "id": "popover_border_width", + "min": 0, + "max": 10, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ settings.popover_border != 'none' }}" + }, + { + "type": "range", + "id": "popover_border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 50, + "visible_if": "{{ settings.popover_border != 'none' }}" + }, + { + "type": "checkbox", + "id": "popover_drop_shadow", + "label": "t:settings.drop_shadow", + "default": true + } + ] + }, + { + "name": "t:names.prices", + "settings": [ + { + "type": "header", + "content": "t:settings.currency_code" + }, + { + "type": "checkbox", + "id": "currency_code_enabled_product_pages", + "label": "t:settings.product_pages", + "default": true + }, + { + "type": "checkbox", + "id": "currency_code_enabled_product_cards", + "label": "t:settings.product_cards", + "default": true + }, + { + "type": "checkbox", + "id": "currency_code_enabled_cart_items", + "label": "t:settings.cart_items", + "default": true + }, + { + "type": "checkbox", + "id": "currency_code_enabled_cart_total", + "label": "t:settings.cart_total", + "default": true + } + ] + }, + { + "name": "t:names.product_cards", + "settings": [ + { + "type": "checkbox", + "id": "quick_add", + "label": "t:settings.quick_add", + "default": true + }, + { + "type": "checkbox", + "id": "mobile_quick_add", + "label": "t:settings.mobile_quick_add", + "default": false, + "visible_if": "{{ settings.quick_add == true }}" + }, + { + "type": "color_scheme", + "id": "quick_add_color_scheme", + "label": "t:settings.quick_add_colors", + "default": "scheme-1", + "visible_if": "{{ settings.quick_add == true }}" + }, + { + "type": "header", + "content": "t:settings.media" + }, + { + "type": "checkbox", + "id": "show_second_image_on_hover", + "label": "t:settings.show_second_image_on_hover", + "default": true + }, + { + "type": "checkbox", + "id": "product_card_carousel", + "label": "t:settings.product_card_carousel", + "default": true + } + ] + }, + { + "name": "t:names.search", + "settings": [ + { + "type": "collection", + "id": "empty_state_collection", + "label": "t:settings.empty_state_collection", + "info": "t:settings.empty_state_collection_info" + }, + { + "type": "header", + "content": "t:names.predictive_search" + }, + { + "type": "range", + "id": "product_corner_radius", + "min": 0, + "max": 32, + "step": 1, + "unit": "px", + "label": "t:settings.product_corner_radius", + "default": 0 + }, + { + "type": "range", + "id": "card_corner_radius", + "min": 0, + "max": 16, + "step": 1, + "unit": "px", + "label": "t:settings.card_corner_radius", + "default": 0 + }, + { + "type": "select", + "id": "card_title_case", + "label": "t:settings.product_and_card_title_case", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "uppercase", + "label": "t:options.uppercase" + } + ], + "default": "default" + } + ] + }, + { + "name": "t:names.swatches", + "settings": [ + { + "type": "checkbox", + "id": "show_variant_image", + "label": "t:settings.variant_images", + "default": false + }, + { + "type": "range", + "id": "variant_swatch_width", + "min": 16, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.width", + "default": 30 + }, + { + "type": "range", + "id": "variant_swatch_height", + "min": 16, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.height", + "default": 30 + }, + { + "type": "range", + "id": "variant_swatch_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.border_radius", + "default": 100 + }, + { + "type": "select", + "id": "variant_swatch_border_style", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "solid" + }, + { + "type": "range", + "id": "variant_swatch_border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ settings.variant_swatch_border_style != 'none' }}" + }, + { + "type": "range", + "id": "variant_swatch_border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 10, + "visible_if": "{{ settings.variant_swatch_border_style != 'none' }}" + } + ] + }, + { + "name": "t:names.variant_pickers", + "settings": [ + { + "type": "header", + "content": "t:content.variant_settings" + }, + { + "type": "header", + "content": "t:content.buttons" + }, + { + "type": "range", + "id": "variant_button_border_width", + "min": 0, + "max": 4, + "step": 1, + "unit": "px", + "label": "t:settings.border_width", + "default": 1 + }, + { + "type": "range", + "id": "variant_button_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "label": "t:settings.border_radius", + "default": 8 + }, + { + "type": "select", + "id": "variant_button_width", + "label": "t:settings.width", + "options": [ + { + "value": "default-width-buttons", + "label": "t:options.fit" + }, + { + "value": "equal-width-buttons", + "label": "t:options.fill" + } + ], + "default": "equal-width-buttons" + } + ] + } +] diff --git a/layout/password.liquid b/layout/password.liquid new file mode 100644 index 000000000..aae6b06be --- /dev/null +++ b/layout/password.liquid @@ -0,0 +1,161 @@ + + + + {%- render 'stylesheets' -%} + + {%- if settings.favicon != blank -%} + + {%- endif -%} + + {% comment %} This a way to wait for main content to load when navigating to a new page so that the view transitions can work consistently {% endcomment %} + + + {%- render 'meta-tags' -%} + {%- render 'fonts' -%} + {%- render 'scripts' -%} + {%- render 'theme-styles-variables' -%} + {%- render 'color-schemes' -%} + + {% if request.design_mode %} + {%- render 'theme-editor' -%} + {% endif %} + + {{ content_for_header }} + + + +
+ {{ content_for_layout }} +
+ +
+

+ {{ 'content.powered_by' | t }} + + {{- 'icon-shopify.svg' | inline_asset_content -}} + +

+ + +
+ + {%- form 'storefront_password' -%} + + +
+ +
+
+

+ {{ 'actions.enter_password' | t }} +

+ + + + {%- if form.errors -%} + + {%- endif -%} +
+
+
+ {%- endform -%} + + {% # theme-check-disable ParserBlockingScript %} + + {% # theme-check-enable ParserBlockingScript %} + + diff --git a/layout/theme.liquid b/layout/theme.liquid new file mode 100644 index 000000000..f0665a82e --- /dev/null +++ b/layout/theme.liquid @@ -0,0 +1,67 @@ + + + + {%- render 'stylesheets' -%} + + {%- if settings.favicon != blank -%} + + {%- endif -%} + + {% comment %} This a way to wait for main content to load when navigating to a new page so that the view transitions can work consistently {% endcomment %} + + + {%- render 'meta-tags' -%} + {%- render 'fonts' -%} + {%- render 'scripts' -%} + {%- render 'theme-styles-variables' -%} + {%- render 'color-schemes' -%} + + {% if request.design_mode %} + {%- render 'theme-editor' -%} + {% endif %} + + {{ content_for_header }} + + + + {% render 'skip-to-content-link', href: '#MainContent', text: 'accessibility.skip_to_text' %} +
+ {% sections 'header-group' %} +
+ +
+ {{ content_for_layout }} +
+ + {% sections 'footer-group' %} + + {% # theme-check-disable ParserBlockingScript %} + + {% # theme-check-enable ParserBlockingScript %} + + {% render 'search-modal' %} + + {% if settings.quick_add or settings.mobile_quick_add %} + {% render 'quick-add-modal' %} + {% endif %} + + diff --git a/locales/bg.json b/locales/bg.json new file mode 100644 index 000000000..46d0ffd15 --- /dev/null +++ b/locales/bg.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Зареждане на видео: {{ description }}", + "sold_out": "Изчерпано", + "email_signup": { + "label": "Имейл", + "placeholder": "Имейл адрес", + "success": "Благодарим, че се абонирахте." + }, + "filter": "Филтър", + "payment_methods": "Начини на плащане", + "contact_form": { + "name": "Име", + "email": "Имейл адрес", + "phone": "Телефон", + "comment": "Коментар", + "post_success": "Благодарим, че се свързахте с нас. Ще се свържем с вас възможно най-скоро.", + "error_heading": "Коригирайте следното:" + } + }, + "accessibility": { + "play_model": "Възпроизвеждане на 3D модел", + "play_video": "Възпроизвеждане на видеоклип", + "unit_price": "Единична цена", + "country_results_count": "{{ count }} резултата", + "slideshow_pause": "Пауза на слайдшоуто", + "slideshow_play": "Възпроизвеждане на слайдшоу", + "remove_item": "Премахване на {{ title}}", + "skip_to_text": "Преминаване към съдържанието", + "skip_to_product_info": "Прескочи към информацията за продукта", + "skip_to_results_list": "Преминаване към списъка с резултати", + "new_window": "Отваря се в нов прозорец.", + "slideshow_next": "Следващ слайд", + "slideshow_previous": "Предишен слайд", + "close_dialog": "Затваряне на диалоговия прозорец", + "reset_search": "Подновяване на търсенето", + "search_results_count": "Открити са {{ count }} резултата от търсенето за „{{ query }}“", + "search_results_no_results": "Няма резултати за „{{ query }}“", + "filters": "Филтри", + "filter_count": { + "one": "Приложен е {{ count }} филтър", + "other": "Приложени са {{ count }} филтъра" + }, + "account": "Отваряне на менюто на профила", + "cart": "Количка", + "cart_count": "Общо артикули в количката", + "menu": "Меню", + "country_region": "Държава/регион", + "slide_status": "Слайд {{ index }} от {{ length }}", + "scroll_to": "Превъртете до {{ title }}", + "loading_product_recommendations": "Зареждане на препоръчани продукти.", + "discount": "Прилагане на код за отстъпка", + "discount_applied": "Приложен код за отстъпка: {{ code }}", + "open_cart_drawer": "Отваряне на количката", + "inventory_status": "Статус на стоковите запаси", + "pause_video": "Пауза на видеоклипа", + "find_country": "Търсене на държава", + "localization_region_and_language": "Отваряне на диалогов прозорец за избор на регион и език", + "open_search_modal": "Отваряне на търсенето", + "decrease_quantity": "Намаляване на количеството", + "increase_quantity": "Увеличаване на количеството", + "quantity": "Количество", + "rating": "Оценката за този продукт е {{ rating }} от 5", + "nested_product": "{{ product_title }} за {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Добавяне към количката", + "clear_all": "Изчистване на всички", + "remove": "Премахване", + "view_in_your_space": "Преглед във вашето пространство", + "show_filters": "Филтър", + "clear": "Изчисти", + "continue_shopping": "Продължете да пазарувате", + "log_in_html": "Имате профил? Влезте за по-бързо преминаване към плащане.", + "see_items": { + "one": "Вижте {{ count }} артикул", + "other": "Вижте {{ count }} артикула" + }, + "view_all": "Покажи всички", + "add": "Добавяне", + "choose": "Избор", + "added": "Добавено", + "show_less": "Покажи по-малко", + "show_more": "Покажи повече", + "close": "Затваряне", + "more": "Още", + "zoom": "Увеличаване", + "close_dialog": "Затваряне на диалоговия прозорец", + "reset": "Нулиране", + "enter_using_password": "Влизане с парола", + "submit": "Изпрати", + "enter_password": "Въведете парола", + "remove_discount": "Премахване на отстъпка {{ code }}", + "view_store_information": "Вижте информация за магазина", + "back": "Назад", + "log_in": "Влизане", + "log_out": "Излизане", + "apply": "Приложи", + "sign_up": "Регистриране", + "sign_in_options": "Други опции за влизане", + "open_image_in_full_screen": "Отваряне на изображението на цял екран", + "sort": "Сортиране", + "show_all_options": "Показване на всички опции" + }, + "content": { + "reviews": "мнения", + "language": "Език", + "localization_region_and_language": "Регион и език", + "no_results_found": "Не са открити резултати", + "cart_total": "Обща сума в количката", + "your_cart_is_empty": "Количката ви е празна", + "product_image": "Изображение на продукта", + "product_information": "Информация за продукта", + "quantity": "Количество", + "product_total": "Обща стойност на продукта", + "cart_estimated_total": "Очаквана обща сума", + "seller_note": "Специални инструкции", + "cart_subtotal": "Междинна сума", + "discounts": "Отстъпки", + "discount": "Отстъпка", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "С включено мито и данъци. Отстъпките и доставката се изчисляват при плащане.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "С включено мито и данъци. Отстъпките и доставката се изчисляват при плащане.", + "taxes_included_shipping_at_checkout_with_policy_html": "С включени данъци. Отстъпките и доставката се изчисляват при плащане.", + "taxes_included_shipping_at_checkout_without_policy": "С включени данъци. Отстъпките и доставката се изчисляват при плащане.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "С включено мито. Данъците, отстъпките и доставката се изчисляват при плащане.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "С включено мито. Данъците, отстъпките и доставката се изчисляват при плащане.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Данъците, отстъпките и доставката се изчисляват при плащане.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Данъците, отстъпките и доставката се изчисляват при плащане.", + "checkout": "Преминаване към плащане", + "cart_title": "Количка", + "price": "Цена", + "price_regular": "Обичайна цена", + "price_compare_at": "Сравнение на цени", + "price_sale": "Цена при разпродажба", + "duties_and_taxes_included": "С включено мито и данъци.", + "duties_included": "С включено мито.", + "shipping_policy_html": "Доставката се изчислява при плащане.", + "taxes_included": "С включени данъци.", + "product_badge_sold_out": "Изчерпано", + "product_badge_sale": "Разпродажба", + "grid_view": { + "default_view": "По подразбиране", + "grid_fieldset": "Grid изглед", + "single_item": "Единична", + "zoom_out": "Намаляване" + }, + "search_input_label": "Търсене", + "search_input_placeholder": "Търсене", + "search_results": "Резултати от търсенето", + "search_results_label": "Резултати от търсенето", + "search_results_no_results": "Няма резултати за „{{ terms }}“. Опитайте друго търсене.", + "search_results_resource_articles": "Публикации в блог", + "search_results_resource_collections": "Колекции", + "search_results_resource_pages": "Страници", + "search_results_resource_products": "Продукти", + "search_results_resource_queries": "Търсене в предложенията", + "search_results_view_all": "Покажи всички", + "search_results_view_all_button": "Покажи всички", + "search_results_resource_products_count": { + "one": "{{ count }} продукт", + "other": "{{ count }} продукта" + }, + "recently_viewed_products": "Наскоро разгледани", + "unavailable": "Неналично", + "collection_placeholder": "Название на колекцията", + "product_card_placeholder": "Название на продукта", + "product_count": "Брой продукти", + "item_count": { + "one": "{{ count }} артикул", + "other": "{{ count }} артикула" + }, + "errors": "Грешки", + "search": "Търсене", + "search_results_no_results_check_spelling": "Няма резултати за „{{ terms }}“. Проверете начина на изписване или използвайте различна дума или фраза.", + "featured_products": "Препоръчани продукти", + "filters": "Филтри", + "no_products_found": "Не са открити продукти.", + "price_from": "От {{ price }}", + "price_filter_html": "Най-високата цена е {{ price }}", + "use_fewer_filters_html": "Опитайте да използвате по-малко филтри или изчистете всички филтри.", + "blog_details_separator": "|", + "read_more": "Прочетете повече...", + "wrong_password": "Неправилна парола", + "discount_code": "Код за отстъпка", + "pickup_available_at_html": "Възможност за вземане от {{ location }}", + "pickup_available_in": "Възможност за вземане от {{ pickup_time }}", + "pickup_not_available": "В момента няма възможност за вземане", + "pickup_ready_in": "{{ pickup_time }}", + "account_title": "Профил", + "account_title_personalized": "Здравейте, {{ first_name }}", + "account_orders": "Поръчки", + "account_profile": "Профил", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "С включено мито и данъци. Доставката се изчислява при плащане.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "С включено мито и данъци. Доставката се изчислява при плащане.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "С включено мито. Доставката се изчислява при плащане.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "С включено мито. Доставката се изчислява при плащане.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Данъците и доставката се изчисляват при плащане.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Данъците и доставката се изчисляват при плащане.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "С включени данъци. Доставката се изчислява при плащане.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "С включени данъци. Доставката се изчислява при плащане.", + "view_more_details": "Покажи повече подробности", + "page_placeholder_title": "Заглавие на страница", + "page_placeholder_content": "Изберере страница, за да видите съдържанието ú", + "placeholder_image": "Временно изображение", + "inventory_low_stock": "Ниски наличности", + "inventory_in_stock": "В наличност", + "inventory_out_of_stock": "Изчерпано количество", + "inventory_low_stock_show_count": { + "one": "Оставаща стойност: {{ count }}", + "other": "Оставаща стойност: {{ count }}" + }, + "shipping_policy": "Доставката се изчислява при плащане.", + "discount_code_error": "Кодът за отстъпка не може да бъде приложен към вашата количка", + "shipping_discount_error": "Отстъпките от доставката се показват при преминаването към плащане след добавяне на адрес", + "powered_by": "Този магазин ще се поддържа от", + "store_owner_link_html": "Вие ли сте собственикът на магазина? Влезте тук" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Използвайте ваучера за подарък онлайн или QR код в магазина", + "title": "Това е остатъкът от вашия ваучер за подарък на стойност {{ value }} за {{ shop }}!", + "subtext": "Вашият ваучер за подарък", + "shop_link": "Посетете магазина онлайн", + "add_to_apple_wallet": "Добавяне към Apple Wallet", + "qr_image_alt": "QR код – сканирайте го, за да използвате ваучера за подарък", + "copy_code": "Копиране на кода на ваучер за подарък", + "expiration_date": "Изтича на {{ expires_on }}", + "copy_code_success": "Кодът е копиран успешно", + "expired": "Изтекъл" + } + }, + "placeholders": { + "password": "Парола", + "search": "Търсене", + "product_title": "Название на продукта", + "collection_title": "Название на колекцията" + }, + "products": { + "product": { + "add_to_cart": "Добавяне към количката", + "adding_to_cart": "Добавяне...", + "added_to_cart": "Добавено в количката", + "add_to_cart_error": "Грешка при добавянето в количката", + "sold_out": "Изчерпано", + "unavailable": "Неналично" + } + }, + "fields": { + "separator": "до" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} коментар", + "other": "{{ count }} коментара" + } + }, + "comment_form": { + "email": "Имейл адрес", + "error": "Коментарът не е публикуван, обърнете внимание на следното:", + "heading": "Оставяне на коментар", + "message": "Съобщение", + "moderated": "Имайте предвид, че коментарите трябва да бъдат одобрени, преди да се публикуват.", + "name": "Име", + "post": "Публикуване на коментар", + "success_moderated": "Коментарът е публикуван, в очакване на модериране", + "success": "Коментарът е публикуван" + } + } +} diff --git a/locales/cs.json b/locales/cs.json new file mode 100644 index 000000000..efde00914 --- /dev/null +++ b/locales/cs.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Načíst video: {{ description }}", + "sold_out": "Vyprodáno", + "email_signup": { + "label": "E-mail", + "placeholder": "E-mailová adresa", + "success": "Díky za odběr!" + }, + "filter": "Filtr", + "payment_methods": "Platební metody", + "contact_form": { + "name": "Název", + "email": "E-mail", + "phone": "Telefon", + "comment": "Komentář", + "post_success": "Děkujeme, že jste nás kontaktovali. Ozveme se vám co možná nejdříve.", + "error_heading": "Upravte prosím následující informace:" + } + }, + "accessibility": { + "play_model": "Přehrát 3D model", + "play_video": "Přehrát video", + "unit_price": "Jednotková cena", + "country_results_count": "Počet výsledků: {{ count }}", + "slideshow_pause": "Pozastavit prezentaci", + "slideshow_play": "Přehrát prezentaci", + "remove_item": "Odstranit {{ title}}", + "skip_to_text": "Přeskočit na obsah", + "skip_to_product_info": "Přejít na informace o produktu", + "skip_to_results_list": "Přejít na seznam výsledků", + "new_window": "Otevře se v novém okně.", + "slideshow_next": "Další snímek", + "slideshow_previous": "Předchozí snímek", + "close_dialog": "Zavřít dialog", + "reset_search": "Resetovat hledání", + "search_results_count": "Pro dotaz „{{ query }}“ byl nalezen tento počet výsledků: {{ count }}", + "search_results_no_results": "Pro dotaz „{{ query }}“ nebyly nalezeny žádné výsledky", + "filters": "Filtry", + "filter_count": { + "one": "Je použit {{ count }} filtr", + "other": "Je použito více filtrů ({{ count }})", + "few": "Je použito více filtrů ({{ count }})", + "many": "Je použito více filtrů ({{ count }})" + }, + "account": "Otevřít nabídku účtu", + "cart": "Košík", + "cart_count": "Celkem položek v košíku", + "menu": "Nabídka", + "country_region": "Země/region", + "slide_status": "Snímek {{ index }} z {{ length }}", + "scroll_to": "Přejděte na {{ title }}", + "loading_product_recommendations": "Načítají se doporučené produkty", + "discount": "Použít slevový kód", + "discount_applied": "Uplatněný slevový kód: {{ code }}", + "open_cart_drawer": "Otevřít košík", + "inventory_status": "Stav skladových zásob", + "pause_video": "Pozastavit video", + "find_country": "Najít zemi", + "localization_region_and_language": "Otevřít výběr regionu a jazyka", + "open_search_modal": "Otevřít vyhledávání", + "decrease_quantity": "Snížit množství", + "increase_quantity": "Zvýšit množství", + "rating": "Hodnocení tohoto produktu je {{ rating }} z 5", + "quantity": "Množství", + "nested_product": "{{ product_title }} pro {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Přidat do košíku", + "clear_all": "Vymazat vše", + "remove": "Odebrat", + "view_in_your_space": "Zobrazit ve vašem prostoru", + "show_filters": "Filtr", + "clear": "Vymazat", + "continue_shopping": "Pokračovat v nákupu", + "log_in_html": "Máte účet? Přihlaste se, abyste urychlili zaplacení.", + "see_items": { + "one": "Viz {{ count }} položka", + "other": "Viz {{ count }} položek", + "few": "Viz {{ count }} položek", + "many": "Viz {{ count }} položek" + }, + "view_all": "Zobrazit vše", + "add": "Přidat", + "choose": "Vybrat", + "added": "Přidáni", + "show_less": "Zobrazit méně", + "show_more": "Zobrazit více", + "close": "Zavřít", + "more": "Více", + "reset": "Resetovat", + "zoom": "Lupa", + "close_dialog": "Zavřít dialog", + "back": "Zpět", + "log_in": "Přihlásit se", + "log_out": "Odhlásit se", + "remove_discount": "Odebrat slevu {{ code }}", + "enter_using_password": "Vstoupit pomocí hesla", + "submit": "Odeslat", + "enter_password": "Zadat heslo", + "view_store_information": "Zobrazit informace obchodu", + "apply": "Použít", + "sign_in_options": "Další možnosti přihlášení", + "sign_up": "Zaregistrovat se", + "open_image_in_full_screen": "Otevřít obrázek na celou obrazovku", + "sort": "Třídit", + "show_all_options": "Zobrazit všechny možnosti" + }, + "content": { + "reviews": "recen.", + "language": "Jazyk", + "localization_region_and_language": "Oblast a jazyk", + "no_results_found": "Nebyly nalezeny žádné výsledky", + "cart_total": "Součet košíku", + "your_cart_is_empty": "Košík je prázdný", + "product_image": "Obrázek produktu", + "product_information": "Informace o produktu", + "quantity": "Množství", + "product_total": "Celkem kusů produktu", + "cart_estimated_total": "Odhadovaný součet", + "seller_note": "Zvláštní pokyny", + "cart_subtotal": "Mezisoučet", + "discounts": "Slevy", + "discount": "Sleva", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Včetně cla a daní. Slevy a cena dopravy se vypočítají na pokladně.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Včetně cla a daní. Slevy a cena dopravy se vypočítají na pokladně.", + "taxes_included_shipping_at_checkout_with_policy_html": "Včetně daní. Slevy a cena dopravy se vypočítají na pokladně.", + "taxes_included_shipping_at_checkout_without_policy": "Včetně daní. Slevy a cena dopravy se vypočítají na pokladně.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Včetně cla. Daně, slevy a cena dopravy se vypočítají na pokladně.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Včetně cla. Daně, slevy a cena dopravy se vypočítají na pokladně.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Daně, slevy a cena dopravy se vypočítají na pokladně.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Daně, slevy a cena dopravy se vypočítají na pokladně.", + "checkout": "Zaplatit", + "cart_title": "Košík", + "price": "Cena", + "price_regular": "Běžná cena", + "price_compare_at": "Původní cena", + "price_sale": "Výprodejová cena", + "duties_and_taxes_included": "Včetně cla a daní.", + "duties_included": "Včetně cla.", + "shipping_policy_html": "Cena dopravy se vypočítá v pokladně.", + "taxes_included": "Včetně daní.", + "product_badge_sold_out": "Vyprodáno", + "product_badge_sale": "Výprodej", + "search_input_label": "Začněte hledat", + "search_input_placeholder": "Vyhledat", + "search_results": "Výsledky hledání", + "search_results_label": "Výsledky hledání", + "search_results_no_results": "Pro dotaz „{{ terms }}“ nebyly nalezeny žádné výsledky. Zkuste vyhledat jiný dotaz.", + "search_results_resource_articles": "Příspěvky na blogu", + "search_results_resource_collections": "Kolekce", + "search_results_resource_pages": "Stránky", + "search_results_resource_products": "Produkty", + "search_results_resource_queries": "Návrhy hledaných výrazů", + "search_results_view_all": "Zobrazit vše", + "search_results_view_all_button": "Zobrazit vše", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} prod.", + "few": "{{ count }} prod.", + "many": "{{ count }} prod." + }, + "grid_view": { + "default_view": "Výchozí", + "grid_fieldset": "Sloupcová mřížka", + "single_item": "Jedna volba", + "zoom_out": "Oddálit" + }, + "unavailable": "Není k dispozici", + "collection_placeholder": "Název kolekce", + "product_card_placeholder": "Název produktu", + "recently_viewed_products": "Nedávno zobrazené", + "product_count": "Počet produktů", + "item_count": { + "one": "{{ count }} položka", + "other": "{{ count }} polož.", + "few": "{{ count }} polož.", + "many": "{{ count }} polož." + }, + "errors": "Chyby", + "search": "Hledání", + "search_results_no_results_check_spelling": "Pro dotaz „{{ terms }}\" nebyly nalezeny žádné výsledky. Zkontrolujte pravopis nebo zadejte jiné slovo či slovní spojení.", + "featured_products": "Propagované produkty", + "no_products_found": "Nebyly nalezeny žádné produkty.", + "price_from": "Od {{ price }}", + "use_fewer_filters_html": "Zkuste použít méně filtrů, nebo vymazat všechny filtry.", + "filters": "Filtry", + "price_filter_html": "Nejvyšší cena je {{ price }}", + "blog_details_separator": "|", + "account_title": "Účet", + "account_title_personalized": "Přihlášený uživatel: {{ first_name }}", + "account_orders": "Objednávky", + "account_profile": "Profil", + "discount_code": "Slevový kód", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Včetně cla a daní. Cena dopravy se vypočítá na pokladně.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Včetně cla a daní. Cena dopravy se vypočítá na pokladně.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Včetně cla. Cena dopravy se vypočítá na pokladně.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Včetně cla. Cena dopravy se vypočítá na pokladně.", + "pickup_available_at_html": "Vyzvednutí je k dispozici v lokalitě {{ location }}", + "pickup_available_in": "Vyzvednutí je k dispozici v {{ pickup_time }}", + "pickup_not_available": "Vyzvednutí není momentálně k dispozici", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Přečíst si více...", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Daně a doprava se vypočítají na pokladně", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Daně a doprava se vypočítají na pokladně", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Včetně daní. Cena dopravy se vypočítá na pokladně.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Včetně daní. Cena dopravy se vypočítá na pokladně.", + "wrong_password": "Heslo není správné", + "view_more_details": "Zobrazit další podrobnosti", + "inventory_low_stock": "Skladové zásoby docházejí", + "inventory_in_stock": "Skladem", + "inventory_out_of_stock": "Není skladem", + "page_placeholder_title": "Titulek stránky", + "page_placeholder_content": "Vyberte stránku, abyste zobrazili její obsah.", + "placeholder_image": "Zástupný znak obrázku", + "inventory_low_stock_show_count": { + "one": "Zbývá: {{ count }}", + "other": "Zbývá: {{ count }}", + "few": "Zbývá: {{ count }}", + "many": "Zbývá: {{ count }}" + }, + "powered_by": "Obchod bude využívat platformu", + "store_owner_link_html": "Jste majitelem obchodu? Přihlaste se zde", + "shipping_discount_error": "Slevy na dopravu se zobrazí při placení po přidání adresy.", + "discount_code_error": "Slevový kód nelze na váš košík uplatnit", + "shipping_policy": "Cena za dopravu se vypočítá u pokladny." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Použijte kód dárkové karty online nebo QR kód na prodejně", + "title": "Zůstatek vaší dárkové karty pro obchod {{ shop }} je: {{ value }}!", + "subtext": "Vaše dárková karta", + "shop_link": "Navštívit online obchod", + "add_to_apple_wallet": "Přidat do Apple Peněženky", + "qr_image_alt": "QR kód: po naskenování můžete uplatnit svou dárkovou kartu", + "copy_code": "Zkopírovat kód dárkové karty", + "expiration_date": "Platnost skončí {{ expires_on }}", + "copy_code_success": "Kód byl úspěšně zkopírován", + "expired": "Po konci platnosti" + } + }, + "placeholders": { + "password": "Heslo", + "search": "Vyhledat", + "product_title": "Název produktu", + "collection_title": "Název kolekce" + }, + "products": { + "product": { + "add_to_cart": "Přidat do košíku", + "adding_to_cart": "Přidávání do košíku...", + "added_to_cart": "Přidáno do košíku", + "add_to_cart_error": "Chyba při přidávání do košíku", + "sold_out": "Vyprodáno", + "unavailable": "Není k dispozici" + } + }, + "fields": { + "separator": "až" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentář", + "other": "počet komentářů: {{ count }}", + "few": "počet komentářů: {{ count }}", + "many": "počet komentářů: {{ count }}" + } + }, + "comment_form": { + "email": "E-mail", + "error": "Komentář se nepodařilo odeslat, prosím vyřešte následující:", + "heading": "Zanechat komentář", + "message": "Zpráva", + "moderated": "Upozorňujeme, že komentáře musí být před zveřejněním schváleny.", + "name": "Jméno", + "post": "Publikovat komentář", + "success_moderated": "Komentář odeslán, čeká na schválení", + "success": "Komentář zveřejněn" + } + } +} diff --git a/locales/cs.schema.json b/locales/cs.schema.json new file mode 100644 index 000000000..24b2e4170 --- /dev/null +++ b/locales/cs.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Ohraničení", + "collapsible_row": "Sbalitelný řádek", + "colors": "Barvy", + "custom_section": "Vlastní sekce", + "icon": "Ikona", + "logo_and_favicon": "Logo a favikona", + "overlapping_blocks": "Překrývající se bloky", + "product_buy_buttons": "Tlačítka nákupu", + "product_description": "Popis", + "product_price": "Cena", + "product_variant_picker": "Výběr varianty", + "slideshow": "Prezentace", + "typography": "Typografie", + "video": "Video", + "slideshow_controls": "Ovládací prvky prezentace", + "size": "Velikost", + "spacing": "Rozestupy", + "product_recommendations": "Doporučené produkty", + "product_media": "Média produktu", + "featured_collection": "Propagovaná kolekce", + "add_to_cart": "Přidat do košíku", + "email_signup": "Přihlášení k odběru e-mailů", + "submit_button": "Tlačítko Odeslat", + "grid_layout_selector": "Selektor rozvržení mřížky", + "image": "Obrázek", + "list_items": "Položky seznamu", + "facets": "Filtry", + "variants": "Varianty", + "product_cards": "Karty produktů", + "styles": "Styly", + "buttons": "Tlačítka", + "inputs": "Vstupy", + "primary_button": "Primární tlačítko", + "secondary_button": "Sekundární tlačítko", + "popovers": "Místní okna", + "products_carousel": "Doporučená kolekce: Karusel", + "products_grid": "Doporučená kolekce: Mřížka", + "marquee": "Běžící text", + "alternating_content_rows": "Střídavé řádky", + "pull_quote": "Vytažený citát", + "contact_form": "Kontaktní formulář", + "featured_product": "Důležitá vlastnost produktu", + "icons_with_text": "Ikony s textem", + "accelerated_checkout": "Zrychlená pokladna", + "accordion": "Skládací panel", + "accordion_row": "Řádek skládacího panelu", + "animations": "Animace", + "announcement": "Oznámení", + "announcement_bar": "Panel oznámení", + "badges": "Odznaky", + "button": "Tlačítko", + "cart": "Košík", + "cart_items": "Položky košíku", + "cart_products": "Produkty košíku", + "cart_title": "Košík", + "collection": "Kolekce", + "collection_card": "Karta kolekce", + "collection_columns": "Sloupce kolekce", + "collection_container": "Kolekce", + "collection_description": "Popisy kolekce", + "collection_image": "Obrázek kolekce", + "collection_info": "Informace o kolekci", + "collection_list": "Seznam kolekcí", + "collections": "Kolekce", + "content": "obsah", + "content_grid": "Mřížka obsahu", + "details": "Podrobnosti", + "divider": "Oddělovač", + "filters": "Filtrování a řazení", + "follow_on_shop": "Sledování v aplikaci Shop", + "footer": "Zápatí", + "footer_utilities": "Nástroje v zápatí", + "group": "Skupina", + "header": "Záhlaví", + "heading": "Nadpis", + "icons": "Ikony", + "image_with_text": "Obrázek s textem", + "input": "Vstup", + "logo": "Logo", + "magazine_grid": "Mřížka časopisu", + "media": "Média", + "menu": "Nabídka", + "mobile_layout": "Mobilní rozvržení", + "payment_icons": "Ikony plateb", + "popup_link": "Odkaz na vyskakovací okno", + "predictive_search": "Vyhledávací okno", + "predictive_search_empty": "Prediktivní vyhledávání prázdné", + "price": "Cena", + "product": "Produkt", + "product_card": "Karta produktu", + "product_card_media": "Média", + "product_card_rendering": "Vykreslení karty produktu", + "product_grid": "Mřížka", + "product_grid_main": "Mřížka produktů", + "product_image": "Obrázek produktu", + "product_information": "Informace o produktu", + "product_review_stars": "Hodnocení pomocí hvězdiček", + "quantity": "Množství", + "row": "Řádek", + "search": "Hledání", + "section": "Sekce", + "selected_variants": "Vybrané varianty", + "shop_the_look": "Nakupujte vzhled", + "slide": "Snímek", + "social_media_links": "Odkazy na sociální sítě", + "steps": "Kroky", + "summary": "Shrnutí", + "swatches": "Vzorníky", + "testimonials": "Ohlasy", + "text": "Text", + "title": "Název", + "utilities": "Nástroje", + "search_input": "Vstup hledání", + "search_results": "Výsledky hledání", + "read_only": "Pouze pro čtení", + "collection_title": "Název kolekce", + "collections_bento": "Seznam kolekcí: Bento", + "faq_section": "Nejčastější dotazy", + "hero": "Hero (hlavní banner)", + "jumbo_text": "Text Jumbo", + "product_list": "Doporučená kolekce", + "spacer": "Rozestup", + "view_all_button": "Zobrazit vše", + "video_section": "Video", + "custom_liquid": "Vlastní kód Liquidu", + "blog": "Blog", + "blog_post": "Blogový příspěvek", + "blog_posts": "Příspěvky na blogu", + "caption": "Titulek", + "collection_card_image": "Obrázek", + "collection_links": "Odkazy na kolekce", + "collection_links_spotlight": "Odkazy na kolekce: Spotlight", + "collection_links_text": "Odkazy na kolekce: Text", + "collections_carousel": "Seznam kolekcí: Karusel", + "collections_editorial": "Seznam kolekcí: Úvodník", + "collections_grid": "Seznam kolekcí: Mřížka", + "copyright": "Copyright", + "count": "Počet", + "divider_section": "Oddělovač", + "drawers": "Výsuvné panely", + "editorial": "Úvodník", + "editorial_jumbo_text": "Úvodník: text Jumbo", + "hero_marquee": "Hlavní banner: běžící text", + "input_fields": "Vstupní pole", + "local_pickup": "Místní vyzvednutí", + "marquee_section": "Běžící text", + "media_with_text": "Média s textem", + "page": "Stránka", + "page_content": "Obsah", + "page_layout": "Rozvržení stránky", + "policy_list": "Odkazy na zásady", + "prices": "Ceny", + "products_editorial": "Doporučená kolekce: Úvodník", + "social_link": "Odkaz na sociální sítě", + "split_showcase": "Rozdělená prezentace", + "variant_pickers": "Výběry varianty", + "product_title": "Název produktu", + "large_logo": "Velké logo", + "product_list_button": "Zobrazit tlačítko vše", + "product_inventory": "Skladové zásoby produktu", + "pills": "Kulaté přepínače", + "description": "Popis" + }, + "settings": { + "alignment": "Zarovnání", + "autoplay": "Automatické přehrávání", + "background": "Pozadí", + "border_radius": "Poloměr rohu", + "border_width": "Tloušťka hranice", + "borders": "Ohraničení", + "bottom_padding": "Dolní vnitřní okraj", + "button": "Tlačítko", + "color": "Barva", + "colors": "Barvy", + "content_alignment": "Zarovnání obsahu", + "content_direction": "Směr obsahu", + "content_position": "Pozice obsahu", + "cover_image_size": "Velikost titulního obrázku", + "cover_image": "Titulní obrázek", + "custom_minimum_height": "Vlastní minimální výška", + "custom_width": "Vlastní šířka", + "enable_video_looping": "Smyčky videa", + "favicon": "Favikona", + "font_family": "Rodina písem", + "gap": "Mezera", + "geometric_translate_y": "Geometrické konvertování Y", + "heading": "Nadpis", + "icon": "Ikona", + "image": "Obrázek", + "image_icon": "Ikona obrázku", + "image_opacity": "Neprůhlednost obrázku", + "image_position": "Pozice obrázku", + "image_ratio": "Poměr obrázku", + "label": "Popisek", + "line_height": "Výška řádku", + "link": "Odkaz", + "layout_gap": "Mezera v rozvržení", + "make_section_full_width": "Nastavit plnou šířku sekce", + "minimum_height": "Minimální výška", + "opacity": "Neprůhlednost", + "overlay_opacity": "Neprůhlednost překryvu", + "padding": "Vnitřní okraj", + "primary_color": "Odkazy", + "product": "Produkt", + "section_width": "Šířka oddílu", + "size": "Velikost", + "slide_spacing": "Mezera mezi snímky", + "slide_width": "Šířka snímku", + "slideshow_fullwidth": "Snímky s plnou šířkou", + "style": "Styl", + "text": "Text", + "text_case": "Velká/malá písmena", + "top_padding": "Horní vnitřní okraj", + "video": "Video", + "video_alt_text": "Alternativní text", + "video_loop": "Smyčka videa", + "video_position": "Pozice videa", + "width": "Šířka", + "z_index": "Z-index", + "limit_content_width": "Omezit šířku obsahu", + "color_scheme": "Barevné schéma", + "inherit_color_scheme": "Převzít barevné schéma", + "product_count": "Počet produktů", + "product_type": "Typ produktu", + "content_width": "Šířka obsahu", + "collection": "Kolekce", + "enable_sticky_content": "Plovoucí obsah v počítači", + "error_color": "Chyba", + "success_color": "Úspěch", + "primary_font": "Primární písmo", + "secondary_font": "Sekundární písmo", + "tertiary_font": "Terciární písmo", + "columns": "Sloupce", + "items_to_show": "Položky k zobrazení", + "layout": "Rozvržení", + "layout_type": "Typ", + "show_grid_layout_selector": "Zobrazit selektor rozvržení mřížky", + "view_more_show": "Zobrazit tlačítko Zobrazit více", + "image_gap": "Mezera mezi obrázky", + "width_desktop": "Šířka počítače", + "width_mobile": "Šířka mobilu", + "border_style": "Stal ohraničení", + "height": "Výška", + "thickness": "Tloušťka", + "stroke": "Tah", + "filter_style": "Styl filtru", + "swatches": "Vzorníky", + "quick_add_colors": "Rychlé přidání barev", + "divider_color": "Oddělovač", + "border_opacity": "Neprůhlednost ohraničení", + "hover_background": "Pozadí při najetí", + "hover_borders": "Ohraničení při najetí", + "hover_text": "Text při najetí", + "primary_hover_color": "Odkazy při najetí", + "primary_button_text": "Text primárního tlačítka", + "primary_button_background": "Pozadí primárního tlačítka", + "primary_button_border": "Ohraničení primárního tlačítka", + "secondary_button_text": "Text sekundárního tlačítka", + "secondary_button_background": "Pozadí sekundárního tlačítka", + "secondary_button_border": "Ohraničení sekundárního tlačítka", + "shadow_color": "Stín", + "video_autoplay": "Automatické přehrávání", + "video_cover_image": "Titulní obrázek", + "video_external_url": "URL", + "video_source": "Zdroj", + "card_image_height": "Výška obrázku produktu", + "first_row_media_position": "Pozice médií v prvním řádku", + "accordion": "Skládací panel", + "aspect_ratio": "Poměr stran", + "auto_rotate_announcements": "Automaticky střídat oznámení", + "auto_rotate_slides": "Automaticky otočit snímky", + "badge_corner_radius": "Poloměr rohu", + "badge_position": "Pozice na kartách", + "badge_sale_color_scheme": "Výprodej", + "badge_sold_out_color_scheme": "Vyprodáno", + "behavior": "Chování", + "blur": "Rozmazání stínů", + "border": "Ohraničení", + "bottom": "Dole", + "carousel_on_mobile": "Karusel v mobilu", + "cart_count": "Počet košíků", + "cart_items": "Položky košíku", + "cart_related_products": "Související produkty", + "cart_title": "Košík", + "cart_total": "Součet košíku", + "cart_type": "Typ", + "case": "Velká/malá písmena", + "checkout_buttons": "Tlačítka zrychlené pokladny", + "collection_list": "Kolekce", + "collection_templates": "Šablony kolekce", + "content": "obsah", + "corner_radius": "Poloměr rohu", + "country_region": "Země/oblast", + "currency_code": "Kód měny", + "custom_height": "Vlastní výška", + "desktop_height": "Výška počítače", + "direction": "Směr", + "display": "Zobrazit", + "divider_thickness": "Tloušťka oddělovače", + "divider": "Oddělovač", + "dividers": "Oddělovače", + "drop_shadow": "Drop stín", + "empty_state_collection_info": "Zobrazuje se před zadáním vyhledávání", + "empty_state_collection": "Prázdná kolekce stavů", + "enable_filtering": "Filtry", + "enable_grid_density": "Ovládání rozvržení mřížky", + "enable_sorting": "Řazení", + "enable_zoom": "Povolení zoomu", + "equal_columns": "Stejné sloupce", + "expand_first_group": "Rozbalit první skupinu", + "extend_media_to_screen_edge": "Rozšíření médií až k okraji obrazovky", + "extend_summary": "Rozšíření až k okraji obrazovky", + "extra_large": "Extra velká", + "extra_small": "Extra malá", + "flag": "Vlajka", + "font_price": "Písmo ceny", + "font_weight": "Hmotnost písma", + "font": "Písmo", + "full_width_first_image": "První obrázek na celou šířku", + "full_width_on_mobile": "Plná šířka na mobilu", + "heading_preset": "Předvolba záhlaví", + "hide_unselected_variant_media": "Skrytí nevybraných variant médií", + "horizontal_gap": "Horizontální mezera", + "horizontal_offset": "Horizontální posun stínu", + "hover_behavior": "Chování při najetí", + "icon_background": "Pozadí ikony", + "icons": "Ikony", + "image_border_radius": "Poloměr rohu obrazu", + "installments": "Splátky", + "integrated_button": "Integrované tlačítko", + "language_selector": "Selektor jazyka", + "large": "Velký", + "left_padding": "Levý vnitřní okraj", + "left": "Doleva", + "letter_spacing": "Proložení znaků", + "limit_media_to_screen_height": "Omezit na výšku obrazovky", + "limit_product_details_width": "Omezit šířku údajů o produktu", + "link_preset": "Předvolba na odkaz", + "links": "Odkazy", + "logo": "Logo", + "loop": "Smyčka", + "make_details_sticky_desktop": "Plovoucí obsah v počítači", + "max_width": "Maximální šířka", + "media_height": "Výška médií", + "media_overlay": "Překrytí médií", + "media_position": "Pozice v médiích", + "media_type": "Typ média", + "media_width": "Šířka média", + "menu": "Nabídka", + "mobile_columns": "Mobilní sloupce", + "mobile_height": "Výška mobilního zařízení", + "mobile_logo_image": "Logo pro mobilní zařízení", + "mobile_quick_add": "Rychlé přidání mobilního telefonu", + "motion_direction": "Směr Motion", + "motion": "Motion", + "movement_direction": "Směr pohybu", + "navigation_bar_color_scheme": "Barevné schéma navigačního panelu", + "navigation_bar": "Navigační lišta", + "navigation": "Navigace", + "open_new_tab": "Otevřít odkaz na nové kartě", + "overlay_color": "Barva překryvu", + "overlay": "Překryv", + "padding_bottom": "Dolní vnitřní okraj", + "padding_horizontal": "Horizontální vnitřní okraj", + "padding_top": "Horní vnitřní okraj", + "page_width": "Šířka stránky", + "pagination": "Stránkování", + "placement": "Umístění", + "position": "Pozice", + "preset": "Přednastavení", + "product_cards": "Karty produktů", + "product_pages": "Stránky produktu", + "product_templates": "Šablony produktů", + "products": "Produkty", + "quick_add": "Rychlé přidání", + "ratio": "Poměr", + "regular": "Standardní", + "review_count": "Počet recenzí", + "right": "Vpravo", + "row_height": "Výška řádku", + "row": "Řádek", + "seller_note": "Povolit poznámku pro prodávajícího", + "shape": "Tvar", + "show_as_accordion": "Zobrazit skládací panel na mobilu", + "show_sale_price_first": "Zobrazit výprodejovou cenu jako první", + "show_tax_info": "Daňové informace", + "show": "Zobrazit", + "small": "Malá", + "speed": "Rychlost", + "statement": "Výpis", + "sticky_header": "Plovoucí záhlaví", + "text_hierarchy": "Hierarchie textu", + "text_presets": "Předvolby textu", + "title": "Název", + "top": "Nahoře", + "type": "Typ", + "type_preset": "Předvolba textu", + "underline_thickness": "Tloušťka podtržení", + "variant_images": "Obrázky variant", + "vendor": "Dodavatel", + "vertical_gap": "Svislá mezera", + "vertical_offset": "Vertikální posun stínu", + "vertical_on_mobile": "Vertikální na mobilu", + "view_all_as_last_card": "„Zobrazit vše“ jako poslední kartu", + "weight": "Hmotnost", + "wrap": "Obtékání", + "read_only": "Pouze pro čtení", + "always_stack_buttons": "Vždy skládat tlačítka pod sebe", + "background_color": "Barva pozadí", + "custom_mobile_size": "Vlastní mobilní velikost", + "custom_mobile_width": "Vlastní šířka mobilu", + "fixed_height": "Výška pixelu", + "fixed_width": "Šířka pixelu", + "gradient_direction": "Směr barevného přechodu", + "hide_padding": "Skrýt vnitřní okraj", + "logo_font": "Písmo loga", + "overlay_style": "Styl překryvu", + "percent_height": "Procentní výška", + "percent_size_mobile": "Procentní velikost", + "percent_size": "Procentní velikost", + "percent_width": "Procentní šířka", + "pixel_size_mobile": "Velikost pixelu", + "pixel_size": "Velikost pixelu", + "shadow_opacity": "Neprůhlednost stínu", + "show_filter_label": "Textové štítky pro použité filtry", + "show_swatch_label": "Textové štítky pro vzorníky", + "size_mobile": "Mobilní zobrazení", + "transparent_background": "Průhledné pozadí", + "unit": "Jednotka", + "account": "Účet", + "align_baseline": "Zarovnat výchozí body textu", + "add_discount_code": "Povolit slevy v košíku", + "background_overlay": "Překryv pozadí", + "background_media": "Média na pozadí", + "border_thickness": "Tloušťka hranice", + "bottom_row": "Spodní řádek", + "button_text_case": "Malá/velká písmena v textu", + "button_text_weight": "Tloušťka textu", + "auto_open_cart_drawer": "Funkce „Přidat do košíku“ automaticky otevírá výsuvný košík", + "collection_count": "Počet kolekcí", + "custom_liquid": "Kód Liquidu", + "default": "Výchozí", + "default_logo": "Výchozí logo", + "divider_width": "Šířka oddělovače", + "headings": "Nadpisy", + "hide_logo_on_home_page": "Skrýt logo na domovské stránce", + "horizontal_padding": "Horizontální vnitřní okraj", + "inverse": "Inverzní", + "inverse_logo": "Inverzní logo", + "layout_style": "Styl", + "length": "Délka", + "mobile_pagination": "Mobilní stránkování", + "open_row_by_default": "Otevřít řádek ve výchozím nastavení", + "page_transition_enabled": "Přechod stránky", + "search": "Hledání", + "search_icon": "Ikona hledání", + "search_position": "Pozice", + "search_row": "Řádek", + "show_author": "Autor", + "show_alignment": "Zobrazit zarovnání", + "show_count": "Zobrazit počet", + "show_date": "Datum", + "show_pickup_availability": "Zobrazit dostupnost vyzvednutí", + "show_search": "Zobrazit vyhledání", + "use_inverse_logo": "Použít inverzní logo", + "vertical_padding": "Vertikální vnitřní okraj", + "visibility": "Viditelnost", + "product_corner_radius": "Poloměr rohu produktu", + "card_corner_radius": "Poloměr rohu karty", + "alignment_mobile": "Zarovnání pro mobilní zařízení", + "animation_repeat": "Opakování animace", + "blurred_reflection": "Rozmazaný odraz", + "card_hover_effect": "Efekt při najetí kurzorem na kartu", + "card_size": "Velikost karty", + "collection_title_case": "Interní balení na název kolekce", + "effects": "Efekty", + "inventory_threshold": "Nízký práh skladových zásob", + "mobile_card_size": "Velikost mobilní karty", + "page": "Stránka", + "product_and_card_title_case": "Interní balení na název produktu a karty", + "product_title_case": "Interní balení na název produktu", + "reflection_opacity": "Neprůhlednost odrazu", + "right_padding": "Pravý vnitřní okraj", + "show_inventory_quantity": "Zobrazit množství nízkých skladových zásob", + "text_label_case": "Interní balení textového štítku", + "transition_to_main_product": "Přechod z karty produktu na stránku produktu", + "show_second_image_on_hover": "Zobrazit druhý obrázek po najetí myší/prstem", + "media": "Média", + "product_card_carousel": "Zobrazit karusel", + "media_fit": "Přizpůsobení multimédií", + "scroll_speed": "Přejít na další oznámení" + }, + "options": { + "adapt_to_image": "Přizpůsobení obrázku", + "apple": "Jablko", + "arrow": "Šipka", + "auto": "Automatická", + "banana": "Banán", + "bottle": "Láhev", + "box": "Krabice", + "buttons": "Tlačítka", + "carrot": "Mrkev", + "center": "Střed", + "chat_bubble": "Bublina chatu", + "clipboard": "Psací podložka s klipem", + "contain": "Obsahuje", + "counter": "Počítadlo", + "cover": "Titulní stránka", + "custom": "Vlastní", + "dairy_free": "Bez mléka", + "dairy": "Mléčný produkt", + "default": "Výchozí", + "dropdowns": "Rozevírací seznamy", + "dots": "Tečky", + "dryer": "Sušička", + "end": "Konec", + "eye": "Oko", + "facebook": "Facebook", + "fill": "Výplň", + "fire": "Oheň", + "fit": "Přizpůsobit", + "full": "Plná", + "full_and_page": "Plné pozadí, obsah na šířku stránky", + "gluten_free": "Bezlepkový produkt", + "heading": "Nadpis", + "heart": "Srdce", + "horizontal": "Vodorovně", + "instagram": "Instagram", + "iron": "Žehlička", + "landscape": "Na šířku", + "large": "Velký", + "leaf": "List", + "leather": "Kůže", + "lg": "LG", + "lightning_bolt": "Blesk", + "link": "Odkaz", + "lipstick": "Rtěnka", + "lock": "Zámek", + "lowercase": "malá písmena", + "m": "M", + "map_pin": "Špendlík na mapě", + "medium": "Střední", + "none": "Žádná", + "numbers": "Čísla", + "nut_free": "Bez ořechů", + "outline": "Obrys", + "page": "Stránka", + "pants": "Kalhoty", + "paw_print": "Otisk tlapky", + "pepper": "Pepř", + "perfume": "Parfém", + "pinterest": "Pinterest", + "plane": "Letadlo", + "plant": "Rostlina", + "portrait": "Na výšku", + "price_tag": "Cenovka", + "question_mark": "Otazník", + "recycle": "Recyklace", + "return": "Návrat", + "ruler": "Pravítko", + "s": "S", + "sentence": "Věta", + "serving_dish": "Servírovací mísa", + "shirt": "Košile", + "shoe": "Bota", + "silhouette": "Silueta", + "small": "Malý", + "snapchat": "Snapchat", + "snowflake": "Sněhová vločka", + "solid": "Jednobarevná", + "space_between": "Mezera mezi", + "square": "Čtverec", + "star": "Hvězdička", + "start": "Začátek", + "stopwatch": "Stopky", + "tiktok": "TikTok", + "truck": "Nákladní vůz", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Velká písmena", + "vertical": "Svisle", + "vimeo": "Vimeo", + "washing": "Praní", + "circle": "Kruh", + "swatches": "Vzorníky", + "full_and_page_offset_left": "Celé pozadí, obsah na šířku stránky, odsazení vlevo", + "full_and_page_offset_right": "Celé pozadí, obsah na šířku stránky, odsazení vpravo", + "offset_left": "Odsazení vlevo", + "offset_right": "Odsazení vpravo", + "page_center_aligned": "Stránka, zarovnání na střed", + "page_left_aligned": "Stránka, zarovnání vlevo", + "page_right_aligned": "Stránka, zarovnání vpravo", + "button": "Tlačítko", + "caption": "Titulek", + "h1": "Nadpis 1", + "h2": "Nadpis 2", + "h3": "Nadpis 3", + "h4": "Nadpis 4", + "h5": "Nadpis 5", + "h6": "Nadpis 6", + "paragraph": "Odstavec", + "primary": "Primární", + "secondary": "Sekundární", + "tertiary": "Terciární", + "chevron_left": "Dvojitá šipka vlevo", + "chevron_right": "Dvojitá šipka vpravo", + "diamond": "Kosočtverec", + "grid": "Mřížka", + "parallelogram": "Rovnoběžník", + "rounded": "Zaoblení", + "fit_content": "Přizpůsobení", + "pills": "Kulaté přepínače", + "heavy": "Silný", + "thin": "Tenký", + "drawer": "Výsuvný panel", + "preview": "Náhled", + "text": "Text", + "video_uploaded": "Nahraný soubor", + "video_external_url": "Externí adresa URL", + "aspect_ratio": "Poměr stran", + "above_carousel": "Nad karuselem", + "all": "Vše", + "always": "Vždy", + "arrows_large": "Velké šipky", + "arrows": "Šipky", + "balance": "Zůstatek", + "bento": "Bento", + "black": "Černá", + "bluesky": "Bluesky", + "body_large": "Tělo (Velké)", + "body_regular": "Tělo (Běžné)", + "body_small": "Tělo (Malé)", + "bold": "Tučné", + "bottom_left": "Dole vlevo", + "bottom_right": "Dole vpravo", + "bottom": "Dole", + "capitalize": "Velká písmena", + "caret": "Caret", + "carousel": "Karusel", + "check_box": "Zaškrtávací políčko", + "chevron_large": "Velký znak tvaru V", + "chevron": "znak tvaru V", + "chevrons": "Znaky tvaru V", + "classic": "Klasický", + "collection_images": "Obrázky kolekce", + "color": "Barva", + "complementary": "Doplňkové", + "dissolve": "Rozpustit", + "dotted": "Tečky", + "editorial": "Editorální styl", + "extra_large": "Extra velká", + "extra_small": "Extra malá", + "featured_collections": "Propagované kolekce", + "featured_products": "Propagované produkty", + "font_primary": "Primární", + "font_secondary": "Sekundární", + "font_tertiary": "Terciární", + "forward": "Vpřed", + "full_screen": "Celá obrazovka", + "heading_extra_large": "Nadpis (extra velký)", + "heading_extra_small": "Nadpis (extra malý)", + "heading_large": "Nadpis (Velký)", + "heading_regular": "Nadpis (Běžný)", + "heading_small": "Nadpis (Malý)", + "icon": "Ikona", + "image": "Obrázek", + "input": "Vstup", + "inside_carousel": "Uvnitř karuselu", + "inverse_large": "Inverzní velké", + "inverse": "Inverze", + "large_arrows": "Velké šipky", + "large_chevrons": "Velký znak tvaru V", + "left": "Doleva", + "light": "Světlý", + "linkedin": "LinkedIn", + "loose": "Volné", + "media_first": "Média na prvním místě", + "media_second": "Média na druhým místě", + "modal": "Modální okno", + "narrow": "Úzká", + "never": "Nikdy", + "next_to_carousel": "Vedle karuselu", + "normal": "Normální", + "nowrap": "Bez zalomení", + "off_media": "Mimo média", + "on_media": "V médiích", + "on_scroll_up": "Při skrolování", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Kulatý", + "plus": "Plus", + "pretty": "Pěkný", + "price": "Cena", + "primary_style": "Primární styl", + "rectangle": "Obdélník", + "regular": "Standardní", + "related": "Související", + "reverse": "Reverzní", + "rich_text": "Formát RTF", + "right": "Vpravo", + "secondary_style": "Sekundární styl", + "semibold": "Polotučné písmo", + "shaded": "Stínování", + "show_second_image": "Zobrazit druhý obrázek", + "single": "Jedna volba", + "slide_left": "O snímek vlevo", + "slide_up": "O snímek nahoru", + "spotify": "Spotify", + "stack": "Nad sebou", + "text_only": "Pouze text", + "threads": "Threads", + "thumbnails": "Miniatury", + "tight": "Těsný", + "top_left": "Nahoře vlevo", + "top_right": "Nahoře vpravo", + "top": "Nahoře", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Podtržení", + "video": "Video", + "wide": "Široká", + "youtube": "YouTube", + "below_image": "Pod obrázkem", + "down": "Dolů", + "fixed": "Pevné", + "gradient": "Barevný přechod", + "on_image": "Na obrázku", + "percent": "Procento", + "pixel": "Pixel", + "up": "Nahoru", + "accent": "Se zvýrazněním", + "body": "Hlavní část", + "button_primary": "Primární tlačítko", + "button_secondary": "Sekundární tlačítko", + "compact": "Kompaktní", + "crop_to_fit": "Oříznout na velikost", + "hidden": "Skryté", + "hint": "Tip", + "maintain_aspect_ratio": "Zachovat poměr stran", + "off": "Vypnout", + "social_bluesky": "Sociální síť: Bluesky", + "social_facebook": "Sociální síť: Facebook", + "social_instagram": "Sociální síť: Instagram", + "social_linkedin": "Sociální síť: LinkedIn", + "social_pinterest": "Sociální síť: Pinterest", + "social_snapchat": "Sociální síť: Snapchat", + "social_spotify": "Sociální síť: Spotify", + "social_threads": "Sociální síť: Threads", + "social_tiktok": "Sociální síť: TikTok", + "social_tumblr": "Sociální síť: Tumblr", + "social_twitter": "Sociální síť: X (Twitter)", + "social_whatsapp": "Sociální síť: WhatsApp", + "social_vimeo": "Sociální síť: Vimeo", + "social_youtube": "Sociální síť: YouTube", + "spotlight": "Spotlight", + "standard": "Standardní", + "subheading": "Podnadpis", + "blur": "Rozostřeni", + "lift": "Zvednutí", + "reveal": "Odhalení", + "scale": "Škálování", + "subtle_zoom": "Přiblížení" + }, + "content": { + "advanced": "Pokročilé", + "background_image": "Obrázek na pozadí", + "background_video": "Video na pozadí", + "block_size": "Velikost bloku", + "borders": "Ohraničení", + "describe_the_video_for": "Popište video pro zákazníky používající čtečky obrazovky. [Zjistit více](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Velikost oddílu", + "slideshow_width": "Šířka snímku", + "typography": "Typografie", + "width_is_automatically_optimized": "Šířka se automaticky optimalizuje pro mobilní prostředí.", + "complementary_products": "Doplňkové produkty je třeba nastavit pomocí aplikace Search & Discovery. [Zjistit více](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Sloupce se automaticky optimalizují pro mobilní prostředí.", + "content_width": "Šířka obsahu se použije pouze v případě, že je šířka oddílu nastavena na plnou šířku.", + "adjustments_affect_all_content": "Platí pro veškerý obsah tohoto bloku", + "responsive_font_sizes": "Velikosti se automaticky přizpůsobují velikostem všech obrazovek.", + "buttons": "Tlačítka", + "swatches": "Vzorníky", + "variant_settings": "Nastavení variant", + "background": "Pozadí", + "appearance": "Vzhled", + "arrows": "Šipky", + "body_size": "Velikost textu", + "bottom_row_appearance": "Vzhled spodního řádku", + "carousel_navigation": "Karuselová navigace", + "carousel_pagination": "Karuselové stránkování", + "copyright": "Copyright", + "edit_logo_in_theme_settings": "Úprava loga v [nastavení motivu](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Úprava formátování cen v [nastavení motivu](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Úprava stylů variant v [nastavení motivu](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Registrace přidat [profily zákazníků](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Aby se tlačítko zobrazilo, musí být nainstalován kanál Shop a aktivována služba Shop Pay. [Zjistit více](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Písma", + "grid": "Mřížka", + "heading_size": "Velikost nadpisu", + "image": "Obrázek", + "input": "Vstup", + "layout": "Rozvržení", + "link": "Odkaz", + "link_padding": "Vnitřní okraj odkazů", + "localization": "Lokalizace", + "logo": "Logo", + "margin": "Okraj", + "media": "Média", + "media_1": "Média 1", + "media_2": "Média 2", + "menu": "nabídka", + "mobile_layout": "Mobilní rozvržení", + "padding": "Vnitřní okraj", + "padding_desktop": "Vnitřní okraj počítače", + "paragraph": "Odstavec", + "policies": "Zásady", + "popup": "Vyskakovací okno", + "search": "Hledání", + "size": "Velikost", + "social_media": "Sociální sítě", + "submit_button": "Tlačítko Odeslat", + "text_presets": "Předvolby textu", + "transparent_background": "Průhledné pozadí", + "typography_primary": "Primární typografie", + "typography_secondary": "Sekundární typografie", + "typography_tertiary": "Terciární typografie", + "mobile_size": "Mobilní zobrazení", + "cards_layout": "Rozvržení karet", + "mobile_width": "Šířka mobilu", + "section_layout": "Rozvržení sekce", + "width": "Šířka", + "carousel": "Karusel", + "colors": "Barvy", + "collection_page": "Stránka s kolekcemi", + "copyright_info": "Zjistěte, jak [upravit své prohlášení o autorských právech ](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Zákaznický účet", + "edit_empty_state_collection_in_theme_settings": "Prázdné kolekce upravujte v [nastavení motivu](/editor?context=theme&category=search)", + "home_page": "Domovská stránka", + "images": "Obrázky", + "inverse_logo_info": "Používáno, když je průhledné pozadí záhlaví nastaveno na Inverzní", + "manage_customer_accounts": "[Spravovat viditelnost](/admin/settings/customer_accounts) v nastavení zákaznického účtu. Starší účty nejsou podporovány.", + "manage_policies": "[Spravovat zásady](/admin/settings/legal)", + "product_page": "Stránka produktu", + "text": "Text", + "thumbnails": "Miniatury", + "visibility": "Viditelnost", + "visible_if_collection_has_more_products": "Viditelné, pokud kolekce obsahuje více produktů, než je jich zobrazeno", + "grid_layout": "Rozvržení mřížky", + "app_required_for_ratings": "Pro hodnocení produktů je nutná aplikace. [Zjistit více](https://help.shopify.com/manual/apps)", + "icon": "Ikona", + "resource_reference_collection_card": "Zobrazí kolekci z nadřazené sekce", + "resource_reference_collection_card_image": "Zobrazí obrázek z nadřazené kolekce", + "resource_reference_collection_title": "Zobrazí nadpis z nadřazené kolekce", + "resource_reference_product": "Automaticky se spojí s nadřazeným produktem", + "resource_reference_product_card": "Zobrazí produkt z nadřazené sekce", + "resource_reference_product_inventory": "Zobrazí skladové zásoby nadřazeného produktu", + "resource_reference_product_price": "Zobrazí cenu nadřazeného produktu", + "resource_reference_product_recommendations": "Zobrazí doporučení založená na nadřazeném produktu", + "resource_reference_product_review": "Zobrazí recenze nadřazeného produktu", + "resource_reference_product_swatches": "Zobrazí vzorníky z nadřazeného produktu", + "resource_reference_product_title": "Zobrazí nadpis z nadřazeného produktu", + "resource_reference_product_variant_picker": "Zobrazí varianty nadřazeného produktu", + "resource_reference_product_media": "Zobrazuje média z nadřazeného produktu", + "product_media": "Média produktu", + "manage_store_name": "[Spravovat název obchodu](/admin/settings/general?edit=storeName)", + "section_link": "Odkaz na sekci" + }, + "html_defaults": { + "share_information_about_your": "

Informujte zákazníky o své značce. Zároveň můžete popsat některý z produktů, oznámit důležité informace nebo přivítat zákazníky ve svém obchodě.

" + }, + "text_defaults": { + "button_label": "Nakupovat nyní", + "collapsible_row": "Sbalitelný řádek", + "heading": "Nadpis", + "email_signup_button_label": "Předplatit", + "accordion_heading": "Záhlaví skládacího panelu", + "contact_form_button_label": "Odeslat", + "popup_link": "Odkaz na vyskakovací okno", + "sign_up": "Zaregistrovat se", + "welcome_to_our_store": "Vítejte v našem obchodě", + "be_bold": "Tučné.", + "shop_our_latest_arrivals": "Vyberte si z novinek v našem obchodě!" + }, + "info": { + "video_alt_text": "Popište video pro uživatele asistivních technologií", + "video_autoplay": "Videa budou ve výchozím nastavení ztlumena", + "video_external": "Zadejte adresu URL z YouTube nebo Vimea", + "carousel_layout_on_mobile": "Karusel se používá na mobilních zařízeních.", + "carousel_hover_behavior_not_supported": "Přejetí myší přes „Karusel“ není podporováno, pokud je na úrovni sekce vybrán typ „Karusel“", + "link_info": "Volitelné: umožňuje kliknutí na ikonu", + "checkout_buttons": "Umožňuje kupujícím rychlejší zaplacení a může zlepšit konverzi. [Zjistit více](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Vlastní nadpis", + "edit_presets_in_theme_settings": "Úprava předvoleb v [nastavení motivu](/editor?context=theme&category=typography)", + "enable_filtering_info": "Přizpůsobte si filtry pomocí aplikace [Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "manage_countries_regions": "[Spravovat země/oblasti](/admin/settings/markets)", + "manage_languages": "[Spravovat jazyky](/admin/settings/languages)", + "transparent_background": "Zkontrolujte každou šablonu, kde je použito průhledné pozadí pro lepší čitelnost", + "grid_layout_on_mobile": "Rozložení mřížky se používá pro mobilní zařízení", + "logo_font": "Platí pouze v případě, že není vybráno logo", + "aspect_ratio_adjusted": "Upraveno v některých rozvrženích", + "auto_open_cart_drawer": "Pokud je tato funkce povolena, při přidání produktu do košíku se automaticky otevře výsuvný košík.", + "custom_liquid": "Přidejte fragmenty aplikací nebo jiný kód a vytvořte pokročilá přizpůsobení. [Zjistit více](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "Platí pouze pro obrázky", + "hover_effects": "Platí pro karty produktů a kolekcí", + "pills_usage": "Používá se pro použité filtry, slevové kódy a návrhy vyhledávání" + }, + "categories": { + "product_list": "Doporučená kolekce", + "basic": "Basic", + "collection": "Kolekce", + "collection_list": "Seznam kolekcí", + "footer": "Zápatí", + "forms": "Formuláře", + "header": "Záhlaví", + "layout": "Rozvržení", + "links": "Odkazy", + "product": "Produkt", + "banners": "Bannery", + "collections": "Kolekce", + "custom": "Vlastní", + "decorative": "Dekorativní", + "products": "Produkty", + "other_sections": "Ostatní", + "storytelling": "Vyprávění příběhů" + } +} diff --git a/locales/da.json b/locales/da.json new file mode 100644 index 000000000..f52eccfe4 --- /dev/null +++ b/locales/da.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Indlæs video: {{ description }}", + "sold_out": "Udsolgt", + "email_signup": { + "label": "Mail", + "placeholder": "Mailadresse", + "success": "Tak for din tilmelding" + }, + "filter": "Filtrer", + "payment_methods": "Betalingsmetoder", + "contact_form": { + "name": "Navn", + "email": "Mailadresse", + "phone": "Telefon", + "comment": "Kommentar", + "post_success": "Tak for din henvendelse. Vi kontakter dig hurtigst muligt.", + "error_heading": "Juster følgende:" + } + }, + "accessibility": { + "play_model": "Afspil 3D-model", + "play_video": "Afspil video", + "unit_price": "Stykpris", + "country_results_count": "{{ count }} resultater", + "slideshow_pause": "Sæt diasshow på pause", + "slideshow_play": "Afspil diasshow", + "skip_to_text": "Gå til indhold", + "skip_to_product_info": "Gå til produktoplysninger", + "skip_to_results_list": "Gå direkte til resultatlisten", + "remove_item": "Fjern {{ title}}", + "new_window": "Åbnes i et nyt vindue.", + "close_dialog": "Luk dialogboks", + "reset_search": "Nulstil søgning", + "search_results_count": "{{ count }} søgeresultater fundet for “{{ query }}”", + "search_results_no_results": "Ingen resultater fundet for “{{ query }}”", + "slideshow_next": "Næste dias", + "slideshow_previous": "Forrige dias", + "filters": "Filtre", + "filter_count": { + "one": "{{ count }} filter anvendt", + "other": "{{ count }} filtre anvendt" + }, + "account": "Åbn kontomenu", + "cart": "Indkøbskurv", + "cart_count": "Varer i alt i indkøbskurven", + "menu": "Menu", + "country_region": "Land/område", + "slide_status": "Dias {{ index }} af {{ length }}", + "scroll_to": "Scroll til {{ title }}", + "loading_product_recommendations": "Indlæser produktanbefalinger", + "discount": "Anvend en rabatkode", + "discount_applied": "Anvendt rabatkode: {{ code }}", + "open_cart_drawer": "Åbn indkøbskurv", + "pause_video": "Sæt video på pause", + "inventory_status": "Lagerstatus", + "find_country": "Find land", + "localization_region_and_language": "Åbn område- og sprogvælger", + "open_search_modal": "Åbn søgning", + "decrease_quantity": "Reducer antal", + "increase_quantity": "Øg antal", + "quantity": "Antal", + "rating": "Bedømmelsen af dette produkt er {{ rating }} ud af 5", + "nested_product": "{{ product_title }} for {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Læg i indkøbskurven", + "clear_all": "Ryd alt", + "remove": "Fjern", + "view_in_your_space": "Se den i dit område", + "show_filters": "Filtrer", + "clear": "Ryd", + "continue_shopping": "Tilbage til butikken", + "log_in_html": "Har du en konto? Log ind for at betale hurtigere.", + "see_items": { + "one": "Se {{ count }} vare", + "other": "Se {{ count }} varer" + }, + "view_all": "Se alle", + "add": "Tilføj", + "choose": "Vælg", + "added": "Tilføjet", + "show_less": "Vis mindre", + "show_more": "Vis mere", + "close": "Luk", + "more": "Mere", + "reset": "Nulstil", + "zoom": "Zoom", + "close_dialog": "Luk dialogboks", + "back": "Tilbage", + "log_in": "Log ind", + "log_out": "Log af", + "remove_discount": "Fjern rabatten {{ code }}", + "enter_using_password": "Brug adgangskode for at få adgang", + "submit": "Send", + "enter_password": "Angiv adgangskode", + "view_store_information": "Se butiksoplysninger", + "apply": "Anvend", + "sign_up": "Tilmeld dig", + "open_image_in_full_screen": "Åbn billede i fuld skærm", + "sign_in_options": "Andre muligheder for at logge ind", + "sort": "Sortér", + "show_all_options": "Vis alle muligheder" + }, + "content": { + "reviews": "anmeldelser", + "language": "Sprog", + "localization_region_and_language": "Område og sprog", + "no_results_found": "Der blev ikke fundet nogen resultater", + "cart_total": "Indkøbskurv i alt", + "your_cart_is_empty": "Din indkøbskurv er tom", + "cart_estimated_total": "Forventet totalbeløb", + "seller_note": "Særlige instruktioner", + "cart_subtotal": "Subtotal", + "discounts": "Rabatter", + "discount": "Rabat", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Inklusive told og skatter. Rabatter og levering beregnes ved betaling.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Inklusive told og skatter. Rabatter og levering beregnes ved betaling.", + "taxes_included_shipping_at_checkout_with_policy_html": "Inklusive skatter. Rabatter og levering beregnes ved betaling.", + "taxes_included_shipping_at_checkout_without_policy": "Inklusive skatter. Rabatter og levering beregnes ved betaling.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Inklusive told. Skatter, rabatter og levering beregnes ved betaling.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Inklusive told. Skatter, rabatter og levering beregnes ved betaling.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Skatter, rabatter og levering beregnes ved betaling.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Skatter, rabatter og levering beregnes ved betaling.", + "checkout": "Gå til betaling", + "cart_title": "Indkøbskurv", + "product_image": "Produktbillede", + "product_information": "Produktoplysninger", + "product_total": "Produkt i alt", + "quantity": "Antal", + "price": "Pris", + "price_regular": "Normalpris", + "price_compare_at": "Sammenligningspris", + "price_sale": "Udsalgspris", + "duties_and_taxes_included": "Inkl. told og skatter.", + "duties_included": "Inkl. told.", + "shipping_policy_html": "Fragt beregnes ved betaling.", + "taxes_included": "Inkl. skatter.", + "product_badge_sold_out": "Udsolgt", + "product_badge_sale": "Udsalg", + "search_input_label": "Søg", + "search_input_placeholder": "Søg", + "search_results": "Søgeresultater", + "search_results_label": "Søgeresultater", + "search_results_no_results": "Der blev ikke fundet nogen resultater for “{{ terms }}”. Prøv at ændre søgeord.", + "search_results_resource_articles": "Blogopslag", + "search_results_resource_collections": "Kollektioner", + "search_results_resource_pages": "Sider", + "search_results_resource_products": "Produkter", + "search_results_resource_queries": "Søgeforslag", + "search_results_view_all": "Se alle", + "search_results_view_all_button": "Se alle", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} produkter" + }, + "grid_view": { + "default_view": "Standard", + "grid_fieldset": "Kolonnegitter", + "single_item": "Enkelt", + "zoom_out": "Zoom ud" + }, + "unavailable": "Ikke tilgængelig", + "collection_placeholder": "Kollektionstitel", + "product_card_placeholder": "Produkttitel", + "recently_viewed_products": "Vist for nylig", + "product_count": "Produktantal", + "item_count": { + "one": "{{ count }} vare", + "other": "{{ count }} varer" + }, + "errors": "Fejl", + "search": "Søg", + "search_results_no_results_check_spelling": "Der blev ikke fundet nogen resultater for “{{ terms }}”. Kontrollér stavemåden, eller brug et andet ord eller udtryk.", + "filters": "Filtre", + "price_from": "Fra {{ price }}", + "price_filter_html": "Den højeste pris er {{ price }}", + "featured_products": "Udvalgte produkter", + "no_products_found": "Der blev ikke fundet nogen produkter.", + "use_fewer_filters_html": "Prøv at bruge færre filtre, eller ryd alle filtre.", + "blog_details_separator": "|", + "account_title": "Konto", + "account_title_personalized": "Hej {{ first_name }}", + "account_orders": "Ordrer", + "account_profile": "Profil", + "discount_code": "Rabatkode", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Inklusive told og skatter. Levering beregnes ved betaling.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Inklusive told og skatter. Levering beregnes ved betaling.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Inklusive told. Levering beregnes ved betaling.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Inklusive told. Levering beregnes ved betaling.", + "pickup_available_at_html": "Afhentning er tilgængelig her: {{ location }}", + "pickup_available_in": "Afhentning er tilgængelig {{ pickup_time }}", + "pickup_not_available": "Afhentning er ikke tilgængelig lige nu", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Læs mere ...", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Skatter og levering beregnes ved betaling.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Skatter og levering beregnes ved betaling.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Inklusive skatter. Levering beregnes ved betaling.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Inklusive skatter. Levering beregnes ved betaling.", + "wrong_password": "Forkert adgangskode", + "view_more_details": "Se flere oplysninger", + "page_placeholder_title": "Sidetitel", + "page_placeholder_content": "Vælg en side for at vise dens indhold.", + "placeholder_image": "Pladsholderbillede", + "powered_by": "Denne butik vil blive drevet af", + "store_owner_link_html": "Er du butiksejeren? Log ind her", + "shipping_discount_error": "Forsendelsesrabatter vises ved betaling efter tilføjelse af en adresse", + "discount_code_error": "Rabatkoden kan ikke anvendes i din indkøbskurv", + "inventory_low_stock": "Lav lagerbeholdning", + "inventory_in_stock": "På lager", + "inventory_out_of_stock": "Ikke på lager", + "shipping_policy": "Levering beregnes ved betaling.", + "inventory_low_stock_show_count": { + "one": "{{ count }} tilbage", + "other": "{{ count }} tilbage" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Brug gavekortkoden online eller som QR-kode i butikken", + "title": "Her er din gavekortsaldo ({{ value }}) for {{ shop }}!", + "subtext": "Dit gavekort", + "shop_link": "Besøg webshop", + "add_to_apple_wallet": "Føj til Apple Wallet", + "qr_image_alt": "QR-kode – scan for at indløse gavekort", + "copy_code": "Kopiér gavekortskode", + "expiration_date": "Udløber {{ expires_on }}", + "copy_code_success": "Koden er blevet kopieret", + "expired": "Udløbet" + } + }, + "placeholders": { + "password": "Adgangskode", + "search": "Søg", + "product_title": "Produkttitel", + "collection_title": "Kollektionstitel" + }, + "products": { + "product": { + "add_to_cart": "Læg i indkøbskurven", + "added_to_cart": "Lagt i indkøbskurv", + "adding_to_cart": "Tilføjer...", + "add_to_cart_error": "Der opstod en fejl, da du lagde varen i indkøbskurven", + "sold_out": "Udsolgt", + "unavailable": "Ikke tilgængelig" + } + }, + "fields": { + "separator": "til" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} kommentar", + "other": "{{ count }} kommentarer" + } + }, + "comment_form": { + "email": "Mail", + "error": "Kommentaren blev ikke offentliggjort. Ret følgende:", + "heading": "Skriv en kommentar", + "message": "Besked", + "moderated": "Bemærk, at kommentarer skal godkendes, før de bliver offentliggjort.", + "name": "Navn", + "post": "Send kommentar", + "success_moderated": "Kommentaren blev indsendt og afventer moderering", + "success": "Kommentaren blev indsendt" + } + } +} diff --git a/locales/da.schema.json b/locales/da.schema.json new file mode 100644 index 000000000..2721dccae --- /dev/null +++ b/locales/da.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Kanter", + "collapsible_row": "Række, der kan skjules", + "colors": "Farver", + "custom_section": "Tilpasset afsnit", + "icon": "Ikon", + "logo_and_favicon": "Logo og favoritikon", + "overlapping_blocks": "Overlappende blokke", + "product_buy_buttons": "Køb-knapper", + "product_description": "Beskrivelse", + "product_price": "Pris", + "product_variant_picker": "Variantvælger", + "slideshow": "Diasshow", + "typography": "Typografi", + "video": "Video", + "slideshow_controls": "Styring af diasshow", + "size": "Størrelse", + "spacing": "Mellemrum", + "product_recommendations": "Anbefalede produkter", + "product_media": "Produktmedier", + "featured_collection": "Udvalgt kollektion", + "add_to_cart": "Læg i indkøbskurven", + "email_signup": "Tilmelding med mail", + "submit_button": "Send-knap", + "grid_layout_selector": "Gitter-vælger", + "image": "Billede", + "list_items": "Listevarer", + "facets": "Facetter", + "variants": "Varianter", + "styles": "Stile", + "product_cards": "Produktkort", + "buttons": "Knapper", + "inputs": "Inputs", + "primary_button": "Primær knap", + "secondary_button": "Sekundær knap", + "popovers": "Popovers", + "marquee": "Lysavis", + "pull_quote": "Citat", + "contact_form": "Kontaktformular", + "featured_product": "Fremhævelser af produkter", + "icons_with_text": "Ikoner med tekst", + "alternating_content_rows": "Hver anden række", + "accelerated_checkout": "Hurtigere betaling", + "accordion": "Harmonika", + "accordion_row": "Harmonikarække", + "animations": "Animationer", + "announcement": "Meddelelse", + "announcement_bar": "Meddelelseslinje", + "badges": "Badges", + "button": "Knap", + "cart": "Indkøbskurv", + "cart_items": "Varer i indkøbskurv", + "cart_products": "Produkter i indkøbskurv", + "cart_title": "Indkøbskurv", + "collection": "Kollektion", + "collection_card": "Kollektionskort", + "collection_columns": "Kollektionskolonner", + "collection_container": "Kollektion", + "collection_description": "Kollektionsbeskrivelse", + "collection_image": "Kollektionsbillede", + "collection_info": "Kollektionsoplysninger", + "collection_list": "Kollektionsliste", + "collections": "Kollektioner", + "content": "Indhold", + "content_grid": "Indholdsgitter", + "details": "Detaljer", + "divider": "Skillelinje", + "filters": "Filtrering og sortering", + "follow_on_shop": "Følg på Shop", + "footer": "Sidefod", + "footer_utilities": "Sidefodfunktioner", + "group": "Gruppe", + "header": "Sidehoved", + "heading": "Overskrift", + "icons": "Ikoner", + "image_with_text": "Billede med tekst", + "input": "Input", + "logo": "Logo", + "magazine_grid": "Magasingitter", + "media": "Medier", + "menu": "Menu", + "mobile_layout": "Mobillayout", + "payment_icons": "Betalingsikoner", + "popup_link": "Link til pop op-vindue", + "predictive_search": "Popover med søgefelt", + "predictive_search_empty": "Prædiktiv søgning er tom", + "price": "Pris", + "product": "Produkt", + "product_card": "Produktkort", + "product_card_media": "Medier", + "product_card_rendering": "Gengivelse af produktkort", + "product_grid": "Gitter", + "product_grid_main": "Produktgitter", + "product_image": "Produktbillede", + "product_information": "Produktoplysninger", + "product_review_stars": "Anmeldelsesstjerner", + "quantity": "Antal", + "row": "Række", + "search": "Søg", + "section": "Sektion", + "selected_variants": "Valgte varianter", + "shop_the_look": "Shop looket", + "slide": "Dias", + "social_media_links": "Links til sociale medier", + "steps": "Trin", + "summary": "Oversigt", + "swatches": "Prøver", + "testimonials": "Udtalelser", + "text": "Tekst", + "title": "Titel", + "utilities": "Funktioner", + "search_input": "Søgeinput", + "search_results": "Søgeresultater", + "read_only": "Skrivebeskyttet", + "collections_bento": "Kollektionsliste: Bento", + "faq_section": "Ofte stillede spørgsmål", + "hero": "Hero", + "jumbo_text": "Jumbotekst", + "product_list": "Fremhævet kollektion", + "spacer": "Afstandsstykke", + "video_section": "Video", + "product_title": "Produkttitel", + "custom_liquid": "Tilpasset Liquid", + "blog": "Blog", + "blog_post": "Blogopslag", + "blog_posts": "Blogopslag", + "caption": "Billedtekst", + "collection_card_image": "Billede", + "collection_title": "Kollektionstitel", + "collection_links": "Kollektionslinks", + "collection_links_spotlight": "Kollektionslinks: Fokus", + "collection_links_text": "Kollektionslinks: Tekst", + "collections_carousel": "Kollektionsliste: Karrusel", + "collections_editorial": "Kollektionsliste: redaktionel", + "collections_grid": "Kollektionsliste: Gitter", + "copyright": "Ophavsret", + "count": "Antal", + "divider_section": "Skillelinje", + "drawers": "Skuffer", + "editorial": "Redaktionel", + "editorial_jumbo_text": "Redaktionel: Jumbo-tekst", + "hero_marquee": "Hero: Lysavis", + "input_fields": "Indtastningsfelter", + "local_pickup": "Lokal afhentning", + "marquee_section": "Lysavis", + "media_with_text": "Medier med tekst", + "page": "Side", + "page_content": "Indhold", + "page_layout": "Sidelayout", + "policy_list": "Links til politikker", + "prices": "Priser", + "product_list_button": "Knappen Se alle", + "products_carousel": "Fremhævet kollektion: Karrusel", + "products_editorial": "Fremhævet kollektion: Redaktionel", + "products_grid": "Fremhævet kollektion: Gitter", + "social_link": "SoMe-link", + "split_showcase": "Opdel udstilling", + "variant_pickers": "Variantvælgere", + "view_all_button": "Se alle", + "pills": "Etiketter", + "large_logo": "Stort logo", + "product_inventory": "Produktlager", + "description": "Beskrivelse" + }, + "settings": { + "alignment": "Justering", + "autoplay": "Automatisk afspilning", + "background": "Baggrund", + "border_radius": "Hjørneradius", + "border_width": "Kanttykkelse", + "borders": "Kanter", + "bottom_padding": "Indre margen, bund", + "button": "Knap", + "color": "Farve", + "colors": "Farver", + "content_alignment": "Indholdsjustering", + "content_direction": "Indholdsretning", + "content_position": "Indholdsplacering", + "cover_image_size": "Størrelse på coverbillede", + "cover_image": "Coverbillede", + "custom_minimum_height": "Tilpasset minimumshøjde", + "custom_width": "Brugerdefineret bredde", + "enable_video_looping": "Looping af videoer", + "favicon": "Favoritikon", + "font_family": "Skrifttypefamilie", + "gap": "Kløft", + "geometric_translate_y": "Geometrisk oversættelse Y", + "heading": "Overskrift", + "icon": "Ikon", + "image": "Billede", + "image_icon": "Ikon for billede", + "image_opacity": "Billedets uigennemsigtighed", + "image_position": "Placering af billede", + "image_ratio": "Billedforhold", + "label": "Label", + "line_height": "Linjehøjde", + "link": "Link", + "layout_gap": "Afstand i layout", + "make_section_full_width": "Gør afsnittet til fuld bredde", + "minimum_height": "Minimumshøjde", + "opacity": "Uigennemsigtighed", + "overlay_opacity": "Overlejringens uigennemsigtighed", + "padding": "Margen", + "primary_color": "Links", + "product": "Produkt", + "section_width": "Afsnitsbredde", + "size": "Størrelse", + "slide_spacing": "Diasmellemrum", + "slide_width": "Diasbredde", + "slideshow_fullwidth": "Dias i fuld bredde", + "style": "Stil", + "text": "Tekst", + "text_case": "Store/små bogstaver", + "top_padding": "Indre margen, top", + "video": "Video", + "video_alt_text": "Alternativ tekst", + "video_loop": "Gentag video", + "video_position": "Videoplacering", + "width": "Bredde", + "z_index": "Å-indeks", + "limit_content_width": "Begræns indholds bredde", + "color_scheme": "Farveskema", + "inherit_color_scheme": "Nedarv farveskema", + "product_count": "Produktantal", + "product_type": "Produkttype", + "content_width": "Indholdsbredde", + "collection": "Kollektion", + "enable_sticky_content": "Klæbende indhold på computer", + "error_color": "Fejl", + "success_color": "Gennemført", + "primary_font": "Primær skrifttype", + "secondary_font": "Sekundær skrifttype", + "tertiary_font": "Tertiær skrifttype", + "columns": "Kolonner", + "items_to_show": "Varer, der kan vises", + "layout": "Layout", + "layout_type": "Type", + "show_grid_layout_selector": "Vis gitter-vælger", + "view_more_show": "Vis knappen “Se mere”", + "image_gap": "Billedafstand", + "width_desktop": "Bredde på computer", + "width_mobile": "Bredde på mobil", + "border_style": "Kantstil", + "height": "Højde", + "thickness": "Tykkelse", + "stroke": "Streg", + "filter_style": "Filterstil", + "swatches": "Prøver", + "quick_add_colors": "Hurtig tilføjelse af farver", + "divider_color": "Skillelinje", + "border_opacity": "Uigennemsigtighed for kant", + "hover_background": "Svævebaggrund", + "hover_borders": "Svævekanter", + "hover_text": "Svævetekst", + "primary_hover_color": "Svævelinks", + "primary_button_text": "Knaptekst for primær knap", + "primary_button_background": "Baggrund for primær knap", + "primary_button_border": "Kant for primær knap", + "secondary_button_text": "Knaptekst for sekundær knap", + "secondary_button_background": "Baggrund for sekundær knap", + "secondary_button_border": "Kant for sekundær knap", + "shadow_color": "Skygge", + "video_autoplay": "Automatisk afspilning", + "video_cover_image": "Coverbillede", + "video_external_url": "Webadresse", + "video_source": "Kilde", + "first_row_media_position": "Placering af medie i først række", + "accordion": "Harmonika", + "aspect_ratio": "Højde-bredde-forhold", + "auto_rotate_announcements": "Roter meddelelser automatisk", + "auto_rotate_slides": "Roter dias automatisk", + "badge_corner_radius": "Hjørneradius", + "badge_position": "Placering på kort", + "badge_sale_color_scheme": "Udsalg", + "badge_sold_out_color_scheme": "Udsolgt", + "behavior": "Adfærd", + "blur": "Sløret skygge", + "border": "Kant", + "bottom": "Nederst", + "card_image_height": "Højde på produktbillede", + "carousel_on_mobile": "Karrusel på mobil", + "cart_count": "Antal i indkøbskurv", + "cart_items": "Varer i indkøbskurv", + "cart_related_products": "Relaterede produkter", + "cart_title": "Indkøbskurv", + "cart_total": "Indkøbskurv i alt", + "cart_type": "Type", + "case": "Store/små bogstaver", + "checkout_buttons": "Knapper til hurtigere betaling", + "collection_list": "Kollektioner", + "collection_templates": "Kollektionsskabeloner", + "content": "Indhold", + "corner_radius": "Hjørneradius", + "country_region": "Land/område", + "currency_code": "Valutakode", + "custom_height": "Tilpasset højde", + "desktop_height": "Højde på computer", + "direction": "Retning", + "display": "Skærm", + "divider_thickness": "Tykkelse på skillelinje", + "divider": "Skillelinje", + "dividers": "Skillelinjer", + "drop_shadow": "Skyggeeffekt", + "empty_state_collection_info": "Vises, før der angives en søgning", + "empty_state_collection": "Kollektion i tom tilstand", + "enable_filtering": "Filtre", + "enable_grid_density": "Styring af gitterlayout", + "enable_sorting": "Sortering", + "enable_zoom": "Aktivér zoom", + "equal_columns": "Ens kolonner", + "expand_first_group": "Udvid første gruppe", + "extend_media_to_screen_edge": "Udvid medier til skærmens kant", + "extend_summary": "Udvid til skærmens kant", + "extra_large": "Ekstra stor", + "extra_small": "Ekstra lille", + "flag": "Flag", + "font_price": "Skrifttype til pris", + "font_weight": "Skrifttykkelse", + "font": "Skrifttype", + "full_width_first_image": "Første billede i fuld bredde", + "full_width_on_mobile": "Fuld bredde på mobil", + "heading_preset": "Forudindstilling for overskrift", + "hide_unselected_variant_media": "Skjul medier for varianter, der ikke er valgt", + "horizontal_gap": "Vandret afstand", + "horizontal_offset": "Vandret forskydning af skygge", + "hover_behavior": "Adfærd, når der peges med musen", + "icon_background": "Ikonbaggrund", + "icons": "Ikoner", + "image_border_radius": "Hjørneradius på billede", + "installments": "Rater", + "integrated_button": "Integreret knap", + "language_selector": "Sprogvælger", + "large": "Stor", + "left_padding": "Venstre indre margen", + "left": "Venstre", + "letter_spacing": "Afstand mellem bogstaver", + "limit_media_to_screen_height": "Begræns til skærmhøjden", + "limit_product_details_width": "Begræns bredden på produktdetaljer", + "link_preset": "Forudindstilling for link", + "links": "Links", + "logo": "Logo", + "loop": "Gentag", + "make_details_sticky_desktop": "Fastgjort på computer", + "max_width": "Max. bredde", + "media_height": "Højde på medie", + "media_overlay": "Overlejring af medie", + "media_position": "Placering af medie", + "media_type": "Medietype", + "media_width": "Bredde på medie", + "menu": "Menu", + "mobile_columns": "Kolonner på mobil", + "mobile_height": "Højde på mobil", + "mobile_logo_image": "Logo på mobil", + "mobile_quick_add": "Hurtig tilføjelse på mobil", + "motion_direction": "Bevægelsesretning", + "motion": "Bevægelse", + "movement_direction": "Bevægelsesretning", + "navigation_bar_color_scheme": "Farveskema til navigationslinje", + "navigation_bar": "Navigationslinje", + "navigation": "Navigation", + "open_new_tab": "Åbn link på ny fane", + "overlay_color": "Farve på overlejring", + "overlay": "Overlejring", + "padding_bottom": "Nederste indre margen", + "padding_horizontal": "Vandret indre margen", + "padding_top": "Øverste indre margen", + "page_width": "Sidebredde", + "pagination": "Sideinddeling", + "placement": "Placering", + "position": "Position", + "preset": "Forudindstilling", + "product_cards": "Produktkort", + "product_pages": "Produktsider", + "product_templates": "Produktskabeloner", + "products": "Produkter", + "quick_add": "Tilføj hurtigt", + "ratio": "Forhold", + "regular": "Almindelig", + "review_count": "Antal anmeldelser", + "right": "Højre", + "row_height": "Rækkehøjde", + "row": "Række", + "seller_note": "Tillad note til sælger", + "shape": "Form", + "show_as_accordion": "Vis som harmonika på mobil", + "show_sale_price_first": "Vis salgsprisen først", + "show_tax_info": "Skatteoplysninger", + "show": "Vis", + "small": "Lille", + "speed": "Hastighed", + "statement": "Erklæring", + "sticky_header": "Fastgjort sidehoved", + "text_hierarchy": "Teksthierarki", + "text_presets": "Forudindstillede tekster", + "title": "Titel", + "top": "Øverst", + "type": "Type", + "type_preset": "Forudindstillet tekst", + "underline_thickness": "Tykkelse af understregning", + "variant_images": "Variantbilleder", + "vendor": "Forhandler", + "vertical_gap": "Lodret afstand", + "vertical_offset": "Lodret forskydning af skygge", + "vertical_on_mobile": "Lodret på mobil", + "view_all_as_last_card": "“Se alle” som sidste kort", + "weight": "Vægt", + "wrap": "Ombryd", + "read_only": "Skrivebeskyttet", + "always_stack_buttons": "Stabl altid knapper", + "background_color": "Baggrundsfarve", + "custom_mobile_size": "Tilpasset størrelse på mobil", + "custom_mobile_width": "Tilpasset bredde på mobil", + "fixed_height": "Højde i pixel", + "fixed_width": "Bredde i pixel", + "gradient_direction": "Retning på graduering", + "hide_padding": "Skjul indre margen", + "logo_font": "Skrifttype i logo", + "overlay_style": "Typen af overlejring", + "percent_height": "Højde i procent", + "percent_size_mobile": "Størrelse i procent", + "percent_size": "Størrelse i procent", + "percent_width": "Bredde i procent", + "pixel_size_mobile": "Størrelse i pixel", + "pixel_size": "Størrelse i pixel", + "shadow_opacity": "Skyggens uigennemsigtighed", + "show_filter_label": "Tekstlabels på anvendte filtre", + "show_swatch_label": "Tekstlabels til prøver", + "size_mobile": "Størrelse på mobil", + "transparent_background": "Gennemsigtig baggrund", + "unit": "Enhed", + "hide_logo_on_home_page": "Skjul logoet på startsiden", + "account": "Konto", + "align_baseline": "Juster tekstens grundlinje", + "add_discount_code": "Tillad rabatter i indkøbskurv", + "background_overlay": "Baggrundsoverlejring", + "background_media": "Baggrundsmedie", + "border_thickness": "Kanttykkelse", + "bottom_row": "Nederste række", + "button_text_case": "Små og store bogstaver", + "button_text_weight": "Tekstvægt", + "card_size": "Kortstørrelse", + "auto_open_cart_drawer": "“Læg i indkøbskurven” åbner automatisk skuffen", + "collection_count": "Antal i kollektionen", + "collection_title_case": "Store og små bogstaver til kollektionstitel", + "custom_liquid": "Liquid-kode", + "default": "Standard", + "default_logo": "Standardlogo", + "divider_width": "Bredde på skillelinje", + "headings": "Overskrifter", + "horizontal_padding": "Vandret indre margen", + "inverse": "Omvendt", + "inverse_logo": "Omvendt logo", + "layout_style": "Stil", + "length": "Længde", + "mobile_card_size": "Størrelse på mobilkort", + "mobile_pagination": "Sideinddeling for mobil", + "open_row_by_default": "Åbn række som standard", + "page": "Side", + "page_transition_enabled": "Sideovergang", + "product_and_card_title_case": "Store og små bogstaver til produkt- og korttitel", + "product_title_case": "Store og små bogstaver til produkttitel", + "right_padding": "Højre udfyldning", + "search": "Søg", + "search_icon": "Søgeikon", + "search_position": "Placering", + "search_row": "Række", + "show_author": "Forfatter", + "show_alignment": "Vis justering", + "show_count": "Vis antal", + "show_date": "Dato", + "show_pickup_availability": "Vis tilgængelighed for afhentning", + "show_search": "Vis søgning", + "text_label_case": "Store og små bogstaver til tekstlabel", + "use_inverse_logo": "Brug omvendt logo", + "vertical_padding": "Lodret indre margen", + "visibility": "Synlighed", + "product_corner_radius": "Hjørneradius på produkt", + "card_corner_radius": "Hjørneradius på kort", + "alignment_mobile": "Justering for mobil", + "animation_repeat": "Gentag animation", + "blurred_reflection": "Sløret refleksion", + "card_hover_effect": "Kortsvæveeffekt", + "effects": "Effekter", + "inventory_threshold": "Lav grænse for lagerbeholdning", + "reflection_opacity": "Refleksionens uigennemsigtighed", + "show_inventory_quantity": "Vis lav lagermængde", + "transition_to_main_product": "Overgang fra produktkort til produktside", + "show_second_image_on_hover": "Vis sekundært billede, når der peges", + "media": "Medie", + "product_card_carousel": "Vis karrusel", + "media_fit": "Medietilpasning", + "scroll_speed": "Tid til næste meddelelse" + }, + "options": { + "adapt_to_image": "Tilpas til billede", + "apple": "Æble", + "arrow": "Pil", + "auto": "Automatisk", + "banana": "Banan", + "bottle": "Flaske", + "box": "Æske", + "buttons": "Knapper", + "carrot": "Gulerod", + "center": "Centreret", + "chat_bubble": "Chatboble", + "clipboard": "Udklipsholder", + "contain": "Indeholder", + "counter": "Tæller", + "cover": "Cover", + "custom": "Tilpasset", + "dairy_free": "Laktosefri", + "dairy": "Mejeri", + "default": "Standard", + "dropdowns": "Rullemenu", + "dots": "Prikker", + "dryer": "Tørrer", + "end": "Slut", + "eye": "Øje", + "facebook": "Facebook", + "fill": "Udfyld", + "fire": "Ild", + "fit": "Tilpas", + "full": "Udfyldt", + "full_and_page": "Udfyldt baggrund, sidebreddeindhold", + "gluten_free": "Glutenfri", + "heading": "Overskrift", + "heart": "Hjerte", + "horizontal": "Vandret", + "instagram": "Instagram", + "iron": "Jern", + "landscape": "Liggende", + "large": "Stor", + "leaf": "Blad", + "leather": "Læder", + "lg": "L", + "lightning_bolt": "Lyn", + "link": "Link", + "lipstick": "Læbestift", + "lock": "Lås", + "lowercase": "små bogstaver", + "m": "M", + "map_pin": "Kortnål", + "medium": "Medium", + "none": "Ingen", + "numbers": "Tal", + "nut_free": "Nøddefri", + "outline": "Kontur", + "page": "Side", + "pants": "Bukser", + "paw_print": "Poteaftryk", + "pepper": "Peber", + "perfume": "Parfume", + "pinterest": "Pinterest", + "plane": "Fly", + "plant": "Plante", + "portrait": "Stående", + "price_tag": "Prismærke", + "question_mark": "Spørgsmålstegn", + "recycle": "Genanvend", + "return": "Returnering", + "ruler": "Lineal", + "s": "S", + "sentence": "Sætning", + "serving_dish": "Serveringsfad", + "shirt": "Skjorte", + "shoe": "Sko", + "silhouette": "Silhuet", + "small": "Lille", + "snapchat": "Snapchat", + "snowflake": "Snefnug", + "solid": "Udfyldt", + "space_between": "Mellemrum mellem", + "square": "Kvadrat", + "star": "Stjerne", + "start": "Start", + "stopwatch": "Stopur", + "tiktok": "TikTok", + "truck": "Lastbil", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Store bogstaver", + "vertical": "Lodret", + "vimeo": "Vimeo", + "washing": "Vask", + "circle": "Cirkel", + "swatches": "Prøver", + "full_and_page_offset_left": "Udfyldt baggrund, sidebreddeindhold, udligning til venstre", + "full_and_page_offset_right": "Udfyldt baggrund, sidebreddeindhold, udligning til højre", + "offset_left": "Udligning til venstre", + "offset_right": "Udligning til højre", + "page_center_aligned": "Side, centreret", + "page_left_aligned": "Side, venstrejusteret", + "page_right_aligned": "Side, højrejusteret", + "button": "Knap", + "caption": "Billedtekst", + "h1": "Overskrift 1", + "h2": "Overskrift 2", + "h3": "Overskrift 3", + "h4": "Overskrift 4", + "h5": "Overskrift 5", + "h6": "Overskrift 6", + "paragraph": "Afsnit", + "primary": "Primær", + "secondary": "Sekundær", + "tertiary": "Tetiær", + "chevron_left": "Venstre chevron", + "chevron_right": "Højre chevron", + "diamond": "Diamant", + "grid": "Gitter", + "parallelogram": "Parallelogram", + "rounded": "Afrundet", + "fit_content": "Tilpas", + "pills": "Etiketter", + "heavy": "Tyk", + "thin": "Tynd", + "drawer": "Skuffe", + "preview": "Forhåndsvisning", + "text": "Tekst", + "video_uploaded": "Uploadet", + "video_external_url": "Ekstern webadresse", + "aspect_ratio": "Højde-bredde-forhold", + "above_carousel": "Over karrusel", + "all": "Alle", + "always": "Altid", + "arrows_large": "Store pile", + "arrows": "Pile", + "balance": "Saldo", + "bento": "Bento", + "black": "Sort", + "bluesky": "Bluesky", + "body_large": "Brødtekst (stor)", + "body_regular": "Brødtekst (almindelig)", + "body_small": "Brødtekst (lille)", + "bold": "Fed", + "bottom_left": "Nederst til venstre", + "bottom_right": "Nederst til højre", + "bottom": "Nederst", + "capitalize": "Store begyndelsesbogstaver", + "caret": "Cirkumfleks", + "carousel": "Karrusel", + "check_box": "Afkrydsningsfelt", + "chevron_large": "Store vinkeltegn", + "chevron": "Vinkeltegn", + "chevrons": "Vinkeltegn", + "classic": "Klassisk", + "collection_images": "Kollektionsbilleder", + "color": "Farve", + "complementary": "Komplementær", + "dissolve": "Opløs", + "dotted": "Punkteret", + "editorial": "Redaktionel", + "extra_large": "Ekstra stor", + "extra_small": "Ekstra lille", + "featured_collections": "Udvalgte kollektioner", + "featured_products": "Udvalgte produkter", + "font_primary": "Primær", + "font_secondary": "Sekundær", + "font_tertiary": "Tertiær", + "forward": "Fremad", + "full_screen": "Fuld skærm", + "heading_extra_large": "Overskrift (ekstra stor)", + "heading_extra_small": "Overskrift (ekstra lille)", + "heading_large": "Overskrift (stor)", + "heading_regular": "Overskrift (almindelig)", + "heading_small": "Overskrift (lille)", + "icon": "Ikon", + "image": "Billede", + "input": "Input", + "inside_carousel": "I karrusel", + "inverse_large": "Omvendt (stor)", + "inverse": "Omvendt", + "large_arrows": "Store pile", + "large_chevrons": "Store vinkeltegn", + "left": "Venstre", + "light": "Lys", + "linkedin": "LinkedIn", + "loose": "Løs", + "media_first": "Medie først", + "media_second": "Medie anden", + "modal": "Modus", + "narrow": "Smal", + "never": "Aldrig", + "next_to_carousel": "Ud for karrusel", + "normal": "Normal", + "nowrap": "Ingen ombrydning", + "off_media": "Ikke i medier", + "on_media": "I medier", + "on_scroll_up": "Når der rulles opad", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Pille", + "plus": "Plus", + "pretty": "Smuk", + "price": "Pris", + "primary_style": "Primær stil", + "rectangle": "Rektangel", + "regular": "Almindelig", + "related": "Relateret", + "reverse": "Omvendt", + "rich_text": "RTF", + "right": "Højre", + "secondary_style": "Sekundær stil", + "semibold": "Halvfed", + "shaded": "Skygge", + "show_second_image": "Vis andet billede", + "single": "Enkelt", + "slide_left": "Skub til venstre", + "slide_up": "Skub op", + "spotify": "Spotify", + "stack": "Stabel", + "text_only": "Kun tekst", + "threads": "Threads", + "thumbnails": "Miniaturer", + "tight": "Tæt", + "top_left": "Øverst til venstre", + "top_right": "Øverst til højre", + "top": "Øverst", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Understregning", + "video": "Video", + "wide": "Bred", + "youtube": "YouTube", + "down": "Ned", + "fixed": "Fast", + "gradient": "Graduering", + "percent": "Procent", + "pixel": "Pixel", + "up": "Op", + "accent": "Accent", + "below_image": "Under billede", + "body": "Brødtekst", + "button_primary": "Primær knap", + "button_secondary": "Sekundær knap", + "compact": "Kompakt", + "crop_to_fit": "Beskær, så det passer", + "hidden": "Skjult", + "hint": "Tip", + "maintain_aspect_ratio": "Bevar højde-bredde-forholdet", + "off": "Fra", + "on_image": "På billede", + "social_bluesky": "Socialt medie: Bluesky", + "social_facebook": "Socialt medie: Facebook", + "social_instagram": "Socialt medie: Instagram", + "social_linkedin": "Socialt medie: LinkedIn", + "social_pinterest": "Socialt medie: Pinterest", + "social_snapchat": "Socialt medie: Snapchat", + "social_spotify": "Socialt medie: Spotify", + "social_threads": "Socialt medie: Threads", + "social_tiktok": "Socialt medie: TikTok", + "social_tumblr": "Socialt medie: Tumblr", + "social_twitter": "Socialt medie: X (Twitter)", + "social_whatsapp": "Socialt medie: WhatsApp", + "social_vimeo": "Socialt medie: Vimeo", + "social_youtube": "Socialt medie: YouTube", + "spotlight": "Spotlight", + "standard": "Standard", + "subheading": "Underoverskrift", + "blur": "Slør", + "lift": "Løft", + "reveal": "Vis", + "scale": "Skaler", + "subtle_zoom": "Zoom" + }, + "content": { + "advanced": "Avanceret", + "background_image": "Baggrundsbillede", + "background_video": "Baggrundsvideo", + "block_size": "Blokstørrelse", + "borders": "Kanter", + "describe_the_video_for": "Beskriv videoen for kunder med en skærmlæser. [Få mere at vide](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Afsnitsstørrelse", + "slideshow_width": "Diasbredde", + "typography": "Typografi", + "width_is_automatically_optimized": "Bredden er automatisk optimeret til mobiltelefoner.", + "complementary_products": "Supplerende produkter skal konfigureres ved hjælp af Search & Discovery-appen. [Få mere at vide](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Kolonner optimeres automatisk til mobil", + "content_width": "Indholdsbredden gælder kun, når afsnitsbredden er angivet til fuld bredde.", + "adjustments_affect_all_content": "Anvendes på alt indhold i denne blok", + "responsive_font_sizes": "Størrelser skaleres automatisk for alle skærmstørrelser", + "buttons": "Knapper", + "swatches": "Prøver", + "variant_settings": "Variantindstillinger", + "background": "Baggrund", + "appearance": "Udseende", + "arrows": "Pile", + "body_size": "Størrelse på brødtekst", + "bottom_row_appearance": "Udseende af nederste række", + "carousel_navigation": "Navigation i karrusel", + "carousel_pagination": "Sideinddeling i karrusel", + "copyright": "Ophavsret", + "edit_logo_in_theme_settings": "Rediger logo i [temaindstillingerne](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Rediger formatering af priser i [temaindstillingerne](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Rediger variantstilen i [temaindstillingerne](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Tilføjelse af tilmeldinger til [kundeprofiler](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Hvis knappen skal vises, skal Shop-kanalen installeres, og Shop Pay skal aktiveres. [Få mere at vide](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Skrifttyper", + "grid": "Gitter", + "heading_size": "Størrelse på overskrift", + "image": "Billede", + "input": "Input", + "layout": "Layout", + "link": "Link", + "link_padding": "Indre margen for link", + "localization": "Tilpasning til lokale forhold", + "logo": "Logo", + "margin": "Margen", + "media": "Medier", + "media_1": "Medie 1", + "media_2": "Medie 2", + "menu": "Menu", + "mobile_layout": "Mobillayout", + "padding": "Indre margen", + "padding_desktop": "Indre margen på computer", + "paragraph": "Afsnit", + "policies": "Politikker", + "popup": "Pop op-vindue", + "search": "Søg", + "size": "Størrelse", + "social_media": "Sociale medier", + "submit_button": "Send-knap", + "text_presets": "Forudindstillede tekster", + "transparent_background": "Gennemsigtig baggrund", + "typography_primary": "Primær typografi", + "typography_secondary": "Sekundær typografi", + "typography_tertiary": "Tertiær typografi", + "mobile_size": "Størrelse på mobil", + "cards_layout": "Kortlayout", + "mobile_width": "Bredde på mobil", + "section_layout": "Afsnitslayout", + "width": "Bredde", + "visibility": "Synlighed", + "visible_if_collection_has_more_products": "Synlig, hvis en kollektion har flere produkter end vist", + "carousel": "Karrusel", + "colors": "Farver", + "collection_page": "Kollektionsside", + "copyright_info": "Se, hvordan du [redigerer din ophavsretserklæring](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Kundekonto", + "edit_empty_state_collection_in_theme_settings": "Rediger kollektion i tom tilstand i [temaindstillingerne](/editor?context=theme&category=search)", + "grid_layout": "Gitterlayout", + "home_page": "Startside", + "images": "Billeder", + "inverse_logo_info": "Bruges, når gennemsigtig baggrund for sidehoved er angivet til Omvendt", + "manage_customer_accounts": "[Administrer synlighed](/admin/settings/customer_accounts) i indstillingerne for kundekonto. Gamle konti understøttes ikke.", + "manage_policies": "[Administrer politikker](/admin/settings/legal)", + "product_page": "Produktside", + "text": "Tekst", + "thumbnails": "Miniaturer", + "app_required_for_ratings": "Der kræves en app til produktbedømmelser. [Få mere at vide](https://help.shopify.com/manual/apps)", + "icon": "Ikon", + "manage_store_name": "[Administrer butiksnavn](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Viser kollektion fra overordnet afsnit", + "resource_reference_collection_card_image": "Viser billede fra overordnet kollektion", + "resource_reference_collection_title": "Viser titel fra overordnet kollektion", + "resource_reference_product": "Forbindes automatisk til overordnet produkt", + "resource_reference_product_card": "Viser produkt fra overordnet afsnit", + "resource_reference_product_inventory": "Viser lagerbeholdning fra overordnet produkt", + "resource_reference_product_price": "Viser pris fra overordnet produkt", + "resource_reference_product_recommendations": "Viser anbefalinger baseret på overordnet produkt", + "resource_reference_product_review": "Viser anmeldelser fra overordnet produkt", + "resource_reference_product_swatches": "Viser prøver fra overordnet produkt", + "resource_reference_product_title": "Viser titel fra overordnet produkt", + "resource_reference_product_variant_picker": "Viser varianter fra overordnet produkt", + "resource_reference_product_media": "Viser medie fra overordnet produkt", + "product_media": "Produktmedier", + "section_link": "Afsnitslink" + }, + "html_defaults": { + "share_information_about_your": "

Del oplysninger om dit brand med dine kunder. Beskriv et produkt, del meddelelser, eller byd velkommen til din butik.

" + }, + "text_defaults": { + "button_label": "Køb nu", + "collapsible_row": "Række, der kan skjules", + "heading": "Overskrift", + "email_signup_button_label": "Abonner", + "accordion_heading": "Overskrift til karrusel", + "contact_form_button_label": "Send", + "popup_link": "Link til pop op-vindue", + "sign_up": "Tilmeld dig", + "welcome_to_our_store": "Velkommen til vores butik", + "be_bold": "Vær modig.", + "shop_our_latest_arrivals": "Køb vores nyheder!" + }, + "info": { + "carousel_layout_on_mobile": "Karrusel anvendes på mobil", + "link_info": "Valgfrit: gør det muligt at klikke på ikon", + "video_alt_text": "Beskriv videoen for brugere med tekniske hjælpemidler", + "video_autoplay": "Lyden i videoer er som standard slået fra", + "video_external": "Brug en YouTube- eller Vimeo-webadresse", + "carousel_hover_behavior_not_supported": "Det understøttes ikke at holde musen over “Karrusel”, når typen “Karrusel” er valgt på afsnitsniveau", + "checkout_buttons": "Tillader, at købere kan betale hurtigere, hvilket kan forbedre konverteringen. [Få mere at vide](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Tilpasset overskrift", + "edit_presets_in_theme_settings": "Rediger forudindstillinger i [temaindstillingerne](/editor?context=theme&category=typography)", + "enable_filtering_info": "Tilpas filtre med [Search & Discovery-appen](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Gitterlayout bruges på mobil", + "manage_countries_regions": "[Administrer lande/områder](/admin/settings/markets)", + "manage_languages": "[Administrer sprog](/admin/settings/languages)", + "transparent_background": "Gennemgå hver skabelon, hvor der er anvendt gennemsigtig baggrund af hensyn til læsbarheden", + "logo_font": "Gælder kun, når der ikke er valgt et logo", + "aspect_ratio_adjusted": "Justeret i nogle layouts", + "auto_open_cart_drawer": "Når indkøbskurvskuffen er aktiveret, åbner den automatisk, når der lægges et produkt i indkøbskurven.", + "custom_liquid": "Tilføj appkodestykker eller anden kode for at oprette avancerede tilpasninger. [Få mere at vide](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Bruges til anvendte filtre, rabatkoder og søgeforslag", + "applies_on_image_only": "Gælder kun for billeder", + "hover_effects": "Gælder for produkter og kollektionskort" + }, + "categories": { + "basic": "Basic", + "collection": "Kollektion", + "collection_list": "Kollektionsliste", + "footer": "Sidefod", + "forms": "Formularer", + "header": "Sidehoved", + "layout": "Layout", + "links": "Links", + "product": "Produkt", + "product_list": "Fremhævet kollektion", + "banners": "Bannere", + "collections": "Kollektioner", + "custom": "Tilpasset", + "decorative": "Dekorativ", + "products": "Produkter", + "other_sections": "Andet", + "storytelling": "Storytelling" + } +} diff --git a/locales/de.json b/locales/de.json new file mode 100644 index 000000000..052111fa2 --- /dev/null +++ b/locales/de.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Video laden: {{ description }}", + "sold_out": "Ausverkauft", + "email_signup": { + "label": "E-Mail", + "placeholder": "E-Mail-Adresse", + "success": "Danke für deine Anmeldung!" + }, + "filter": "Filtern", + "payment_methods": "Zahlungsmethoden", + "contact_form": { + "name": "Name", + "email": "E-Mail-Adresse", + "phone": "Telefonnummer", + "comment": "Kommentar", + "post_success": "Danke, dass du uns kontaktiert hast. Wir werden uns so schnell wie möglich bei dir melden.", + "error_heading": "Bitte passe Folgendes an:" + } + }, + "accessibility": { + "play_model": "3D-Modell abspielen", + "play_video": "Video abspielen", + "unit_price": "Grundpreis", + "country_results_count": "{{ count }} Ergebnisse", + "slideshow_pause": "Slideshow pausieren", + "slideshow_play": "Slideshow abspielen", + "remove_item": "Entferne {{ title}}", + "skip_to_text": "Direkt zum Inhalt", + "skip_to_product_info": "Zu Produktinformationen springen", + "skip_to_results_list": "Zur Ergebnisliste springen", + "new_window": "Wird in einem neuen Fenster geöffnet.", + "slideshow_next": "Nächste Folie", + "slideshow_previous": "Vorherige Folie", + "close_dialog": "Dialogfeld schließen", + "reset_search": "Suche zurücksetzen", + "search_results_count": "{{ count }} Suchergebnisse für „{{ query }}“ gefunden", + "search_results_no_results": "Keine Ergebnisse für „{{ query }}“ gefunden", + "filters": "Filter", + "account": "Kontomenü öffnen", + "cart": "Warenkorb", + "cart_count": "Artikel im Warenkorb insgesamt", + "filter_count": { + "one": "{{ count }} Filter angewandt", + "other": "{{ count }} Filter angewandt" + }, + "menu": "Menü", + "country_region": "Land/Region", + "slide_status": "Folie {{ index }} von {{ length }}", + "scroll_to": "Zu {{ title }} scrollen", + "discount": "Rabattcode anwenden", + "loading_product_recommendations": "Produktempfehlungen werden geladen", + "discount_applied": "Angewendeter Rabattcode: {{ code }}", + "open_cart_drawer": "Warenkorb öffnen", + "inventory_status": "Inventarstatus", + "pause_video": "Video pausieren", + "find_country": "Land finden", + "localization_region_and_language": "Region- und Sprachauswahl öffnen", + "open_search_modal": "Suche öffnen", + "decrease_quantity": "Menge verringern", + "increase_quantity": "Menge erhöhen", + "quantity": "Anzahl", + "rating": "Die Bewertung für dieses Produkts lautet {{ rating }} von 5 Sternen", + "nested_product": "{{ product_title }} für {{ parent_title }}" + }, + "actions": { + "add_to_cart": "In den Warenkorb legen", + "clear_all": "Alles löschen", + "remove": "Entfernen", + "view_in_your_space": "In deinem Bereich anzeigen", + "show_filters": "Filtern", + "clear": "Löschen", + "continue_shopping": "Weiter einkaufen", + "log_in_html": "Hast du ein Konto? Logge dich ein, damit es beim Checkout schneller geht.", + "see_items": { + "one": "{{ count }} Artikel anzeigen", + "other": "{{ count }} Artikel anzeigen" + }, + "view_all": "Alle anzeigen", + "add": "Hinzufügen", + "choose": "Auswählen", + "added": "Hinzugefügt", + "show_less": "Weniger anzeigen", + "show_more": "Mehr anzeigen", + "close": "Schließen", + "more": "Mehr", + "reset": "Zurücksetzen", + "zoom": "Zoomen", + "close_dialog": "Dialogfeld schließen", + "back": "Zurück", + "log_in": "Anmelden", + "log_out": "Abmelden", + "remove_discount": "Rabatt {{ code }} entfernen", + "enter_using_password": "Mit Passwort anmelden", + "submit": "Senden", + "enter_password": "Passwort eingeben", + "view_store_information": "Shop-Informationen anzeigen", + "apply": "Anwenden", + "sign_in_options": "Andere Anmeldeoptionen", + "sign_up": "Registrieren", + "open_image_in_full_screen": "Bild im Vollbildmodus öffnen", + "sort": "Sortieren", + "show_all_options": "Alle Optionen anzeigen" + }, + "content": { + "reviews": "Reviews", + "language": "Sprache", + "localization_region_and_language": "Region und Sprache", + "no_results_found": "Keine Ergebnisse gefunden", + "cart_total": "Gesamtbetrag im Warenkorb", + "your_cart_is_empty": "Dein Warenkorb ist leer", + "product_image": "Produktbild", + "product_information": "Produktinformationen", + "quantity": "Anzahl", + "product_total": "Produkt insgesamt", + "cart_estimated_total": "Geschätzter Gesamtbetrag", + "seller_note": "Besondere Anweisungen", + "cart_subtotal": "Zwischensumme", + "discounts": "Rabatte", + "discount": "Rabatt", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Inkl. Zollgebühren und Steuern. Rabatte und Versand werden beim Checkout berechnet.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Inkl. Zollgebühren und Steuern. Rabatte und Versand werden beim Checkout berechnet.", + "taxes_included_shipping_at_checkout_with_policy_html": "Inkl. Steuern. Rabatte und Versand werden beim Checkout berechnet.", + "taxes_included_shipping_at_checkout_without_policy": "Inkl. Steuern. Rabatte und Versand werden beim Checkout berechnet.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Inkl. Zollgebühren. Steuern, Rabatte und Versand werden beim Checkout berechnet.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Inkl. Zollgebühren. Steuern, Rabatte und Versand werden beim Checkout berechnet.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Steuern, Rabatte und Versand werden beim Checkout berechnet.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Steuern, Rabatte und Versand werden beim Checkout berechnet.", + "checkout": "Auschecken", + "cart_title": "Warenkorb", + "price": "Preis", + "price_regular": "Normaler Preis", + "price_compare_at": "Vergleichspreis", + "price_sale": "Angebotspreis", + "duties_and_taxes_included": "Inkl. Zollgebühren und Steuern.", + "duties_included": "Inkl. Zollgebühren.", + "shipping_policy_html": "Versand wird beim Checkout berechnet.", + "taxes_included": "Inkl. Steuern.", + "product_badge_sold_out": "Ausverkauft", + "product_badge_sale": "Sale", + "search_input_label": "Suchen", + "search_input_placeholder": "Suchen", + "search_results": "Suchergebnisse", + "search_results_label": "Suchergebnisse", + "search_results_no_results": "Keine Ergebnisse für „{{ terms }}“ gefunden. Versuche es mit einem anderen Suchbegriff.", + "search_results_resource_articles": "Blog-Beiträge", + "search_results_resource_collections": "Kollektionen", + "search_results_resource_pages": "Seiten", + "search_results_resource_products": "Produkte", + "search_results_resource_queries": "Suchvorschläge", + "search_results_view_all": "Alle anzeigen", + "search_results_view_all_button": "Alle anzeigen", + "search_results_resource_products_count": { + "one": "{{ count }} Produkt", + "other": "{{ count }} Produkte" + }, + "grid_view": { + "default_view": "Standard", + "grid_fieldset": "Spaltenraster", + "single_item": "Einzeln", + "zoom_out": "Herauszoomen" + }, + "recently_viewed_products": "Zuletzt angesehen", + "unavailable": "Nicht verfügbar", + "collection_placeholder": "Kollektionstitel", + "product_card_placeholder": "Produkttitel", + "product_count": "Produktanzahl", + "item_count": { + "one": "{{ count }} Artikel", + "other": "{{ count }} Artikel" + }, + "errors": "Fehler", + "price_from": "Ab {{ price }}", + "search": "Suche", + "search_results_no_results_check_spelling": "Keine Ergebnisse für „{{ terms }}“ gefunden. Überprüfe die Schreibweise oder versuche es mit einer anderen Suchanfrage.", + "featured_products": "Vorgestellte Produkte", + "filters": "Filter", + "no_products_found": "Keine Produkte gefunden.", + "price_filter_html": "Der höchste Preis ist {{ price }}", + "use_fewer_filters_html": "Versuche, weniger Filter zu verwenden oder alle Filter zu löschen.", + "account_title": "Konto", + "account_title_personalized": "Hallo {{ first_name }}", + "account_orders": "Bestellungen", + "account_profile": "Profil", + "blog_details_separator": "|", + "discount_code": "Rabattcode", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Inkl. Zollgebühren und Steuern. Versand wird beim Checkout berechnet.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Inkl. Zollgebühren und Steuern. Versand wird beim Checkout berechnet.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Inkl. Zollgebühren. Versand wird beim Checkout berechnet.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Inkl. Zollgebühren. Versand wird beim Checkout berechnet.", + "pickup_available_at_html": "Abholung bei {{ location }} verfügbar", + "pickup_available_in": "Abholung verfügbar, {{ pickup_time }}", + "pickup_not_available": "Abholung derzeit nicht verfügbar", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Mehr lesen …", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Steuern und Versand werden beim Checkout berechnet.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Steuern und Versand werden beim Checkout berechnet.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Inkl. Steuern. Versand wird beim Checkout berechnet.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Inkl. Steuern. Versand wird beim Checkout berechnet.", + "wrong_password": "Falsches Passwort", + "view_more_details": "Weitere Details anzeigen", + "inventory_low_stock": "Niedriger Lagerbestand", + "inventory_in_stock": "Auf Lager", + "inventory_out_of_stock": "Nicht vorrätig", + "page_placeholder_title": "Seitentitel", + "page_placeholder_content": "Wähle eine Seite aus, die angezeigt werden soll.", + "placeholder_image": "Platzhalterbild", + "shipping_policy": "Versandkosten werden beim Checkout berechnet.", + "inventory_low_stock_show_count": { + "one": "{{ count }} übrig", + "other": "{{ count }} übrig" + }, + "powered_by": "Dieser Shop wird unterstützt werden von", + "store_owner_link_html": "Bist du der Shop-Inhaber? Hier einloggen", + "shipping_discount_error": "Versandrabatte werden beim Checkout angezeigt, nachdem die Adresse hinzugefügt wurde", + "discount_code_error": "Rabattcode kann nicht auf den Warenkorb angewendet werden" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Verwende diesen Geschenkgutscheincode online oder verwende den QR-Code im Shop", + "title": "Hier ist dein {{ value }}-Gutschein für {{ shop }}!", + "subtext": "Dein Gutschein", + "shop_link": "Onlineshop besuchen", + "add_to_apple_wallet": "Zu Apple Wallet hinzufügen", + "qr_image_alt": "QR-Code – Scannen, um Gutschein einzulösen", + "copy_code": "Geschenkgutscheincode kopieren", + "expiration_date": "Gültig bis {{ expires_on }}", + "copy_code_success": "Code erfolgreich kopiert", + "expired": "Abgelaufen" + } + }, + "placeholders": { + "password": "Passwort", + "search": "Suchen", + "product_title": "Produkttitel", + "collection_title": "Kollektionstitel" + }, + "products": { + "product": { + "add_to_cart": "In den Warenkorb legen", + "added_to_cart": "Zum Warenkorb hinzugefügt", + "adding_to_cart": "Wird hinzugefügt...", + "add_to_cart_error": "Fehler beim Hinzufügen zum Warenkorb", + "sold_out": "Ausverkauft", + "unavailable": "Nicht verfügbar" + } + }, + "fields": { + "separator": "bis" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} Kommentar", + "other": "{{ count }} Kommentare" + } + }, + "comment_form": { + "email": "E-Mail", + "error": "Kommentar konnte nicht gepostet werden. Bitte beachte Folgendes:", + "heading": "Hinterlasse einen Kommentar", + "message": "Nachricht", + "moderated": "Bitte beachte, dass Kommentare vor der Veröffentlichung freigegeben werden müssen.", + "name": "Name", + "post": "Kommentar posten", + "success_moderated": "Kommentar gepostet, Moderation ausstehend", + "success": "Kommentar gepostet" + } + } +} diff --git a/locales/de.schema.json b/locales/de.schema.json new file mode 100644 index 000000000..a8b1dc0c7 --- /dev/null +++ b/locales/de.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Ränder", + "collapsible_row": "Einklappbare Reihe", + "custom_section": "Benutzerdefinierter Abschnitt", + "icon": "Symbol", + "logo_and_favicon": "Logo und Favicon", + "product_buy_buttons": "Kaufschaltflächen", + "product_description": "Beschreibung", + "product_price": "Preis", + "slideshow": "Slideshow", + "typography": "Typografie", + "video": "Video", + "colors": "Farben", + "overlapping_blocks": "Überlappende Blöcke", + "product_variant_picker": "Variantenauswahl", + "slideshow_controls": "Slideshow-Steuerelemente", + "size": "Größe", + "spacing": "Abstand", + "product_recommendations": "Empfohlene Produkte", + "product_media": "Produktmedien", + "featured_collection": "Vorgestellte Kollektion", + "add_to_cart": "In den Warenkorb legen", + "email_signup": "E-Mail-Anmeldung", + "submit_button": "Schaltfläche „Senden“", + "grid_layout_selector": "Raster-Layout-Auswahl", + "image": "Bild", + "list_items": "Listenelemente", + "facets": "Filter", + "variants": "Varianten", + "styles": "Stile", + "product_cards": "Produktkarten", + "buttons": "Schaltflächen", + "inputs": "Eingaben", + "primary_button": "Primäre Schaltfläche", + "secondary_button": "Sekundäre Schaltfläche", + "popovers": "Pop-overs", + "marquee": "Marquee", + "products_carousel": "Vorgestellte Kollektion: Karussell", + "products_grid": "Vorgestellte Kollektion: Raster", + "pull_quote": "Zitat", + "contact_form": "Kontaktformular", + "featured_product": "Produkthighlight", + "icons_with_text": "Symbole mit Text", + "alternating_content_rows": "Abwechselnde Zeilen", + "accelerated_checkout": "Beschleunigter Checkout", + "accordion": "Akkordeon", + "accordion_row": "Akkordeon-Zeile", + "animations": "Animationen", + "announcement": "Ankündigung", + "announcement_bar": "Ankündigungsleiste", + "badges": "Badges", + "button": "Schaltfläche", + "cart": "Warenkorb", + "cart_items": "Artikel im Warenkorb", + "cart_products": "Produkte im Warenkorb", + "cart_title": "Warenkorb", + "collection": "Kollektion", + "collection_card": "Kollektionskarte", + "collection_columns": "Kollektionsspalten", + "collection_container": "Kollektion", + "collection_description": "Kollektionsbeschreibung", + "collection_image": "Kollektionsbild", + "collection_info": "Kollektionsinformationen", + "collection_list": "Kollektionsliste", + "collections": "Kollektionen", + "collections_bento": "Kollektionsliste: Bento", + "collections_carousel": "Kollektionsliste: Karussell", + "collections_grid": "Kollektionsliste: Raster", + "content": "Inhalt", + "content_grid": "Inhaltsraster", + "details": "Details", + "divider": "Trennlinie", + "divider_section": "Trennlinie", + "faq_section": "FAQ", + "filters": "Filtern und Sortieren", + "follow_on_shop": "In Shop folgen", + "footer": "Fußzeile", + "footer_utilities": "Tools für Fußzeile", + "group": "Gruppe", + "header": "Header", + "heading": "Überschrift", + "hero": "Hero-Bild", + "icons": "Symbole", + "image_with_text": "Bild mit Text", + "input": "Eingabe", + "logo": "Logo", + "magazine_grid": "Magazinraster", + "media": "Medien", + "menu": "Menü", + "mobile_layout": "Mobiles Layout", + "payment_icons": "Zahlungssymbole", + "popup_link": "Pop-up-Link", + "predictive_search": "Popover suchen", + "predictive_search_empty": "Vorausschauende Suche leer", + "price": "Preis", + "product": "Produkt", + "product_card": "Produktkarte", + "product_card_media": "Medien", + "product_card_rendering": "Rendering der Produktkarten", + "product_grid": "Raster", + "product_grid_main": "Produktraster", + "product_image": "Produktbild", + "product_information": "Produktinformationen", + "product_review_stars": "Bewertungssterne", + "quantity": "Anzahl", + "row": "Zeile", + "search": "Suche", + "section": "Abschnitt", + "selected_variants": "Ausgewählte Varianten", + "shop_the_look": "Look kaufen", + "slide": "Folie", + "social_media_links": "Social-Media-Links", + "steps": "Schritte", + "summary": "Übersicht", + "swatches": "Farbfelder", + "testimonials": "Erfahrungsberichte", + "text": "Text", + "title": "Titel", + "utilities": "Hilfsprogramme", + "video_section": "Video", + "spacer": "Abstandhalter", + "product_list": "Vorgestellte Kollektion", + "jumbo_text": "Text im Großformat", + "search_input": "Sucheingabe", + "search_results": "Suchergebnisse", + "read_only": "Schreibgeschützt", + "collection_title": "Kollektionstitel", + "view_all_button": "Alle anzeigen", + "custom_liquid": "Benutzerdefiniertes Liquid", + "blog": "Blog", + "blog_post": "Blog-Beitrag", + "blog_posts": "Blog-Beiträge", + "caption": "Bildtext", + "collection_card_image": "Bild", + "collection_links": "Kollektions-Links", + "collection_links_spotlight": "Kollektionslinks: Spotlight", + "collection_links_text": "Kollektionslinks: Text", + "collections_editorial": "Kollektionsliste: Editorial", + "copyright": "Urheberrecht", + "count": "Anzahl", + "drawers": "Einschübe", + "editorial": "Editorial", + "editorial_jumbo_text": "Editorial: Text im Großformat", + "hero_marquee": "Hero: Marquee", + "input_fields": "Eingabefelder", + "local_pickup": "Lokale Abholung", + "marquee_section": "Marquee", + "media_with_text": "Medien mit Text", + "page": "Seite", + "page_content": "Inhalt", + "page_layout": "Seitenlayout", + "policy_list": "Links zu Richtlinien", + "prices": "Preise", + "products_editorial": "Vorgestellte Kollektion: Redaktionell", + "social_link": "Social-Media-Link", + "split_showcase": "Split Showcase", + "variant_pickers": "Variantenauswahl", + "product_title": "Produkttitel", + "large_logo": "Großes Logo", + "product_list_button": "Schaltfläche „Alle anzeigen“", + "product_inventory": "Produktinventar", + "pills": "Kapseln", + "description": "Beschreibung" + }, + "settings": { + "autoplay": "Automatische Wiedergabe", + "background": "Hintergrund", + "border_radius": "Eckradius", + "border_width": "Randdicke", + "borders": "Ränder", + "bottom_padding": "Unteres Padding", + "color": "Farbe", + "content_direction": "Inhaltsrichtung", + "content_position": "Inhaltsposition", + "cover_image_size": "Größe des Titelbilds", + "cover_image": "Titelbild", + "custom_width": "Benutzerdefinierte Breite", + "enable_video_looping": "Videoschleife", + "favicon": "Favicon", + "heading": "Titel", + "icon": "Symbol", + "image_icon": "Bildsymbol", + "make_section_full_width": "Abschnitt über die gesamte Breite", + "overlay_opacity": "Überlagerungsdeckkraft", + "padding": "Padding", + "product": "Produkt", + "text": "Text", + "top_padding": "Oberes Padding", + "video": "Video", + "video_alt_text": "Alt-Text", + "video_loop": "Video in Dauerschleife", + "video_position": "Videoposition", + "width": "Breite", + "alignment": "Ausrichtung", + "button": "Schaltfläche", + "colors": "Farben", + "content_alignment": "Inhaltsausrichtung", + "custom_minimum_height": "Benutzerdefinierte Mindesthöhe", + "font_family": "Schriftartfamilie", + "gap": "Abstand", + "geometric_translate_y": "Geometric translate Y", + "image": "Bild", + "image_opacity": "Deckkraft des Bilds", + "image_position": "Bildposition", + "image_ratio": "Bildverhältnis", + "label": "Beschriftung", + "line_height": "Zeilenhöhe", + "link": "Link", + "layout_gap": "Lücke im Layout", + "minimum_height": "Mindesthöhe", + "opacity": "Opazität", + "primary_color": "Links", + "section_width": "Abschnittsbreite", + "size": "Größe", + "slide_spacing": "Lücke in der Folie", + "slide_width": "Folienbreite", + "slideshow_fullwidth": "Folien in voller Breite", + "style": "Optik", + "text_case": "Fall", + "z_index": "z-index", + "limit_content_width": "Begrenzte Inhaltsbreite", + "color_scheme": "Farbschema", + "inherit_color_scheme": "Farbschema übernehmen", + "product_count": "Produktanzahl", + "product_type": "Produkttyp", + "content_width": "Inhaltsbreite", + "collection": "Kollektion", + "enable_sticky_content": "Fixierte Inhalte für Desktop", + "error_color": "Fehler", + "success_color": "Erfolg", + "primary_font": "Primäre Schriftart", + "secondary_font": "Sekundäre Schriftart", + "tertiary_font": "Tertiäre Schriftart", + "columns": "Spalten", + "items_to_show": "Anzuzeigende Elemente", + "layout": "Layout", + "layout_type": "Art", + "show_grid_layout_selector": "Raster-Layout-Auswahl anzeigen", + "view_more_show": "\"Mehr anzeigen\"-Schaltfläche anzeigen", + "image_gap": "Bildabstand", + "width_desktop": "Breite bei Desktop-Ansicht", + "width_mobile": "Breite bei mobiler Ansicht", + "border_style": "Stil für Rand", + "height": "Höhe", + "thickness": "Dicke", + "stroke": "Strich", + "filter_style": "Filterstil", + "swatches": "Farbfelder", + "quick_add_colors": "Farben schnell hinzufügen", + "divider_color": "Trennlinie", + "border_opacity": "Deckkraft des Rands", + "hover_background": "Hover-Hintergrund", + "hover_borders": "Hover-Grenzen", + "hover_text": "Hover-Text", + "primary_hover_color": "Hover-Links", + "primary_button_text": "Text für primäre Schaltfläche", + "primary_button_background": "Hintergrund für primäre Schaltfläche", + "primary_button_border": "Grenze für primäre Schaltfläche", + "secondary_button_text": "Text für sekundäre Schaltfläche", + "secondary_button_background": "Hintergrund für sekundäre Schaltfläche", + "secondary_button_border": "Grenze für sekundäre Schaltfläche", + "shadow_color": "Schatten", + "mobile_logo_image": "Mobiles Logo", + "video_autoplay": "Automatische Wiedergabe", + "video_cover_image": "Titelbild", + "video_external_url": "URL", + "video_source": "Quelle", + "card_image_height": "Produktbildhöhe", + "first_row_media_position": "Erste Zeile Medienposition", + "accordion": "Akkordeon", + "aspect_ratio": "Seitenverhältnis", + "auto_rotate_announcements": "Autorotieren der Ankündigungen", + "auto_rotate_slides": "Autorotieren der Slides", + "badge_corner_radius": "Eckradius", + "badge_position": "Position auf Karten", + "badge_sale_color_scheme": "Sale", + "badge_sold_out_color_scheme": "Ausverkauft", + "behavior": "Verhalten", + "blur": "Schatten-Weichzeichnung", + "border": "Rand", + "bottom": "Unten", + "carousel_on_mobile": "Karussell in mobiler Ansicht", + "cart_count": "Anzahl im Warenkorb", + "cart_items": "Artikel im Warenkorb", + "cart_related_products": "Ähnliche Produkte", + "cart_title": "Warenkorb", + "cart_total": "Gesamtbetrag im Warenkorb", + "cart_type": "Art", + "case": "Fall", + "checkout_buttons": "Schaltflächen für beschleunigten Checkout", + "collection_list": "Kollektionen", + "collection_templates": "Kollektionsvorlagen", + "content": "Inhalt", + "corner_radius": "Eckradius", + "country_region": "Land/Region", + "currency_code": "Währungscode", + "custom_height": "Benutzerdefinierte Höhe", + "desktop_height": "Desktop-Höhe", + "direction": "Richtung", + "display": "Anzeige", + "divider_thickness": "Dicke der Trennlinie", + "divider": "Trennlinie", + "dividers": "Trennlinien", + "drop_shadow": "Schlagschatten", + "empty_state_collection_info": "Wird vor der Eingabe einer Suche angezeigt", + "empty_state_collection": "Kollektion mit Status „Leer“", + "enable_filtering": "Filter", + "enable_grid_density": "Steuerung des Raster-Layouts", + "enable_sorting": "Sortierung", + "enable_zoom": "Zoom aktivieren", + "equal_columns": "Gleiche Spalten", + "expand_first_group": "Erste Gruppe erweitern", + "extend_media_to_screen_edge": "Medien bis zum Bildschirmrand erweitern", + "extend_summary": "Bis zum Bildschirmrand erweitern", + "extra_large": "Extra groß", + "extra_small": "Extra klein", + "flag": "Markierung", + "font_price": "Schriftart für Preis", + "font_weight": "Schriftstärke", + "font": "Schriftart", + "full_width_first_image": "Erstes Bild in voller Breite", + "full_width_on_mobile": "Volle Breite in mobiler Ansicht", + "heading_preset": "Überschrift (Voreinstellung)", + "hide_unselected_variant_media": "Medien für nicht ausgewählte Variante ausblenden", + "horizontal_gap": "Horizontale Lücke", + "horizontal_offset": "Horizontaler Offset für Schatten", + "hover_behavior": "Hover-Verhalten", + "icon_background": "Symbol-Hintergrund", + "icons": "Symbole", + "image_border_radius": "Eckradius von Bild", + "installments": "Raten", + "integrated_button": "Integrierte Schaltfläche", + "language_selector": "Sprachauswahl", + "large": "Groß", + "left_padding": "Padding links", + "left": "Links", + "letter_spacing": "Buchstabenabstand", + "limit_media_to_screen_height": "Auf Bildschirmhöhe beschränken", + "limit_product_details_width": "Breite der Produktdetails beschränken", + "link_preset": "Link-Voreinstellung", + "links": "Links", + "logo": "Logo", + "loop": "Schleife", + "make_details_sticky_desktop": "Bei Desktop fixiert", + "max_width": "Maximale Breite", + "media_height": "Medienhöhe", + "media_overlay": "Medienüberlagerung", + "media_position": "Medienposition", + "media_type": "Medientyp", + "media_width": "Medienbreite", + "menu": "Menü", + "mobile_columns": "Spalten für mobile Ansicht", + "mobile_height": "Höhe für mobile Ansicht", + "mobile_quick_add": "Schnelles Hinzufügen für mobile Ansicht", + "motion_direction": "Bewegungsrichtung", + "motion": "Bewegung", + "movement_direction": "Bewegungsrichtung", + "navigation_bar_color_scheme": "Farbschema für Navigationsleiste", + "navigation_bar": "Navigationsleiste", + "navigation": "Navigation", + "open_new_tab": "Link in neuem Tab öffnen", + "overlay_color": "Überlagerungsfarbe", + "overlay": "Überlagerung", + "padding_bottom": "Padding unten", + "padding_horizontal": "Padding horizontal", + "padding_top": "Padding oben", + "page_width": "Seitenbreite", + "pagination": "Seitennummerierung", + "placement": "Platzierung", + "position": "Position", + "preset": "Voreinstellung", + "product_cards": "Produktkarten", + "product_pages": "Produktseiten", + "product_templates": "Produktvorlagen", + "products": "Produkte", + "quick_add": "Schnelles Hinzufügen", + "ratio": "Verhältnis", + "regular": "Regulär", + "review_count": "Anzahl überprüfen", + "right": "Rechts", + "row_height": "Zeilenhöhe", + "row": "Zeile", + "seller_note": "Notiz für Verkäufer zulassen", + "shape": "Form", + "show_as_accordion": "Als Akkordeon in mobiler Ansicht anzeigen", + "show_sale_price_first": "Verkaufspreis zuerst anzeigen", + "show_tax_info": "Steuerinformationen", + "show": "Anzeigen", + "small": "Klein", + "speed": "Geschwindigkeit", + "statement": "Aussage", + "sticky_header": "Fixierter Header", + "text_hierarchy": "Texthierarchie", + "text_presets": "Textvoreinstellungen", + "title": "Titel", + "top": "Oben", + "type_preset": "Textvoreinstellung", + "type": "Art", + "underline_thickness": "Unterstreichungsstärke", + "variant_images": "Variantenbilder", + "vendor": "Anbieter", + "vertical_gap": "Vertikale Lücke", + "vertical_offset": "Vertikaler Offset für Schatten", + "vertical_on_mobile": "Vertikal in mobiler Ansicht", + "view_all_as_last_card": "„Alle anzeigen“ als letzte Karte", + "weight": "Gewicht", + "wrap": "Textumbruch", + "logo_font": "Schriftart für Logo", + "background_color": "Hintergrundfarbe", + "size_mobile": "Mobile Größe", + "pixel_size_mobile": "Größe in Pixel", + "percent_size_mobile": "Größe in Prozent", + "unit": "Einheit", + "custom_mobile_size": "Benutzerdefinierte mobile Größe", + "fixed_height": "Höhe in Pixeln", + "fixed_width": "Breite in Pixeln", + "percent_height": "Höhe in Prozent", + "percent_width": "Breite in Prozent", + "percent_size": "Größe in Prozent", + "pixel_size": "Größe in Pixel", + "hide_padding": "Padding ausblenden", + "always_stack_buttons": "Schaltflächen immer stapeln", + "custom_mobile_width": "Benutzerdefinierte mobile Breite", + "shadow_opacity": "Deckkraft des Schattens", + "show_filter_label": "Beschriftungen für angewandte Filter", + "show_swatch_label": "Beschriftungen für Farbfelder", + "transparent_background": "Transparenter Hintergrund", + "read_only": "Schreibgeschützt", + "gradient_direction": "Richtung Farbverlauf", + "headings": "Überschriften", + "overlay_style": "Überlagerungsstil", + "account": "Konto", + "align_baseline": "Text-Baseline ausrichten", + "add_discount_code": "Rabatte im Warenkorb erlauben", + "background_overlay": "Hintergrund-Überlagerung", + "background_media": "Medien im Hintergrund", + "border_thickness": "Randdicke", + "bottom_row": "Unterste Zeile", + "button_text_case": "Groß- oder Kleinschreibung", + "button_text_weight": "Schriftstärke", + "auto_open_cart_drawer": "Die Aktion „In den Warenkorb legen“ öffnet automatisch den Einschub", + "collection_count": "Anzahl der Kollektionen", + "custom_liquid": "Liquid-Code", + "default": "Standard", + "default_logo": "Standard-Logo", + "divider_width": "Breite der Trennlinie", + "hide_logo_on_home_page": "Logo auf der Startseite ausblenden", + "horizontal_padding": "Horizontales Padding", + "inverse": "Invertiert", + "inverse_logo": "Invertiertes Logo", + "layout_style": "Optik", + "length": "Länge", + "mobile_pagination": "Mobile Seitennummerierung", + "open_row_by_default": "Reihe standardmäßig öffnen", + "page_transition_enabled": "Seitenübergang", + "search": "Suche", + "search_icon": "Suchsymbol", + "search_position": "Position", + "search_row": "Zeile", + "show_author": "Autor", + "show_alignment": "Ausrichtung anzeigen", + "show_count": "Anzahl anzeigen", + "show_date": "Datum", + "show_pickup_availability": "Verfügbarkeit von Abholungen anzeigen", + "show_search": "Suche anzeigen", + "use_inverse_logo": "Invertiertes Logo verwenden", + "vertical_padding": "Vertikales Padding", + "visibility": "Sichtbarkeit", + "product_corner_radius": "Produkt-Eckradius", + "card_corner_radius": "Karten-Eckradius", + "alignment_mobile": "Ausrichtung Mobilgerät", + "animation_repeat": "Animation wiederholen", + "blurred_reflection": "Unscharfe Spiegelung", + "card_hover_effect": "Karten-Hover-Effekt", + "card_size": "Kartengröße", + "collection_title_case": "Groß-/Kleinschreibung des Kollektionstitels", + "effects": "Effekte", + "inventory_threshold": "Schwelle für niedrigen Lagerbestand", + "mobile_card_size": "Kartengröße für Mobilgeräte", + "page": "Seite", + "product_and_card_title_case": "Groß-/Kleinschreibung des Produkt- und Kartentitels", + "product_title_case": "Groß-/Kleinschreibung des Produkttitels", + "reflection_opacity": "Opazität der Spiegelung", + "right_padding": "Rechtes Padding", + "show_inventory_quantity": "Menge bei niedrigem Lagerbestand anzeigen", + "text_label_case": "Groß-/Kleinschreibung der Beschriftung", + "transition_to_main_product": "Übergang von Produktkarte zu Produktseite", + "show_second_image_on_hover": "Hover-Effekt mit zweitem Bild", + "media": "Medien", + "product_card_carousel": "Karussell anzeigen", + "media_fit": "Medienanpassung", + "scroll_speed": "Zeit bis zur nächsten Ankündigung" + }, + "options": { + "adapt_to_image": "An Bild anpassen", + "apple": "Apfel", + "arrow": "Pfeil", + "banana": "Banane", + "bottle": "Flasche", + "box": "Box", + "buttons": "Schaltflächen", + "carrot": "Möhre", + "center": "Zentriert", + "chat_bubble": "Chat-Blase", + "clipboard": "Zwischenablage", + "contain": "Enthalten", + "counter": "Zähler", + "cover": "Cover", + "custom": "Benutzerdefiniert", + "dairy_free": "Laktosefrei", + "dairy": "Milch", + "dropdowns": "Dropdown-Listen", + "dots": "Punkte", + "dryer": "Trockner", + "end": "Ende", + "eye": "Auge", + "facebook": "Facebook", + "fire": "Feuer", + "gluten_free": "Glutenfrei", + "heart": "Herz", + "horizontal": "Horizontal", + "instagram": "Instagram", + "iron": "Bügeleisen", + "large": "Groß", + "leaf": "Blatt", + "leather": "Leder", + "lightning_bolt": "Blitz", + "lipstick": "Lippenstift", + "lock": "Schloss", + "map_pin": "Pinnnadel", + "medium": "Mittel", + "none": "Keiner", + "numbers": "Zahlen", + "nut_free": "Ohne Nüsse", + "pants": "Hosen", + "paw_print": "Pfotenabdruck", + "pepper": "Pfeffer", + "perfume": "Parfüm", + "pinterest": "Pinterest", + "plane": "Flugzeug", + "plant": "Pflanze", + "price_tag": "Preisschild", + "question_mark": "Fragezeichen", + "recycle": "Wiederverwenden", + "return": "Rückgabe", + "ruler": "Lineal", + "serving_dish": "Servierteller", + "shirt": "Hemd", + "shoe": "Schuh", + "silhouette": "Silhouette", + "small": "Klein", + "snapchat": "Snapchat", + "snowflake": "Schneeflocke", + "star": "Stern", + "start": "Start", + "stopwatch": "Stoppuhr", + "tiktok": "TikTok", + "truck": "Lieferwagen", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "vertical": "Vertikal", + "vimeo": "Vimeo", + "washing": "Wäsche", + "auto": "Auto", + "default": "Standard", + "fill": "Füllung", + "fit": "Passform", + "full": "Voll", + "full_and_page": "An den Hintergrund und die volle Seitenbreite angepasster Inhalt", + "heading": "Titel", + "landscape": "Querformat", + "lg": "LG", + "link": "Link", + "lowercase": "Kleinschreibung", + "m": "M", + "outline": "Umriss", + "page": "Seite", + "portrait": "Hochformat", + "s": "S", + "sentence": "Satz", + "solid": "Fest", + "space_between": "Leerzeichen zwischen", + "square": "Square", + "uppercase": "Großbuchstaben", + "circle": "Kreis", + "swatches": "Farbfelder", + "full_and_page_offset_left": "An den Hintergrund und die volle Seitenbreite angepasster Inhalt, Offset links", + "full_and_page_offset_right": "An den Hintergrund und die volle Seitenbreite angepasster Inhalt, Offset rechts", + "offset_left": "Offset links", + "offset_right": "Offset rechts", + "page_center_aligned": "Seite, mittig ausgerichtet", + "page_left_aligned": "Seite, links ausgerichtet", + "page_right_aligned": "Seite, rechts ausgerichtet", + "button": "Schaltfläche", + "caption": "Bildtext", + "h1": "Überschrift 1", + "h2": "Überschrift 2", + "h3": "Überschrift 3", + "h4": "Überschrift 4", + "h5": "Überschrift 5", + "h6": "Überschrift 6", + "paragraph": "Absatz", + "primary": "Primär", + "secondary": "Sekundär", + "tertiary": "Tertiär", + "chevron_left": "Chevron nach links", + "chevron_right": "Chevron nach rechts", + "diamond": "Diamant", + "grid": "Raster", + "parallelogram": "Parallelogramm", + "rounded": "Gerundet", + "fit_content": "Passform", + "pills": "Kapseln", + "heavy": "Kräftig", + "thin": "Dünn", + "drawer": "Einschub", + "preview": "Vorschau", + "text": "Text", + "video_uploaded": "Hochgeladen", + "video_external_url": "Externe URL", + "aspect_ratio": "Seitenverhältnis", + "above_carousel": "Oberhalb des Karussells", + "all": "Alle", + "always": "Immer", + "arrows_large": "Große Pfeile", + "arrows": "Pfeile", + "balance": "Balance", + "bento": "Bento", + "black": "Schwarz", + "bluesky": "Bluesky", + "body_large": "Text (groß)", + "body_regular": "Text (regulär)", + "body_small": "Text (klein)", + "bold": "Fett", + "bottom_left": "Unten, links", + "bottom_right": "Unten, rechts", + "bottom": "Unten", + "capitalize": "In Großbuchstaben schreiben", + "caret": "Cursor", + "carousel": "Karussell", + "check_box": "Kontrollkästchen", + "chevron_large": "Große Chevrons", + "chevron": "Chevron", + "chevrons": "Chevrons", + "classic": "Klassisch", + "collection_images": "Kollektionsbilder", + "color": "Farbe", + "complementary": "Ergänzend", + "dissolve": "Überblenden", + "dotted": "Gepunktet", + "editorial": "Editorial", + "extra_large": "Extra groß", + "extra_small": "Extra klein", + "featured_collections": "Vorgestellte Kollektionen", + "featured_products": "Vorgestellte Produkte", + "font_primary": "Primär", + "font_secondary": "Sekundär", + "font_tertiary": "Tertiär", + "forward": "Vorwärts", + "full_screen": "Vollbild", + "heading_extra_large": "Überschrift (extra groß)", + "heading_extra_small": "Überschrift (extra klein)", + "heading_large": "Überschrift (groß)", + "heading_regular": "Überschrift (regulär)", + "heading_small": "Überschrift (klein)", + "icon": "Symbol", + "image": "Bild", + "input": "Eingabe", + "inside_carousel": "Innenkarussell", + "inverse_large": "Invertiert groß", + "inverse": "Invertiert", + "large_arrows": "Große Pfeile", + "large_chevrons": "Große Chevrons", + "left": "Links", + "light": "Hell", + "linkedin": "LinkedIn", + "loose": "Ungebunden", + "media_first": "Medien zuerst", + "media_second": "Medien als zweites", + "modal": "Modal", + "narrow": "Schmal", + "never": "Nie", + "next_to_carousel": "Neben dem Karussell", + "normal": "Normal", + "nowrap": "Kein Zeilenumbruch", + "off_media": "Nicht bei Medien", + "on_media": "Bei Medien", + "on_scroll_up": "Beim Hochscrollen", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Oval", + "plus": "Plus", + "pretty": "Schön", + "price": "Preis", + "primary_style": "Primärer Stil", + "rectangle": "Rechteck", + "regular": "Regulär", + "related": "Ähnlich", + "reverse": "Umkehren", + "rich_text": "Rich Text", + "right": "Rechts", + "secondary_style": "Sekundärer Stil", + "semibold": "Halbfett", + "shaded": "Schattiert", + "show_second_image": "Zweites Bild anzeigen", + "single": "Einzeln", + "slide_left": "Nach links schieben", + "slide_up": "Nach oben schieben", + "spotify": "Spotify", + "stack": "Stapel", + "text_only": "Nur Text", + "threads": "Threads", + "thumbnails": "Vorschaubilder", + "tight": "Eng", + "top_left": "Oben links", + "top_right": "Oben rechts", + "top": "Oben", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Unterstreichen", + "video": "Video", + "wide": "Breit", + "youtube": "YouTube", + "up": "Oben", + "down": "Unten", + "gradient": "Farbverlauf", + "fixed": "Fest", + "pixel": "Pixel", + "percent": "Prozent", + "accent": "Akzent", + "below_image": "Unter Bild", + "body": "Nachricht", + "button_primary": "Primäre Schaltfläche", + "button_secondary": "Sekundäre Schaltfläche", + "compact": "Kompakt", + "crop_to_fit": "Passend zuschneiden", + "hidden": "Versteckt", + "hint": "Tipp", + "maintain_aspect_ratio": "Seitenverhältnisse beibehalten", + "off": "Aus", + "on_image": "Auf Bild", + "social_bluesky": "Social: Bluesky", + "social_facebook": "Social: Facebook", + "social_instagram": "Social: Instagram", + "social_linkedin": "Social: LinkedIn", + "social_pinterest": "Social: Pinterest", + "social_snapchat": "Social: Snapchat", + "social_spotify": "Social: Spotify", + "social_threads": "Social: Threads", + "social_tiktok": "Social: TikTok", + "social_tumblr": "Social: Tumblr", + "social_twitter": "Social: X (Twitter)", + "social_whatsapp": "Social: WhatsApp", + "social_vimeo": "Social: Vimeo", + "social_youtube": "Social: YouTube", + "spotlight": "Spotlight", + "standard": "Standard", + "subheading": "Unterüberschrift", + "blur": "Weichzeichnen", + "lift": "Lift", + "reveal": "Einblenden", + "scale": "Skalierung", + "subtle_zoom": "Zoomen" + }, + "content": { + "background_video": "Hintergrund-Video", + "describe_the_video_for": "Beschreibe das Video für Kunden, die Bildschirmlesegeräte benutzen. [Mehr Informationen](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "Breite wird automatisch für die mobile Nutzung optimiert.", + "advanced": "Advanced", + "background_image": "Hintergrundbild", + "block_size": "Blockgröße", + "borders": "Ränder", + "section_size": "Abschnittsgröße", + "slideshow_width": "Folienbreite", + "typography": "Typografie", + "complementary_products": "Ergänzende Produkte müssen mit der Search & Discovery-App eingerichtet werden. [Mehr Informationen](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Spalten werden automatisch für die mobile Nutzung optimiert", + "content_width": "Inhaltsbreite wird nur angewendet, wenn für die Abschnittsbreite volle Breite festgelegt ist.", + "adjustments_affect_all_content": "Gilt für alle Inhalte in diesem Block", + "responsive_font_sizes": "Die Größe wird automatisch auf sämtliche Bildschirmgrößen skaliert.", + "buttons": "Schaltflächen", + "swatches": "Farbfelder", + "variant_settings": "Varianteneinstellungen", + "background": "Hintergrund", + "appearance": "Erscheinungsbild", + "arrows": "Pfeile", + "body_size": "Textgröße", + "bottom_row_appearance": "Erscheinungsbild der untersten Zeile", + "carousel_navigation": "Karussell-Navigation", + "carousel_pagination": "Karussell-Seitennummerierung", + "copyright": "Urheberrecht", + "edit_logo_in_theme_settings": "Bearbeite dein Logo in den [Theme-Einstellungen](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Bearbeite die Preisformatierung in den [Theme-Einstellungen](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Bearbeite den Variantenstil in den [Theme-Einstellungen](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Registrierungen hinzufügen [Kundenprofile ](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Damit die Schaltfläche angezeigt wird, muss der Shop-Kanal installiert und Shop Pay aktiviert sein. [Mehr Informationen](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Schriftarten", + "grid": "Raster", + "heading_size": "Größe der Überschrift", + "image": "Bild", + "input": "Eingabe", + "layout": "Layout", + "link": "Link", + "link_padding": "Link-Padding", + "localization": "Lokalisierung", + "logo": "Logo", + "margin": "Rand", + "media": "Medien", + "media_1": "Medien 1", + "media_2": "Medien 2", + "menu": "Menü", + "mobile_layout": "Mobiles Layout", + "padding": "Padding", + "padding_desktop": "Desktop-Padding", + "paragraph": "Absatz", + "policies": "Richtlinien", + "popup": "Pop-up", + "search": "Suche", + "size": "Größe", + "social_media": "Social Media", + "submit_button": "Schaltfläche „Senden“", + "text_presets": "Textvoreinstellungen", + "transparent_background": "Transparenter Hintergrund", + "typography_primary": "Primäre Typografie", + "typography_secondary": "Sekundäre Typografie", + "typography_tertiary": "Tertiäre Typografie", + "mobile_size": "Mobile Größe", + "cards_layout": "Karten-Layout", + "section_layout": "Abschnitts-Layout", + "mobile_width": "Breite bei mobiler Ansicht", + "width": "Breite", + "carousel": "Karussell", + "colors": "Farben", + "collection_page": "Kollektionsseite", + "copyright_info": "Hier erfährst du, wie du [deinen Urheberrechtshinweis bearbeitest](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Kundenkonto", + "edit_empty_state_collection_in_theme_settings": "Kollektion mit Status „Leer“ in [Theme-Einstellungen]](/editor?context=theme&category=search) verwalten", + "home_page": "Startseite", + "images": "Bilder", + "inverse_logo_info": "Wird verwendet, wenn der transparente Header-Hintergrund auf „Invertiert“ gesetzt ist", + "manage_customer_accounts": "[Sichtbarkeit verwalten](/admin/settings/customer_accounts) in den Kundenkontoeinstellungen. Veraltete Konten werden nicht unterstützt.", + "manage_policies": "[Richtlinien verwalten](/admin/settings/legal)", + "product_page": "Produktseite", + "text": "Text", + "thumbnails": "Vorschaubilder", + "visibility": "Sichtbarkeit", + "visible_if_collection_has_more_products": "Sichtbar, wenn die Kollektion mehr als die angezeigten Produkte enthält", + "grid_layout": "Raster-Layout", + "app_required_for_ratings": "Für Produktbewertungen wird eine App benötigt. [Mehr Informationen](https://help.shopify.com/manual/apps)", + "icon": "Symbol", + "manage_store_name": "[Shop-Namen verwalten ](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Zeigt Kollektion aus übergeordnetem Abschnitt an", + "resource_reference_collection_card_image": "Zeigt Bild aus übergeordneter Kollektion an", + "resource_reference_collection_title": "Zeigt Titel aus übergeordneter Kollektion an", + "resource_reference_product": "Verbindet sich automatisch mit übergeordnetem Produkt", + "resource_reference_product_card": "Zeigt Produkt aus übergeordnetem Abschnitt an", + "resource_reference_product_inventory": "Zeigt Inventar aus übergeordnetem Produkt an", + "resource_reference_product_media": "Zeigt Medien aus dem übergeordneten Produkt an", + "resource_reference_product_price": "Zeigt Preis aus übergeordnetem Produkt an", + "resource_reference_product_recommendations": "Zeigt Empfehlungen auf Basis des übergeordneten Produkts an", + "resource_reference_product_review": "Zeigt Bewertungen aus übergeordnetem Produkt an", + "resource_reference_product_swatches": "Zeigt Farbfelder aus übergeordnetem Produkt an", + "resource_reference_product_title": "Zeigt Titel aus übergeordnetem Produkt an", + "resource_reference_product_variant_picker": "Zeigt Varianten aus übergeordnetem Produkt an", + "product_media": "Produktmedien", + "section_link": "Abschnitts-Link" + }, + "html_defaults": { + "share_information_about_your": "

Teile Infos über deine Marke mit deinen Kunden. Beschreibe ein Produkt, kündige etwas an oder heiße Kunden willkommen.

" + }, + "text_defaults": { + "collapsible_row": "Einklappbare Reihe", + "button_label": "Jetzt einkaufen", + "heading": "Titel", + "email_signup_button_label": "Abonnieren", + "accordion_heading": "Akkordeon-Überschrift", + "contact_form_button_label": "Senden", + "popup_link": "Pop-up-Link", + "sign_up": "Registrieren", + "welcome_to_our_store": "Willkommen in unserem Shop", + "be_bold": "Sei mutig.", + "shop_our_latest_arrivals": "Durchstöbere unsere aktuellsten Neuheiten!" + }, + "info": { + "video_alt_text": "Beschreibe das Video für Nutzer von unterstützender Technologie.", + "video_autoplay": "Videos werden standardmäßig stummgeschaltet", + "video_external": "YouTube- oder Vimeo-URL verwenden", + "carousel_layout_on_mobile": "Karussell wird auf Mobilgerät verwendet", + "carousel_hover_behavior_not_supported": "„Karussell“-Hover wird nicht unterstützt, wenn der Typ „Karussell“ auf der Abschnittsebene ausgewählt ist", + "link_info": "Optional: macht das Symbol anklickbar", + "checkout_buttons": "Ermöglicht es Käufern, schneller auszuchecken, und kann die Conversion optimieren. [Mehr Informationen](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Benutzerdefinierte Überschrift", + "edit_presets_in_theme_settings": "Bearbeite Voreinstellungen in den [Theme-Einstellungen](/editor?context=theme&category=typography)", + "enable_filtering_info": "Passe Filter an mit der [Search & Discovery-App](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Das Raster-Layout wird für die mobile Ansicht verwendet", + "manage_countries_regions": "[Länder/Regionen verwalten](/admin/settings/markets)", + "manage_languages": "[Sprachen verwalten](/admin/settings/languages)", + "transparent_background": "Überprüfe alle Vorlagen, in denen ein transparenter Hintergrund verwendet wird, auf ihre Lesbarkeit", + "logo_font": "Gilt nur, wenn kein Logo ausgewählt wurde", + "aspect_ratio_adjusted": "In einigen Layouts angepasst", + "auto_open_cart_drawer": "Wenn er aktiviert ist, wird der Warenkorbeinschub automatisch geöffnet, wenn ein Produkt zum Warenkorb hinzugefügt wird.", + "custom_liquid": "Füge App-Snippets oder anderen Code hinzu, um fortgeschrittene Anpassungen zu erstellen. [Mehr Informationen](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "Gilt nur für Bilder", + "hover_effects": "Bezieht sich auf Produkt- und Kollektionskarten", + "pills_usage": "Für angewandte Filter, Rabattcodes und Suchvorschläge" + }, + "categories": { + "product_list": "Vorgestellte Kollektion", + "basic": "Basic", + "collection": "Kollektion", + "collection_list": "Kollektionsliste", + "footer": "Fußzeile", + "forms": "Formulare", + "header": "Header", + "layout": "Layout", + "links": "Links", + "product": "Produkt", + "banners": "Banner", + "collections": "Kollektionen", + "custom": "Benutzerdefiniert", + "decorative": "Dekorativ", + "products": "Produkte", + "other_sections": "Weitere", + "storytelling": "Storytelling" + } +} diff --git a/locales/el.json b/locales/el.json new file mode 100644 index 000000000..391b20e74 --- /dev/null +++ b/locales/el.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Φόρτωση βίντεο: {{ description }}", + "sold_out": "Εξαντλήθηκε", + "email_signup": { + "label": "Email", + "placeholder": "Διεύθυνση email", + "success": "Ευχαριστούμε για την εγγραφή!" + }, + "filter": "Φιλτράρισμα", + "payment_methods": "Μέθοδοι πληρωμής", + "contact_form": { + "name": "Όνομα", + "email": "Email", + "phone": "Τηλέφωνο", + "comment": "Σχόλιο", + "post_success": "Ευχαριστούμε που επικοινωνήσατε μαζί μας. Θα σας απαντήσουμε το συντομότερο δυνατόν.", + "error_heading": "Προσαρμόστε τα παρακάτω:" + } + }, + "accessibility": { + "play_model": "Αναπαραγωγή μοντέλου 3D", + "play_video": "Αναπαραγωγή βίντεο", + "unit_price": "Τιμή μονάδας", + "country_results_count": "{{ count }} αποτελέσματα", + "slideshow_pause": "Παύση παρουσίασης", + "slideshow_play": "Αναπαραγωγή παρουσίασης", + "remove_item": "Κατάργηση {{ title}}", + "skip_to_text": "Απευθείας μετάβαση στο περιεχόμενο", + "skip_to_product_info": "Μετάβαση στις πληροφορίες προϊόντος", + "skip_to_results_list": "Μεταβείτε στη λίστα αποτελεσμάτων", + "new_window": "Ανοίγει σε νέο παράθυρο.", + "close_dialog": "Κλείσιμο διαλόγου", + "reset_search": "Επαναφορά αναζήτησης", + "search_results_count": "{{ count }} αποτελέσματα αναζήτησης βρέθηκαν για \"{{ query }}\"", + "search_results_no_results": "Δεν βρέθηκαν αποτελέσματα για \"{{ query }}\"", + "slideshow_next": "Επόμενη διαφάνεια", + "slideshow_previous": "Προηγούμενη διαφάνεια", + "filters": "Φίλτρα", + "account": "Άνοιγμα μενού λογαριασμού", + "cart": "Καλάθι", + "cart_count": "Σύνολο προϊόντων στο καλάθι", + "filter_count": { + "one": "Εφαρμόστηκε {{ count }} φίλτρο", + "other": "Εφαρμόστηκαν {{ count }} φίλτρα" + }, + "menu": "Μενού", + "country_region": "Χώρα/Περιοχή", + "slide_status": "Διαφάνεια {{ index }} από {{ length }}", + "scroll_to": "Κύλιση προς το {{ title }}", + "loading_product_recommendations": "Φόρτωση συστάσεων προϊόντων", + "discount": "Εφαρμογή κωδικού έκπτωσης", + "discount_applied": "Εφαρμόστηκε ο κωδικός έκπτωση: {{ code }}", + "open_cart_drawer": "Άνοιγμα καλαθιού", + "inventory_status": "Κατάσταση αποθέματος", + "pause_video": "Παύση του βίντεο", + "localization_region_and_language": "Επιλέξτε περιοχή και γλώσσα", + "open_search_modal": "Άνοιγμα αναζήτησης", + "find_country": "Εύρεση χώρας", + "decrease_quantity": "Μείωση ποσότητας", + "increase_quantity": "Αύξηση ποσότητας", + "quantity": "Ποσότητα", + "rating": "Η βαθμολογία αυτού του προϊόντος είναι {{ rating }} στα 5", + "nested_product": "{{ product_title }} για {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Προσθήκη στο καλάθι", + "clear_all": "Διαγραφή όλων", + "remove": "Κατάργηση", + "view_in_your_space": "Προβολή στον χώρο σας", + "show_filters": "Φιλτράρισμα", + "clear": "Διαγραφή", + "continue_shopping": "Συνέχιση αγορών", + "log_in_html": "Έχετε λογαριασμό; Συνδεθείτε για ταχύτερη ολοκλήρωση των αγορών σας.", + "see_items": { + "one": "Δείτε {{ count }} στοιχείο", + "other": "Δείτε {{ count }} στοιχεία" + }, + "view_all": "Προβολή όλων", + "add": "Προσθήκη", + "choose": "Επιλέξτε", + "added": "Προστέθηκε", + "show_less": "Εμφάνιση λιγότερων", + "show_more": "Εμφάνιση περισσότερων", + "close": "Κλείσιμο", + "more": "Περισσότερα", + "zoom": "Μεγέθυνση", + "close_dialog": "Κλείσιμο διαλόγου", + "reset": "Επαναφορά", + "enter_using_password": "Είσοδος με τη χρήση κωδικού πρόσβασης", + "submit": "Υποβολή", + "enter_password": "Εισαγάγετε κωδικό πρόσβασης", + "back": "Πίσω", + "log_in": "Σύνδεση", + "log_out": "Αποσύνδεση", + "remove_discount": "Κατάργηση κωδικού έκπτωσης {{ code }}", + "view_store_information": "Προβολή πληροφοριών καταστήματος", + "apply": "Εφαρμογή", + "sign_in_options": "Άλλες επιλογές σύνδεσης", + "sign_up": "Εγγραφή", + "open_image_in_full_screen": "Άνοιγμα εικόνας σε πλήρη οθόνη", + "sort": "Ταξινόμηση", + "show_all_options": "Εμφάνιση όλων των επιλογών" + }, + "content": { + "reviews": "κριτικές", + "no_results_found": "Δεν βρέθηκαν αποτελέσματα", + "language": "Γλώσσα", + "localization_region_and_language": "Περιοχή και γλώσσα", + "cart_total": "Συνολικό ποσό στο καλάθι", + "your_cart_is_empty": "Το καλάθι σας είναι κενό", + "product_image": "Εικόνα προϊόντος", + "product_information": "Πληροφορίες προϊόντος", + "quantity": "Ποσότητα", + "product_total": "Συνολική ποσότητα για το προϊόν", + "cart_estimated_total": "Εκτιμώμενο σύνολο", + "seller_note": "Ειδικές οδηγίες", + "cart_subtotal": "Υποσύνολο", + "discounts": "Εκπτώσεις", + "discount": "Έκπτωση", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Οι δασμοί και οι φόροι συμπεριλαμβάνονται. Οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Οι δασμοί και οι φόροι συμπεριλαμβάνονται. Οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_included_shipping_at_checkout_with_policy_html": "Οι φόροι συμπεριλαμβάνονται. Οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_included_shipping_at_checkout_without_policy": "Οι φόροι συμπεριλαμβάνονται. Οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Οι δασμοί συμπεριλαμβάνονται. Οι φόροι, οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Οι δασμοί συμπεριλαμβάνονται. Οι φόροι, οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Οι φόροι, οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Οι φόροι, οι εκπτώσεις και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "checkout": "Ολοκλήρωση αγοράς", + "cart_title": "Καλάθι", + "price": "Τιμή", + "price_regular": "Κανονική τιμή", + "price_compare_at": "Σύγκριση σε τιμή", + "price_sale": "Τιμή έκπτωσης", + "duties_and_taxes_included": "Οι δασμοί και οι φόροι συμπεριλαμβάνονται.", + "duties_included": "Οι δασμοί συμπεριλαμβάνονται.", + "shipping_policy_html": "Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_included": "Οι φόροι συμπεριλαμβάνονται.", + "product_badge_sold_out": "Εξαντλήθηκε", + "product_badge_sale": "Έκπτωση", + "search_input_label": "Αναζήτηση", + "search_input_placeholder": "Αναζήτηση", + "search_results": "Αποτελέσματα αναζήτησης", + "search_results_label": "Αποτελέσματα αναζήτησης", + "search_results_no_results": "Δεν βρέθηκαν αποτελέσματα για \"{{ terms }}\". Δοκιμάστε άλλη αναζήτηση.", + "search_results_resource_articles": "Αναρτήσεις ιστολογίου", + "search_results_resource_collections": "Συλλογές", + "search_results_resource_pages": "Σελίδες", + "search_results_resource_products": "Προϊόντα", + "search_results_resource_queries": "Προτάσεις αναζήτησης", + "search_results_view_all": "Προβολή όλων", + "search_results_view_all_button": "Προβολή όλων", + "search_results_resource_products_count": { + "one": "{{ count }} προϊόν", + "other": "{{ count }} προϊόντα" + }, + "grid_view": { + "default_view": "Προεπιλογή", + "grid_fieldset": "Column grid", + "single_item": "Ενιαία", + "zoom_out": "Σμίκρυνση" + }, + "unavailable": "Μη διαθέσιμο", + "recently_viewed_products": "Πρόσφατα προβαλλόμενες", + "collection_placeholder": "Τίτλος συλλογής", + "product_card_placeholder": "Τίτλος προϊόντος", + "product_count": "Αριθμός προϊόντων", + "item_count": { + "one": "{{ count }} προϊόν", + "other": "{{ count }} προϊόντα" + }, + "errors": "Σφάλματα", + "price_from": "Από {{ price }}", + "search": "Αναζήτηση", + "search_results_no_results_check_spelling": "Δεν βρέθηκαν αποτελέσματα για \"{{ terms }}\". Ελέγξτε την ορθογραφία ή χρησιμοποιήστε άλλη λέξη ή φράση.", + "featured_products": "Επιλεγμένα προϊόντα", + "no_products_found": "Δεν βρέθηκαν προϊόντα.", + "use_fewer_filters_html": "Δοκιμάστε να χρησιμοποιήσετε λιγότερα φίλτρα ή καταργήστε όλα τα φίλτρα.", + "filters": "Φίλτρα", + "price_filter_html": "Η υψηλότερη τιμή είναι {{ price }}", + "blog_details_separator": "|", + "read_more": "Διαβάστε περισσότερα...", + "wrong_password": "Λανθασμένος κωδικός πρόσβασης", + "account_title": "Λογαριασμός", + "account_title_personalized": "Γεια σας {{ first_name }},", + "account_orders": "Παραγγελίες", + "account_profile": "Προφίλ", + "discount_code": "Κωδικός έκπτωσης", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Οι δασμοί και οι φόροι συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Οι δασμοί και οι φόροι συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Οι δασμοί συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Οι δασμοί συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "pickup_available_at_html": "Υπάρχει δυνατότητα παραλαβής από {{ location }}", + "pickup_available_in": "Υπάρχει δυνατότητα παραλαβής στις {{ pickup_time }}", + "pickup_not_available": "Δεν υπάρχει δυνατότητα παραλαβής αυτήν τη στιγμή", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Οι φόροι και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Οι φόροι και τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Οι φόροι συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Οι φόροι συμπεριλαμβάνονται. Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "view_more_details": "Προβολή περισσοτέρων λεπτομερειών", + "inventory_low_stock": "Χαμηλό απόθεμα", + "inventory_in_stock": "Σε απόθεμα", + "inventory_out_of_stock": "Χωρίς απόθεμα", + "page_placeholder_title": "Τίτλος σελίδας", + "page_placeholder_content": "Επιλέξτε μια σελίδα για να δείτε το περιεχόμενό της.", + "placeholder_image": "Εικόνα placeholder", + "inventory_low_stock_show_count": { + "one": "{{ count }} ακόμη", + "other": "{{ count }} ακόμη" + }, + "shipping_policy": "Τα έξοδα αποστολής υπολογίζονται κατά την ολοκλήρωση της αγοράς.", + "discount_code_error": "Ο κωδικός έκπτωσης δεν μπορεί να εφαρμοστεί στο καλάθι σας", + "powered_by": "Αυτό το κατάστημα θα υποστηρίζεται από το", + "store_owner_link_html": "Είστε ο ιδιοκτήτης του καταστήματος; Συνδεθείτε εδώ", + "shipping_discount_error": "Οι εκπτώσεις αποστολής εμφανίζονται στην ολοκλήρωση αγοράς μετά την προσθήκη διεύθυνσης" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Χρησιμοποιήστε τον κωδικό της δωροκάρτας στο διαδίκτυο ή τον κωδικό QR στο κατάστημα", + "title": "Αυτό είναι το υπόλοιπο της δωροκάρτας σας ύψους {{ value }} για το {{ shop }}!", + "subtext": "Η δωροκάρτα σας", + "shop_link": "Επισκεφτείτε το διαδικτυακό κατάστημα", + "add_to_apple_wallet": "Προσθήκη στο Apple Wallet", + "qr_image_alt": "Κωδικός QR — σαρώστε για να εξαργυρώσετε τη δωροκάρτα", + "copy_code": "Αντιγραφή κωδικού δωροκάρτας", + "expiration_date": "Λήγει στις {{ expires_on }}", + "copy_code_success": "Η αντιγραφή του κωδικού ήταν επιτυχής", + "expired": "Έληξε" + } + }, + "placeholders": { + "password": "Κωδικός πρόσβασης", + "search": "Αναζήτηση", + "product_title": "Τίτλος προϊόντος", + "collection_title": "Τίτλος συλλογής" + }, + "products": { + "product": { + "add_to_cart": "Προσθήκη στο καλάθι", + "added_to_cart": "Προστέθηκε στο καλάθι", + "adding_to_cart": "Προσθήκη...", + "add_to_cart_error": "Παρουσιάστηκε σφάλμα κατά την προσθήκη στο καλάθι", + "sold_out": "Εξαντλήθηκε", + "unavailable": "Μη διαθέσιμο" + } + }, + "fields": { + "separator": "σε" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} σχόλιο", + "other": "{{ count }} σχόλια" + } + }, + "comment_form": { + "email": "Email", + "error": "Αποτυχία δημοσίευσης σχολίου, αντιμετωπίστε τα εξής:", + "heading": "Υποβάλετε ένα σχόλιο", + "message": "Μήνυμα", + "moderated": "Έχετε υπόψη ότι τα σχόλια χρειάζεται να λάβουν έγκριση προτού δημοσιευτούν.", + "name": "Όνομα", + "post": "Ανάρτηση σχολίου", + "success_moderated": "Το σχόλιο δημοσιεύτηκε, εν αναμονή τροποποίησης", + "success": "Το σχόλιο δημοσιεύτηκε" + } + } +} diff --git a/locales/en.default.json b/locales/en.default.json new file mode 100644 index 000000000..11fbd5c4d --- /dev/null +++ b/locales/en.default.json @@ -0,0 +1,281 @@ +/* + * ------------------------------------------------------------ + * IMPORTANT: The contents of this file are auto-generated. + * + * This file may be updated by the Shopify admin language editor + * or related systems. Please exercise caution as any changes + * made to this file may be overwritten. + * ------------------------------------------------------------ + */ +{ + "accessibility": { + "account": "Open account menu", + "cart": "Cart", + "cart_count": "Total items in cart", + "close_dialog": "Close dialog", + "country_region": "Country/Region", + "country_results_count": "{{ count }} results", + "decrease_quantity": "Decrease quantity", + "discount": "Apply a discount code", + "discount_applied": "Applied discount code: {{ code }}", + "filters": "Filters", + "filter_count": { + "one": "{{ count }} filter applied", + "other": "{{ count }} filters applied" + }, + "increase_quantity": "Increase quantity", + "inventory_status": "Inventory status", + "localization_region_and_language": "Open region and language selector", + "menu": "Menu", + "nested_product": "{{ product_title }} for {{ parent_title }}", + "new_window": "Opens in a new window.", + "open_cart_drawer": "Open cart", + "open_search_modal": "Open search", + "quantity": "Quantity", + "pause_video": "Pause video", + "play_model": "Play 3D model", + "play_video": "Play video", + "loading_product_recommendations": "Loading product recommendations", + "rating": "Rating of this product is {{ rating }} out of 5", + "remove_item": "Remove {{ title}}", + "reset_search": "Reset search", + "scroll_to": "Scroll to {{ title }}", + "search_results_count": "{{ count }} search results found for \"{{ query }}\"", + "search_results_no_results": "No results found for \"{{ query }}\"", + "skip_to_product_info": "Skip to product information", + "skip_to_results_list": "Skip to results list", + "skip_to_text": "Skip to content", + "slide_status": "Slide {{ index }} of {{ length }}", + "slideshow_next": "Next slide", + "slideshow_pause": "Pause slideshow", + "slideshow_play": "Play slideshow", + "slideshow_previous": "Previous slide", + "unit_price": "Unit price", + "find_country": "Find country" + }, + "actions": { + "add": "Add", + "add_to_cart": "Add to cart", + "added": "Added", + "apply": "Apply", + "back": "Back", + "choose": "Choose", + "clear": "Clear", + "clear_all": "Clear all", + "close": "Close", + // Continue shopping link on the cart page which takes the user back to a collection page + "continue_shopping": "Continue shopping", + "enter_password": "Enter password", + "log_in_html": "Have an account? Log in to check out faster.", + "log_in": "Sign in", + "log_out": "Log out", + "open_image_in_full_screen": "Open image in full screen", + "remove": "Remove", + "remove_discount": "Remove discount {{ code }}", + "show_all_options": "Show all options", + "see_items": { + "one": "See {{ count }} item", + "other": "See {{ count }} items" + }, + "show_filters": "Filter", + "show_less": "Show less", + "show_more": "Show more", + "sign_in_options": "Other sign in options", + "view_in_your_space": "View in your space", + "view_all": "View all", + "more": "More", + "zoom": "Zoom", + "close_dialog": "Close dialog", + "reset": "Reset", + "enter_using_password": "Enter using password", + "sign_up": "Sign up", + "submit": "Submit", + "view_store_information": "View store information", + "sort": "Sort" + }, + "blocks": { + "contact_form": { + "name": "Name", + "email": "Email", + "phone": "Phone", + "comment": "Comment", + "post_success": "Thanks for contacting us. We'll get back to you as soon as possible.", + "error_heading": "Please adjust the following:" + }, + "email_signup": { + "label": "Email", + "placeholder": "Email address", + "success": "Thanks for subscribing!" + }, + "filter": "Filter", + "load_video": "Load video: {{ description }}", + "sold_out": "Sold out", + "payment_methods": "Payment methods" + }, + "blogs": { + "article": { + "comments_heading": { + "one": "{{ count }} comment", + "other": "{{ count }} comments" + }, + "comment_author_separator": "•" + }, + "comment_form": { + "email": "Email", + "error": "Comment failed to post, please address the following:", + "heading": "Leave a comment", + "message": "Message", + "moderated": "Please note, comments need to be approved before they are published.", + "name": "Name", + "post": "Post comment", + "success_moderated": "Comment posted, awaiting moderation", + "success": "Comment posted" + } + }, + "content": { + "discount": "Discount", + "account_title": "Account", + "account_title_personalized": "Hi {{ first_name }}", + "account_orders": "Orders", + "account_profile": "Profile", + "blog_details_separator": "|", + "cart_estimated_total": "Estimated total", + "cart_title": "Cart", + "cart_subtotal": "Subtotal", + "cart_total": "Cart total", + "checkout": "Check out", + "collection_placeholder": "Collection title", + "discount_code": "Discount code", + "shipping_discount_error": "Shipping discounts are shown at checkout after adding an address", + "discount_code_error": "Discount code cannot be applied to your cart", + "discounts": "Discounts", + "duties_and_taxes_included": "Duties and taxes included.", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Duties and taxes included. Discounts and shipping calculated at checkout.", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Duties and taxes included. Shipping is calculated at checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Duties and taxes included. Discounts and shipping calculated at checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Duties and taxes included. Shipping is calculated at checkout.", + "duties_included": "Duties included.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Duties included. Taxes, discounts and shipping calculated at checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Duties included. Shipping is calculated at checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Duties included. Taxes, discounts and shipping calculated at checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Duties included. Shipping is calculated at checkout.", + "featured_products": "Featured products", + "filters": "Filters", + "grid_view": { + "default_view": "Default", + "grid_fieldset": "Column grid", + "single_item": "Single", + "zoom_out": "Zoom out" + }, + "inventory_low_stock_show_count": { + "one": "{{ count }} left", + "other": "{{ count }} left" + }, + "inventory_low_stock": "Low stock", + "inventory_in_stock": "In stock", + "inventory_out_of_stock": "Out of stock", + "item_count": { + "one": "{{ count }} item", + "other": "{{ count }} items" + }, + "language": "Language", + "localization_region_and_language": "Region and language", + "no_products_found": "No products found.", + "no_results_found": "No results found", + "page_placeholder_title": "Page title", + "page_placeholder_content": "Select a page to display its content.", + "pickup_available_at_html": "Pickup available at {{ location }}", + "pickup_available_in": "Pickup available, {{ pickup_time }}", + "pickup_not_available": "Pickup currently not available", + "pickup_ready_in": "{{ pickup_time }}", + "powered_by": "This shop will be powered by", + "price": "Price", + "price_compare_at": "Compare at price", + "price_from": "From {{ price }}", + "price_regular": "Regular price", + "price_sale": "Sale price", + "price_filter_html": "The highest price is {{ price }}", + "product_image": "Product image", + "product_information": "Product information", + "product_total": "Product total", + "product_badge_sold_out": "Sold out", + "product_badge_sale": "Sale", + "product_card_placeholder": "Product title", + "placeholder_image": "Placeholder image", + "quantity": "Quantity", + "recently_viewed_products": "Recently viewed", + "reviews": "reviews", + "read_more": "Read more...", + "search_input_label": "Search", + "search_input_placeholder": "Search", + "search": "Search", + "search_results": "Search results", + "search_results_label": "Search results", + "search_results_no_results": "No results found for \"{{ terms }}\". Try another search.", + "search_results_no_results_check_spelling": "No results found for \"{{ terms }}\". Check the spelling or use a different word or phrase.", + "search_results_resource_articles": "Blog posts", + "search_results_resource_collections": "Collections", + "search_results_resource_pages": "Pages", + "search_results_resource_products": "Products", + "search_results_resource_products_count": { + "one": "{{ count }} product", + "other": "{{ count }} products" + }, + "search_results_resource_queries": "Search suggestions", + "search_results_view_all": "View all", + "search_results_view_all_button": "View all", + "seller_note": "Special instructions", + "shipping_policy": "Shipping calculated at checkout.", + "shipping_policy_html": "Shipping calculated at checkout.", + "store_owner_link_html": "Are you the store owner? Log in here", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Taxes, discounts and shipping calculated at checkout.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Taxes and shipping calculated at checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Taxes, discounts and shipping calculated at checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Taxes and shipping calculated at checkout.", + "taxes_included": "Taxes included.", + "taxes_included_shipping_at_checkout_with_policy_html": "Taxes included. Discounts and shipping calculated at checkout.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Taxes included. Shipping is calculated at checkout.", + "taxes_included_shipping_at_checkout_without_policy": "Taxes included. Discounts and shipping calculated at checkout.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Taxes included. Shipping is calculated at checkout.", + "unavailable": "Unavailable", + "use_fewer_filters_html": "Try using fewer filters, or clear all filters.", + "view_more_details": "View more details", + "your_cart_is_empty": "Your cart is empty", + "product_count": "Product count", + "errors": "Errors", + "wrong_password": "Wrong password" + }, + "fields": { + "separator": "to" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Use the gift card code online or QR code in-store", + "title": "Here's your {{ value }} gift card balance for {{ shop }}!", + "subtext": "Your gift card", + "shop_link": "Visit online store", + "add_to_apple_wallet": "Add to Apple Wallet", + "qr_image_alt": "QR code — scan to redeem gift card", + "copy_code": "Copy gift card code", + "expiration_date": "Expires {{ expires_on }}", + "copy_code_success": "Code copied successfully", + "expired": "Expired" + } + }, + "placeholders": { + "password": "Password", + "search": "Search", + "product_title": "Product title", + "collection_title": "Collection title" + }, + "products": { + "product": { + "add_to_cart": "Add to cart", + "adding_to_cart": "Adding...", + "added_to_cart": "Added to cart", + "add_to_cart_error": "Error adding to cart", + "sold_out": "Sold out", + "unavailable": "Unavailable" + } + } +} diff --git a/locales/en.default.schema.json b/locales/en.default.schema.json new file mode 100644 index 000000000..a6f41d940 --- /dev/null +++ b/locales/en.default.schema.json @@ -0,0 +1,940 @@ +/* + * ------------------------------------------------------------ + * IMPORTANT: The contents of this file are auto-generated. + * + * This file may be updated by the Shopify admin language editor + * or related systems. Please exercise caution as any changes + * made to this file may be overwritten. + * ------------------------------------------------------------ + */ +{ + "categories": { + "banners": "Banners", + "basic": "Basic", + "collection": "Collection", + "collections": "Collections", + "collection_list": "Collection list", + "custom": "Custom", + "decorative": "Decorative", + "footer": "Footer", + "forms": "Forms", + "header": "Header", + "layout": "Layout", + "links": "Links", + "product": "Product", + "products": "Products", + "product_list": "Featured collection", + "other_sections": "Other", + "storytelling": "Storytelling" + }, + "content": { + "visible_if_collection_has_more_products": "Visible if collection has more products than shown", + "adjustments_affect_all_content": "Applies to all content in this block", + "advanced": "Advanced", + "appearance": "Appearance", + "arrows": "Arrows", + "background": "Background", + "background_image": "Background image", + "background_video": "Background video", + "block_size": "Block size", + "body_size": "Body size", + "borders": "Borders", + "bottom_row_appearance": "Bottom row appearance", + "buttons": "Buttons", + "cards_layout": "Cards layout", + "carousel": "Carousel", + "carousel_navigation": "Carousel navigation", + "carousel_pagination": "Carousel pagination", + "colors": "Colors", + "collection_page": "Collection page", + "complementary_products": "Complementary products must be set up using the Search & Discovery app. [Learn more](https://help.shopify.com/manual/online-store/search-and-discovery)", + "content_width": "Content width only applies when the section width is set to full width.", + "copyright": "Copyright", + "copyright_info": "Learn how to [edit your copyright statement](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Customer account", + "describe_the_video_for": "Describe the video for customers using screen readers. [Learn more](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "edit_empty_state_collection_in_theme_settings": "Edit empty state collection in [theme settings](/editor?context=theme&category=search)", + "edit_logo_in_theme_settings": "Edit logo in [theme settings](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Edit price formatting in [theme settings](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Edit variant styling in [theme settings](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Signups add [customer profiles](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "For the button to show, the Shop channel must be installed and Shop Pay activated. [Learn more](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Fonts", + "grid": "Grid", + "grid_layout": "Grid layout", + "heading_size": "Heading size", + "home_page": "Home page", + "icon": "Icon", + "image": "Image", + "images": "Images", + "input": "Input", + "inverse_logo_info": "Used when transparent header background is set to Inverse", + "layout": "Layout", + "link": "Link", + "link_padding": "Link padding", + "localization": "Localization", + "logo": "Logo", + "manage_customer_accounts": "[Manage visibility](/admin/settings/customer_accounts) in customer account settings. Legacy accounts not supported.", + "manage_policies": "[Manage policies](/admin/settings/legal)", + "manage_store_name": "[Manage store name](/admin/settings/general?edit=storeName)", + "margin": "Margin", + "media": "Media", + "media_1": "Media 1", + "media_2": "Media 2", + "menu": "Menu", + "mobile_column_optimization": "Columns will automatically optimize for mobile", + "mobile_layout": "Mobile layout", + "mobile_size": "Mobile size", + "mobile_width": "Mobile width", + "padding": "Padding", + "padding_desktop": "Desktop padding", + "paragraph": "Paragraph", + "policies": "Policies", + "popup": "Popup", + "product_media": "Product media", + "product_page": "Product page", + "responsive_font_sizes": "Sizes automatically scale for all screen sizes", + "resource_reference_collection_card": "Displays collection from parent section", + "resource_reference_collection_card_image": "Displays image from parent collection", + "resource_reference_collection_title": "Displays title from parent collection", + "resource_reference_product": "Auto connects to parent product", + "resource_reference_product_card": "Displays product from parent section", + "resource_reference_product_inventory": "Displays inventory from parent product", + "resource_reference_product_media": "Displays media from parent product", + "resource_reference_product_price": "Displays price from parent product", + "resource_reference_product_recommendations": "Displays recommendations based on parent product", + "resource_reference_product_review": "Displays reviews from parent product", + "resource_reference_product_swatches": "Displays swatches from parent product", + "resource_reference_product_title": "Displays title from parent product", + "resource_reference_product_variant_picker": "Displays variants from parent product", + "search": "Search", + "section_layout": "Section layout", + "section_link": "Section link", + "section_size": "Section size", + "size": "Size", + "slideshow_width": "Slide width", + "social_media": "Social media", + "submissions_are_sent_to_store_email_address": "Submissions are sent to your store's [sender email address](https://admin.shopify.com/settings/notifications)", + "submit_button": "Submit button", + "swatches": "Swatches", + "text": "Text", + "text_presets": "Text presets", + "thumbnails": "Thumbnails", + "transparent_background": "Transparent background", + "typography": "Typography", + "typography_primary": "Primary typography", + "typography_secondary": "Secondary typography", + "typography_tertiary": "Tertiary typography", + "variant_settings": "Variant settings", + "visibility": "Visibility", + "width": "Width", + "width_is_automatically_optimized": "Width is automatically optimized for mobile.", + "app_required_for_ratings": "An app is required for product ratings. [Learn more](https://help.shopify.com/manual/apps)" + }, + "html_defaults": { + "share_information_about_your": "

Share information about your brand with your customers. Describe a product, make announcements, or welcome customers to your store.

" + }, + "info": { + "applies_on_image_only": "Applies to images only", + "aspect_ratio_adjusted": "Adjusted in some layouts", + "auto_open_cart_drawer": "When enabled, the cart drawer will automatically open when a product is added to cart.", + "carousel_hover_behavior_not_supported": "\"Carousel\" hover is not supported when \"Carousel\" type is selected at the section level", + "carousel_layout_on_mobile": "Carousel is used on mobile", + "checkout_buttons": "Allows buyers to check out faster and can improve conversion. [Learn more](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Custom heading", + "custom_liquid": "Add app snippets or other code to create advanced customizations. [Learn more](https://shopify.dev/docs/api/liquid)", + "edit_presets_in_theme_settings": "Edit presets in [theme settings](/editor?context=theme&category=typography)", + "enable_filtering_info": "Customize filters with the [Search & Discovery app](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Grid layout is used for mobile", + "hover_effects": "Applies to product and collection cards", + "link_info": "Optional: makes icon clickable", + "logo_font": "Applies only when a logo is not selected", + "manage_countries_regions": "[Manage countries/regions](/admin/settings/markets)", + "manage_languages": "[Manage languages](/admin/settings/languages)", + "transparent_background": "Review each template where transparent background is applied for readability", + "video_alt_text": "Describe the video for assistive tech users", + "video_autoplay": "Videos will be muted by default", + "video_external": "Use a YouTube or Vimeo URL", + "pills_usage": "Used for applied filters, discount codes, and search suggestions" + + }, + "names": { + "product_title": "Product title", + "custom_liquid": "Custom liquid", + "404": "404", + "accelerated_checkout": "Accelerated checkout", + "accordion": "Accordion", + "accordion_row": "Accordion row", + "add_to_cart": "Add to cart", + "alternating_content_rows": "Alternating rows", + "animations": "Animations", + "announcement": "Announcement", + "announcement_bar": "Announcement bar", + "badges": "Badges", + "blog": "Blog", + "blog_post": "Blog post", + "blog_posts": "Blog posts", + "borders": "Borders", + "button": "Button", + "buttons": "Buttons", + "caption": "Caption", + "cart": "Cart", + "cart_items": "Cart items", + "cart_products": "Cart products", + "cart_title": "Cart", + "collapsible_row": "Collapsible row", + "collection": "Collection", + "collection_card": "Collection card", + "collection_card_image": "Image", + "collection_columns": "Collection columns", + "collection_container": "Collection", + "collection_description": "Collection description", + "collection_image": "Collection image", + "collection_info": "Collection info", + "collection_list": "Collection list", + "collection_title": "Collection title", + "collections": "Collections", + "collection_links": "Collection links", + "collection_links_spotlight": "Collection links: Spotlight", + "collection_links_text": "Collection links: Text", + "collections_bento": "Collection list: Bento", + "collections_carousel": "Collection list: Carousel", + "collections_editorial": "Collection list: Editorial", + "collections_grid": "Collection list: Grid", + "colors": "Colors", + "contact_form": "Contact form", + "content": "Content", + "content_grid": "Content grid", + "copyright": "Copyright", + "count": "Count", + "custom_section": "Custom section", + "description": "Description", + "details": "Details", + "divider": "Divider", + "divider_section": "Divider", + "drawers": "Drawers", + "editorial": "Editorial", + "editorial_jumbo_text": "Editorial: Jumbo text", + "email_signup": "Email signup", + "facets": "Facets", + "faq_section": "FAQ", + "featured_collection": "Featured collection", + "featured_product": "Product highlight", + "filters": "Filtering and sorting", + "follow_on_shop": "Follow on Shop", + "footer": "Footer", + "footer_utilities": "Footer utilities", + "grid_layout_selector": "Grid layout selector", + "group": "Group", + "header": "Header", + "heading": "Heading", + "hero": "Hero", + "hero_marquee": "Hero: Marquee", + "icon": "Icon", + "icons": "Icons", + "icons_with_text": "Icons with text", + "image": "Image", + "image_with_text": "Image with text", + "input": "Input", + "input_fields": "Input fields", + "inputs": "Inputs", + "jumbo_text": "Jumbo text", + "large_logo": "Large logo", + "list_items": "List items", + "local_pickup": "Local pickup", + "logo": "Logo", + "logo_and_favicon": "Logo and favicon", + "magazine_grid": "Magazine grid", + "marquee": "Marquee", + "marquee_section": "Marquee", + "media": "Media", + "media_with_text": "Media with text", + "menu": "Menu", + "mobile_layout": "Mobile layout", + "overlapping_blocks": "Overlapping blocks", + "page": "Page", + "page_content": "Content", + "page_layout": "Page layout", + "payment_icons": "Payment icons", + "policy_list": "Policy links", + "popovers": "Popovers", + "popup_link": "Popup link", + "predictive_search": "Search popover", + "predictive_search_empty": "Predictive search empty", + "price": "Price", + "prices": "Prices", + "primary_button": "Primary button", + "product": "Product", + "product_buy_buttons": "Buy buttons", + "product_card": "Product card", + "product_card_media": "Media", + "product_card_rendering": "Product card rendering", + "product_cards": "Product cards", + "product_description": "Description", + "product_grid": "Grid", + "product_grid_main": "Product grid", + "product_image": "Product image", + "product_information": "Product information", + "product_list": "Featured collection", + "product_list_button": "View all button", + "product_media": "Product media", + "product_price": "Price", + "product_recommendations": "Recommended products", + "product_review_stars": "Review stars", + "product_variant_picker": "Variant picker", + "products_carousel": "Featured collection: Carousel", + "products_editorial": "Featured collection: Editorial", + "products_grid": "Featured collection: Grid", + "product_inventory": "Product inventory", + "pull_quote": "Pull quote", + "quantity": "Quantity", + "read_only": "Read only", + "row": "Row", + "search": "Search", + "search_input": "Search input", + "search_results": "Search results", + "secondary_button": "Secondary button", + "section": "Section", + "selected_variants": "Selected variants", + "shop_the_look": "Shop the look", + "size": "Size", + "slide": "Slide", + "slideshow": "Slideshow", + "slideshow_controls": "Slideshow controls", + "social_link": "Social link", + "social_media_links": "Social media links", + "spacer": "Spacer", + "spacing": "Spacing", + "split_showcase": "Split showcase", + "steps": "Steps", + "styles": "Styles", + "submit_button": "Submit button", + "summary": "Summary", + "swatches": "Swatches", + "testimonials": "Testimonials", + "text": "Text", + "title": "Title", + "typography": "Typography", + "utilities": "Utilities", + "variant_pickers": "Variant pickers", + "variants": "Variants", + "video": "Video", + "video_section": "Video", + "view_all_button": "View all", + "pills": "Pills" + }, + "options": { + "above_carousel": "Above carousel", + "accent": "Accent", + "adapt_to_image": "Adapt to image", + "all": "All", + "always": "Always", + "apple": "Apple", + "arrow": "Arrow", + "arrows": "Arrows", + "arrows_large": "Large arrows", + "aspect_ratio": "Aspect ratio", + "auto": "Auto", + "balance": "Balance", + "banana": "Banana", + "below_image": "Below image", + "bento": "Bento", + "black": "Black", + "bluesky": "Bluesky", + "blur": "Blur", + "body": "Body", + "body_large": "Body (Large)", + "body_regular": "Body (Regular)", + "body_small": "Body (Small)", + "bold": "Bold", + "bottle": "Bottle", + "bottom": "Bottom", + "bottom_left": "Bottom left", + "bottom_right": "Bottom right", + "box": "Box", + "button": "Button", + "button_primary": "Primary button", + "button_secondary": "Secondary button", + "buttons": "Buttons", + "capitalize": "Capitalize", + "caption": "Caption", + "caret": "Caret", + "carousel": "Carousel", + "carrot": "Carrot", + "center": "Center", + "chat_bubble": "Chat bubble", + "check_box": "Check box", + "chevron": "Chevron", + "chevron_large": "Large chevrons", + "chevron_left": "Chevron left", + "chevron_right": "Chevron right", + "chevrons": "Chevrons", + "circle": "Circle", + "classic": "Classic", + "clipboard": "Clipboard", + "collection_images": "Collection images", + "color": "Color", + "compact": "Compact", + "complementary": "Complementary", + "contain": "Contain", + "counter": "Counter", + "cover": "Cover", + "crop_to_fit": "Crop to fit", + "custom": "Custom", + "dairy": "Dairy", + "dairy_free": "Dairy free", + "default": "Default", + "diamond": "Diamond", + "dissolve": "Dissolve", + "dots": "Dots", + "dotted": "Dotted", + "down": "Down", + "drawer": "Drawer", + "dropdowns": "Dropdowns", + "dryer": "Dryer", + "editorial": "Editorial", + "end": "End", + "extra_large": "Extra large", + "extra_small": "Extra small", + "eye": "Eye", + "facebook": "Facebook", + "featured_collections": "Featured collections", + "featured_products": "Featured products", + "fill": "Fill", + "fire": "Fire", + "fit": "Fit", + "fit_content": "Fit", + "fixed": "Fixed", + "font_primary": "Primary", + "font_secondary": "Secondary", + "font_tertiary": "Tertiary", + "forward": "Forward", + "full": "Full", + "full_and_page": "Full background, page-width content", + "full_and_page_offset_left": "Full background, page-width content, offset left", + "full_and_page_offset_right": "Full background, page-width content, offset right", + "full_screen": "Full screen", + "gluten_free": "Gluten free", + "gradient": "Gradient", + "grid": "Grid", + "h1": "Heading 1", + "h2": "Heading 2", + "h3": "Heading 3", + "h4": "Heading 4", + "h5": "Heading 5", + "h6": "Heading 6", + "heading": "Heading", + "heading_extra_large": "Heading (Extra large)", + "heading_extra_small": "Heading (Extra small)", + "heading_large": "Heading (Large)", + "heading_regular": "Heading (Regular)", + "heading_small": "Heading (Small)", + "heart": "Heart", + "heavy": "Heavy", + "hidden": "Hidden", + "hint": "Hint", + "horizontal": "Horizontal", + "icon": "Icon", + "image": "Image", + "input": "Input", + "inside_carousel": "Inside carousel", + "instagram": "Instagram", + "inverse_large": "Inverse large", + "inverse": "Inverse", + "iron": "Iron", + "landscape": "Landscape", + "large": "Large", + "large_arrows": "Large arrows", + "large_chevrons": "Large chevrons", + "leaf": "Leaf", + "leather": "Leather", + "left": "Left", + "lg": "LG", + "lift": "Lift", + "light": "Light", + "lightning_bolt": "Lightning bolt", + "link": "Link", + "linkedin": "LinkedIn", + "lipstick": "Lipstick", + "lock": "Lock", + "loose": "Loose", + "lowercase": "lowercase", + "m": "M", + "maintain_aspect_ratio": "Maintain aspect ratio", + "map_pin": "Map pin", + "media_first": "Media first", + "media_second": "Media second", + "medium": "Medium", + "modal": "Modal", + "narrow": "Narrow", + "never": "Never", + "next_to_carousel": "Next to carousel", + "none": "None", + "normal": "Normal", + "nowrap": "No wrap", + "numbers": "Numbers", + "nut_free": "Nut free", + "off": "Off", + "off_media": "Off media", + "offset_left": "Offset left", + "offset_right": "Offset right", + "on_image": "On image", + "on_media": "On media", + "on_scroll_up": "On scroll up", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "outline": "Outline", + "page": "Page", + "page_center_aligned": "Page, center aligned", + "page_left_aligned": "Page, left aligned", + "page_right_aligned": "Page, right aligned", + "pants": "Pants", + "paragraph": "Paragraph", + "parallelogram": "Parallelogram", + "paw_print": "Paw print", + "pepper": "Pepper", + "percent": "Percent", + "perfume": "Perfume", + "pill": "Pill", + "pills": "Pills", + "pinterest": "Pinterest", + "pixel": "Pixel", + "plane": "Plane", + "plant": "Plant", + "plus": "Plus", + "portrait": "Portrait", + "pretty": "Pretty", + "preview": "Preview", + "price": "Price", + "price_tag": "Price tag", + "primary": "Primary", + "primary_style": "Primary style", + "question_mark": "Question mark", + "rectangle": "Rectangle", + "recycle": "Recycle", + "regular": "Regular", + "related": "Related", + "return": "Return", + "reveal": "Reveal", + "reverse": "Reverse", + "rich_text": "Rich text", + "right": "Right", + "rounded": "Rounded", + "ruler": "Ruler", + "s": "S", + "scale": "Scale", + "secondary": "Secondary", + "secondary_style": "Secondary style", + "semibold": "Semibold", + "sentence": "Sentence", + "serving_dish": "Serving dish", + "shaded": "Shaded", + "shirt": "Shirt", + "shoe": "Shoe", + "show_second_image": "Show second image", + "silhouette": "Silhouette", + "single": "Single", + "slide_left": "Slide left", + "slide_up": "Slide up", + "small": "Small", + "snapchat": "Snapchat", + "snowflake": "Snowflake", + "social_bluesky": "Social: Bluesky", + "social_facebook": "Social: Facebook", + "social_instagram": "Social: Instagram", + "social_linkedin": "Social: LinkedIn", + "social_pinterest": "Social: Pinterest", + "social_snapchat": "Social: Snapchat", + "social_spotify": "Social: Spotify", + "social_threads": "Social: Threads", + "social_tiktok": "Social: TikTok", + "social_tumblr": "Social: Tumblr", + "social_twitter": "Social: X (Twitter)", + "social_whatsapp": "Social: WhatsApp", + "social_vimeo": "Social: Vimeo", + "social_youtube": "Social: YouTube", + "solid": "Solid", + "space_between": "Space between", + "spotify": "Spotify", + "spotlight": "Spotlight", + "square": "Square", + "stack": "Stack", + "standard": "Standard", + "star": "Star", + "start": "Start", + "stopwatch": "Stopwatch", + "subheading": "Subheading", + "subtle_zoom": "Zoom", + "swatches": "Swatches", + "tertiary": "Tertiary", + "text": "Text", + "text_only": "Text only", + "thin": "Thin", + "threads": "Threads", + "thumbnails": "Thumbnails", + "tight": "Tight", + "tiktok": "TikTok", + "top": "Top", + "top_left": "Top left", + "top_right": "Top right", + "truck": "Truck", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Underline", + "up": "Up", + "uppercase": "Uppercase", + "vertical": "Vertical", + "video": "Video", + "video_external_url": "External URL", + "video_uploaded": "Uploaded", + "vimeo": "Vimeo", + "washing": "Washing", + "wide": "Wide", + "youtube": "YouTube" + }, + "settings": { + "accordion": "Accordion", + "account": "Account", + "alignment": "Alignment", + "alignment_mobile": "Mobile alignment", + "align_baseline": "Align text baseline", + "animation_repeat": "Repeat animation", + "add_discount_code": "Allow discounts in cart", + "always_stack_buttons": "Always stack buttons", + "aspect_ratio": "Aspect ratio", + "auto_rotate_announcements": "Auto-rotate announcements", + "auto_rotate_slides": "Auto-rotate slides", + "autoplay": "Autoplay", + "background": "Background", + "background_color": "Background color", + "background_overlay": "Background overlay", + "badge_corner_radius": "Corner radius", + "background_media": "Background media", + "badge_position": "Position on cards", + "badge_sale_color_scheme": "Sale", + "badge_sold_out_color_scheme": "Sold out", + "behavior": "Behavior", + "blur": "Shadow blur", + "blurred_reflection": "Blurred reflection", + "border": "Border", + "border_opacity": "Border opacity", + "border_radius": "Corner radius", + "border_style": "Border style", + "border_thickness": "Border thickness", + "border_width": "Border thickness", + "borders": "Borders", + "bottom": "Bottom", + "bottom_row": "Bottom row", + "bottom_padding": "Bottom padding", + "button": "Button", + "button_text_case": "Text case", + "button_text_weight": "Text weight", + "card_hover_effect": "Card hover effect", + "card_image_height": "Product image height", + "card_size": "Card size", + "carousel_on_mobile": "Carousel on mobile", + "cart_count": "Cart count", + "cart_items": "Cart items", + "cart_related_products": "Related products", + "cart_title": "Cart", + "cart_total": "Cart total", + "cart_type": "Type", + "auto_open_cart_drawer": "\"Add to cart\" auto-opens drawer", + "case": "Case", + "checkout_buttons": "Accelerated checkout buttons", + "collection": "Collection", + "collection_count": "Collection count", + "collection_list": "Collections", + "collection_templates": "Collection templates", + "collection_title_case": "Collection title case", + "color": "Color", + "color_scheme": "Color scheme", + "colors": "Colors", + "columns": "Columns", + "content": "Content", + "content_alignment": "Content alignment", + "content_direction": "Content direction", + "content_position": "Content position", + "content_width": "Content width", + "corner_radius": "Corner radius", + "country_region": "Country/Region", + "cover_image": "Cover image", + "cover_image_size": "Cover image size", + "currency_code": "Currency code", + "custom_height": "Custom height", + "custom_minimum_height": "Custom minimum height", + "custom_mobile_size": "Custom mobile size", + "custom_mobile_width": "Custom mobile width", + "custom_width": "Custom width", + "custom_liquid": "Liquid code", + "default": "Default", + "default_logo": "Default logo", + "desktop_height": "Desktop height", + "direction": "Direction", + "display": "Display", + "divider": "Divider", + "divider_color": "Divider", + "divider_thickness": "Divider thickness", + "divider_width": "Divider width", + "dividers": "Dividers", + "drop_shadow": "Drop shadow", + "effects": "Effects", + "empty_state_collection": "Empty state collection", + "empty_state_collection_info": "Shown before a search is entered", + "enable_filtering": "Filters", + "enable_grid_density": "Grid layout control", + "enable_sorting": "Sorting", + "enable_sticky_content": "Sticky content on desktop", + "enable_video_looping": "Video looping", + "enable_zoom": "Enable zoom", + "equal_columns": "Equal columns", + "error_color": "Error", + "expand_first_group": "Expand first group", + "extend_media_to_screen_edge": "Extend media to screen edge", + "extend_summary": "Extend to screen edge", + "extra_large": "Extra large", + "extra_small": "Extra small", + "favicon": "Favicon", + "filter_style": "Filter style", + "first_row_media_position": "First row media position", + "fixed_height": "Pixel height", + "fixed_width": "Pixel width", + "flag": "Flag", + "font": "Font", + "font_family": "Font family", + "font_price": "Price font", + "font_weight": "Font weight", + "full_width_first_image": "Full width first image", + "full_width_on_mobile": "Full width on mobile", + "gap": "Gap", + "geometric_translate_y": "Geometric translate Y", + "gradient_direction": "Gradient direction", + "heading": "Heading", + "heading_preset": "Heading preset", + "headings": "Headings", + "height": "Height", + "hide_logo_on_home_page": "Hide logo on home page", + "hide_padding": "Hide padding", + "hide_unselected_variant_media": "Hide unselected variant media", + "horizontal_gap": "Horizontal gap", + "horizontal_offset": "Shadow horizontal offset", + "horizontal_padding": "Horizontal padding", + "hover_background": "Hover background", + "hover_behavior": "Hover behavior", + "hover_borders": "Hover borders", + "hover_text": "Hover text", + "icon": "Icon", + "icon_background": "Icon background", + "icons": "Icons", + "image": "Image", + "image_border_radius": "Image corner radius", + "image_gap": "Image gap", + "image_icon": "Image icon", + "image_opacity": "Image opacity", + "image_position": "Image position", + "image_ratio": "Image ratio", + "inherit_color_scheme": "Inherit color scheme", + "inventory_threshold": "Low stock threshold", + "inverse": "Inverse", + "inverse_logo": "Inverse logo", + "installments": "Installments", + "integrated_button": "Integrated button", + "items_to_show": "Items to show", + "label": "Label", + "language_selector": "Language selector", + "large": "Large", + "layout": "Layout", + "layout_gap": "Layout gap", + "layout_style": "Style", + "layout_type": "Type", + "left": "Left", + "left_padding": "Left padding", + "length": "Length", + "letter_spacing": "Letter spacing", + "limit_content_width": "Limit content width", + "limit_media_to_screen_height": "Constrain to screen height", + "limit_product_details_width": "Limit product details width", + "line_height": "Line height", + "link": "Link", + "link_preset": "Link preset", + "links": "Links", + "logo": "Logo", + "logo_font": "Logo font", + "loop": "Loop", + "make_details_sticky_desktop": "Sticky on desktop", + "make_section_full_width": "Make section full width", + "max_width": "Max width", + "media": "Media", + "media_fit": "Media fit", + "media_height": "Media height", + "media_overlay": "Media overlay", + "media_position": "Media position", + "media_type": "Media type", + "media_width": "Media width", + "menu": "Menu", + "minimum_height": "Minimum height", + "mobile_card_size": "Mobile card size", + "mobile_columns": "Mobile columns", + "mobile_height": "Mobile height", + "mobile_logo_image": "Mobile logo", + "mobile_pagination": "Mobile pagination", + "mobile_quick_add": "Mobile quick add", + "motion": "Motion", + "motion_direction": "Motion direction", + "movement_direction": "Movement direction", + "navigation": "Navigation", + "navigation_bar": "Navigation bar", + "navigation_bar_color_scheme": "Navigation bar color scheme", + "opacity": "Opacity", + "open_new_tab": "Open link in new tab", + "open_row_by_default": "Open row by default", + "overlay": "Overlay", + "overlay_color": "Overlay color", + "overlay_opacity": "Overlay opacity", + "overlay_style": "Overlay style", + "padding": "Padding", + "padding_bottom": "Padding bottom", + "padding_horizontal": "Padding horizontal", + "padding_top": "Padding top", + "page": "Page", + "page_transition_enabled": "Page transition", + "page_width": "Page width", + "pagination": "Pagination", + "percent_height": "Percent height", + "percent_size": "Percent size", + "percent_size_mobile": "Percent size", + "percent_width": "Percent width", + "pixel_size": "Pixel size", + "pixel_size_mobile": "Pixel size", + "placement": "Placement", + "position": "Position", + "preset": "Preset", + "primary_button_background": "Primary button background", + "primary_button_border": "Primary button border", + "primary_button_text": "Primary button text", + "primary_color": "Links", + "primary_font": "Primary font", + "primary_hover_color": "Hover links", + "product": "Product", + "product_and_card_title_case": "Product and card title case", + "product_card_carousel": "Show carousel", + "product_cards": "Product cards", + "product_count": "Product count", + "product_pages": "Product pages", + "product_templates": "Product templates", + "product_title_case": "Product title case", + "product_type": "Product type", + "products": "Products", + "quick_add": "Quick add", + "quick_add_colors": "Quick add colors", + "ratio": "Ratio", + "read_only": "Read only", + "reflection_opacity": "Reflection opacity", + "regular": "Regular", + "review_count": "Review count", + "right": "Right", + "right_padding": "Right padding", + "row": "Row", + "scroll_speed": "Time to next announcement", + "search": "Search", + "search_icon": "Search icon", + "search_position": "Position", + "search_row": "Row", + "row_height": "Row height", + "secondary_button_background": "Secondary button background", + "secondary_button_border": "Secondary button border", + "secondary_button_text": "Secondary button text", + "secondary_font": "Secondary font", + "section_width": "Section width", + "seller_note": "Allow note to seller", + "shadow_color": "Shadow", + "shadow_opacity": "Shadow opacity", + "shape": "Shape", + "show": "Show", + "show_as_accordion": "Show as accordion on mobile", + "show_author": "Author", + "show_alignment": "Show alignment", + "show_count": "Show count", + "show_date": "Date", + "show_filter_label": "Text labels for applied filters", + "show_grid_layout_selector": "Show grid layout selector", + "show_inventory_quantity": "Show low stock quantity", + "show_pickup_availability": "Show pickup availability", + "show_sale_price_first": "Show sale price first", + "show_search": "Show search", + "show_second_image_on_hover": "Show second image on hover", + "show_swatch_label": "Text labels for swatches", + "show_tax_info": "Tax information", + "size": "Size", + "size_mobile": "Mobile size", + "slide_spacing": "Slide gap", + "slide_width": "Slide width", + "slideshow_fullwidth": "Full width slides", + "small": "Small", + "speed": "Speed", + "statement": "Statement", + "sticky_header": "Sticky header", + "stroke": "Stroke", + "style": "Style", + "success_color": "Success", + "swatches": "Swatches", + "tertiary_font": "Tertiary font", + "text": "Text", + "text_case": "Case", + "text_hierarchy": "Text hierarchy", + "text_label_case": "Text label case", + "text_presets": "Text presets", + "thickness": "Thickness", + "title": "Title", + "top": "Top", + "top_padding": "Top padding", + "transition_to_main_product": "Product card to product page transition", + "transparent_background": "Transparent background", + "type": "Type", + "type_preset": "Text preset", + "underline_thickness": "Underline thickness", + "unit": "Unit", + "use_inverse_logo": "Use inverse logo", + "variant_images": "Variant images", + "vendor": "Vendor", + "vertical_gap": "Vertical gap", + "vertical_offset": "Shadow vertical offset", + "vertical_on_mobile": "Vertical on mobile", + "vertical_padding": "Vertical padding", + "video": "Video", + "video_alt_text": "Alt text", + "video_autoplay": "Autoplay", + "video_cover_image": "Cover image", + "video_external_url": "URL", + "video_loop": "Loop video", + "video_position": "Video position", + "video_source": "Source", + "view_all_as_last_card": "\"View all\" as last card", + "view_more_show": "Show View more button", + "visibility": "Visibility", + "weight": "Weight", + "width": "Width", + "width_desktop": "Desktop width", + "width_mobile": "Mobile width", + "wrap": "Wrap", + "z_index": "Z-index", + "product_corner_radius": "Product corner radius", + "card_corner_radius": "Card corner radius" + }, + "text_defaults": { + "accordion_heading": "Accordion heading", + "be_bold": "Be bold.", + "button_label": "Shop now", + "collapsible_row": "Collapsible row", + "contact_form_button_label": "Submit", + "email_signup_button_label": "Subscribe", + "heading": "Heading", + "popup_link": "Popup link", + "sign_up": "Sign up", + "shop_our_latest_arrivals": "Shop our latest arrivals!", + "welcome_to_our_store": "Welcome to our store" + } +} diff --git a/locales/es.json b/locales/es.json new file mode 100644 index 000000000..48e871ad3 --- /dev/null +++ b/locales/es.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Cargar video: {{ description }}", + "sold_out": "Agotado", + "email_signup": { + "label": "Correo electrónico", + "placeholder": "Dirección de correo electrónico", + "success": "¡Gracias por suscribirte!" + }, + "filter": "Filtro", + "payment_methods": "Formas de pago", + "contact_form": { + "name": "Nombre", + "email": "Correo electrónico", + "phone": "Teléfono", + "comment": "Comentario", + "post_success": "Gracias por contactarnos. Te responderemos lo antes posible.", + "error_heading": "Realiza los ajustes siguientes:" + } + }, + "accessibility": { + "play_model": "Reproducir el modelo 3D", + "play_video": "Reproducir el video", + "unit_price": "Precio unitario", + "country_results_count": "{{ count }} resultados", + "slideshow_pause": "Pausar la presentación de diapositivas", + "slideshow_play": "Reproducir la presentación de diapositivas", + "remove_item": "Eliminar {{ title}}", + "skip_to_text": "Ir directamente al contenido", + "skip_to_product_info": "Ir directamente a la información del producto", + "skip_to_results_list": "Omitir para ir a lista de resultados", + "new_window": "Se abre en una ventana nueva.", + "slideshow_next": "Siguiente diapositiva", + "slideshow_previous": "Diapositiva anterior", + "close_dialog": "Cerrar diálogo", + "reset_search": "Restablecer la búsqueda", + "search_results_count": "{{ count }} resultados de búsqueda para \"{{ query }}\"", + "search_results_no_results": "No se encontraron resultados para \"{{ query }}\"", + "filters": "Filtros", + "filter_count": { + "one": "{{ count }} filtro aplicado", + "other": "{{ count }} filtros aplicados", + "many": "{{ count }} filtros aplicados" + }, + "account": "Abrir menú de cuenta", + "cart": "Carrito", + "cart_count": "Total de artículos en el carrito", + "menu": "Menú", + "country_region": "País o región", + "slide_status": "Diapositiva {{ index }} de {{ length }}", + "scroll_to": "Desplázate a {{ title }}", + "loading_product_recommendations": "Carga de recomendaciones de productos", + "discount": "Aplicar un código de descuento", + "discount_applied": "Aplicar código de descuento: {{ code }}", + "open_cart_drawer": "Abrir carrito", + "pause_video": "Pausar el video", + "inventory_status": "Estado del inventario", + "find_country": "Buscar país", + "localization_region_and_language": "Abrir selector de región e idioma", + "open_search_modal": "Abrir búsqueda", + "decrease_quantity": "Disminuir cantidad", + "increase_quantity": "Aumentar cantidad", + "quantity": "Cantidad", + "rating": "La calificación de este producto es {{ rating }} de 5", + "nested_product": "{{ product_title }} para {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Agregar al carrito", + "clear_all": "Borrar todo", + "remove": "Eliminar", + "view_in_your_space": "Ver en tu espacio", + "show_filters": "Filtro", + "clear": "Borrar", + "continue_shopping": "Seguir comprando", + "log_in_html": "¿Tienes una cuenta? Inicia sesión para pagar más rápido.", + "see_items": { + "one": "Ver {{ count }} artículo", + "other": "Ver {{ count }} artículos", + "many": "Ver {{ count }} artículos" + }, + "view_all": "Ver todo", + "add": "Añadir", + "choose": "Elegir", + "added": "Agregada", + "show_less": "Mostrar menos", + "show_more": "Mostrar más", + "close": "Cerrar", + "more": "Más", + "reset": "Restablecer", + "zoom": "Ampliar", + "close_dialog": "Cerrar diálogo", + "submit": "Enviar", + "back": "Atrás", + "log_in": "Iniciar sesión", + "log_out": "Cerrar sesión", + "remove_discount": "Eliminar el descuento {{ code }}", + "enter_using_password": "Entrar con contraseña", + "enter_password": "Introducir la contraseña", + "view_store_information": "Ver la información de la tienda", + "apply": "Aplicar", + "open_image_in_full_screen": "Abrir imagen a pantalla completa", + "sign_in_options": "Otras opciones de inicio de sesión", + "sign_up": "Registrarse", + "sort": "Ordenar", + "show_all_options": "Mostrar todas las opciones" + }, + "content": { + "reviews": "reseñas", + "language": "Idioma", + "localization_region_and_language": "Región e idioma", + "no_results_found": "No se han encontrado resultados", + "cart_total": "Total del carrito", + "your_cart_is_empty": "Tu carrito esta vacío", + "product_image": "Imagen del producto", + "product_information": "Información del producto", + "quantity": "Cantidad", + "product_total": "Total del producto", + "cart_estimated_total": "Total estimado", + "seller_note": "Instrucciones especiales", + "cart_subtotal": "Subtotal", + "discounts": "Descuentos", + "discount": "Descuento", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Aranceles e impuestos incluidos. Descuentos y envío calculados en la página de pago.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Aranceles e impuestos incluidos. Descuentos y envío calculados en la pantalla de pago.", + "taxes_included_shipping_at_checkout_with_policy_html": "Impuestos incluidos. Descuentos y envío calculados en la página de pago.", + "taxes_included_shipping_at_checkout_without_policy": "Impuestos incluidos. Descuentos y envío calculados en la pantalla de pago.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Aranceles incluidos. Impuestos, descuentos y envío calculados en la página de pago.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Aranceles incluidos. Impuestos, descuentos y envío calculados en la página de pago.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Impuestos, descuentos y envío calculados en la página de pago.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Impuestos, descuentos y envío calculados en la página de pago.", + "checkout": "Pagar", + "cart_title": "Carrito", + "price": "Precio", + "price_regular": "Precio habitual", + "price_compare_at": "Precio de comparación", + "price_sale": "Precio de oferta", + "duties_and_taxes_included": "Aranceles e impuestos incluidos.", + "duties_included": "Aranceles incluidos.", + "shipping_policy_html": "Los gastos de envío se calculan en la página de pago.", + "taxes_included": "Impuestos incluidos.", + "product_badge_sold_out": "Agotado", + "product_badge_sale": "Oferta", + "grid_view": { + "default_view": "Predeterminado", + "grid_fieldset": "Columna de cuadrícula", + "single_item": "Única", + "zoom_out": "Alejar" + }, + "search_input_label": "Buscar", + "search_input_placeholder": "Buscar", + "search_results": "Resultados de la búsqueda", + "search_results_label": "Resultados de la búsqueda", + "search_results_no_results": "No se encontró ningún resultado para \"{{ terms }}\". Prueba con otra búsqueda.", + "search_results_resource_articles": "Artículos del blog", + "search_results_resource_collections": "Colecciones", + "search_results_resource_pages": "Páginas", + "search_results_resource_products": "Productos", + "search_results_resource_queries": "Sugerencias de búsqueda", + "search_results_view_all": "Ver todo", + "search_results_view_all_button": "Ver todo", + "search_results_resource_products_count": { + "one": "{{ count }} producto", + "other": "{{ count }} productos", + "many": "{{ count }} productos" + }, + "recently_viewed_products": "Visto recientemente", + "unavailable": "No disponible", + "collection_placeholder": "Título de la colección", + "product_card_placeholder": "Nombre del producto", + "product_count": "Recuento de productos", + "item_count": { + "one": "{{ count }} artículo", + "other": "{{ count }} artículos", + "many": "{{ count }} artículos" + }, + "errors": "Errores", + "search": "Buscar", + "search_results_no_results_check_spelling": "No se encontró ningún resultado para \"{{ terms }}\". Revisa la ortografía o usa una palabra o frase diferente.", + "no_products_found": "No se encontró ningún producto.", + "price_from": "Desde {{ price }}", + "use_fewer_filters_html": "Prueba a utilizar menos filtros o elimina todos los filtros.", + "featured_products": "Productos destacados", + "filters": "Filtros", + "price_filter_html": "El precio más alto es {{ price }}", + "blog_details_separator": "|", + "read_more": "Leer más...", + "account_title": "Cuenta", + "account_title_personalized": "Hola, {{ first_name }}:", + "account_orders": "Pedidos", + "account_profile": "Perfil", + "discount_code": "Código de descuento", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Aranceles e impuestos incluidos. Los gastos de envío se calculan en la página de pago.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Aranceles e impuestos incluidos. Los gastos de envío se calculan en la página de pago.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Aranceles incluidos. Los gastos de envío se calculan en la página de pago.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Aranceles incluidos. Los gastos de envío se calculan en la página de pago.", + "pickup_available_at_html": "Retiro disponible en {{ location }}", + "pickup_available_in": "Retiro disponible, {{ pickup_time }}", + "pickup_not_available": "El retiro no está disponible actualmente", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Los impuestos y los gastos de envío se calculan en la página de pago.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Los impuestos y los gastos de envío se calculan en la página de pago.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Impuestos incluidos. Los gastos de envío se calculan en la página de pago.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Impuestos incluidos. Los gastos de envío se calculan en la página de pago.", + "wrong_password": "Contraseña incorrecta", + "view_more_details": "Ver más información", + "page_placeholder_title": "Título de la página", + "page_placeholder_content": "Selecciona una página para mostrar su contenido.", + "placeholder_image": "Imagen marcadora de posición", + "powered_by": "Esta tienda contará con tecnología de", + "store_owner_link_html": "¿Esta tienda es tuya? Inicia sesión aquí", + "shipping_discount_error": "Los descuentos de envío se muestran en la pantalla de pago tras agregar una dirección", + "discount_code_error": "El código de descuento no se puede aplicar a tu carrito", + "inventory_low_stock": "Bajas existencias", + "inventory_in_stock": "En existencias", + "inventory_out_of_stock": "Agotado", + "shipping_policy": "Envío calculado en el pago.", + "inventory_low_stock_show_count": { + "one": "{{ count }} restante", + "other": "{{ count }} restantes", + "many": "{{ count }} restantes" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Usar el código de la tarjeta de regalo online o el código QR en la tienda", + "title": "Este es el saldo de tu tarjeta de regalo de {{ value }} para {{ shop }}.", + "subtext": "Tu tarjeta de regalo", + "shop_link": "Visitar la tienda online", + "add_to_apple_wallet": "Agregar a Apple Wallet", + "qr_image_alt": "Código QR — escanea para canjear la tarjeta de regalo", + "copy_code": "Copiar el código de la tarjeta de regalo", + "expiration_date": "Caduca el {{ expires_on }}", + "copy_code_success": "El código se copió correctamente", + "expired": "Vencida" + } + }, + "placeholders": { + "password": "Contraseña", + "search": "Buscar", + "product_title": "Nombre del producto", + "collection_title": "Título de la colección" + }, + "products": { + "product": { + "add_to_cart": "Agregar al carrito", + "added_to_cart": "Agregado al carrito", + "adding_to_cart": "Agregando...", + "add_to_cart_error": "Error al agregar al carrito", + "sold_out": "Agotado", + "unavailable": "No disponible" + } + }, + "fields": { + "separator": "a" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} comentario", + "other": "{{ count }} comentarios", + "many": "{{ count }} comentarios" + } + }, + "comment_form": { + "email": "Correo electrónico", + "error": "No se pudo publicar el comentario. Corrige lo siguiente:", + "heading": "Dejar un comentario", + "message": "Mensaje", + "moderated": "Ten en cuenta que los comentarios deben aprobarse antes de que se publiquen.", + "name": "Nombre", + "post": "Publicar comentario", + "success_moderated": "Comentario publicado y a la espera de moderación", + "success": "Comentario publicado" + } + } +} diff --git a/locales/es.schema.json b/locales/es.schema.json new file mode 100644 index 000000000..0b8c426f9 --- /dev/null +++ b/locales/es.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Bordes", + "collapsible_row": "Fila desplegable", + "colors": "Colores", + "custom_section": "Sección personalizada", + "icon": "Ícono", + "logo_and_favicon": "Logo y favicon", + "overlapping_blocks": "Bloques solapados", + "product_buy_buttons": "Botones de compra", + "product_description": "Descripción", + "product_price": "Precio", + "product_variant_picker": "Selector de variante", + "slideshow": "Diapositivas", + "typography": "Tipografía", + "video": "Video", + "slideshow_controls": "Controles de la presentación de diapositivas", + "size": "Talla", + "spacing": "Espaciado", + "product_recommendations": "Productos recomendados", + "product_media": "Elementos multimedia del producto", + "featured_collection": "Colección destacada", + "add_to_cart": "Agregar al carrito", + "email_signup": "Suscriptor de correo electrónico", + "submit_button": "Botón de enviar", + "grid_layout_selector": "Selector de grid layout", + "image": "Imagen", + "list_items": "Artículos de la lista", + "facets": "Facetas", + "variants": "Variantes", + "styles": "Estilos", + "product_cards": "Tarjetas de producto", + "primary_button": "Botón principal", + "secondary_button": "Botón secundario", + "popovers": "Elementos emergentes", + "buttons": "Botones", + "inputs": "Entradas", + "marquee": "Marquesina", + "alternating_content_rows": "Filas alternantes", + "product_list": "Colección destacada", + "spacer": "Separador", + "pull_quote": "Cita destacada", + "contact_form": "Formulario de contacto", + "featured_product": "Aspecto destacado del producto", + "icons_with_text": "Ícono con texto", + "accelerated_checkout": "Proceso de pago acelerado", + "accordion": "Acordeón", + "accordion_row": "Fila del acordeón", + "animations": "Animaciones", + "announcement": "Anuncio", + "announcement_bar": "Barra de anuncios", + "badges": "Emblemas", + "button": "Botón", + "cart": "Carrito", + "cart_items": "Artículos en el carrito", + "cart_products": "Productos en el carrito", + "cart_title": "Carrito", + "collection": "Colección", + "collection_card": "Tarjeta de la colección", + "collection_columns": "Columnas de la colección", + "collection_container": "Colección", + "collection_description": "Descripción de la colección", + "collection_image": "Imagen de la colección", + "collection_info": "Información de la colección", + "collection_list": "Lista de colecciones", + "collections": "Colecciones", + "content": "Contenido", + "content_grid": "Contenido de la cuadrícula", + "details": "Información", + "divider": "Divisor", + "filters": "Filtrado y ordenado", + "follow_on_shop": "Seguir en Shop", + "footer": "Pie de página", + "footer_utilities": "Utilidades del pie de página", + "group": "Grupo", + "header": "Encabezado", + "heading": "Encabezado", + "icons": "Íconos", + "image_with_text": "Imagen con texto", + "input": "Información", + "logo": "Logo", + "magazine_grid": "Cuadrícula de revista", + "media": "Elementos multimedia", + "menu": "Menú", + "mobile_layout": "Diseño móvil", + "payment_icons": "Íconos de pago", + "popup_link": "Enlace emergente", + "predictive_search": "Ventana emergente de búsqueda", + "predictive_search_empty": "Búsqueda predictiva vacía", + "price": "Precio", + "product": "Producto", + "product_card": "Tarjeta del producto", + "product_card_media": "Elementos multimedia", + "product_card_rendering": "Renderizado de la tarjeta del producto", + "product_grid": "Cuadrícula", + "product_grid_main": "Cuadrícula del producto", + "product_image": "Imagen del producto", + "product_information": "Información del producto", + "product_review_stars": "Revisar las estrellas", + "quantity": "Cantidad", + "row": "Fila", + "search": "Buscar", + "section": "Sección", + "selected_variants": "Variantes seleccionadas", + "shop_the_look": "Comprar el look", + "slide": "Diapositiva", + "social_media_links": "Enlaces de redes sociales", + "steps": "Pasos", + "summary": "Resumen", + "swatches": "Muestras", + "testimonials": "Testimonios", + "text": "Texto", + "title": "Título", + "utilities": "Utilidades", + "search_input": "Buscar entrada", + "search_results": "Resultados de la búsqueda", + "read_only": "Solo lectura", + "collections_bento": "Lista de colecciones: Bento", + "faq_section": "Preguntas frecuentes", + "hero": "Hero", + "jumbo_text": "Texto de Jumbo", + "video_section": "Video", + "custom_liquid": "Liquid personalizado", + "blog": "Blog", + "blog_post": "Artículo del blog", + "blog_posts": "Artículos del blog", + "caption": "Leyenda", + "collection_card_image": "Imagen", + "collection_title": "Título de la colección", + "collection_links": "Enlaces de la colección", + "collection_links_spotlight": "Enlaces de colecciones: Spotlight", + "collection_links_text": "Enlaces de colecciones: texto", + "collections_carousel": "Lista de colecciones: carrusel", + "collections_editorial": "Lista de colecciones: Editorial", + "collections_grid": "Lista de colecciones: cuadrícula", + "copyright": "Derechos de autor", + "count": "Recuento", + "divider_section": "Divisor", + "drawers": "Cajones", + "editorial": "Editorial", + "editorial_jumbo_text": "Editorial: texto de Jumbo", + "hero_marquee": "Hero: marquesina", + "input_fields": "Campos de entrada", + "local_pickup": "Retiro en tienda", + "marquee_section": "Marquesina", + "media_with_text": "Multimedia con texto", + "page": "Página", + "page_content": "Contenido", + "page_layout": "Diseño de página", + "policy_list": "Enlaces a la política", + "prices": "Precios", + "products_carousel": "Colección destacada: Carrusel", + "products_editorial": "Colección destacada: Editorial", + "products_grid": "Colección destacada: Cuadrícula", + "social_link": "Enlace a redes sociales", + "split_showcase": "Dividir presentación", + "variant_pickers": "Selectores de variante", + "view_all_button": "Ver todo", + "product_title": "Nombre del producto", + "large_logo": "Logo grande", + "product_list_button": "Botón Ver todo", + "product_inventory": "Inventario de productos", + "pills": "Cápsulas", + "description": "Descripción" + }, + "settings": { + "alignment": "Alineación", + "autoplay": "Reproducción automática", + "background": "Fondo", + "border_radius": "Radio de esquina", + "border_width": "Grosor del borde", + "borders": "Bordes", + "bottom_padding": "Relleno inferior", + "button": "Botón", + "color": "Color", + "colors": "Colores", + "content_alignment": "Alineación de contenido", + "content_direction": "Dirección del contenido", + "content_position": "Posición del contenido", + "cover_image_size": "Tamaño de la imagen de portada", + "cover_image": "Imagen de portada", + "custom_minimum_height": "Altura mínima personalizada", + "custom_width": "Ancho personalizado", + "enable_video_looping": "Reproducción de video en bucle", + "favicon": "Favicon", + "font_family": "Familia de fuentes", + "gap": "Espacio", + "geometric_translate_y": "Traslación Y geométrica", + "heading": "Encabezado", + "icon": "Ícono", + "image": "Imagen", + "image_icon": "Ícono de imagen", + "image_opacity": "Opacidad de la imagen", + "image_position": "Posición de la imagen", + "image_ratio": "Relación de aspecto de imagen", + "label": "Etiqueta", + "line_height": "Altura de línea", + "link": "Enlace", + "layout_gap": "Espacio de diseño", + "make_section_full_width": "Definir ancho completo en la sección", + "minimum_height": "Altura mínima", + "opacity": "Opacidad", + "overlay_opacity": "Opacidad superpuesta", + "padding": "Relleno", + "primary_color": "Enlaces", + "product": "Producto", + "section_width": "Ancho de sección", + "size": "Tamaño", + "slide_spacing": "Espacio entre diapositivas", + "slide_width": "Ancho de diapositiva", + "slideshow_fullwidth": "Diapositivas de ancho completo", + "style": "Estilo", + "text": "Texto", + "text_case": "Caso", + "top_padding": "Relleno superior", + "video": "Video", + "video_alt_text": "Texto alternativo", + "video_loop": "Video en bucle", + "video_position": "Posición del video", + "width": "Anchura", + "z_index": "Índice Z", + "limit_content_width": "Ancho límite del contenido", + "color_scheme": "Esquema de colores", + "inherit_color_scheme": "Heredar esquema de colores", + "product_count": "Conteo de productos", + "product_type": "Tipo de producto", + "content_width": "Ancho del contenido", + "collection": "Colección", + "enable_sticky_content": "Contenido fijo en el escritorio", + "error_color": "Error", + "success_color": "Correcto", + "primary_font": "Fuente principal", + "secondary_font": "Fuente secundaria", + "tertiary_font": "Fuente terciaria", + "columns": "Columnas", + "items_to_show": "Artículos que mostrar", + "layout": "Diseño", + "layout_type": "Tipo", + "show_grid_layout_selector": "Mostrar el selector de grid layout", + "view_more_show": "Mostrar el botón Ver más", + "image_gap": "Separación entre imágenes", + "width_desktop": "Anchura del escritorio", + "width_mobile": "Anchura de móvil", + "border_style": "Estilo de borde", + "height": "Altura", + "thickness": "Grosor", + "stroke": "Trazo", + "filter_style": "Filtrar por estilo", + "swatches": "Muestras", + "quick_add_colors": "Colores de agregado rápido", + "divider_color": "Divisor", + "border_opacity": "Opacidad del borde", + "hover_background": "Color del fondo al pasar el cursor", + "hover_borders": "Color de los bordes al pasar el cursor", + "hover_text": "Color del texto al pasar el cursor", + "primary_hover_color": "Color de los enlaces al pasar el cursor", + "primary_button_text": "Texto del botón principal", + "primary_button_background": "Fondo del botón principal", + "primary_button_border": "Borde del botón principal", + "secondary_button_text": "Texto del botón secundario", + "secondary_button_background": "Fondo del botón secundario", + "secondary_button_border": "Borde del botón secundario", + "shadow_color": "Sombra", + "background_color": "Color de fondo", + "video_autoplay": "Reproducción automática", + "video_cover_image": "Imagen de portada", + "video_external_url": "URL", + "video_source": "Fuente", + "first_row_media_position": "Posición del elemento multimedia en primera fila", + "hide_padding": "Ocultar relleno", + "size_mobile": "Tamaño del móvil", + "pixel_size_mobile": "Tamaño del píxel", + "percent_size_mobile": "Tamaño del porcentaje", + "unit": "Unidad", + "custom_mobile_size": "Tamaño de móvil personalizado", + "fixed_height": "Altura del píxel", + "fixed_width": "Ancho del píxel", + "percent_height": "Altura del porcentaje", + "percent_width": "Ancho del porcentaje", + "percent_size": "Tamaño del porcentaje", + "pixel_size": "Tamaño del píxel", + "accordion": "Acordeón", + "aspect_ratio": "Relación de aspecto", + "auto_rotate_announcements": "Rotar anuncios automáticamente", + "auto_rotate_slides": "Rotar las diapositivas automáticamente", + "badge_corner_radius": "Radio de esquina", + "badge_position": "Posición en las tarjetas", + "badge_sale_color_scheme": "Oferta", + "badge_sold_out_color_scheme": "Agotado", + "behavior": "Comportamiento", + "blur": "Sombreado difuminado", + "border": "Borde", + "bottom": "Abajo", + "card_image_height": "Altura de la imagen del producto", + "carousel_on_mobile": "Carrusel en móvil", + "cart_count": "Conteo del carrito", + "cart_items": "Artículos en el carrito", + "cart_related_products": "Productos relacionados", + "cart_title": "Carrito", + "cart_total": "Total del carrito", + "cart_type": "Tipo", + "case": "Caso", + "checkout_buttons": "Botones de proceso de pago acelerado", + "collection_list": "Colecciones", + "collection_templates": "Plantilla de colección", + "content": "Contenido", + "corner_radius": "Radio de esquina", + "country_region": "País o región", + "currency_code": "Código de moneda", + "custom_height": "Altura personalizada", + "desktop_height": "Altura del escritorio", + "direction": "Dirección", + "display": "Pantalla", + "divider_thickness": "Grosor del divisor", + "divider": "Divisor", + "dividers": "Divisores", + "drop_shadow": "Sombra de Drop", + "empty_state_collection_info": "Mostrar antes de ingresar la búsqueda", + "empty_state_collection": "Colección en estado vacío", + "enable_filtering": "Filtros", + "enable_grid_density": "Control del diseño de la cuadrícula", + "enable_sorting": "Ordenación", + "enable_zoom": "Activar zoom", + "equal_columns": "Columnas iguales", + "expand_first_group": "Expandir el primer grupo", + "extend_media_to_screen_edge": "Ampliar el elemento multimedia al borde de la pantalla", + "extend_summary": "Ampliar al borde de la pantalla", + "extra_large": "Extra grande", + "extra_small": "Extra pequeño", + "flag": "Marcar", + "font_price": "Fuente del precio", + "font_weight": "Peso de la fuente", + "font": "Fuente", + "full_width_first_image": "Primera imagen de ancho completo", + "full_width_on_mobile": "Ancho completo de móvil", + "heading_preset": "Encabezado predefinido", + "hide_unselected_variant_media": "Ocultar elementos multimedia no seleccionados", + "horizontal_gap": "Espacio horizontal", + "horizontal_offset": "Sombreado de la desalineación horizontal", + "hover_behavior": "Comportamiento al pasar el cursor", + "icon_background": "Fondo del ícono", + "icons": "Íconos", + "image_border_radius": "Radio de la esquina de la imagen", + "installments": "Cuotas", + "integrated_button": "Botón integrado", + "language_selector": "Selector de idioma", + "large": "Grande", + "left_padding": "Relleno a la izquierda", + "left": "Izquierda", + "letter_spacing": "Espaciado de letras", + "limit_media_to_screen_height": "Ajustar a la altura de la pantalla", + "limit_product_details_width": "Limitar la anchura de los detalles del producto", + "link_preset": "Enlace predefinido", + "links": "Enlaces", + "logo_font": "Fuente del logo", + "logo": "Logo", + "loop": "Bucle", + "make_details_sticky_desktop": "Fijo en el escritorio", + "max_width": "Anchura máxima", + "media_height": "Altura del elemento multimedia", + "media_overlay": "Sobreposición del elemento multimedia", + "media_position": "Posición del elemento multimedia", + "media_type": "Tipo del elemento multimedia", + "media_width": "Anchura del elemento multimedia", + "menu": "Menú", + "mobile_columns": "Columnas móviles", + "mobile_height": "Altura móvil", + "mobile_logo_image": "Logo en dispositivo móvil", + "mobile_quick_add": "Agregado rápido móvil", + "motion_direction": "Dirección de movimiento", + "motion": "Movimiento", + "movement_direction": "Dirección del movimiento", + "navigation_bar_color_scheme": "Esquema de los colores de la barra de navegación", + "navigation_bar": "Barra de navegación", + "navigation": "Navegación", + "open_new_tab": "Abrir el enlace en una pestaña nueva", + "overlay_color": "Color de sobreposición", + "overlay": "Superposición", + "padding_bottom": "Relleno en la parte inferior", + "padding_horizontal": "Relleno horizontal", + "padding_top": "Relleno en la parte superior", + "page_width": "Ancho de página", + "pagination": "Paginación", + "placement": "Colocación", + "position": "Posición", + "preset": "Predefinido", + "product_cards": "Tarjetas del producto", + "product_pages": "Páginas de productos", + "product_templates": "Plantilla de producto", + "products": "Productos", + "quick_add": "Agregado rápido", + "ratio": "Proporción", + "regular": "Normal", + "review_count": "Conteo de la revisión", + "right": "Derecha", + "row_height": "Altura de la fila", + "row": "Fila", + "seller_note": "Permitir notas al vendedor", + "shape": "Forma", + "show_as_accordion": "Mostrar como acordeón en móvil", + "show_sale_price_first": "Mostrar el precio de oferta primero", + "show_tax_info": "Información fiscal", + "show": "Mostrar", + "small": "Pequeño", + "speed": "Velocidad", + "statement": "Extracto", + "sticky_header": "Encabezado fijo", + "text_hierarchy": "Jerarquía del texto", + "text_presets": "Textos predefinidos", + "title": "Título", + "top": "Arriba", + "type": "Tipo", + "type_preset": "Textos predefinidos", + "underline_thickness": "Espesor de subrayado", + "variant_images": "Imágenes de variantes", + "vendor": "Proveedor", + "vertical_gap": "Espacio vertical", + "vertical_offset": "Sombreado de la desalineación vertical", + "vertical_on_mobile": "Vertical en móvil", + "view_all_as_last_card": "\"Ver todo\" como última tarjeta", + "weight": "Peso", + "wrap": "Ajustar", + "read_only": "Solo lectura", + "always_stack_buttons": "Apilar siempre los botones", + "custom_mobile_width": "Ancho personalizado para móviles", + "gradient_direction": "Dirección del degradado", + "headings": "Encabezados", + "overlay_style": "Estilo de sobreposición", + "shadow_opacity": "Opacidad del sombreado", + "show_filter_label": "Etiquetas de texto para los filtros aplicados", + "show_swatch_label": "Etiquetas de texto para muestras", + "transparent_background": "Fondo transparente", + "account": "Cuenta", + "align_baseline": "Alinear la línea de base del texto", + "animation_repeat": "Repetir animación", + "add_discount_code": "Permitir descuentos en el carrito", + "background_overlay": "Sobreposición del fondo", + "background_media": "Elemento multimedia de fondo", + "border_thickness": "Grosor del borde", + "bottom_row": "Fila inferior", + "button_text_case": "Caja de texto", + "button_text_weight": "Grosor del texto", + "auto_open_cart_drawer": "\"Agregar al carrito\" abre automáticamente el carrito lateral", + "collection_count": "Conteo de colecciones", + "custom_liquid": "Código de Liquid", + "default": "Predeterminado", + "default_logo": "Logo predeterminado", + "divider_width": "Ancho del divisor", + "effects": "Efectos", + "hide_logo_on_home_page": "Ocultar logo en la página de inicio", + "horizontal_padding": "Relleno horizontal", + "inverse": "Inverso", + "inverse_logo": "Logo inverso", + "layout_style": "Estilo", + "length": "Longitud", + "mobile_pagination": "Paginación móvil", + "open_row_by_default": "Abrir fila de forma predeterminada", + "page": "Página", + "page_transition_enabled": "Transición de la página", + "search": "Búsqueda", + "search_icon": "Ícono de búsqueda", + "search_position": "Posición", + "search_row": "Fila", + "show_author": "Autor", + "show_alignment": "Mostrar alineación", + "show_count": "Mostrar recuento", + "show_date": "Fecha", + "show_pickup_availability": "Mostrar disponibilidad de retiro", + "show_search": "Mostrar búsqueda", + "use_inverse_logo": "Utilizar logo inverso", + "vertical_padding": "Relleno vertical", + "visibility": "Visibilidad", + "product_corner_radius": "Radio de la esquina del producto", + "card_corner_radius": "Radio de la esquina de la tarjeta", + "alignment_mobile": "Alineación para dispositivo móvil", + "blurred_reflection": "Reflejo difuminado", + "card_hover_effect": "Efecto hover de la tarjeta", + "card_size": "Tamaño de tarjeta", + "collection_title_case": "Caja del título de la colección", + "inventory_threshold": "Umbral de existencias bajas", + "mobile_card_size": "Tamaño de tarjeta en móvil", + "product_and_card_title_case": "Caja del título del producto y la tarjeta", + "product_title_case": "Caja del nombre del producto", + "reflection_opacity": "Opacidad del reflejo", + "right_padding": "Relleno derecho", + "show_inventory_quantity": "Mostrar cantidad de existencias bajas", + "text_label_case": "Caja de la etiqueta de texto", + "transition_to_main_product": "Transición de la tarjeta de producto a la página de producto", + "show_second_image_on_hover": "Mostrar segunda imagen al pasar el cursor", + "media": "Elementos multimedia", + "product_card_carousel": "Mostrar carrusel", + "media_fit": "Ajuste de elemento multimedia", + "scroll_speed": "Desplazarse al siguiente anuncio" + }, + "options": { + "adapt_to_image": "Adaptar a la imagen", + "apple": "Manzana", + "arrow": "Flecha", + "auto": "Automática", + "banana": "Plátano", + "bottle": "Biberón", + "box": "Caja", + "buttons": "Botones", + "carrot": "Zanahoria", + "center": "Centrado", + "chat_bubble": "Globo de chat", + "clipboard": "Portapapeles", + "contain": "Contiene", + "counter": "Contador", + "cover": "Portada", + "custom": "Personalizado", + "dairy_free": "Sin lácteos", + "dairy": "Lácteos", + "default": "Predeterminada", + "dropdowns": "Desplegables", + "dots": "Puntos", + "dryer": "Secador", + "end": "Fin", + "eye": "Ojo", + "facebook": "Facebook", + "fill": "Rellenar", + "fire": "Fuego", + "fit": "Ajuste", + "full": "Completa", + "full_and_page": "Fondo completo, contenido de ancho de página", + "gluten_free": "Sin gluten", + "heading": "Encabezado", + "heart": "Corazón", + "horizontal": "Horizontal", + "instagram": "Instagram", + "iron": "Plancha", + "landscape": "Paisaje", + "large": "Grande", + "leaf": "Hoja", + "leather": "Cuero", + "lg": "L", + "lightning_bolt": "Relámpago", + "link": "Enlace", + "lipstick": "Lápiz labial", + "lock": "Candado", + "lowercase": "minúscula", + "m": "M", + "map_pin": "Alfiler en mapa", + "medium": "Mediano", + "none": "Ninguno", + "numbers": "Números", + "nut_free": "Sin frutos secos", + "outline": "Contorno", + "page": "Página", + "pants": "Pantalones", + "paw_print": "Huella de una pata", + "pepper": "Pimienta", + "perfume": "Perfume", + "pinterest": "Pinterest", + "plane": "Avión", + "plant": "Planta", + "portrait": "Retrato", + "price_tag": "Etiqueta de precio", + "question_mark": "Signo de interrogación", + "recycle": "Reciclar", + "return": "Devolución", + "ruler": "Regla", + "s": "S", + "sentence": "Oración", + "serving_dish": "Plato de servir", + "shirt": "Camisa", + "shoe": "Zapato", + "silhouette": "Silueta", + "small": "Pequeña", + "snapchat": "Snapchat", + "snowflake": "Copo de nieve", + "solid": "Sólido", + "space_between": "Espacio entre", + "square": "Cuadrado", + "star": "Estrella", + "start": "Inicio", + "stopwatch": "Cronómetro", + "tiktok": "TikTok", + "truck": "Camión", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Mayúscula", + "vertical": "Vertical", + "vimeo": "Vimeo", + "washing": "Lavado", + "circle": "Círculo", + "swatches": "Muestras", + "full_and_page_offset_left": "Fondo completo, contenido de ancho de página, offset a la izquierda", + "full_and_page_offset_right": "Fondo completo, contenido de ancho de página, offset a la derecha", + "offset_left": "Offset a la izquierda", + "offset_right": "Offset a la derecha", + "page_center_aligned": "Página, alineado al centro", + "page_left_aligned": "Página, alineado a la izquierda", + "page_right_aligned": "Página, alineado a la derecha", + "button": "Botón", + "caption": "Leyenda", + "h1": "Título 1", + "h2": "Título 2", + "h3": "Título 3", + "h4": "Título 4", + "h5": "Título 5", + "h6": "Título 6", + "paragraph": "Párrafo", + "primary": "Principal", + "secondary": "Secundario", + "tertiary": "Terciario", + "chevron_left": "Comillas angulares izquierda", + "chevron_right": "Comillas angulares derecha", + "diamond": "Diamante", + "grid": "Cuadrícula", + "parallelogram": "Paralelogramo", + "rounded": "Redondeado", + "fit_content": "Ajustar", + "pills": "Cápsulas", + "heavy": "Grueso", + "thin": "Fino", + "drawer": "Cajón", + "preview": "Vista previa", + "text": "Texto", + "up": "Arriba", + "down": "Abajo", + "gradient": "Degradado", + "video_uploaded": "Subido", + "video_external_url": "URL externa", + "fixed": "Fijo", + "pixel": "Píxel", + "percent": "Porcentaje", + "aspect_ratio": "Relación de aspecto", + "above_carousel": "Arriba del carrusel", + "all": "Todo", + "always": "Siempre", + "arrows_large": "Flechas grandes", + "arrows": "Flechas", + "balance": "Saldo", + "bento": "Bento", + "black": "Negro", + "bluesky": "Bluesky", + "body_large": "Cuerpo del texto (grande)", + "body_regular": "Cuerpo del texto (regular)", + "body_small": "Cuerpo del texto (pequeño)", + "bold": "Negrita", + "bottom_left": "Abajo a la izquierda", + "bottom_right": "Abajo a la derecha", + "bottom": "Abajo", + "capitalize": "Capitalizar", + "caret": "Cursor", + "carousel": "Carrusel", + "check_box": "Casilla de verificación", + "chevron_large": "Comillas angulares grandes", + "chevron": "Comillas angulares", + "chevrons": "Comillas angulares", + "classic": "Clásico", + "collection_images": "Imágenes de la colección", + "color": "Color", + "complementary": "Complementario", + "dissolve": "Desvanecer", + "dotted": "Punteado", + "editorial": "Editorial", + "extra_large": "Extra grande", + "extra_small": "Extra pequeño", + "featured_collections": "Colecciones destacadas", + "featured_products": "Productos destacados", + "font_primary": "Principal", + "font_secondary": "Secundario", + "font_tertiary": "Terciario", + "forward": "Adelante", + "full_screen": "Pantalla completa", + "heading_extra_large": "Encabezado (extra grande)", + "heading_extra_small": "Encabezado (extra pequeño)", + "heading_large": "Encabezado (grande)", + "heading_regular": "Encabezado (normal)", + "heading_small": "Encabezado (pequeño)", + "icon": "Ícono", + "image": "Imagen", + "input": "Información", + "inside_carousel": "Dentro del carrusel", + "inverse_large": "Inverso grande", + "inverse": "Inverso", + "large_arrows": "Flechas grandes", + "large_chevrons": "Comillas angulares grandes", + "left": "Izquierda", + "light": "Claro", + "linkedin": "LinkedIn", + "loose": "Libre", + "media_first": "Primer elemento multimedia", + "media_second": "Segundo elemento multimedia", + "modal": "Modal", + "narrow": "Estrecho", + "never": "Nunca", + "next_to_carousel": "Junto al carrusel", + "normal": "Normal", + "nowrap": "Sin envolver", + "off_media": "Elemento multimedia inactivado", + "on_media": "Elemento multimedia activado", + "on_scroll_up": "Al desplazarse hacia arriba", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Ovalado", + "plus": "Plus", + "pretty": "Embellecer", + "price": "Precio", + "primary_style": "Estilo principal", + "rectangle": "Rectángulo", + "regular": "Normal", + "related": "Relacionado", + "reverse": "Revertir", + "rich_text": "Texto enriquecido", + "right": "Derecha", + "secondary_style": "Estilo secundario", + "semibold": "Seminegrita", + "shaded": "Sombreado", + "show_second_image": "Mostrar segunda imagen", + "single": "Individual", + "slide_left": "Deslizar hacia la izquierda", + "slide_up": "Deslizar hacia arriba", + "spotify": "Spotify", + "stack": "Apilar", + "text_only": "Solo texto", + "threads": "Hilos", + "thumbnails": "Miniaturas", + "tight": "Ajustado", + "top_left": "Arriba a la izquierda", + "top_right": "Arriba a la derecha", + "top": "Arriba", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Subrayado", + "video": "Video", + "wide": "Ancho", + "youtube": "YouTube", + "compact": "Compacto", + "standard": "Estándar", + "accent": "Énfasis", + "below_image": "Bajo la imagen", + "blur": "Difuminar", + "body": "Cuerpo", + "button_primary": "Botón principal", + "button_secondary": "Botón secundario", + "crop_to_fit": "Recortar para ajustar", + "hidden": "Oculto", + "hint": "Sugerencia", + "maintain_aspect_ratio": "Mantener relación de aspecto", + "off": "Desactivado", + "on_image": "Sobre la imagen", + "reveal": "Mostrar", + "social_bluesky": "Red social: Bluesky", + "social_facebook": "Red social: Facebook", + "social_instagram": "Red social: Instagram", + "social_linkedin": "Red social: LinkedIn", + "social_pinterest": "Red social: Pinterest", + "social_snapchat": "Red social: Snapchat", + "social_spotify": "Red social: Spotify", + "social_threads": "Red social: Hilo", + "social_tiktok": "Red social: TikTok", + "social_tumblr": "Red social: Tumblr", + "social_twitter": "Red social: X (Twitter)", + "social_whatsapp": "Red social: WhatsApp", + "social_vimeo": "Red social: Vimeo", + "social_youtube": "Red social: YouTube", + "spotlight": "Spotlight", + "subheading": "Subtítulo", + "lift": "Subir", + "scale": "Escalar", + "subtle_zoom": "Ampliar" + }, + "content": { + "advanced": "Avanzado", + "background_image": "Imagen de fondo", + "background_video": "Video de fondo", + "block_size": "Tamaño de bloque", + "borders": "Bordes", + "describe_the_video_for": "Describe el video para los clientes que usan lectores de pantalla. [Más información](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Tamaño de sección", + "slideshow_width": "Ancho de diapositiva", + "typography": "Tipografía", + "width_is_automatically_optimized": "El ancho se optimiza automáticamente para dispositivos móviles.", + "complementary_products": "Los productos complementarios deben configurarse con la aplicación Search & Discovery. [Obtén más información](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Las columnas se optimizarán automáticamente para dispositivos móviles", + "content_width": "El ancho del contenido solo se aplica cuando el ancho de la sección está establecido en ancho completo.", + "adjustments_affect_all_content": "Afecta a todo el contenido de este bloque", + "responsive_font_sizes": "Los tamaños se adaptan automáticamente a todos los tamaños de pantalla", + "buttons": "Botones", + "swatches": "Muestras", + "variant_settings": "Configuración de las variantes", + "background": "Fondo", + "cards_layout": "Diseño de tarjetas", + "section_layout": "Diseño de la sección", + "mobile_size": "Tamaño del móvil", + "appearance": "Apariencia", + "arrows": "Flechas", + "body_size": "Tamaño del cuerpo del texto", + "bottom_row_appearance": "Apariencia de la fila inferior", + "carousel_navigation": "Navegación de carrusel", + "carousel_pagination": "Paginación de carrusel", + "copyright": "Derechos de autor", + "edit_logo_in_theme_settings": "Edita tu logo en [configuración del tema](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Edita el formato en [configuración del tema](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Edita la variante de estilo en [configuración del tema](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Suscriptores agregados [perfiles de clientes](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Para que el botón se muestre, debes tener instalado el canal de Shop y Shop Pay activado. [Obtén más información](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Fuentes", + "grid": "Cuadrícula", + "heading_size": "Tamaño del título", + "image": "Imagen", + "input": "Información", + "layout": "Diseño", + "link": "Enlace", + "link_padding": "Relleno del enlace", + "localization": "Localización", + "logo": "Logo", + "margin": "Margen", + "media": "Elementos multimedia", + "media_1": "Elementos multimedia 1", + "media_2": "Elementos multimedia 2", + "menu": "Menú", + "mobile_layout": "Diseño móvil", + "padding": "Relleno", + "padding_desktop": "Relleno del escritorio", + "paragraph": "Párrafo", + "policies": "Políticas", + "popup": "Ventana emergente", + "search": "Buscar", + "size": "Tamaño", + "social_media": "Redes sociales", + "submit_button": "Botón de enviar", + "text_presets": "Textos predefinidos", + "transparent_background": "Fondo transparente", + "typography_primary": "Tipografía principal", + "typography_secondary": "Tipografía secundaria", + "typography_tertiary": "Tipografía terciaria", + "mobile_width": "Ancho para móviles", + "width": "Ancho", + "carousel": "Carrusel", + "colors": "Colores", + "collection_page": "Página de colección", + "copyright_info": "Descubre cómo [editar tu declaración de derechos de autor](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Cuenta de cliente", + "edit_empty_state_collection_in_theme_settings": "Edita el estado vacío de la colección en [configuración del tema ](/editor?context=theme&category=search)", + "home_page": "Página de inicio", + "images": "Imágenes", + "inverse_logo_info": "Se utiliza cuando el fondo del encabezado transparente está configurado como Inverso", + "manage_customer_accounts": "[Gestionar visibilidad](/admin/settings/customer_accounts) en la configuración de las cuentas de cliente. Las cuentas heredadas no son compatibles.", + "manage_policies": "[Gestionar políticas](/admin/settings/legal)", + "product_page": "Página de producto", + "text": "Texto", + "thumbnails": "Miniaturas", + "visibility": "Visibilidad", + "visible_if_collection_has_more_products": "Visible si la colección tiene más productos que los que se muestran", + "grid_layout": "Diseño de cuadrícula", + "app_required_for_ratings": "Se requiere una aplicación para las calificaciones de productos. [Obtén más información en](https://help.shopify.com/manual/apps)", + "icon": "Ícono", + "manage_store_name": "[Gestionar nombre de la tienda](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Muestra la colección de la sección principal", + "resource_reference_collection_card_image": "Muestra la imagen de la colección principal", + "resource_reference_collection_title": "Muestra el título de la colección principal", + "resource_reference_product": "Se conecta automáticamente con el producto principal", + "resource_reference_product_card": "Muestra el producto de la sección principal", + "resource_reference_product_inventory": "Muestra el inventario del producto principal", + "resource_reference_product_price": "Muestra el precio del producto principal", + "resource_reference_product_recommendations": "Muestra recomendaciones basadas en el producto principal", + "resource_reference_product_review": "Muestra reseñas del producto principal", + "resource_reference_product_swatches": "Muestra muestras del producto principal", + "resource_reference_product_title": "Muestra el título del producto principal", + "resource_reference_product_variant_picker": "Muestra variantes del producto principal", + "resource_reference_product_media": "Muestra multimedia del producto principal", + "product_media": "Elementos multimedia del producto", + "section_link": "Enlace de la sección" + }, + "html_defaults": { + "share_information_about_your": "

Comparte información sobre tu marca con los clientes. Describe un producto, comparte anuncios o da la bienvenida a los clientes a tu tienda.

" + }, + "text_defaults": { + "button_label": "Comprar ahora", + "collapsible_row": "Fila desplegable", + "heading": "Encabezado", + "email_signup_button_label": "Suscribirse", + "accordion_heading": "Encabezado de acordeón", + "contact_form_button_label": "Enviar", + "popup_link": "Enlace emergente", + "sign_up": "Registrarse", + "welcome_to_our_store": "Te damos la bienvenida a nuestra tienda", + "be_bold": "Sé audaz.", + "shop_our_latest_arrivals": "¡Compra nuestras últimas novedades!" + }, + "info": { + "carousel_layout_on_mobile": "El carrusel se utiliza en dispositivos móviles", + "link_info": "Opcional: hace que los íconos sean navegables", + "video_alt_text": "Describe el vídeo para quienes usan tecnologías asistivas", + "video_autoplay": "Los vídeos se silenciarán por defecto", + "video_external": "Usa una URL de YouTube o Vimeo", + "carousel_hover_behavior_not_supported": "No se admite el efecto hover en \"Carrusel\" cuando se elige el tipo \"Carrusel\" en el nivel de sección", + "checkout_buttons": "Permite a los compradores pagar más rápido y puede mejorar la conversión. [Obtén más información](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Encabezado personalizado", + "edit_presets_in_theme_settings": "Edita la configuración predeterminada en [configuración del tema](/editor?context=theme&category=typography)", + "enable_filtering_info": "Personaliza los filtros con la [aplicación Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "El diseño de cuadrícula se usa para móvil", + "logo_font": "Solo se aplica cuando no hay un logo seleccionado", + "manage_countries_regions": "[Gestionar países o regiones](/admin/settings/markets)", + "manage_languages": "[Gestionar idiomas](/admin/settings/languages)", + "transparent_background": "Revisa los formularios en los que el fondo transparente se aplica para facilitar la lectura", + "aspect_ratio_adjusted": "Ajustado en algunos diseños", + "auto_open_cart_drawer": "Si está habilitado, el carrito lateral se abre automáticamente cuando se agrega un producto al carrito.", + "custom_liquid": "Agrega fragmentos de la aplicación u otros códigos para crear personalizaciones avanzadas. [Obtén más información](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "Solo se aplica a las imágenes", + "hover_effects": "Aplica a los productos y tarjetas de colección", + "pills_usage": "Se utiliza para filtros aplicados, códigos de descuento y sugerencias de búsqueda" + }, + "categories": { + "basic": "Básico", + "collection": "Colección", + "collection_list": "Lista de colecciones", + "footer": "Pie de página", + "forms": "Formularios", + "header": "Encabezado", + "layout": "Diseño", + "links": "Enlaces", + "product": "Producto", + "product_list": "Colección destacada", + "banners": "Banners", + "collections": "Colecciones", + "custom": "Personalizar", + "decorative": "Decorativo", + "products": "Productos", + "other_sections": "Otro", + "storytelling": "Narración" + } +} diff --git a/locales/fi.json b/locales/fi.json new file mode 100644 index 000000000..f529499b6 --- /dev/null +++ b/locales/fi.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Lataa video: {{ description }}", + "sold_out": "Loppuunmyyty", + "email_signup": { + "label": "Sähköposti", + "placeholder": "Sähköpostiosoite", + "success": "Kiitos tilauksesta!" + }, + "filter": "Suodata", + "payment_methods": "Maksutavat", + "contact_form": { + "name": "Nimi", + "email": "Sähköpostiosoite", + "phone": "Puhelinnumero", + "comment": "Kommentti", + "post_success": "Kiitos yhteydenotostasi. Vastaamme sinulle mahdollisimman pian.", + "error_heading": "Muokkaa seuraavia:" + } + }, + "accessibility": { + "play_model": "Toista 3D-malli", + "play_video": "Toista video", + "unit_price": "Yksikköhinta", + "country_results_count": "{{ count }} tulosta", + "slideshow_pause": "Keskeytä diaesitys", + "slideshow_play": "Toista diaesitys", + "remove_item": "Poista {{ title}}", + "skip_to_text": "Ohita ja siirry sisältöön", + "skip_to_product_info": "Siirry tuotetietoihin", + "skip_to_results_list": "Siirry tulosluetteloon", + "new_window": "Avautuu uuteen ikkunaan.", + "slideshow_next": "Seuraava dia", + "slideshow_previous": "Edellinen dia", + "close_dialog": "Sulje valintaikkuna", + "reset_search": "Nollaa haku", + "search_results_count": "{{ count }} hakutulosta haulla {{ query }}", + "search_results_no_results": "Ei tuloksia haulla {{ query }}", + "filters": "Suodattimet", + "filter_count": { + "one": "{{ count }} suodatin käytössä", + "other": "{{ count }} suodatinta käytössä" + }, + "account": "Avaa tilivalikko", + "cart": "Ostoskori", + "cart_count": "Tuotteita ostoskorissa yhteensä", + "menu": "Valikko", + "country_region": "Maa/alue", + "slide_status": "Dia {{ index }}/{{ length }}", + "scroll_to": "Vieritä kohtaan {{ title }}", + "loading_product_recommendations": "Tuotesuositusten lataaminen", + "discount": "Käytä alennuskoodia", + "discount_applied": "Käytetty alennuskoodi: {{ code }}", + "open_cart_drawer": "Avaa ostoskori", + "inventory_status": "Varaston tila", + "pause_video": "Keskeytä video", + "find_country": "Etsi maa", + "localization_region_and_language": "Avaa alueen ja kielen valitsin", + "open_search_modal": "Avaa haku", + "decrease_quantity": "Pienennä määrää", + "increase_quantity": "Suurenna määrää", + "quantity": "Määrä", + "rating": "Tämän tuoteen tuotearvio on {{ rating }}/5", + "nested_product": "{{ product_title }} – {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Lisää ostoskoriin", + "clear_all": "Tyhjennä kaikki", + "remove": "Poista", + "view_in_your_space": "Näytä omassa tilassasi", + "show_filters": "Suodata", + "clear": "Tyhjennä", + "continue_shopping": "Jatka ostoksia", + "log_in_html": "Onko sinulla tili? Kirjaudu sisään, jotta voit maksaa kassalla nopeammin.", + "see_items": { + "one": "Näytä {{ count }} tuote", + "other": "Näytä {{ count }} tuotetta" + }, + "view_all": "Näytä kaikki", + "add": "Lisää", + "choose": "Valitse", + "added": "Lisätty", + "show_less": "Näytä vähemmän", + "show_more": "Näytä lisää", + "close": "Sulje", + "more": "Lisää", + "reset": "Palauta", + "zoom": "Lähennä", + "close_dialog": "Sulje valintaikkuna", + "back": "Takaisin", + "log_in": "Kirjaudu sisään", + "log_out": "Kirjaudu ulos", + "remove_discount": "Poista alennus {{ code }}", + "enter_using_password": "Siirry sisään antamalla salasana", + "submit": "Lähetä", + "enter_password": "Anna salasana", + "view_store_information": "Näytä kaupan tiedot", + "apply": "Käytä", + "sign_in_options": "Muut kirjautumisvaihtoehdot", + "sign_up": "Rekisteröidy", + "open_image_in_full_screen": "Avaa kuva koko näytön tilassa", + "sort": "Lajittele", + "show_all_options": "Näytä kaikki vaihtoehdot" + }, + "content": { + "reviews": "arvostelua", + "language": "Kieli", + "localization_region_and_language": "Alue ja kieli", + "no_results_found": "Tuloksia ei löytynyt", + "cart_total": "Ostoskori yhteensä", + "your_cart_is_empty": "Ostoskorisi on tyhjä", + "product_image": "Tuotekuva", + "product_information": "Tuotetiedot", + "quantity": "Määrä", + "product_total": "Tuote yhteensä", + "cart_estimated_total": "Arvioitu kokonaishinta", + "seller_note": "Erityisohjeet", + "cart_subtotal": "Välisumma", + "discounts": "Alennukset", + "discount": "Alennus", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Sisältää tullit ja verot. Alennukset ja toimituskulut lasketaan kassalla.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Sisältää tullit ja verot. Alennukset ja toimituskulut lasketaan kassalla.", + "taxes_included_shipping_at_checkout_with_policy_html": "Sisältää verot. Alennukset ja toimituskulut lasketaan kassalla.", + "taxes_included_shipping_at_checkout_without_policy": "Sisältää verot. Alennukset ja toimituskulut lasketaan kassalla.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Sisältää tullit. Verot, alennukset ja toimituskulut lasketaan kassalla.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Sisältää tullit. Verot, alennukset ja toimituskulut lasketaan kassalla.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Verot, alennukset ja toimituskulut lasketaan kassalla.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Verot, alennukset ja toimituskulut lasketaan kassalla.", + "checkout": "Maksa kassalla", + "cart_title": "Ostoskori", + "price": "Hinta", + "price_regular": "Normaalihinta", + "price_compare_at": "Vertailuhinta", + "price_sale": "Alennushinta", + "duties_and_taxes_included": "Sisältää tullit ja verot.", + "duties_included": "Sisältää tullit.", + "shipping_policy_html": "Toimituskulut lasketaan kassalla.", + "taxes_included": "Sisältää verot.", + "product_badge_sold_out": "Loppuunmyyty", + "product_badge_sale": "Alennusmyynti", + "search_input_label": "Hae", + "search_input_placeholder": "Hae", + "search_results": "Hakutulokset", + "search_results_label": "Hakutulokset", + "search_results_no_results": "Ei tuloksia haulla {{ terms }}. Kokeile tehdä uusi haku.", + "search_results_resource_articles": "Blogipostaukset", + "search_results_resource_collections": "Kokoelmat", + "search_results_resource_pages": "Sivut", + "search_results_resource_products": "Tuotteet", + "search_results_resource_queries": "Hakuehdotukset", + "search_results_view_all": "Näytä kaikki", + "search_results_view_all_button": "Näytä kaikki", + "search_results_resource_products_count": { + "one": "{{ count }} tuote", + "other": "{{ count }} tuotetta" + }, + "grid_view": { + "default_view": "Oletus", + "grid_fieldset": "Sarakeruudukko", + "single_item": "Yksittäinen", + "zoom_out": "Loitonna" + }, + "unavailable": "Ei saatavilla", + "collection_placeholder": "Kokoelman nimi", + "product_card_placeholder": "Tuotteen nimi", + "recently_viewed_products": "Äskettäin katsottu", + "product_count": "Tuotemäärä", + "item_count": { + "one": "{{ count }} tuote", + "other": "{{ count }} tuotetta" + }, + "errors": "Virheet", + "search": "Haku", + "search_results_no_results_check_spelling": "Ei tuloksia haulla {{ terms }}. Tarkista oikeinkirjoitus tai kokeile toista sanaa tai ilmaisua.", + "featured_products": "Esiteltävät tuotteet", + "price_from": "Alkaen {{ price }}", + "filters": "Suodattimet", + "no_products_found": "Tuotteita ei löytynyt.", + "price_filter_html": "Korkein hinta on {{ price }}", + "use_fewer_filters_html": "Käytä vähemmän suodattimia tai tyhjennä kaikki suodattimet.", + "read_more": "Lue lisää...", + "blog_details_separator": "|", + "account_title": "Tili", + "account_title_personalized": "Hei {{ first_name }}!", + "account_orders": "Tilaukset", + "account_profile": "Profiili", + "discount_code": "Alennuskoodi", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Sisältää tullit ja verot. Toimituskulut lasketaan kassalla.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Sisältää tullit ja verot. Toimituskulut lasketaan kassalla.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Sisältää tullit. Toimituskulut lasketaan kassalla.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Sisältää tullit. Toimituskulut lasketaan kassalla.", + "pickup_available_at_html": "Noudettavissa sijainnista {{ location }}", + "pickup_available_in": "Noudettavissa klo {{ pickup_time }}", + "pickup_not_available": "Nouto ei ole tällä hetkellä mahdollista", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Verot ja toimituskulut lasketaan kassalla.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Verot ja toimituskulut lasketaan kassalla.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Sisältää verot. Toimituskulut lasketaan kassalla.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Sisältää verot. Toimituskulut lasketaan kassalla.", + "wrong_password": "Väärä salasana", + "view_more_details": "Katso lisätietoja", + "inventory_low_stock": "Varasto vähissä", + "inventory_in_stock": "Varastossa", + "inventory_out_of_stock": "Loppunut varastosta", + "page_placeholder_title": "Sivun otsikko", + "page_placeholder_content": "Valitse sivu, jonka sisältöä haluat tarkastella.", + "placeholder_image": "Paikkamerkkikuva", + "inventory_low_stock_show_count": { + "one": "{{ count }} jäljellä", + "other": "{{ count }} jäljellä" + }, + "powered_by": "Tämän kaupan alustana on", + "store_owner_link_html": "Oletko kaupan omistaja? Kirjaudu sisään tästä", + "shipping_discount_error": "Toimitusalennukset näytetään kassalla osoitteen lisäämisen jälkeen", + "discount_code_error": "Alennuskoodin lisääminen ostoskoriisi ei onnistu", + "shipping_policy": "Toimituskulut lasketaan kassalla." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Käytä lahjakortin koodia verkossa tai QR-koodia kaupassa", + "title": "Tässä on lahjakorttisi saldo ({{ value }}) kauppaan {{ shop }}!", + "subtext": "Lahjakorttisi", + "shop_link": "Vieraile verkkokaupassa", + "add_to_apple_wallet": "Lisää Apple Walletiin", + "qr_image_alt": "QR-koodi – lunasta lahjakortti skannaamalla", + "copy_code": "Kopioi lahjakortin koodi", + "expiration_date": "Voimassa {{ expires_on }} asti", + "copy_code_success": "Koodin kopioiminen onnistui", + "expired": "Vanhentunut" + } + }, + "placeholders": { + "password": "Salasana", + "search": "Hae", + "product_title": "Tuotteen nimi", + "collection_title": "Kokoelman nimi" + }, + "products": { + "product": { + "add_to_cart": "Lisää ostoskoriin", + "added_to_cart": "Lisätty ostoskoriin", + "adding_to_cart": "Lisätään...", + "add_to_cart_error": "Ostoskoriin lisättäessä tapahtui virhe", + "sold_out": "Loppuunmyyty", + "unavailable": "Ei käytettävissä" + } + }, + "fields": { + "separator": "-" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} kommentti", + "other": "{{ count }} kommenttia" + } + }, + "comment_form": { + "email": "Sähköposti", + "error": "Kommenttia ei voitu julkaista. Korjaa seuraavat:", + "heading": "Jätä kommentti", + "message": "Viesti", + "moderated": "Huomaa, että kommenttien täytyy olla hyväksyttyjä ennen kuin ne julkaistaan.", + "name": "Nimi", + "post": "Julkaise kommentti", + "success_moderated": "Kommentti on julkaistu; odotetaan moderointia", + "success": "Kommentti on julkaistu" + } + } +} diff --git a/locales/fi.schema.json b/locales/fi.schema.json new file mode 100644 index 000000000..811d905fe --- /dev/null +++ b/locales/fi.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Reunukset", + "collapsible_row": "Pienenettävä rivi", + "colors": "Värit", + "custom_section": "Mukautettu osio", + "icon": "Kuvake", + "logo_and_favicon": "Logo ja favicon", + "overlapping_blocks": "Päällekkäiset lohkot", + "product_buy_buttons": "Osta-painikkeet", + "product_description": "Kuvaus", + "product_price": "Hinta", + "product_variant_picker": "Versionvalitsin", + "slideshow": "Diaesitys", + "typography": "Typografia", + "video": "Video", + "slideshow_controls": "Diaesityksen säätimet", + "size": "Koko", + "spacing": "Välit", + "product_recommendations": "Suositellut tuotteet", + "product_media": "Tuotemediat", + "featured_collection": "Esittelykokoelma", + "add_to_cart": "Lisää ostoskoriin", + "email_signup": "Sähköpostirekisteröityminen", + "submit_button": "Lähetä-painike", + "grid_layout_selector": "Ruudukkopohjan valitsin", + "image": "Kuva", + "list_items": "Luettelon tuotteet", + "facets": "Kohdistukset", + "variants": "Versiot", + "styles": "Tyylit", + "product_cards": "Tuotekortit", + "buttons": "Painikkeet", + "inputs": "Syötteet", + "primary_button": "Ensisijainen painike", + "secondary_button": "Toissijainen painike", + "popovers": "Ponnahdusilmoitukset", + "marquee": "Markiisi", + "alternating_content_rows": "Vaihtelevat rivit", + "pull_quote": "Nosto", + "contact_form": "Yhteydenottolomake", + "featured_product": "Tuotteen korostus", + "icons_with_text": "Kuvakkeet ja teksti", + "accelerated_checkout": "Nopeutettu kassa", + "accordion": "Haitari", + "accordion_row": "Haitaririvi", + "animations": "Animaatiot", + "announcement": "Ilmoitus", + "announcement_bar": "Ilmoituspalkki", + "badges": "Tunnukset", + "button": "Painike", + "cart": "Ostoskori", + "cart_items": "Ostoskorin tuotteet", + "cart_products": "Ostoskorin tuotteet", + "cart_title": "Ostoskori", + "collection": "Kokoelma", + "collection_card": "Kokoelman kortti", + "collection_columns": "Kokoelman sarakkeet", + "collection_container": "Kokoelma", + "collection_description": "Kokoelman kuvaus", + "collection_image": "Kokoelman kuva", + "collection_info": "Kokoelman tiedot", + "collection_list": "Kokoelmaluettelo", + "collections": "Kokoelmat", + "content": "Sisältö", + "content_grid": "Sisältöruudukko", + "details": "Tiedot", + "divider": "Väliviiva", + "filters": "Suodatus ja lajittelu", + "follow_on_shop": "Seuraa Shopissa", + "footer": "Alatunniste", + "footer_utilities": "Alatunnisteen työkalut", + "group": "Ryhmä", + "header": "Ylätunniste", + "heading": "Otsikko", + "icons": "Kuvakkeet", + "image_with_text": "Kuva ja teksti", + "input": "Syöte", + "logo": "Logo", + "magazine_grid": "Lehtiruudukko", + "media": "Media", + "menu": "Valikko", + "mobile_layout": "Mobiiliasettelu", + "payment_icons": "Maksukuvakkeet", + "popup_link": "Ponnahduslinkki", + "predictive_search": "Haun ponnahdusilmoitus", + "predictive_search_empty": "Ennakoiva haku tyhjä", + "price": "Hinta", + "product": "Tuote", + "product_card": "Tuotekortti", + "product_card_media": "Media", + "product_card_rendering": "Tuotekorttien muodostus", + "product_grid": "Ruudukko", + "product_grid_main": "Tuoteruudukko", + "product_image": "Tuotekuva", + "product_information": "Tuotetiedot", + "product_list": "Esittelykokoelma", + "product_review_stars": "Arvion tähdet", + "quantity": "Määrä", + "row": "Rivi", + "search": "Haku", + "section": "Osio", + "selected_variants": "Valitut versiot", + "shop_the_look": "Valitse ulkoasu", + "slide": "Dia", + "social_media_links": "Sosiaalisen median linkit", + "spacer": "Erotin", + "steps": "Vaiheet", + "summary": "Yhteenveto", + "swatches": "Väriruudut", + "testimonials": "Suositukset", + "text": "Teksti", + "title": "Otsikko", + "utilities": "Apuohjelmat", + "search_input": "Hakusyöte", + "search_results": "Hakutulokset", + "read_only": "Vain luku", + "collection_title": "Kokoelman nimi", + "collections_bento": "Kokoelmaluettelo: bento", + "faq_section": "Usein kysyttyä", + "hero": "Pääkuva", + "jumbo_text": "Jumboteksti", + "view_all_button": "Näytä kaikki", + "video_section": "Video", + "blog": "Blogi", + "blog_posts": "Blogipostaukset", + "custom_liquid": "Mukautettu liquid", + "blog_post": "Blogipostaus", + "caption": "Kuvateksti", + "collection_card_image": "Kuva", + "collection_links": "Kokoelmalinkit", + "collection_links_spotlight": "Kokoelmalinkit: Spotlight", + "collection_links_text": "Kokoelmalinkit: teksti", + "collections_carousel": "Kokoelmaluettelo: karuselli", + "collections_editorial": "Kokoelmaluettelo: editoriaali", + "collections_grid": "Kokoelmaluettelo: ruudukko", + "copyright": "Tekijänoikeus", + "count": "Määrä", + "divider_section": "Väliviiva", + "drawers": "Laatikot", + "editorial": "Editoriaali", + "editorial_jumbo_text": "Editoriaali: jumboteksti", + "hero_marquee": "Hero: markiisi", + "input_fields": "Syötekentät", + "local_pickup": "Paikallinen nouto", + "marquee_section": "Markiisi", + "media_with_text": "Media ja teksti", + "page": "Sivu", + "page_content": "Sisältö", + "page_layout": "Sivun asettelu", + "policy_list": "Käytäntöjen linkit", + "prices": "Hinnat", + "product_list_button": "Näytä kaikki ‑painike", + "products_carousel": "Esittelykokoelma: karuselli", + "products_editorial": "Esittelykokoelma: editoriaali", + "products_grid": "Esittelykokoelma: ruudukko", + "product_inventory": "Tuotevarasto", + "social_link": "Sosiaalisen median linkki", + "split_showcase": "Jaettu esittely", + "variant_pickers": "Versionvalitsimet", + "pills": "Pillerikuvakkeet", + "product_title": "Tuotteen nimi", + "large_logo": "Suuri logo", + "description": "Kuvaus" + }, + "settings": { + "alignment": "Tasaus", + "autoplay": "Automaattinen toisto", + "background": "Tausta", + "border_radius": "Kulman säde", + "border_width": "Reunan paksuus", + "borders": "Reunukset", + "bottom_padding": "Alaosan täyttö", + "button": "Painike", + "color": "Väri", + "colors": "Värit", + "content_alignment": "Sisällön kohdistus", + "content_direction": "Sisällön suunta", + "content_position": "Sisällön sijainti", + "cover_image_size": "Kansikuvan koko", + "cover_image": "Kansikuva", + "custom_minimum_height": "Räätälöity vähimmäiskorkeus", + "custom_width": "Mukautettu leveys", + "enable_video_looping": "Videon jatkuva toisto", + "favicon": "Favicon", + "font_family": "Fonttiperhe", + "gap": "Rako", + "geometric_translate_y": "Geometrinen sijainti Y", + "heading": "Otsikko", + "icon": "Kuvake", + "image": "Kuva", + "image_icon": "Kuvakuvake", + "image_opacity": "Kuvan peittävyys", + "image_position": "Kuvan sijainti", + "image_ratio": "Kuvasuhde", + "label": "Merkintä", + "line_height": "Rivin korkeus", + "link": "Linkki", + "layout_gap": "Pohjan rako", + "make_section_full_width": "Tee osiosta täysleveä", + "minimum_height": "Vähimmäiskorkeus", + "opacity": "Peittävyys", + "overlay_opacity": "Peittokuvan läpikuultavuus", + "padding": "Puskuri", + "primary_color": "Linkit", + "product": "Tuote", + "section_width": "Osion leveys", + "size": "Koko", + "slide_spacing": "Dian rako", + "slide_width": "Dian leveys", + "slideshow_fullwidth": "Täysleveät diat", + "style": "Tyyli", + "text": "Teksti", + "text_case": "Kotelo", + "top_padding": "Yläosan täyttö", + "video": "Video", + "video_alt_text": "Vaihtoehtoinen teksti", + "video_loop": "Jatkuvasti toistuva video", + "video_position": "Videon sijainti", + "width": "Leveys", + "z_index": "Z-arvo", + "limit_content_width": "Rajoita sisällön leveyttä", + "color_scheme": "Värimalli", + "inherit_color_scheme": "Periytä värimalli", + "product_count": "Tuotemäärä", + "product_type": "Tuotetyyppi", + "content_width": "Sisällön leveys", + "collection": "Kokoelma", + "enable_sticky_content": "Ota kiinnitetty sisältö käyttöön tietokoneversiossa", + "error_color": "Virhe", + "success_color": "Onnistui", + "primary_font": "Ensisijainen fontti", + "secondary_font": "Toissijainen fontti", + "tertiary_font": "Kolmas fontti", + "columns": "Sarakkeet", + "items_to_show": "Näytettävät tuotteet", + "layout": "Pohja", + "layout_type": "Tyyppi", + "show_grid_layout_selector": "Näytä ruudukkopohjan valitsin", + "view_more_show": "Näytä Näytä lisää -painike", + "image_gap": "Kuvien välinen kuilu", + "width_desktop": "Tietokoneleveys", + "width_mobile": "Mobiililaiteleveys", + "border_style": "Reunan tyyli", + "height": "Korkeus", + "thickness": "Paksuus", + "stroke": "Viiva", + "filter_style": "Suodattimen tyyli", + "swatches": "Väriruudut", + "quick_add_colors": "Värien pikalisääminen", + "divider_color": "Jakaja", + "border_opacity": "Reunan läpikuultamattomuus", + "hover_background": "Leijuva tausta", + "hover_borders": "Leijuvat reunat", + "hover_text": "Leijuva teksti", + "primary_hover_color": "Leijuvat linkit", + "primary_button_text": "Ensisijaisen painikkeen teksti", + "primary_button_background": "Ensisijaisen painikkeen tausta", + "primary_button_border": "Ensisijaisen painikkeen reuna", + "secondary_button_text": "Toissijaisen painikkeen teksti", + "secondary_button_background": "Toissijaisen painikkeen tausta", + "secondary_button_border": "Toissijaisen painikkeen reuna", + "shadow_color": "Varjo", + "limit_media_to_screen_height": "Sovita näytön korkeuteen", + "video_autoplay": "Automaattinen toisto", + "video_cover_image": "Kansikuva", + "video_external_url": "URL-osoite", + "video_source": "Lähde", + "first_row_media_position": "Ensimmäisen rivin mediasijainti", + "accordion": "Haitari", + "aspect_ratio": "Kuvasuhde", + "auto_rotate_announcements": "Kierrä ilmoituksia automaattisesti", + "auto_rotate_slides": "Käännä diat automaattisesti", + "background_color": "Taustaväri", + "badge_corner_radius": "Kulman säde", + "badge_position": "Sijainti korteilla", + "badge_sale_color_scheme": "Alennusmyynti", + "badge_sold_out_color_scheme": "Loppuunmyyty", + "behavior": "Käyttäytyminen", + "blur": "Varjon sumennus", + "border": "Reuna", + "bottom": "Alareuna", + "card_image_height": "Tuotekuvan korkeus", + "carousel_on_mobile": "Karuselli mobiililaitteessa", + "cart_count": "Ostoskorimäärä", + "cart_items": "Ostoskorin tuotteet", + "cart_related_products": "Liittyvät tuotteet", + "cart_title": "Ostoskori", + "cart_total": "Ostoskori yhteensä", + "cart_type": "Tyyppi", + "case": "Kotelo", + "checkout_buttons": "Nopeutetun kassan painikkeet", + "collection_list": "Kokoelmat", + "collection_templates": "Kokoelmamallit", + "content": "Sisältö", + "corner_radius": "Kulman säde", + "country_region": "Maa/alue", + "currency_code": "Valuuttakoodi", + "custom_height": "Mukautettu korkeus", + "custom_mobile_size": "Mukautettu mobiilikoko", + "desktop_height": "Työpöydän korkeus", + "direction": "Suunta", + "display": "Näyttö", + "divider_thickness": "Jakajan paksuus", + "divider": "Väliviiva", + "dividers": "Jakajat", + "drop_shadow": "Taustavarjo", + "empty_state_collection_info": "Näytetään ennen haun syöttämistä", + "empty_state_collection": "Tyhjä tila -kokoelma", + "enable_filtering": "Suodattimet", + "enable_grid_density": "Ruudukkopohjan hallinta", + "enable_sorting": "Lajittelu", + "enable_zoom": "Ota zoomaus käyttöön", + "equal_columns": "Yhtenäiset sarakkeet", + "expand_first_group": "Laajenna ensimmäinen ryhmä", + "extend_media_to_screen_edge": "Laajenna media näytön reunaan", + "extend_summary": "Laajenna näytön reunaan", + "extra_large": "Erikoissuuri", + "extra_small": "Erikoispieni", + "fixed_height": "Pikselikorkeus", + "fixed_width": "Pikselileveys", + "flag": "Merkitse", + "font_price": "Hinnan fontti", + "font_weight": "Fontin paino", + "font": "Fontti", + "full_width_first_image": "Täysleveä ensimmäinen kuva", + "full_width_on_mobile": "Täysi leveys mobiililaitteella", + "heading_preset": "Otsikon esiasetus", + "hide_padding": "Piilota täyte", + "hide_unselected_variant_media": "Piilota valitsemattoman version media", + "horizontal_gap": "Vaakasuuntainen rako", + "horizontal_offset": "Varjon vaakasuuntainen siirtymä", + "hover_behavior": "Osoituksen käyttäytyminen", + "icon_background": "Kuvakkeen tausta", + "icons": "Kuvakkeet", + "image_border_radius": "Kuvan reunan säde", + "installments": "Maksuerät", + "integrated_button": "Integroitu painike", + "language_selector": "Kielivalitsin", + "large": "Suuri", + "left_padding": "Vasemman osan täyttö", + "left": "Vasen", + "letter_spacing": "Kirjainväli", + "limit_product_details_width": "Rajoita tuotetietojen leveyttä", + "link_preset": "Linkin esiasetus", + "links": "Linkit", + "logo_font": "Logon fontti", + "logo": "Logo", + "loop": "Silmukka", + "make_details_sticky_desktop": "Kiinnitettynä työpöydälle", + "max_width": "Enimmäisleveys", + "media_height": "Median korkeus", + "media_overlay": "Median peite", + "media_position": "Median sijainti", + "media_type": "Median tyyppi", + "media_width": "Median leveys", + "menu": "Valikko", + "mobile_columns": "Mobiilisarakkeet", + "mobile_height": "Mobiilikorkeus", + "mobile_logo_image": "Mobiililogo", + "mobile_quick_add": "Mobiilipikalisäys", + "motion_direction": "Liikesuunta", + "motion": "Liike", + "movement_direction": "Liikkeen suunta", + "navigation_bar_color_scheme": "Navigointirivin väriteema", + "navigation_bar": "Navigointirivi", + "navigation": "Navigointi", + "open_new_tab": "Avaa linkki uudella välilehdellä", + "overlay_color": "Värikerros", + "overlay": "Peittokuva", + "padding_bottom": "Alareunatäyte", + "padding_horizontal": "Vaakatäyte", + "padding_top": "Yläreunatäyte", + "page_width": "Sivun leveys", + "pagination": "Sivunumerointi", + "percent_height": "Prosenttikorkeus", + "percent_size_mobile": "Prosenttikoko", + "percent_size": "Prosenttikoko", + "percent_width": "Prosenttileveys", + "pixel_size_mobile": "Pikselikoko", + "pixel_size": "Pikselikoko", + "placement": "Sijoitus", + "position": "Sijainti", + "preset": "Esiasetus", + "product_cards": "Tuotekortit", + "product_pages": "Tuotesivut", + "product_templates": "Tuotemallit", + "products": "Tuotteet", + "quick_add": "Pikalisäys", + "ratio": "Suhde", + "regular": "Normaali", + "review_count": "Arviomäärä", + "right": "Oikea", + "row_height": "Rivikorkeus", + "row": "Rivi", + "seller_note": "Salli huomautus myyjälle", + "shape": "Muoto", + "show_as_accordion": "Näytä haitarina mobiililaitteessa", + "show_sale_price_first": "Näytä alennushinta ensin", + "show_tax_info": "Verotiedot", + "show": "Näytä", + "size_mobile": "Mobiilikoko", + "small": "Pieni", + "speed": "Nopeus", + "statement": "Tiliote", + "sticky_header": "Paikallaan pysyvä ylätunniste", + "text_hierarchy": "Tekstihierarkia", + "text_presets": "Tekstin esiasetukset", + "title": "Otsikko", + "top": "Yläreuna", + "type": "Tyyppi", + "type_preset": "Tekstin esiasetus", + "underline_thickness": "Alleviivauksen paksuus", + "unit": "Yksikkö", + "variant_images": "Version kuvat", + "vendor": "Myyjä", + "vertical_gap": "Pystyrako", + "vertical_offset": "Varjon pystysuuntainen siirtymä", + "vertical_on_mobile": "Pystysuuntainen mobiililaitteella", + "view_all_as_last_card": "\"Näytä kaikki\" viimeisenä korttina", + "weight": "Paino", + "wrap": "Tekstin rivitys", + "read_only": "Vain luku", + "always_stack_buttons": "Pinoa painikkeet aina", + "custom_mobile_width": "Mukautettu mobiilileveys", + "gradient_direction": "Liukuvärin suunta", + "overlay_style": "Peittokuvatyyli", + "shadow_opacity": "Varjon peittävyys", + "show_filter_label": "Käytettyjen suodattimien tekstiselitteet", + "show_swatch_label": "Väriruutujen tekstiselitteet", + "transparent_background": "Läpinäkyvä tausta", + "hide_logo_on_home_page": "Piilota logo etusivulta", + "account": "Tili", + "alignment_mobile": "Mobiilitasaus", + "align_baseline": "Kohdista tekstin jalkalinja", + "add_discount_code": "Salli alennukset ostoskorissa", + "background_overlay": "Taustan peittokuva", + "background_media": "Taustamedia", + "border_thickness": "Reunan paksuus", + "bottom_row": "Alin rivi", + "button_text_case": "Tekstin kirjasinkoko", + "button_text_weight": "Tekstin paksuus", + "card_size": "Kortin koko", + "auto_open_cart_drawer": "”Lisää ostoskoriin” avaa ostoskorin automaattisesti", + "collection_count": "Kokoelman määrä", + "collection_title_case": "Kokoelman nimen kirjainkoko", + "custom_liquid": "Liquid-koodi", + "default": "Oletus", + "default_logo": "Oletuslogo", + "divider_width": "Erottimen leveys", + "headings": "Otsikot", + "horizontal_padding": "Vaakatäyte", + "inventory_threshold": "Vähäisen varaston kynnysarvo", + "inverse": "Käänteinen", + "inverse_logo": "Käänteinen logo", + "layout_style": "Tyyli", + "length": "Pituus", + "mobile_card_size": "Mobiilikortin koko", + "mobile_pagination": "Sivunumerointi mobiililaitteella", + "open_row_by_default": "Avaa rivi oletusarvoisesti", + "page": "Sivu", + "page_transition_enabled": "Sivusiirtymä", + "product_and_card_title_case": "Tuotteen ja kortin nimen kirjainkoko", + "product_title_case": "Tuotteen nimen kirjainkoko", + "right_padding": "Oikean osan täyttö", + "search": "Hae", + "search_icon": "Hakukuvake", + "search_position": "Sijainti", + "search_row": "Rivi", + "show_author": "Tekijä", + "show_alignment": "Näytä tasaus", + "show_count": "Näytä määrä", + "show_date": "Päivämäärä", + "show_inventory_quantity": "Näytä vähäisen varaston määrä", + "show_pickup_availability": "Näytä noudon saatavuus", + "show_search": "Näytä haku", + "text_label_case": "Tekstimerkinnän kirjainkoko", + "use_inverse_logo": "Käytä käänteistä logoa", + "vertical_padding": "Pystytäyte", + "visibility": "Näkyvyys", + "product_corner_radius": "Tuotteen kulman säde", + "card_corner_radius": "Kortin kulman säde", + "animation_repeat": "Toistuva animaatio", + "blurred_reflection": "Sumennettu heijastus", + "card_hover_effect": "Kortin osoitusefekti", + "effects": "Efektit", + "reflection_opacity": "Heijastuksen peittävyys", + "transition_to_main_product": "Siirtymä tuotekortista tuotesivuun", + "media": "Media", + "product_card_carousel": "Näytä karuselli", + "show_second_image_on_hover": "Näytä toinen kuva osoitettaessa", + "media_fit": "Median sovitus", + "scroll_speed": "Aikaa seuraavaan ilmoitukseen" + }, + "options": { + "adapt_to_image": "Sovita kuvaan", + "apple": "Omena", + "arrow": "Nuoli", + "auto": "Automaattinen", + "banana": "Banaani", + "bottle": "Pullo", + "box": "Laatikko", + "buttons": "Painikkeet", + "carrot": "Porkkana", + "center": "Keskitetty", + "chat_bubble": "Keskustelukupla", + "clipboard": "Leikepöytä", + "contain": "Sisältää", + "counter": "Laskuri", + "cover": "Kansi", + "custom": "Mukautettu", + "dairy_free": "Maidoton", + "dairy": "Maitotuote", + "default": "Oletus", + "dropdowns": "Pudotusvalikot", + "dots": "Pisteet", + "dryer": "Kuivain", + "end": "Päättyminen", + "eye": "Silmä", + "facebook": "Facebook", + "fill": "Täytä", + "fire": "Tuli", + "fit": "Sovita", + "full": "Täysi", + "full_and_page": "Täysi tausta, sisällöllä sivun leveys", + "gluten_free": "Gluteeniton", + "heading": "Otsikko", + "heart": "Sydän", + "horizontal": "Vaaka", + "instagram": "Instagram", + "iron": "Silitysrauta", + "landscape": "Vaaka", + "large": "Suuri", + "leaf": "Lehti", + "leather": "Nahka", + "lg": "LG", + "lightning_bolt": "Salama", + "link": "Linkki", + "lipstick": "Huulipuna", + "lock": "Lukko", + "lowercase": "pienet kirjaimet", + "m": "M", + "map_pin": "Karttamerkki", + "medium": "Keskikokoinen", + "none": "Ei mitään", + "numbers": "Numerot", + "nut_free": "Pähkinätön", + "outline": "Reunus", + "page": "Sivu", + "pants": "Housut", + "paw_print": "Tassun jälki", + "pepper": "Pippuri", + "perfume": "Tuoksu", + "pinterest": "Pinterest", + "plane": "Lentokone", + "plant": "Kasvi", + "portrait": "Muotokuva", + "price_tag": "Hintalappu", + "question_mark": "Kysymysmerkki", + "recycle": "Kierrätys", + "return": "Palautus", + "ruler": "Viivain", + "s": "S", + "sentence": "Lause", + "serving_dish": "Tarjoiluastia", + "shirt": "Paita", + "shoe": "Kenkä", + "silhouette": "Siluetti", + "small": "Pieni", + "snapchat": "Snapchat", + "snowflake": "Lumihiutale", + "solid": "Yhtenäinen", + "space_between": "Väli:", + "square": "Neliö", + "star": "Tähti", + "start": "Alkaminen", + "stopwatch": "Sekuntikello", + "tiktok": "TikTok", + "truck": "Kuljetusajoneuvo", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Isot kirjaimet", + "vertical": "Pysty", + "vimeo": "Vimeo", + "washing": "Pesu", + "circle": "Ympyrä", + "swatches": "Väriruudut", + "full_and_page_offset_left": "Täysi tausta, koko sivun levyinen sisältö, vasemmalla", + "full_and_page_offset_right": "Täysi tausta, koko sivun levyinen sisältö, oikealla", + "offset_left": "Vasemmalla", + "offset_right": "Oikealla", + "page_center_aligned": "Sivu, tasattu keskelle", + "page_left_aligned": "Sivu, tasattu vasemmalle", + "page_right_aligned": "Sivu, tasattu oikealle", + "button": "Painike", + "caption": "Kuvateksti", + "h1": "Otsikko 1", + "h2": "Otsikko 2", + "h3": "Otsikko 3", + "h4": "Otsikko 4", + "h5": "Otsikko 5", + "h6": "Otsikko 6", + "paragraph": "Kappale", + "primary": "Ensisijainen", + "secondary": "Toissijainen", + "tertiary": "Kolmas", + "chevron_left": "V-merkki vasemmalle", + "chevron_right": "V-merkki oikealle", + "diamond": "Timantti", + "grid": "Ruudukko", + "parallelogram": "Suunnikas", + "rounded": "Pyöristetty", + "fit_content": "Sopivuus", + "pills": "Pillerikuvakkeet", + "heavy": "Paksu", + "thin": "Ohut", + "drawer": "Laatikko", + "preview": "Esikatselu", + "text": "Teksti", + "video_uploaded": "Ladattu", + "video_external_url": "Ulkoinen URL", + "aspect_ratio": "Kuvasuhde", + "fixed": "Kiinteä", + "pixel": "Pikseli", + "percent": "Prosenttiosuus", + "above_carousel": "Yläpuolella oleva karuselli", + "all": "Kaikki", + "up": "Ylös", + "down": "Alas", + "always": "Aina", + "arrows_large": "Suuret nuolet", + "arrows": "Nuolet", + "balance": "Saldo", + "bento": "Bento", + "black": "Musta", + "bluesky": "Bluesky", + "body_large": "Leipäteksti (suuri)", + "body_regular": "Leipäteksti (tavallinen)", + "body_small": "Leipäteksti (pieni)", + "bold": "Lihavoitu", + "bottom_left": "Alhaalla vasemmalla", + "bottom_right": "Alhaalla oikealla", + "bottom": "Alareuna", + "capitalize": "Suuret kirjaimet", + "caret": "Caret", + "carousel": "Karuselli", + "check_box": "Valintaruutu", + "chevron_large": "Suuret V-merkit", + "chevron": "V-merkki", + "chevrons": "V-merkit", + "classic": "Klassinen", + "collection_images": "Kokoelman kuvat", + "color": "Väri", + "complementary": "Täydentävä", + "dissolve": "Häivytä", + "dotted": "Pisteillä", + "editorial": "Editoriaali", + "extra_large": "Erikoissuuri", + "extra_small": "Erikoispieni", + "featured_collections": "Esittelyssä olevat kokoelmat", + "featured_products": "Esittelyssä olevat tuotteet", + "font_primary": "Ensisijainen", + "font_secondary": "Toissijainen", + "font_tertiary": "Kolmas", + "forward": "Eteenpäin", + "full_screen": "Koko näytön tila", + "gradient": "Liukuväri", + "heading_extra_large": "Otsikko (erikoissuuri)", + "heading_extra_small": "Otsikko (erikoispieni)", + "heading_large": "Otsikko (suuri)", + "heading_regular": "Otsikko (tavallinen)", + "heading_small": "Otsikko (pieni)", + "icon": "Kuvake", + "image": "Kuva", + "input": "Syöte", + "inside_carousel": "Sisäkaruselli", + "inverse_large": "Käänteinen suuri", + "inverse": "Käänteinen", + "large_arrows": "Suuret nuolet", + "large_chevrons": "Suuret V-merkit", + "left": "Vasen", + "light": "Vaalea", + "linkedin": "LinkedIn", + "loose": "Harva", + "media_first": "Media ensin", + "media_second": "Media toiseksi", + "modal": "Modaalinen", + "narrow": "Kapea", + "never": "Ei koskaan", + "next_to_carousel": "Karusellin vieressä", + "normal": "Normaali", + "nowrap": "Ei rivitystä", + "off_media": "Pois mediasta", + "on_media": "Mediassa", + "on_scroll_up": "Ylöspäin vieritettäessä", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Kapseli", + "plus": "Plus", + "pretty": "Kaunis", + "price": "Hinta", + "primary_style": "Ensisijainen tyyli", + "rectangle": "Suorakaide", + "regular": "Normaali", + "related": "Aiheeseen liittyvä", + "reverse": "Käänteinen", + "rich_text": "Rich text", + "right": "Oikea", + "secondary_style": "Toissijainen tyyli", + "semibold": "Puolilihavoitu", + "shaded": "Varjostettu", + "show_second_image": "Näytä toinen kuva", + "single": "Yksittäinen", + "slide_left": "Liu'uta vasemmalle", + "slide_up": "Liu'uta ylös", + "spotify": "Spotify", + "stack": "Pino", + "text_only": "Vain teksti", + "threads": "Threads", + "thumbnails": "Pikkukuvat", + "tight": "Tiivis", + "top_left": "Ylhäällä vasemmalla", + "top_right": "Ylhäällä oikealla", + "top": "Yläreuna", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Alleviivattu", + "video": "Video", + "wide": "Laaja", + "youtube": "YouTube", + "below_image": "Kuvan alapuolella", + "crop_to_fit": "Rajaa sopivaksi", + "maintain_aspect_ratio": "Säilytä kuvasuhde", + "off": "Ei käytössä", + "on_image": "Kuvan päällä", + "accent": "Korostus", + "body": "Leipäteksti", + "button_primary": "Ensisijainen painike", + "button_secondary": "Toissijainen painike", + "compact": "Kompakti", + "hidden": "Piilotettu", + "hint": "Vihje", + "social_bluesky": "Some: Bluesky", + "social_facebook": "Some: Facebook", + "social_instagram": "Some: Instagram", + "social_linkedin": "Some: LinkedIn", + "social_pinterest": "Some: Pinterest", + "social_snapchat": "Some: Snapchat", + "social_spotify": "Some: Spotify", + "social_threads": "Some: Threads", + "social_tiktok": "Some: TikTok", + "social_tumblr": "Some: Tumblr", + "social_twitter": "Some: X (Twitter)", + "social_whatsapp": "Some: WhatsApp", + "social_vimeo": "Some: Vimeo", + "social_youtube": "Some: YouTube", + "spotlight": "Spotlight", + "standard": "Normaali", + "subheading": "Alaotsikko", + "blur": "Sumeus", + "lift": "Nosto", + "reveal": "Paljastus", + "scale": "Skaalaus", + "subtle_zoom": "Zoomaus" + }, + "content": { + "advanced": "Kehittynyt", + "background_image": "Taustakuva", + "background_video": "Taustavideo", + "block_size": "Lohkokoko", + "borders": "Reunukset", + "describe_the_video_for": "Kuvaile videota näytönlukijoita käyttäviä asiakkaita varten. [Lisätietoja](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Osion koko", + "slideshow_width": "Dian leveys", + "typography": "Typografia", + "width_is_automatically_optimized": "Leveys optimoidaan automaattisesti mobiililaitteille.", + "complementary_products": "Täydentävät tuotteet on määritettävä Search & Discovery -sovelluksella. [Lisätietoja](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Sarakkeet optimoidaan automaattisesti mobiililaitteille", + "content_width": "Sisällön leveyttä sovelletaan vain, kun osion leveydeksi on valittu täysi leveys.", + "adjustments_affect_all_content": "Vaikuttaa kaikkeen tämän lohkon sisältöön", + "responsive_font_sizes": "Koko skaalataan automaattisesti näytön kokoiseksi", + "buttons": "Painikkeet", + "swatches": "Väriruudut", + "variant_settings": "Version asetukset", + "background": "Tausta", + "appearance": "Ulkoasu", + "arrows": "Nuolet", + "body_size": "Leipätekstin koko", + "mobile_size": "Mobiilikoko", + "bottom_row_appearance": "Alarivin ulkoasu", + "cards_layout": "Korttien asettelu", + "carousel_navigation": "Karusellinavigointi", + "carousel_pagination": "Karusellisivunumerointi", + "copyright": "Tekijänoikeus", + "edit_logo_in_theme_settings": "Muokkaa logoa kohdassa [teeman asetukset](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Muokkaa hinnan muotoilua kohdassa [teeman asetukset](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Muokkaa version tyyliä kohdassa [teeman asetukset](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Rekisteröitymiset lisäävät [asiakasprofiilit](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Jotta painike näkyisi, Shop-kanavan tulee olla asennettuna ja Shop Payn aktivoituna. [Lisätietoja](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Fontit", + "grid": "Ruudukko", + "heading_size": "Otsikon koko", + "image": "Kuva", + "input": "Syöte", + "layout": "Pohja", + "link": "Linkki", + "link_padding": "Linkin täyttö", + "localization": "Lokalisointi", + "logo": "Logo", + "margin": "Marginaali", + "media": "Media", + "media_1": "Media 1", + "media_2": "Media 2", + "menu": "Valikko", + "mobile_layout": "Mobiiliasettelu", + "padding": "Täyttö", + "padding_desktop": "Työpöydän täyttö", + "paragraph": "Kappale", + "policies": "Käytännöt", + "popup": "Ponnahdusikkuna", + "search": "Haku", + "section_layout": "Osion asettelu", + "size": "Koko", + "social_media": "Sosiaalinen media", + "submit_button": "Lähetä-painike", + "text_presets": "Tekstin esiasetukset", + "transparent_background": "Läpinäkyvä tausta", + "typography_primary": "Ensisijainen typografia", + "typography_secondary": "Toissijainen typografia", + "typography_tertiary": "Kolmas typografia", + "mobile_width": "Mobiilileveys", + "width": "Leveys", + "images": "Kuvat", + "visibility": "Näkyvyys", + "visible_if_collection_has_more_products": "Näkyvissä, jos kokoelmassa on näytettyä enemmän tuotteita", + "carousel": "Karuselli", + "colors": "Värit", + "collection_page": "Kokoelmasivu", + "copyright_info": "Lisätietoja [tekijänoikeusilmoituksen muokkaamisesta](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Asiakastili", + "edit_empty_state_collection_in_theme_settings": "Muokkaa tyhjän tilan kokoelmaa kohdassa [teema-asetukset](/editor?context=theme&category=search)", + "grid_layout": "Ruudukkoasettelu", + "home_page": "Etusivu", + "inverse_logo_info": "Käytetään, kun läpinäkyvän ylätunnisteen taustaksi on määritetty käänteinen", + "manage_customer_accounts": "[Hallitse näkyvyyttä](/admin/settings/customer_accounts) asiakastilin asetuksissa. Vanhoja tilejä ei tueta.", + "manage_policies": "[Hallinnoi käytäntöjä](/admin/settings/legal)", + "product_page": "Tuotesivu", + "text": "Teksti", + "thumbnails": "Pikkukuvat", + "app_required_for_ratings": "Tuotearviot edellyttävät sovellusta. [Lue lisää](https://help.shopify.com/manual/apps)", + "icon": "Kuvake", + "manage_store_name": "[Hallitse kaupan nimeä](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Esittää ylätason kokoelman", + "resource_reference_collection_card_image": "Esittää kuvan ylätason kokoelmasta", + "resource_reference_collection_title": "Esittää ylätason kokoelman otsikon", + "resource_reference_product": "Automaattinen liitäntä ylätason tuotteeseen", + "resource_reference_product_card": "Esittää tuotteen ylätason osiosta", + "resource_reference_product_inventory": "Esittää ylätason tuotteen varaston", + "resource_reference_product_price": "Esittää ylätason tuotteen hinnan", + "resource_reference_product_recommendations": "Näyttää suosituksia ylätason tuotteen pohjalta", + "resource_reference_product_review": "Esittää arvosteluja ylätason tuotteesta", + "resource_reference_product_swatches": "Esittää ylätason tuotteen väriruutuja", + "resource_reference_product_title": "Esittää ylätason tuotteen otsikon", + "resource_reference_product_variant_picker": "Esittää ylätason tuotteen versioita", + "resource_reference_product_media": "Näyttää mediaa ylätason tuotteesta", + "product_media": "Tuotemediat", + "section_link": "Osiolinkki" + }, + "html_defaults": { + "share_information_about_your": "

Kerro brändiäsi koskevia tietoja asiakkaillesi. Kuvaile tuotetta, jaa ilmoituksia tai toivota asiakkaat tervetulleiksi kauppaasi.

" + }, + "text_defaults": { + "button_label": "Osta nyt", + "collapsible_row": "Pienenettävä rivi", + "heading": "Otsikko", + "email_signup_button_label": "Tilaa", + "accordion_heading": "Haitariotsikko", + "contact_form_button_label": "Lähetä", + "popup_link": "Ponnahduslinkki", + "sign_up": "Rekisteröidy", + "welcome_to_our_store": "Tervetuloa kauppaamme", + "be_bold": "Tule huomatuksi.", + "shop_our_latest_arrivals": "Osta uusimpia tuotteitamme!" + }, + "info": { + "carousel_layout_on_mobile": "Karusellia käytetään mobiililaitteessa", + "link_info": "Valinnainen: tekee kuvakkeesta klikattavan", + "video_alt_text": "Kuvaile videota avustavaa teknologiaa käyttäville", + "video_autoplay": "Videot on mykistetty oletuksena", + "video_external": "Käytä YouTube- tai Vimeo-linkkiä", + "carousel_hover_behavior_not_supported": "Karusellin osoittamista ei tueta, kun Karuselli-tyyppi on valittu osiotasolla", + "checkout_buttons": "Antaa ostajille mahdollisuuden maksaa kassalla nopeammin ja voi parantaa konversiota. [Lisätietoja](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Mukautettu otsikko", + "edit_presets_in_theme_settings": "Muokkaa esiasetuksia kohdassa [teeman asetukset](/editor?context=theme&category=typography)", + "enable_filtering_info": "Mukauta suodattimia [Search & Discovery ‑sovelluksella](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Mobiililaitteille käytetään ruudukkopohjaa", + "logo_font": "Käytetään vain, kun logoa ei ole valittu", + "manage_countries_regions": "[Hallinnoi maita/alueita](/admin/settings/markets)", + "manage_languages": "[Hallinnoi kieliä](/admin/settings/languages)", + "transparent_background": "Tarkista luettavuus jokaisessa mallissa, jossa käytetään läpinäkyvää taustaa", + "aspect_ratio_adjusted": "Säädetty joissakin pohjissa", + "auto_open_cart_drawer": "Kun veto-ostoskori on käytössä, se avataan automaattisesti, kun tuote lisätään ostoskoriin.", + "custom_liquid": "Luo vaativampia mukautuksia lisäämällä sovelluksen koodinpätkiä tai muuta koodia. [Lue lisää](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Käyttökohteita käytetyt suodattimet, alennuskoodit ja hakuehdotukset", + "applies_on_image_only": "Koskee vain kuvia", + "hover_effects": "Käytetään tuote- ja kokoelmakorteissa" + }, + "categories": { + "basic": "Basic", + "collection": "Kokoelma", + "collection_list": "Kokoelmaluettelo", + "footer": "Alatunniste", + "forms": "Lomakkeet", + "header": "Ylätunniste", + "layout": "Pohja", + "links": "Linkit", + "product": "Tuote", + "product_list": "Esittelykokoelma", + "banners": "Bannerit", + "collections": "Kokoelmat", + "custom": "Mukautettu", + "decorative": "Koristeellinen", + "products": "Tuotteet", + "other_sections": "Muu", + "storytelling": "Tarinankerronta" + } +} diff --git a/locales/fr.json b/locales/fr.json new file mode 100644 index 000000000..cc5a24772 --- /dev/null +++ b/locales/fr.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Charger la vidéo : {{ description }}", + "sold_out": "Épuisé", + "email_signup": { + "label": "E-mail", + "placeholder": "Adresse e-mail", + "success": "Merci de vous être abonné(e) !" + }, + "filter": "Filtrer", + "payment_methods": "Moyens de paiement", + "contact_form": { + "name": "Nom", + "email": "E-mail", + "phone": "Téléphone", + "comment": "Commentaire", + "post_success": "Merci de nous avoir contactés. Nous vous répondrons dès que possible.", + "error_heading": "Veuillez ajuster les éléments suivants :" + } + }, + "accessibility": { + "play_model": "Jouer le modèle 3D", + "play_video": "Lire la vidéo", + "unit_price": "Prix unitaire", + "country_results_count": "{{ count }} résultats", + "slideshow_pause": "Interrompre le diaporama", + "slideshow_play": "Lire le diaporama", + "remove_item": "Supprimer {{ title}}", + "skip_to_text": "Ignorer et passer au contenu", + "skip_to_product_info": "Passer aux informations sur le produit", + "skip_to_results_list": "Passer à la liste des résultats", + "new_window": "S’ouvre dans une nouvelle fenêtre.", + "slideshow_next": "Diapositive suivante", + "slideshow_previous": "Diapositive précédente", + "close_dialog": "Fermer la boîte de dialogue", + "reset_search": "Réinitialiser la recherche", + "search_results_count": "{{ count }} résultats de recherche trouvés pour « {{ query }} »", + "search_results_no_results": "Aucun résultat trouvé pour « {{ query }} »", + "filters": "Filtres", + "filter_count": { + "one": "{{ count }} filtre appliqué", + "other": "{{ count }} filtres appliqués", + "many": "{{ count }} filtres appliqués" + }, + "account": "Ouvrir le menu du compte", + "cart": "Panier", + "cart_count": "Nombre total d’articles dans le panier", + "menu": "Menu", + "country_region": "Pays/région", + "slide_status": "Diapositive {{ index }} sur {{ length }}", + "scroll_to": "Faire défiler vers {{ title }}", + "loading_product_recommendations": "Chargement des recommandations de produits", + "discount": "Appliquer un code de réduction", + "discount_applied": "Code de réduction appliqué : {{ code }}", + "open_cart_drawer": "Ouvrir le panier", + "inventory_status": "Statut du stock", + "pause_video": "Mettre la vidéo en pause", + "find_country": "Trouver un pays", + "localization_region_and_language": "Ouvrir le sélecteur de région et de langue", + "open_search_modal": "Ouvrir la recherche", + "decrease_quantity": "Diminuer la quantité", + "increase_quantity": "Augmenter la quantité", + "quantity": "Quantité", + "rating": "La note de ce produit est {{ rating }} sur 5", + "nested_product": "{{ product_title }} pour {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Ajouter au panier", + "clear_all": "Tout effacer", + "remove": "Supprimer", + "view_in_your_space": "Afficher dans votre espace", + "show_filters": "Filtrer", + "clear": "Effacer", + "continue_shopping": "Continuer les achats", + "log_in_html": "Vous possédez un compte ? Connectez-vous pour payer plus vite.", + "see_items": { + "one": "Voir {{ count }} article", + "other": "Voir {{ count }} articles", + "many": "Voir {{ count }} articles" + }, + "view_all": "Voir tout", + "add": "Ajouter", + "choose": "Choisir", + "added": "Ajouté", + "show_less": "Afficher moins", + "show_more": "Afficher plus", + "close": "Fermer", + "more": "Plus", + "reset": "Réinitialiser", + "zoom": "Zoom", + "close_dialog": "Fermer la boîte de dialogue", + "enter_using_password": "Accéder avec le mot de passe", + "submit": "Soumettre", + "enter_password": "Saisir le mot de passe", + "back": "Retour", + "log_in": "Se connecter", + "log_out": "Se déconnecter", + "remove_discount": "Supprimer le {{ code }} de réduction", + "view_store_information": "Afficher les informations de la boutique", + "apply": "Appliquer", + "sign_up": "S’inscrire", + "sign_in_options": "Autres options de connexion", + "open_image_in_full_screen": "Ouvrir l’image en plein écran", + "sort": "Trier", + "show_all_options": "Afficher toutes les options" + }, + "content": { + "reviews": "avis", + "language": "Langue", + "localization_region_and_language": "Région et langue", + "no_results_found": "Aucun résultat trouvé", + "cart_total": "Total du panier", + "your_cart_is_empty": "Votre panier est vide", + "product_image": "Image de produit", + "product_information": "Informations sur le produit", + "quantity": "Quantité", + "product_total": "Nombre total de produits", + "cart_estimated_total": "Total estimé", + "seller_note": "Instructions spéciales", + "cart_subtotal": "Sous-total", + "discounts": "Réductions", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Frais de douane et taxes inclus. Réductions et frais d’expédition calculés à l’étape du paiement.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Frais de douane et taxes inclus. Réductions et frais d’expédition calculés à l’étape du paiement.", + "taxes_included_shipping_at_checkout_with_policy_html": "Taxes incluses. Réductions et frais d’expédition calculés à l’étape du paiement.", + "taxes_included_shipping_at_checkout_without_policy": "Taxes incluses. Réductions et frais d’expédition calculés à l’étape du paiement.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Frais de douane inclus. Taxes, réductions et frais d’expédition calculés à l’étape du paiement.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Frais de douane inclus. Taxes, réductions et frais d’expédition calculés à l’étape du paiement.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Taxes, réductions et frais d’expédition calculés à l’étape du paiement.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Taxes, réductions et frais d’expédition calculés à l’étape du paiement.", + "checkout": "Payer", + "cart_title": "Panier", + "price": "Prix", + "price_regular": "Prix régulier", + "price_compare_at": "Prix avant réduction", + "price_sale": "Prix promotionnel", + "duties_and_taxes_included": "Frais de douane et taxes inclus.", + "duties_included": "Frais de douane inclus.", + "shipping_policy_html": "Expédition calculée lors du paiement.", + "taxes_included": "Taxes incluses.", + "product_badge_sold_out": "Épuisé", + "product_badge_sale": "Promotion", + "grid_view": { + "default_view": "Par défaut", + "grid_fieldset": "Grille de colonnes", + "single_item": "Unique", + "zoom_out": "Dézoomer" + }, + "search_input_label": "Rechercher", + "search_input_placeholder": "Rechercher", + "search_results": "Résultats de la recherche", + "search_results_label": "Résultats de la recherche", + "search_results_no_results": "Aucun résultat trouvé pour « {{ terms }} ». Essayez une autre recherche.", + "search_results_resource_articles": "Articles de blog", + "search_results_resource_collections": "Collections", + "search_results_resource_pages": "Pages", + "search_results_resource_products": "Produits", + "search_results_resource_queries": "Suggestions de recherche", + "search_results_view_all": "Tout afficher", + "search_results_view_all_button": "Tout afficher", + "search_results_resource_products_count": { + "one": "{{ count }} produit", + "other": "{{ count }} produits", + "many": "{{ count }} produits" + }, + "recently_viewed_products": "Récemment consulté(s)", + "unavailable": "Indisponible", + "collection_placeholder": "Titre de la collection", + "product_card_placeholder": "Titre du produit", + "product_count": "Nombre de produits", + "item_count": { + "one": "{{ count }} article", + "other": "{{ count }} articles", + "many": "{{ count }} articles" + }, + "errors": "Erreurs", + "price_from": "De {{ price }}", + "search": "Rechercher", + "search_results_no_results_check_spelling": "Aucun résultat trouvé pour « {{ terms }} ». Vérifiez l’orthographe ou utilisez un autre mot ou une autre expression.", + "no_products_found": "Aucun produit trouvé.", + "use_fewer_filters_html": "Essayez d’utiliser moins de filtres, ou effacez tous les filtres.", + "featured_products": "Produits en vedette", + "filters": "Filtres", + "price_filter_html": "Le prix le plus élevé est de {{ price }}", + "blog_details_separator": "|", + "read_more": "Lire plus...", + "wrong_password": "Mot de passe incorrect", + "account_title": "Compte", + "account_title_personalized": "Bonjour {{ first_name }}", + "account_orders": "Commandes", + "account_profile": "Profil", + "discount_code": "Code de réduction", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Droits de douane et taxes inclus. L’expédition est calculée lors du paiement.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Droits de douane et taxes inclus. L’expédition est calculée lors du paiement.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Droits de douane inclus. L’expédition est calculée lors du paiement.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Droits de douane inclus. L’expédition est calculée lors du paiement.", + "pickup_available_at_html": "Retrait disponible à {{ location }}", + "pickup_available_in": "Retrait disponible, {{ pickup_time }}", + "pickup_not_available": "Retrait actuellement non disponible", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Taxes et expédition calculés lors du paiement.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Taxes et expédition calculés lors du paiement.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Taxes incluses. L’expédition est calculée lors du paiement.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Taxes incluses. L’expédition est calculée lors du paiement.", + "view_more_details": "Afficher plus de détails", + "page_placeholder_title": "Titre de la page", + "page_placeholder_content": "Sélectionnez une page pour afficher son contenu.", + "placeholder_image": "Image du paramètre fictif", + "inventory_low_stock": "Stock faible", + "inventory_in_stock": "En stock", + "inventory_out_of_stock": "En rupture de stock", + "inventory_low_stock_show_count": { + "one": "{{ count }} restant(s)", + "other": "{{ count }} restant(s)", + "many": "{{ count }} restant(s)" + }, + "shipping_policy": "Expédition calculée lors du paiement.", + "powered_by": "Cette boutique sera exploitée par", + "store_owner_link_html": "Êtes-vous le propriétaire de la boutique ? Connectez-vous ici", + "shipping_discount_error": "Les réductions sur l’expédition sont affichées lors du paiement après avoir ajouté une adresse", + "discount_code_error": "Le code de réduction ne peut pas être appliqué à votre panier", + "discount": "Réduction" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Utiliser le code de la carte‑cadeau en ligne ou le code QR en boutique", + "title": "Voici le solde de votre carte‑cadeau {{ shop }} d'une valeur de {{ value }} !", + "subtext": "Votre carte‑cadeau", + "shop_link": "Visiter la boutique en ligne", + "add_to_apple_wallet": "Ajouter à Apple Wallet", + "qr_image_alt": "Code QR : scannez‑le pour utiliser votre carte‑cadeau", + "copy_code": "Copier le code de la carte‑cadeau", + "expiration_date": "Expire le {{ expires_on }}", + "copy_code_success": "Le code a bien été copié", + "expired": "Expirée" + } + }, + "placeholders": { + "password": "Mot de passe", + "search": "Rechercher", + "product_title": "Titre de produit", + "collection_title": "Titre de la collection" + }, + "products": { + "product": { + "add_to_cart": "Ajouter au panier", + "added_to_cart": "Ajouté au panier", + "adding_to_cart": "Ajout...", + "add_to_cart_error": "Erreur lors de l’ajout au panier", + "sold_out": "Épuisé", + "unavailable": "Non disponible(s)" + } + }, + "fields": { + "separator": "à" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} commentaire", + "other": "{{ count }} commentaires", + "many": "{{ count }} commentaires" + } + }, + "comment_form": { + "email": "E-mail", + "error": "La publication du commentaire a échoué. Veuillez corriger les éléments suivants :", + "heading": "Laisser un commentaire", + "message": "Message", + "moderated": "Veuillez noter que les commentaires doivent être approuvés avant leur publication.", + "name": "Nom", + "post": "Publier le commentaire", + "success_moderated": "Commentaire publié, en attente de modération", + "success": "Commentaire publié" + } + } +} diff --git a/locales/fr.schema.json b/locales/fr.schema.json new file mode 100644 index 000000000..84ed32ef2 --- /dev/null +++ b/locales/fr.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Bordures", + "collapsible_row": "Rangée réductible", + "custom_section": "Section personnalisée", + "icon": "Icône", + "logo_and_favicon": "Logo et favicon", + "product_buy_buttons": "Boutons d’achat", + "product_description": "Description", + "product_price": "Prix", + "slideshow": "Diaporama", + "typography": "Typographie", + "video": "Vidéo", + "colors": "Couleurs", + "overlapping_blocks": "Chevauchement de blocs", + "product_variant_picker": "Sélecteur de variante", + "slideshow_controls": "Contrôles du diaporama", + "size": "Taille", + "spacing": "Espacement", + "product_recommendations": "Produits recommandés", + "product_media": "Média (produit)", + "featured_collection": "Collection en vedette", + "add_to_cart": "Ajouter au panier", + "email_signup": "Inscription à la liste de diffusion", + "submit_button": "Bouton Soumettre", + "grid_layout_selector": "Sélecteur de mise en page en grille", + "image": "Image", + "list_items": "Articles de la liste", + "facets": "Facettes", + "variants": "Variantes", + "styles": "Styles", + "product_cards": "Cartes de produit", + "primary_button": "Bouton primaire", + "secondary_button": "Bouton secondaire", + "popovers": "Popovers", + "buttons": "Boutons", + "inputs": "Entrées", + "marquee": "Marquee", + "alternating_content_rows": "Rangées alternées", + "pull_quote": "Citation originale", + "contact_form": "Formulaire de contact", + "featured_product": "Produit en vedette", + "icons_with_text": "Icônes avec texte", + "jumbo_text": "Texte géant", + "accelerated_checkout": "Paiement accéléré", + "accordion": "Accordéon", + "accordion_row": "Rangées d’accordéon", + "animations": "Animations", + "announcement": "Annonce", + "announcement_bar": "Barre d’annonces", + "badges": "Badges", + "button": "Bouton", + "cart": "Panier", + "cart_items": "Articles dans le panier", + "cart_products": "Produits dans le panier", + "cart_title": "Panier", + "collection": "Collection", + "collection_card": "Carte de collection", + "collection_columns": "Colonnes de collection", + "collection_container": "Collection", + "collection_description": "Description de la collection", + "collection_image": "Image de la collection", + "collection_info": "Informations sur la collection", + "collection_list": "Liste des collections", + "collections": "Collections", + "content": "Contenu", + "content_grid": "Grille de contenu", + "details": "Détails", + "divider": "Séparateur", + "filters": "Filtrage et tri", + "follow_on_shop": "Suivre sur Shop", + "footer": "Pied de page", + "footer_utilities": "Options du pied de page", + "group": "Groupe", + "header": "En-tête", + "heading": "Titre", + "icons": "Icônes", + "image_with_text": "Image avec texte", + "input": "Entrée", + "logo": "Logo", + "magazine_grid": "Grille de magazine", + "media": "Support multimédia", + "menu": "Menu", + "mobile_layout": "Mise en page sur mobile", + "payment_icons": "Icônes de paiement", + "popup_link": "Lien ouvrant une pop-up", + "predictive_search": "Rechercher le popover", + "predictive_search_empty": "Recherche prédictive sans résultats", + "price": "Prix", + "product": "Produit", + "product_card": "Carte de produit", + "product_card_media": "Support multimédia", + "product_card_rendering": "Présentation de la carte de produit", + "product_grid": "Grille", + "product_grid_main": "Grille de produit", + "product_image": "Image de produit", + "product_information": "Informations sur le produit", + "product_review_stars": "Étoiles de notation", + "quantity": "Quantité", + "row": "Rangée", + "search": "Rechercher", + "section": "Section", + "selected_variants": "Variantes sélectionnées", + "shop_the_look": "Acheter le look", + "slide": "Diapositive", + "social_media_links": "Icônes de médias sociaux", + "steps": "Étapes", + "summary": "Résumé", + "swatches": "Échantillons", + "testimonials": "Témoignages", + "text": "Texte", + "title": "Titre", + "utilities": "Utilitaires", + "search_input": "Champ de recherche", + "search_results": "Résultats de la recherche", + "read_only": "Lecture seule", + "collections_bento": "Liste de collections : Bento", + "faq_section": "FAQ", + "hero": "Héros", + "product_list": "Collection en vedette", + "spacer": "Espacement", + "video_section": "Vidéo", + "custom_liquid": "Code Liquid personnalisé", + "blog": "Blog", + "blog_post": "Article de blog", + "blog_posts": "Articles de blog", + "caption": "Légende", + "collection_card_image": "Image", + "collection_title": "Titre de la collection", + "collection_links": "Liens des collections", + "collection_links_spotlight": "Liens de collections : Spotlight", + "collection_links_text": "Liens de collections : Texte", + "collections_carousel": "Liste de collections : Carrousel", + "collections_editorial": "Liste de collections : éditorial", + "collections_grid": "Liste de collections : Grille", + "copyright": "Droits d’auteur", + "count": "Quantité", + "divider_section": "Séparateur", + "drawers": "Tiroirs", + "editorial": "Éditorial", + "editorial_jumbo_text": "Éditorial : Texte géant", + "hero_marquee": "Héros : Marquee", + "input_fields": "Champs de saisie", + "local_pickup": "Retrait en magasin", + "marquee_section": "Marquee", + "media_with_text": "Support multimédia avec texte", + "page": "Page", + "page_content": "Contenu", + "page_layout": "Mise en page de la page", + "policy_list": "Liens vers les politiques", + "prices": "Prix", + "product_list_button": "Bouton Afficher tout", + "products_carousel": "Collection en vedette : Carrousel", + "products_editorial": "Collection en vedette : Éditorial", + "products_grid": "Collection en vedette : Grille", + "social_link": "Lien de réseau social", + "split_showcase": "Diviser la présentation", + "variant_pickers": "Sélecteurs de variante", + "view_all_button": "Voir tout", + "pills": "Boutons pilule", + "product_title": "Titre de produit", + "large_logo": "Grand logo", + "product_inventory": "Stock de produits", + "description": "Description" + }, + "settings": { + "autoplay": "Jeu automatique", + "background": "Arrière‑plan", + "border_radius": "Rayon de coin", + "border_width": "Épaisseur de la bordure", + "borders": "Bordures", + "bottom_padding": "Marge inférieure", + "color": "Couleur", + "content_direction": "Direction du contenu", + "content_position": "Position du contenu", + "cover_image_size": "Taille de l’image de couverture", + "cover_image": "Image de couverture", + "custom_width": "Largeur personnalisée", + "enable_video_looping": "Lecture en boucle des vidéos", + "favicon": "Favicon", + "heading": "Titre", + "icon": "Icône", + "image_icon": "Icône de l’image", + "make_section_full_width": "Rendre la section pleine largeur", + "overlay_opacity": "Opacité de la superposition", + "padding": "Marge intérieure", + "product": "Produit", + "text": "Texte", + "top_padding": "Marge supérieure", + "video": "Vidéo", + "video_alt_text": "Texte alternatif", + "video_loop": "Mettre en loop la vidéo", + "video_position": "Position de la vidéo", + "width": "Largeur", + "alignment": "Alignement", + "button": "Bouton", + "colors": "Couleurs", + "content_alignment": "Alignement du contenu", + "custom_minimum_height": "Hauteur minimale personnalisée", + "font_family": "Famille de polices", + "gap": "Écart", + "geometric_translate_y": "Translation géométrique Y", + "image": "Image", + "image_opacity": "Opacité de l’image", + "image_position": "Position de l’image", + "image_ratio": "Rapport d’aspect de l’image", + "label": "Étiquette", + "line_height": "Hauteur de la ligne", + "link": "Lien", + "layout_gap": "Écart dans la mise en page", + "minimum_height": "Hauteur minimale", + "opacity": "Opacité", + "primary_color": "Liens", + "section_width": "Largeur de la section", + "size": "Taille", + "slide_spacing": "Écart entre les diapositives", + "slide_width": "Largeur de la diapositive", + "slideshow_fullwidth": "Diapositives en pleine largeur", + "style": "Style", + "text_case": "Cas", + "z_index": "Z-index", + "limit_content_width": "Largeur limite du contenu", + "color_scheme": "Nuancier de couleurs", + "inherit_color_scheme": "Hériter du nuancier de couleurs", + "product_count": "Nombre de produits", + "product_type": "Type de produit", + "content_width": "Largeur du contenu", + "collection": "Collection", + "enable_sticky_content": "Contenu fixe sur ordinateur", + "error_color": "Erreur", + "success_color": "Opération réussie", + "primary_font": "Police principale", + "secondary_font": "Police secondaire", + "tertiary_font": "Police tertiaire", + "columns": "Colonnes", + "items_to_show": "Articles à afficher", + "layout": "Mise en page", + "layout_type": "Type", + "show_grid_layout_selector": "Afficher le sélecteur de mise en page en grille", + "view_more_show": "Afficher le bouton Tout afficher", + "image_gap": "Écart d’image", + "width_desktop": "Largeur d’écran de bureau", + "width_mobile": "Largeur d’écran d’appareil mobile", + "border_style": "Style de bordure", + "height": "Hauteur", + "thickness": "Épaisseur", + "stroke": "Trait", + "filter_style": "Style de filtre", + "swatches": "Échantillons", + "quick_add_colors": "Ajout de couleur rapide", + "divider_color": "Séparateur", + "border_opacity": "Opacité de la bordure", + "hover_background": "Arrière‑plan de survol", + "hover_borders": "Bordures de survol", + "hover_text": "Texte de survol", + "primary_hover_color": "Liens de survol", + "primary_button_text": "Texte du bouton principal", + "primary_button_background": "Arrière‑plan du bouton principal", + "primary_button_border": "Bordure du bouton principal", + "secondary_button_text": "Texte du bouton secondaire", + "secondary_button_background": "Arrière‑plan du bouton secondaire", + "secondary_button_border": "Bordure du bouton secondaire", + "shadow_color": "Ombre", + "video_autoplay": "Lecture automatique", + "video_cover_image": "Image de couverture", + "video_external_url": "URL", + "video_source": "Source", + "first_row_media_position": "Position des supports multimédias de la première rangée", + "shadow_opacity": "Opacité de l’ombre", + "show_filter_label": "Étiquettes de texte pour les filtres appliqués", + "show_swatch_label": "Étiquettes de texte pour les échantillons", + "accordion": "Accordéon", + "aspect_ratio": "Format d’image", + "auto_rotate_announcements": "Rotation automatique des annonces", + "auto_rotate_slides": "Rotation automatique des diapositives", + "badge_corner_radius": "Rayon de coin", + "badge_position": "Position sur les cartes", + "badge_sale_color_scheme": "Vente", + "badge_sold_out_color_scheme": "Épuisé", + "behavior": "Comportement", + "blur": "Ombre floue", + "border": "Bordure", + "bottom": "En bas", + "card_image_height": "Hauteur de l’image de produit", + "carousel_on_mobile": "Carrousel sur appareil mobile", + "cart_count": "Quantité dans le panier", + "cart_items": "Articles dans le panier", + "cart_related_products": "Produits associés", + "cart_title": "Panier", + "cart_total": "Total du panier", + "cart_type": "Type", + "case": "Cas", + "checkout_buttons": "Boutons de paiement accéléré", + "collection_list": "Collections", + "collection_templates": "Modèles de collection", + "content": "Contenu", + "corner_radius": "Rayon de coin", + "country_region": "Pays/région", + "currency_code": "Code de devise", + "custom_height": "Hauteur personnalisée", + "desktop_height": "Hauteur du bureau", + "direction": "Direction", + "display": "Afficher", + "divider_thickness": "Épaisseur du séparateur", + "divider": "Séparateur", + "dividers": "Séparateurs", + "drop_shadow": "Ombre portée", + "empty_state_collection_info": "Affiché avant la saisie d’une recherche", + "empty_state_collection": "Collection vide", + "enable_filtering": "Filtres", + "enable_grid_density": "Contrôle de la mise en page de grille", + "enable_sorting": "Tri", + "enable_zoom": "Activer le zoom", + "equal_columns": "Colonnes uniformes", + "expand_first_group": "Agrandir le premier groupe", + "extend_media_to_screen_edge": "Afficher le support multimédia en plein écran", + "extend_summary": "Afficher en plein écran", + "extra_large": "Très grand", + "extra_small": "Très petit", + "flag": "Marqueur", + "font_price": "Police du prix", + "font_weight": "Épaisseur de la police", + "font": "Police", + "full_width_first_image": "Image principale en pleine largeur", + "full_width_on_mobile": "Pleine largeur sur mobile", + "heading_preset": "Réglage prédéfini pour le titre", + "hide_unselected_variant_media": "Masquer le support multimédia non sélectionné", + "horizontal_gap": "Écart horizontal", + "horizontal_offset": "Décalage horizontal de l’ombre", + "hover_behavior": "Comportement au survol", + "icon_background": "Arrière-plan de l’icône", + "icons": "Icônes", + "image_border_radius": "Rayon des coins de l’image", + "installments": "Versements", + "integrated_button": "Bouton intégré", + "language_selector": "Sélecteur de langue", + "large": "Grand", + "left_padding": "Marge de gauche", + "left": "Gauche", + "letter_spacing": "Espacement des lettres", + "limit_media_to_screen_height": "Limiter à la hauteur de l’écran", + "limit_product_details_width": "Limiter la largeur des détails de produit", + "link_preset": "Réglage prédéfini pour le lien", + "links": "Liens", + "logo": "Logo", + "loop": "Boucle", + "make_details_sticky_desktop": "Fixe sur le bureau", + "max_width": "Largeur max.", + "media_height": "Hauteur du support multimédia", + "media_overlay": "Superposition du support multimédia", + "media_position": "Position du support multimédia", + "media_type": "Type de support multimédia", + "media_width": "Largeur du support multimédia", + "menu": "Menu", + "mobile_columns": "Colonnes sur appareil mobile", + "mobile_height": "Hauteur sur appareil mobile", + "mobile_logo_image": "Logo sur mobile", + "mobile_quick_add": "Ajout rapide sur appareil mobile", + "motion_direction": "Direction du mouvement", + "motion": "Mouvement", + "movement_direction": "Direction du déplacement", + "navigation_bar_color_scheme": "Schéma de couleurs de la barre de navigation", + "navigation_bar": "Barre de navigation", + "navigation": "Navigation", + "open_new_tab": "Ouvrir le lien dans un nouvel onglet", + "overlay_color": "Couleur de superposition", + "overlay": "Superposition", + "padding_bottom": "Marge inférieure", + "padding_horizontal": "Marge horizontale", + "padding_top": "Marge supérieure", + "page_width": "Largeur de la page", + "pagination": "Pagination", + "placement": "Placement", + "position": "Position", + "preset": "Réglage prédéfini", + "product_cards": "Cartes de produits", + "product_pages": "Pages de produits", + "product_templates": "Modèles de produits", + "products": "Produits", + "quick_add": "Ajout rapide", + "ratio": "Rapport", + "regular": "Normal", + "review_count": "Nombre d’avis", + "right": "Droite", + "row_height": "Hauteur de la rangée", + "row": "Rangée", + "seller_note": "Ajouter un message pour le vendeur", + "shape": "Forme", + "show_as_accordion": "Afficher sous forme d’accordéon sur appareil mobile", + "show_sale_price_first": "Afficher d’abord le prix avant réduction", + "show_tax_info": "Informations fiscales", + "show": "Afficher", + "small": "Petit", + "speed": "Vitesse", + "statement": "Relevé", + "sticky_header": "En-tête fixe", + "text_hierarchy": "Hiérarchie du texte", + "text_presets": "Réglages de texte prédéfinis", + "title": "Titre", + "top": "Haut", + "type": "Type", + "type_preset": "Réglage de texte prédéfini", + "underline_thickness": "Largeur du soulignement", + "variant_images": "Images de variantes", + "vendor": "Fournisseur", + "vertical_gap": "Écart vertical", + "vertical_offset": "Décalage vertical de l’ombre", + "vertical_on_mobile": "Vertical sur appareil mobile", + "view_all_as_last_card": "« Afficher tout » comme dernière carte", + "weight": "Poids", + "wrap": "Renvoi à la ligne", + "read_only": "Lecture seule", + "always_stack_buttons": "Toujours empiler les boutons", + "background_color": "Couleur d’arrière-plan", + "custom_mobile_size": "Taille mobile personnalisée", + "custom_mobile_width": "Largeur mobile personnalisée", + "fixed_height": "Hauteur en pixels", + "fixed_width": "Largeur en pixels", + "gradient_direction": "Direction du dégradé", + "hide_padding": "Masquer l’espacement", + "logo_font": "Police du logo", + "overlay_style": "Style de superposition", + "percent_height": "Hauteur en pourcentage", + "percent_size_mobile": "Taille en pourcentage", + "percent_size": "Taille en pourcentage", + "percent_width": "Largeur en pourcentage", + "pixel_size_mobile": "Taille en pixels", + "pixel_size": "Taille en pixels", + "size_mobile": "Taille mobile", + "transparent_background": "Arrière-plan transparent", + "unit": "Unité", + "account": "Compte", + "align_baseline": "Aligner la ligne de base du texte", + "add_discount_code": "Autoriser les réductions dans le panier", + "background_overlay": "Superposition d’arrière-plan", + "background_media": "Support multimédia en arrière-plan", + "border_thickness": "Épaisseur de la bordure", + "bottom_row": "Rangée inférieure", + "button_text_case": "Casse du texte", + "button_text_weight": "Épaisseur du texte", + "card_size": "Taille de carte", + "auto_open_cart_drawer": "L’option « Ajouter au panier » ouvre automatiquement le panier", + "collection_count": "Nombre de collections", + "custom_liquid": "Code Liquid", + "default": "Par défaut", + "default_logo": "Logo par défaut", + "divider_width": "Largeur du séparateur", + "headings": "Titres", + "hide_logo_on_home_page": "Masquer le logo sur la page d’accueil", + "horizontal_padding": "Espacement horizontal", + "inverse": "Inverse", + "inverse_logo": "Logo inverse", + "layout_style": "Style", + "length": "Longueur", + "mobile_card_size": "Taille de carte mobile", + "mobile_pagination": "Pagination mobile", + "open_row_by_default": "Ouvrir la rangée par défaut", + "page": "Page", + "page_transition_enabled": "Transition de la page", + "right_padding": "Espacement à droite", + "search": "Rechercher", + "search_icon": "Icône de recherche", + "search_position": "Position", + "search_row": "Rangée", + "show_author": "Auteur", + "show_alignment": "Afficher l’alignement", + "show_count": "Afficher la quantité", + "show_date": "Date", + "show_pickup_availability": "Afficher la disponibilité de retrait", + "show_search": "Afficher la recherche", + "use_inverse_logo": "Utiliser le logo inverse", + "vertical_padding": "Espacement vertical", + "visibility": "Visibilité", + "product_corner_radius": "Rayon des coins du produit", + "card_corner_radius": "Rayon des coins de la carte", + "alignment_mobile": "Alignement sur mobile", + "animation_repeat": "Répéter l’animation", + "blurred_reflection": "Réflexion floutée", + "card_hover_effect": "Effet de survol des cartes", + "collection_title_case": "Casse du titre de la collection", + "effects": "Effets", + "inventory_threshold": "Seuil de stock faible", + "product_and_card_title_case": "Casse du titre de produit et de la carte", + "product_title_case": "Casse du titre de produit", + "reflection_opacity": "Opacité de la réflexion", + "show_inventory_quantity": "Afficher la quantité de stock faible", + "text_label_case": "Casse de l’étiquette de texte", + "transition_to_main_product": "Transition de carte de produit à page de produit", + "media": "Support multimédia", + "product_card_carousel": "Afficher le carrousel", + "show_second_image_on_hover": "Afficher la deuxième image au passage de la souris", + "media_fit": "Taille des supports multimédia", + "scroll_speed": "Délai avant l’annonce suivante" + }, + "options": { + "adapt_to_image": "Adapter à l’image", + "apple": "Pomme", + "arrow": "Flèche", + "banana": "Banane", + "bottle": "Bouteille", + "box": "Colis", + "buttons": "Boutons", + "carrot": "Carotte", + "center": "Centre", + "chat_bubble": "Bulle de chat", + "clipboard": "Presse-papiers", + "contain": "Contenir", + "counter": "Compteur", + "cover": "Couverture", + "custom": "Personnalisé", + "dairy_free": "Sans produits laitiers", + "dairy": "Produits laitiers", + "dropdowns": "Menus déroulants", + "dots": "Points", + "dryer": "Sèche-linge", + "end": "Fin", + "eye": "Œil", + "facebook": "Facebook", + "fire": "Feu", + "gluten_free": "Sans gluten", + "heart": "Cœur", + "horizontal": "Horizontale", + "instagram": "Instagram", + "iron": "Fer", + "large": "Grand", + "leaf": "Feuille", + "leather": "Cuir", + "lightning_bolt": "Foudre", + "lipstick": "Rouge à lèvres", + "lock": "Cadenas", + "map_pin": "Épingle de carte", + "medium": "Moyen", + "none": "Aucun", + "numbers": "Numéros", + "nut_free": "Sans noix", + "pants": "Pantalons", + "paw_print": "Empreinte de patte", + "pepper": "Poivre", + "perfume": "Parfum", + "pinterest": "Pinterest", + "plane": "Avion", + "plant": "Plante", + "price_tag": "Étiquette de prix", + "question_mark": "Point d’interrogation", + "recycle": "Recyclage", + "return": "Retour", + "ruler": "Règle", + "serving_dish": "Plat de service", + "shirt": "Chemise", + "shoe": "Chaussure", + "silhouette": "Silhouette", + "small": "Petit", + "snapchat": "Snapchat", + "snowflake": "Flocon de neige", + "star": "Étoile", + "start": "Début", + "stopwatch": "Chronomètre", + "tiktok": "TikTok", + "truck": "Camion", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "vertical": "Verticale", + "vimeo": "Vimeo", + "washing": "Lavage", + "auto": "Auto", + "default": "Par défaut", + "fill": "Remplir", + "fit": "Ajuster", + "full": "Complet", + "full_and_page": "Arrière-plan complet, contenu de la largeur de la page", + "heading": "Titre", + "landscape": "Paysage", + "lg": "L", + "link": "Lien", + "lowercase": "minuscule", + "m": "M", + "outline": "Contour", + "page": "Page", + "portrait": "Portrait", + "s": "S", + "sentence": "Phrase", + "solid": "Uni", + "space_between": "Espace entre", + "square": "Carré", + "uppercase": "Majuscule", + "circle": "Cercle", + "swatches": "Échantillons", + "full_and_page_offset_left": "Arrière-plan complet, contenu de la largeur de la page, décalage à gauche", + "full_and_page_offset_right": "Arrière-plan complet, contenu de la largeur de la page, décalage à droite", + "offset_left": "Décalage à gauche", + "offset_right": "Décalage à droite", + "page_center_aligned": "Page, centrée", + "page_left_aligned": "Page, alignée à gauche", + "page_right_aligned": "Page, alignée à droite", + "button": "Bouton", + "caption": "Légende", + "h1": "Titre 1", + "h2": "Titre 2", + "h3": "Titre 3", + "h4": "Titre 4", + "h5": "Titre 5", + "h6": "Titre 6", + "paragraph": "Paragraphe", + "primary": "Principal", + "secondary": "Secondaire", + "tertiary": "Tertiaire", + "chevron_left": "Chevron gauche", + "chevron_right": "Chevron droite", + "diamond": "Losange", + "grid": "Grille", + "parallelogram": "Parallélogramme", + "rounded": "Arrondis", + "fit_content": "Ajuster", + "pills": "Boutons pilule", + "heavy": "Épais", + "thin": "Fin", + "drawer": "Tiroir", + "preview": "Aperçu", + "text": "Texte", + "video_uploaded": "Téléchargée", + "video_external_url": "URL externe", + "aspect_ratio": "Proportions", + "above_carousel": "Au-dessus du carrousel", + "all": "Tous", + "always": "Toujours", + "arrows_large": "Grandes flèches", + "arrows": "Flèches", + "balance": "Solde", + "bento": "Bento", + "black": "Noir", + "bluesky": "Bluesky", + "body_large": "Corps (grand)", + "body_regular": "Corps (normal)", + "body_small": "Corps (petit)", + "bold": "Gras", + "bottom_left": "En bas à gauche", + "bottom_right": "En bas à droite", + "bottom": "En bas", + "capitalize": "Mettre en majuscules", + "caret": "Caret", + "carousel": "Carrousel", + "check_box": "Case à cocher", + "chevron_large": "Gros chevrons", + "chevron": "Chevron", + "chevrons": "Chevrons", + "classic": "Classique", + "collection_images": "Images de la collection", + "color": "Couleur", + "complementary": "Complémentaire", + "dissolve": "Fondu", + "dotted": "Pointillé", + "editorial": "Éditorial", + "extra_large": "Très grand", + "extra_small": "Très petit", + "featured_collections": "Collections en vedette", + "featured_products": "Produits en vedette", + "font_primary": "Principal", + "font_secondary": "Secondaire", + "font_tertiary": "Tertiaire", + "forward": "Avancer", + "full_screen": "Plein écran", + "heading_extra_large": "Titre (très grand)", + "heading_extra_small": "Titre (très petit)", + "heading_large": "Titre (grand)", + "heading_regular": "Titre (normal)", + "heading_small": "Titre (petit)", + "icon": "Icône", + "image": "Image", + "input": "Entrée", + "inside_carousel": "Dans le carrousel", + "inverse_large": "Inversé en grande taille", + "inverse": "Inverse", + "large_arrows": "Grandes flèches", + "large_chevrons": "Gros chevrons", + "left": "Gauche", + "light": "Clair", + "linkedin": "LinkedIn", + "loose": "Lâche", + "media_first": "Support multimédia en premier", + "media_second": "Support multimédia en second", + "modal": "Fenêtre modale", + "narrow": "Étroit", + "never": "Jamais", + "next_to_carousel": "À côté du carrousel", + "normal": "Normal", + "nowrap": "Pas de retour à la ligne", + "off_media": "En dehors du support multimédia", + "on_media": "Sur le support multimédia", + "on_scroll_up": "Lors du défilement vers le haut", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Rectangle arrondi", + "plus": "Plus", + "pretty": "Optimisé", + "price": "Prix", + "primary_style": "Style principal", + "rectangle": "Rectangle", + "regular": "Normal", + "related": "Associé", + "reverse": "Inverser", + "rich_text": "Texte enrichi", + "right": "Droite", + "secondary_style": "Style secondaire", + "semibold": "Semi-gras", + "shaded": "Ombré", + "show_second_image": "Afficher la deuxième image", + "single": "Unique", + "slide_left": "Faire glisser vers la gauche", + "slide_up": "Glisser vers le haut", + "spotify": "Spotify", + "stack": "Pile", + "text_only": "Texte uniquement", + "threads": "Threads", + "thumbnails": "Miniatures", + "tight": "Serré", + "top_left": "En haut à gauche", + "top_right": "En haut à droite", + "top": "Haut", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Souligner", + "video": "Vidéo", + "wide": "Large", + "youtube": "YouTube", + "down": "Bas", + "fixed": "Fixe", + "gradient": "Dégradé", + "percent": "Pourcentage", + "pixel": "Pixel", + "up": "Haut", + "compact": "Compacte", + "standard": "Standard", + "accent": "Accent", + "below_image": "Sous l’image", + "body": "Corps", + "button_primary": "Bouton primaire", + "button_secondary": "Bouton secondaire", + "crop_to_fit": "Recadrer pour adapter", + "hidden": "Masqué", + "hint": "Astuce", + "maintain_aspect_ratio": "Conserver les proportions", + "off": "Désactivé", + "on_image": "Sur l’image", + "social_bluesky": "Social : Bluesky", + "social_facebook": "Social : Facebook", + "social_instagram": "Social : Instagram", + "social_linkedin": "Social : LinkedIn", + "social_pinterest": "Social : Pinterest", + "social_snapchat": "Social : Snapchat", + "social_spotify": "Social : Spotify", + "social_threads": "Social : Threads", + "social_tiktok": "Social : TikTok", + "social_tumblr": "Social : Tumblr", + "social_twitter": "Social : X (Twitter)", + "social_whatsapp": "Social : WhatsApp", + "social_vimeo": "Social : Vimeo", + "social_youtube": "Social : YouTube", + "spotlight": "Spotlight", + "subheading": "Sous-titre", + "blur": "Flou", + "lift": "Élévation", + "reveal": "Révéler", + "scale": "Échelle", + "subtle_zoom": "Zoom" + }, + "content": { + "background_video": "Vidéo d’arrière-plan", + "describe_the_video_for": "Décrivez la vidéo pour les clients utilisant des lecteurs d’écran. [En savoir plus](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "La largeur est automatiquement optimisée pour les appareils mobiles.", + "advanced": "Avancé", + "background_image": "Image de fond", + "block_size": "Taille du bloc", + "borders": "Bordures", + "section_size": "Taille de la section", + "slideshow_width": "Largeur de la diapositive", + "typography": "Typographie", + "complementary_products": "Les produits complémentaires doivent être configurés via l’application Search & Discovery. [En savoir plus](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Les colonnes s’adapteront automatiquement à l’affichage des appareils mobiles", + "content_width": "La largeur du contenu s’applique uniquement si la largeur de la section est définie sur pleine largeur.", + "adjustments_affect_all_content": "S’applique à l’ensemble du contenu de ce bloc", + "responsive_font_sizes": "Les tailles s’ajustent automatiquement à tous les formats d’écran", + "buttons": "Boutons", + "swatches": "Échantillons", + "variant_settings": "Paramètres des variantes", + "background": "Arrière‑plan", + "appearance": "Apparence", + "arrows": "Flèches", + "body_size": "Taille du corps", + "bottom_row_appearance": "Apparence de la rangée inférieure", + "carousel_navigation": "Navigation dans le carrousel", + "carousel_pagination": "Pagination du carrousel", + "copyright": "Droits d’auteur", + "edit_logo_in_theme_settings": "Modifiez le logo dans [paramètres du thème ](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Modifiez le formatage des prix dans [paramètres du thème ](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Modifiez les variantes de style dans [paramètres du thème ](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Ajout d’inscriptions [profils clients ](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Pour afficher le bouton, le canal Shop doit être installé et Shop Pay activé. [En savoir plus](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Polices", + "grid": "Grille", + "heading_size": "Taille du titre", + "image": "Image", + "input": "Entrée", + "layout": "Mise en page", + "link": "Lien", + "link_padding": "Marge du lien", + "localization": "Localisation", + "logo": "Logo", + "margin": "Marge", + "media": "Support multimédia", + "media_1": "Support multimédia 1", + "media_2": "Support multimédia 2", + "menu": "Menu", + "mobile_layout": "Mise en page sur mobile", + "padding": "Marge", + "padding_desktop": "Marge du bureau", + "paragraph": "Paragraphe", + "policies": "Politiques", + "popup": "Pop-up", + "search": "Rechercher", + "size": "Taille", + "social_media": "Médias sociaux", + "submit_button": "Bouton Soumettre", + "text_presets": "Réglages de texte prédéfinis", + "transparent_background": "Arrière-plan transparent", + "typography_primary": "Typographie principale", + "typography_secondary": "Typographie secondaire", + "typography_tertiary": "Typographie tertiaire", + "mobile_size": "Taille mobile", + "cards_layout": "Mise en page des cartes", + "mobile_width": "Largeur mobile", + "section_layout": "Mise en page de la section", + "width": "Largeur", + "visible_if_collection_has_more_products": "Visible si la collection comprend plus de produits que ceux affichés", + "carousel": "Carrousel", + "colors": "Couleurs", + "collection_page": "Page de collection", + "copyright_info": "Découvrez comment [modifier votre déclaration de droits d’auteur](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Compte client", + "edit_empty_state_collection_in_theme_settings": "Modifier la collection par défaut dans les [paramètres de thèmes ](/editor?context=theme&category=search)", + "grid_layout": "Mise en page en grille", + "home_page": "Page d’accueil", + "images": "Images", + "inverse_logo_info": "Utilisé lorsque l’arrière-plan d’en-tête transparent est défini sur Inverse", + "manage_customer_accounts": "[Gérer la visibilité](/admin/settings/customer_accounts) dans les paramètres des comptes clients. Les anciens comptes ne sont pas pris en charge.", + "manage_policies": "[Gérer les politiques](/admin/settings/legal)", + "product_page": "Page de produit", + "text": "Texte", + "thumbnails": "Miniatures", + "visibility": "Visibilité", + "app_required_for_ratings": "Une application est requise pour les évaluations de produits. [En savoir plus](https://help.shopify.com/manual/apps)", + "icon": "Icône", + "manage_store_name": "[Gérer le nom de la boutique :](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Affiche la collection à partir de la section parent", + "resource_reference_collection_card_image": "Affiche l’image à partir de la collection parent", + "resource_reference_collection_title": "Affiche le titre à partir de la collection parent", + "resource_reference_product": "Se connecte automatiquement au produit parent", + "resource_reference_product_card": "Affiche le produit à partir de la section parent", + "resource_reference_product_inventory": "Affiche le stock à partir du produit parent", + "resource_reference_product_price": "Affiche le prix à partir du produit parent", + "resource_reference_product_recommendations": "Affiche les recommandations en fonction du produit parent", + "resource_reference_product_review": "Affiche les avis à partir du produit parent", + "resource_reference_product_swatches": "Affiche les échantillons à partir du produit parent", + "resource_reference_product_title": "Affiche le titre à partir du produit parent", + "resource_reference_product_variant_picker": "Affiche les variantes à partir du produit parent", + "resource_reference_product_media": "Affiche les supports multimédias du produit parent", + "product_media": "Support multimédia du produit", + "section_link": "Lien vers la section" + }, + "html_defaults": { + "share_information_about_your": "

Partagez des informations sur votre marque. Décrivez un produit, partagez des annonces ou souhaitez la bienvenue à vos clients dans votre boutique.

" + }, + "text_defaults": { + "collapsible_row": "Rangée réductible", + "button_label": "Acheter maintenant", + "heading": "Titre", + "email_signup_button_label": "S’abonner", + "be_bold": "Osez.", + "accordion_heading": "Titre de l’accordéon", + "contact_form_button_label": "Soumettre", + "popup_link": "Lien ouvrant une pop-up", + "sign_up": "S’inscrire", + "welcome_to_our_store": "Bienvenue dans notre boutique", + "shop_our_latest_arrivals": "Achetez nos dernières arrivées !" + }, + "info": { + "carousel_layout_on_mobile": "Le carrousel est utilisé sur mobile", + "video_alt_text": "Décrivez la vidéo pour les utilisateurs de technologie d’assistance", + "video_autoplay": "Le son des vidéos sera désactivé par défaut", + "video_external": "Utilisez une URL YouTube ou Vimeo", + "link_info": "Facultatif : permet de cliquer sur l’icône", + "carousel_hover_behavior_not_supported": "Le survol du « carrousel » n’est pas pris en charge lorsque le type « Carrousel » est sélectionné au niveau de la section", + "checkout_buttons": "Accélère le processus de paiement pour les acheteurs et peut optimiser le taux de conversion. [En savoir plus](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Titre personnalisé", + "edit_presets_in_theme_settings": "Modifiez les réglages prédéfinis dans [paramètres du thème ](/editor?context=theme&category=typography)", + "enable_filtering_info": "Personnaliser les filtres avec l’[application Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "La mise en page de grille est utilisée pour les appareils mobiles", + "manage_countries_regions": "[Gérer les pays/régions](/admin/settings/markets)", + "manage_languages": "[Gérer les langues](/admin/settings/languages)", + "transparent_background": "Vérifiez chaque modèle utilisant un arrière-plan transparent pour s’assurer qu’il reste lisible", + "logo_font": "S’applique uniquement lorsqu’un logo n’est pas sélectionné", + "aspect_ratio_adjusted": "Ajusté dans certaines mises en page", + "auto_open_cart_drawer": "Lorsque cette option est activée, le panier coulissant s’ouvre automatiquement lorsqu’un produit est ajouté.", + "custom_liquid": "Ajoutez des extraits d’application ou d’autres éléments de code pour créer des personnalisations avancées.[En savoir plus](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Utilisée pour les filtres appliqués, les codes de réduction et les suggestions de recherche", + "applies_on_image_only": "S’applique uniquement aux images", + "hover_effects": "S’applique à des cartes de produits et de collections" + }, + "categories": { + "basic": "Basic", + "collection": "Collection", + "collection_list": "Liste des collections", + "footer": "Pied de page", + "forms": "Formulaires", + "header": "En-tête", + "layout": "Mise en page", + "links": "Liens", + "product": "Produit", + "product_list": "Collection en vedette", + "banners": "Bannières", + "collections": "Collections", + "custom": "Personnalisées", + "decorative": "Décoratives", + "products": "Produits", + "other_sections": "Autre", + "storytelling": "Narration" + } +} diff --git a/locales/hr.json b/locales/hr.json new file mode 100644 index 000000000..fc19dd32f --- /dev/null +++ b/locales/hr.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Učitaj videozapis: {{ description }}", + "sold_out": "Rasprodano", + "email_signup": { + "label": "Adresa e-pošte", + "placeholder": "Adresa e-pošte", + "success": "Hvala što ste se pretplatili!" + }, + "filter": "Filtriraj", + "payment_methods": "Načini plaćanja", + "contact_form": { + "name": "Ime", + "email": "Adresa e-pošte", + "phone": "Telefon", + "comment": "Komentar", + "post_success": "Hvala vam na javljanju. Odgovorit ćemo vam u najkraćem mogućem roku.", + "error_heading": "Prilagodite sljedeće:" + } + }, + "accessibility": { + "play_model": "Reproduciraj 3D model", + "play_video": "Reproduciraj videozapis", + "unit_price": "Jedinična cijena", + "country_results_count": "Broj rezultata: {{ count }}", + "slideshow_pause": "Pauziraj prezentaciju", + "slideshow_play": "Reproduciraj prezentaciju", + "remove_item": "Ukloni {{ title}}", + "skip_to_text": "Preskoči na sadržaj", + "skip_to_product_info": "Preskoči do informacija o proizvodu", + "skip_to_results_list": "Preskoči na popis rezultata", + "new_window": "Otvara se u novom prozoru.", + "slideshow_next": "Sljedeći slajd", + "slideshow_previous": "Prethodni slajd", + "close_dialog": "Zatvori dijaloški okvir", + "reset_search": "Ponovno postavi pretragu", + "search_results_count": "Broj rezultata pretraživanja pronađenih za „{{ query }}”: {{ count }}", + "search_results_no_results": "Nema rezultata za „{{ query }}”", + "filters": "Filtri", + "filter_count": { + "one": "Primijenjen je {{ count }} filtar", + "other": "Primijenjen je sljedeći broj filtara: {{ count }}", + "few": "Primijenjen je sljedeći broj filtara: {{ count }}" + }, + "account": "Otvori izbornik računa", + "cart": "Košarica", + "cart_count": "Ukupan broj stavki u košarici", + "menu": "Izbornik", + "country_region": "Država/regija", + "slide_status": "Slajd {{ index }} od {{ length }}", + "scroll_to": "Idi na {{ title }}", + "loading_product_recommendations": "Učitavanje preporuka proizvoda", + "discount": "Primijeni kod za popust", + "discount_applied": "Primijenjeni kod za popust: {{ code }}", + "open_cart_drawer": "Otvori košaricu", + "inventory_status": "Status zaliha", + "pause_video": "Pauziraj videozapis", + "localization_region_and_language": "Otvori izbornik regije i jezika", + "open_search_modal": "Otvori pretraživanje", + "find_country": "Pronađi državu", + "decrease_quantity": "Smanji količinu", + "increase_quantity": "Povećaj količinu", + "quantity": "Količina", + "rating": "Ocjena ovog proizvoda je {{ rating }} od 5", + "nested_product": "{{ product_title }} za {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Dodaj u košaricu", + "clear_all": "Očisti sve", + "remove": "Ukloni", + "view_in_your_space": "Pogledajte u svojem prostoru", + "show_filters": "Filtriraj", + "clear": "Očisti", + "continue_shopping": "Nastavi s kupovinom", + "log_in_html": "Imate li račun? Prijavite se za brži završetak kupovine.", + "see_items": { + "one": "Pogledaj sljedeći broj artikala: {{ count }}", + "other": "Pogledaj sljedeći broj artikala: {{ count }}", + "few": "Pogledaj sljedeći broj artikala: {{ count }}" + }, + "view_all": "Prikaži sve", + "add": "Dodaj", + "choose": "Odaberi", + "added": "Dodano", + "show_less": "Prikaži manje", + "show_more": "Prikaži više", + "close": "Zatvori", + "more": "Više", + "zoom": "Uvećaj", + "close_dialog": "Zatvori dijaloški okvir", + "reset": "Resetiraj", + "back": "Natrag", + "log_in": "Prijava", + "log_out": "Odjava", + "remove_discount": "Ukloni popust {{ code }}", + "enter_using_password": "Uđite pomoću lozinke", + "submit": "Pošalji", + "enter_password": "Unesite lozinku", + "view_store_information": "Prikaži informacije o trgovini", + "apply": "Primijeni", + "sign_in_options": "Druge mogućnosti prijave", + "sign_up": "Registrirajte se", + "open_image_in_full_screen": "Otvori sliku preko cijelog zaslona", + "sort": "Razvrstaj", + "show_all_options": "Prikaži sve opcije" + }, + "content": { + "reviews": "recenzije", + "no_results_found": "Nema pronađenih rezultata", + "language": "Jezik", + "localization_region_and_language": "Regija i jezik", + "cart_total": "Ukupni iznos košarice", + "your_cart_is_empty": "Vaša je košarica prazna", + "product_image": "Slika proizvoda", + "product_information": "Informacije o proizvodu", + "quantity": "Količina", + "product_total": "Proizvod ukupno", + "cart_estimated_total": "Procijenjen ukupni iznos", + "seller_note": "Posebne upute", + "cart_subtotal": "Podzbroj", + "discounts": "Popusti", + "discount": "Popust", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Carina i porezi su uključeni. Popusti i poštarina obračunavaju se prilikom plaćanja.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Carina i porezi su uključeni. Popusti i poštarina obračunavaju se prilikom plaćanja.", + "taxes_included_shipping_at_checkout_with_policy_html": "Porezi su uključeni. Popusti i poštarina obračunavaju se prilikom plaćanja.", + "taxes_included_shipping_at_checkout_without_policy": "Porezi su uključeni. Popusti i poštarina obračunavaju se prilikom plaćanja.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Carina je uključena. Porezi, popusti i poštarina obračunavaju se prilikom plaćanja.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Carina je uključena. Porezi, popusti i poštarina obračunavaju se prilikom plaćanja.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Porezi, popusti i poštarina obračunavaju se prilikom plaćanja.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Porezi, popusti i poštarina obračunavaju se prilikom plaćanja.", + "price": "Cijena", + "price_regular": "Redovna cijena", + "price_compare_at": "Usporedba cijena", + "price_sale": "Prodajna cijena", + "checkout": "Plaćanje", + "cart_title": "Košarica", + "duties_and_taxes_included": "Carina i porezi su uključeni.", + "duties_included": "Carina je uključena.", + "shipping_policy_html": "Poštarina se obračunava prilikom plaćanja.", + "taxes_included": "Porezi su uključeni.", + "product_badge_sold_out": "Rasprodano", + "product_badge_sale": "Sniženje", + "search_input_label": "Traži", + "search_input_placeholder": "Pretraživanje", + "search_results": "Rezultati pretraživanja", + "search_results_label": "Rezultati pretraživanja", + "search_results_no_results": "Nema rezultata za „{{ terms }}”. Pokušajte izvršiti drugo pretraživanje.", + "search_results_resource_articles": "Objava na blogu", + "search_results_resource_collections": "Kolekcije", + "search_results_resource_pages": "Stranice", + "search_results_resource_products": "Proizvodi", + "search_results_resource_queries": "Prijedlozi pretraživanja", + "search_results_view_all": "Prikaži sve", + "search_results_view_all_button": "Prikaži sve", + "search_results_resource_products_count": { + "one": "{{ count }} proizvod", + "other": "Broj proizvoda: {{ count }}", + "few": "Broj proizvoda: {{ count }}" + }, + "grid_view": { + "default_view": "Zadano", + "grid_fieldset": "Grid sa stupcima", + "single_item": "Jedan", + "zoom_out": "Smanji" + }, + "recently_viewed_products": "Nedavno pregledano", + "unavailable": "Nedostupno", + "collection_placeholder": "Naziv kolekcije", + "product_card_placeholder": "Naziv proizvoda", + "product_count": "Broj proizvoda", + "item_count": { + "one": "{{ count }} artikl", + "other": "Broj artikala: {{ count }}", + "few": "Broj artikala: {{ count }}" + }, + "errors": "Pogreške", + "search": "Pretraživanje", + "search_results_no_results_check_spelling": "Nema rezultata za „{{ terms }}”. Provjerite pravopis ili upotrijebite drugu riječ ili izraz.", + "featured_products": "Istaknuti proizvodi", + "no_products_found": "Nije pronađen nijedan proizvod.", + "price_from": "Od {{ price }}", + "use_fewer_filters_html": "Pokušaje upotrijebiti manje filtara ili očistite sve filtere.", + "filters": "Filtri", + "price_filter_html": "Najveća cijena iznosi {{ price }}", + "blog_details_separator": "|", + "read_more": "Pročitajte više...", + "account_title": "Račun", + "account_title_personalized": "Pozdrav, {{ first_name }}", + "account_orders": "Narudžbe", + "account_profile": "Profil", + "discount_code": "Kod za popust", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Carina i porezi su uključeni. Poštarina se obračunava prilikom plaćanja.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Carina i porezi su uključeni. Poštarina se obračunava prilikom plaćanja.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Carina je uključena. Poštarina se obračunava prilikom plaćanja.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Carina je uključena. Poštarina se obračunava prilikom plaćanja.", + "pickup_available_at_html": "Preuzimanje je dostupno na lokaciji {{ location }}", + "pickup_available_in": "Preuzimanje je dostupno, {{ pickup_time }}", + "pickup_not_available": "Preuzimanje trenutačno nije dostupno", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Porezi i troškovi dostave obračunavaju se prilikom završetka kupovine.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Porezi i poštarina obračunavaju se prilikom plaćanja.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Porezi su uključeni. Poštarina se obračunava prilikom plaćanja.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Porezi su uključeni. Poštarina se obračunava prilikom plaćanja.", + "wrong_password": "Pogrešna lozinka", + "view_more_details": "Prikaži više pojedinosti", + "page_placeholder_title": "Naslov stranice", + "page_placeholder_content": "Odaberite stranicu za prikaz sadržaja.", + "placeholder_image": "Slika kao rezervirano mjesto", + "inventory_low_stock": "Preostalo malo komada", + "inventory_in_stock": "Na zalihama", + "inventory_out_of_stock": "Nema na zalihama", + "shipping_policy": "Poštarina se obračunava prilikom plaćanja.", + "inventory_low_stock_show_count": { + "one": "preostalo: {{ count }}", + "other": "preostalo: {{ count }}", + "few": "preostalo: {{ count }}" + }, + "discount_code_error": "Kod za popust se ne može primijeniti na Vašu košaricu", + "shipping_discount_error": "Popusti na dostavu prikazuju se na blagajni nakon dodavanja adrese", + "powered_by": "Ova trgovina koristi sustav", + "store_owner_link_html": "Jeste li vlasnik/vlasnica trgovine? Prijavite se ovdje" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Upotrijebite kod poklon-kartice na internetu ili QR kod u trgovini", + "title": "Poklanjamo vam darovnu karticu u vrijednosti od {{ value }} za trgovinu {{ shop }}!", + "subtext": "Vaša poklon-kartica", + "shop_link": "Posjeti internetsku trgovinu", + "add_to_apple_wallet": "Dodaj u Apple Wallet", + "qr_image_alt": "QR kod – skenirajte ga kako biste iskoristili poklon-karticu", + "copy_code": "Kopiraj kod poklon-kartice", + "expiration_date": "Istječe {{ expires_on }}", + "copy_code_success": "Kod je uspješno kopiran", + "expired": "Isteklo" + } + }, + "placeholders": { + "password": "Lozinka", + "search": "Pretraživanje", + "product_title": "Naziv proizvoda", + "collection_title": "Naziv kolekcije" + }, + "products": { + "product": { + "add_to_cart": "Dodaj u košaricu", + "added_to_cart": "Dodano u košaricu", + "adding_to_cart": "Dodavanje...", + "add_to_cart_error": "Pogreška prilikom dodavanja u košaricu", + "sold_out": "Rasprodano", + "unavailable": "Nedostupno" + } + }, + "fields": { + "separator": "do" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentar", + "other": "{{ count }} komentara", + "few": "{{ count }} komentara" + } + }, + "comment_form": { + "email": "Adresa e-pošte", + "error": "Objava komentara nije uspjela, obratite se na sljedeće:", + "heading": "Ostavite komentar", + "message": "Poruka", + "moderated": "Napominjemo da komentari moraju biti odobreni prije objave.", + "name": "Ime", + "post": "Objavi komentar", + "success_moderated": "Komentar je objavljen, čeka moderiranje", + "success": "Komentar objavljen" + } + } +} diff --git a/locales/hu.json b/locales/hu.json new file mode 100644 index 000000000..25bca4765 --- /dev/null +++ b/locales/hu.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Videó betöltése: {{ description }}", + "sold_out": "Elfogyott", + "email_signup": { + "label": "E-mail-cím", + "placeholder": "E-mail-cím", + "success": "Köszönjük feliratkozást!" + }, + "filter": "Szűrés", + "payment_methods": "Fizetési módok", + "contact_form": { + "name": "Név", + "email": "E-mail-cím", + "phone": "Telefonszám", + "comment": "Hozzászólás", + "post_success": "Köszönjük, hogy írtál nekünk. A lehető legrövidebb időn belül válaszolni fogunk.", + "error_heading": "Kérjük, helyesbítsd a következőket:" + } + }, + "accessibility": { + "play_model": "3D-modell lejátszása", + "play_video": "Videó lejátszása", + "unit_price": "Egységár", + "country_results_count": "{{ count }} találat", + "slideshow_pause": "Diavetítés megállítása", + "slideshow_play": "Diavetítés indítása", + "remove_item": "{{ title}} eltávolítása", + "skip_to_text": "Ugrás a tartalomhoz", + "skip_to_product_info": "Kihagyás, és ugrás a termékadatokra", + "skip_to_results_list": "Ugrás a találati listára", + "new_window": "Új ablakban nyílik meg.", + "slideshow_next": "Következő dia", + "slideshow_previous": "Előző dia", + "close_dialog": "Párbeszédablak bezárása", + "reset_search": "Keresés alaphelyzetbe állítása", + "search_results_count": "{{ count }} találat a(z) „{{ query }}” kifejezésre", + "search_results_no_results": "Nincs találat a(z) „{{ query }}” kifejezésre", + "filters": "Szűrők", + "filter_count": { + "one": "{{ count }} szűrő alkalmazva", + "other": "{{ count }} szűrő alkalmazva" + }, + "account": "Fiókmenü megnyitása", + "cart": "Kosár", + "cart_count": "Összes termék a kosárban", + "menu": "Menü", + "country_region": "Ország/régió", + "slide_status": "{{ index }}./{{ length }} dia", + "scroll_to": "Görgess ide: {{ title }}", + "loading_product_recommendations": "Termékajánlások betöltése", + "discount": "Kedvezménykód beváltása", + "discount_applied": "Beváltott kedvezménykód: {{ code }}", + "open_cart_drawer": "Kosár megnyitása", + "inventory_status": "Készlet állapota", + "pause_video": "Videó szüneteltetése", + "find_country": "Ország keresése", + "localization_region_and_language": "Régió- és nyelvválasztó megnyitása", + "open_search_modal": "Keresés megnyitása", + "decrease_quantity": "Mennyiség csökkentése", + "increase_quantity": "Mennyiség növelése", + "quantity": "Mennyiség", + "rating": "A termék értékelése: {{ rating }} / 5", + "nested_product": "{{ product_title }} – {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Hozzáadás a kosárhoz", + "clear_all": "Az összes törléses", + "remove": "Eltávolítás", + "view_in_your_space": "Megtekintés a saját környezetben", + "show_filters": "Szűrés", + "clear": "Törlés", + "continue_shopping": "Vásárlás folytatása", + "log_in_html": "Már van fiókod? Jelentkezz be a gyorsabb fizetéshez.", + "see_items": { + "one": "{{ count }} termék megtekintése", + "other": "{{ count }} termék megtekintése" + }, + "view_all": "Az összes megtekintése", + "add": "Hozzáadás", + "choose": "Kiválasztás", + "added": "Hozzáadva", + "show_less": "Kevesebb megjelenítése", + "show_more": "Több megjelenítése", + "close": "Bezárás", + "more": "Egyebek", + "zoom": "Nagyítás", + "close_dialog": "Párbeszédablak bezárása", + "reset": "Alaphelyzetbe állítás", + "enter_using_password": "Belépés jelszóval", + "submit": "Beküldés", + "enter_password": "Jelszó megadása", + "back": "Vissza", + "log_in": "Bejelentkezés", + "log_out": "Kijelentkezés", + "remove_discount": "Kedvezménykód ({{ code }}) eltávolítása", + "view_store_information": "Webáruház adatai", + "apply": "Beváltás", + "sign_in_options": "További bejelentkezési lehetőségek", + "sign_up": "Regisztráció", + "open_image_in_full_screen": "Kép megnyitása teljes képernyőn", + "sort": "Rendezés", + "show_all_options": "Összes lehetőség megjelenítése" + }, + "content": { + "reviews": "összegzés", + "no_results_found": "Nincs találat", + "language": "Nyelv", + "localization_region_and_language": "Régió és nyelv", + "cart_total": "Kosár végösszege", + "your_cart_is_empty": "A kosarad üres", + "product_image": "Termékkép", + "product_information": "Termékadatok", + "quantity": "Mennyiség", + "product_total": "Termék végösszege", + "cart_estimated_total": "Becsült végösszeg", + "seller_note": "Különleges utasítások", + "cart_subtotal": "Részösszeg", + "discounts": "Kedvezmények", + "discount": "Kedvezmény", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Tartalmazza a vámokat és az adókat. A kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Tartalmazza a vámokat és az adókat. A kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "taxes_included_shipping_at_checkout_with_policy_html": "Tartalmazza az adókat. A kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "taxes_included_shipping_at_checkout_without_policy": "Tartalmazza az adókat. A kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Tartalmazza a vámokat. Az adók, a kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Tartalmazza a vámokat. Az adók, a kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Az adók, a kedvezmények és a szállítási költség kiszámítása a pénztárban történik..", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Az adók, a kedvezmények és a szállítási költség kiszámítása a pénztárban történik.", + "cart_title": "Kosár", + "price": "Ár", + "price_regular": "Normál ár", + "price_compare_at": "Összehasonlítás ár alapján", + "price_sale": "Akciós ár", + "checkout": "Fizetés", + "duties_and_taxes_included": "Tartalmazza a vámokat és az adókat.", + "duties_included": "Tartalmazza a vámokat.", + "shipping_policy_html": "A fizetéskor kiszámított szállítási költség.", + "taxes_included": "Tartalmazza az adókat.", + "product_badge_sold_out": "Elfogyott", + "product_badge_sale": "Akciós", + "grid_view": { + "default_view": "Alapértelmezett", + "grid_fieldset": "Oszloprács", + "single_item": "Önálló", + "zoom_out": "Felnagyítás" + }, + "search_input_label": "Keresés", + "search_input_placeholder": "Keresés", + "search_results": "Találatok", + "search_results_label": "Találatok", + "search_results_no_results": "Nincs találat erre: „{{ terms }}”. Próbálj meg másra rákeresni.", + "search_results_resource_articles": "Blogbejegyzések", + "search_results_resource_collections": "Kollekciók", + "search_results_resource_pages": "Oldal", + "search_results_resource_products": "Termékek", + "search_results_resource_queries": "Javaslatok keresése", + "search_results_view_all": "Összes megtekintése", + "search_results_view_all_button": "Összes megtekintése", + "search_results_resource_products_count": { + "one": "{{ count }} termék", + "other": "{{ count }} termék" + }, + "recently_viewed_products": "Nemrégiben megtekintett", + "unavailable": "Nem áll rendelkezésre", + "collection_placeholder": "Kollekció címe", + "product_card_placeholder": "Termék címe", + "product_count": "Termékek száma", + "item_count": { + "one": "{{ count }} termék", + "other": "{{ count }} termék" + }, + "errors": "Hibák", + "price_from": "Indulóár: {{ price }}", + "featured_products": "Kiemelt termékek", + "no_products_found": "Nincs találat.", + "use_fewer_filters_html": "Próbálj meg kevesebb szűrőt használni, vagy töröld az összes szűrőt.", + "search": "Keresés", + "search_results_no_results_check_spelling": "Nincs találat erre: „{{ terms }}”. Ellenőrizd a helyesírást, vagy írj be egy másik szót vagy kifejezést.", + "filters": "Szűrők", + "price_filter_html": "A legmagasabb ár {{ price }}", + "blog_details_separator": "|", + "read_more": "Bővebben…", + "wrong_password": "Hibás jelszó", + "account_title": "Fiók", + "account_title_personalized": "Kedves {{ first_name }}!", + "account_orders": "Rendelések", + "account_profile": "Profil", + "discount_code": "Kedvezménykód", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Tartalmazza a vámokat és az adókat. A szállítási díjat a pénztárnál számítjuk ki.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Tartalmazza a vámokat és az adókat. A szállítási díjat a pénztárnál számítjuk ki.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Tartalmazza a vámokat. A szállítási díjat a pénztárnál számítjuk ki.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Tartalmazza a vámokat. A szállítási díjat a pénztárnál számítjuk ki.", + "pickup_available_at_html": "Személyesen átvehető itt: {{ location }}", + "pickup_available_in": "Személyesen átvehető ekkor: {{ pickup_time }}", + "pickup_not_available": "Személyes átvétel jelenleg nem érhető el", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Az adókat és a szállítási díjat a pénztárnál számítjuk ki.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Az adókat és a szállítási díjat a pénztárnál számítjuk ki.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Tartalmazza az adókat. A szállítási díjat a pénztárnál számítjuk ki.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Tartalmazza az adókat. A szállítási díjat a pénztárnál számítjuk ki.", + "view_more_details": "További részletek megtekintése", + "inventory_low_stock": "Alacsony készlet", + "inventory_in_stock": "Készleten", + "inventory_out_of_stock": "Nincs készleten", + "page_placeholder_title": "Oldal címe", + "page_placeholder_content": "Jelölj ki egy oldalt a tartalma megjelenítéséhez.", + "placeholder_image": "Helyőrző kép", + "inventory_low_stock_show_count": { + "one": "Elérhető összeg: {{ count }}", + "other": "Elérhető összeg: {{ count }}" + }, + "shipping_policy": "A fizetéskor kiszámított szállítási költség.", + "discount_code_error": "A kedvezménykód nem érvényesíthető a kosaradon", + "shipping_discount_error": "A szállítási kedvezmények a fizetéskor jelennek meg a cím megadását követően", + "powered_by": "A bolt szolgáltatója:", + "store_owner_link_html": "Te vagy az áruház tulajdonosa? Jelentkezz be itt" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Az ajándékkártya kódja online, a QR-kód pedig az üzletben használható fel", + "title": "Íme a(z) {{ shop }} üzletben levásárolható, {{ value }} értékű ajándékkártyád!", + "subtext": "Ajándékkártya", + "shop_link": "Webáruház megnyitása", + "add_to_apple_wallet": "Hozzáadás az Apple Wallethoz", + "qr_image_alt": "Ezt a QR-kódot beszkennelve beválthatod az ajándékkártyát.", + "copy_code": "Ajándékkártya kódjának másolása", + "expiration_date": "Lejárat dátuma: {{ expires_on }}", + "copy_code_success": "Sikeres volt a kód másolása", + "expired": "Lejárt" + } + }, + "placeholders": { + "password": "Jelszó", + "search": "Keresés", + "product_title": "Termék megnevezése", + "collection_title": "Kollekció megnevezése" + }, + "products": { + "product": { + "add_to_cart": "Hozzáadás a kosárhoz", + "added_to_cart": "Hozzáadva a kosárhoz", + "adding_to_cart": "Hozzáadás…", + "add_to_cart_error": "Nem tudtuk hozzáadni a terméket a kosárhoz", + "sold_out": "Elfogyott", + "unavailable": "Nincs készleten" + } + }, + "fields": { + "separator": "–" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} hozzászólás", + "other": "{{ count }} hozzászólás" + } + }, + "comment_form": { + "email": "E‑mail-cím", + "error": "A hozzászólás közzététele nem sikerült, kérjük, ügyelj a következőkre:", + "heading": "Hozzászólás írása", + "message": "Üzenet", + "moderated": "Felhívjuk a figyelmedet, hogy közzététel előtt a hozzászólásokat jóvá kell hagyni.", + "name": "Név", + "post": "Hozzászólás elküldése", + "success_moderated": "Hozzászólás közzétéve, moderálásra vár", + "success": "Hozzászólás közzétéve" + } + } +} diff --git a/locales/id.json b/locales/id.json new file mode 100644 index 000000000..072d49ea4 --- /dev/null +++ b/locales/id.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Muat video: {{ description }}", + "sold_out": "Habis", + "email_signup": { + "label": "Email", + "placeholder": "Alamat email", + "success": "Terima kasih sudah berlangganan!" + }, + "filter": "Filter", + "payment_methods": "Metode pembayaran", + "contact_form": { + "name": "Nama", + "email": "Email", + "phone": "Telepon", + "comment": "Komentar", + "post_success": "Terima kasih sudah menghubungi kami. Kami akan segera menghubungi Anda.", + "error_heading": "Mohon sesuaikan:" + } + }, + "accessibility": { + "play_model": "Putar model 3D", + "play_video": "Putar video", + "unit_price": "Harga satuan", + "country_results_count": "{{ count }} hasil", + "slideshow_pause": "Jeda slideshow", + "slideshow_play": "Putar slideshow", + "remove_item": "Hapus {{ title}}", + "skip_to_text": "Langsung ke konten", + "skip_to_product_info": "Langsung ke informasi produk", + "skip_to_results_list": "Langsung ke daftar hasil", + "new_window": "Membuka di jendela baru.", + "close_dialog": "Tutup dialog", + "reset_search": "Reset pencarian", + "search_results_count": "{{ count }} hasil pencarian ditemukan untuk \"{{ query }}\"", + "search_results_no_results": "Tidak ditemukan hasil untuk \"{{ query }}\"", + "slideshow_next": "Slide berikutnya", + "slideshow_previous": "Slide sebelumnya", + "filters": "Filter", + "account": "Buka menu akun", + "cart": "Keranjang", + "cart_count": "Total item di keranjang", + "filter_count": { + "one": "{{ count }} filter diterapkan", + "other": "{{ count }} filter diterapkan" + }, + "menu": "Menu", + "country_region": "Negara/Wilayah", + "slide_status": "Slide {{ index }} dari {{ length }}", + "scroll_to": "Gulir ke {{ title }}", + "loading_product_recommendations": "Memuat rekomendasi produk", + "discount": "Pakai kode diskon", + "discount_applied": "Kode diskon yang dipakai: {{ code }}", + "open_cart_drawer": "Buka troli", + "inventory_status": "Status Inventaris", + "pause_video": "Jeda video", + "find_country": "Temukan negara", + "localization_region_and_language": "Buka selektor wilayah dan bahasa", + "open_search_modal": "Buka pencarian", + "decrease_quantity": "Kurangi jumlah", + "increase_quantity": "Tambah jumlah", + "quantity": "Jumlah", + "rating": "Peringkat produk ini adalah {{ rating }} dari 5", + "nested_product": "{{ product_title }} untuk {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Tambahkan ke keranjang", + "clear_all": "Hapus semua", + "remove": "Hapus", + "view_in_your_space": "Lihat di lokasi Anda", + "show_filters": "Filter", + "clear": "Kosongkan", + "continue_shopping": "Lanjutkan belanja", + "log_in_html": "Sudah punya akun? Login untuk checkout lebih cepat.", + "see_items": { + "one": "Lihat {{ count }} item", + "other": "Lihat {{ count }} item" + }, + "view_all": "Lihat semua", + "add": "Tambah", + "choose": "Pilih", + "added": "Ditambahkan", + "show_less": "Sembunyikan lainnya", + "show_more": "Selengkapnya", + "close": "Tutup", + "more": "Selengkapnya", + "zoom": "Perbesar", + "close_dialog": "Tutup dialog", + "reset": "Reset", + "remove_discount": "Hapus diskon {{ code }}", + "enter_using_password": "Masuk dengan sandi", + "submit": "Kirim", + "enter_password": "Masukkan sandi", + "view_store_information": "Lihat informasi toko", + "back": "Kembali", + "log_in": "Masuk", + "log_out": "Logout", + "apply": "Pakai", + "sign_in_options": "Opsi masuk lainnya", + "open_image_in_full_screen": "Buka gambar dalam layar penuh", + "sign_up": "Daftar", + "sort": "Urutkan", + "show_all_options": "Tampilkan semua opsi" + }, + "content": { + "reviews": "ulasan", + "language": "Bahasa", + "localization_region_and_language": "Wilayah dan bahasa", + "no_results_found": "Hasil tidak ditemukan", + "cart_total": "Total keranjang", + "your_cart_is_empty": "Keranjang Anda kosong", + "product_image": "Gambar produk", + "product_information": "Informasi produk", + "quantity": "Jumlah", + "product_total": "Total produk", + "cart_estimated_total": "Estimasi total", + "seller_note": "Instruksi khusus", + "cart_subtotal": "Subtotal", + "discounts": "Diskon", + "discount": "Diskon", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Termasuk bea cukai dan pajak. Diskon dan biaya pengiriman dihitung saat checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Termasuk bea cukai dan pajak. Diskon dan biaya pengiriman dihitung saat checkout.", + "taxes_included_shipping_at_checkout_with_policy_html": "Termasuk pajak. Diskon dan biaya pengiriman dihitung saat checkout.", + "taxes_included_shipping_at_checkout_without_policy": "Termasuk pajak. Diskon dan biaya pengiriman dihitung saat checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Termasuk bea cukai. Pajak, diskon, dan biaya pengiriman dihitung saat checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Termasuk bea cukai. Pajak, diskon, dan biaya pengiriman dihitung saat checkout.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Pajak, diskon, dan biaya pengiriman dihitung saat checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Pajak, diskon, dan biaya pengiriman dihitung saat checkout.", + "checkout": "Check out", + "cart_title": "Keranjang", + "price": "Harga", + "price_regular": "Harga reguler", + "price_compare_at": "Bandingkan dengan harga", + "price_sale": "Harga obral", + "duties_and_taxes_included": "Termasuk bea cukai dan pajak.", + "duties_included": "Termasuk bea cukai.", + "shipping_policy_html": "Biaya pengiriman dihitung saat checkout.", + "taxes_included": "Termasuk pajak.", + "product_badge_sold_out": "Habis", + "product_badge_sale": "Promo", + "search_input_label": "Cari", + "search_input_placeholder": "Cari", + "search_results": "Hasil pencarian", + "search_results_label": "Hasil pencarian", + "search_results_no_results": "Tidak ada hasil yang ditemukan untuk \"{{ terms }}\". Coba pencarian lain.", + "search_results_resource_articles": "Postingan blog", + "search_results_resource_collections": "Koleksi", + "search_results_resource_pages": "Halaman", + "search_results_resource_products": "Produk", + "search_results_resource_queries": "Saran pencarian", + "search_results_view_all": "Lihat semua", + "search_results_view_all_button": "Lihat semua", + "search_results_resource_products_count": { + "one": "{{ count }} produk", + "other": "{{ count }} produk" + }, + "grid_view": { + "default_view": "Default", + "grid_fieldset": "Grid kolom", + "single_item": "Tunggal", + "zoom_out": "Perkecil" + }, + "recently_viewed_products": "Baru saja dilihat", + "collection_placeholder": "Judul koleksi", + "product_card_placeholder": "Judul produk", + "unavailable": "Tidak tersedia", + "product_count": "Jumlah produk", + "item_count": { + "one": "{{ count }} item", + "other": "{{ count }} item" + }, + "errors": "Kesalahan", + "price_from": "Mulai {{ price }}", + "search": "Cari", + "search_results_no_results_check_spelling": "Tidak ada hasil yang ditemukan untuk \"{{ terms }}\". Periksa ejaan atau gunakan kata atau frasa yang berbeda.", + "featured_products": "Produk unggulan", + "no_products_found": "Tidak ada produk yang ditemukan.", + "use_fewer_filters_html": "Coba kurangi filter, atau hapus semua filter.", + "filters": "Filter", + "price_filter_html": "Harga tertingginya adalah {{ price }}", + "blog_details_separator": "|", + "read_more": "Baca selengkapnya...", + "discount_code": "Kode diskon", + "pickup_available_at_html": "Pengambilan dapat dilakukan di {{ location }}", + "pickup_available_in": "Pengambilan dapat dilakukan pada {{ pickup_time }}", + "pickup_not_available": "Pengambilan saat ini tidak tersedia", + "pickup_ready_in": "{{ pickup_time }}", + "wrong_password": "Sandi salah", + "account_title": "Akun", + "account_title_personalized": "Hai {{ first_name }}", + "account_orders": "Pesanan", + "account_profile": "Profil", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Termasuk bea cukai dan pajak. Biaya pengiriman dihitung saat checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Termasuk bea cukai dan pajak. Biaya pengiriman dihitung saat checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Termasuk bea cukai. Biaya pengiriman dihitung saat checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Termasuk bea cukai. Biaya pengiriman dihitung saat checkout.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Pajak dan biaya pengiriman dihitung saat checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Pajak dan biaya pengiriman dihitung saat checkout.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Termasuk pajak. Biaya pengiriman dihitung saat checkout.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Termasuk pajak. Biaya pengiriman dihitung saat checkout.", + "view_more_details": "Lihat detail lebih lanjut", + "inventory_low_stock": "Stok sedikit", + "inventory_in_stock": "Tersedia", + "inventory_out_of_stock": "Stok habis", + "page_placeholder_title": "Judul halaman", + "page_placeholder_content": "Pilih halaman untuk menampilkan kontennya.", + "placeholder_image": "Gambar placeholder", + "inventory_low_stock_show_count": { + "one": "Tersisa {{ count }}", + "other": "Tersisa {{ count }}" + }, + "discount_code_error": "Kode diskon tidak dapat diterapkan ke keranjang Anda", + "shipping_policy": "Biaya pengiriman dihitung saat checkout.", + "shipping_discount_error": "Diskon biaya pengiriman akan ditampilkan saat checkout setelah menambahkan alamat", + "powered_by": "Toko ini didukung oleh", + "store_owner_link_html": "Anda pemilik toko? Login di sini" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Gunakan kode voucher secara online atau kode QR di toko", + "title": "Ini dia voucher senilai {{ value }} Anda untuk {{ shop }}!", + "subtext": "Voucher Anda", + "shop_link": "Kunjungi toko online", + "add_to_apple_wallet": "Tambahkan ke Apple Wallet", + "qr_image_alt": "Kode QR — pindai untuk menukarkan voucher", + "copy_code": "Salin kode voucher", + "expiration_date": "Kedaluwarsa pada {{ expires_on }}", + "copy_code_success": "Kode berhasil disalin", + "expired": "Kedaluwarsa" + } + }, + "placeholders": { + "password": "Sandi", + "search": "Cari", + "product_title": "Judul produk", + "collection_title": "Judul koleksi" + }, + "products": { + "product": { + "add_to_cart": "Tambahkan ke keranjang", + "added_to_cart": "Ditambahkan ke keranjang", + "adding_to_cart": "Menambahkan...", + "add_to_cart_error": "Kesalahan saat menambahkan ke keranjang", + "sold_out": "Habis", + "unavailable": "Tidak Tersedia" + } + }, + "fields": { + "separator": "hingga" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentar", + "other": "{{ count }} komentar" + } + }, + "comment_form": { + "email": "Email", + "error": "Komentar gagal dikirim, perbaiki hal-hal berikut:", + "heading": "Tulis komentar", + "message": "Pesan", + "moderated": "Ingat, komentar perlu disetujui sebelum dipublikasikan.", + "name": "Nama", + "post": "Posting komentar", + "success_moderated": "Komentar diposting, menunggu moderasi", + "success": "Komentar diposting" + } + } +} diff --git a/locales/it.json b/locales/it.json new file mode 100644 index 000000000..3f7cad5b5 --- /dev/null +++ b/locales/it.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Carica il video: {{ description }}", + "sold_out": "Esaurito", + "email_signup": { + "label": "Email", + "placeholder": "Indirizzo email", + "success": "Grazie per l'iscrizione!" + }, + "filter": "Filtro", + "payment_methods": "Metodi di pagamento", + "contact_form": { + "name": "Nome", + "email": "Email", + "phone": "Telefono", + "comment": "Commento", + "post_success": "Grazie per averci contattato. Risponderemo il prima possibile.", + "error_heading": "Correggi gli errori seguenti:" + } + }, + "accessibility": { + "play_model": "Riproduci modello 3D", + "play_video": "Riproduci video", + "unit_price": "Prezzo unitario", + "country_results_count": "{{ count }} risultati", + "slideshow_pause": "Metti in pausa presentazione", + "slideshow_play": "Avvia presentazione", + "remove_item": "Rimuovi {{ title}}", + "skip_to_text": "Vai direttamente al contenuto", + "skip_to_product_info": "Passa alle informazioni sul prodotto", + "skip_to_results_list": "Passa all'elenco dei risultati", + "new_window": "Si apre in una nuova finestra.", + "slideshow_next": "Slide successiva", + "slideshow_previous": "Slide precedente", + "close_dialog": "Chiudi finestra di dialogo", + "reset_search": "Ripristina ricerca", + "search_results_count": "{{ count }} risultati della ricerca trovati per \"{{ query }}\"", + "search_results_no_results": "Nessun risultato trovato per \"{{ query }}\"", + "filters": "Filtri", + "filter_count": { + "one": "{{ count }} filtro applicato", + "other": "{{ count }} filtri applicati", + "many": "{{ count }} filtri applicati" + }, + "account": "Apri menu dell'account", + "cart": "Carrello", + "cart_count": "Totale articoli nel carrello", + "menu": "Menu", + "country_region": "Paese/Area geografica", + "slide_status": "Slide {{ index }} di {{ length }}", + "scroll_to": "Scorri fino a {{ title }}", + "loading_product_recommendations": "Caricamento delle raccomandazioni sui prodotti", + "discount": "Applica un codice sconto", + "discount_applied": "Codice sconto applicato: {{ code }}", + "open_cart_drawer": "Apri carrello", + "inventory_status": "Stato delle scorte", + "pause_video": "Metti video in pausa", + "find_country": "Trova paese", + "localization_region_and_language": "Apri selettore dell'area geografica e della lingua", + "open_search_modal": "Apri ricerca", + "decrease_quantity": "Diminuisci quantità", + "increase_quantity": "Aumenta quantità", + "quantity": "Quantità", + "rating": "Il voto per questo prodotto è {{ rating }} su 5", + "nested_product": "{{ product_title }} per {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Aggiungi al carrello", + "clear_all": "Cancella tutto", + "remove": "Rimuovi", + "view_in_your_space": "Visualizza nel tuo spazio", + "show_filters": "Filtro", + "clear": "Cancella", + "continue_shopping": "Continua lo shopping", + "log_in_html": "Hai un account? Accedi per un check-out più veloce.", + "see_items": { + "one": "Vedi {{ count }} articolo", + "other": "Vedi {{ count }} articoli", + "many": "Vedi {{ count }} articoli" + }, + "view_all": "Visualizza tutto", + "add": "Aggiungi", + "choose": "Scegli", + "added": "Aggiunto", + "show_less": "Mostra meno", + "show_more": "Mostra di più", + "close": "Chiudi", + "more": "Altro", + "reset": "Ripristina", + "zoom": "Zoom", + "close_dialog": "Chiudi finestra di dialogo", + "back": "Indietro", + "log_in": "Accedi", + "log_out": "Esci", + "remove_discount": "Rimuovi sconto {{ code }}", + "enter_using_password": "Accedi utilizzando la password", + "submit": "Invia", + "enter_password": "Inserisci password", + "view_store_information": "Visualizza i dettagli del negozio", + "apply": "Applica", + "sign_in_options": "Altre opzioni di accesso", + "sign_up": "Iscriviti", + "open_image_in_full_screen": "Apri immagine a schermo intero", + "sort": "Ordina", + "show_all_options": "Mostra tutte le opzioni" + }, + "content": { + "reviews": "recensioni", + "no_results_found": "Nessun risultato trovato", + "language": "Lingua", + "localization_region_and_language": "Area geografica e lingua", + "cart_total": "Totale carrello", + "your_cart_is_empty": "Il tuo carrello è vuoto", + "product_image": "Immagine del prodotto", + "product_information": "Informazioni sul prodotto", + "quantity": "Quantità", + "product_total": "Totale del prodotto", + "cart_estimated_total": "Totale stimato", + "seller_note": "Istruzioni speciali", + "cart_subtotal": "Subtotale", + "discounts": "Sconti", + "discount": "Sconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Dazi e imposte inclusi. Sconti e spedizione calcolati al check-out.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Dazi e imposte inclusi. Sconti e spedizione calcolati al check-out.", + "taxes_included_shipping_at_checkout_with_policy_html": "Imposte incluse. Sconti e spedizione calcolati al check-out.", + "taxes_included_shipping_at_checkout_without_policy": "Imposte incluse. Sconti e spedizione calcolati al check-out.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Dazi inclusi. Imposte, sconti e spedizione calcolati al check-out.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Dazi inclusi. Imposte, sconti e spedizione calcolati al check-out.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Imposte, sconti e spedizione calcolati al check-out.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Imposte, sconti e spedizione calcolati al check-out.", + "checkout": "Check-out", + "cart_title": "Carrello", + "price": "Prezzo", + "price_regular": "Prezzo di listino", + "price_compare_at": "Prezzo di confronto", + "price_sale": "Prezzo promozionale", + "duties_and_taxes_included": "Dazi e imposte inclusi.", + "duties_included": "Dazi inclusi.", + "shipping_policy_html": "Spese di spedizione calcolate al check-out.", + "taxes_included": "Imposte incluse.", + "product_badge_sold_out": "Esaurito", + "product_badge_sale": "In offerta", + "search_input_label": "Ricerca", + "search_input_placeholder": "Ricerca", + "search_results": "Risultati della ricerca", + "search_results_label": "Risultati della ricerca", + "search_results_no_results": "Nessun risultato trovato per “{{ terms }}”. Prova con un’altra ricerca.", + "search_results_resource_articles": "Articoli del blog", + "search_results_resource_collections": "Collezioni", + "search_results_resource_pages": "Pagine", + "search_results_resource_products": "Prodotti", + "search_results_resource_queries": "Suggerimenti di ricerca", + "search_results_view_all": "Visualizza tutto", + "search_results_view_all_button": "Visualizza tutto", + "search_results_resource_products_count": { + "one": "{{ count }} prodotto", + "other": "{{ count }} prodotti", + "many": "{{ count }} prodotti" + }, + "grid_view": { + "default_view": "Predefinito", + "grid_fieldset": "Griglia a colonne", + "single_item": "Singola", + "zoom_out": "Allontana" + }, + "unavailable": "Non disponibile", + "collection_placeholder": "Titolo della collezione", + "product_card_placeholder": "Titolo del prodotto", + "recently_viewed_products": "Visualizzati di recente", + "product_count": "Conteggio prodotti", + "item_count": { + "one": "{{ count }} articolo", + "other": "{{ count }} articoli", + "many": "{{ count }} articoli" + }, + "errors": "Errori", + "search": "Ricerca", + "search_results_no_results_check_spelling": "Nessun risultato trovato per \"{{ terms }}\". Controlla l'ortografia o usa un'altra parola o frase.", + "featured_products": "Prodotti in primo piano", + "no_products_found": "Nessun prodotto trovato.", + "price_from": "Da {{ price }}", + "use_fewer_filters_html": "Prova a usare meno filtri oppure cancella tutti i filtri.", + "filters": "Filtri", + "price_filter_html": "Il prezzo più alto è {{ price }}", + "blog_details_separator": "|", + "read_more": "Maggiori informazioni...", + "account_title": "Account", + "account_title_personalized": "Ciao {{ first_name }}", + "account_orders": "Ordini", + "account_profile": "Profilo", + "discount_code": "Codice sconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Imposte e dazi inclusi. Le spese di spedizione vengono calcolate al check-out.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Imposte e dazi inclusi. Le spese di spedizione vengono calcolate al check-out.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Dazi inclusi. Le spese di spedizione vengono calcolate al check-out.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Dazi inclusi. Le spese di spedizione vengono calcolate al check-out.", + "pickup_available_at_html": "Ritiro disponibile presso la sede {{ location }}", + "pickup_available_in": "Ritiro disponibile, {{ pickup_time }}", + "pickup_not_available": "Ritiro non disponibile al momento", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Imposte e spese di spedizione calcolate al check-out.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Imposte e spese di spedizione calcolate al check-out.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Imposte incluse. Le spese di spedizione vengono calcolate al check-out.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Imposte incluse. Le spese di spedizione vengono calcolate al check-out.", + "wrong_password": "Password errata", + "view_more_details": "Visualizza più dettagli", + "inventory_low_stock": "Scorte ridotte", + "inventory_in_stock": "Disponibile", + "inventory_out_of_stock": "Esaurito", + "page_placeholder_title": "Titolo della pagina", + "page_placeholder_content": "Seleziona una pagina per visualizzarne il contenuto.", + "placeholder_image": "Immagine segnaposto", + "inventory_low_stock_show_count": { + "one": "{{ count }} rimasto", + "other": "{{ count }} rimasto", + "many": "{{ count }} rimasto" + }, + "discount_code_error": "Il codice sconto non può essere applicato al tuo carrello", + "shipping_policy": "Spese di spedizione calcolate al check-out.", + "powered_by": "Questo negozio sarà ospitato su", + "store_owner_link_html": "Il negozio è di tua proprietà? Accedi qui", + "shipping_discount_error": "Gli sconti sulla spedizione vengono mostrati al momento del check-out dopo l'aggiunta di un indirizzo" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Utilizza il codice del buono regalo online o il codice QR in negozio", + "title": "Ecco il saldo del tuo buono regalo dal valore di {{ value }} per {{ shop }}!", + "subtext": "Il tuo buono regalo", + "shop_link": "Visita il negozio online", + "add_to_apple_wallet": "Aggiungi a Apple Wallet", + "qr_image_alt": "Codice QR — scansiona per riscattare il buono regalo", + "copy_code": "Copia codice del buono regalo", + "expiration_date": "Scade il giorno {{ expires_on }}", + "copy_code_success": "Codice copiato correttamente", + "expired": "Scaduto" + } + }, + "placeholders": { + "password": "Password", + "search": "Ricerca", + "product_title": "Titolo del prodotto", + "collection_title": "Titolo della collezione" + }, + "products": { + "product": { + "add_to_cart": "Aggiungi al carrello", + "added_to_cart": "Aggiunto al carrello", + "adding_to_cart": "Aggiunta in corso...", + "add_to_cart_error": "Errore durante l'aggiunta al carrello", + "sold_out": "Esaurito", + "unavailable": "Non disponibile" + } + }, + "fields": { + "separator": "a" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} commento", + "other": "{{ count }} commenti", + "many": "{{ count }} commenti" + } + }, + "comment_form": { + "email": "Email", + "error": "Pubblicazione del commento non riuscita; verifica quanto segue:", + "heading": "Lascia un commento", + "message": "Messaggio", + "moderated": "Ricorda che i commenti devono essere approvati prima di essere pubblicati.", + "name": "Nome", + "post": "Pubblica commento", + "success_moderated": "Commento pubblicato, in attesa di moderazione", + "success": "Commento pubblicato" + } + } +} diff --git a/locales/it.schema.json b/locales/it.schema.json new file mode 100644 index 000000000..d52603538 --- /dev/null +++ b/locales/it.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Bordi", + "collapsible_row": "Riga comprimibile", + "colors": "Colori", + "custom_section": "Sezione personalizzata", + "icon": "Icona", + "logo_and_favicon": "Logo e favicon", + "overlapping_blocks": "Blocchi sovrapposti", + "product_buy_buttons": "Pulsanti Acquista", + "product_description": "Descrizione", + "product_price": "Prezzo", + "product_variant_picker": "Selettore di variante", + "slideshow": "Presentazione", + "typography": "Caratteri tipografici", + "video": "Video", + "slideshow_controls": "Controlli di presentazione", + "size": "Dimensione", + "spacing": "Spaziatura", + "product_recommendations": "Prodotti consigliati", + "product_media": "Contenuti multimediali prodotto", + "featured_collection": "Collezione in evidenza", + "add_to_cart": "Aggiungi al carrello", + "email_signup": "Iscrizione alla newsletter", + "submit_button": "Pulsante Invia", + "grid_layout_selector": "Selettore layout griglia", + "image": "Immagine", + "list_items": "Articoli dell'elenco", + "facets": "Facet", + "variants": "Varianti", + "product_cards": "Schede prodotto", + "styles": "Stili", + "primary_button": "Pulsante primario", + "secondary_button": "Pulsante secondario", + "popovers": "Finestre a comparsa", + "buttons": "Pulsanti", + "inputs": "Input", + "marquee": "Area di selezione", + "alternating_content_rows": "Righe alternate", + "pull_quote": "Citazione", + "contact_form": "Modulo di contatto", + "featured_product": "Prodotti in evidenza", + "icons_with_text": "Icone con testo", + "products_carousel": "Collezione in evidenza: Carosello", + "products_grid": "Collezione in evidenza: Griglia", + "product_list": "Collezione in evidenza", + "spacer": "Spaziatore", + "accelerated_checkout": "Check-out veloce", + "accordion": "Accordion", + "accordion_row": "riga Accordion", + "animations": "Animazioni", + "announcement": "Annuncio", + "announcement_bar": "Barra degli annunci", + "badges": "Badge", + "button": "Pulsante", + "cart": "Carrello", + "cart_items": "Articoli nel carrello", + "cart_products": "Prodotti del carrello", + "cart_title": "Carrello", + "collection": "Collezione", + "collection_card": "Scheda collezioni", + "collection_columns": "Colonne collezioni", + "collection_container": "Collezione", + "collection_description": "Descrizione della collezione", + "collection_image": "Immagine della collezione", + "collection_info": "Informazioni sulla collezione", + "collection_list": "Elenco delle collezioni", + "collections": "Collezioni", + "content": "Contenuto", + "content_grid": "Griglia contenuto", + "details": "Dettagli", + "divider": "Divisore", + "filters": "Filtri e ordinamento", + "follow_on_shop": "Segui su Shop", + "footer": "Footer", + "footer_utilities": "Utility di footer", + "group": "Gruppo", + "header": "Header", + "heading": "Titolo", + "icons": "Icone", + "image_with_text": "Immagine con testo", + "input": "Input", + "logo": "Logo", + "magazine_grid": "Griglia riviste", + "media": "Contenuti multimediali", + "menu": "Menu", + "mobile_layout": "Layout dispositivo mobile", + "payment_icons": "Icone di pagamento", + "popup_link": "Link pop up", + "predictive_search": "Popover ricerca", + "predictive_search_empty": "Ricerca predittiva vuota", + "price": "Prezzo", + "product": "Prodotto", + "product_card": "Scheda prodotto", + "product_card_media": "Contenuti multimediali", + "product_card_rendering": "Rendering della scheda prodotto", + "product_grid": "Griglia", + "product_grid_main": "Griglia prodotti", + "product_image": "Immagine del prodotto", + "product_information": "Informazioni sul prodotto", + "product_review_stars": "Stelline recensione", + "quantity": "Quantità", + "row": "Riga", + "search": "Ricerca", + "section": "Sezione", + "selected_variants": "Varianti selezionate", + "shop_the_look": "Acquista l'outfit", + "slide": "Scorrimento", + "social_media_links": "Link ai social media", + "steps": "Passaggi", + "summary": "Riepilogo", + "swatches": "Campioni di colore", + "testimonials": "Testimonial", + "text": "Testo", + "title": "Titolo", + "utilities": "Utility", + "search_input": "Input di ricerca", + "search_results": "Risultati della ricerca", + "read_only": "Sola lettura", + "collection_title": "Titolo della collezione", + "collections_bento": "Elenco delle collezioni: Bento", + "collections_carousel": "Elenco delle collezioni: carosello", + "collections_grid": "Elenco delle collezioni: griglia", + "collection_links": "Link alle collezioni", + "collection_links_spotlight": "Link alle collezioni: Spotlight", + "collection_links_text": "Link alle collezioni: testo", + "count": "Conteggio", + "divider_section": "Divisore", + "faq_section": "Domande frequenti", + "hero": "Hero", + "jumbo_text": "Testo jumbo", + "marquee_section": "Area di selezione", + "media_with_text": "Contenuti multimediali con testo", + "view_all_button": "Visualizza tutto", + "video_section": "Video", + "blog": "Blog", + "blog_posts": "Articoli del blog", + "product_title": "Titolo del prodotto", + "custom_liquid": "Liquid personalizzato", + "blog_post": "Articolo del blog", + "caption": "Didascalia", + "collection_card_image": "Immagine", + "collections_editorial": "Elenco delle collezioni: editoriale", + "copyright": "Copyright", + "drawers": "Finestre", + "editorial": "Editoriale", + "editorial_jumbo_text": "Editoriale: testo Jumbo", + "hero_marquee": "Hero: Marquee", + "input_fields": "Campi di inserimento", + "local_pickup": "Ritiro locale", + "page": "Pagina", + "page_content": "Contenuto", + "page_layout": "Layout pagina", + "policy_list": "Link alle informative", + "prices": "Prezzi", + "product_list_button": "Pulsante Visualizza tutto", + "products_editorial": "Collezione in evidenza: Editoriale", + "social_link": "Link ai social", + "split_showcase": "Split Showcase", + "variant_pickers": "Selettori di varianti", + "pills": "A pillole", + "large_logo": "Logo grande", + "product_inventory": "Scorte prodotti", + "description": "Descrizione" + }, + "settings": { + "alignment": "Allineamento", + "autoplay": "Riproduzione automatica", + "background": "Sfondo", + "border_radius": "Raggio angolo", + "border_width": "Spessore bordo", + "borders": "Bordi", + "bottom_padding": "Spaziatura inferiore", + "button": "Pulsante", + "color": "Colore", + "colors": "Colori", + "content_alignment": "Allineamento contenuto", + "content_direction": "Orientamento contenuto", + "content_position": "Posizione contenuto", + "cover_image_size": "Dimensioni immagine di copertina", + "cover_image": "Immagine di copertina", + "custom_minimum_height": "Altezza minima personalizzata", + "custom_width": "Larghezza personalizzata", + "enable_video_looping": "Riproduzione in loop dei video", + "favicon": "Favicon", + "font_family": "Famiglia di font", + "gap": "Divario", + "geometric_translate_y": "Traslazione geometrica Y", + "heading": "Titolo", + "icon": "Icona", + "image": "Immagine", + "image_icon": "Icona immagine", + "image_opacity": "Opacità immagine", + "image_position": "Posizione immagine", + "image_ratio": "Proporzioni immagine", + "label": "Etichetta", + "line_height": "Altezza linea", + "link": "Link", + "layout_gap": "Spazio di layout", + "make_section_full_width": "Rendi sezione a larghezza intera", + "minimum_height": "Altezza minima", + "opacity": "Opacità", + "overlay_opacity": "Opacità della sovrapposizione", + "padding": "Spaziatura", + "primary_color": "Link", + "product": "Prodotto", + "section_width": "Larghezza sezione", + "size": "Taglia", + "slide_spacing": "Spazio slide", + "slide_width": "Larghezza slide", + "slideshow_fullwidth": "Slide a larghezza piena", + "style": "Stile", + "text": "Testo", + "text_case": "Maiuscole/Minuscole", + "top_padding": "Spaziatura superiore", + "video": "Video", + "video_alt_text": "Testo alternativo", + "video_loop": "Video in loop", + "video_position": "Posizione del video", + "width": "Larghezza", + "z_index": "Indice Z", + "limit_content_width": "Limita larghezza del contenuto", + "color_scheme": "Schema colori", + "inherit_color_scheme": "Importa automaticamente schema colori", + "product_count": "Conteggio prodotti", + "product_type": "Tipo di prodotto", + "content_width": "Larghezza contenuto", + "collection": "Collezione", + "enable_sticky_content": "Contenuto fisso su desktop", + "error_color": "Errore", + "success_color": "Operazione riuscita", + "primary_font": "Font primario", + "secondary_font": "Font secondario", + "tertiary_font": "Font terziario", + "columns": "Colonne", + "items_to_show": "Elementi da mostrare", + "layout": "Layout", + "layout_type": "Tipo", + "show_grid_layout_selector": "Mostra selettore layout griglia", + "view_more_show": "Mostra pulsante Visualizza altro", + "image_gap": "Spazio immagine", + "width_desktop": "Larghezza desktop", + "width_mobile": "Larghezza dispositivo mobile", + "border_style": "Stile bordo", + "height": "Altezza", + "thickness": "Spessore", + "stroke": "Tratto", + "filter_style": "Filtra stile", + "swatches": "Campioni di colore", + "quick_add_colors": "Aggiunta rapida colori", + "divider_color": "Divisore", + "border_opacity": "Opacità del bordo", + "hover_background": "Sfondo effetto hover", + "hover_borders": "Bordi effetto hover", + "hover_text": "Testo effetto hover", + "primary_hover_color": "Link effetto hover", + "primary_button_text": "Testo pulsante primario", + "primary_button_background": "Sfondo pulsante primario", + "primary_button_border": "Bordo pulsante primario", + "secondary_button_text": "Testo pulsante secondario", + "secondary_button_background": "Sfondo pulsante secondario", + "secondary_button_border": "Bordo pulsante secondario", + "shadow_color": "Ombra", + "mobile_logo_image": "Logo mobile", + "video_autoplay": "Riproduzione automatica", + "video_cover_image": "Immagine di copertina", + "video_external_url": "URL", + "video_source": "Fonte", + "first_row_media_position": "Posizione contenuti multimediali su prima riga", + "card_image_height": "Altezza immagine del prodotto", + "background_color": "Colore dello sfondo", + "hide_padding": "Nascondi spaziatura", + "logo_font": "Font del logo", + "size_mobile": "Dimensione mobile", + "pixel_size_mobile": "Dimensione in pixel", + "percent_size_mobile": "Dimensione in percentuale", + "unit": "Unità", + "custom_mobile_size": "Dimensione mobile personalizzata", + "fixed_height": "Altezza in pixel", + "fixed_width": "Larghezza in pixel", + "percent_height": "Altezza in percentuale", + "percent_width": "Larghezza in percentuale", + "percent_size": "Dimensione in percentuale", + "pixel_size": "Dimensione in pixel", + "accordion": "Accordion", + "aspect_ratio": "Proporzioni", + "auto_rotate_announcements": "Ruota annunci automaticamente", + "auto_rotate_slides": "Ruota slide automaticamente", + "badge_corner_radius": "Raggio angolo", + "badge_position": "Posizione sulle schede", + "badge_sale_color_scheme": "In offerta", + "badge_sold_out_color_scheme": "Esaurito", + "behavior": "Comportamento", + "blur": "Ombra sfumata", + "border": "Bordo", + "bottom": "In basso", + "carousel_on_mobile": "Carosello su dispositivo mobile", + "cart_count": "Conteggio carrello", + "cart_items": "Articoli nel carrello", + "cart_related_products": "Prodotti simili", + "cart_title": "Carrello", + "cart_total": "Totale carrello", + "cart_type": "Tipo", + "case": "Maiuscole/Minuscole", + "checkout_buttons": "Pulsanti del check-out veloce", + "collection_list": "Collezioni", + "collection_templates": "Modelli per la collezione", + "content": "Contenuto", + "corner_radius": "Raggio angolo", + "country_region": "Paese/Area geografica", + "currency_code": "Codice valuta", + "custom_height": "Altezza personalizzata", + "desktop_height": "Altezza desktop", + "direction": "Direzione", + "display": "Schermo", + "divider_thickness": "Spessore divisore", + "divider": "Divisore", + "dividers": "Divisori", + "drop_shadow": "Ombra discendente", + "empty_state_collection_info": "Mostrato prima di inserire una ricerca", + "empty_state_collection": "Collezione con stato vuoto", + "enable_filtering": "Filtri", + "enable_grid_density": "Controllo layout griglia", + "enable_sorting": "Ordinamento", + "enable_zoom": "Abilita zoom", + "equal_columns": "Colonne uguali", + "expand_first_group": "Espandi primo gruppo", + "extend_media_to_screen_edge": "Estendi contenuti multimediali al bordo dello schermo", + "extend_summary": "Estendi al bordo dello schermo", + "extra_large": "Molto grande", + "extra_small": "Molto piccolo", + "flag": "Bandiera", + "font_price": "Font del prezzo", + "font_weight": "Peso font", + "font": "Font", + "full_width_first_image": "Prima immagine a larghezza intera", + "full_width_on_mobile": "Larghezza intera su dispositivo mobile", + "heading_preset": "Preconfigurazioni titolo", + "hide_unselected_variant_media": "Nascondi contenuti multimediali della variante non selezionata", + "horizontal_gap": "Distanza orizzontale", + "horizontal_offset": "Scostamento orizzontale ombreggiatura", + "hover_behavior": "Comportamento al passaggio del mouse", + "icon_background": "Sfondo icona", + "icons": "Icone", + "image_border_radius": "Raggio angolo dell'immagine", + "installments": "Rate", + "integrated_button": "Pulsante integrato", + "language_selector": "Selettore lingua", + "large": "Grande", + "left_padding": "Spaziatura a sinistra", + "left": "Sinistra", + "letter_spacing": "Spaziatura dei caratteri", + "limit_media_to_screen_height": "Adatta all'altezza dello schermo", + "limit_product_details_width": "Limita larghezza dettagli del prodotto", + "link_preset": "Preconfigurazione link", + "links": "Link", + "logo": "Logo", + "loop": "Loop", + "make_details_sticky_desktop": "Fisso su desktop", + "max_width": "Larghezza massima", + "media_height": "Altezza contenuti multimediali", + "media_overlay": "Sovrapposizione contenuti multimediali", + "media_position": "Posizione contenuti multimediali", + "media_type": "Tipo di contenuti multimediali", + "media_width": "Larghezza contenuti multimediali", + "menu": "Menu", + "mobile_columns": "Colonne su dispositivi mobili", + "mobile_height": "Altezza su dispositivi mobili", + "mobile_quick_add": "Aggiunta rapida dispositivi mobili", + "motion_direction": "Direzione Motion", + "motion": "Motion", + "movement_direction": "Direzione movimento", + "navigation_bar_color_scheme": "Schema di colori della barra di navigazione", + "navigation_bar": "Barra di navigazione", + "navigation": "Navigazione", + "open_new_tab": "Apri link in una nuova scheda", + "overlay_color": "Colore sovrapposizione", + "overlay": "Sovrapposizione", + "padding_bottom": "Spaziatura inferiore", + "padding_horizontal": "Spaziatura orizzontale", + "padding_top": "Spaziatura superiore", + "page_width": "Larghezza pagina", + "pagination": "Impaginazione", + "placement": "Posizionamento", + "position": "Posizione", + "preset": "Preconfigurazione", + "product_cards": "Schede prodotto", + "product_pages": "Pagine del prodotto", + "product_templates": "Modelli prodotto", + "products": "Prodotti", + "quick_add": "Aggiunta rapida", + "ratio": "Proporzioni", + "regular": "Normale", + "review_count": "Conteggio recensioni", + "right": "Destra", + "row_height": "Altezza riga", + "row": "Riga", + "seller_note": "Consenti nota al venditore", + "shape": "Forma", + "show_as_accordion": "Mostra come Accordion su dispositivo mobile", + "show_sale_price_first": "Mostra prima i prezzi di vendita", + "show_tax_info": "Dati fiscali", + "show": "Mostra", + "small": "Piccolo", + "speed": "Velocità", + "statement": "Estratto conto", + "sticky_header": "Header fisso", + "text_hierarchy": "Gerarchia testo", + "text_presets": "Preconfigurazioni del testo", + "title": "Titolo", + "top": "In alto", + "type": "Tipo", + "type_preset": "Preconfigurazione del testo", + "underline_thickness": "Spessore sottolineatura", + "variant_images": "Immagini varianti", + "vendor": "Venditore", + "vertical_gap": "Distanza verticale", + "vertical_offset": "Scostamento verticale ombreggiatura", + "vertical_on_mobile": "Verticale su dispositivo mobile", + "view_all_as_last_card": "\"Visualizza tutto\" come ultima scheda", + "weight": "Peso", + "wrap": "A capo", + "read_only": "Sola lettura", + "always_stack_buttons": "Impila sempre i pulsanti", + "button_text_case": "Maiuscole/minuscole testo", + "button_text_weight": "Spessore testo", + "custom_mobile_width": "Larghezza personalizzata dispositivo mobile", + "gradient_direction": "Direzione del gradiente", + "headings": "Intestazioni", + "horizontal_padding": "Spaziatura interna orizzontale", + "overlay_style": "Stile sovrapposizione", + "shadow_opacity": "Opacità ombra", + "show_filter_label": "Etichette di testo per i filtri applicati", + "show_swatch_label": "Etichette di testo per i campioni di colore", + "show_count": "Mostra conteggio", + "transparent_background": "Sfondo trasparente", + "vertical_padding": "Spaziatura interna verticale", + "visibility": "Visibilità", + "account": "Account", + "align_baseline": "Allinea la base del testo", + "add_discount_code": "Consenti sconti nel carrello", + "background_overlay": "Sovrapposizione sfondo", + "background_media": "Contenuti multimediali sfondo", + "border_thickness": "Spessore bordo", + "bottom_row": "Riga inferiore", + "card_size": "Dimensioni scheda", + "auto_open_cart_drawer": "\"Aggiungi al carrello\" apre automaticamente la finestra", + "collection_count": "Conteggio collezioni", + "collection_title_case": "Maiuscole/minuscole del titolo della collezione", + "custom_liquid": "Codice Liquid", + "default": "Predefinito", + "default_logo": "Logo predefinito", + "divider_width": "Larghezza divisore", + "hide_logo_on_home_page": "Nascondi logo sulla homepage", + "inverse": "Inverso", + "inverse_logo": "Logo inverso", + "layout_style": "Stile", + "length": "Lunghezza", + "mobile_card_size": "Dimensioni scheda per dispositivi mobili", + "mobile_pagination": "Impaginazione per dispositivi mobili", + "open_row_by_default": "Riga aperta per impostazione predefinita", + "page": "Pagina", + "page_transition_enabled": "Transizione pagina", + "product_and_card_title_case": "Maiuscole/minuscole del titolo del prodotto e della scheda", + "product_title_case": "Maiuscole/minuscole del titolo del prodotto", + "right_padding": "Spaziatura interna a destra", + "search": "Ricerca", + "search_icon": "Icona di ricerca", + "search_position": "Posizione", + "search_row": "Riga", + "show_author": "Autore", + "show_alignment": "Mostra allineamento", + "show_date": "Data", + "show_pickup_availability": "Mostra disponibilità per il ritiro", + "show_search": "Mostra ricerca", + "text_label_case": "Maiuscole/minuscole dell'etichetta di testo", + "use_inverse_logo": "Usa logo inverso", + "product_corner_radius": "Raggio angolo prodotto", + "card_corner_radius": "Raggio angolo scheda", + "alignment_mobile": "Allineamento su dispositivi mobili", + "animation_repeat": "Ripeti animazione", + "blurred_reflection": "Riflesso sfocato", + "card_hover_effect": "Effetto al passaggio del mouse sulla scheda", + "effects": "Effetti", + "inventory_threshold": "Soglia per scorte in esaurimento", + "reflection_opacity": "Opacità del riflesso", + "show_inventory_quantity": "Mostra quantità scorte in esaurimento", + "transition_to_main_product": "Transizione dalla scheda prodotto alla pagina del prodotto", + "show_second_image_on_hover": "Mostra seconda immagine al passaggio del mouse", + "media": "Contenuti multimediali", + "product_card_carousel": "Mostra carosello", + "media_fit": "Adattamento dei contenuti multimediali", + "scroll_speed": "Scorri al prossimo annuncio" + }, + "options": { + "adapt_to_image": "Adatta a immagine", + "apple": "Mela", + "arrow": "Freccia", + "auto": "Automatico", + "banana": "Banana", + "bottle": "Bottiglia", + "box": "Scatola", + "buttons": "Pulsanti", + "carrot": "Carota", + "center": "Al centro", + "chat_bubble": "Fumetto chat", + "clipboard": "Blocco appunti", + "contain": "Limita", + "counter": "Contatore", + "cover": "Copertina", + "custom": "Personalizzato", + "dairy_free": "Senza latticini", + "dairy": "Latticini", + "default": "Predefinito", + "dropdowns": "Menu a discesa", + "dots": "Punti", + "dryer": "Asciugatrice", + "end": "Alla fine", + "eye": "Occhio", + "facebook": "Facebook", + "fill": "Riempi", + "fire": "Fuoco", + "fit": "Adatta", + "full": "Completo", + "full_and_page": "Sfondo completo, contenuto a larghezza di pagina", + "gluten_free": "Senza glutine", + "heading": "Titolo", + "heart": "Cuore", + "horizontal": "Orizzontale", + "instagram": "Instagram", + "iron": "Ferro", + "landscape": "Orizzontale", + "large": "Grande", + "leaf": "Foglia", + "leather": "Pelle", + "lg": "L", + "lightning_bolt": "Fulmine", + "link": "Link", + "lipstick": "Rossetto", + "lock": "Lucchetto", + "lowercase": "minuscolo", + "m": "M", + "map_pin": "Pin mappa", + "medium": "Medio", + "none": "Nessuno", + "numbers": "Numeri", + "nut_free": "Senza frutta a guscio", + "outline": "Contorno", + "page": "Pagina", + "pants": "Pantaloni", + "paw_print": "Impronta di zampa", + "pepper": "Pepe", + "perfume": "Profumi", + "pinterest": "Pinterest", + "plane": "Aereo", + "plant": "Piante", + "portrait": "Verticale", + "price_tag": "Cartellino prezzo", + "question_mark": "Punto interrogativo", + "recycle": "Riciclo", + "return": "Reso", + "ruler": "Righello", + "s": "S", + "sentence": "Frase", + "serving_dish": "Piatto da portata", + "shirt": "Maglietta", + "shoe": "Scarpa", + "silhouette": "Silhouette", + "small": "Piccola", + "snapchat": "Snapchat", + "snowflake": "Fiocco di neve", + "solid": "Pieno", + "space_between": "Spazio in mezzo", + "square": "Quadrato", + "star": "Stella", + "start": "All'inizio", + "stopwatch": "Cronometro", + "tiktok": "TikTok", + "truck": "Camion", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Maiuscolo", + "vertical": "Verticale", + "vimeo": "Vimeo", + "washing": "Lavaggio", + "circle": "Tondo", + "swatches": "Campioni di colore", + "full_and_page_offset_left": "Sfondo completo, contenuto a larghezza di pagina, scostamento a sinistra", + "full_and_page_offset_right": "Sfondo completo, contenuto a larghezza di pagina, scostamento a destra", + "offset_left": "Scostamento a sinistra", + "offset_right": "Scostamento a destra", + "page_center_aligned": "Pagina, allineamento centrale", + "page_left_aligned": "Pagina, allineamento a sinistra", + "page_right_aligned": "Pagina, allineamento a destra", + "button": "Pulsante", + "caption": "Didascalia", + "h1": "Titolo 1", + "h2": "Titolo 2", + "h3": "Titolo 3", + "h4": "Titolo 4", + "h5": "Titolo 5", + "h6": "Titolo 6", + "paragraph": "Paragrafo", + "primary": "Primario", + "secondary": "Secondario", + "tertiary": "Terziario", + "chevron_left": "Parentesi ad angolo a sinistra", + "chevron_right": "Parentesi ad angolo a destra", + "diamond": "Diamante", + "grid": "Griglia", + "parallelogram": "Parallelogramma", + "rounded": "Arrotondati", + "fit_content": "Vestibilità", + "pills": "\"A pillole\"", + "heavy": "Marcato", + "thin": "Fine", + "drawer": "Finestra", + "preview": "Anteprima", + "text": "Testo", + "video_uploaded": "Caricato", + "video_external_url": "URL esterno", + "up": "Su", + "down": "Giù", + "gradient": "Gradiente", + "aspect_ratio": "Proporzioni", + "fixed": "Fisso", + "pixel": "Pixel", + "percent": "Percentuale", + "above_carousel": "Sopra il carosello", + "all": "Tutto", + "always": "Sempre", + "arrows_large": "Frecce grandi", + "arrows": "Frecce", + "balance": "Saldo", + "bento": "Bento", + "black": "Nero", + "bluesky": "Bluesky", + "body_large": "Testo (grande)", + "body_regular": "Testo (normale)", + "body_small": "Testo (piccolo)", + "bold": "Grassetto", + "bottom_left": "In basso a sinistra", + "bottom_right": "In basso a destra", + "bottom": "In basso", + "capitalize": "Maiuscole", + "caret": "Accento circonflesso", + "carousel": "Carosello", + "check_box": "Casella di controllo", + "chevron_large": "Parentesi ad angolo grandi", + "chevron": "Parentesi ad angolo", + "chevrons": "Parentesi ad angolo", + "classic": "Classico", + "collection_images": "Immagini collezione", + "color": "Colore", + "complementary": "Complementare", + "dissolve": "Dissolvi", + "dotted": "Punteggiato", + "editorial": "Editoriale", + "extra_large": "Molto grande", + "extra_small": "Molto piccolo", + "featured_collections": "Collezioni in evidenza", + "featured_products": "Prodotti in evidenza", + "font_primary": "Primario", + "font_secondary": "Secondario", + "font_tertiary": "Terziario", + "forward": "Avanti", + "full_screen": "Schermo intero", + "heading_extra_large": "Titolo (molto grande)", + "heading_extra_small": "Titolo (molto piccolo)", + "heading_large": "Titolo (grande)", + "heading_regular": "Titolo (normale)", + "heading_small": "Titolo (piccolo)", + "icon": "Icona", + "image": "Immagine", + "input": "Input", + "inside_carousel": "Carosello interno", + "inverse_large": "Inverso grande", + "inverse": "Inverso", + "large_arrows": "Frecce grandi", + "large_chevrons": "Parentesi ad angolo grandi", + "left": "Sinistra", + "light": "Leggero", + "linkedin": "LinkedIn", + "loose": "Lento", + "media_first": "Contenuti multimediali primi", + "media_second": "Contenuti multimediali secondi", + "modal": "Modale", + "narrow": "Stretto", + "never": "Mai", + "next_to_carousel": "Accanto al carosello", + "normal": "Normale", + "nowrap": "Nessun a capo", + "off_media": "Fuori dai contenuti multimediali", + "on_media": "Sui contenuti multimediali", + "on_scroll_up": "Durante lo scorrimento verso l'alto", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "A pillola", + "plus": "Plus", + "pretty": "Pretty", + "price": "Prezzo", + "primary_style": "Stile primario", + "rectangle": "Rettangolo", + "regular": "Normale", + "related": "Correlato", + "reverse": "Inverso", + "rich_text": "Rich text", + "right": "Destra", + "secondary_style": "Stile secondario", + "semibold": "Semigrassetto", + "shaded": "Ombreggiato", + "show_second_image": "Mostra seconda immagine", + "single": "Singola", + "slide_left": "Scorri verso sinistra", + "slide_up": "Scorri in alto", + "spotify": "Spotify", + "stack": "Pila", + "text_only": "Solo testo", + "threads": "Threads", + "thumbnails": "Miniature", + "tight": "Stretto", + "top_left": "In alto a sinistra", + "top_right": "In alto a destra", + "top": "In alto", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Sottolineato", + "video": "Video", + "wide": "Largo", + "youtube": "YouTube", + "below_image": "Sotto l'immagine", + "button_primary": "Pulsante primario", + "button_secondary": "Pulsante secondario", + "hidden": "Nascosto", + "on_image": "Sull'immagine", + "spotlight": "In evidenza", + "compact": "Compatto", + "standard": "Standard", + "accent": "Elemento decorativo", + "body": "Corpo", + "crop_to_fit": "Ritaglia per adattare", + "hint": "Suggerimento", + "maintain_aspect_ratio": "Mantieni proporzioni", + "off": "Disattivato", + "social_bluesky": "Social: Bluesky", + "social_facebook": "Social: Facebook", + "social_instagram": "Social: Instagram", + "social_linkedin": "Social: LinkedIn", + "social_pinterest": "Social: Pinterest", + "social_snapchat": "Social: Snapchat", + "social_spotify": "Social: Spotify", + "social_threads": "Social: Threads", + "social_tiktok": "Social: TikTok", + "social_tumblr": "Social: Tumblr", + "social_twitter": "Social: X (Twitter)", + "social_whatsapp": "Social: WhatsApp", + "social_vimeo": "Social: Vimeo", + "social_youtube": "Social: YouTube", + "subheading": "Sottotitolo", + "blur": "Sfocato", + "lift": "Solleva", + "reveal": "Rivela", + "scale": "Ridimensiona", + "subtle_zoom": "Zoom" + }, + "content": { + "advanced": "Avanzato", + "background_image": "Immagine di sfondo", + "background_video": "Video in background", + "block_size": "Dimensione blocco", + "borders": "Bordi", + "describe_the_video_for": "Descrivi il video per i clienti che utilizzano i lettori di schermo. [Maggiori informazioni](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Dimensione sezione", + "slideshow_width": "Larghezza slide", + "typography": "Caratteri tipografici", + "width_is_automatically_optimized": "Larghezza automaticamente ottimizzata per i dispositivi mobili.", + "complementary_products": "I prodotti complementari devono essere configurati tramite l'app Search & Discovery. [Maggiori informazioni](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Le colonne verranno ottimizzate automaticamente per i dispositivi mobili", + "content_width": "La larghezza del contenuto si applica solo quando la larghezza della sezione è impostata come intera larghezza.", + "adjustments_affect_all_content": "Si applica all'intero contenuto di questo blocco", + "responsive_font_sizes": "Le dimensioni si adattano automaticamente a tutte le dimensioni dello schermo", + "buttons": "Pulsanti", + "swatches": "Campioni di colore", + "variant_settings": "Impostazioni relative alla variante", + "background": "Sfondo", + "cards_layout": "Layout schede", + "section_layout": "Layout sezione", + "mobile_size": "Dimensione mobile", + "appearance": "Aspetto", + "arrows": "Frecce", + "body_size": "Dimensioni del testo", + "bottom_row_appearance": "Aspetto della riga inferiore", + "carousel_navigation": "Navigazione carosello", + "carousel_pagination": "Impaginazione carosello", + "copyright": "Copyright", + "edit_logo_in_theme_settings": "Modifica il logo in [impostazioni tema](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Modifica la formattazione dei prezzi in [impostazioni tema](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Modifica lo stile della variante in [impostazioni tema](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Aggiunta di iscrizioni [profili cliente](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Affinché il pulsante venga visualizzato, il canale Shop deve essere installato e Shop Pay attivato. [Maggiori informazioni](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Font", + "grid": "Griglia", + "heading_size": "Dimensione titolo", + "image": "Immagine", + "input": "Input", + "layout": "Layout", + "link": "Link", + "link_padding": "Spaziatura link", + "localization": "Localizzazione", + "logo": "Logo", + "margin": "Margine", + "media": "Contenuti multimediali", + "media_1": "Contenuti multimediali 1", + "media_2": "Contenuti multimediali 2", + "menu": "Menu", + "mobile_layout": "Layout dispositivo mobile", + "padding": "Spaziatura", + "padding_desktop": "Spaziatura desktop", + "paragraph": "Paragrafo", + "policies": "Politiche", + "popup": "Pop up", + "search": "Ricerca", + "size": "Dimensione", + "social_media": "Social media", + "submit_button": "Pulsante Invia", + "text_presets": "Preconfigurazioni del testo", + "transparent_background": "Sfondo trasparente", + "typography_primary": "Caratteri tipografici primari", + "typography_secondary": "Caratteri tipografici secondari", + "typography_tertiary": "Caratteri tipografici terziari", + "mobile_width": "Larghezza dispositivo mobile", + "width": "Larghezza", + "images": "Immagini", + "visible_if_collection_has_more_products": "Visibile se la collezione contiene più prodotti di quelli mostrati", + "carousel": "Carosello", + "colors": "Colori", + "collection_page": "Pagina di collezione", + "copyright_info": "Scopri come [modificare l'informativa sul copyright](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Account cliente", + "edit_empty_state_collection_in_theme_settings": "Modifica collezione con stato vuoto in [impostazioni del tema](/editor?context=theme&category=search)", + "grid_layout": "Layout a griglia", + "home_page": "Homepage", + "inverse_logo_info": "Utilizzato quando lo sfondo trasparente dell’header è impostato su Inverso", + "manage_customer_accounts": "[Gestisci la visibilità](/admin/settings/customer_accounts) nelle impostazioni dell'account cliente. Gli account legacy non sono supportati.", + "manage_policies": "[Gestisci informative](/admin/settings/legal)", + "product_page": "Pagina del prodotto", + "text": "Testo", + "thumbnails": "Miniature", + "visibility": "Visibilità", + "app_required_for_ratings": "Per le valutazioni dei prodotti è necessaria un'app. [Maggiori informazioni](https://help.shopify.com/manual/apps)", + "icon": "Icona", + "manage_store_name": "[Gestisci il nome del negozio](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Visualizza la collezione dalla sezione padre", + "resource_reference_collection_card_image": "Visualizza l'immagine dalla collezione padre", + "resource_reference_collection_title": "Visualizza il titolo dalla collezione padre", + "resource_reference_product": "Si collega automaticamente al prodotto padre", + "resource_reference_product_card": "Visualizza il prodotto dalla sezione padre", + "resource_reference_product_inventory": "Visualizza le scorte dal prodotto padre", + "resource_reference_product_price": "Visualizza il prezzo dal prodotto padre", + "resource_reference_product_recommendations": "Visualizza le raccomandazioni basate sul prodotto padre", + "resource_reference_product_review": "Visualizza le recensioni dal prodotto padre", + "resource_reference_product_swatches": "Visualizza i campioni di colore dal prodotto padre", + "resource_reference_product_title": "Visualizza il titolo dal prodotto padre", + "resource_reference_product_variant_picker": "Visualizza le varianti dal prodotto padre", + "resource_reference_product_media": "Visualizza i contenuti multimediali dal prodotto padre", + "product_media": "Contenuti multimediali prodotto", + "section_link": "Link alla sezione" + }, + "html_defaults": { + "share_information_about_your": "

Condividi informazioni sul tuo brand con i clienti. Descrivi un prodotto, condividi gli annunci o dai il benvenuto ai clienti nel tuo negozio.

" + }, + "text_defaults": { + "button_label": "Acquista ora", + "collapsible_row": "Riga comprimibile", + "heading": "Titolo", + "email_signup_button_label": "Iscriviti", + "accordion_heading": "Titolo Accordion", + "contact_form_button_label": "Invia", + "popup_link": "Link pop up", + "sign_up": "Registrati", + "welcome_to_our_store": "Ti diamo il benvenuto nel nostro negozio", + "be_bold": "Sii audace.", + "shop_our_latest_arrivals": "Scopri gli ultimi arrivi." + }, + "info": { + "carousel_layout_on_mobile": "Carosello utilizzato su dispositivo mobile", + "link_info": "Facoltativo: rende l'icona selezionabile", + "video_alt_text": "Descrivi il video per gli utenti che utilizzano tecnologie assistive", + "video_autoplay": "L'audio del video verrà disattivato per impostazione predefinita", + "video_external": "Utilizza un URL YouTube o Vimeo", + "carousel_hover_behavior_not_supported": "L'effetto hover \"Carosello\" non è supportato quando il tipo \"Carosello\" è selezionato a livello di sezione", + "grid_layout_on_mobile": "Layout griglia utilizzato per dispositivi mobili", + "logo_font": "Si applica solo quando nessun logo è selezionato", + "checkout_buttons": "Consente agli acquirenti di effettuare il check-out più velocemente e può migliorare la conversione. [Maggiori informazioni](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Titolo personalizzato", + "edit_presets_in_theme_settings": "Modifica le preconfigurazioni in [impostazioni tema](/editor?context=theme&category=typography)", + "enable_filtering_info": "Personalizza i filtri con l'[app Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "manage_countries_regions": "[Gestisci paesi/aree geografiche](/admin/settings/markets)", + "manage_languages": "[Gestisci lingue](/admin/settings/languages)", + "transparent_background": "Esamina ogni modello in cui viene applicato uno sfondo trasparente per la leggibilità", + "aspect_ratio_adjusted": "Adattate in alcuni layout", + "auto_open_cart_drawer": "Se abilitata, quando un prodotto viene aggiunto al carrello la finestra del carrello si apre automaticamente.", + "custom_liquid": "Aggiungi snippet di app o altro codice per creare personalizzazioni avanzate. [Maggiori informazioni](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Utilizzato per filtri applicati, codici sconto e suggerimenti di ricerca", + "applies_on_image_only": "Si applica solo alle immagini", + "hover_effects": "Si applica alle schede di prodotti e collezioni" + }, + "categories": { + "product_list": "Collezione in evidenza", + "basic": "Base", + "collection": "Collezione", + "collection_list": "Elenco delle collezioni", + "footer": "Footer", + "forms": "Moduli", + "header": "Header", + "layout": "Layout", + "links": "Link", + "product": "Prodotto", + "decorative": "Decorativo", + "banners": "Banner", + "collections": "Collezioni", + "custom": "Personalizzato", + "products": "Prodotti", + "other_sections": "Altro", + "storytelling": "Storytelling" + } +} diff --git a/locales/ja.json b/locales/ja.json new file mode 100644 index 000000000..1c8330000 --- /dev/null +++ b/locales/ja.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "ビデオを読み込む: {{ description }}", + "sold_out": "売り切れ", + "email_signup": { + "label": "メール", + "placeholder": "メールアドレス", + "success": "ご登録ありがとうございます!" + }, + "filter": "フィルター", + "payment_methods": "決済方法", + "contact_form": { + "name": "名前", + "email": "メールアドレス", + "phone": "電話", + "comment": "コメント", + "post_success": "お問い合わせいただきありがとうございます。早急に返信いたします。", + "error_heading": "以下を確認してください。" + } + }, + "accessibility": { + "play_model": "3Dモデルを再生", + "play_video": "ビデオを再生", + "unit_price": "単価", + "country_results_count": "{{ count }}件の結果", + "slideshow_pause": "スライドショーを一時停止", + "slideshow_play": "スライドショーを再生", + "remove_item": "{{ title}}を削除する", + "skip_to_text": "コンテンツにスキップ", + "skip_to_product_info": "商品情報にスキップ", + "skip_to_results_list": "結果リストにスキップ", + "new_window": "新しいウィンドウで開きます。", + "slideshow_next": "次のスライド", + "slideshow_previous": "前のスライド", + "close_dialog": "ダイアログを閉じる", + "reset_search": "検索をリセットする", + "search_results_count": "「{{ query }}」の検索結果{{ count }}件", + "search_results_no_results": "「{{ query }}」の検索結果は見つかりませんでした", + "filters": "絞り込み", + "filter_count": { + "one": "{{ count }}フィルターを適用しました", + "other": "{{ count }}フィルターを適用しました" + }, + "account": "アカウントメニューを開く", + "cart": "カート", + "cart_count": "カート内の合計アイテム数", + "menu": "メニュー", + "country_region": "国 / 地域", + "slide_status": "スライド {{ index }}/{{ length }}", + "scroll_to": "{{ title }}までスクロール", + "loading_product_recommendations": "商品のおすすめを読み込んでいます", + "discount": "クーポンコードを適用する", + "discount_applied": "適用クーポンコード:{{ code }}", + "open_cart_drawer": "カートを開く", + "pause_video": "動画を一時停止", + "inventory_status": "在庫ステータス", + "find_country": "国を探す", + "localization_region_and_language": "地域と言語のセレクターを開く", + "open_search_modal": "検索を開く", + "decrease_quantity": "数量を減らす", + "increase_quantity": "数量を増やす", + "quantity": "数量", + "rating": "この商品の評価は、5段階中{{ rating }}です", + "nested_product": "{{ parent_title }}向けの{{ product_title }}" + }, + "actions": { + "add_to_cart": "カートに追加", + "clear_all": "すべてクリア", + "remove": "削除", + "view_in_your_space": "スペースに表示", + "show_filters": "フィルター", + "clear": "透明", + "continue_shopping": "買い物を続ける", + "log_in_html": "アカウントをお持ちですか?ログインすることで、チェックアウトがスピーディーに行えます。", + "see_items": { + "one": "{{ count }}個のアイテムを表示する", + "other": "{{ count }}個のアイテムを表示する" + }, + "view_all": "すべてを表示", + "add": "追加", + "choose": "選択", + "added": "追加済み", + "show_less": "表示を減らす", + "show_more": "さらに表示する", + "close": "閉じる", + "more": "さらに表示する", + "reset": "リセット", + "zoom": "ズーム", + "close_dialog": "ダイアログを閉じる", + "back": "戻る", + "log_in": "ログイン", + "log_out": "ログアウト", + "remove_discount": "クーポン{{ code }}を削除する", + "enter_using_password": "パスワードを入力してアクセスする", + "submit": "送信", + "enter_password": "パスワードを入力する", + "view_store_information": "ストア情報を表示する", + "apply": "適用", + "open_image_in_full_screen": "画像を全画面で表示", + "sign_in_options": "その他のログインオプション", + "sign_up": "サインアップする", + "sort": "並び替え", + "show_all_options": "すべてのオプションを表示する" + }, + "content": { + "reviews": "レビュー", + "language": "言語", + "localization_region_and_language": "地域と言語", + "no_results_found": "結果は見つかりませんでした", + "cart_total": "カートの合計", + "your_cart_is_empty": "カートの中身が空です", + "product_image": "商品画像", + "product_information": "商品情報", + "quantity": "数量", + "product_total": "商品合計", + "cart_estimated_total": "見積もり合計", + "seller_note": "特別な指示", + "cart_subtotal": "小計", + "discounts": "ディスカウント", + "discount": "ディスカウント", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "関税と税金が含まれます。ディスカウントと配送料はチェックアウト時に計算されます。", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "関税と税金が含まれます。ディスカウントと配送料はチェックアウト時に計算されます。", + "taxes_included_shipping_at_checkout_with_policy_html": "税込。ディスカウントと配送料はチェックアウト時に計算されます。", + "taxes_included_shipping_at_checkout_without_policy": "税込。ディスカウントと配送料はチェックアウト時に計算されます。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "関税込。税、ディスカウント、および配送料はチェックアウト時に計算されます。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "関税込。税、ディスカウント、および配送料はチェックアウト時に計算されます。", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "税、ディスカウント、および配送料はチェックアウト時に計算されます。", + "taxes_at_checkout_shipping_at_checkout_without_policy": "税、ディスカウント、および配送料はチェックアウト時に計算されます。", + "checkout": "チェックアウト", + "cart_title": "カート", + "price": "価格", + "price_regular": "通常価格", + "price_compare_at": "割引前価格", + "price_sale": "セール価格", + "duties_and_taxes_included": "関税と税金が含まれます。", + "duties_included": "関税込。", + "shipping_policy_html": "配送料はチェックアウト時に計算されます。", + "taxes_included": "税込。", + "product_badge_sold_out": "売り切れ", + "product_badge_sale": "セール", + "search_input_label": "検索", + "search_input_placeholder": "検索", + "search_results": "検索結果", + "search_results_label": "検索結果", + "search_results_no_results": "「{{ terms }}」の検索結果は見つかりませんでした。別の検索をお試しください。", + "search_results_resource_articles": "ブログ記事", + "search_results_resource_collections": "コレクション", + "search_results_resource_pages": "ページ", + "search_results_resource_products": "商品管理", + "search_results_resource_queries": "検索候補", + "search_results_view_all": "すべてを表示", + "search_results_view_all_button": "すべてを表示", + "search_results_resource_products_count": { + "one": "{{ count }}個の商品", + "other": "{{ count }}個の商品" + }, + "grid_view": { + "default_view": "デフォルト", + "grid_fieldset": "列グリッド", + "single_item": "単一", + "zoom_out": "ズームアウト" + }, + "recently_viewed_products": "最近閲覧した商品", + "unavailable": "利用不可", + "collection_placeholder": "コレクションのタイトル", + "product_card_placeholder": "商品名", + "product_count": "商品数", + "item_count": { + "one": "{{ count }}個のアイテム", + "other": "{{ count }}個のアイテム" + }, + "errors": "エラー", + "search": "検索", + "search_results_no_results_check_spelling": "「{{ terms }}」の検索結果は見つかりませんでした。スペルを確認するか、別の単語やフレーズを使用してください。", + "featured_products": "注目商品", + "no_products_found": "商品が見つかりません。", + "price_from": "{{ price }}から", + "use_fewer_filters_html": "フィルターの数を減らしたり、すべてのフィルターをクリアしたりしてみてください。", + "filters": "絞り込み", + "price_filter_html": "最高価格は{{ price }}です", + "blog_details_separator": "|", + "read_more": "続きを読む...", + "account_title": "アカウント", + "account_title_personalized": "こんにちは、{{ first_name }}さん", + "account_orders": "注文", + "account_profile": "プロフィール", + "discount_code": "クーポンコード", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "関税と税金が含まれます。送料はチェックアウト時に計算されます。", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "関税と税金が含まれます。送料はチェックアウト時に計算されます。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "関税が含まれています。送料はチェックアウト時に計算されます。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "関税が含まれています。送料はチェックアウト時に計算されます。", + "pickup_available_at_html": "{{ location }}での受取が可能です", + "pickup_available_in": "{{ pickup_time }}に受取が可能です", + "pickup_not_available": "受取は現在不可能です", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "税と配送料はチェックアウト時に計算されます", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "税と配送料はチェックアウト時に計算されます", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "税込。送料はチェックアウト時に計算されます。", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "税込。送料はチェックアウト時に計算されます。", + "view_more_details": "詳細を表示する", + "wrong_password": "パスワードが正しくありません。", + "powered_by": "このお店は次を使用しています", + "store_owner_link_html": "あなたはストアオーナーですか?こちらからログインする", + "shipping_discount_error": "配送料の割引は、住所を追加した後のチェックアウト時に表示されます", + "discount_code_error": "クーポンコードはあなたのカートには適用できません。", + "inventory_low_stock": "低在庫", + "inventory_in_stock": "在庫あり", + "inventory_out_of_stock": "在庫切れ", + "page_placeholder_title": "ページタイトル", + "page_placeholder_content": "ページを選択して、そのコンテンツを表示します。", + "placeholder_image": "プレースホルダーの画像", + "shipping_policy": "配送料はチェックアウト時に計算されます。", + "inventory_low_stock_show_count": { + "one": "残り{{ count }}利用できます", + "other": "残り{{ count }}利用できます" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "オンラインではギフトカードコード、実店舗ではQRコードを使用する", + "title": "{{ shop }}で利用可能な{{ value }}のギフトカードの残高です。", + "subtext": "あなたのギフトカード", + "shop_link": "オンラインストアにアクセスする", + "add_to_apple_wallet": "Apple Walletに追加する", + "qr_image_alt": "QRコード: スキャンしてギフトカードにクーポンを使う", + "copy_code": "ギフトカードコードをコピーする", + "expiration_date": "{{ expires_on }}に期限が切れます", + "copy_code_success": "コードは正常にコピーされました", + "expired": "期限切れ" + } + }, + "placeholders": { + "password": "パスワード", + "search": "検索", + "product_title": "商品名", + "collection_title": "コレクションのタイトル" + }, + "products": { + "product": { + "add_to_cart": "カートに追加する", + "added_to_cart": "カートに追加済み", + "adding_to_cart": "追加中...", + "add_to_cart_error": "カートに追加する際にエラーが発生しました", + "sold_out": "売り切れ", + "unavailable": "利用できません" + } + }, + "fields": { + "separator": "~" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }}件のコメント", + "other": "{{ count }}件のコメント" + } + }, + "comment_form": { + "email": "メールアドレス", + "error": "コメントを投稿できませんでした。次の点に留意してください。", + "heading": "コメントを残す", + "message": "メッセージ", + "moderated": "コメントは公開前に承認される必要があることにご注意ください。", + "name": "名前", + "post": "コメントを投稿する", + "success_moderated": "コメントを投稿しました。承認待ちです", + "success": "コメントを投稿しました" + } + } +} diff --git a/locales/ja.schema.json b/locales/ja.schema.json new file mode 100644 index 000000000..9715966ab --- /dev/null +++ b/locales/ja.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "罫線", + "collapsible_row": "折りたたみ可能な行", + "colors": "色", + "custom_section": "カスタムセクション", + "icon": "アイコン", + "logo_and_favicon": "ロゴとファビコン", + "overlapping_blocks": "重複したブロック", + "product_buy_buttons": "購入ボタン", + "product_description": "説明", + "product_price": "価格", + "product_variant_picker": "バリエーションピッカー", + "slideshow": "スライドショー", + "typography": "タイポグラフィー", + "video": "ビデオ", + "slideshow_controls": "スライドショーのコントロール", + "size": "サイズ", + "spacing": "間隔", + "product_recommendations": "おすすめ商品", + "product_media": "商品メディア", + "featured_collection": "特集コレクション", + "add_to_cart": "カートに追加する", + "email_signup": "メール登録者", + "submit_button": "送信ボタン", + "grid_layout_selector": "グリッドレイアウトセレクター", + "image": "画像", + "list_items": "リストのアイテム", + "facets": "絞り込み", + "variants": "バリエーション", + "styles": "スタイル", + "product_cards": "商品カード", + "buttons": "ボタン", + "inputs": "入力", + "primary_button": "プライマリボタン", + "secondary_button": "サブボタン", + "popovers": "ポップオーバー", + "marquee": "マーキー", + "alternating_content_rows": "代替行", + "pull_quote": "引用文", + "contact_form": "お問い合わせフォーム", + "featured_product": "商品のハイライト", + "icons_with_text": "テキスト付きアイコン", + "product_list": "注目のコレクション", + "spacer": "スペーサー", + "products_carousel": "注目のコレクション:カルーセル", + "products_grid": "注目のコレクション:グリッド", + "accelerated_checkout": "簡単なチェックアウト", + "accordion": "アコーディオン", + "accordion_row": "アコーディオンの行", + "animations": "アニメーション", + "announcement": "お知らせ", + "announcement_bar": "お知らせバー", + "badges": "バッジ", + "button": "ボタン", + "cart": "カート", + "cart_items": "カート内のアイテム", + "cart_products": "カート内の商品", + "cart_title": "カート", + "collection": "コレクション", + "collection_card": "コレクションカード", + "collection_columns": "コレクション列", + "collection_container": "コレクション", + "collection_description": "コレクションの説明", + "collection_image": "コレクションの画像", + "collection_info": "コレクション情報", + "collection_list": "コレクションリスト", + "collections": "コレクション", + "content": "コンテンツ", + "content_grid": "コンテンツグリッド", + "details": "詳細", + "divider": "区切り線", + "filters": "絞り込みと並べ替え", + "follow_on_shop": "Shopでフォロー", + "footer": "フッター", + "footer_utilities": "フッターユーティリティ", + "group": "グループ", + "header": "ヘッダー", + "heading": "見出し", + "icons": "アイコン", + "image_with_text": "テキスト付き画像", + "input": "入力", + "logo": "ロゴ", + "magazine_grid": "マガジングリッド", + "media": "メディア", + "menu": "メニュー", + "mobile_layout": "モバイルのレイアウト", + "payment_icons": "決済アイコン", + "popup_link": "ポップアップリンク", + "predictive_search": "ポップオーバーを検索する", + "predictive_search_empty": "予測検索なし", + "price": "価格", + "product": "商品", + "product_card": "商品カード", + "product_card_media": "メディア", + "product_card_rendering": "商品カードのレンダリング", + "product_grid": "グリッド", + "product_grid_main": "商品グリッド", + "product_image": "商品画像", + "product_information": "商品情報", + "product_review_stars": "星評価", + "quantity": "数量", + "row": "行", + "search": "検索", + "section": "セクション", + "selected_variants": "選択されたバリエーション", + "shop_the_look": "このルックを購入", + "slide": "スライド", + "social_media_links": "SNSのリンク", + "steps": "手順", + "summary": "サマリー", + "swatches": "見本", + "testimonials": "お客様の声", + "text": "テキスト", + "title": "タイトル", + "utilities": "ユーティリティ", + "collection_title": "コレクションのタイトル", + "collections_bento": "コレクションリスト:Bento", + "faq_section": "よくある質問", + "hero": "ヒーロー", + "jumbo_text": "ジャンボテキスト", + "read_only": "読み取り専用", + "search_input": "入力を検索", + "search_results": "検索結果", + "view_all_button": "すべてを表示", + "video_section": "ビデオ", + "custom_liquid": "カスタムLiquid", + "blog": "ブログ", + "blog_post": "ブログ記事", + "blog_posts": "ブログ記事", + "caption": "キャプション", + "collection_card_image": "画像", + "collection_links": "コレクションリンク", + "collection_links_spotlight": "コレクションリンク:Spotlight", + "collection_links_text": "コレクションリンク:テキスト", + "collections_carousel": "コレクションリスト:カルーセル", + "collections_editorial": "コレクションリスト: エディトリアル", + "collections_grid": "コレクションリスト:グリッド", + "copyright": "著作権", + "count": "在庫数", + "divider_section": "区切り線", + "drawers": "ドロワー", + "editorial": "編集", + "editorial_jumbo_text": "編集:ジャンボ文字", + "hero_marquee": "ヒーロー:マーキー", + "input_fields": "入力フィールド", + "local_pickup": "店舗受取", + "marquee_section": "マーキー", + "media_with_text": "テキスト付きメディア", + "page": "ページ", + "page_content": "コンテンツ", + "page_layout": "ページレイアウト", + "policy_list": "ポリシーリンク", + "prices": "価格", + "products_editorial": "注目のコレクション:エディトリアル", + "social_link": "ソーシャルリンク", + "split_showcase": "Split showcase", + "variant_pickers": "バリエーションピッカー", + "product_title": "商品名", + "large_logo": "大きなロゴ", + "product_list_button": "[すべて表示] ボタン", + "product_inventory": "商品の在庫", + "pills": "ピル型ボタン", + "description": "説明" + }, + "settings": { + "alignment": "配置", + "autoplay": "自動再生", + "background": "背景", + "border_radius": "角の半径", + "border_width": "罫線の太さ", + "borders": "罫線", + "bottom_padding": "下部の余白", + "button": "ボタン", + "color": "色", + "colors": "色", + "content_alignment": "コンテンツアラインメント", + "content_direction": "コンテンツの方向", + "content_position": "コンテンツンの位置", + "cover_image_size": "カバー画像サイズ", + "cover_image": "カバー画像", + "custom_minimum_height": "高さのカスタム最小寸法", + "custom_width": "幅のカスタマイズ", + "enable_video_looping": "ビデオループしています", + "favicon": "ファビコン", + "font_family": "フォントファミリー", + "gap": "隙間", + "geometric_translate_y": "Y軸方向の移動", + "heading": "見出し", + "icon": "アイコン", + "image": "画像", + "image_icon": "画像のアイコン", + "image_opacity": "画像の不透明率", + "image_position": "画像の位置", + "image_ratio": "画像比", + "label": "ラベル", + "line_height": "行の高さ", + "link": "リンク", + "layout_gap": "レイアウトの隙間", + "make_section_full_width": "セクションを全幅にする", + "minimum_height": "高さの最小寸法", + "opacity": "不透過率", + "overlay_opacity": "オーバーレイの不透明率", + "padding": "余白", + "primary_color": "リンク", + "product": "商品", + "section_width": "セクション幅", + "size": "サイズ", + "slide_spacing": "スライドの間隔", + "slide_width": "スライド幅", + "slideshow_fullwidth": "全幅", + "style": "スタイル", + "text": "テキスト", + "text_case": "ケース", + "top_padding": "上部の余白", + "video": "ビデオ", + "video_alt_text": "代替テキスト", + "video_loop": "ループビデオ", + "video_position": "ビデオの位置", + "width": "幅", + "z_index": "Zインデックス", + "limit_content_width": "コンテンツ幅を制限する", + "color_scheme": "配色", + "inherit_color_scheme": "配色を継承する", + "product_count": "商品数", + "product_type": "商品タイプ", + "content_width": "コンテンツ幅", + "collection": "コレクション", + "enable_sticky_content": "デスクトップのコンテンツ固定表示", + "error_color": "エラー", + "success_color": "成功", + "primary_font": "メインフォント", + "secondary_font": "サブフォント", + "tertiary_font": "第3カテゴリーフォント", + "columns": "列", + "items_to_show": "表示アイテム数", + "layout": "レイアウト", + "layout_type": "タイプ", + "show_grid_layout_selector": "グリッドレイアウトセレクターを表示する", + "view_more_show": "「さらに表示」ボタンを表示する", + "image_gap": "画像の間隔", + "width_desktop": "デスクトップの幅", + "width_mobile": "モバイルの幅", + "border_style": "罫線スタイル", + "height": "高さ", + "thickness": "太さ", + "stroke": "ストローク", + "filter_style": "絞り込みスタイル", + "swatches": "見本", + "quick_add_colors": "色のクイック追加", + "divider_color": "区切り線", + "border_opacity": "境界線の不透明度", + "hover_background": "ホバーの背景", + "hover_borders": "ホバーの枠線", + "hover_text": "ホバーのテキスト", + "primary_hover_color": "ホバーリンク", + "primary_button_text": "プライマリボタンのテキスト", + "primary_button_background": "プライマリボタンの背景", + "primary_button_border": "プライマリボタンの枠線", + "secondary_button_text": "サブボタンのテキスト", + "secondary_button_background": "サブボタンの背景", + "secondary_button_border": "サブボタンの枠線", + "shadow_color": "影", + "limit_media_to_screen_height": "画面の高さに制限", + "video_autoplay": "自動再生", + "video_cover_image": "カバー画像", + "video_external_url": "URL", + "video_source": "ソース", + "background_color": "背景色", + "first_row_media_position": "最初の行のメディアの位置", + "hide_padding": "パディングを非表示", + "size_mobile": "モバイルサイズ", + "pixel_size_mobile": "ピクセルサイズ", + "percent_size_mobile": "パーセントサイズ", + "unit": "ユニット", + "custom_mobile_size": "カスタムモバイルサイズ", + "fixed_height": "ピクセル高さ", + "fixed_width": "ピクセル幅", + "percent_height": "パーセント高さ", + "percent_width": "パーセント幅", + "percent_size": "パーセントサイズ", + "pixel_size": "ピクセルサイズ", + "card_image_height": "商品画像の高さ", + "logo_font": "ロゴフォント", + "always_stack_buttons": "ボタンを常にスタック", + "custom_mobile_width": "カスタムモバイル幅", + "accordion": "アコーディオン", + "aspect_ratio": "アスペクト比", + "auto_rotate_announcements": "自動切り替えのお知らせ", + "auto_rotate_slides": "スライドの自動切り替え", + "badge_corner_radius": "角の半径", + "badge_position": "カードでの位置", + "badge_sale_color_scheme": "セール", + "badge_sold_out_color_scheme": "売り切れ", + "behavior": "挙動", + "blur": "影のぼかし", + "border": "罫線", + "bottom": "下", + "carousel_on_mobile": "モバイル上のカルーセル", + "cart_count": "カート数", + "cart_items": "カート内のアイテム", + "cart_related_products": "関連商品", + "cart_title": "カート", + "cart_total": "カートの合計", + "cart_type": "タイプ", + "case": "ケース", + "checkout_buttons": "簡単なチェックアウトボタン", + "collection_list": "コレクション", + "collection_templates": "コレクションテンプレート", + "content": "コンテンツ", + "corner_radius": "角の半径", + "country_region": "国/地域", + "currency_code": "通貨コード", + "custom_height": "ユーザー定義の高さ", + "desktop_height": "デスクトップの高さ", + "direction": "方向", + "display": "表示", + "divider_thickness": "区切り線の太さ", + "divider": "区切り線", + "dividers": "区切り線", + "drop_shadow": "ドロップシャドウ", + "empty_state_collection_info": "検索が入力される前に表示", + "empty_state_collection": "空の状態のコレクション", + "enable_filtering": "絞り込み", + "enable_grid_density": "グリッドレイアウト制御", + "enable_sorting": "並べ替え", + "enable_zoom": "ズームを有効にする", + "equal_columns": "等幅列", + "expand_first_group": "1番目のグループを展開", + "extend_media_to_screen_edge": "メディアを画面の端まで拡張する", + "extend_summary": "画面の端まで拡張する", + "extra_large": "特大", + "extra_small": "極小", + "flag": "フラグ", + "font_price": "価格のフォント", + "font_weight": "フォントの太さ", + "font": "フォント", + "full_width_first_image": "最初の画像を全幅表示", + "full_width_on_mobile": "モバイルで全幅表示", + "heading_preset": "見出しのプリセット", + "hide_unselected_variant_media": "未選択のバリエーションメディアを非表示", + "horizontal_gap": "水平方向の間隔", + "horizontal_offset": "影の横方向のオフセット", + "hover_behavior": "カーソルを置く動作", + "icon_background": "アイコンの背景", + "icons": "アイコン", + "image_border_radius": "画像の角丸", + "installments": "分割払い", + "integrated_button": "統合ボタン", + "language_selector": "言語セレクター", + "large": "大", + "left_padding": "左の余白", + "left": "左", + "letter_spacing": "文字間隔", + "limit_product_details_width": "商品の詳細の幅を制限する", + "link_preset": "リンクのプリセット", + "links": "リンク", + "logo": "ロゴ", + "loop": "ループ", + "make_details_sticky_desktop": "デスクトップに固定表示", + "max_width": "最大幅", + "media_height": "メディアの高さ", + "media_overlay": "メディアオーバーレイ", + "media_position": "メディアの位置", + "media_type": "メディアタイプ", + "media_width": "メディアの幅", + "menu": "メニュー", + "mobile_columns": "モバイル列", + "mobile_height": "モバイルの高さ", + "mobile_logo_image": "モバイルのロゴ", + "mobile_quick_add": "モバイルのクイック追加", + "motion_direction": "モーションの方向", + "motion": "モーション", + "movement_direction": "移動方向", + "navigation_bar_color_scheme": "メニューバーの配色パターン", + "navigation_bar": "メニューバー", + "navigation": "メニュー", + "open_new_tab": "リンクを新しいタブで開く", + "overlay_color": "オーバーレイの色", + "overlay": "オーバーレイ", + "padding_bottom": "余白 (下)", + "padding_horizontal": "余白 (左右)", + "padding_top": "余白 (上)", + "page_width": "ページの幅", + "pagination": "ページネーション", + "placement": "配置", + "position": "位置", + "preset": "プリセット", + "product_cards": "商品カード", + "product_pages": "商品ページ", + "product_templates": "商品のテンプレート", + "products": "商品", + "quick_add": "クイック追加", + "ratio": "比率", + "regular": "標準", + "review_count": "レビュー数", + "right": "右", + "row_height": "行の高さ", + "row": "行", + "seller_note": "販売者へのメモを許可する", + "shape": "形状", + "show_as_accordion": "モバイルにアコーディオンとして表示", + "show_sale_price_first": "セール価格を最初に表示", + "show_tax_info": "税情報", + "show": "表示する", + "small": "小", + "speed": "速度", + "statement": "明細書", + "sticky_header": "固定表示ヘッダー", + "text_hierarchy": "テキストの階層", + "text_presets": "テキストプリセット", + "title": "タイトル", + "top": "上", + "type": "タイプ", + "type_preset": "テキストプリセット", + "underline_thickness": "下線の太さ", + "variant_images": "バリエーション画像", + "vendor": "販売元", + "vertical_gap": "垂直方向の間隔", + "vertical_offset": "影の縦方向のオフセット", + "vertical_on_mobile": "モバイルで縦画面表示", + "view_all_as_last_card": "最後のカードで「すべて表示」", + "weight": "重量", + "wrap": "折り返し", + "gradient_direction": "グラデーションの方向", + "headings": "見出し", + "overlay_style": "オーバーレイスタイル", + "read_only": "読み取り専用", + "shadow_opacity": "影の不透明度", + "show_filter_label": "適用されたフィルターのテキストラベル", + "show_swatch_label": "スウォッチのテキストラベル", + "transparent_background": "透明な背景", + "hide_logo_on_home_page": "ホームページのロゴを非表示にする", + "account": "アカウント", + "align_baseline": "テキストのBaselineをAlign", + "add_discount_code": "カートでのディスカウントを許可する", + "background_overlay": "背景オーバーレイ", + "background_media": "背景メディア", + "border_thickness": "罫線の太さ", + "bottom_row": "一番下の行", + "button_text_case": "テキストケース", + "button_text_weight": "テキストの太さ", + "auto_open_cart_drawer": "「カートに追加」すると自動的にドロワーが開きます", + "collection_count": "コレクション数", + "custom_liquid": "Liquidコード", + "default": "デフォルト", + "default_logo": "デフォルトのロゴ", + "divider_width": "区切り線の幅", + "horizontal_padding": "水平余白", + "inverse": "反転", + "inverse_logo": "逆さロゴ", + "layout_style": "スタイル", + "length": "長さ", + "mobile_pagination": "モバイルページネーション", + "open_row_by_default": "デフォルトで行を開く", + "page_transition_enabled": "ページ移行", + "search": "検索", + "search_icon": "検索アイコン", + "search_position": "位置", + "search_row": "行", + "show_author": "作成者", + "show_alignment": "配置を表示", + "show_count": "カウントを表示", + "show_date": "日付", + "show_pickup_availability": "受取の対応可否を表示する", + "show_search": "検索を表示する", + "use_inverse_logo": "逆方向のロゴを使用する", + "vertical_padding": "垂直余白", + "visibility": "公開/非公開", + "product_corner_radius": "商品の角丸の半径", + "card_corner_radius": "カードの角丸の半径", + "alignment_mobile": "モバイル配置", + "animation_repeat": "繰り返しアニメーション", + "blurred_reflection": "ぼやけた反射", + "card_hover_effect": "カードのホバー効果", + "card_size": "カードサイズ", + "collection_title_case": "コレクションタイトルの大文字・小文字設定", + "effects": "効果", + "inventory_threshold": "低在庫しきい値", + "mobile_card_size": "モバイルカードサイズ", + "page": "ページ", + "product_and_card_title_case": "商品とカードのタイトルの大文字・小文字設定", + "product_title_case": "商品名の大文字・小文字設定", + "reflection_opacity": "反射の不透明度", + "right_padding": "右の余白", + "show_inventory_quantity": "低在庫数量を表示する", + "text_label_case": "テキストラベルの大文字・小文字設定", + "transition_to_main_product": "商品カードから商品ページへの遷移", + "show_second_image_on_hover": "マウスオーバー時に2番目の画像を表示する", + "media": "メディア", + "product_card_carousel": "カルーセルを表示する", + "media_fit": "適合したメディア", + "scroll_speed": "次のお知らせにスクロール" + }, + "options": { + "adapt_to_image": "画像に合わせる", + "apple": "リンゴ", + "arrow": "矢", + "auto": "自動", + "banana": "バナナ", + "bottle": "ボトル", + "box": "ボックス", + "buttons": "ボタン", + "carrot": "ニンジン", + "center": "中央", + "chat_bubble": "チャットバブル", + "clipboard": "クリップボード", + "contain": "領域に収める", + "counter": "カウンター", + "cover": "カバー", + "custom": "カスタム", + "dairy_free": "乳製品不使用", + "dairy": "乳製品", + "default": "デフォルト", + "dropdowns": "ドロップダウン", + "dots": "ドット", + "dryer": "ドライヤー", + "end": "終了", + "eye": "目", + "facebook": "Facebook", + "fill": "塗りつぶし", + "fire": "火", + "fit": "フィット", + "full": "全体", + "full_and_page": "全背景、ページ幅のコンテンツ", + "gluten_free": "グルテン不使用", + "heading": "見出し", + "heart": "ハート", + "horizontal": "水平", + "instagram": "Instagram", + "iron": "アイロン", + "landscape": "横長", + "large": "大", + "leaf": "葉", + "leather": "革製品", + "lg": "L", + "lightning_bolt": "稲妻", + "link": "リンク", + "lipstick": "リップスティック", + "lock": "ロック", + "lowercase": "小文字", + "m": "M", + "map_pin": "マップピン", + "medium": "中", + "none": "なし", + "numbers": "数字", + "nut_free": "ナッツ類不使用", + "outline": "アウトライン", + "page": "ページ", + "pants": "パンツ", + "paw_print": "肉球プリント", + "pepper": "こしょう", + "perfume": "香水", + "pinterest": "Pinterest", + "plane": "飛行機", + "plant": "植物", + "portrait": "縦長", + "price_tag": "値札", + "question_mark": "疑問符", + "recycle": "リサイクル", + "return": "返品", + "ruler": "定規", + "s": "S", + "sentence": "文章", + "serving_dish": "取り皿", + "shirt": "シャツ", + "shoe": "靴", + "silhouette": "シルエット", + "small": "小", + "snapchat": "Snapchat", + "snowflake": "雪片", + "solid": "ソリッド", + "space_between": "感覚", + "square": "正方形", + "star": "星", + "start": "開始", + "stopwatch": "ストップウォッチ", + "tiktok": "TikTok", + "truck": "トラック", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "大文字", + "vertical": "垂直", + "vimeo": "Vimeo", + "washing": "洗濯", + "circle": "円形", + "swatches": "見本", + "full_and_page_offset_left": "全背景、ページ幅のコンテンツ、左にオフセット", + "full_and_page_offset_right": "全背景、ページ幅のコンテンツ、右にオフセット", + "offset_left": "左にオフセット", + "offset_right": "右にオフセット", + "page_center_aligned": "ページ、中央揃え", + "page_left_aligned": "ページ、左揃え", + "page_right_aligned": "ページ、右揃え", + "button": "ボタン", + "caption": "キャプション", + "h1": "見出し1", + "h2": "見出し2", + "h3": "見出し3", + "h4": "見出し4", + "h5": "見出し5", + "h6": "見出し6", + "paragraph": "段落", + "primary": "メイン", + "secondary": "サブ", + "tertiary": "第3カテゴリー", + "chevron_left": "左向き山形印", + "chevron_right": "右向き山形印", + "diamond": "ダイヤモンド", + "grid": "グリッド", + "parallelogram": "平行四辺形", + "rounded": "角丸", + "fit_content": "フィット", + "pills": "ピル型ボタン", + "heavy": "太い", + "thin": "細い", + "drawer": "ドロワー", + "preview": "プレビューする", + "text": "テキスト", + "video_uploaded": "アップロードする", + "video_external_url": "外部URL", + "up": "上", + "down": "下", + "gradient": "グラデーション", + "fixed": "固定", + "pixel": "ピクセル", + "percent": "割合", + "aspect_ratio": "アスペクト比", + "above_carousel": "カルーセルの上", + "all": "すべて", + "always": "常時", + "arrows_large": "大きな矢印", + "arrows": "矢印", + "balance": "バランス", + "bento": "Bento", + "black": "ブラック", + "bluesky": "Bluesky", + "body_large": "本文 (大)", + "body_regular": "本文 (中)", + "body_small": "本文 (小)", + "bold": "太字", + "bottom_left": "左下", + "bottom_right": "右下", + "bottom": "下", + "capitalize": "大文字にする", + "caret": "キャレット", + "carousel": "カルーセル", + "check_box": "チェックボックス", + "chevron_large": "大きな山かっこ", + "chevron": "山かっこ", + "chevrons": "山かっこ", + "classic": "クラシック", + "collection_images": "コレクションの画像", + "color": "色", + "complementary": "付属", + "dissolve": "ディゾルブ", + "dotted": "点線", + "editorial": "編集", + "extra_large": "特大", + "extra_small": "極小", + "featured_collections": "特集コレクション", + "featured_products": "注目商品", + "font_primary": "一次", + "font_secondary": "二次", + "font_tertiary": "三次", + "forward": "進む", + "full_screen": "全画面表示", + "heading_extra_large": "見出し (特大)", + "heading_extra_small": "見出し (極小)", + "heading_large": "見出し (大)", + "heading_regular": "見出し (中)", + "heading_small": "見出し (小)", + "icon": "アイコン", + "image": "画像", + "input": "入力", + "inside_carousel": "カルーセル内", + "inverse_large": "反転 (大)", + "inverse": "反転", + "large_arrows": "大きな矢印", + "large_chevrons": "大きな山かっこ", + "left": "左", + "light": "明るい", + "linkedin": "LinkedIn", + "loose": "ルーズ", + "media_first": "1番目のメディア", + "media_second": "2番目のメディア", + "modal": "モーダル", + "narrow": "狭い", + "never": "なし", + "next_to_carousel": "カルーセルの横", + "normal": "標準", + "nowrap": "折り返しなし", + "off_media": "オフメディア", + "on_media": "オンメディア", + "on_scroll_up": "スクロールアップ時", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "ピル", + "plus": "Shopify Plus", + "pretty": "きれい", + "price": "価格", + "primary_style": "一次スタイル", + "rectangle": "長方形", + "regular": "標準", + "related": "関連", + "reverse": "逆", + "rich_text": "リッチテキスト", + "right": "右", + "secondary_style": "二次スタイル", + "semibold": "やや太字", + "shaded": "網掛け", + "show_second_image": "2番目の画像を表示", + "single": "単一", + "slide_left": "左にスライド", + "slide_up": "上にスライド", + "spotify": "Spotify", + "stack": "スタック", + "text_only": "テキストのみ", + "threads": "Threads", + "thumbnails": "サムネイル", + "tight": "タイト", + "top_left": "左上", + "top_right": "右上", + "top": "上", + "two_number": "2", + "two_thirds": "2/3", + "underline": "下線", + "video": "ビデオ", + "wide": "ワイド", + "youtube": "YouTube", + "below_image": "画像の下", + "on_image": "画像上", + "accent": "アクセント", + "body": "本文", + "button_primary": "プライマリボタン", + "button_secondary": "サブボタン", + "compact": "コンパクト", + "crop_to_fit": "フィットするようにトリミング", + "hidden": "非公開", + "hint": "ヒント", + "maintain_aspect_ratio": "アスペクト比を維持する", + "off": "オフ", + "social_bluesky": "ソーシャル:Bluesky", + "social_facebook": "ソーシャル:Facebook", + "social_instagram": "ソーシャル:Instagram", + "social_linkedin": "ソーシャル:LinkedIn", + "social_pinterest": "ソーシャル:Pinterest", + "social_snapchat": "ソーシャル:Snapchat", + "social_spotify": "ソーシャル:Spotify", + "social_threads": "ソーシャル:Threads", + "social_tiktok": "ソーシャル:TikTok", + "social_tumblr": "ソーシャル:Tumblr", + "social_twitter": "ソーシャル:X (Twitter)", + "social_whatsapp": "ソーシャル:WhatsApp", + "social_vimeo": "ソーシャル:Vimeo", + "social_youtube": "ソーシャル:YouTube", + "spotlight": "Spotlight", + "standard": "標準", + "subheading": "小見出し", + "blur": "ぼかし", + "lift": "リフト", + "reveal": "表示する", + "scale": "拡大", + "subtle_zoom": "ズーム" + }, + "content": { + "advanced": "高度", + "background_image": "背景画像", + "background_video": "背景ビデオ", + "block_size": "ブロックサイズ", + "borders": "罫線", + "describe_the_video_for": "スクリーンリーダーを使用しているお客様向けにビデオの説明を記入してください。[詳しくはこちら](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "セクションのサイズ", + "slideshow_width": "スライド幅", + "typography": "タイポグラフィー", + "width_is_automatically_optimized": "幅はモバイル用に自動で最適化されます。", + "complementary_products": "付加的な商品は、Search & Discoveryアプリを使用して設定する必要があります。[詳しくはこちら](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "列はモバイル用に自動で最適化されます", + "content_width": "コンテンツ幅は、セクション幅が全幅に設定されている場合にのみ適用されます。", + "adjustments_affect_all_content": "このブロックのすべてのコンテンツに適用", + "responsive_font_sizes": "サイズはすべての画面サイズに合わせて自動的に拡大されます", + "buttons": "ボタン", + "swatches": "見本", + "variant_settings": "バリエーションの設定", + "background": "背景", + "cards_layout": "カードレイアウト", + "section_layout": "セクションレイアウト", + "mobile_size": "モバイルサイズ", + "mobile_width": "モバイルの幅", + "width": "幅", + "appearance": "外観", + "arrows": "矢印", + "body_size": "本文サイズ", + "bottom_row_appearance": "最下行の外観", + "carousel_navigation": "カルーセルメニュー", + "carousel_pagination": "カルーセルページネーション", + "copyright": "著作権", + "edit_logo_in_theme_settings": "[テーマ設定](/editor?context=theme&category=logo%20and%20favicon) ] でロゴを編集", + "edit_price_in_theme_settings": "[テーマ設定](/editor?context=theme&category=currency%20code) ] で価格フォーマットを編集", + "edit_variants_in_theme_settings": "[テーマ設定](/editor?context=theme&category=variants)] でバリエーションスタイルを編集", + "email_signups_create_customer_profiles": "登録すると [お客様プロフィール](https://help.shopify.com/manual/customers)] が追加されます", + "follow_on_shop_eligiblity": "ボタンを表示するには、Shopチャネルがインストールされ、Shop Payが有効になっている必要があります。[詳しくはこちら](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "フォント", + "grid": "グリッド", + "heading_size": "見出しサイズ", + "image": "画像", + "input": "入力", + "layout": "レイアウト", + "link": "リンク", + "link_padding": "リンクの余白", + "localization": "ローカライズ", + "logo": "ロゴ", + "margin": "マージン", + "media": "メディア", + "media_1": "メディア 1", + "media_2": "メディア 2", + "menu": "メニュー", + "mobile_layout": "モバイルのレイアウト", + "padding": "余白", + "padding_desktop": "デスクトップの余白", + "paragraph": "段落", + "policies": "ポリシー", + "popup": "ポップアップ", + "search": "検索", + "size": "サイズ", + "social_media": "SNS", + "submit_button": "送信ボタン", + "text_presets": "テキストプリセット", + "transparent_background": "透明な背景", + "typography_primary": "一次タイポグラフィ", + "typography_secondary": "二次タイポグラフィ", + "typography_tertiary": "三次タイポグラフィ", + "visibility": "公開/非公開", + "carousel": "カルーセル", + "colors": "色", + "collection_page": "コレクションページ", + "copyright_info": "[著作権声明を編集する]方法を学ぶ](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "お客様アカウント", + "edit_empty_state_collection_in_theme_settings": "[テーマ設定]で空の状態コレクションを編集する](/editor?context=theme&category=search)", + "home_page": "ホームページ", + "images": "画像", + "inverse_logo_info": "透明なヘッダーの背景が [反転] に設定されている場合に使用されます", + "manage_customer_accounts": "[お客様アカウント設定で可視性を管理します](/admin/settings/customer_accounts)。レガシーアカウントはサポートされていません。", + "manage_policies": "[ポリシーを管理](/admin/settings/legal)", + "product_page": "商品ページ", + "text": "テキスト", + "thumbnails": "サムネイル", + "visible_if_collection_has_more_products": "コレクションに表示されているよりも多くの商品がある場合に表示されます", + "grid_layout": "グリッドレイアウト", + "app_required_for_ratings": "商品評価にはアプリが必要です。[詳しくはこちら](https://help.shopify.com/manual/apps)", + "icon": "アイコン", + "manage_store_name": "[ストア名の管理](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "親セクションのコレクションを表示する", + "resource_reference_collection_card_image": "親コレクションの画像を表示する", + "resource_reference_collection_title": "親コレクションのタイトルを表示する", + "resource_reference_product": "親商品に自動接続する", + "resource_reference_product_card": "親セクションの商品を表示する", + "resource_reference_product_inventory": "親商品の在庫を表示する", + "resource_reference_product_price": "親商品の価格を表示する", + "resource_reference_product_recommendations": "親商品に基づく推奨事項を表示する", + "resource_reference_product_review": "親商品のレビューを表示する", + "resource_reference_product_swatches": "親商品の見本を表示する", + "resource_reference_product_title": "親商品のタイトルを表示する", + "resource_reference_product_variant_picker": "親商品のバリエーションを表示する", + "resource_reference_product_media": "親商品のメディアを表示", + "product_media": "商品メディア", + "section_link": "セクションリンク" + }, + "html_defaults": { + "share_information_about_your": "

ブランドに関する情報をお客様と共有します。商品を説明したり、告知をしたり、ストアへのお客様を歓迎したりします。

" + }, + "text_defaults": { + "button_label": "今すぐ購入", + "collapsible_row": "折りたたみ可能な行", + "heading": "見出し", + "email_signup_button_label": "登録", + "accordion_heading": "アコーディオンの見出し", + "contact_form_button_label": "送信する", + "popup_link": "ポップアップリンク", + "sign_up": "サインアップ", + "welcome_to_our_store": "ストアへようこそ", + "be_bold": "太字にします。", + "shop_our_latest_arrivals": "最新の商品を購入しましょう!" + }, + "info": { + "video_alt_text": "支援技術ユーザー向けのビデオを説明する", + "video_autoplay": "動画はデフォルトでミュートされます", + "video_external": "YouTubeやVimeoのURLを使う", + "carousel_layout_on_mobile": "カルーセルはモバイルで使用します", + "link_info": "任意:アイコンをクリックできるようになります", + "carousel_hover_behavior_not_supported": "「Carousel」タイプがセクションレベルで選択されている場合、「Carousel」ホバーは使用できません", + "grid_layout_on_mobile": "モバイルではグリッドレイアウトが使用されます", + "logo_font": "ロゴが選択されていない場合にのみ適用されます", + "checkout_buttons": "購入者はより迅速にチェックアウトでき、コンバージョンが改善されます。[詳しくはこちら](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "カスタムヘッダー", + "edit_presets_in_theme_settings": "[テーマ設定](/editor?context=theme&category=typography)] でプリセットを編集", + "enable_filtering_info": "[Search & Discoveryアプリ](https://help.shopify.com/manual/online-store/search-and-discovery/filters) ] で絞り込みをカスタマイズ", + "manage_countries_regions": "[国/地域を管理](/admin/settings/markets)", + "manage_languages": "[言語を管理](/admin/settings/languages)", + "transparent_background": "読みやすいように透明な背景が適用された各テンプレートを確認します", + "aspect_ratio_adjusted": "一部レイアウトを調整しました", + "auto_open_cart_drawer": "有効にすると、商品がカートに追加されたときにカートドロワーが自動的に開きます。", + "custom_liquid": "アプリのスニペットやその他のコードを追加して、高度なカスタマイズを作成します。[詳しくはこちら](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "画像にのみ適用する", + "hover_effects": "商品およびコレクションカードに適用する", + "pills_usage": "適用されたフィルター、割引コード、検索候補に使用されます" + }, + "categories": { + "product_list": "注目のコレクション", + "basic": "Basic Shopify", + "collection": "コレクション", + "collection_list": "コレクションリスト", + "footer": "フッター", + "forms": "フォーム", + "header": "ヘッダー", + "layout": "レイアウト", + "links": "リンク", + "product": "商品", + "banners": "バナー", + "collections": "コレクション", + "custom": "カスタム", + "decorative": "装飾体", + "products": "商品", + "other_sections": "その他", + "storytelling": "ストーリーテリング" + } +} diff --git a/locales/ko.json b/locales/ko.json new file mode 100644 index 000000000..8edfd9339 --- /dev/null +++ b/locales/ko.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "동영상 로드: {{ description }}", + "sold_out": "품절", + "email_signup": { + "label": "이메일", + "placeholder": "이메일 주소", + "success": "가입해 주셔서 감사합니다!" + }, + "filter": "필터", + "payment_methods": "결제 방법", + "contact_form": { + "name": "이름", + "email": "이메일", + "phone": "전화", + "comment": "댓글", + "post_success": "문의해 주셔서 감사합니다. 최대한 빨리 답변드리겠습니다.", + "error_heading": "다음을 조정하세요." + } + }, + "accessibility": { + "play_model": "3D 모델 재생", + "play_video": "동영상 재생", + "unit_price": "단가", + "country_results_count": "결과 {{ count }}개", + "slideshow_pause": "슬라이드 쇼 멈춤", + "slideshow_play": "슬라이드 쇼 재생", + "remove_item": "{{ title}} 제거", + "skip_to_text": "콘텐츠로 건너뛰기", + "skip_to_product_info": "제품 정보로 건너뛰기", + "skip_to_results_list": "결과 목록으로 건너뛰기", + "new_window": "새 창에서 열립니다.", + "slideshow_next": "다음 슬라이드", + "slideshow_previous": "이전 슬라이드", + "close_dialog": "대화 상자 닫기", + "reset_search": "검색 재설정", + "search_results_count": "\"{{ query }}\" 검색 결과 {{ count }}건", + "search_results_no_results": "\"{{ query }}\" 검색 결과 없음", + "filters": "필터", + "filter_count": { + "one": "{{ count }}개 필터 적용됨", + "other": "{{ count }}개 필터 적용됨" + }, + "account": "계정 메뉴 열기", + "cart": "카트", + "cart_count": "카트에 있는 총 품목 수", + "menu": "메뉴", + "country_region": "국가/지역", + "slide_status": "{{ index }}/{{ length }}번째 슬라이드", + "scroll_to": "{{ title }}(으)로 스크롤", + "loading_product_recommendations": "제품 추천 로드 중", + "discount": "할인 코드 적용", + "discount_applied": "적용된 할인 코드: {{ code }}", + "open_cart_drawer": "카트 열기", + "pause_video": "동영상 일시 중지", + "inventory_status": "재고 상태", + "find_country": "국가 찾기", + "localization_region_and_language": "지역 및 언어 선택기 열기", + "open_search_modal": "검색 열기", + "decrease_quantity": "수량 감소", + "increase_quantity": "수량 증가", + "quantity": "수량", + "rating": "이 제품의 평점은 5점 만점에 {{ rating }}점입니다", + "nested_product": "{{ parent_title }}용 {{ product_title }}" + }, + "actions": { + "add_to_cart": "카트에 추가", + "clear_all": "모두 지우기", + "remove": "제거", + "view_in_your_space": "사용자 공간에서 보기", + "show_filters": "필터", + "clear": "지우기", + "continue_shopping": "쇼핑 계속하기", + "log_in_html": "계정이 있으십니까? 더 빠르게 결제하려면 로그인하십시오.", + "see_items": { + "one": "{{ count }}개 품목 보기", + "other": "{{ count }}개 품목 보기" + }, + "view_all": "모두 보기", + "add": "추가", + "choose": "선택", + "added": "추가됨", + "show_less": "간단히 표시", + "show_more": "자세히 표시", + "close": "닫기", + "more": "자세히", + "reset": "재설정", + "zoom": "확대/축소", + "close_dialog": "대화 상자 닫기", + "enter_using_password": "비밀번호를 사용하여 입장", + "submit": "제출", + "enter_password": "비밀번호 입력", + "remove_discount": "할인 {{ code }} 제거", + "view_store_information": "스토어 정보 보기", + "back": "뒤로", + "log_in": "로그인", + "log_out": "로그아웃", + "apply": "적용", + "open_image_in_full_screen": "전체 화면으로 이미지 열기", + "sign_in_options": "기타 로그인 옵션", + "sign_up": "가입하기", + "sort": "정렬", + "show_all_options": "모든 옵션 보기" + }, + "content": { + "reviews": "리뷰", + "language": "언어", + "localization_region_and_language": "지역 및 언어", + "no_results_found": "결과 없음", + "cart_total": "카트 총계", + "your_cart_is_empty": "카트가 비어 있습니다", + "product_image": "제품 이미지", + "product_information": "제품 정보", + "quantity": "수량", + "product_total": "제품 총계", + "cart_estimated_total": "예상 총액", + "seller_note": "특별 지침", + "cart_subtotal": "소계", + "discounts": "할인", + "discount": "할인", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "관세 및 세금이 포함된 가격입니다. 결제 시 할인 및 배송료가 계산됩니다.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "관세 및 세금이 포함된 가격입니다. 결제 시 할인 및 배송료가 계산됩니다.", + "taxes_included_shipping_at_checkout_with_policy_html": "세금이 포함된 가격입니다. 결제 시 할인 및 배송료가 계산됩니다.", + "taxes_included_shipping_at_checkout_without_policy": "세금이 포함된 가격입니다. 결제 시 할인 및 배송료가 계산됩니다.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "관세가 포함된 가격입니다. 결제 시 세금, 할인 및 배송료가 계산됩니다.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "관세가 포함된 가격입니다. 결제 시 세금, 할인 및 배송료가 계산됩니다.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "결제 시 세금, 할인 및 배송료가 계산됩니다.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "결제 시 세금, 할인 및 배송료가 계산됩니다.", + "checkout": "결제", + "cart_title": "카트", + "price": "가격", + "price_regular": "정가", + "price_compare_at": "가격 비교", + "price_sale": "할인가", + "duties_and_taxes_included": "관세 및 세금이 포함된 가격입니다.", + "duties_included": "관세가 포함된 가격입니다.", + "shipping_policy_html": "배송료는 결제 시 계산됩니다.", + "taxes_included": "세금이 포함된 가격입니다.", + "product_badge_sold_out": "품절", + "product_badge_sale": "판매", + "search_input_label": "검색", + "search_input_placeholder": "검색", + "search_results": "검색 결과", + "search_results_label": "검색 결과", + "search_results_no_results": "\"{{ terms }}\"에 대한 검색 결과가 없습니다. 다시 검색해 보세요", + "search_results_resource_articles": "블로그 게시물", + "search_results_resource_collections": "컬렉션", + "search_results_resource_pages": "페이지", + "search_results_resource_products": "제품", + "search_results_resource_queries": "검색 제안", + "search_results_view_all": "모두 보기", + "search_results_view_all_button": "모두 보기", + "search_results_resource_products_count": { + "one": "제품 {{ count }}개", + "other": "제품 {{ count }}개" + }, + "grid_view": { + "default_view": "기본", + "grid_fieldset": "열 그리드", + "single_item": "단일", + "zoom_out": "축소" + }, + "recently_viewed_products": "최근에 본 항목", + "unavailable": "사용할 수 없음", + "collection_placeholder": "컬렉션 제목", + "product_card_placeholder": "제품 이름", + "product_count": "제품 수", + "item_count": { + "one": "{{ count }}개 품목", + "other": "{{ count }}개 품목" + }, + "errors": "오류", + "search": "검색", + "search_results_no_results_check_spelling": "\"{{ terms }}\"에 대한 검색 결과가 없습니다. 철자를 확인하거나 다른 단어 또는 문구를 사용해 보세요.", + "filters": "필터", + "no_products_found": "제품을 찾을 수 없습니다.", + "price_from": "{{ price }}부터", + "price_filter_html": "최고가는 {{ price }}입니다", + "use_fewer_filters_html": "필터 수를 줄여보거나 모든 필터를 지워보세요.", + "featured_products": "추천 제품", + "blog_details_separator": "|", + "read_more": "자세히 보기", + "wrong_password": "잘못된 비밀번호", + "discount_code": "할인 코드", + "pickup_available_at_html": "{{ location }}에서 픽업 가능", + "pickup_available_in": "{{ pickup_time }}에 픽업 가능", + "pickup_not_available": "현재 픽업 사용 불가", + "pickup_ready_in": "{{ pickup_time }}", + "account_title": "계정", + "account_title_personalized": "{{ first_name }} 님, 안녕하세요.", + "account_orders": "주문", + "account_profile": "프로필", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "관세 및 세금이 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "관세 및 세금이 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "관세가 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "관세가 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "세금 및 배송료는 결제 시 계산됩니다.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "세금 및 배송료는 결제 시 계산됩니다.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "세금이 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "세금이 포함된 가격입니다. 배송료는 결제 시 계산됩니다.", + "view_more_details": "더 많은 세부 정보 보기", + "powered_by": "상점 제공:", + "store_owner_link_html": "스토어 소유자이신가요? 여기에서 로그인하세요.", + "shipping_discount_error": "배송 요금 할인은 결제 단계에서 주소를 추가한 후에 표시됩니다.", + "discount_code_error": "카트에 할인 코드를 적용할 수 없습니다", + "inventory_low_stock": "재고 부족", + "inventory_in_stock": "재고 있음", + "inventory_out_of_stock": "품절", + "page_placeholder_title": "페이지 제목", + "page_placeholder_content": "해당 콘텐츠를 표시할 페이지를 선택합니다.", + "placeholder_image": "플레이스 홀더 이미지", + "shipping_policy": "결제 시 배송료 계산됨.", + "inventory_low_stock_show_count": { + "one": "{{ count }}개 남음", + "other": "{{ count }}개 남음" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "온라인 기프트 카드 코드 또는 매장 내 QR 코드 사용", + "title": "다음은 {{ shop }}의 {{ value }} 기프트 카드 잔액입니다.", + "subtext": "기프트 카드", + "shop_link": "온라인 스토어 방문", + "add_to_apple_wallet": "Apple Wallet에 추가", + "qr_image_alt": "QR 코드 — 스캔하여 기프트 카드 사용", + "copy_code": "기프트 카드 코드 복사", + "expiration_date": "만료: {{ expires_on }}", + "copy_code_success": "코드 복사 완료", + "expired": "만료됨" + } + }, + "placeholders": { + "password": "비밀번호", + "search": "검색", + "product_title": "제품명", + "collection_title": "컬렉션 제목" + }, + "products": { + "product": { + "add_to_cart": "카트에 추가", + "added_to_cart": "카트에 추가됨", + "adding_to_cart": "추가 중...", + "add_to_cart_error": "카트에 추가하는 중 오류 발생", + "sold_out": "품절", + "unavailable": "사용할 수 없음" + } + }, + "fields": { + "separator": "~" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "댓글 {{ count }}개", + "other": "댓글 {{ count }}개" + } + }, + "comment_form": { + "email": "이메일", + "error": "댓글을 게시하지 못했습니다. 다음 사항을 해결해 주세요.", + "heading": "댓글 남기기", + "message": "메시지", + "moderated": "댓글을 게시하려면 먼저 승인을 받아야 합니다.", + "name": "이름", + "post": "댓글 달기", + "success_moderated": "댓글이 게시되었습니다. 조정 대기 중입니다", + "success": "댓글 게시됨" + } + } +} diff --git a/locales/ko.schema.json b/locales/ko.schema.json new file mode 100644 index 000000000..94a7c9ae6 --- /dev/null +++ b/locales/ko.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "테두리", + "collapsible_row": "축소 가능한 행", + "custom_section": "사용자 지정 섹션", + "icon": "아이콘", + "logo_and_favicon": "로고 및 Favicon", + "product_buy_buttons": "구매 버튼", + "product_description": "설명", + "product_price": "가격", + "slideshow": "슬라이드 쇼", + "typography": "입력 체계", + "video": "동영상", + "colors": "색상", + "overlapping_blocks": "겹치는 블록", + "product_variant_picker": "이형 상품 피커", + "slideshow_controls": "슬라이드 쇼 제어", + "size": "사이즈", + "spacing": "간격", + "product_recommendations": "추천 제품", + "product_media": "제품 미디어", + "featured_collection": "추천 컬렉션", + "add_to_cart": "카트에 추가", + "email_signup": "이메일 가입", + "submit_button": "제출 버튼", + "grid_layout_selector": "그리드 레이아웃 선택기", + "image": "이미지", + "list_items": "목록 항목", + "facets": "패싯", + "variants": "이형 상품", + "styles": "스타일", + "product_cards": "제품 카드", + "buttons": "버튼", + "inputs": "입력", + "primary_button": "기본 버튼", + "secondary_button": "보조 버튼", + "popovers": "팝오버", + "marquee": "움직이는 텍스트", + "pull_quote": "풀 인용문", + "contact_form": "연락처 양식", + "featured_product": "제품 주요 특성", + "icons_with_text": "텍스트 포함 아이콘", + "alternating_content_rows": "대체 행", + "accelerated_checkout": "빠른 결제", + "accordion": "아코디언", + "accordion_row": "아코디언 행", + "animations": "애니메이션", + "announcement": "공지", + "announcement_bar": "공지 표시줄", + "badges": "배지", + "button": "버튼", + "cart": "카트", + "cart_items": "카트 품목", + "cart_products": "카트 제품", + "cart_title": "카트", + "collection": "컬렉션", + "collection_card": "컬렉션 카드", + "collection_columns": "컬렉션 열", + "collection_container": "컬렉션", + "collection_description": "컬렉션 설명", + "collection_image": "컬렉션 이미지", + "collection_info": "컬렉션 정보", + "collection_list": "컬렉션 목록", + "collections": "컬렉션", + "content": "콘텐츠", + "content_grid": "콘텐츠 그리드", + "details": "세부 정보", + "divider": "구분선", + "filters": "필터 및 정렬", + "follow_on_shop": "Shop에서 팔로우", + "footer": "바닥글", + "footer_utilities": "바닥글 유틸리티", + "group": "그룹", + "header": "머리글", + "heading": "제목", + "icons": "아이콘", + "image_with_text": "텍스트 포함 이미지", + "input": "입력", + "logo": "로고", + "magazine_grid": "잡지 그리드", + "media": "미디어", + "menu": "메뉴", + "mobile_layout": "모바일 레이아웃", + "payment_icons": "결제 아이콘", + "popup_link": "팝업 링크", + "predictive_search": "검색 팝오버", + "predictive_search_empty": "예측 검색 비어 있음", + "price": "가격", + "product": "제품", + "product_card": "제품 카드", + "product_card_media": "미디어", + "product_card_rendering": "제품 카드 렌더링", + "product_grid": "그리드", + "product_grid_main": "제품 그리드", + "product_image": "제품 이미지", + "product_information": "제품 정보", + "product_review_stars": "리뷰 별점", + "quantity": "수량", + "row": "행", + "search": "검색", + "section": "섹션", + "selected_variants": "선택한 이형 상품", + "shop_the_look": "Shop 외관", + "slide": "슬라이드", + "social_media_links": "소셜 미디어 링크", + "steps": "단계", + "summary": "요약", + "swatches": "견본", + "testimonials": "추천", + "text": "텍스트", + "title": "제목", + "utilities": "유틸리티", + "search_input": "입력 검색", + "search_results": "검색 결과", + "read_only": "읽기 전용", + "collection_title": "컬렉션 제목", + "collections_bento": "컬렉션 목록: Bento", + "faq_section": "FAQ", + "hero": "히어로", + "jumbo_text": "대형 텍스트", + "product_list": "추천 컬렉션", + "spacer": "스페이서", + "view_all_button": "모두 보기", + "video_section": "동영상", + "blog": "블로그", + "blog_posts": "블로그 게시물", + "custom_liquid": "사용자 지정 Liquid", + "blog_post": "블로그 게시물", + "caption": "캡션", + "collection_card_image": "이미지", + "collection_links": "컬렉션 링크", + "collection_links_spotlight": "컬렉션 링크: 스포트라이트", + "collection_links_text": "컬렉션 링크: 텍스트", + "collections_carousel": "컬렉션 목록: 캐러셀", + "collections_editorial": "컬렉션 목록: 편집", + "collections_grid": "컬렉션 목록: 그리드", + "copyright": "저작권", + "count": "개수", + "divider_section": "구분선", + "drawers": "펼침 메뉴", + "editorial": "편집", + "editorial_jumbo_text": "편집: 점보 텍스트", + "hero_marquee": "히어로: 움직이는 텍스트", + "input_fields": "입력 필드", + "local_pickup": "지역 픽업", + "marquee_section": "움직이는 텍스트", + "media_with_text": "텍스트가 있는 미디어", + "page": "페이지", + "page_content": "콘텐츠", + "page_layout": "페이지 레이아웃", + "policy_list": "정책 링크", + "prices": "가격", + "products_carousel": "추천 컬렉션: 캐러셀", + "products_editorial": "추천 컬렉션: 에디토리얼", + "products_grid": "추천 컬렉션: 그리드", + "social_link": "소셜 링크", + "split_showcase": "분할 쇼케이스", + "variant_pickers": "이형 상품 피커", + "product_title": "제품 이름", + "large_logo": "큰 로고", + "product_list_button": "모두 보기 버튼", + "product_inventory": "제품 재고", + "pills": "타원형", + "description": "설명" + }, + "settings": { + "autoplay": "자동 재생", + "background": "배경", + "border_radius": "코너 반경", + "border_width": "테두리 두께", + "borders": "테두리", + "bottom_padding": "하단 패딩", + "color": "색상", + "content_direction": "콘텐츠 방향", + "content_position": "콘텐츠 위치", + "cover_image_size": "커버 이미지 크기", + "cover_image": "커버 이미지", + "custom_width": "사용자 지정 폭", + "enable_video_looping": "동영상 루프", + "favicon": "Favicon", + "heading": "제목", + "icon": "아이콘", + "image_icon": "이미지 아이콘", + "make_section_full_width": "섹션을 전체 폭 사용", + "overlay_opacity": "오버레이 불투명도", + "padding": "패딩", + "product": "제품", + "text": "텍스트", + "top_padding": "상단 패딩", + "video": "동영상", + "video_alt_text": "대체 텍스트", + "video_loop": "루프 동영상", + "video_position": "동영상 위치", + "width": "너비", + "alignment": "정렬", + "button": "버튼", + "colors": "색상", + "content_alignment": "콘텐츠 정렬", + "custom_minimum_height": "사용자 지정 최소 높이", + "font_family": "글꼴 집합", + "gap": "간격", + "geometric_translate_y": "Geometric translate Y", + "image": "이미지", + "image_opacity": "이미지 불투명도", + "image_position": "이미지 위치", + "image_ratio": "이미지 비율", + "label": "레이블", + "line_height": "라인 높이", + "link": "링크", + "layout_gap": "레이아웃 간격", + "minimum_height": "최소 높이", + "opacity": "불투명도", + "primary_color": "링크", + "section_width": "섹션 폭", + "size": "사이즈", + "slide_spacing": "슬라이드 간격", + "slide_width": "슬라이드 너비", + "slideshow_fullwidth": "전체 슬라이드 너비", + "style": "스타일", + "text_case": "케이스", + "z_index": "Z-색인", + "limit_content_width": "콘텐츠 너비 제한", + "color_scheme": "색상 배합", + "inherit_color_scheme": "색상 배합 상속", + "product_count": "제품 수", + "product_type": "제품 유형", + "content_width": "콘텐츠 너비", + "collection": "컬렉션", + "enable_sticky_content": "데스크톱에서 콘텐츠 고정", + "error_color": "오류", + "success_color": "성공", + "primary_font": "기본 글꼴", + "secondary_font": "보조 글꼴", + "tertiary_font": "3차 글꼴", + "columns": "열", + "items_to_show": "표시할 항목", + "layout": "레이아웃", + "layout_type": "유형", + "show_grid_layout_selector": "그리드 레이아웃 선택기 표시", + "view_more_show": "자세히 보기 버튼 표시", + "image_gap": "이미지 간격", + "width_desktop": "데스크톱 너비", + "width_mobile": "모바일 너비", + "border_style": "테두리 스타일", + "height": "높이", + "thickness": "두께", + "stroke": "획", + "filter_style": "필터 스타일", + "swatches": "견본", + "quick_add_colors": "색상 빠른 추가", + "divider_color": "구분선", + "border_opacity": "테두리 투명도", + "hover_background": "호버 시 배경", + "hover_borders": "호버 시 테두리", + "hover_text": "호버 시 텍스트", + "primary_hover_color": "호버 링크", + "primary_button_text": "기본 버튼 텍스트", + "primary_button_background": "기본 버튼 배경", + "primary_button_border": "기본 버튼 테두리", + "secondary_button_text": "보조 버튼 텍스트", + "secondary_button_background": "보조 버튼 배경", + "secondary_button_border": "보조 버튼 테두리", + "shadow_color": "그림자", + "video_autoplay": "자동 재생", + "video_cover_image": "커버 이미지", + "video_external_url": "URL", + "video_source": "소스", + "first_row_media_position": "1행 미디어 위치", + "accordion": "아코디언", + "aspect_ratio": "가로 세로 비율", + "auto_rotate_announcements": "공지 사항 자동 회전", + "auto_rotate_slides": "슬라이드 자동 회전", + "badge_corner_radius": "코너 반경", + "badge_position": "카드에서의 위치", + "badge_sale_color_scheme": "판매", + "badge_sold_out_color_scheme": "품절", + "behavior": "동작", + "blur": "그림자 흐림", + "border": "테두리", + "bottom": "아래쪽", + "card_image_height": "제품 이미지 높이", + "carousel_on_mobile": "모바일에서의 캐러셀", + "cart_count": "카트 수", + "cart_items": "카트 품목", + "cart_related_products": "관련 제품", + "cart_title": "카트", + "cart_total": "카트 총계", + "cart_type": "유형", + "case": "케이스", + "checkout_buttons": "빠른 결제 버튼", + "collection_list": "컬렉션", + "collection_templates": "컬렉션 템플릿", + "content": "콘텐츠", + "corner_radius": "코너 반경", + "country_region": "국가/지역", + "currency_code": "통화 코드", + "custom_height": "사용자 지정 높이", + "desktop_height": "데스크톱 높이", + "direction": "방향", + "display": "표시", + "divider_thickness": "구분선 두께", + "divider": "구분선", + "dividers": "구분선", + "drop_shadow": "그림자 드롭", + "empty_state_collection_info": "검색어 입력 전에 표시", + "empty_state_collection": "빈 상태 컬렉션", + "enable_filtering": "필터", + "enable_grid_density": "그리드 레이아웃 컨트롤", + "enable_sorting": "정렬", + "enable_zoom": "확대/축소 사용", + "equal_columns": "동일한 열", + "expand_first_group": "첫 번째 그룹 확장", + "extend_media_to_screen_edge": "미디어를 화면 가장자리까지 확장", + "extend_summary": "화면 가장자리까지 확장", + "extra_large": "아주 크게", + "extra_small": "아주 작게", + "flag": "플래그", + "font_price": "가격 글꼴", + "font_weight": "글꼴 굵기", + "font": "글꼴", + "full_width_first_image": "전체 너비 첫 번째 이미지", + "full_width_on_mobile": "모바일에서 전체 너비로 표시", + "heading_preset": "제목 사전 설정", + "hide_unselected_variant_media": "선택하지 않은 이형 상품의 미디어 숨기기", + "horizontal_gap": "수평 간격", + "horizontal_offset": "그림자 가로 오프셋", + "hover_behavior": "호버 동작", + "icon_background": "아이콘 배경", + "icons": "아이콘", + "image_border_radius": "이미지 코너 반경", + "installments": "할부", + "integrated_button": "통합 버튼", + "language_selector": "언어 선택기", + "large": "크게", + "left_padding": "왼쪽 패딩", + "left": "왼쪽", + "letter_spacing": "문자 간격", + "limit_media_to_screen_height": "화면 높이로 제한", + "limit_product_details_width": "제품 세부 정보 너비 제한", + "link_preset": "링크 사전 설정", + "links": "링크", + "logo": "로고", + "loop": "루프", + "make_details_sticky_desktop": "데스크톱에서 고정", + "max_width": "최대 너비", + "media_height": "미디어 높이", + "media_overlay": "미디어 오버레이", + "media_position": "미디어 위치", + "media_type": "미디어 유형", + "media_width": "미디어 너비", + "menu": "메뉴", + "mobile_columns": "모바일 열", + "mobile_height": "모바일 높이", + "mobile_logo_image": "모바일 로고", + "mobile_quick_add": "모바일 빠른 추가", + "motion_direction": "모션 방향", + "motion": "모션", + "movement_direction": "이동 방향", + "navigation_bar_color_scheme": "탐색 바 색상 배합", + "navigation_bar": "탐색 바", + "navigation": "탐색", + "open_new_tab": "새 탭에서 링크 열기", + "overlay_color": "오버레이 색상", + "overlay": "오버레이", + "padding_bottom": "아래쪽 패딩", + "padding_horizontal": "가로 패딩", + "padding_top": "위쪽 패딩", + "page_width": "페이지 너비", + "pagination": "페이지 매김", + "placement": "배치", + "position": "위치", + "preset": "사전 설정", + "product_cards": "제품 카드", + "product_pages": "제품 페이지", + "product_templates": "제품 템플릿", + "products": "제품", + "quick_add": "빠른 추가", + "ratio": "비율", + "regular": "일반", + "review_count": "리뷰 수", + "right": "오른쪽", + "row_height": "행 높이", + "row": "행", + "seller_note": "판매자에게 메모 허용", + "shape": "모양", + "show_as_accordion": "모바일에서 아코디언 표시", + "show_sale_price_first": "할인가 먼저 표시", + "show_tax_info": "세금 정보", + "show": "표시", + "small": "작게", + "speed": "속도", + "statement": "명세서", + "sticky_header": "고정 머리글", + "text_hierarchy": "텍스트 계층", + "text_presets": "텍스트 사전 설정", + "title": "제목", + "top": "위쪽", + "type": "유형", + "type_preset": "텍스트 사전 설정", + "underline_thickness": "굵은 밑줄 표시", + "variant_images": "이형 상품 이미지", + "vendor": "공급업체", + "vertical_gap": "수직 간격", + "vertical_offset": "그림자 세로 오프셋", + "vertical_on_mobile": "모바일에서 세로로 표시", + "view_all_as_last_card": "마지막 카드로 \"모두 보기\"", + "weight": "중량", + "wrap": "줄바꿈", + "read_only": "읽기 전용", + "always_stack_buttons": "항상 버튼 중첩", + "background_color": "배경 색상", + "custom_mobile_size": "사용자 지정 모바일 크기", + "custom_mobile_width": "사용자 지정 모바일 너비", + "fixed_height": "픽셀 높이", + "fixed_width": "픽셀 너비", + "gradient_direction": "그라데이션 방향", + "hide_padding": "패딩 숨기기", + "logo_font": "로고 글꼴", + "overlay_style": "오버레이 스타일", + "percent_height": "일정 비율 높이", + "percent_size_mobile": "일정 비율 크기", + "percent_size": "일정 비율 크기", + "percent_width": "일정 비율 너비", + "pixel_size_mobile": "픽셀 크기", + "pixel_size": "픽셀 크기", + "shadow_opacity": "그림자 불투명도", + "show_filter_label": "적용된 필터의 텍스트 레이블", + "show_swatch_label": "견본의 텍스트 레이블", + "size_mobile": "모바일 크기", + "transparent_background": "투명한 배경", + "unit": "단위", + "hide_logo_on_home_page": "홈페이지 로고 숨기기", + "account": "계정", + "align_baseline": "텍스트 기준선 맞춤", + "add_discount_code": "카트에 할인 허용", + "background_overlay": "배경 오버레이", + "background_media": "배경 미디어", + "border_thickness": "테두리 두께", + "bottom_row": "아래쪽 행", + "button_text_case": "텍스트 케이스", + "button_text_weight": "텍스트 두께", + "auto_open_cart_drawer": "'카트에 추가'로 서랍 자동 열기", + "collection_count": "컬렉션 수", + "custom_liquid": "Liquid 코드", + "default": "기본", + "default_logo": "기본 로고", + "divider_width": "구분선 폭", + "headings": "제목", + "horizontal_padding": "수평 패딩", + "inverse": "서로 바꾸기", + "inverse_logo": "서로 바꾸기 로고", + "layout_style": "스타일", + "length": "길이", + "mobile_pagination": "모바일 페이지 매김", + "open_row_by_default": "기본적으로 행 열기", + "page_transition_enabled": "페이지 전환", + "search": "검색", + "search_icon": "검색 아이콘", + "search_position": "위치", + "search_row": "행", + "show_author": "작성자", + "show_alignment": "정렬 표시", + "show_count": "개수 표시", + "show_date": "날짜", + "show_pickup_availability": "픽업 사용 가능성 표시", + "show_search": "검색 표시", + "use_inverse_logo": "서로 바꾸기 로고 사용", + "vertical_padding": "수직 패딩", + "visibility": "표시 유형", + "product_corner_radius": "제품 코너 반경", + "card_corner_radius": "카드 코너 반경", + "alignment_mobile": "모바일 정렬", + "animation_repeat": "애니메이션 반복", + "blurred_reflection": "흐려진 반사", + "card_hover_effect": "카드 호버 효과", + "card_size": "카드 크기", + "collection_title_case": "컬렉션 제목 케이스", + "effects": "효과", + "inventory_threshold": "재고 부족 임계값", + "mobile_card_size": "모바일 카드 크기", + "page": "페이지", + "product_and_card_title_case": "제품 및 카드 제목 케이스", + "product_title_case": "제품 제목 케이스", + "reflection_opacity": "반사 불투명도", + "right_padding": "오른쪽 패딩", + "show_inventory_quantity": "재고 수량 부족 표시", + "text_label_case": "텍스트 레이블 케이스", + "transition_to_main_product": "제품 카드에서 제품 페이지로의 전환", + "show_second_image_on_hover": "마우스를 올리면 보조 이미지 표시", + "media": "미디어", + "product_card_carousel": "캐러셀 표시", + "media_fit": "미디어 맞춤", + "scroll_speed": "다음 공지사항으로 스크롤" + }, + "options": { + "adapt_to_image": "이미지에 맞춤", + "apple": "사과", + "arrow": "화살표", + "banana": "바나나", + "bottle": "병", + "box": "상자", + "buttons": "버튼", + "carrot": "당근", + "center": "가운데", + "chat_bubble": "채팅 말풍선", + "clipboard": "클립보드", + "contain": "포함", + "counter": "카운터", + "cover": "커버", + "custom": "사용자 지정", + "dairy_free": "유제품 무첨가", + "dairy": "유제품", + "dropdowns": "드롭다운", + "dots": "점", + "dryer": "드라이어", + "end": "종료", + "eye": "눈", + "facebook": "Facebook", + "fire": "불", + "gluten_free": "글루텐 프리", + "heart": "하트", + "horizontal": "수평", + "instagram": "Instagram", + "iron": "강철", + "large": "라지", + "leaf": "나뭇잎", + "leather": "가죽", + "lightning_bolt": "번개", + "lipstick": "립스틱", + "lock": "자물쇠", + "map_pin": "지도 핀", + "medium": "미디움", + "none": "없음", + "numbers": "번호", + "nut_free": "너트 프리", + "pants": "바지", + "paw_print": "발자국", + "pepper": "후추", + "perfume": "향수", + "pinterest": "Pinterest", + "plane": "비행기", + "plant": "식물", + "price_tag": "가격표", + "question_mark": "물음표", + "recycle": "재활용", + "return": "반품", + "ruler": "자", + "serving_dish": "서빙용 접시", + "shirt": "셔츠", + "shoe": "신발", + "silhouette": "실루엣", + "small": "스몰", + "snapchat": "Snapchat", + "snowflake": "스노우플레이크", + "star": "별", + "start": "시작", + "stopwatch": "스톱워치", + "tiktok": "TikTok", + "truck": "트럭", + "tumblr": "Tumblr", + "twitter": "X(Twitter)", + "vertical": "수직", + "vimeo": "Vimeo", + "washing": "씻기", + "auto": "자동", + "default": "기본값", + "fill": "채우기", + "fit": "핏", + "full": "전체", + "full_and_page": "전체 배경, 페이지 너비 콘텐츠", + "heading": "제목", + "landscape": "가로", + "lg": "LG", + "link": "링크", + "lowercase": "소문자", + "m": "M", + "outline": "아웃라인", + "page": "페이지", + "portrait": "세로", + "s": "S", + "sentence": "문장", + "solid": "실선", + "space_between": "사이 간격", + "square": "정사각형", + "uppercase": "대문자", + "circle": "원형", + "swatches": "견본", + "full_and_page_offset_left": "전체 배경, 페이지 너비 콘텐츠, 왼쪽 오프셋", + "full_and_page_offset_right": "전체 배경, 페이지 너비 콘텐츠, 오른쪽 오프셋", + "offset_left": "왼쪽 오프셋", + "offset_right": "오른쪽 오프셋", + "page_center_aligned": "페이지, 가운데 맞춤", + "page_left_aligned": "페이지, 왼쪽 맞춤", + "page_right_aligned": "페이지, 오른쪽 맞춤", + "button": "버튼", + "caption": "캡션", + "h1": "제목 1", + "h2": "제목 2", + "h3": "제목 3", + "h4": "제목 4", + "h5": "제목 5", + "h6": "제목 6", + "paragraph": "단락", + "primary": "기본", + "secondary": "보조", + "tertiary": "3차", + "chevron_left": "왼쪽 방향 표시", + "chevron_right": "오른쪽 방향 표시", + "diamond": "다이아몬드", + "grid": "그리드", + "parallelogram": "평행사변형", + "rounded": "원형", + "fit_content": "핏", + "pills": "타원형", + "heavy": "굵게", + "thin": "가늘게", + "drawer": "서랍", + "preview": "미리 보기", + "text": "텍스트", + "video_uploaded": "업로드됨", + "video_external_url": "외부 URL", + "above_carousel": "캐러셀 위", + "all": "모두", + "always": "항상", + "arrows_large": "큰 화살표", + "arrows": "화살표", + "aspect_ratio": "가로 세로 비율", + "balance": "잔액", + "bento": "Bento", + "black": "검은색", + "bluesky": "Bluesky", + "body_large": "본문(크게)", + "body_regular": "본문(보통)", + "body_small": "본문(작게)", + "bold": "굵게", + "bottom_left": "왼쪽 하단", + "bottom_right": "오른쪽 하단", + "bottom": "아래쪽", + "capitalize": "대문자", + "caret": "캐럿", + "carousel": "캐러셀", + "check_box": "확인란", + "chevron_large": "큰 셰브론", + "chevron": "방향 표시", + "chevrons": "방향 표시", + "classic": "클래식", + "collection_images": "컬렉션 이미지", + "color": "색상", + "complementary": "보완", + "dissolve": "디졸브", + "dotted": "점", + "editorial": "편집", + "extra_large": "아주 크게", + "extra_small": "아주 작게", + "featured_collections": "추천 컬렉션", + "featured_products": "추천 제품", + "font_primary": "기본", + "font_secondary": "보조", + "font_tertiary": "3차", + "forward": "앞으로", + "full_screen": "전체 화면", + "heading_extra_large": "제목(아주 크게)", + "heading_extra_small": "제목(아주 작게)", + "heading_large": "제목(크게)", + "heading_regular": "제목(보통)", + "heading_small": "제목(작게)", + "icon": "아이콘", + "image": "이미지", + "input": "입력", + "inside_carousel": "캐러셀 내부", + "inverse_large": "서로 바꾸기(크게)", + "inverse": "서로 바꾸기", + "large_arrows": "큰 화살표", + "large_chevrons": "큰 셰브론", + "left": "왼쪽", + "light": "가늘게", + "linkedin": "LinkedIn", + "loose": "느슨한", + "media_first": "첫 번째 미디어", + "media_second": "두 번째 미디어", + "modal": "모달", + "narrow": "좁게", + "never": "사용하지 않음", + "next_to_carousel": "캐러셀 옆", + "normal": "보통", + "nowrap": "줄바꿈 없음", + "off_media": "미디어 끄기", + "on_media": "미디어 켜기", + "on_scroll_up": "위로 스크롤", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "타원형", + "plus": "+", + "pretty": "예쁜", + "price": "가격", + "primary_style": "기본 스타일", + "rectangle": "직사각형", + "regular": "일반", + "related": "관련", + "reverse": "거꾸로", + "rich_text": "서식있는 텍스트", + "right": "오른쪽", + "secondary_style": "보조 스타일", + "semibold": "약간 굵게", + "shaded": "음영으로 표시", + "show_second_image": "보조 이미지 표시", + "single": "단일", + "slide_left": "왼쪽으로 슬라이드", + "slide_up": "위로 슬라이드", + "spotify": "Spotify", + "stack": "스택", + "text_only": "텍스트 전용", + "threads": "Threads", + "thumbnails": "썸네일", + "tight": "단단한", + "top_left": "왼쪽 상단", + "top_right": "오른쪽 상단", + "top": "위쪽", + "two_number": "2", + "two_thirds": "2/3", + "underline": "밑줄", + "video": "동영상", + "wide": "넓게", + "youtube": "YouTube", + "below_image": "이미지 아래", + "down": "아래", + "fixed": "고정", + "gradient": "그라데이션", + "on_image": "이미지 위", + "percent": "비율", + "pixel": "픽셀", + "up": "위", + "accent": "강조", + "body": "본문", + "button_primary": "기본 버튼", + "button_secondary": "보조 버튼", + "compact": "소형", + "crop_to_fit": "알맞은 크기로 자르기", + "hidden": "숨겨짐", + "hint": "힌트", + "maintain_aspect_ratio": "가로 세로 비율 유지", + "off": "꺼짐", + "social_bluesky": "소셜 미디어: Bluesky", + "social_facebook": "소셜 미디어: Facebook", + "social_instagram": "소셜 미디어: Instagram", + "social_linkedin": "소셜 미디어: LinkedIn", + "social_pinterest": "소셜 미디어: Pinterest", + "social_snapchat": "소셜 미디어: Snapchat", + "social_spotify": "소셜 미디어: Spotify", + "social_threads": "소셜 미디어: Threads", + "social_tiktok": "소셜 미디어: TikTok", + "social_tumblr": "소셜 미디어: Tumblr", + "social_twitter": "소셜 미디어: X(Twitter)", + "social_whatsapp": "소셜 미디어: WhatsApp", + "social_vimeo": "소셜 미디어: Vimeo", + "social_youtube": "소셜 미디어: YouTube", + "spotlight": "스포트라이트", + "standard": "표준", + "subheading": "소제목", + "blur": "흐리게", + "lift": "리프트", + "reveal": "표시", + "scale": "크기 조정", + "subtle_zoom": "확대/축소" + }, + "content": { + "background_video": "배경 동영상", + "describe_the_video_for": "스크린리더를 사용하는 고객에게 슬라이드 쇼를 설명합니다. [자세히 알아보기](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "너비는 자동으로 모바일에 최적화됩니다.", + "advanced": "Advanced", + "background_image": "배경 이미지", + "block_size": "블록 사이즈", + "borders": "테두리", + "section_size": "섹션 사이즈", + "slideshow_width": "슬라이드 너비", + "typography": "입력 체계", + "complementary_products": "Search & Discovery 앱을 사용하여 보완 제품을 설정해야 합니다. [자세히 알아보기](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "열은 자동으로 모바일에 최적화됩니다", + "content_width": "콘텐츠 너비는 섹션 너비가 전체 너비로 설정된 경우에만 적용됩니다.", + "adjustments_affect_all_content": "이 블록의 모든 콘텐츠에 적용됩니다", + "responsive_font_sizes": "모든 화면 크기에 맞게 크기가 자동으로 조정됩니다", + "buttons": "버튼", + "swatches": "견본", + "variant_settings": "이형 상품 설정", + "background": "배경", + "appearance": "모양", + "arrows": "화살표", + "body_size": "본문 사이즈", + "bottom_row_appearance": "아래쪽 행 모양", + "carousel_navigation": "캐러셀 탐색", + "carousel_pagination": "캐러셀 페이지 매김", + "copyright": "저작권", + "edit_logo_in_theme_settings": "[테마 설정](/editor?context=theme&category=logo%20and%20favicon)에서 로고 편집", + "edit_price_in_theme_settings": "[테마 설정](/editor?context=theme&category=currency%20code)에서 가격 형식 편집", + "edit_variants_in_theme_settings": "[테마 설정](/editor?context=theme&category=variants)에서 이형 상품 스타일 편집", + "email_signups_create_customer_profiles": "가입하면 [고객 프로필](https://help.shopify.com/manual/customers)이 추가됩니다", + "follow_on_shop_eligiblity": "버튼을 표시하려면 Shop 채널이 설치되어 있고 Shop Pay가 활성화되어 있어야 합니다. [자세히 알아보기](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "글꼴", + "grid": "그리드", + "heading_size": "제목 사이즈", + "image": "이미지", + "input": "입력", + "layout": "레이아웃", + "link": "링크", + "link_padding": "링크 패딩", + "localization": "현지화", + "logo": "로고", + "margin": "여백", + "media": "미디어", + "media_1": "미디어 1", + "media_2": "미디어 2", + "menu": "메뉴", + "mobile_layout": "모바일 레이아웃", + "padding": "패딩", + "padding_desktop": "데스크톱 패딩", + "paragraph": "단락", + "policies": "정책", + "popup": "팝업", + "search": "검색", + "size": "사이즈", + "social_media": "소셜 미디어", + "submit_button": "제출 버튼", + "text_presets": "텍스트 사전 설정", + "transparent_background": "투명한 배경", + "typography_primary": "기본 입력 체계", + "typography_secondary": "보조 입력 체계", + "typography_tertiary": "3차 입력 체계", + "mobile_size": "모바일 크기", + "cards_layout": "카드 레이아웃", + "mobile_width": "모바일 너비", + "section_layout": "섹션 레이아웃", + "width": "너비", + "images": "이미지", + "visibility": "표시 유형", + "carousel": "캐러셀", + "colors": "색상", + "collection_page": "컬렉션 페이지", + "copyright_info": "[저작권 표시 편집](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message) 방법 알아보기", + "customer_account": "고객 계정", + "edit_empty_state_collection_in_theme_settings": "[테마 설정](/editor?context=theme&category=search)에서 빈 상태 컬렉션 편집", + "home_page": "홈페이지", + "inverse_logo_info": "투명 머리글 배경이 서로 바꾸기로 설정된 경우 사용됩니다", + "manage_customer_accounts": "고객 계정 설정에서 [표시 여부를 관리](/admin/settings/customer_accounts)합니다. 레거시 계정은 지원되지 않습니다.", + "manage_policies": "[정책 관리](/admin/settings/legal)", + "product_page": "제품 페이지", + "text": "텍스트", + "thumbnails": "썸네일", + "visible_if_collection_has_more_products": "컬렉션에 표시된 것보다 많은 제품이 있는 경우 표시됩니다", + "grid_layout": "그리드 레이아웃", + "app_required_for_ratings": "제품 평점을 표시하려면 앱이 필요합니다. [자세히 알아보기](https://help.shopify.com/manual/apps)", + "icon": "아이콘", + "manage_store_name": "[스토어 이름 관리](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "상위 섹션의 컬렉션을 표시합니다", + "resource_reference_collection_card_image": "상위 컬렉션의 이미지를 표시합니다", + "resource_reference_collection_title": "상위 컬렉션의 이름을 표시합니다", + "resource_reference_product": "상위 제품에 자동으로 연결합니다", + "resource_reference_product_card": "상위 섹션의 제품을 표시합니다", + "resource_reference_product_inventory": "상위 제품의 재고를 표시합니다", + "resource_reference_product_price": "상위 제품의 가격을 표시합니다", + "resource_reference_product_recommendations": "상위 제품을 기반으로 추천 제품을 표시합니다", + "resource_reference_product_review": "상위 제품의 리뷰를 표시합니다", + "resource_reference_product_swatches": "상위 제품의 견본을 표시합니다", + "resource_reference_product_title": "상위 제품의 이름을 표시합니다", + "resource_reference_product_variant_picker": "상위 제품의 이형 상품을 표시합니다", + "resource_reference_product_media": "상위 제품의 미디어를 표시합니다", + "product_media": "제품 미디어", + "section_link": "섹션 링크" + }, + "html_defaults": { + "share_information_about_your": "

고객과 브랜드 정보를 공유하세요. 제품을 설명하고 공지 사항을 제공하고, 스토어를 방문하는 고객을 환영할 수 있습니다.

" + }, + "text_defaults": { + "collapsible_row": "축소 가능한 행", + "button_label": "지금 쇼핑하기", + "heading": "제목", + "email_signup_button_label": "가입", + "accordion_heading": "아코디언 제목", + "contact_form_button_label": "제출", + "popup_link": "팝업 링크", + "sign_up": "가입하기", + "welcome_to_our_store": "스토어에 오신 것을 환영합니다", + "be_bold": "대담하게", + "shop_our_latest_arrivals": "최신 상품을 쇼핑하세요!" + }, + "info": { + "carousel_layout_on_mobile": "캐러셀은 모바일에서 사용됩니다.", + "link_info": "선택 사항: 아이콘을 클릭할 수 있게 설정", + "video_alt_text": "보조 기술 사용자에게 동영상을 설명합니다", + "video_autoplay": "동영상은 기본적으로 음소거됩니다", + "video_external": "YouTube 또는 Vimeo URL 사용", + "carousel_hover_behavior_not_supported": "섹션 수준에서 '캐러셀' 유형을 선택하면 '캐러셀' 호버 기능은 지원되지 않습니다.", + "checkout_buttons": "구매자가 더 빨리 결제하고 전환율을 높일 수 있습니다. [자세히 알아보기](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "사용자 지정 제목", + "edit_presets_in_theme_settings": "[테마 설정](/editor?context=theme&category=typography)에서 사전 설정 편집", + "enable_filtering_info": "[Search & Discovery 앱](https://help.shopify.com/manual/online-store/search-and-discovery/filters)으로 필터를 맞춤 설정합니다", + "grid_layout_on_mobile": "모바일에서는 그리드 레이아웃이 사용됩니다", + "manage_countries_regions": "[국가/지역 관리하기](/admin/settings/markets)", + "manage_languages": "[언어 관리하기](/admin/settings/languages)", + "transparent_background": "읽기 쉽도록 투명한 배경이 적용된 각 템플릿을 검토합니다", + "logo_font": "로고가 선택되지 않은 경우에만 적용됩니다", + "aspect_ratio_adjusted": "일부 레이아웃에서 조정됨", + "auto_open_cart_drawer": "이 기능을 활성화하면, 카트에 제품이 추가될 때 카트 서랍이 자동으로 열립니다.", + "custom_liquid": "앱 코드 조각이나 기타 코드를 추가하여 고급 맞춤 설정을 생성할 수 있습니다. [자세히 알아보기](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "이미지에만 적용", + "hover_effects": "제품 및 컬렉션 카드에 적용합니다", + "pills_usage": "적용된 필터, 할인 코드 및 검색 제안에 사용됩니다" + }, + "categories": { + "basic": "Basic", + "collection": "컬렉션", + "collection_list": "컬렉션 목록", + "footer": "바닥글", + "forms": "양식", + "header": "머리글", + "layout": "레이아웃", + "links": "링크", + "product": "제품", + "product_list": "추천 컬렉션", + "banners": "배너", + "collections": "컬렉션", + "custom": "사용자 지정", + "decorative": "장식용", + "products": "제품", + "other_sections": "기타", + "storytelling": "스토리텔링" + } +} diff --git a/locales/lt.json b/locales/lt.json new file mode 100644 index 000000000..fc98a0ddf --- /dev/null +++ b/locales/lt.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Įkelti vaizdo įrašą „{{ description }}“", + "sold_out": "Išparduota", + "email_signup": { + "label": "El. paštas", + "placeholder": "El. pašto adresas", + "success": "Dėkojame, kad prenumeruojate!" + }, + "filter": "Filtruoti", + "payment_methods": "Mokėjimo būdai", + "contact_form": { + "name": "Vardas", + "email": "El. pašto adresas", + "phone": "Telefonas", + "comment": "Komentaras", + "post_success": "Dėkojame, kad kreipėtės. Atsakysime kaip galėdami greičiau.", + "error_heading": "Pakoreguokite toliau pateiktą informaciją:" + } + }, + "accessibility": { + "play_model": "Paleisti 3D modelį", + "play_video": "Paleisti vaizdo įrašą", + "unit_price": "Vieneto kaina", + "country_results_count": "{{ count }} rezultatai (-ų)", + "slideshow_pause": "Pristabdyti skaidrių peržiūrą", + "slideshow_play": "Leisti skaidrių peržiūrą", + "remove_item": "Pašalinti {{ title}}", + "skip_to_text": "Eiti į turinį", + "skip_to_product_info": "Eiti prie informacijos apie gaminį", + "skip_to_results_list": "Eiti į rezultatų sąrašą", + "new_window": "Atidaroma naujame lange.", + "slideshow_next": "Kita skaidrė", + "slideshow_previous": "Ankstesnė skaidrė", + "close_dialog": "Uždaryti dialogo langą", + "reset_search": "Nustatyti paiešką iš naujo", + "search_results_count": "Rasti {{ count }} rezultatai (-ų) pagal užklausą „{{ query }}“", + "search_results_no_results": "Nerasta jokių rezultatų pagal užklausą „{{ query }}“", + "filters": "Filtrai", + "account": "Atidaryti paskyros meniu", + "cart": "Krepšelis", + "cart_count": "Iš viso prekių krepšelyje", + "filter_count": { + "one": "Pritaikytas {{ count }} filtras", + "other": "Pritaikyti filtrai: {{ count }}", + "few": "Pritaikyti filtrai: {{ count }}", + "many": "Pritaikyti filtrai: {{ count }}" + }, + "menu": "Meniu", + "country_region": "Šalis / regionas", + "slide_status": "{{ index }} skaidrė iš {{ length }}", + "scroll_to": "Slinkti į „{{ title }}“", + "loading_product_recommendations": "Įkeliamos gaminių rekomendacijos", + "discount": "Taikyti nuolaidos kodą", + "discount_applied": "Pritaikytas nuolaidos kodas: {{ code }}", + "open_cart_drawer": "Atidaryti krepšelį", + "inventory_status": "Atsargų būsena", + "pause_video": "Pristabdyti vaizdo įrašą", + "find_country": "Rasti šalį", + "localization_region_and_language": "Atidaryti regiono ir kalbos parinkiklį", + "open_search_modal": "Atidaryti paiešką", + "decrease_quantity": "Sumažinti kiekį", + "increase_quantity": "Padidinti kiekį", + "rating": "Šio produkto vertinimas: {{ rating }} iš 5", + "quantity": "Kiekis", + "nested_product": "{{ product_title }} ({{ parent_title }})" + }, + "actions": { + "add_to_cart": "Įdėti į krepšelį", + "clear_all": "Išvalyti viską", + "remove": "Pašalinti", + "view_in_your_space": "Peržiūra savo erdvėje", + "show_filters": "Filtruoti", + "clear": "Išvalyti", + "continue_shopping": "Tęsti apsipirkimą", + "log_in_html": "Turite paskyrą? Prisijunkite ir atsiskaitysite greičiau.", + "see_items": { + "one": "Žr. {{ count }} prekę", + "other": "Žr. {{ count }} prekes(-ių)", + "few": "Žr. {{ count }} prekes(-ių)", + "many": "Žr. {{ count }} prekes(-ių)" + }, + "view_all": "Žr. viską", + "add": "Pridėti", + "choose": "Rinktis", + "added": "Pridėta", + "show_less": "Rodyti mažiau", + "show_more": "Rodyti daugiau", + "close": "Uždaryti", + "more": "Daugiau", + "zoom": "Keisti mastelį", + "close_dialog": "Uždaryti dialogo langą", + "reset": "Nustatyti iš naujo", + "back": "Atgal", + "log_in": "Prisijungti", + "log_out": "Atsijungti", + "remove_discount": "Pašalinti nuolaidos {{ code }}", + "enter_using_password": "Įeiti naudojant slaptažodį", + "submit": "Pateikti", + "enter_password": "Įveskite slaptažodį", + "view_store_information": "Žiūrėti parduotuvės informaciją", + "apply": "Taikyti", + "sign_in_options": "Kitos prisijungimo parinktys", + "sign_up": "Prisiregistruoti", + "open_image_in_full_screen": "Atidaryti vaizdą per visą ekraną", + "sort": "Rūšiuoti", + "show_all_options": "Rodyti visus variantus" + }, + "content": { + "reviews": "apžvalgos (-ų; -a)", + "language": "Kalba", + "localization_region_and_language": "Regionas ir kalba", + "no_results_found": "Rezultatų nerasta", + "cart_total": "Bendra krepšelio suma", + "your_cart_is_empty": "Jūsų krepšelis tuščias", + "product_image": "Gaminio nuotrauka", + "product_information": "Gaminio informacija", + "quantity": "Kiekis", + "product_total": "Iš viso gaminių", + "cart_estimated_total": "Apskaičiuota bendra suma", + "seller_note": "Specialūs nurodymai", + "cart_subtotal": "Tarpinė suma", + "discounts": "Nuolaidos", + "discount": "Nuolaida", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Muito ir kiti mokesčiai įtraukti. Nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Muito ir kiti mokesčiai įtraukti. Nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_included_shipping_at_checkout_with_policy_html": "Mokesčiai įtraukti. Nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_included_shipping_at_checkout_without_policy": "Mokesčiai įtraukti. Nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Muito mokesčiai įtraukti. Mokesčiai, nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Muito mokesčiai įtraukti. Mokesčiai, nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Mokesčiai, nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Mokesčiai, nuolaidos ir siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "checkout": "Atsiskaityti", + "cart_title": "Krepšelis", + "price": "Kaina", + "price_regular": "Įprasta kaina", + "price_compare_at": "Kainų palyginimas", + "price_sale": "Kaina su nuolaida", + "duties_and_taxes_included": "Muito ir kiti mokesčiai įtraukti.", + "duties_included": "Muito mokesčiai įtraukti.", + "shipping_policy_html": "Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_included": "Mokesčiai įtraukti.", + "product_badge_sold_out": "Išparduota", + "product_badge_sale": "Išpardavimas", + "search_input_label": "Ieškoti", + "search_input_placeholder": "Ieškoti", + "search_results": "Paieškos rezultatai", + "search_results_label": "Paieškos rezultatai", + "search_results_no_results": "Nerasta rezultatų pagal užklausą „{{ terms }}“. Bandykite kitą paiešką.", + "search_results_resource_articles": "Tinklaraščio įrašai", + "search_results_resource_collections": "Kolekcijos", + "search_results_resource_pages": "Puslapiai", + "search_results_resource_products": "Gaminiai", + "search_results_resource_queries": "Paieškos pasiūlymai", + "search_results_view_all": "Žr. viską", + "search_results_view_all_button": "Žr. viską", + "search_results_resource_products_count": { + "one": "{{ count }} gaminys", + "other": "{{ count }} gaminiai (-ių)", + "few": "{{ count }} gaminiai (-ių)", + "many": "{{ count }} gaminiai (-ių)" + }, + "grid_view": { + "default_view": "Numatytasis", + "grid_fieldset": "Stulpelių tinklelis", + "single_item": "Vienas", + "zoom_out": "Atitraukti" + }, + "recently_viewed_products": "Neseniai žiūrėta", + "unavailable": "Nepasiekiama", + "collection_placeholder": "Kolekcijos pavadinimas", + "product_card_placeholder": "Gaminio pavadinimas", + "product_count": "Gaminių skaičius", + "item_count": { + "one": "{{ count }} prekė", + "other": "{{ count }} prekės (-ių)", + "few": "{{ count }} prekės (-ių)", + "many": "{{ count }} prekės (-ių)" + }, + "errors": "Klaidos", + "price_from": "Nuo {{ price }}", + "featured_products": "Siūlomi gaminiai", + "filters": "Filtrai", + "no_products_found": "Nerasta jokių gaminių.", + "price_filter_html": "Didžiausia kaina yra {{ price }}", + "use_fewer_filters_html": "Pabandykite naudoti mažiau filtrų arba išvalyti visus filtrus.", + "search": "Ieškoti", + "search_results_no_results_check_spelling": "Jokių rezultatų pagal užklausą „{{ terms }}“. Patikrinkite rašybą arba vartokite kitą žodį ar frazę.", + "blog_details_separator": "|", + "read_more": "Skaityti daugiau...", + "account_title": "Paskyra", + "account_title_personalized": "Sveiki, {{ first_name }},", + "account_orders": "Užsakymai", + "account_profile": "Profilis", + "discount_code": "Nuolaidos kodas", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Muito ir kiti mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Muito ir kiti mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Muito mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Muito mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "pickup_available_at_html": "Galima atsiimti {{ location }}", + "pickup_available_in": "Galima atsiimti {{ pickup_time }}", + "pickup_not_available": "Šiuo metu atsiimti negalima", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Mokesčiai ir siuntimo išlaidos apskaičiuojami atsiskaitant.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Mokesčiai ir siuntimo išlaidos apskaičiuojami atsiskaitant.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Mokesčiai įtraukti. Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "wrong_password": "Slaptažodis neteisingas", + "view_more_details": "Žiūrėti daugiau informacijos", + "inventory_low_stock": "Atsargos senka", + "inventory_in_stock": "Yra sandėlyje", + "inventory_out_of_stock": "Neturime", + "page_placeholder_title": "Puslapio pavadinimas", + "page_placeholder_content": "Pasirinkite puslapį jo turiniui peržiūrėti.", + "placeholder_image": "Vietos ženklo vaizdas", + "inventory_low_stock_show_count": { + "one": "Liko {{ count }}", + "other": "Liko {{ count }}", + "few": "Liko {{ count }}", + "many": "Liko {{ count }}" + }, + "discount_code_error": "Jūsų krepšeliui nuolaidos kodo pritaikyti negalima", + "shipping_policy": "Siuntimo išlaidos apskaičiuojamos atsiskaitant.", + "shipping_discount_error": "Siuntimui taikomos nuolaidos rodomos atsiskaitant, įvedus adresą", + "powered_by": "Ši parduotuvė bus teikiama per platformą", + "store_owner_link_html": "Ar esate parduotuvės savininkas? Prisijunkite čia" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Panaudokite dovanų kortelės kodą internetinėje parduotuvėje arba QR kodą fizinėje parduotuvėje", + "title": "Štai jūsų {{ value }} vertės parduotuvės {{ shop }} dovanų kortelė!", + "subtext": "Jūsų dovanų kortelė", + "shop_link": "Apsilankyti internetinėje parduotuvėje", + "add_to_apple_wallet": "Pridėti prie „Apple Wallet“", + "qr_image_alt": "QR kodas — nuskaitykite ir panaudokite dovanų kortelę", + "copy_code": "Kopijuoti dovanų kortelės kodą", + "expiration_date": "Baigs galioti {{ expires_on }}", + "copy_code_success": "Kodą pavyko nukopijuoti", + "expired": "Nebegalioja" + } + }, + "placeholders": { + "password": "Slaptažodis", + "search": "Ieškoti", + "product_title": "Gaminio pavadinimas", + "collection_title": "Kolekcijos pavadinimas" + }, + "products": { + "product": { + "add_to_cart": "Įdėti į krepšelį", + "added_to_cart": "Įdėta į krepšelį", + "adding_to_cart": "Pridedama…", + "add_to_cart_error": "Dedant į krepšelį įvyko klaida", + "sold_out": "Išparduota", + "unavailable": "Nėra" + } + }, + "fields": { + "separator": "iki" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentaras", + "other": "{{ count }} komentarai (-ų)", + "few": "{{ count }} komentarai (-ų)", + "many": "{{ count }} komentarai (-ų)" + } + }, + "comment_form": { + "email": "El. pašto adresas", + "error": "Komentaro paskelbti nepavyko, išspręskite nurodytas problemas:", + "heading": "Rašyti komentarą", + "message": "Žinutė", + "moderated": "Turėkite omenyje, kad prieš paskelbiant komentarus, jie turi būti patvirtinti.", + "name": "Vardas", + "post": "Skelbti komentarą", + "success_moderated": "Komentaras paskelbtas, laukiama moderavimo", + "success": "Komentaras paskelbtas" + } + } +} diff --git a/locales/nb.json b/locales/nb.json new file mode 100644 index 000000000..91e896dc7 --- /dev/null +++ b/locales/nb.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Last inn video: {{ description }}", + "sold_out": "Utsolgt", + "email_signup": { + "label": "E-post", + "placeholder": "E-postadresse", + "success": "Takk for at du abonnerer!" + }, + "filter": "Filter", + "payment_methods": "Betalingsmåter", + "contact_form": { + "name": "Navn", + "email": "E-post", + "phone": "Telefon", + "comment": "Kommentar", + "post_success": "Takk for at du kontaktet oss. Vi svarer så snart som mulig.", + "error_heading": "Juster følgende:" + } + }, + "accessibility": { + "play_model": "Spill av 3D-modell", + "play_video": "Spill av video", + "unit_price": "Enhetspris", + "country_results_count": "{{ count }} resultater", + "slideshow_pause": "Sett lysbildefremvisningen på pause", + "slideshow_play": "Spill av lysbildefremvisningen", + "remove_item": "Fjern {{ title}}", + "skip_to_text": "Gå videre til innholdet", + "skip_to_product_info": "Hopp til produktinformasjon", + "skip_to_results_list": "Gå til resultatlisten", + "new_window": "Åpner i et nytt vindu.", + "slideshow_next": "Neste lysbilde", + "slideshow_previous": "Forrige lysbilde", + "close_dialog": "Lukk dialogboksen", + "reset_search": "Tilbakestill søk", + "search_results_count": "{{ count }} søkeresultater funnet for «{{ query }}»", + "search_results_no_results": "Fant ingen resultater for «{{ query }}»", + "filters": "Filtre", + "filter_count": { + "one": "{{ count }} filter brukt", + "other": "{{ count }} filtre brukt" + }, + "account": "Åpne kontomenyen", + "cart": "Handlekurv", + "cart_count": "Totalt antall varer i handlekurven", + "menu": "Meny", + "country_region": "Land/region", + "slide_status": "Lysbilde {{ index }} av {{ length }}", + "scroll_to": "Bla til {{ title }}", + "loading_product_recommendations": "Laster inn produktanbefalinger", + "discount": "Bruk en rabattkode", + "discount_applied": "Brukt rabattkode: {{ code }}", + "open_cart_drawer": "Åpne handlekurven", + "pause_video": "Sett videoen på pause", + "inventory_status": "Lagerstatus", + "find_country": "Finn land", + "localization_region_and_language": "Åpne område- og språkvelgeren", + "open_search_modal": "Åpne søk", + "decrease_quantity": "Reduser antallet", + "increase_quantity": "Øk antallet", + "quantity": "Antall", + "rating": "Vurderingen av dette produktet er {{ rating }} av 5", + "nested_product": "{{ product_title }} for {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Legg i handlekurv", + "clear_all": "Fjern alle", + "remove": "Fjern", + "view_in_your_space": "Vis på området ditt", + "show_filters": "Filter", + "clear": "Fjern", + "continue_shopping": "Fortsett å handle", + "log_in_html": "Har du en konto? Logg inn for å betale raskere.", + "see_items": { + "one": "Se {{ count }} vare", + "other": "Se {{ count }} varer" + }, + "view_all": "Vis alle", + "add": "Legg til", + "choose": "Velg", + "added": "Lagt til", + "show_less": "Vis mindre", + "show_more": "Vis mer", + "close": "Lukk", + "more": "Mer", + "reset": "Tilbakestill", + "zoom": "Zoom", + "close_dialog": "Lukk dialogboksen", + "apply": "Bruk", + "back": "Tilbake", + "log_in": "Logg inn", + "log_out": "Logg ut", + "remove_discount": "Fjern rabatten {{ code }}", + "enter_using_password": "Bruk passordet til å gå inn", + "submit": "Send inn", + "enter_password": "Angi passordet", + "view_store_information": "Vis butikkinformasjon", + "open_image_in_full_screen": "Åpne bildet i fullskjerm", + "sign_in_options": "Andre påloggingsalternativer", + "sign_up": "Registrer deg", + "sort": "Sorter", + "show_all_options": "Vis alle alternativer" + }, + "content": { + "reviews": "anmeldelser", + "no_results_found": "Fant ingen resultater", + "language": "Språk", + "localization_region_and_language": "Område og språk", + "cart_total": "Totalsum for handlekurv", + "your_cart_is_empty": "Handlekurven din er tom", + "product_image": "Produktbilde", + "product_information": "Produktinformasjon", + "quantity": "Antall", + "product_total": "Sum for produkt", + "cart_estimated_total": "Estimert totalsum", + "seller_note": "Spesielle instruksjoner", + "cart_subtotal": "Delsum", + "discounts": "Rabatter", + "discount": "Rabatt", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Inkludert toll og andre avgifter. Rabatter og frakt beregnes i kassen.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Inkludert toll og andre avgifter. Rabatter og frakt beregnes i kassen.", + "taxes_included_shipping_at_checkout_with_policy_html": "Avgifter inkludert. Rabatter og frakt beregnes i kassen.", + "taxes_included_shipping_at_checkout_without_policy": "Avgifter inkludert. Rabatter og frakt beregnes i kassen.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Tollavgifter inkludert. Avgifter, rabatter og frakt beregnes i kassen.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Tollavgifter inkludert. Avgifter, rabatter og frakt beregnes i kassen.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Avgifter, rabatter og frakt beregnes i kassen.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Avgifter, rabatter og frakt beregnes i kassen.", + "checkout": "Betaling", + "cart_title": "Handlekurv", + "price": "Pris", + "price_regular": "Vanlig pris", + "price_compare_at": "Sammenligningspris", + "price_sale": "Rabattert pris", + "duties_and_taxes_included": "Toll og andre avgifter inkludert.", + "duties_included": "Tollavgifter inkludert.", + "shipping_policy_html": "Frakt beregnes i kassen.", + "taxes_included": "Avgifter inkludert.", + "product_badge_sold_out": "Utsolgt", + "product_badge_sale": "Salg", + "search_input_label": "Søk", + "search_input_placeholder": "Søk", + "search_results": "Søkeresultater", + "search_results_label": "Søkeresultater", + "search_results_no_results": "Fant ingen resultater for «{{ terms }}». Prøv et annet søk.", + "search_results_resource_articles": "Blogginnlegg", + "search_results_resource_collections": "Samlinger", + "search_results_resource_pages": "Sider", + "search_results_resource_products": "Produkter", + "search_results_resource_queries": "Søkeforslag", + "search_results_view_all": "Vis alle", + "search_results_view_all_button": "Vis alle", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} produkter" + }, + "grid_view": { + "default_view": "Standard", + "grid_fieldset": "Kolonne-rutenett", + "single_item": "Enkel", + "zoom_out": "Zoom ut" + }, + "recently_viewed_products": "Nylig vist", + "unavailable": "Utilgjengelig", + "collection_placeholder": "Samlingstittel", + "product_card_placeholder": "Produkttittel", + "product_count": "Antall produkter", + "item_count": { + "one": "{{ count }} vare", + "other": "{{ count }} varer" + }, + "errors": "Feil", + "price_from": "Fra {{ price }}", + "search": "Søk", + "search_results_no_results_check_spelling": "Fant ingen resultater for «{{ terms }}». Kontroller stavemåten, eller bruk et annet ord eller frase.", + "featured_products": "Utvalgte produkter", + "filters": "Filtre", + "no_products_found": "Fant ingen produkter.", + "price_filter_html": "Den høyeste prisen er {{ price }}", + "use_fewer_filters_html": "Prøv å bruke færre filtre eller tøm alle filtre.", + "blog_details_separator": "|", + "read_more": "Les mer …", + "account_title": "Konto", + "account_title_personalized": "Hei, {{ first_name }}", + "account_orders": "Bestillinger", + "account_profile": "Profil", + "discount_code": "Rabattkode", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Inkludert tollplikter og avgifter. Frakt beregnes i kassen.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Inkludert tollplikter og avgifter. Frakt beregnes i kassen.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Inkludert tollplikter. Frakt beregnes i kassen.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Inkludert tollplikter. Frakt beregnes i kassen.", + "pickup_available_at_html": "Kan hentes hos {{ location }}", + "pickup_available_in": "Kan hentes {{ pickup_time }}", + "pickup_not_available": "Henting er ikke tilgjengelig for øyeblikket", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Avgifter og frakt beregnes i kassen.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Avgifter og frakt beregnes i kassen.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Avgifter inkludert. Frakt beregnes i kassen.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Avgifter inkludert. Frakt beregnes i kassen.", + "view_more_details": "Vis mer informasjon", + "wrong_password": "Feil passord", + "page_placeholder_title": "Sidetittel", + "page_placeholder_content": "Velg en side for å vise innholdet.", + "placeholder_image": "Plassholderbilde", + "shipping_discount_error": "Fraktrabatter vises i kassen etter at du har lagt til en adresse", + "discount_code_error": "Rabattkoden kan ikke brukes på handlekurven din", + "inventory_low_stock": "Lav lagerbeholdning", + "inventory_in_stock": "På lager", + "inventory_out_of_stock": "Ikke på lager", + "shipping_policy": "Frakt beregnes i kassen.", + "inventory_low_stock_show_count": { + "one": "{{ count }} igjen", + "other": "{{ count }} igjen" + }, + "powered_by": "Denne butikken skal bli drevet av", + "store_owner_link_html": "Er du butikkeieren? Logg inn her" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Bruk gavekortet på nettet eller QR-koden i butikken", + "title": "Her er gavekortsaldoen {{ value }} for {{ shop }}.", + "subtext": "Ditt gavekort", + "shop_link": "Besøk nettbutikken", + "add_to_apple_wallet": "Legg til i Apple Wallet", + "qr_image_alt": "QR-kode – skann for å løse inn gavekortet", + "copy_code": "Kopier gavekortkoden", + "expiration_date": "Utløper {{ expires_on }}", + "copy_code_success": "Koden er kopiert", + "expired": "Utløpt" + } + }, + "placeholders": { + "password": "Passord", + "search": "Søk", + "product_title": "Produkttittel", + "collection_title": "Samlingstittel" + }, + "products": { + "product": { + "add_to_cart": "Legg i handlekurv", + "added_to_cart": "Lagt til i handlekurv", + "adding_to_cart": "Legger til ...", + "add_to_cart_error": "Problem med å legge til i handlekurven", + "sold_out": "Utsolgt", + "unavailable": "Utilgjengelig" + } + }, + "fields": { + "separator": "til" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} kommentar", + "other": "{{ count }} kommentarer" + } + }, + "comment_form": { + "email": "E-postadresse", + "error": "Kunne ikke legge ut kommentaren. Kontroller følgende:", + "heading": "Skriv en kommentar", + "message": "Melding", + "moderated": "Merk at kommentarer må godkjennes før de publiseres.", + "name": "Navn", + "post": "Del en kommentar", + "success_moderated": "Kommentar lagt ut, venter på moderering", + "success": "Kommentar lagt ut" + } + } +} diff --git a/locales/nb.schema.json b/locales/nb.schema.json new file mode 100644 index 000000000..7c3f852da --- /dev/null +++ b/locales/nb.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Rammer", + "collapsible_row": "Sammenleggbar rad", + "colors": "Farger", + "custom_section": "Egendefinert seksjon", + "icon": "Ikon", + "logo_and_favicon": "Logo og favorittikon", + "overlapping_blocks": "Overlappende blokker", + "product_buy_buttons": "Kjøp-knapper", + "product_description": "Beskrivelse", + "product_price": "Pris", + "product_variant_picker": "Variantvelger", + "slideshow": "Lysbildefremvisning", + "typography": "Typografi", + "video": "Video", + "slideshow_controls": "Kontroller for lysbildefremvisning", + "size": "Størrelse", + "spacing": "Mellomrom", + "product_recommendations": "Anbefalte produkter", + "product_media": "Produktmedier", + "featured_collection": "Fremhevet samling", + "add_to_cart": "Legg i handlekurv", + "email_signup": "E-postregistrering", + "submit_button": "Send inn-knapp", + "grid_layout_selector": "Velger for rutenettlayout", + "image": "Bilde", + "list_items": "List opp varer", + "facets": "Aspekter", + "variants": "Varianter", + "product_cards": "Produktkort", + "styles": "Stiler", + "primary_button": "Primærknapp", + "secondary_button": "Sekundær knapp", + "buttons": "Knapper", + "inputs": "Inndata", + "popovers": "Forgrunnsvinduer", + "marquee": "Marquee", + "alternating_content_rows": "Vekslende rader", + "pull_quote": "Nøkkelsitat", + "contact_form": "Kontaktskjema", + "featured_product": "Produkthøydepunkter", + "icons_with_text": "Ikoner med tekst", + "products_carousel": "Utvalgt kolleksjon: Karusell", + "products_grid": "Utvalgt kolleksjon: Rutenett", + "jumbo_text": "Jumbotekst", + "accelerated_checkout": "Hurtigkasse", + "accordion": "Trekkspill", + "accordion_row": "Trekkspillrad", + "animations": "Animasjoner", + "announcement": "Kunngjøring", + "announcement_bar": "Kunngjøringsrad", + "badges": "Merker", + "button": "Knapp", + "cart": "Handlekurv", + "cart_items": "Varer i handlekurven", + "cart_products": "Handlekurvprodukter", + "cart_title": "Handlekurv", + "collection": "Samling", + "collection_card": "Samlingskort", + "collection_columns": "Samlingskolonner", + "collection_container": "Samling", + "collection_description": "Samlingsbeskrivelse", + "collection_image": "Samlingsbilde", + "collection_info": "Samlingsinfo", + "collection_list": "Samlingsliste", + "collections": "Samlinger", + "content": "Innhold", + "content_grid": "Innholdsrutenett", + "details": "Detaljer", + "divider": "Skillelinje", + "filters": "Filtrering og sortering", + "follow_on_shop": "Følg på Shop", + "footer": "Bunntekst", + "footer_utilities": "Bunntekstverktøy", + "group": "Gruppe", + "header": "Topptekst", + "heading": "Overskrift", + "icons": "Ikoner", + "image_with_text": "Bilde med tekst", + "input": "Inndata", + "logo": "Logo", + "magazine_grid": "Magasinrutenett", + "media": "Medier", + "menu": "Meny", + "mobile_layout": "Mobillayout", + "payment_icons": "Betalingsikoner", + "popup_link": "Popup-kobling", + "predictive_search": "Søk popover-vindu", + "predictive_search_empty": "Tomt prediktivt søk", + "price": "Pris", + "product": "Produkt", + "product_card": "Produktkort", + "product_card_media": "Medier", + "product_card_rendering": "Gjengivelse av produktkort", + "product_grid": "Rutenett", + "product_grid_main": "Produktrutenett", + "product_image": "Produktbilde", + "product_information": "Produktinformasjon", + "product_list": "Utvalgt kolleksjon", + "product_review_stars": "Stjerner i anmeldelse", + "quantity": "Antall", + "row": "Rad", + "search": "Søk", + "section": "Seksjon", + "selected_variants": "Valgte varianter", + "shop_the_look": "Kjøp stilen", + "slide": "Lysbilde", + "social_media_links": "Koblinger til sosiale medier", + "spacer": "Avstandsstykke", + "steps": "Steg", + "summary": "Sammendrag", + "swatches": "Fargekart", + "testimonials": "Tilbakemeldinger fra kunder", + "text": "Tekst", + "title": "Tittel", + "utilities": "Verktøy", + "search_input": "Søkinndata", + "search_results": "Søkeresultater", + "read_only": "Skrivebeskyttet", + "collection_title": "Samlingstittel", + "collections_bento": "Samlingsliste: Bento", + "faq_section": "Vanlige spørsmål", + "hero": "Hovedbanner", + "view_all_button": "Vis alle", + "video_section": "Video", + "blog": "Blogg", + "blog_posts": "Blogginnlegg", + "custom_liquid": "Egendefinert Liquid", + "blog_post": "Blogginnlegg", + "caption": "Bildetekst", + "collection_card_image": "Bilde", + "collection_links": "Samlingslenker", + "collection_links_spotlight": "Samlingskoblinger: Spotlight", + "collection_links_text": "Samlingskoblinger: Tekst", + "collections_carousel": "Samlingsliste: Karusell", + "collections_editorial": "Samlingliste: Redaksjonell", + "collections_grid": "Samlingsliste: Rutenett", + "copyright": "Opphavsrett", + "count": "Antall", + "divider_section": "Skillelinje", + "drawers": "Skuffer", + "editorial": "Redaksjonell", + "editorial_jumbo_text": "Redaksjonell: Jumbotekst", + "hero_marquee": "Hovedbanner: Skrollbanner", + "input_fields": "Inndatafelter", + "local_pickup": "Lokal henting", + "marquee_section": "Marquee", + "media_with_text": "Medier med tekst", + "page": "Side", + "page_content": "Innhold", + "page_layout": "Sidelayout", + "policy_list": "Koblinger til retningslinjer", + "prices": "Priser", + "products_editorial": "Utvalgt kolleksjon: Redaksjonell", + "social_link": "Kobling til sosiale medier", + "split_showcase": "Split-presentasjon", + "variant_pickers": "Variantvelgere", + "pills": "Piller", + "product_title": "Produkttittel", + "large_logo": "Stor logo", + "product_list_button": "«Vis alle»-knappen", + "product_inventory": "Produktlager", + "description": "Beskrivelse" + }, + "settings": { + "alignment": "Justering", + "autoplay": "Spill av automatisk", + "background": "Bakgrunn", + "border_radius": "Hjørneradius", + "border_width": "Tykkelse på kantlinje", + "borders": "Rammer", + "bottom_padding": "Bunnmarg", + "button": "Knapp", + "color": "Farge", + "colors": "Farger", + "content_alignment": "Innholdsjustering", + "content_direction": "Innholdsretning", + "content_position": "Innholdsplassering", + "cover_image_size": "Størrelse på forsidebilde", + "cover_image": "Forsidebilde", + "custom_minimum_height": "Egendefinert minimumshøyde", + "custom_width": "Egendefinert bredde", + "enable_video_looping": "Løkkeavspilling av video", + "favicon": "Favorittikon", + "font_family": "Skrifttypefamilie", + "gap": "Mellomrom", + "geometric_translate_y": "Geometrisk omforming Y", + "heading": "Overskrift", + "icon": "Ikon", + "image": "Bilde", + "image_icon": "Bildeikon", + "image_opacity": "Gjennomsiktighet for bilde", + "image_position": "Bildeposisjon", + "image_ratio": "Bildeforhold", + "label": "Etikett", + "line_height": "Linjehøyde", + "link": "Kobling", + "layout_gap": "Layoutmellomrom", + "make_section_full_width": "Gjør seksjonen til full bredde", + "minimum_height": "Minimumshøyde", + "opacity": "Gjennomsiktighet", + "overlay_opacity": "Overleggets gjennomsiktighet", + "padding": "Marg", + "primary_color": "Koblinger", + "product": "Produkt", + "section_width": "Seksjonsbredde", + "size": "Størrelse", + "slide_spacing": "Lysbildemellomrom", + "slide_width": "Lysbildebredde", + "slideshow_fullwidth": "Lysbilder i full bredde", + "style": "Stil", + "text": "Tekst", + "text_case": "Store/små bokstaver", + "top_padding": "Toppmarg", + "video": "Video", + "video_alt_text": "Alt. tekst", + "video_loop": "Spill av video i loop", + "video_position": "Videoplassering", + "width": "Bredde", + "z_index": "Z-indeks", + "limit_content_width": "Begrens innholdets bredde", + "color_scheme": "Fargepalett", + "inherit_color_scheme": "Arv fargepalett", + "product_count": "Antall produkter", + "product_type": "Produkttype", + "content_width": "Innholdsbredde", + "collection": "Samling", + "enable_sticky_content": "Festet innhold på stasjonær datamaskin", + "error_color": "Feil", + "success_color": "Vellykket", + "primary_font": "Primær skrifttype", + "secondary_font": "Sekundær skrifttype", + "tertiary_font": "Tertiær skrifttype", + "columns": "Kolonner", + "items_to_show": "Varer som skal vises", + "layout": "Layout", + "layout_type": "Type", + "show_grid_layout_selector": "Vis velger for rutenettlayout", + "view_more_show": "Vis Se mer-knapp", + "image_gap": "Bildemellomrom", + "width_desktop": "Bredde på stasjonær datamaskin", + "width_mobile": "Bredde på mobil", + "border_style": "Rammestil", + "height": "Høyde", + "thickness": "Tykkelse", + "stroke": "Strøk", + "filter_style": "Filterstil", + "swatches": "Fargekart", + "quick_add_colors": "Legg til farger raskt", + "divider_color": "Skillelinje", + "border_opacity": "Grenseopasitet", + "hover_background": "Bakgrunn når markøren holdes over", + "hover_borders": "Grenser når markøren holdes over", + "hover_text": "Tekst når markøren holdes over", + "primary_hover_color": "Koblinger når markøren holdes over", + "primary_button_text": "Tekst for primærknapp", + "primary_button_background": "Bakgrunn for primærknapp", + "primary_button_border": "Grense for primærknapp", + "secondary_button_text": "Tekst for sekundær knapp", + "secondary_button_background": "Bakgrunn for sekundær knapp", + "secondary_button_border": "Grense for sekundær knapp", + "shadow_color": "Skygge", + "video_autoplay": "Spill av automatisk", + "video_cover_image": "Forsidebilde", + "video_external_url": "URL-adresse", + "video_source": "Kilde", + "first_row_media_position": "Medieposisjon på første rad", + "card_image_height": "Produktbildehøyde", + "shadow_opacity": "Skyggegjennomsiktighet", + "show_filter_label": "Tekstetiketter for brukte filtre", + "show_swatch_label": "Tekstetiketter for fargekart", + "accordion": "Trekkspill", + "aspect_ratio": "Størrelsesforhold", + "auto_rotate_announcements": "Roter kunngjøringer automatisk", + "auto_rotate_slides": "Roter lysbilder automatisk", + "background_color": "Bakgrunnsfarge", + "badge_corner_radius": "Hjørneradius", + "badge_position": "Plassering på kort", + "badge_sale_color_scheme": "Salg", + "badge_sold_out_color_scheme": "Utsolgt", + "behavior": "Atferd", + "blur": "Uskarphet på skygge", + "border": "Kantlinje", + "bottom": "Bunn", + "carousel_on_mobile": "Karusell på mobil", + "cart_count": "Antall i handlekurven", + "cart_items": "Varer i handlekurven", + "cart_related_products": "Relaterte produkter", + "cart_title": "Handlekurv", + "cart_total": "Totalsum for handlekurv", + "cart_type": "Type", + "case": "Store/små bokstaver", + "checkout_buttons": "Knapper til hurtigkasse", + "collection_list": "Samlinger", + "collection_templates": "Samlingsmaler", + "content": "Innhold", + "corner_radius": "Hjørneradius", + "country_region": "Land/område", + "currency_code": "Valutakode", + "custom_height": "Tilpasset høyde", + "custom_mobile_size": "Tilpasset mobilstørrelse", + "desktop_height": "Høyde på stasjonær datamaskin", + "direction": "Retning", + "display": "Visning", + "divider_thickness": "Tykkelse på skillelinje", + "divider": "Skillelinje", + "dividers": "Skillelinjer", + "drop_shadow": "Skygge", + "empty_state_collection_info": "Vises før et søk legges inn", + "empty_state_collection": "Tom status på samling", + "enable_filtering": "Filtre", + "enable_grid_density": "Kontroll for rutenettlayout", + "enable_sorting": "Sortering", + "enable_zoom": "Aktiver zoom", + "equal_columns": "Like kolonner", + "expand_first_group": "Utvid første gruppe", + "extend_media_to_screen_edge": "Utvid medier til skjermkanten", + "extend_summary": "Utvid til skjermkanten", + "extra_large": "Ekstra stor", + "extra_small": "Ekstra liten", + "fixed_height": "Pikselhøyde", + "fixed_width": "Pikselbredde", + "flag": "Flagg", + "font_price": "Skriftstørrelse for pris", + "font_weight": "Skriftvekt", + "font": "Skrifttype", + "full_width_first_image": "Første bilde i full bredde", + "full_width_on_mobile": "Full bredde på mobil", + "heading_preset": "Forhåndsinnstilling for overskrift", + "hide_padding": "Skjul utfyllingen", + "hide_unselected_variant_media": "Skjul uvalgte variantmedier", + "horizontal_gap": "Horisontalt mellomrom", + "horizontal_offset": "Horisontal forskyving av skygge", + "hover_behavior": "Virkning av bevegelse over", + "icon_background": "Ikonbakgrunn", + "icons": "Ikoner", + "image_border_radius": "Hjørneradius på bilde", + "installments": "Avdrag", + "integrated_button": "Integrert knapp", + "language_selector": "Språkvelger", + "large": "Stor", + "left_padding": "Venstremarg", + "left": "Venstre", + "letter_spacing": "Bokstavavstand", + "limit_media_to_screen_height": "Begrens til skjermens høyde", + "limit_product_details_width": "Begrens produktdetaljers bredde", + "link_preset": "Forhåndsinnstilling for kobling", + "links": "Koblinger", + "logo_font": "Skrifttype for logo", + "logo": "Logo", + "loop": "Gjenta", + "make_details_sticky_desktop": "Festet på stasjonær datamaskin", + "max_width": "Maksbredde", + "media_height": "Mediehøyde", + "media_overlay": "Medieoverlegg", + "media_position": "Medieposisjon", + "media_type": "Medietype", + "media_width": "Mediebredde", + "menu": "Meny", + "mobile_columns": "Mobilkolonner", + "mobile_height": "Mobilhøyde", + "mobile_logo_image": "Mobillogo", + "mobile_quick_add": "Mobil hurtigregistrering", + "motion_direction": "Bevegelsesretning", + "motion": "Bevegelse", + "movement_direction": "Flytteretning", + "navigation_bar_color_scheme": "Fargeskjema for navigasjonsrad", + "navigation_bar": "Navigasjonsrad", + "navigation": "Navigasjon", + "open_new_tab": "Åpne kobling i ny fane", + "overlay_color": "Overleggsfarge", + "overlay": "Overlegg", + "padding_bottom": "Bunnmarg", + "padding_horizontal": "Horisontal marg", + "padding_top": "Toppmarg", + "page_width": "Sidebredde", + "pagination": "Sideinndeling", + "percent_height": "Prosenthøyde", + "percent_size_mobile": "Prosentstørrelse", + "percent_size": "Prosentstørrelse", + "percent_width": "Prosentbredde", + "pixel_size_mobile": "Pikselstørrelse", + "pixel_size": "Pikselstørrelse", + "placement": "Plassering", + "position": "Posisjon", + "preset": "Forhåndsinnstilling", + "product_cards": "Produktkort", + "product_pages": "Produktsider", + "product_templates": "Produktmaler", + "products": "Produkter", + "quick_add": "Hurtigregistrering", + "ratio": "Forhold", + "regular": "Vanlig", + "review_count": "Antall anmeldelser", + "right": "Høyre", + "row_height": "Radhøyde", + "row": "Rad", + "seller_note": "Tillat merknad til selger", + "shape": "Form", + "show_as_accordion": "Vis som trekkspill på mobil", + "show_sale_price_first": "Vis salgspris først", + "show_tax_info": "Skatteinformasjon", + "show": "Vis", + "size_mobile": "Mobilstørrelse", + "small": "Liten", + "speed": "Hastighet", + "statement": "Sammendrag", + "sticky_header": "Festet topptekst", + "text_hierarchy": "Teksthierarki", + "text_presets": "Forhåndsinnstillinger for tekst", + "title": "Tittel", + "top": "Topp", + "type": "Type", + "type_preset": "Forhåndsinnstillinger for tekst", + "underline_thickness": "Tykkelse på understrekning", + "unit": "Enhet", + "variant_images": "Variantbilder", + "vendor": "Selger", + "vertical_gap": "Vertikalt mellomrom", + "vertical_offset": "Vertikal forskyving av skygge", + "vertical_on_mobile": "Vertikalt på mobil", + "view_all_as_last_card": "«Vis alle» som siste kort", + "weight": "Vekt", + "wrap": "Tekstbryting", + "read_only": "Skrivebeskyttet", + "always_stack_buttons": "Knapper skal alltid stables", + "custom_mobile_width": "Egendefinert mobilbredde", + "gradient_direction": "Gradientretning", + "headings": "Overskrifter", + "overlay_style": "Overleggstil", + "transparent_background": "Gjennomsiktig bakgrunn", + "account": "Konto", + "align_baseline": "Juster tekstgrunnlinjen", + "add_discount_code": "Tillat rabatter i handlekurv", + "background_overlay": "Bakgrunnsoverlegg", + "background_media": "Bakgrunnsmedier", + "border_thickness": "Tykkelse på kantlinje", + "bottom_row": "Bunnrad", + "button_text_case": "Bruk av store og små bokstaver", + "button_text_weight": "Tekstvekt", + "card_size": "Kortstørrelse", + "auto_open_cart_drawer": "«Legg til i handlekurven» åpner skuffen automatisk", + "collection_count": "Samlingsantall", + "collection_title_case": "Eske til samlingstittel", + "custom_liquid": "Liquid-kode", + "default": "Standard", + "default_logo": "Standardlogo", + "divider_width": "Skillelinjebredde", + "hide_logo_on_home_page": "Skjul logo på startside", + "horizontal_padding": "Horisontal utfylling", + "inverse": "Omvendt", + "inverse_logo": "Omvendt logo", + "layout_style": "Stil", + "length": "Lengde", + "mobile_card_size": "Mobilkortstørrelse", + "mobile_pagination": "Mobilinndeling", + "open_row_by_default": "Åpne rad som standard", + "page": "Side", + "page_transition_enabled": "Sideovergang", + "product_and_card_title_case": "Eske til produkt og korttittel", + "product_title_case": "Eske til produkttittel", + "right_padding": "Høyremarg", + "search": "Søk", + "search_icon": "Søkeikon", + "search_position": "Posisjon", + "search_row": "Rad", + "show_author": "Forfatter", + "show_alignment": "Vis justeringen", + "show_count": "Vis antall", + "show_date": "Dato", + "show_pickup_availability": "Vis hentetilgjengelighet", + "show_search": "Vis søk", + "text_label_case": "Eske til tekstetikett", + "use_inverse_logo": "Bruk omvendt logo", + "vertical_padding": "Vertikal utfylling", + "visibility": "Synlighet", + "product_corner_radius": "Hjørneradius på produkt", + "card_corner_radius": "Hjørneradius på kort", + "alignment_mobile": "Justering på mobil", + "animation_repeat": "Gjenta animasjon", + "blurred_reflection": "Uskarp refleksjon", + "card_hover_effect": "Musepekereffekt på kort", + "effects": "Effekter", + "inventory_threshold": "Terskel for lav lagerbeholdning", + "reflection_opacity": "Refleksjonsopasitet", + "show_inventory_quantity": "Vis lav lagerbeholdning", + "transition_to_main_product": "Overgang fra produktkort til produktside", + "show_second_image_on_hover": "Vis sekundærbilde når musepekeren beveges over", + "media": "Medier", + "product_card_carousel": "Vis karusell", + "media_fit": "Mediepassform", + "scroll_speed": "Rull til neste kunngjøring" + }, + "options": { + "adapt_to_image": "Tilpass til bilde", + "apple": "Eple", + "arrow": "Pil", + "auto": "Automatisk", + "banana": "Banan", + "bottle": "Flaske", + "box": "Boks", + "buttons": "Knapper", + "carrot": "Gulrot", + "center": "Sentrert", + "chat_bubble": "Chatboble", + "clipboard": "Skriveplater", + "contain": "Inneholde", + "counter": "Teller", + "cover": "Forside", + "custom": "Tilpasset", + "dairy_free": "Melkefritt", + "dairy": "Meierivarer", + "default": "Standard", + "dropdowns": "Rullegardinmenyer", + "dots": "Prikker", + "dryer": "Tørker", + "end": "Slutt", + "eye": "Øye", + "facebook": "Facebook", + "fill": "Fyll", + "fire": "Brann", + "fit": "Tilpasning", + "full": "Full", + "full_and_page": "Full bakgrunn, innhold i sidebredde", + "gluten_free": "Glutenfri", + "heading": "Overskrift", + "heart": "Hjerte", + "horizontal": "Horisontalt", + "instagram": "Instagram", + "iron": "Jern", + "landscape": "Landskap", + "large": "Stor", + "leaf": "Blad", + "leather": "Skinn", + "lg": "LG", + "lightning_bolt": "Lyn", + "link": "Kobling", + "lipstick": "Leppestift", + "lock": "Lås", + "lowercase": "liten bokstav", + "m": "M", + "map_pin": "Kartpinne", + "medium": "Medie", + "none": "Ingen", + "numbers": "Tall", + "nut_free": "Nøttefri", + "outline": "Omriss", + "page": "Side", + "pants": "Bukser", + "paw_print": "Potetrykk", + "pepper": "Pepper", + "perfume": "Parfyme", + "pinterest": "Pinterest", + "plane": "Fly", + "plant": "Plante", + "portrait": "Portrett", + "price_tag": "Prislapp", + "question_mark": "Spørsmålstegn", + "recycle": "Resirkuler", + "return": "Retur", + "ruler": "Linjal", + "s": "S", + "sentence": "Setning", + "serving_dish": "Serveringsfat", + "shirt": "Skjorte", + "shoe": "Sko", + "silhouette": "Silhuett", + "small": "Liten", + "snapchat": "Snapchat", + "snowflake": "Snøkrystall", + "solid": "Fylt", + "space_between": "Mellomrom mellom", + "square": "Firkantet", + "star": "Stjerne", + "start": "Start", + "stopwatch": "Stoppeklokke", + "tiktok": "TikTok", + "truck": "Varebil", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Store bokstaver", + "vertical": "Vertikalt", + "vimeo": "Vimeo", + "washing": "Vasking", + "circle": "Sirkel", + "swatches": "Fargekart", + "full_and_page_offset_left": "Full bakgrunn, innhold i sidebredde, justert mot venstre", + "full_and_page_offset_right": "Full bakgrunn, innhold i sidebredde, justert mot høyre", + "offset_left": "Justert mot venstre", + "offset_right": "Justert mot høyre", + "page_center_aligned": "Side, midtjustert", + "page_left_aligned": "Side, justert mot venstre", + "page_right_aligned": "Side, justert mot høyre", + "button": "Knapp", + "caption": "Bildetekst", + "h1": "Overskrift 1", + "h2": "Overskrift 2", + "h3": "Overskrift 3", + "h4": "Overskrift 4", + "h5": "Overskrift 5", + "h6": "Overskrift 6", + "paragraph": "Avsnitt", + "primary": "Primær", + "secondary": "Sekundær", + "tertiary": "Tertiær", + "chevron_left": "Større enn", + "chevron_right": "Mindre enn", + "diamond": "Diamant", + "grid": "Rutenett", + "parallelogram": "Parallellogram", + "rounded": "Avrundet", + "fit_content": "Tilpasning", + "pills": "Piller", + "heavy": "Tung", + "thin": "Tynn", + "drawer": "Skuff", + "preview": "Forhåndsvis", + "text": "Tekst", + "video_uploaded": "Lastet opp", + "video_external_url": "Ekstern URL-adresse", + "aspect_ratio": "Størrelsesforhold", + "fixed": "Fast", + "pixel": "Piksel", + "percent": "Prosent", + "above_carousel": "Over karusell", + "all": "Alle", + "up": "Opp", + "down": "Ned", + "always": "Alltid", + "arrows_large": "Store piler", + "arrows": "Piler", + "balance": "Saldo", + "bento": "Bento", + "black": "Svart", + "bluesky": "Bluesky", + "body_large": "Brødtekst (stor)", + "body_regular": "Brødtekst (vanlig)", + "body_small": "Brødtekst (liten)", + "bold": "Fet", + "bottom_left": "Nederst til venstre", + "bottom_right": "Nederst til høyre", + "bottom": "Bunn", + "capitalize": "Store bokstaver", + "caret": "Aksenttegn (caret)", + "carousel": "Karusell", + "check_box": "Avmerkingsboks", + "chevron_large": "Store sjevroner", + "chevron": "Sjevron", + "chevrons": "Sjevroner", + "classic": "Klassisk", + "collection_images": "Samlingsbilder", + "color": "Farge", + "complementary": "Komplementær", + "dissolve": "Gå jevnt over i hverandre", + "dotted": "Prikker", + "editorial": "Redaksjonell", + "extra_large": "Ekstra stor", + "extra_small": "Ekstra liten", + "featured_collections": "Fremhevede samlinger", + "featured_products": "Utvalgte produkter", + "font_primary": "Primær", + "font_secondary": "Sekundær", + "font_tertiary": "Tertiær", + "forward": "Frem", + "full_screen": "Fullskjerm", + "gradient": "Fargeovergang", + "heading_extra_large": "Overskrift (ekstra stor)", + "heading_extra_small": "Overskrift (ekstra liten)", + "heading_large": "Overskrift (stor)", + "heading_regular": "Overskrift (normal)", + "heading_small": "Overskrift (liten)", + "icon": "Ikon", + "image": "Bilde", + "input": "Inndata", + "inside_carousel": "Inne i karusell", + "inverse_large": "Omvendt stor", + "inverse": "Omvendt", + "large_arrows": "Store piler", + "large_chevrons": "Store sjevroner", + "left": "Venstre", + "light": "Lys", + "linkedin": "LinkedIn", + "loose": "Løs", + "media_first": "Medier først", + "media_second": "Medier som nummer to", + "modal": "Modal", + "narrow": "Smal", + "never": "Aldri", + "next_to_carousel": "Ved siden av karusell", + "normal": "Normal", + "nowrap": "Ingen tekstbryting", + "off_media": "Medier på", + "on_media": "Medier av", + "on_scroll_up": "Ved rulling oppover", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Pille", + "plus": "Plus", + "pretty": "Pent", + "price": "Pris", + "primary_style": "Primærstil", + "rectangle": "Rektangel", + "regular": "Vanlig", + "related": "Relatert", + "reverse": "Omvendt", + "rich_text": "Rik tekst", + "right": "Høyre", + "secondary_style": "Sekundærstil", + "semibold": "Halvfet", + "shaded": "Skyggelagt", + "show_second_image": "Vis bilde nummer 2", + "single": "Enkel", + "slide_left": "Bla til venstre", + "slide_up": "Bla opp", + "spotify": "Spotify", + "stack": "Stabel", + "text_only": "Kun tekst", + "threads": "Threads", + "thumbnails": "Miniatyrbilder", + "tight": "Tett", + "top_left": "Øverst til venstre", + "top_right": "Øverst til høyre", + "top": "Topp", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Understreking", + "video": "Video", + "wide": "Bred", + "youtube": "YouTube", + "accent": "Aksent", + "below_image": "Under bildet", + "body": "Brødtekst", + "button_primary": "Primærknapp", + "button_secondary": "Sekundær knapp", + "compact": "Kompakt", + "crop_to_fit": "Tilpass", + "hidden": "Skjult", + "hint": "Hint", + "maintain_aspect_ratio": "Oppretthold størrelsesforholdet", + "off": "Av", + "on_image": "På bildet", + "social_bluesky": "Sosiale medier: Bluesky", + "social_facebook": "Sosiale medier: Facebook", + "social_instagram": "Sosiale medier: Instagram", + "social_linkedin": "Sosiale medier: LinkedIn", + "social_pinterest": "Sosiale medier: Pinterest", + "social_snapchat": "Sosiale medier: Snapchat", + "social_spotify": "Sosiale medier: Spotify", + "social_threads": "Sosiale medier: Threads", + "social_tiktok": "Sosiale medier: TikTok", + "social_tumblr": "Sosiale medier: Tumblr", + "social_twitter": "Sosiale medier: X (Twitter)", + "social_whatsapp": "Sosiale medier: WhatsApp", + "social_vimeo": "Sosiale medier: Vimeo", + "social_youtube": "Sosiale medier: YouTube", + "spotlight": "Spotlight", + "standard": "Standard", + "subheading": "Underoverskrift", + "blur": "Uklarhet", + "lift": "Løft", + "reveal": "Avsløring", + "scale": "Skala", + "subtle_zoom": "Zoom" + }, + "content": { + "advanced": "Avansert", + "background_image": "Bakgrunnsbilde", + "background_video": "Bakgrunnsvideo", + "block_size": "Blokkstørrelse", + "borders": "Rammer", + "describe_the_video_for": "Beskriv videoen for kunder som bruker skjermlesere. [Finn ut mer](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Seksjonsstørrelse", + "slideshow_width": "Lysbildebredde", + "typography": "Typografi", + "width_is_automatically_optimized": "Bredden optimaliseres automatisk for mobil.", + "complementary_products": "Tilleggsprodukter må konfigureres ved hjelp av Search & Discovery-appen. [Finn ut mer](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Kolonner optimaliseres automatisk for mobil", + "content_width": "Innholdsbredden gjelder bare når seksjonsbredden er angitt til full bredde.", + "adjustments_affect_all_content": "Gjelder alt innhold i denne blokken", + "responsive_font_sizes": "Størrelser skaleres automatisk for alle skjermstørrelser", + "buttons": "Knapper", + "swatches": "Fargekart", + "variant_settings": "Variantinnstillinger", + "background": "Bakgrunn", + "appearance": "Utseende", + "arrows": "Piler", + "body_size": "Størrelse på hovedinnhold", + "mobile_size": "Mobilstørrelse", + "bottom_row_appearance": "Utseende på nederste rad", + "cards_layout": "Layout for kort", + "carousel_navigation": "Karusellnavigasjon", + "carousel_pagination": "Sideinndeling på karusell", + "copyright": "Opphavsrett", + "edit_logo_in_theme_settings": "Rediger logo i [temainnstillinger](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Rediger prisformatering i [temainnstillinger](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Rediger variantstyling i [temainnstillinger](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Legg til registreringer [av kundeprofiler](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "For at knappen skal vises, må Shop-kanalen være installert og Shop Pay aktivert. [Finn ut mer](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Skrifttyper", + "grid": "Rutenett", + "heading_size": "Overskriftsstørrelse", + "image": "Bilde", + "input": "Inndata", + "layout": "Layout", + "link": "Kobling", + "link_padding": "Marg rundt kobling", + "localization": "Lokal tilpasning", + "logo": "Logo", + "margin": "Margin", + "media": "Medier", + "media_1": "Medium 1", + "media_2": "Medium 2", + "menu": "Meny", + "mobile_layout": "Mobillayout", + "padding": "Marg", + "padding_desktop": "Marg på stasjonær datamaskin", + "paragraph": "Avsnitt", + "policies": "Retningslinjer", + "popup": "Popup", + "search": "Søk", + "section_layout": "Layout for seksjon", + "size": "Størrelse", + "social_media": "Sosiale medier", + "submit_button": "Send inn-knapp", + "text_presets": "Forhåndsinnstillinger for tekst", + "transparent_background": "Gjennomsiktig bakgrunn", + "typography_primary": "Primær typografi", + "typography_secondary": "Sekundær typografi", + "typography_tertiary": "Tertiær typografi", + "mobile_width": "Mobilbredde", + "width": "Bredde", + "images": "Bilder", + "carousel": "Karusell", + "colors": "Farger", + "collection_page": "Samlingside", + "copyright_info": "Finn ut hvordan du [redigerer opphavsrettserklæringen](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Kundekonto", + "edit_empty_state_collection_in_theme_settings": "Rediger samling i tom tilstand i [temainnstillinger](/editor?context=theme&category=search)", + "grid_layout": "Layout i rutenett", + "home_page": "Startside", + "inverse_logo_info": "Brukes når gjennomsiktig topptekstbakgrunn er satt til Invers", + "manage_customer_accounts": "[Administrer synlighet](/admin/settings/customer_accounts) i kundekontoinnstillingene. Eldre kontoer støttes ikke.", + "manage_policies": "[Administrer retningslinjer](/admin/settings/legal)", + "product_page": "Produktside", + "text": "Tekst", + "thumbnails": "Miniatyrbilder", + "visibility": "Synlighet", + "visible_if_collection_has_more_products": "Synlig hvis samlingen har flere produkter enn det som vises", + "app_required_for_ratings": "En app kreves for produktanmeldelser. [Finn ut mer](https://help.shopify.com/manual/apps)", + "icon": "Ikon", + "manage_store_name": "[Administrer butikknavnet](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Viser samling fra overordnet seksjon", + "resource_reference_collection_card_image": "Viser bilde fra overordnet samling", + "resource_reference_collection_title": "Viser tittel fra overordnet samling", + "resource_reference_product": "Kobler automatisk til overordnet produkt", + "resource_reference_product_card": "Viser produkt fra overordnet seksjon", + "resource_reference_product_inventory": "Viser lagerbeholdning fra overordnet produkt", + "resource_reference_product_price": "Viser pris fra overordnet produkt", + "resource_reference_product_recommendations": "Viser anbefalinger basert på overordnet produkt", + "resource_reference_product_review": "Viser anmeldelser fra overordnet produkt", + "resource_reference_product_swatches": "Viser fargekart fra overordnet produkt", + "resource_reference_product_title": "Viser tittel fra overordnet produkt", + "resource_reference_product_variant_picker": "Viser varianter fra overordnet produkt", + "resource_reference_product_media": "Viser medier fra overordnet produkt", + "product_media": "Produktmedier", + "section_link": "Seksjonslenke" + }, + "html_defaults": { + "share_information_about_your": "

Del informasjon om merkevaren din med kundene. Beskriv et produkt, gjør kunngjøringer eller ønsk kundene velkommen til butikken.

" + }, + "text_defaults": { + "button_label": "Shop nå", + "collapsible_row": "Sammenleggbar rad", + "heading": "Overskrift", + "email_signup_button_label": "Abonner", + "be_bold": "Vær modig.", + "accordion_heading": "Overskrift for trekkspill", + "contact_form_button_label": "Send inn", + "popup_link": "Popup-kobling", + "sign_up": "Registrer deg", + "welcome_to_our_store": "Velkommen til butikken vår", + "shop_our_latest_arrivals": "Kjøp nyhetene våre!" + }, + "info": { + "carousel_layout_on_mobile": "Karusell er brukt på mobil", + "link_info": "Valgfritt: Det gjør ikonet klikkbart", + "video_alt_text": "Beskriv videoen for personer som bruker hjelpeteknologi", + "video_autoplay": "Videolyden er slått av som standard", + "video_external": "Bruk en YouTube- eller Vimeo-URL-adresse", + "carousel_hover_behavior_not_supported": "Funksjonen med å holde markøren over «Karusell» støttes ikke når «Karusell»-typen er valgt på seksjonsnivå", + "checkout_buttons": "Lar kjøpere betale raskere og kan forbedre konverteringen. [Finn ut mer](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Egendefinert overskrift", + "edit_presets_in_theme_settings": "Rediger forhåndsinnstillinger i [temainnstillinger](/editor?context=theme&category=typography)", + "enable_filtering_info": "Tilpass filtre med [Search & Discovery-appen](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Rutenettlayout brukes for mobil", + "logo_font": "Brukes bare når det ikke er valgt en logo", + "manage_countries_regions": "[Administrer land/områder](/admin/settings/markets)", + "manage_languages": "[Administrer språk](/admin/settings/languages)", + "transparent_background": "Se gjennom hver mal der gjennomsiktig bakgrunn er brukt for lesbarhet", + "aspect_ratio_adjusted": "Justert i noen layouts", + "auto_open_cart_drawer": "Når dette er aktivert, åpnes handlekurvskuffen automatisk når et produkt legges til i handlekurven.", + "custom_liquid": "Legg til app-kodeutdrag eller en annen kode for å opprette avanserte tilpasninger. [Finn ut mer](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Brukes for anvendte filtre, rabattkoder og søkeforslag", + "applies_on_image_only": "Gjelder bare bilder", + "hover_effects": "Gjelder produkt- og samlingskort" + }, + "categories": { + "product_list": "Utvalgt kolleksjon", + "basic": "Basic", + "collection": "Samling", + "collection_list": "Liste over samlinger", + "footer": "Bunntekst", + "forms": "Skjemaer", + "header": "Topptekst", + "layout": "Layout", + "links": "Koblinger", + "product": "Produkt", + "banners": "Bannere", + "collections": "Samlinger", + "custom": "Tilpasset", + "decorative": "Dekorativ", + "products": "Produkter", + "other_sections": "Annet", + "storytelling": "Historiefortelling" + } +} diff --git a/locales/nl.json b/locales/nl.json new file mode 100644 index 000000000..dee5bb460 --- /dev/null +++ b/locales/nl.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Video laden: {{ description }}", + "sold_out": "Uitverkocht", + "email_signup": { + "label": "E-mail", + "placeholder": "E-mailadres", + "success": "Bedankt dat je abonnee bent geworden!" + }, + "filter": "Filter", + "payment_methods": "Betaalmethoden", + "contact_form": { + "name": "Naam", + "email": "E-mail", + "phone": "Telefoonnummer", + "comment": "Reactie", + "post_success": "Bedankt dat je contact met ons hebt opgenomen. Je hoort zo snel mogelijk van ons.", + "error_heading": "Pas het volgende aan:" + } + }, + "accessibility": { + "play_model": "3D-model afspelen", + "play_video": "Video afspelen", + "unit_price": "Eenheidsprijs", + "country_results_count": "{{ count }} resultaten", + "slideshow_pause": "Diavoorstelling pauzeren", + "slideshow_play": "Diavoorstelling afspelen", + "remove_item": "{{ title}} verwijderen", + "skip_to_text": "Ga direct naar de content", + "skip_to_product_info": "Ga direct naar de productinformatie", + "skip_to_results_list": "Meteen naar lijst met resultaten", + "new_window": "Wordt geopend in een nieuw venster.", + "slideshow_next": "Volgende dia", + "slideshow_previous": "Vorige dia", + "close_dialog": "Dialoogvenster sluiten", + "reset_search": "Zoekactie opnieuw instellen", + "search_results_count": "{{ count }} zoekresultaten gevonden voor '{{ query }}'", + "search_results_no_results": "Geen resultaten gevonden voor '{{ query }}'", + "filters": "Filters", + "filter_count": { + "one": "{{ count }} filter toegepast", + "other": "{{ count }} filters toegepast" + }, + "account": "Accountmenu openen", + "cart": "Winkelwagen", + "cart_count": "Totaal aantal artikelen in winkelwagen", + "menu": "Menu", + "country_region": "Land/regio", + "slide_status": "Dia {{ index }} van {{ length }}", + "scroll_to": "Scrol naar {{ title }}", + "loading_product_recommendations": "Productaanbevelingen laden", + "discount": "Kortingscode toepassen", + "discount_applied": "Toegepaste kortingscode: {{ code }}", + "open_cart_drawer": "Winkelwagen openen", + "inventory_status": "Voorraadstatus", + "pause_video": "Video pauzeren", + "find_country": "Land zoeken", + "localization_region_and_language": "Regio- en taalkiezer openen", + "open_search_modal": "Zoeken openen", + "decrease_quantity": "Aantal verlagen", + "increase_quantity": "Aantal verhogen", + "quantity": "Aantal", + "rating": "Beoordeling van dit product is {{ rating }} van 5", + "nested_product": "{{ product_title }} voor {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Aan winkelwagen toevoegen", + "clear_all": "Alles wissen", + "remove": "Verwijderen", + "view_in_your_space": "In ruimte bekijken", + "show_filters": "Filter", + "clear": "Wissen", + "continue_shopping": "Doorgaan met winkelen", + "log_in_html": "Heb je een account? Log in om sneller af te rekenen.", + "see_items": { + "one": "{{ count }} artikel weergeven", + "other": "{{ count }} artikelen weergeven" + }, + "view_all": "Alles bekijken", + "add": "Toevoegen", + "choose": "Kiezen", + "added": "Toegevoegd", + "show_less": "Minder weergeven", + "show_more": "Meer weergeven", + "close": "Sluiten", + "more": "Meer", + "reset": "Opnieuw instellen", + "zoom": "Zoomen", + "close_dialog": "Dialoogvenster sluiten", + "back": "Terug", + "log_in": "Inloggen", + "log_out": "Uitloggen", + "remove_discount": "Kortingscode {{ code }} verwijderen", + "enter_using_password": "Ga naar binnen met wachtwoord", + "submit": "Indienen", + "enter_password": "Wachtwoord invoeren", + "view_store_information": "Winkelgegevens bekijken", + "apply": "Toepassen", + "sign_in_options": "Andere inlogopties", + "sign_up": "Aanmelden", + "open_image_in_full_screen": "Afbeelding openen in volledig scherm", + "sort": "Sorteren", + "show_all_options": "Alle opties tonen" + }, + "content": { + "reviews": "recensies", + "no_results_found": "Geen resultaten gevonden", + "language": "Taal", + "localization_region_and_language": "Regio en taal", + "cart_total": "Totaal van de winkelwagen", + "your_cart_is_empty": "Je winkelwagen is leeg", + "product_image": "Productafbeelding", + "product_information": "Productinformatie", + "quantity": "Aantal", + "product_total": "Totaal product", + "cart_estimated_total": "Geschat totaal", + "seller_note": "Speciale instructies", + "cart_subtotal": "Subtotaal", + "discounts": "Kortingen", + "discount": "Korting", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Douanerechten en belastingen inbegrepen. Kortingen en verzending worden bij de checkout berekend.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Douanerechten en belastingen inbegrepen. Kortingen en verzending worden bij de checkout berekend.", + "taxes_included_shipping_at_checkout_with_policy_html": "Belastingen inbegrepen. Kortingen en verzending worden bij de checkout berekend.", + "taxes_included_shipping_at_checkout_without_policy": "Belastingen inbegrepen. Kortingen en verzending worden bij de checkout berekend.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Douanerechten inbegrepen. Belastingen, kortingen en verzending worden bij de checkout berekend.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Douanerechten inbegrepen. Belastingen, kortingen en verzending worden bij de checkout berekend.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Belastingen, kortingen en verzending worden bij de checkout berekend.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Belastingen, kortingen en verzending worden bij de checkout berekend.", + "checkout": "Afrekenen", + "cart_title": "Winkelwagen", + "price": "Prijs", + "price_regular": "Normale prijs", + "price_compare_at": "Vergelijkingsprijs", + "price_sale": "Prijs met korting", + "duties_and_taxes_included": "Douanerechten en belastingen inbegrepen.", + "duties_included": "Douanerechten inbegrepen.", + "shipping_policy_html": "Verzendkosten worden berekend bij de checkout.", + "taxes_included": "Belastingen inbegrepen.", + "product_badge_sold_out": "Uitverkocht", + "product_badge_sale": "Uitverkoop", + "search_input_label": "Zoeken", + "search_input_placeholder": "Zoekopdracht", + "search_results": "Zoekresultaten", + "search_results_label": "Zoekresultaten", + "search_results_no_results": "Geen resultaten gevonden voor '{{ terms }}'. Probeer een andere zoekopdracht.", + "search_results_resource_articles": "Blogposts", + "search_results_resource_collections": "Collecties", + "search_results_resource_pages": "Pagina's", + "search_results_resource_products": "Producten", + "search_results_resource_queries": "Zoeksuggesties", + "search_results_view_all": "Alles bekijken", + "search_results_view_all_button": "Alles bekijken", + "search_results_resource_products_count": { + "one": "{{ count }} product", + "other": "{{ count }} producten" + }, + "grid_view": { + "default_view": "Standaard", + "grid_fieldset": "Kolomgrid", + "single_item": "Eén", + "zoom_out": "Uitzoomen" + }, + "recently_viewed_products": "Recent beoordeeld", + "unavailable": "Niet beschikbaar", + "collection_placeholder": "Titel collectie", + "product_card_placeholder": "Producttitel", + "product_count": "Aantal producten", + "item_count": { + "one": "{{ count }} artikel", + "other": "{{ count }} artikelen" + }, + "errors": "Fouten", + "price_from": "Vanaf {{ price }}", + "search": "Zoekopdracht", + "search_results_no_results_check_spelling": "Geen resultaten gevonden voor '{{ terms }}'. Controleer de spelling of gebruik een ander woord of een andere zin.", + "featured_products": "Uitgelichte producten", + "filters": "Filters", + "no_products_found": "Geen producten gevonden.", + "price_filter_html": "De hoogste prijs is {{ price }}", + "use_fewer_filters_html": "Probeer minder filters te gebruiken of wis alle filters.", + "blog_details_separator": "|", + "read_more": "Meer informatie...", + "account_title": "Account", + "account_title_personalized": "Hallo {{ first_name }}", + "account_orders": "Bestellingen", + "account_profile": "Profiel", + "discount_code": "Kortingscode", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Douanerechten en belastingen inbegrepen. Verzendkosten worden berekend bij de checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Douanerechten en belastingen inbegrepen. Verzendkosten worden berekend bij de checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Douanerechten inbegrepen. Verzendkosten worden berekend bij de checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Douanerechten inbegrepen. Verzendkosten worden berekend bij de checkout.", + "pickup_available_at_html": "Afhalen is mogelijk op {{ location }}", + "pickup_available_in": "Afhalen mogelijk, {{ pickup_time }}", + "pickup_not_available": "Afhalen is op dit moment niet beschikbaar", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Belastingen en verzendkosten worden berekend bij de checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Belastingen en verzendkosten worden berekend bij de checkout.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Belastingen inbegrepen. Verzendkosten worden berekend bij de checkout.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Belastingen inbegrepen. Verzendkosten worden berekend bij de checkout.", + "wrong_password": "Wachtwoord onjuist", + "view_more_details": "Meer gegevens bekijken", + "page_placeholder_title": "Paginatitel", + "page_placeholder_content": "Selecteer een pagina om de content weer te geven.", + "placeholder_image": "Afbeelding tijdelijke aanduiding", + "inventory_low_stock": "Voorraad laag", + "inventory_in_stock": "Op voorraad", + "inventory_out_of_stock": "Niet op voorraad", + "inventory_low_stock_show_count": { + "one": "{{ count }} over", + "other": "{{ count }} over" + }, + "shipping_policy": "Verzendkosten worden berekend bij de checkout.", + "shipping_discount_error": "Verzendkortingen worden bij de checkout getoond nadat het adres is ingevoerd", + "discount_code_error": "Kortingscode kan niet worden toegepast op je winkelwagen", + "powered_by": "Deze winkel wordt mogelijk gemaakt door", + "store_owner_link_html": "Ben jij de winkeleigenaar? Log hier in" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Gebruik de cadeauboncode online of de QR-code in de winkel", + "title": "Dit is het saldo van de cadeaubon ter waarde van {{ value }} voor {{ shop }}", + "subtext": "Je cadeaubon", + "shop_link": "Webshop bezoeken", + "add_to_apple_wallet": "Aan Apple Wallet toevoegen", + "qr_image_alt": "QR-code — scan om cadeaubon te verzilveren", + "copy_code": "Cadeauboncode kopiëren", + "expiration_date": "Verloopt op {{ expires_on }}", + "copy_code_success": "Code gekopieerd", + "expired": "Verlopen" + } + }, + "placeholders": { + "password": "Wachtwoord", + "search": "Zoeken", + "product_title": "Producttitel", + "collection_title": "Collectietitel" + }, + "products": { + "product": { + "add_to_cart": "Aan winkelwagen toevoegen", + "adding_to_cart": "Toevoegen...", + "added_to_cart": "Toegevoegd aan winkelwagen", + "add_to_cart_error": "Fout bij het toevoegen aan de winkelwagen", + "sold_out": "Uitverkocht", + "unavailable": "Niet beschikbaar" + } + }, + "fields": { + "separator": "aan" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} reactie", + "other": "{{ count }} reacties" + } + }, + "comment_form": { + "email": "E-mail", + "error": "Reactie kan niet worden geplaatst, controleer het volgende:", + "heading": "Reactie plaatsen", + "message": "Bericht", + "moderated": "Let op: Reacties worden pas na goedkeuring gepubliceerd.", + "name": "Naam", + "post": "Reactie plaatsen", + "success_moderated": "Reactie geplaatst, in afwachting van moderatie", + "success": "Reactie geplaatst" + } + } +} diff --git a/locales/nl.schema.json b/locales/nl.schema.json new file mode 100644 index 000000000..8147422f6 --- /dev/null +++ b/locales/nl.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Grenzen", + "collapsible_row": "Inklapbare rij", + "custom_section": "Aangepaste sectie", + "icon": "Pictogram", + "logo_and_favicon": "Logo en favicon", + "product_buy_buttons": "Koopknoppen", + "product_description": "Beschrijving", + "product_price": "Prijs", + "slideshow": "Diavoorstelling", + "typography": "Typografie", + "video": "Video", + "colors": "Kleuren", + "overlapping_blocks": "Overlappende blokken", + "product_variant_picker": "Variantkiezer", + "slideshow_controls": "Knoppen voor diavoorstelling", + "size": "Grootte", + "spacing": "Afstand", + "product_recommendations": "Aanbevolen producten", + "product_media": "Productmedia", + "featured_collection": "Uitgelichte collectie", + "add_to_cart": "Aan winkelwagen toevoegen", + "email_signup": "Aanmelding voor het ontvangen van e-mail", + "submit_button": "Knop voor indienen", + "grid_layout_selector": "Grid-indelingskiezer", + "image": "Afbeelding", + "list_items": "Items in de lijst", + "facets": "Filters", + "variants": "Varianten", + "product_cards": "Productkaarten", + "styles": "Stijlen", + "buttons": "Knoppen", + "inputs": "Invoer", + "primary_button": "Primaire knop", + "secondary_button": "Secundaire knop", + "popovers": "Pop-overs", + "marquee": "Marquee", + "alternating_content_rows": "Afwisselende rijen", + "product_list": "Uitgelichte collectie", + "spacer": "Opvulling", + "products_carousel": "Uitgelichte collectie: Carrousel", + "products_grid": "Uitgelichte collectie: Raster", + "pull_quote": "Citaat ophalen", + "contact_form": "Contactformulier", + "featured_product": "Uitgelichte producten", + "icons_with_text": "Pictogrammen met tekst", + "accelerated_checkout": "Versnelde checkout", + "accordion": "Accordeon", + "accordion_row": "Accordeon-rij", + "animations": "Animaties", + "announcement": "Aankondiging", + "announcement_bar": "Aankondigingsbalk", + "badges": "Badges", + "button": "Knop", + "cart": "Winkelwagen", + "cart_items": "Artikelen in winkelwagen", + "cart_products": "Producten in winkelwagen", + "cart_title": "Winkelwagen", + "collection": "Collectie", + "collection_card": "Collectiekaart", + "collection_columns": "Collectiekolommen", + "collection_container": "Collectie", + "collection_description": "Collectiebeschrijving", + "collection_image": "Collectie-afbeelding", + "collection_info": "Collectiegegevens", + "collection_list": "Collectielijst", + "collections": "Collecties", + "content": "Content", + "content_grid": "Content-grid", + "details": "Gegevens", + "divider": "Scheidingslijn", + "filters": "Filteren en sorteren", + "follow_on_shop": "Volgen op Shop", + "footer": "Voettekst", + "footer_utilities": "Voettekst hulpprogramma's", + "group": "Groep", + "header": "Koptekst", + "heading": "Koptekst", + "icons": "Pictogrammen", + "image_with_text": "Afbeelding met tekst", + "input": "Invoer", + "jumbo_text": "Jumbo-tekst", + "logo": "Logo", + "magazine_grid": "Tijdschrift-grid", + "media": "Media", + "menu": "Menu", + "mobile_layout": "Opmaak voor mobiel", + "payment_icons": "Betalingspictogrammen", + "popup_link": "Pop-uplink", + "predictive_search": "Popover voor zoeken", + "predictive_search_empty": "Voorspellende zoekopdracht leeg", + "price": "Prijs", + "product": "Product", + "product_card": "Productkaart", + "product_card_media": "Media", + "product_card_rendering": "Rendering productkaarten", + "product_grid": "Grid", + "product_grid_main": "Productgrid", + "product_image": "Productafbeelding", + "product_information": "Productinformatie", + "product_review_stars": "Reviewsterren", + "quantity": "Aantal", + "row": "Rij", + "search": "Zoekopdracht", + "section": "Sectie", + "selected_variants": "Geselecteerde varianten", + "shop_the_look": "Shop the look", + "slide": "Dia", + "social_media_links": "Links naar social media", + "steps": "Stappen", + "summary": "Overzicht", + "swatches": "Stalen", + "testimonials": "Getuigenissen", + "text": "Tekst", + "title": "Titel", + "utilities": "Hulpprogramma's", + "search_input": "Input zoeken", + "search_results": "Zoekresultaten", + "read_only": "Alleen lezen", + "collection_title": "Titel collectie", + "collections_bento": "Collectielijst: Bento", + "faq_section": "Veelgestelde vragen", + "hero": "Hero", + "view_all_button": "Alles bekijken", + "video_section": "Video", + "product_title": "Producttitel", + "custom_liquid": "Aangepaste Liquid", + "blog": "Blog", + "blog_post": "Blogpost", + "blog_posts": "Blogposts", + "caption": "Bijschrift", + "collection_card_image": "Afbeelding", + "collection_links": "Collectielinks", + "collection_links_spotlight": "Collectielinks: Spotlight", + "collection_links_text": "Collectielinks: Tekst", + "collections_carousel": "Collectielijst: Carrousel", + "collections_editorial": "Collectielijst: redactioneel", + "collections_grid": "Collectielijst: Grid", + "copyright": "Auteursrecht", + "count": "Aantal", + "divider_section": "Scheidingslijn", + "drawers": "Lades", + "editorial": "Redactioneel", + "editorial_jumbo_text": "Redactioneel: Jumbo-tekst", + "hero_marquee": "Hero: Marquee", + "input_fields": "Invoervelden", + "local_pickup": "Afhalen ter plaatse", + "marquee_section": "Marquee", + "media_with_text": "Media met tekst", + "page": "Pagina", + "page_content": "Content", + "page_layout": "Paginaopmaak", + "policy_list": "Links naar beleid", + "prices": "Prijzen", + "product_list_button": "Knop Alles weergeven", + "products_editorial": "Uitgelichte collectie: Redactioneel", + "social_link": "Socialmedia-link", + "split_showcase": "Split showcase", + "variant_pickers": "Variantkiezers", + "pills": "Keuzeopties", + "large_logo": "Groot logo", + "product_inventory": "Productvoorraad", + "description": "Beschrijving" + }, + "settings": { + "autoplay": "Automatisch afspelen", + "background": "Achtergrond", + "border_radius": "Hoekradius", + "border_width": "Randdikte", + "borders": "Grenzen", + "bottom_padding": "Opvulling onder", + "color": "Kleur", + "content_direction": "Richting van content", + "content_position": "Positie van content", + "cover_image_size": "Grootte coverafbeelding", + "cover_image": "Coverafbeelding", + "custom_width": "Aangepaste breedte", + "enable_video_looping": "Videolussen", + "favicon": "Favicon", + "heading": "Koptekst", + "icon": "Pictogram", + "image_icon": "Afbeelding pictogram", + "make_section_full_width": "Volledige breedte voor sectie gebruiken", + "overlay_opacity": "Dekking van overlay", + "padding": "Opvulling", + "product": "Product", + "text": "Tekst", + "top_padding": "Opvulling boven", + "video": "Video", + "video_alt_text": "Alt-tekst", + "video_loop": "Video continu herhalen", + "video_position": "Videopositie", + "width": "Breedte", + "alignment": "Uitlijning", + "button": "Knop", + "colors": "Kleuren", + "content_alignment": "Content uitlijnen", + "custom_minimum_height": "Aangepaste minimale hoogte", + "font_family": "Lettertypefamilie", + "gap": "Gat", + "geometric_translate_y": "Geometrische translatie Y", + "image": "Afbeelding", + "image_opacity": "Doorzichtigheid van afbeelding", + "image_position": "Afbeeldingspositie", + "image_ratio": "Breedte-/hoogteverhouding van afbeeldingen", + "label": "Label", + "line_height": "Lijnhoogte", + "link": "Link", + "layout_gap": "Gat in de opmaak", + "minimum_height": "Minimale hoogte", + "opacity": "Dekking", + "primary_color": "Links", + "section_width": "Breedte voor sectie", + "size": "Maat", + "slide_spacing": "Ruimte tussen dia's", + "slide_width": "Breedte dia", + "slideshow_fullwidth": "Dia's met volledige breedte", + "style": "Stijl", + "text_case": "Kast", + "z_index": "Z-index", + "limit_content_width": "Limiet contentbreedte", + "color_scheme": "Kleurschema", + "inherit_color_scheme": "Kleurschema overnemen", + "product_count": "Aantal producten", + "product_type": "Producttype", + "content_width": "Contentbreedte", + "collection": "Collectie", + "enable_sticky_content": "Sticky content op desktop", + "error_color": "Fout", + "success_color": "Geslaagd", + "primary_font": "Primair lettertype", + "secondary_font": "Secundair lettertype", + "tertiary_font": "Tertiair lettertype", + "columns": "Kolommen", + "items_to_show": "Items om weer te geven", + "layout": "Opmaak", + "layout_type": "Type", + "show_grid_layout_selector": "Grid-indelingskiezer weergeven", + "view_more_show": "De knop 'Meer weergeven' weergeven", + "image_gap": "Ruimte tussen afbeeldingen", + "width_desktop": "Desktopbreedte", + "width_mobile": "Breedte voor mobiel", + "border_style": "Randstijl", + "height": "Hoogte", + "thickness": "Dikte", + "stroke": "Streep", + "filter_style": "Filterstijl", + "swatches": "Stalen", + "quick_add_colors": "Snel kleuren toevoegen", + "divider_color": "Scheidingslijn", + "border_opacity": "Transparantie rand", + "hover_background": "Zweef-achtergrond", + "hover_borders": "Zweef-randen", + "hover_text": "Zweef-tekst", + "primary_hover_color": "Zweef-links", + "primary_button_text": "Tekst van primaire knop", + "primary_button_background": "Achtergrond van primaire knop", + "primary_button_border": "Rand van primaire knop", + "secondary_button_text": "Tekst van secundaire knop", + "secondary_button_background": "Achtergrond van secundaire knop", + "secondary_button_border": "Rand van secundaire knop", + "shadow_color": "Schaduw", + "mobile_logo_image": "Mobiellogo", + "video_autoplay": "Automatisch afspelen", + "video_cover_image": "Coverafbeelding", + "video_external_url": "URL", + "video_source": "Bron", + "first_row_media_position": "Positie van media eerste rij", + "hide_padding": "Opvulling verbergen", + "background_color": "Achtergrondkleur", + "size_mobile": "Grootte mobiel", + "pixel_size_mobile": "Pixelgrootte", + "percent_size_mobile": "Percentagegrootte", + "unit": "Eenheid", + "custom_mobile_size": "Aangepaste grootte mobiel", + "fixed_height": "Pixelhoogte", + "fixed_width": "Pixelbreedte", + "percent_height": "Percentagehoogte", + "percent_width": "Percentagebreedte", + "percent_size": "Percentagegrootte", + "pixel_size": "Pixelgrootte", + "card_image_height": "Hoogte productafbeelding", + "logo_font": "Lettertype logo", + "accordion": "Accordeon", + "always_stack_buttons": "Knoppen altijd stapelen", + "aspect_ratio": "Beeldverhouding", + "auto_rotate_announcements": "Aankondigingen automatisch draaien", + "auto_rotate_slides": "Dia's automatisch draaien", + "badge_corner_radius": "Hoekradius", + "badge_position": "Positie op kaarten", + "badge_sale_color_scheme": "Uitverkoop", + "badge_sold_out_color_scheme": "Uitverkocht", + "behavior": "Gedrag", + "blur": "Schaduwvervaging", + "border": "Rand", + "bottom": "Onder", + "carousel_on_mobile": "Carrousel op mobiel", + "cart_count": "Aantal in winkelwagen", + "cart_items": "Artikelen in winkelwagen", + "cart_related_products": "Gerelateerde producten", + "cart_title": "Winkelwagen", + "cart_total": "Totaal van de winkelwagen", + "cart_type": "Type", + "case": "Kast", + "checkout_buttons": "Knoppen voor versnelde checkout", + "collection_list": "Collecties", + "collection_templates": "Collectie-templates", + "content": "Content", + "corner_radius": "Hoekradius", + "country_region": "Land/regio", + "currency_code": "Valutacode", + "custom_height": "Aangepaste hoogte", + "custom_mobile_width": "Aangepaste breedte voor mobiel", + "desktop_height": "Desktophoogte", + "direction": "Richting", + "display": "Weergave", + "divider_thickness": "Dikte scheidingslijn", + "divider": "Scheidingslijn", + "dividers": "Scheidingslijnen", + "drop_shadow": "Slagschaduw", + "empty_state_collection_info": "Getoond voordat zoekterm wordt ingevoerd", + "empty_state_collection": "Collectie lege staat", + "enable_filtering": "Filters", + "enable_grid_density": "Bediening grid-indeling", + "enable_sorting": "Sorteren", + "enable_zoom": "Zoom inschakelen", + "equal_columns": "Gelijke kolommen", + "expand_first_group": "Eerste groep uitklappen", + "extend_media_to_screen_edge": "Media uitbreiden tot schermrand", + "extend_summary": "Uitbreiden tot schermrand", + "extra_large": "Extra groot", + "extra_small": "Extra klein", + "flag": "Vlag", + "font_price": "Lettertype prijs", + "font_weight": "Lettertypegewicht", + "font": "Lettertype", + "full_width_first_image": "Volledige breedte eerste afbeelding", + "full_width_on_mobile": "Volledige breedte op mobiel", + "heading_preset": "Voorinstelling koptekst", + "hide_unselected_variant_media": "Niet-geselecteerde media van varianten verbergen", + "horizontal_gap": "Horizontaal hiaat", + "horizontal_offset": "Schaduw horizontale verschuiving", + "hover_behavior": "Zweef-gedrag", + "icon_background": "Achtergrond pictogram", + "icons": "Pictogrammen", + "image_border_radius": "Hoekradius afbeelding", + "installments": "Termijnbetalingen", + "integrated_button": "Geïntegreerde knop", + "language_selector": "Taalkiezer", + "large": "Groot", + "left_padding": "Opvulling links", + "left": "Links", + "letter_spacing": "Letterspatiëring", + "limit_media_to_screen_height": "Beperken tot schermhoogte", + "limit_product_details_width": "Breedtelimiet productgegevens", + "link_preset": "Voorinstelling van link", + "links": "Links", + "logo": "Logo", + "loop": "Lus", + "make_details_sticky_desktop": "Sticky op desktop", + "max_width": "Max. breedte", + "media_height": "Mediahoogte", + "media_overlay": "Media-overlay", + "media_position": "Mediapositie", + "media_type": "Mediatype", + "media_width": "Mediabreedte", + "menu": "Menu", + "mobile_columns": "Kolommen mobiel", + "mobile_height": "Hoogte mobiel", + "mobile_quick_add": "Snel toevoegen mobiel", + "motion_direction": "Richting van beweging", + "motion": "Beweging", + "movement_direction": "Richting van verplaatsing", + "navigation_bar_color_scheme": "Kleurschema navigatiebalk", + "navigation_bar": "Navigatiebalk", + "navigation": "Navigatie", + "open_new_tab": "Link openen op nieuw tabblad", + "overlay_color": "Kleur van overlay", + "overlay": "Overlay", + "padding_bottom": "Opvulling onderaan", + "padding_horizontal": "Opvulling horizontaal", + "padding_top": "Opvulling bovenaan", + "page_width": "Paginabreedte", + "pagination": "Paginering", + "placement": "Plaatsing", + "position": "Positie", + "preset": "Voorinstelling", + "product_cards": "Productkaarten", + "product_pages": "Productpagina's", + "product_templates": "Producttemplates", + "products": "Producten", + "quick_add": "Snel toevoegen", + "ratio": "Verhouding", + "regular": "Standaard", + "review_count": "Aantal reviews", + "right": "Rechts", + "row_height": "Rijhoogte", + "row": "Rij", + "seller_note": "Notitie aan verkoper toestaan", + "shadow_opacity": "Schaduwdekking", + "shape": "Vorm", + "show_as_accordion": "Weergeven als accordeon op mobiel", + "show_filter_label": "Tekstlabels voor toegepaste filters", + "show_sale_price_first": "Aanbieding eerst weergeven", + "show_swatch_label": "Tekstlabels voor stalen", + "show_tax_info": "Belastinggegevens", + "show": "Weergeven", + "small": "Klein", + "speed": "Snelheid", + "statement": "Overzicht", + "sticky_header": "Sticky koptekst", + "text_hierarchy": "Teksthiërarchie", + "text_presets": "Voorinstellingen voor tekst", + "title": "Titel", + "top": "Boven", + "type": "Type", + "type_preset": "Voorinstelling voor tekst", + "underline_thickness": "Dikte onderstreep", + "variant_images": "Variantafbeeldingen", + "vendor": "Verkoper", + "vertical_gap": "Verticaal hiaat", + "vertical_offset": "Schaduw verticale verschuiving", + "vertical_on_mobile": "Verticaal op mobiel", + "view_all_as_last_card": "'Alles weergeven' als laatste kaart", + "weight": "Gewicht", + "wrap": "Terugloop", + "read_only": "Alleen lezen", + "gradient_direction": "Richting van kleurverloop", + "headings": "Kopteksten", + "overlay_style": "Overlaystijl", + "transparent_background": "Transparante achtergrond", + "hide_logo_on_home_page": "Logo op homepage verbergen", + "account": "Account", + "align_baseline": "Tekst uitlijnen op basislijn", + "add_discount_code": "Kortingen in winkelwagen toestaan", + "background_overlay": "Overlay achtergrond", + "background_media": "Achtergrondmedia", + "border_thickness": "Randdikte", + "bottom_row": "Onderste rij", + "button_text_case": "Hoofd- of kleine letters", + "button_text_weight": "Tekstdikte", + "card_size": "Maat kaart", + "auto_open_cart_drawer": "Met Toevoegen aan winkelwagen wordt de optie automatisch geopend", + "collection_count": "Aantal collecties", + "collection_title_case": "Collectietitel doos", + "custom_liquid": "Liquid-code", + "default": "Standaard", + "default_logo": "Standaardlogo", + "divider_width": "Dikte scheidingslijn", + "horizontal_padding": "Horizontaal vullen", + "inverse": "Omkeren", + "inverse_logo": "Logo voor Omkeren", + "layout_style": "Stijl", + "length": "Lengte", + "mobile_card_size": "Maat mobiele kaart", + "mobile_pagination": "Paginering mobiel", + "open_row_by_default": "Rij standaard openen", + "page": "Pagina", + "page_transition_enabled": "Paginaovergang", + "product_and_card_title_case": "Product- en kaarttitel doos", + "product_title_case": "Producttitel doos", + "right_padding": "Opvulling rechts", + "search": "Zoeken", + "search_icon": "Zoekpictogram", + "search_position": "Positie", + "search_row": "Rij", + "show_author": "Auteur", + "show_alignment": "Uitlijning weergeven", + "show_count": "Aantal tonen", + "show_date": "Datum", + "show_pickup_availability": "Toon beschikbaarheid van afhaalmoment", + "show_search": "Zoekopdracht weergeven", + "text_label_case": "Tekstlabel doos", + "use_inverse_logo": "Inverse logo gebruiken", + "vertical_padding": "Verticaal vullen", + "visibility": "Zichtbaarheid", + "product_corner_radius": "Hoekradius product", + "card_corner_radius": "Hoekradius kaart", + "alignment_mobile": "Uitlijning op mobiel", + "animation_repeat": "Animatie herhalen", + "blurred_reflection": "Onscherpe weerspiegeling", + "card_hover_effect": "Zweefeffect voor kaart", + "effects": "Effecten", + "inventory_threshold": "Drempelwaarde lage voorraad", + "reflection_opacity": "Opaciteit reflectie", + "show_inventory_quantity": "Laag voorraadaantal weergeven", + "transition_to_main_product": "Overgang van productkaart naar productpagina", + "show_second_image_on_hover": "Tweede afbeelding weergeven als je de aanwijzer erboven beweegt", + "media": "Media", + "product_card_carousel": "Carrousel weergeven", + "media_fit": "Mediafit", + "scroll_speed": "Tijd tot de volgende aankondiging" + }, + "options": { + "adapt_to_image": "Aanpassen aan afbeelding", + "apple": "Appel", + "arrow": "Pijl", + "banana": "Banaan", + "bottle": "Fles", + "box": "Doos", + "buttons": "Knoppen", + "carrot": "Wortel", + "center": "Centraal", + "chat_bubble": "Chatbubbel", + "clipboard": "Klembord", + "contain": "Bevat", + "counter": "Teller", + "cover": "Cover", + "custom": "Aangepast", + "dairy_free": "Zuivelvrij", + "dairy": "Zuivel", + "dropdowns": "Vervolgkeuzelijsten", + "dots": "Stippen", + "dryer": "Droger", + "end": "Einde", + "eye": "Oog", + "facebook": "Facebook", + "fire": "Vuur", + "gluten_free": "Glutenvrij", + "heart": "Hart", + "horizontal": "Horizontaal", + "instagram": "Instagram", + "iron": "Strijkijzer", + "large": "Groot", + "leaf": "Blad", + "leather": "Leer", + "lightning_bolt": "Bliksem", + "lipstick": "Lipstick", + "lock": "Slot", + "map_pin": "Kaart-pin", + "medium": "Gemiddeld", + "none": "Geen", + "numbers": "Getallen", + "nut_free": "Notenvrij", + "pants": "Lange broek", + "paw_print": "Pootafdruk", + "pepper": "Peper", + "perfume": "Parfum", + "pinterest": "Pinterest", + "plane": "Vliegtuig", + "plant": "Plant", + "price_tag": "Prijstag", + "question_mark": "Vraagteken", + "recycle": "Recyclen", + "return": "Retourneren", + "ruler": "Liniaal", + "serving_dish": "Serveerschaal", + "shirt": "Overhemd", + "shoe": "Schoen", + "silhouette": "Silhouet", + "small": "Klein", + "snapchat": "Snapchat", + "snowflake": "Sneeuwvlok", + "star": "Ster", + "start": "Begin", + "stopwatch": "Stopwatch", + "tiktok": "TikTok", + "truck": "Vrachtwagen", + "tumblr": "Tumblr", + "twitter": "X (voorheen Twitter)", + "vertical": "Verticaal", + "vimeo": "Vimeo", + "washing": "Wassen", + "auto": "Auto", + "default": "Standaard", + "fill": "Opvullen", + "fit": "Aanpassen", + "full": "Volledig", + "full_and_page": "Volledige achtergrond, paginabrede content", + "heading": "Koptekst", + "landscape": "Landschap", + "lg": "LG", + "link": "Link", + "lowercase": "kleine letters", + "m": "M", + "outline": "Omlijnen", + "page": "Pagina", + "portrait": "Portret", + "s": "S", + "sentence": "Zin", + "solid": "Effen", + "space_between": "Ruimte tussen", + "square": "Vierkant", + "uppercase": "Hoofdletters", + "circle": "Cirkel", + "swatches": "Stalen", + "full_and_page_offset_left": "Volledige achtergrond, paginabreedte content, offset links", + "full_and_page_offset_right": "Volledige achtergrond, paginabreedte content, offset rechts", + "offset_left": "Offset links", + "offset_right": "Offset rechts", + "page_center_aligned": "Pagina, gecentreerd", + "page_left_aligned": "Pagina, links uitgelijnd", + "page_right_aligned": "Pagina, rechts uitgelijnd", + "button": "Knop", + "caption": "Bijschrift", + "h1": "Kop 1", + "h2": "Kop 2", + "h3": "Kop 3", + "h4": "Kop 4", + "h5": "Kop 5", + "h6": "Kop 6", + "paragraph": "Paragraaf", + "primary": "Primair", + "secondary": "Secundair", + "tertiary": "Tertiair", + "chevron_left": "Chevronpijl naar links", + "chevron_right": "Chevronpijl naar rechts", + "diamond": "Ruit", + "grid": "Grid", + "parallelogram": "Parallellogram", + "rounded": "Afgerond", + "fit_content": "Pasvorm", + "pills": "Keuzeopties", + "heavy": "Dik", + "thin": "Dun", + "drawer": "Optie", + "preview": "Voorbeeld", + "text": "Tekst", + "video_uploaded": "Geüpload", + "video_external_url": "Externe URL", + "up": "Omhoog", + "down": "Omlaag", + "gradient": "Kleurverloop", + "fixed": "Vast", + "pixel": "Pixel", + "percent": "Percentage", + "aspect_ratio": "Lengte-breedteverhouding", + "above_carousel": "Boven carrousel", + "all": "Alle", + "always": "Altijd", + "arrows_large": "Grote pijlen", + "arrows": "Pijlen", + "balance": "Saldo", + "bento": "Bento", + "black": "Zwart", + "bluesky": "Bluesky", + "body_large": "Hoofdtekst (groot)", + "body_regular": "Hoofdtekst (normaal)", + "body_small": "Hoofdtekst (klein)", + "bold": "Vetgedrukt", + "bottom_left": "Linksonder", + "bottom_right": "Rechtsonder", + "bottom": "Onder", + "capitalize": "Met hoofdletters schrijven", + "caret": "Caret", + "carousel": "Carrousel", + "check_box": "Vakje selecteren", + "chevron_large": "Grote chevronpijlen", + "chevron": "Chevronpijl", + "chevrons": "Chevronpijlen", + "classic": "Klassiek", + "collection_images": "Collectie-afbeeldingen", + "color": "Kleur", + "complementary": "Aanvullend", + "dissolve": "Oplossen", + "dotted": "Stippellijn", + "editorial": "Redactioneel", + "extra_large": "Extra groot", + "extra_small": "Extra klein", + "featured_collections": "Uitgelichte collecties", + "featured_products": "Uitgelichte producten", + "font_primary": "Primair", + "font_secondary": "Secundair", + "font_tertiary": "Tertiair", + "forward": "Vooruit", + "full_screen": "Volledig scherm", + "heading_extra_large": "Koptekst (extra groot)", + "heading_extra_small": "Koptekst (extra klein)", + "heading_large": "Koptekst (groot)", + "heading_regular": "Koptekst (normaal)", + "heading_small": "Koptekst (klein)", + "icon": "Pictogram", + "image": "Afbeelding", + "input": "Invoer", + "inside_carousel": "Binnen carrousel", + "inverse_large": "Omkeren groot", + "inverse": "Omkeren", + "large_arrows": "Grote pijlen", + "large_chevrons": "Grote chevronpijlen", + "left": "Links", + "light": "Licht", + "linkedin": "LinkedIn", + "loose": "Los", + "media_first": "Media eerst", + "media_second": "Media tweede", + "modal": "Modaal", + "narrow": "Smal", + "never": "Nooit", + "next_to_carousel": "Naast carrousel", + "normal": "Normaal", + "nowrap": "Geen terugloop", + "off_media": "Van media af", + "on_media": "Op media", + "on_scroll_up": "Bij omhoog scrollen", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Pil", + "plus": "Plus", + "pretty": "Knap", + "price": "Prijs", + "primary_style": "Primaire stijl", + "rectangle": "Rechthoek", + "regular": "Standaard", + "related": "Verwant", + "reverse": "Omgekeerd", + "rich_text": "Tekst met opmaak", + "right": "Rechts", + "secondary_style": "Secundaire stijl", + "semibold": "Halfvet", + "shaded": "Met schaduw", + "show_second_image": "Tweede afbeelding weergeven", + "single": "Eén", + "slide_left": "Naar links schuiven", + "slide_up": "Naar boven schuiven", + "spotify": "Spotify", + "stack": "Stapelen", + "text_only": "Alleen tekst", + "threads": "Threads", + "thumbnails": "Miniatuurafbeeldingen", + "tight": "Strak", + "top_left": "Linksboven", + "top_right": "Rechtsboven", + "top": "Boven", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Onderstrepen", + "video": "Video", + "wide": "Breed", + "youtube": "YouTube", + "accent": "Accent", + "below_image": "Onder afbeelding", + "body": "Hoofdtekst", + "button_primary": "Primaire knop", + "button_secondary": "Secundaire knop", + "compact": "Compact", + "crop_to_fit": "Bijsnijden om passend te maken", + "hidden": "Verborgen", + "hint": "Hint", + "maintain_aspect_ratio": "Beeldverhouding behouden", + "off": "Uit", + "on_image": "Op afbeelding", + "social_bluesky": "Social: Bluesky", + "social_facebook": "Social: Facebook", + "social_instagram": "Social: Instagram", + "social_linkedin": "Social: LinkedIn", + "social_pinterest": "Social: Pinterest", + "social_snapchat": "Social: Snapchat", + "social_spotify": "Social: Spotify", + "social_threads": "Social: Threads", + "social_tiktok": "Social: TikTok", + "social_tumblr": "Social: Tumblr", + "social_twitter": "Social: X (Twitter)", + "social_whatsapp": "Social: WhatsApp", + "social_vimeo": "Social: Vimeo", + "social_youtube": "Social: YouTube", + "spotlight": "Spotlight", + "standard": "Standaard", + "subheading": "Subkop", + "blur": "Vervaging", + "lift": "Optillen", + "reveal": "Tonen", + "scale": "Schalen", + "subtle_zoom": "Zoomen" + }, + "content": { + "background_video": "Achtergrondvideo", + "describe_the_video_for": "Geef een beschrijving van de video voor klanten die schermlezers gebruiken. [Meer informatie](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "De breedte wordt automatisch geoptimaliseerd voor mobiel.", + "advanced": "Geavanceerd", + "background_image": "Achtergrondafbeelding", + "block_size": "Blokmaat", + "borders": "Grenzen", + "section_size": "Sectiemaat", + "slideshow_width": "Breedte dia", + "typography": "Typografie", + "complementary_products": "Aanvullende producten moeten worden ingesteld met de Search & Discovery-app. [Meer informatie](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Kolommen worden automatisch geoptimaliseerd voor mobiel", + "content_width": "Contentbreedte is alleen van toepassing als de sectiebreedte is ingesteld op volledige breedte.", + "adjustments_affect_all_content": "Geldt voor alle content in dit blok", + "responsive_font_sizes": "Grootten worden automatisch geschaald voor alle schermgrootten", + "buttons": "Knoppen", + "swatches": "Stalen", + "variant_settings": "Variantinstellingen", + "background": "Achtergrond", + "cards_layout": "Kaartopmaak", + "section_layout": "Sectieopmaak", + "mobile_size": "Grootte mobiel", + "appearance": "Uiterlijk", + "arrows": "Pijlen", + "body_size": "Grootte hoofdtekst", + "bottom_row_appearance": "Uiterlijk onderste rij", + "carousel_navigation": "Carrousel-navigatie", + "carousel_pagination": "Carrousel-paginering", + "copyright": "Auteursrecht", + "edit_logo_in_theme_settings": "Bewerk logo in [thema-instellingen](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Bewerk prijsopmaak in [thema-instellingen](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Bewerk variantstijlen in [thema-instellingen](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Toevoeging aanmeldingen [klantprofielen](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "De knop wordt alleen weergegeven als het Shop-kanaal is geïnstalleerd en Shop Pay is geactiveerd. [Meer informatie](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Lettertypen", + "grid": "Grid", + "heading_size": "Grootte koptekst", + "image": "Afbeelding", + "input": "Invoer", + "layout": "Opmaak", + "link": "Link", + "link_padding": "Opvulling link", + "localization": "Lokalisatie", + "logo": "Logo", + "margin": "Marge", + "media": "Media", + "media_1": "Media 1", + "media_2": "Media 2", + "menu": "Menu", + "mobile_layout": "Opmaak voor mobiel", + "mobile_width": "Breedte voor mobiel", + "padding": "Opvulling", + "padding_desktop": "Opvulling desktop", + "paragraph": "Paragraaf", + "policies": "Beleid", + "popup": "Pop-up", + "search": "Zoekopdracht", + "size": "Grootte", + "social_media": "Social media", + "submit_button": "Knop voor indienen", + "text_presets": "Voorinstellingen voor tekst", + "transparent_background": "Transparante achtergrond", + "typography_primary": "Primaire typografie", + "typography_secondary": "Secundaire typografie", + "typography_tertiary": "Tertiaire typografie", + "width": "Breedte", + "visibility": "Zichtbaarheid", + "visible_if_collection_has_more_products": "Zichtbaar als een collectie meer producten heeft dan weergegeven", + "carousel": "Carrousel", + "colors": "Kleuren", + "collection_page": "Collectiepagina", + "copyright_info": "Leer hoe je [je auteursrechtverklaring bewerkt](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Klantaccount", + "edit_empty_state_collection_in_theme_settings": "Bewerk collectie lege staat in [thema-instellingen](/editor?context=theme&category=search)", + "grid_layout": "Grid-indeling", + "home_page": "Homepage", + "images": "Afbeeldingen", + "inverse_logo_info": "Gebruikt wanneer transparante koptekstachtergrond is ingesteld op Omkeren", + "manage_customer_accounts": "[Beheer zichtbaarheid](/admin/settings/customer_accounts) in klantaccountinstellingen. Verouderde accounts worden niet ondersteund.", + "manage_policies": "[Beleidsregels beheren](/admin/settings/legal)", + "product_page": "Productpagina", + "text": "Tekst", + "thumbnails": "Miniatuurafbeeldingen", + "app_required_for_ratings": "Er is een app vereist voor productbeoordelingen. [Meer informatie](https://help.shopify.com/manual/apps)", + "icon": "Pictogram", + "manage_store_name": "[Winkelnaam beheren](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Geeft collectie uit bovenliggende sectie weer", + "resource_reference_collection_card_image": "Geeft afbeelding uit bovenliggende collectie weer", + "resource_reference_collection_title": "Geeft titel uit bovenliggende collectie weer", + "resource_reference_product": "Koppelt automatisch met bovenliggend product", + "resource_reference_product_card": "Geeft product uit bovenliggende sectie weer", + "resource_reference_product_inventory": "Geeft voorraad uit bovenliggend product weer", + "resource_reference_product_price": "Geeft prijs uit bovenliggend product weer", + "resource_reference_product_recommendations": "Geeft aanbevelingen weer op basis van bovenliggend product", + "resource_reference_product_review": "Geeft recensies uit bovenliggend product weer", + "resource_reference_product_swatches": "Geeft stalen uit bovenliggend product weer", + "resource_reference_product_title": "Geeft titel uit bovenliggend product weer", + "resource_reference_product_variant_picker": "Geeft varianten uit bovenliggend product weer", + "resource_reference_product_media": "Geeft media van bovenliggend product weer", + "product_media": "Productmedia", + "section_link": "Sectielink" + }, + "html_defaults": { + "share_information_about_your": "

Deel informatie over je merk met klanten. Beschrijf een product, doe aankondigingen of verwelkom klanten in je winkel.

" + }, + "text_defaults": { + "collapsible_row": "Inklapbare rij", + "button_label": "Shop nu", + "heading": "Koptekst", + "email_signup_button_label": "Abonneren", + "accordion_heading": "Accordeon-koptekst", + "contact_form_button_label": "Indienen", + "popup_link": "Pop-uplink", + "sign_up": "Aanmelden", + "welcome_to_our_store": "Welkom in onze winkel", + "be_bold": "Laat je zien.", + "shop_our_latest_arrivals": "Shop onze nieuwste producten!" + }, + "info": { + "carousel_layout_on_mobile": "Carrousel wordt gebruikt op mobiel", + "video_alt_text": "Beschrijf de video voor gebruikers van ondersteunende technologie", + "video_autoplay": "Video's worden standaard gedempt", + "video_external": "Een URL van YouTube of Vimeo gebruiken", + "link_info": "Optioneel: maakt pictogram klikbaar", + "carousel_hover_behavior_not_supported": "Zweven boven 'carrousel' wordt niet ondersteund wanneer het type ‘Carrousel’ is geselecteerd op sectieniveau", + "checkout_buttons": "Zorgt ervoor dat kopers sneller kunnen afrekenen en kan de conversie verbeteren. [Meer informatie](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Aangepaste koptekst", + "edit_presets_in_theme_settings": "Bewerk voorinstellingen in [thema-instellingen](/editor?context=theme&category=typography)", + "enable_filtering_info": "Pas filters aan met de [Search & Discovery-app](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Grid-indeling wordt gebruikt voor mobiel", + "logo_font": "Alleen van toepassing als er geen logo is geselecteerd", + "manage_countries_regions": "[Landen/regio's beheren](/admin/settings/markets)", + "manage_languages": "[Talen beheren](/admin/settings/languages)", + "transparent_background": "Controleer elke template waar een transparante achtergrond wordt toegepast voor leesbaarheid", + "aspect_ratio_adjusted": "Aangepast in sommige opmaken", + "auto_open_cart_drawer": "Als deze optie is ingeschakeld, wordt de winkelwagenoptie automatisch geopend wanneer een product wordt toegevoegd aan de winkelwagen.", + "custom_liquid": "Voeg app-fragmenten of andere code toe om geavanceerde aanpassingen aan te maken. [Meer informatie](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Gebruikt voor toegepaste filters, kortingscodes en zoeksuggesties", + "applies_on_image_only": "Uitsluitend van toepassing op afbeeldingen", + "hover_effects": "Van toepassing op product- en collectiekaarten" + }, + "categories": { + "product_list": "Uitgelichte collectie", + "basic": "Basis", + "collection": "Collectie", + "collection_list": "Collectielijst", + "footer": "Voettekst", + "forms": "Formulieren", + "header": "Koptekst", + "layout": "Opmaak", + "links": "Links", + "product": "Product", + "banners": "Banners", + "collections": "Collecties", + "custom": "Aangepast", + "decorative": "Decoratief", + "products": "Producten", + "other_sections": "Anders", + "storytelling": "Storytelling" + } +} diff --git a/locales/pl.json b/locales/pl.json new file mode 100644 index 000000000..18dc60731 --- /dev/null +++ b/locales/pl.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Załaduj film: {{ description }}", + "sold_out": "Wyprzedane", + "email_signup": { + "label": "E-mail", + "placeholder": "Adres e-mail", + "success": "Dziękujemy za subskrypcję!" + }, + "filter": "Filtr", + "payment_methods": "Metody płatności", + "contact_form": { + "name": "Nazwisko", + "email": "E-mail", + "phone": "Telefon", + "comment": "Komentarz", + "post_success": "Dziękujemy za skontaktowanie się z nami. Odpowiemy tak szybko, jak to możliwe.", + "error_heading": "Dostosuj następujące dane:" + } + }, + "accessibility": { + "play_model": "Odtwórz model 3D", + "play_video": "Odtwórz film", + "unit_price": "Cena jednostkowa", + "country_results_count": "Liczba wyników: {{ count }}", + "slideshow_pause": "Wstrzymaj pokaz slajdów", + "slideshow_play": "Odtwórz pokaz slajdów", + "remove_item": "Usuń {{ title}}", + "skip_to_text": "Przejdź do treści", + "skip_to_product_info": "Pomiń, aby przejść do informacji o produkcie", + "skip_to_results_list": "Przejdź do listy wyników", + "new_window": "Otwiera się w nowym oknie.", + "slideshow_next": "Następny slajd", + "slideshow_previous": "Poprzedni slajd", + "close_dialog": "Zamknij okno dialogowe", + "reset_search": "Resetuj wyszukiwanie", + "search_results_count": "Znaleziono wyniki wyszukiwania ({{ count }}) dla „{{ query }}”", + "search_results_no_results": "Nie znaleziono wyników dla „{{ query }}”", + "filters": "Filtry", + "account": "Otwórz menu konta", + "cart": "Koszyk", + "cart_count": "Łączna liczba pozycji w koszyku", + "filter_count": { + "one": "Zastosowano {{ count }} filtr", + "other": "Zastosowane filtry: {{ count }}", + "few": "Zastosowane filtry: {{ count }}", + "many": "Zastosowane filtry: {{ count }}" + }, + "menu": "Menu", + "country_region": "Kraj/region", + "slide_status": "Slajd {{ index }} z {{ length }}", + "scroll_to": "Przewiń do {{ title }}", + "loading_product_recommendations": "Wczytywanie polecanych produktów", + "discount": "Zastosuj kod rabatowy", + "discount_applied": "Zastosowany kod rabatowy: {{ code }}", + "open_cart_drawer": "Otwórz koszyk", + "pause_video": "Zatrzymaj film", + "inventory_status": "Stan zapasów", + "find_country": "Znajdź kraj", + "localization_region_and_language": "Otwórz region i selektor języka", + "open_search_modal": "Otwórz wyszukiwanie", + "decrease_quantity": "Zmniejsz ilość", + "increase_quantity": "Zwiększ ilość", + "rating": "Ocena tego produktu to: {{ rating }} na 5", + "quantity": "Ilość", + "nested_product": "{{ product_title }}: {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Dodaj do koszyka", + "clear_all": "Wyczyść wszystko", + "remove": "Usuń", + "view_in_your_space": "Zobacz w swojej przestrzeni", + "show_filters": "Filtr", + "clear": "Wyczyść", + "continue_shopping": "Kontynuuj zakupy", + "log_in_html": "Masz już konto? Zaloguj się, aby szybciej realizować zakupy.", + "see_items": { + "one": "Zobacz {{ count }} pozycję", + "other": "Zobacz {{ count }} pozycje(-i)", + "few": "Zobacz {{ count }} pozycje(-i)", + "many": "Zobacz {{ count }} pozycje(-i)" + }, + "view_all": "Wyświetl wszystko", + "add": "Dodaj", + "choose": "Wybierz", + "added": "Dodano", + "show_less": "Pokaż mniej", + "show_more": "Pokaż więcej", + "close": "Zamknij", + "more": "Więcej", + "reset": "Zresetuj", + "zoom": "Powiększenie", + "close_dialog": "Zamknij okno dialogowe", + "back": "Powrót", + "log_in": "Zaloguj się", + "log_out": "Wyloguj się", + "remove_discount": "Usuń rabat {{ code }}", + "enter_using_password": "Wejdź, używając hasła", + "submit": "Prześlij", + "enter_password": "Wpisz hasło", + "view_store_information": "Wyświetl informacje o sklepie", + "apply": "Zastosuj", + "open_image_in_full_screen": "Otwórz obraz w trybie pełnoekranowym", + "sign_in_options": "Inne opcje logowania", + "sign_up": "Zarejestruj się", + "sort": "Sortuj", + "show_all_options": "Pokaż wszystkie opcje" + }, + "content": { + "reviews": "recenzje", + "language": "Język", + "localization_region_and_language": "Region i język", + "no_results_found": "Nie znaleziono wyników", + "cart_total": "Całkowita wartość koszyka", + "your_cart_is_empty": "Twój koszyk jest pusty", + "product_image": "Obraz produktu", + "product_information": "Informacje o produkcie", + "quantity": "Ilość", + "product_total": "Produkt łącznie", + "cart_estimated_total": "Przewidywana suma", + "seller_note": "Specjalne instrukcje", + "cart_subtotal": "Suma częściowa", + "discounts": "Rabaty", + "discount": "Rabat", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Z wliczonymi cłami i podatkami. Obliczenie rabatów i wysyłki przy realizacji zakupu.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Z wliczonymi cłami i podatkami. Obliczenie rabatów i wysyłki przy realizacji zakupu.", + "taxes_included_shipping_at_checkout_with_policy_html": "Z wliczonymi podatkami. Obliczenie rabatów i wysyłki przy realizacji zakupu.", + "taxes_included_shipping_at_checkout_without_policy": "Z wliczonymi podatkami. Obliczenie rabatów i wysyłki przy realizacji zakupu.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Z wliczonymi cłami. Obliczenie podatków, rabatów i wysyłki przy realizacji zakupu.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Z wliczonymi cłami. Obliczenie podatków, rabatów i wysyłki przy realizacji zakupu.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Obliczenie podatków, rabatów i wysyłki przy realizacji zakupu.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Obliczenie podatków, rabatów i wysyłki przy realizacji zakupu.", + "checkout": "Zrealizuj zakup", + "cart_title": "Koszyk", + "price": "Cena", + "price_regular": "Cena regularna", + "price_compare_at": "Cena do porównania", + "price_sale": "Cena promocyjna", + "duties_and_taxes_included": "Z wliczonymi cłami i podatkami.", + "duties_included": "Z wliczonymi cłami.", + "shipping_policy_html": "Koszt wysyłki obliczony przy realizacji zakupu.", + "taxes_included": "Z wliczonymi podatkami.", + "product_badge_sold_out": "Wyprzedane", + "product_badge_sale": "W promocji", + "search_input_label": "Szukaj", + "search_input_placeholder": "Szukaj", + "search_results": "Wyniki wyszukiwania", + "search_results_label": "Wyniki wyszukiwania", + "search_results_no_results": "Nie znaleziono wyników dla „{{ terms }}”. Spróbuj innego wyszukiwania.", + "search_results_resource_articles": "Posty na blogu", + "search_results_resource_collections": "Kolekcje", + "search_results_resource_pages": "Strony", + "search_results_resource_products": "Produkty", + "search_results_resource_queries": "Podpowiedzi wyszukiwania", + "search_results_view_all": "Wyświetl wszystko", + "search_results_view_all_button": "Wyświetl wszystko", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} produktów", + "few": "{{ count }} produktów", + "many": "{{ count }} produktów" + }, + "grid_view": { + "default_view": "Domyślne", + "grid_fieldset": "Siatka kolumn", + "single_item": "Pojedyncze", + "zoom_out": "Pomniejsz" + }, + "unavailable": "Niedostępne", + "collection_placeholder": "Tytuł kolekcji", + "product_card_placeholder": "Tytuł produktu", + "recently_viewed_products": "Ostatnio wyświetlone", + "product_count": "Liczba produktów", + "item_count": { + "one": "{{ count }} pozycja", + "other": "Pozycje: {{ count }}", + "few": "Pozycje: {{ count }}", + "many": "Pozycje: {{ count }}" + }, + "errors": "Błędy", + "search": "Wyszukiwanie", + "search_results_no_results_check_spelling": "Nie znaleziono wyników dla „{{ terms }}”. Sprawdź pisownię lub użyj innego słowa lub zwrotu.", + "featured_products": "Polecane produkty", + "price_from": "Od {{ price }}", + "filters": "Filtry", + "no_products_found": "Nie znaleziono produktów.", + "price_filter_html": "Najwyższa cena to {{ price }}", + "use_fewer_filters_html": "Spróbuj użyć mniej filtrów lub wyczyść wszystkie filtry.", + "blog_details_separator": "|", + "account_title": "Konto", + "account_title_personalized": "Dzień dobry, {{ first_name }}!", + "account_orders": "Zamówienia", + "account_profile": "Profil", + "discount_code": "Kod rabatowy", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Z wliczonymi cłami i podatkami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Z wliczonymi cłami i podatkami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Z wliczonymi cłami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Z wliczonymi cłami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "pickup_available_at_html": "Odbiór możliwy w: {{ location }}", + "pickup_available_in": "Odbiór możliwy, {{ pickup_time }}", + "pickup_not_available": "Odbiór jest obecnie niemożliwy", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Czytaj dalej...", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Podatki i koszty wysyłki obliczane przy realizacji zakupu.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Podatki i koszty wysyłki obliczane przy realizacji zakupu.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Z wliczonymi podatkami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Z wliczonymi podatkami. Koszt wysyłki jest obliczany przy realizacji zakupu.", + "wrong_password": "Hasło nieprawidłowe", + "view_more_details": "Wyświetl więcej szczegółów", + "powered_by": "Ten sklep będzie obsługiwany przez", + "store_owner_link_html": "Czy jesteś właścicielem sklepu? Zaloguj się tutaj", + "shipping_discount_error": "Rabaty na wysyłkę są widoczne przy realizacji zakupu, gdy dodany zostanie adres", + "discount_code_error": "Nie można dodać kodu rabatowego do Twojego koszyka", + "inventory_low_stock": "Niski poziom zapasu", + "inventory_in_stock": "W magazynie", + "inventory_out_of_stock": "Zapas wyczerpany", + "page_placeholder_title": "Tytuł strony", + "page_placeholder_content": "Wybierz stronę, aby wyświetlić jej zawartość.", + "placeholder_image": "Obraz symbolu zastępczego", + "shipping_policy": "Koszt wysyłki obliczany przy realizacji zakupu.", + "inventory_low_stock_show_count": { + "one": "Pozostało: {{ count }}", + "other": "Pozostało: {{ count }}", + "few": "Pozostało: {{ count }}", + "many": "Pozostało: {{ count }}" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Użyj kodu karty prezentowej online lub kodu QR w sklepie", + "title": "Oto Twoja karta prezentowa o wartości {{ value }} do {{ shop }}!", + "subtext": "Twoja karta prezentowa", + "shop_link": "Odwiedź sklep online", + "add_to_apple_wallet": "Dodaj do Apple Wallet", + "qr_image_alt": "Kod QR – zeskanuj, aby wykorzystać kartę prezentową", + "copy_code": "Kopiuj kod karty prezentowej", + "expiration_date": "Wygasa {{ expires_on }}", + "copy_code_success": "Kod został skopiowany", + "expired": "Ważność wygasła" + } + }, + "products": { + "product": { + "add_to_cart": "Dodaj do koszyka", + "adding_to_cart": "Trwa dodawanie...", + "added_to_cart": "Dodano do koszyka", + "add_to_cart_error": "Błąd podczas dodawania do koszyka", + "sold_out": "Wyprzedane", + "unavailable": "Niedostępny" + } + }, + "placeholders": { + "password": "Hasło", + "search": "Szukaj", + "product_title": "Tytuł produktu", + "collection_title": "Tytuł kolekcji" + }, + "fields": { + "separator": "do" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentarz", + "other": "Komentarze: {{ count }}", + "few": "Komentarze: {{ count }}", + "many": "Komentarze: {{ count }}" + } + }, + "comment_form": { + "email": "E-mail", + "error": "Nie udało się opublikować komentarza, zwróć uwagę na:", + "heading": "Wprowadź komentarz", + "message": "Wiadomość", + "moderated": "Pamiętaj, że komentarze muszą zostać zatwierdzone przed opublikowaniem.", + "name": "Nazwa", + "post": "Opublikuj komentarz", + "success_moderated": "Komentarz został opublikowany i oczekuje na moderację", + "success": "Opublikowano komentarz" + } + } +} diff --git a/locales/pl.schema.json b/locales/pl.schema.json new file mode 100644 index 000000000..3682d76cc --- /dev/null +++ b/locales/pl.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Obramowania", + "collapsible_row": "Zwijany wiersz", + "custom_section": "Sekcja niestandardowa", + "icon": "Ikona", + "logo_and_favicon": "Logo i ikona Favicon", + "product_buy_buttons": "Przyciski zakupu", + "product_description": "Opis", + "product_price": "Cena", + "slideshow": "Pokaz slajdów", + "typography": "Typografia", + "video": "Film", + "colors": "Kolory", + "overlapping_blocks": "Nakładające się bloki", + "product_variant_picker": "Selektor wariantów", + "slideshow_controls": "Elementy sterujące pokazem slajdów", + "size": "Rozmiar", + "spacing": "Odstępy", + "product_recommendations": "Polecane produkty", + "product_media": "Multimedia produktu", + "featured_collection": "Polecana kolekcja", + "add_to_cart": "Dodaj do koszyka", + "email_signup": "Rejestracja w celu otrzymywania e-maili", + "submit_button": "Przycisk Prześlij", + "grid_layout_selector": "Selektor układu siatki", + "image": "Obraz", + "list_items": "Pozycje listy", + "facets": "Aspekty", + "variants": "Warianty", + "styles": "Style", + "product_cards": "Karty produktów", + "buttons": "Przyciski", + "inputs": "Dane wejściowe", + "primary_button": "Przycisk główny", + "secondary_button": "Przycisk dodatkowy", + "popovers": "Wyskakujące okienka", + "marquee": "Baner", + "alternating_content_rows": "Naprzemienne wiersze", + "pull_quote": "Cytat typu pull", + "contact_form": "Formularz kontaktowy", + "featured_product": "Główne cechy produktu", + "icons_with_text": "Ikony z tekstem", + "product_list": "Polecana kolekcja", + "spacer": "Rozdzielacz", + "products_carousel": "Polecana kolekcja: karuzela", + "products_grid": "Polecana kolekcja: siatka", + "accelerated_checkout": "Przyspieszona realizacja zakupu", + "accordion": "Akordeon", + "accordion_row": "Rząd akordeonu", + "animations": "Animacje", + "announcement": "Ogłoszenie", + "announcement_bar": "Pasek ogłoszeń", + "badges": "Znaczki", + "button": "Przycisk", + "cart": "Koszyk", + "cart_items": "Pozycje w koszyku", + "cart_products": "Produkty w koszyku", + "cart_title": "Koszyk", + "collection": "Kolekcja", + "collection_card": "Karty kolekcji", + "collection_columns": "Kolumny kolekcji", + "collection_container": "Kolekcja", + "collection_description": "Opisy kolekcji", + "collection_image": "Obraz kolekcji", + "collection_info": "Informacje o kolekcji", + "collection_list": "Lista kolekcji", + "collections": "Kolekcje", + "content": "Treść", + "content_grid": "Siatka treści", + "details": "Szczegóły", + "divider": "Separator", + "filters": "Filtrowanie i sortowanie", + "follow_on_shop": "Obserwuj w Shop", + "footer": "Stopka", + "footer_utilities": "Narzędzia stopki", + "group": "Grupa", + "header": "Nagłówek", + "heading": "Nagłówek", + "icons": "Ikony", + "image_with_text": "Obraz z tekstem", + "input": "Dane wejściowe", + "logo": "Logo", + "magazine_grid": "Siatka czasopisma", + "media": "Multimedia", + "menu": "Menu", + "mobile_layout": "Układ na urządzeniu mobilnym", + "payment_icons": "Ikony płatności", + "popup_link": "Wyskakujący link", + "predictive_search": "Wyskakujące okienko wyszukiwania", + "predictive_search_empty": "Zapytania wyszukiwania z podpowiedziami są puste", + "price": "Cena", + "product": "Produkt", + "product_card": "Karta produktów", + "product_card_media": "Multimedia", + "product_card_rendering": "Render karty produktów", + "product_grid": "Siatka", + "product_grid_main": "Siatka produktów", + "product_image": "Obraz produktu", + "product_information": "Informacje o produkcie", + "product_review_stars": "Gwiazdki recenzji", + "quantity": "Ilość", + "row": "Wiersz", + "search": "Wyszukiwanie", + "section": "Sekcja", + "selected_variants": "Wybrane warianty", + "shop_the_look": "Kup stylizację", + "slide": "Slajd", + "social_media_links": "Linki do mediów społecznościowych", + "steps": "Kroki", + "summary": "Podsumowanie", + "swatches": "Próbki", + "testimonials": "Referencje", + "text": "Tekst", + "title": "Tytuł", + "utilities": "Użyteczne funkcje", + "search_input": "Wpis wyszukiwania", + "search_results": "Wyniki wyszukiwania", + "read_only": "Tylko do odczytu", + "collection_title": "Tytuł kolekcji", + "collections_bento": "Lista kolekcji: Bento", + "faq_section": "Często zadawane pytanie", + "hero": "Bohater", + "jumbo_text": "Tekst jumbo", + "view_all_button": "Wyświetl wszystko", + "video_section": "Film", + "custom_liquid": "Niestandardowy kod Liquid", + "blog": "Blog", + "blog_post": "Post na blogu", + "blog_posts": "Posty na blogu", + "caption": "Napis", + "collection_card_image": "Obraz", + "collection_links": "Linki do kolekcji", + "collection_links_spotlight": "Linki kolekcji: Spotlight", + "collection_links_text": "Linki fo kolekcji: tekst", + "collections_carousel": "Lista kolekcji: karuzela", + "collections_editorial": "Lista kolekcji: układ redakcyjny", + "collections_grid": "Lista kolekcji: siatka", + "copyright": "Prawo autorskie", + "count": "Liczba", + "divider_section": "Separator", + "drawers": "Szuflady", + "editorial": "Artykuł", + "editorial_jumbo_text": "Artykuł: tekst jumbo", + "hero_marquee": "Element główny: baner", + "input_fields": "Pola wprowadzania", + "local_pickup": "Odbiór lokalny", + "marquee_section": "Baner", + "media_with_text": "Media z tekstem", + "page": "Strona", + "page_content": "Treść", + "page_layout": "Układ strony", + "policy_list": "Linki do polityki", + "prices": "Ceny", + "products_editorial": "Polecana kolekcja: materiał redakcyjny", + "social_link": "Link do mediów społecznościowych", + "split_showcase": "Podzielona prezentacja", + "variant_pickers": "Selektory wariantów", + "product_title": "Tytuł produktu", + "large_logo": "Duże logo", + "product_list_button": "Przycisk Wyświetl wszystkie", + "product_inventory": "Zapas produktu", + "pills": "Przyciski", + "description": "Opis" + }, + "settings": { + "autoplay": "Autoodtwarzanie", + "background": "Tło", + "border_radius": "Promień rogu", + "border_width": "Grubość obramowania", + "borders": "Obramowania", + "bottom_padding": "Wypełnienie na dole", + "color": "Kolor", + "content_direction": "Kierunek zawartości", + "content_position": "Położenie zawartości", + "cover_image_size": "Wielkość obrazu w tle", + "cover_image": "Obraz w tle", + "custom_width": "Niestandardowa szerokość", + "enable_video_looping": "Zapętlanie wideo", + "favicon": "Ikona Favicon", + "heading": "Nagłówek", + "icon": "Ikona", + "image_icon": "Ikona obrazu", + "make_section_full_width": "Rozwiń sekcję na całą szerokość", + "overlay_opacity": "Nieprzezroczystość nakładki", + "padding": "Wypełnienie", + "product": "Produkt", + "text": "Tekst", + "top_padding": "Wypełnienie na górze", + "video": "Film", + "video_alt_text": "Alternatywny tekst", + "video_loop": "Zapętlony film", + "video_position": "Pozycja filmu", + "width": "Szerokość", + "alignment": "Wyrównanie", + "button": "Przycisk", + "colors": "Kolory", + "content_alignment": "Wyrównanie zawartości", + "custom_minimum_height": "Niestandardowa minimalna wysokość", + "font_family": "Rodzina czcionek", + "gap": "Odstęp", + "geometric_translate_y": "Przesunięcie geometryczne wzdłuż osi Y", + "image": "Obraz", + "image_opacity": "Nieprzezroczystość obrazu", + "image_position": "Położenie obrazu", + "image_ratio": "Proporcja obrazu", + "label": "Etykieta", + "line_height": "Wysokość linii", + "link": "Link", + "layout_gap": "Luka w układzie", + "minimum_height": "Minimalna wysokość", + "opacity": "Nieprzezroczystość", + "primary_color": "Linki", + "section_width": "Szerokość sekcji", + "size": "Rozmiar", + "slide_spacing": "Luka w slajdzie", + "slide_width": "Szerokość slajdu", + "slideshow_fullwidth": "Slajdy o pełnej szerokości", + "style": "Styl", + "text_case": "Wielkość liter", + "z_index": "Indeks Z", + "limit_content_width": "Ogranicz szerokość treści", + "color_scheme": "Kolorystyka", + "inherit_color_scheme": "Kolorystyka", + "product_count": "Liczba produktów", + "product_type": "Typ produktu", + "content_width": "Szerokość treści", + "collection": "Kolekcja", + "enable_sticky_content": "Włącz przypiętą zawartość na komputerze", + "error_color": "Błąd", + "success_color": "Powodzenie", + "primary_font": "Czcionka podstawowa", + "secondary_font": "Czcionka dodatkowa", + "tertiary_font": "Czcionka trzeciorzędna", + "columns": "Kolumny", + "items_to_show": "Pozycje do wyświetlenia", + "layout": "Układ", + "layout_type": "Typ", + "show_grid_layout_selector": "Wyświetl selektor układu siatki", + "view_more_show": "Pokaż przycisk „Wyświetl wszystkie”", + "image_gap": "Odstęp między obrazami", + "width_desktop": "Szerokość na komputerze", + "width_mobile": "Szerokość na urządzeniu mobilnym", + "border_style": "Styl obramowania", + "height": "Wysokość", + "thickness": "Grubość", + "stroke": "Obrys", + "filter_style": "Fitruj styl", + "swatches": "Próbki", + "quick_add_colors": "Szybkie dodawanie kolorów", + "divider_color": "Separator", + "border_opacity": "Nieprzezroczystość obramowania", + "hover_background": "Tło obszaru aktywnego", + "hover_borders": "Obramowanie obszaru aktywnego", + "hover_text": "Tekst obszaru aktywnego", + "primary_hover_color": "Linki obszaru aktywnego", + "primary_button_text": "Tekst głównego przycisku", + "primary_button_background": "Tło głównego przycisku", + "primary_button_border": "Obramowanie przycisku głównego", + "secondary_button_text": "Tekst przycisku dodatkowego", + "secondary_button_background": "Tło przycisku dodatkowego", + "secondary_button_border": "Obramowanie przycisku dodatkowego", + "shadow_color": "Cień", + "video_autoplay": "Autoodtwarzanie", + "video_cover_image": "Obraz okładki", + "video_external_url": "Adres URL", + "video_source": "Źródło", + "background_color": "Kolor tła", + "first_row_media_position": "Pozycja multimediów w pierwszym wierszu", + "hide_padding": "Ukryj wypełnienie", + "size_mobile": "Rozmiar mobilny", + "pixel_size_mobile": "Rozmiar w pikselach", + "percent_size_mobile": "Rozmiar w procentach", + "unit": "Jednostka", + "custom_mobile_size": "Niestandardowy rozmiar mobilny", + "fixed_height": "Wysokość w pikselach", + "fixed_width": "Szerokość w pikselach", + "percent_height": "Wysokość w procentach", + "percent_width": "Szerokość w procentach", + "percent_size": "Rozmiar w procentach", + "pixel_size": "Rozmiar w pikselach", + "card_image_height": "Wysokość obrazu produktu", + "logo_font": "Czcionka logo", + "accordion": "Akordeon", + "aspect_ratio": "Współczynnik proporcji", + "auto_rotate_announcements": "Automatyczna zmiana ogłoszeń", + "auto_rotate_slides": "Automatyczna zmiana slajdów", + "badge_corner_radius": "Promień rogu", + "badge_position": "Położenie na kartach", + "badge_sale_color_scheme": "W promocji", + "badge_sold_out_color_scheme": "Wyprzedane", + "behavior": "Zachowanie", + "blur": "Rozmycie cienia", + "border": "Obramowanie", + "bottom": "Dół", + "carousel_on_mobile": "Karuzela na urządzenia mobilne", + "cart_count": "Liczba produktów w koszyku", + "cart_items": "Pozycje w koszyku", + "cart_related_products": "Powiązane produkty", + "cart_title": "Koszyk", + "cart_total": "Całkowita wartość koszyka", + "cart_type": "Typ", + "case": "Wielkość liter", + "checkout_buttons": "Przyciski przyspieszonej realizacji zakupu", + "collection_list": "Kolekcje", + "collection_templates": "Szablony kolekcji", + "content": "Treść", + "corner_radius": "Promień rogu", + "country_region": "Kraj/region", + "currency_code": "Kod waluty", + "custom_height": "Niestandardowa wysokość", + "desktop_height": "Szerokość na komputerze", + "direction": "Kierunek", + "display": "Wyświetl", + "divider_thickness": "Grubość separatora", + "divider": "Separator", + "dividers": "Separatory", + "drop_shadow": "Rzuć cień", + "empty_state_collection_info": "Wyświetlane przed wprowadzeniem wyszukiwania", + "empty_state_collection": "Status pustej kolekcji", + "enable_filtering": "Filtry", + "enable_grid_density": "Kontrola układu siatki", + "enable_sorting": "Sortowanie", + "enable_zoom": "Włącz powiększenie", + "equal_columns": "Równe kolumny", + "expand_first_group": "Rozwiń pierwszą grupę", + "extend_media_to_screen_edge": "Rozciągnij multimedia do krawędzi ekranu", + "extend_summary": "Rozciągnij do krawędzi ekranu", + "extra_large": "Bardzo duży", + "extra_small": "Bardzo mała", + "flag": "Flaga", + "font_price": "Czcionka ceny", + "font_weight": "Grubość czcionki", + "font": "Czcionka", + "full_width_first_image": "Pierwszy obraz o pełnej szerokości", + "full_width_on_mobile": "Pełna szerokość na urządzeniu mobilnym", + "heading_preset": "Ustawienie wstępne nagłówka", + "hide_unselected_variant_media": "Ukryj niewybrane pliki multimedialne wariantów", + "horizontal_gap": "Odstęp w poziomie", + "horizontal_offset": "Poziome przesunięcie cienia", + "hover_behavior": "Zachowanie po najechaniu kursorem", + "icon_background": "Tło ikony", + "icons": "Ikony", + "image_border_radius": "Promień rogu obrazu", + "installments": "Raty", + "integrated_button": "Zintegrowany przycisk", + "language_selector": "Selektor języka", + "large": "Duży", + "left_padding": "Wypełnienie z lewej", + "left": "Lewa strona", + "letter_spacing": "Odstęp między literami", + "limit_media_to_screen_height": "Ograniczenie do wysokości ekranu", + "limit_product_details_width": "Ogranicz szerokość szczegółów produktu", + "link_preset": "Ustawienie wstępne linku", + "links": "Linki", + "logo": "Logo", + "loop": "Pętla", + "make_details_sticky_desktop": "Przyklejony na komputerach", + "max_width": "Maks. szerokość", + "media_height": "Wysokość multimediów", + "media_overlay": "Nakładka na multimediach", + "media_position": "Pozycja multimediów", + "media_type": "Typ multimediów", + "media_width": "Szerokość multimediów", + "menu": "Menu", + "mobile_columns": "Kolumny na urządzeniu mobilnym", + "mobile_height": "Wysokość na urządzeniu mobilnym", + "mobile_logo_image": "Logo na urządzeniu mobilnym", + "mobile_quick_add": "Szybkie dodawanie na urządzeniu mobilnym", + "motion_direction": "Kierunek ruchu", + "motion": "Ruch", + "movement_direction": "Kierunek ruchu", + "navigation_bar_color_scheme": "Schemat kolorów paska nawigacji", + "navigation_bar": "Pasek nawigacji", + "navigation": "Nawigacja", + "open_new_tab": "Otwórz link w nowej karcie", + "overlay_color": "Kolor nakładki", + "overlay": "Nakładka", + "padding_bottom": "Wypełnienie na dole", + "padding_horizontal": "Wypełnienie w poziomie", + "padding_top": "Wypełnienie na górze", + "page_width": "Szerokość strony", + "pagination": "Paginacja", + "placement": "Umieszczanie", + "position": "Pozycja", + "preset": "Ustawienie wstępne", + "product_cards": "Karty produktów", + "product_pages": "Strony produktu", + "product_templates": "Szablony produktów", + "products": "Produkty", + "quick_add": "Szybkie dodawanie", + "ratio": "Proporcja", + "regular": "Zwykły", + "review_count": "Liczba recenzji", + "right": "Prawa strona", + "row_height": "Wysokość rzędu", + "row": "Wiersz", + "seller_note": "Zezwalaj na dodawanie uwag dla sprzedawcy", + "shape": "Kształt", + "show_as_accordion": "Wyświetlaj jako akordeon na urządzeniach mobilnych", + "show_sale_price_first": "Najpierw pokaż cenę promocyjną", + "show_tax_info": "Informacje podatkowe", + "show": "Pokaż", + "small": "Mała", + "speed": "Szybkość", + "statement": "Wyciąg", + "sticky_header": "Przyklejony nagłówek", + "text_hierarchy": "Hierarchia tekstu", + "text_presets": "Ustawienia wstępne tekstu", + "title": "Tytuł", + "top": "Góra", + "type": "Typ", + "type_preset": "Ustawienie wstępne tekstu", + "underline_thickness": "Grubość podkreślenia", + "variant_images": "Obrazy wariantów", + "vendor": "Dostawca", + "vertical_gap": "Odstęp w pionie", + "vertical_offset": "Przesunięcie cienia w pionie", + "vertical_on_mobile": "Pionowo na urządzeniu mobilnym", + "view_all_as_last_card": "„Wyświetl wszystkie” jako ostatnia karta", + "weight": "Waga", + "wrap": "Zawijaj", + "read_only": "Tylko do odczytu", + "always_stack_buttons": "Zawsze układaj przyciski", + "custom_mobile_width": "Niestandardowa szerokość na urządzeniu mobilnym", + "gradient_direction": "Kierunek gradientu", + "overlay_style": "Styl nakładki", + "shadow_opacity": "Krycie cienia", + "show_filter_label": "Etykiety tekstowe dla zastosowanych filtrów", + "show_swatch_label": "Etykiety tekstowe dla próbek", + "transparent_background": "Przezroczyste tło", + "account": "Konto", + "align_baseline": "Wyrównaj linię bazową tekstu", + "add_discount_code": "Włącz rabaty w koszyku", + "background_overlay": "Nakładka tła", + "background_media": "Multimedia w tle", + "border_thickness": "Grubość obramowania", + "bottom_row": "Wiersz dolny", + "button_text_case": "Wielkość liter tekstu", + "button_text_weight": "Waga tekstu", + "auto_open_cart_drawer": "„Dodaj do koszyka” automatycznie otwiera szufladę", + "collection_count": "Liczba kolekcji", + "custom_liquid": "Kod Liquid", + "default": "Domyślne", + "default_logo": "Domyślne logo", + "divider_width": "Szerokość separatora", + "headings": "Nagłówki", + "hide_logo_on_home_page": "Ukryj logo na stronie głównej", + "horizontal_padding": "Wypełnienie poziome", + "inverse": "Odwrócenie", + "inverse_logo": "Odwrócone logo", + "layout_style": "Styl", + "length": "Długość", + "mobile_pagination": "Paginacja mobilna", + "open_row_by_default": "Domyślnie otwórz wiersz", + "page_transition_enabled": "Przejścia między stronami", + "search": "Wyszukiwanie", + "search_icon": "Ikona wyszukiwania", + "search_position": "Pozycja", + "search_row": "Wiersz", + "show_author": "Autor", + "show_alignment": "Pokaż dopasowanie", + "show_count": "Pokaż liczbę", + "show_date": "Data", + "show_pickup_availability": "Pokaż możliwość odbioru", + "show_search": "Pokaż wyszukiwanie", + "use_inverse_logo": "Użyj odwróconego logo", + "vertical_padding": "Wypełnienie pionowe", + "visibility": "Widoczność", + "product_corner_radius": "Promień rogu produktu", + "card_corner_radius": "Promień rogu karty", + "alignment_mobile": "Dopasowanie na urządzeniu mobilnym", + "animation_repeat": "Powtórz animację", + "blurred_reflection": "Zamazane odbicie", + "card_hover_effect": "Efekt najechania kursorem na kartę", + "card_size": "Rozmiar karty", + "collection_title_case": "Wielkość liter tytułu kolekcji", + "effects": "Efekty", + "inventory_threshold": "Niski próg zapasu", + "mobile_card_size": "Rozmiar karty mobilnej", + "page": "Strona", + "product_and_card_title_case": "Wielkość liter tytułu produktu i karty", + "product_title_case": "Wielkość liter tytułu produktu", + "reflection_opacity": "Nieprzezroczystość odbicia", + "right_padding": "Wypełnienie z prawej", + "show_inventory_quantity": "Wyświetl niski poziom zapasu", + "text_label_case": "Wielkość liter etykiety tekstowej", + "transition_to_main_product": "Przejście z karty produktu do strony produktu", + "show_second_image_on_hover": "Pokaż drugi obraz po najechaniu kursorem", + "media": "Multimedia", + "product_card_carousel": "Wyświetl karuzelę", + "media_fit": "Dopasowanie multimediów", + "scroll_speed": "Czas do następnego ogłoszenia" + }, + "options": { + "adapt_to_image": "Dostosuj do obrazu", + "apple": "Jabłko", + "arrow": "Strzałka", + "banana": "Banan", + "bottle": "Butelka", + "box": "Skrzynka", + "buttons": "Przyciski", + "carrot": "Marchewka", + "center": "Środek", + "chat_bubble": "Dymek czatu", + "clipboard": "Podkładka do pisania", + "contain": "Zawiera", + "counter": "Licznik", + "cover": "Strona tytułowa", + "custom": "Niestandardowy", + "dairy_free": "Bezmleczne", + "dairy": "Nabiał", + "dropdowns": "Listy rozwijane", + "dots": "Kropki", + "dryer": "Suszarka", + "end": "Koniec", + "eye": "Oko", + "facebook": "Facebook", + "fire": "Ogień", + "gluten_free": "Bez glutenu", + "heart": "Serce", + "horizontal": "W poziomie", + "instagram": "Instagram", + "iron": "Żelazko", + "large": "Duży", + "leaf": "Liść", + "leather": "Skóra", + "lightning_bolt": "Błyskawica", + "lipstick": "Pomadka do ust", + "lock": "Zamek", + "map_pin": "Pinezka na mapie", + "medium": "Średni", + "none": "Brak", + "numbers": "Liczby", + "nut_free": "Bez orzechów", + "pants": "Spodnie", + "paw_print": "Odcisk łapy", + "pepper": "Pieprz", + "perfume": "Perfumy", + "pinterest": "Pinterest", + "plane": "Samolot", + "plant": "Roślina", + "price_tag": "Metka z ceną", + "question_mark": "Znak zapytania", + "recycle": "Zutylizuj", + "return": "Zwrot", + "ruler": "Linijka", + "serving_dish": "Naczynie do serwowania", + "shirt": "Koszula", + "shoe": "But", + "silhouette": "Sylwetka", + "small": "Mały", + "snapchat": "Snapchat", + "snowflake": "Płatek śniegu", + "star": "Gwiazdka", + "start": "Początek", + "stopwatch": "Stoper", + "tiktok": "TikTok", + "truck": "Ciężarówka", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "vertical": "W pionie", + "vimeo": "Vimeo", + "washing": "Pranie", + "auto": "Automatyczny", + "default": "Domyślny", + "fill": "Wypełnienie", + "fit": "Dopasowanie", + "full": "Pełne", + "full_and_page": "Pełne tło, zawartość na szerokość strony", + "heading": "Nagłówek", + "landscape": "Poziomo", + "lg": "LG", + "link": "Link", + "lowercase": "małe litery", + "m": "M", + "outline": "Obrys", + "page": "Strona", + "portrait": "Pionowo", + "s": "S", + "sentence": "Zdanie", + "solid": "Pełny", + "space_between": "Odstęp między", + "square": "Kwadratowy", + "uppercase": "Duże litery", + "circle": "Koło", + "swatches": "Próbki", + "full_and_page_offset_left": "Pełne tło, treść na szerokość strony, przesunięcie w lewo", + "full_and_page_offset_right": "Pełne tło, treść na szerokość strony, przesunięcie w prawo", + "offset_left": "Przesunięcie w lewo", + "offset_right": "Przesunięcie w prawo", + "page_center_aligned": "Strona z wyrównaniem do środka", + "page_left_aligned": "Strona wyrównana do lewej", + "page_right_aligned": "Strona wyrównana do prawej", + "button": "Przycisk", + "caption": "Napis", + "h1": "Nagłówek 1", + "h2": "Nagłówek 2", + "h3": "Nagłówek 3", + "h4": "Nagłówek 4", + "h5": "Nagłówek 5", + "h6": "Nagłówek 6", + "paragraph": "Akapit", + "primary": "Główna", + "secondary": "Dodatkowa", + "tertiary": "Trzeciorzędna", + "chevron_left": "Pagon skierowany w lewo", + "chevron_right": "Pagon skierowany w prawo", + "diamond": "Romb", + "grid": "Siatka", + "parallelogram": "Równoległobok", + "rounded": "Zaokrąglenie", + "fit_content": "Dopasowanie", + "pills": "Przyciski", + "heavy": "Gruby", + "thin": "Cienki", + "drawer": "Szuflada", + "preview": "Podgląd", + "text": "Tekst", + "video_uploaded": "Przesłany", + "video_external_url": "Zewnętrzny adres URL", + "up": "W górę", + "down": "W dół", + "gradient": "Gradient", + "fixed": "Stałe", + "pixel": "Piksel", + "percent": "Procent", + "aspect_ratio": "Współczynnik proporcji", + "above_carousel": "Powyżej karuzeli", + "all": "Wszystkie", + "always": "Zawsze", + "arrows_large": "Duże strzałki", + "arrows": "Strzałki", + "balance": "Balance", + "bento": "Bento", + "black": "Czarny", + "bluesky": "Bluesky", + "body_large": "Tekst podstawowy (duży)", + "body_regular": "Tekst podstawowy (standardowy)", + "body_small": "Tekst podstawowy (mały)", + "bold": "Pogrubienie", + "bottom_left": "Lewy dolny", + "bottom_right": "Prawy dolny", + "bottom": "Dół", + "capitalize": "Wielkie litery", + "caret": "Trójkątna strzałka", + "carousel": "Karuzela", + "check_box": "Pole wyboru", + "chevron_large": "Duża jodełka", + "chevron": "Jodełka", + "chevrons": "Jodełka", + "classic": "Klasyczny", + "collection_images": "Obraz kolekcji", + "color": "Kolor", + "complementary": "Uzupełniające", + "dissolve": "Rozmyj", + "dotted": "Kropkowane", + "editorial": "Redakcyjny", + "extra_large": "Bardzo duży", + "extra_small": "Bardzo mała", + "featured_collections": "Polecane kolekcje", + "featured_products": "Polecane produkty", + "font_primary": "Główna", + "font_secondary": "Dodatkowy", + "font_tertiary": "Trzeciorzędna", + "forward": "Dalej", + "full_screen": "Tryb pełnoekranowy", + "heading_extra_large": "Nagłówek (bardzo duży)", + "heading_extra_small": "Nagłówek (bardzo mały)", + "heading_large": "Nagłówek (duży)", + "heading_regular": "Nagłówek (standardowy)", + "heading_small": "Nagłówek (mały)", + "icon": "Ikona", + "image": "Obraz", + "input": "Dane wejściowe", + "inside_carousel": "Wewnątrz karuzeli", + "inverse_large": "Odwrócone duże", + "inverse": "Odwrócone", + "large_arrows": "Duże strzałki", + "large_chevrons": "Duża jodełka", + "left": "Lewa strona", + "light": "Jasny", + "linkedin": "LinkedIn", + "loose": "Luźny", + "media_first": "Multimedia w pierwszej kolejności", + "media_second": "Multimedia w drugiej kolejności", + "modal": "Tryb modalny", + "narrow": "Wąski", + "never": "Nigdy", + "next_to_carousel": "Obok karuzeli", + "normal": "Standard", + "nowrap": "Bez zawijania", + "off_media": "Poza multimediami", + "on_media": "Na multimediach", + "on_scroll_up": "Przy przewijaniu w górę", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Okrągły przełącznik", + "plus": "Plus", + "pretty": "Pretty", + "price": "Cena", + "primary_style": "Styl podstawowy", + "rectangle": "Prostokąt", + "regular": "Zwykły", + "related": "Powiązane", + "reverse": "Odwróć", + "rich_text": "Tekst sformatowany", + "right": "Prawa strona", + "secondary_style": "Styl dodatkowy", + "semibold": "Półpogrubiony", + "shaded": "Cieniowany", + "show_second_image": "Pokaż drugi obraz", + "single": "Pojedyncze", + "slide_left": "Przesuń w lewo", + "slide_up": "Przesuń w górę", + "spotify": "Spotify", + "stack": "Stos", + "text_only": "Tylko tekst", + "threads": "Threads", + "thumbnails": "Miniatury", + "tight": "Tight", + "top_left": "U góry po lewej", + "top_right": "U góry po prawej", + "top": "Góra", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Podkreślenie", + "video": "Film", + "wide": "Szeroki", + "youtube": "Youtube", + "accent": "Akcent", + "below_image": "Pod obrazem", + "body": "Tekst podstawowy", + "button_primary": "Przycisk główny", + "button_secondary": "Przycisk dodatkowy", + "compact": "Kompaktowa", + "crop_to_fit": "Przytnij, aby dopasować", + "hidden": "Ukryte", + "hint": "Wskazówka", + "maintain_aspect_ratio": "Zachowaj współczynnik proporcji", + "off": "Wył.", + "on_image": "Na obrazie", + "social_bluesky": "Media społecznościowe: Bluesky", + "social_facebook": "Media społecznościowe: Facebook", + "social_instagram": "Media społecznościowe: Instagram", + "social_linkedin": "Media społecznościowe: LinkedIn", + "social_pinterest": "Media społecznościowe: Pinterest", + "social_snapchat": "Media społecznościowe: Snapchat", + "social_spotify": "Media społecznościowe: Spotify", + "social_threads": "Media społecznościowe: Threads", + "social_tiktok": "Media społecznościowe: TikTok", + "social_tumblr": "Media społecznościowe: Tumblr", + "social_twitter": "Media społecznościowe: X (Twitter)", + "social_whatsapp": "Media społecznościowe: WhatsApp", + "social_vimeo": "Media społecznościowe: Vimeo", + "social_youtube": "Media społecznościowe: YouTube", + "spotlight": "Spotlight", + "standard": "Standardowa", + "subheading": "Nagłówek podrzędny", + "blur": "Zamaż", + "lift": "Uniesienie", + "reveal": "Pokaż", + "scale": "Skalowanie", + "subtle_zoom": "Powiększenie" + }, + "content": { + "background_video": "Film w tle", + "describe_the_video_for": "Opisz film dla klientów korzystających z czytników ekranu. [Dowiedz się więcej](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "Szerokość jest automatycznie dostosowywana do urządzeń mobilnych.", + "advanced": "Zaawansowane", + "background_image": "Obraz tła", + "block_size": "Rozmiar bloku", + "borders": "Obramowania", + "section_size": "Rozmiar sekcji", + "slideshow_width": "Szerokość slajdu", + "typography": "Typografia", + "complementary_products": "Produkty uzupełniające należy skonfigurować za pomocą aplikacji Search & Discovery. [Dowiedz się więcej](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Kolumny będą automatycznie optymalizowane pod kątem urządzeń mobilnych", + "content_width": "Szerokość treści ma zastosowanie tylko wtedy, gdy szerokość sekcji jest ustawiona na pełny zakres.", + "adjustments_affect_all_content": "Dotyczy całej zawartości w tym bloku", + "responsive_font_sizes": "Rozmiary są automatycznie skalowane dla wszystkich rozmiarów ekranów", + "buttons": "Przyciski", + "swatches": "Próbki", + "variant_settings": "Ustawienia wariantów", + "background": "Tło", + "cards_layout": "Układ kart", + "section_layout": "Układ sekcji", + "mobile_size": "Rozmiar mobilny", + "appearance": "Wygląd", + "arrows": "Strzałki", + "body_size": "Rozmiar tekstu podstawowego", + "bottom_row_appearance": "Wygląd dolnego rzędu", + "carousel_navigation": "Nawigacja po karuzeli", + "carousel_pagination": "Paginacja karuzeli", + "copyright": "Prawo autorskie", + "edit_logo_in_theme_settings": "Edytuj logo w [ustawieniach szablonu](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Edytuj format cen w [ustawieniach szablonu](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Edytuj styl wariantów w [ustawieniach szablonu](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Rejestracje dodają [profile klienta](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Aby przycisk był widoczny, kanał Shop musi być zainstalowany, a usługa Shop Pay musi być aktywna. [Dowiedz się więcej](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Czcionki", + "grid": "Siatka", + "heading_size": "Rozmiar nagłówka", + "image": "Obraz", + "input": "Dane wejściowe", + "layout": "Układ", + "link": "Link", + "link_padding": "Wypełnienie linku", + "localization": "Lokalizacja", + "logo": "Logo", + "margin": "Marża", + "media": "Multimedia", + "media_1": "Multimedia 1", + "media_2": "Multimedia 2", + "menu": "Menu", + "mobile_layout": "Układ na urządzeniu mobilnym", + "padding": "Wypełnienie", + "padding_desktop": "Wypełnienie pulpitu", + "paragraph": "Akapit", + "policies": "Zasady", + "popup": "Wyskakujące okienko", + "search": "Wyszukiwanie", + "size": "Rozmiar", + "social_media": "Media społecznościowe", + "submit_button": "Przycisk Prześlij", + "text_presets": "Ustawienia wstępne tekstu", + "transparent_background": "Przezroczyste tło", + "typography_primary": "Typografia podstawowa", + "typography_secondary": "Typografia dodatkowa", + "typography_tertiary": "Typografia trzeciorzędna", + "mobile_width": "Szerokość na urządzeniu mobilnym", + "width": "Szerokość", + "carousel": "Karuzela", + "colors": "Kolory", + "collection_page": "Strona kolekcji", + "copyright_info": "Dowiedz się, jak [edytować Twoje oświadczenie o prawach autorskich](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Konto klienta", + "edit_empty_state_collection_in_theme_settings": "Edytuj kolekcję pustych stanów w [ustawieniach szablonu](/editor?context=theme&category=search)", + "home_page": "Strona główna", + "images": "Zdjęcia", + "inverse_logo_info": "Używana po ustawieniu transparentnego tła nagłówka na „Odwrócenie”", + "manage_customer_accounts": "[Zarządzaj widocznością](/admin/settings/customer_accounts) w ustawieniach konta klienta. Starsze konta nie są obsługiwane.", + "manage_policies": "[Zarządzaj politykami](/admin/settings/legal)", + "product_page": "Strona produktu", + "text": "Tekst", + "thumbnails": "Miniatury", + "visibility": "Widoczność", + "visible_if_collection_has_more_products": "Widoczne, jeśli kolekcja ma więcej produktów niż pokazano", + "grid_layout": "Układ siatki", + "app_required_for_ratings": "Do oceniania produktów wymagana jest aplikacja. [Dowiedz się więcej](https://help.shopify.com/manual/apps)", + "icon": "Ikona", + "manage_store_name": "[Zarządzaj nazwą sklepu](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Wyświetla kolekcję z sekcji nadrzędnej", + "resource_reference_collection_card_image": "Wyświetla obraz z kolekcji nadrzędnej", + "resource_reference_collection_title": "Wyświetla tytuł z kolekcji nadrzędnej", + "resource_reference_product": "Automatycznie łączy z produktem nadrzędnym", + "resource_reference_product_card": "Wyświetla produkt z sekcji nadrzędnej", + "resource_reference_product_inventory": "Wyświetla zapas z produktu nadrzędnego", + "resource_reference_product_price": "Wyświetla cenę z produktu nadrzędnego", + "resource_reference_product_recommendations": "Wyświetla polecenia na podstawie produktu nadrzędnego", + "resource_reference_product_review": "Wyświetla recenzje z produktu nadrzędnego", + "resource_reference_product_swatches": "Wyświetla próbki z produktu nadrzędnego", + "resource_reference_product_title": "Wyświetla tytuł z produktu nadrzędnego", + "resource_reference_product_variant_picker": "Wyświetla warianty z produktu nadrzędnego", + "resource_reference_product_media": "Wyświetla multimedia z produktu nadrzędnego", + "product_media": "Multimedia produktu", + "section_link": "Link sekcji" + }, + "html_defaults": { + "share_information_about_your": "

Udostępnij klientom informacje o swojej marce. Opisz produkt, udostępnij ogłoszenia lub przywitaj klientów w swoim sklepie.

" + }, + "text_defaults": { + "collapsible_row": "Zwijany wiersz", + "button_label": "Kup teraz", + "heading": "Nagłówek", + "email_signup_button_label": "Subskrybuj", + "accordion_heading": "Nagłówek akordeonu", + "contact_form_button_label": "Prześlij", + "popup_link": "Wyskakujący link", + "sign_up": "Zarejestruj się", + "welcome_to_our_store": "Witamy w naszym sklepie", + "be_bold": "Odważ się.", + "shop_our_latest_arrivals": "Odkryj nasze najnowsze produkty!" + }, + "info": { + "video_alt_text": "Opisz film dla użytkowników technologii asystujących", + "video_autoplay": "Filmy będą domyślnie wyciszone", + "video_external": "Użyj adresu URL do YouTube lub Vimeo", + "link_info": "Opcjonalnie: umożliwia kliknięcie ikony", + "carousel_layout_on_mobile": "Karuzela jest używana na urządzeniach mobilnych", + "carousel_hover_behavior_not_supported": "Najechanie kursorem na karuzelę nie jest obsługiwane, gdy wybrano karuzelę na poziomie sekcji.", + "checkout_buttons": "Umożliwia kupującym szybsze dokonanie zakupu i może poprawić konwersję. [Dowiedz się więcej](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Niestandardowy nagłówek", + "edit_presets_in_theme_settings": "Edytuj ustawienia wstępne w [ustawieniach szablonu](/editor?context=theme&category=typography)", + "enable_filtering_info": "Dostosuj filtry za pomocą [aplikacji Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Układ siatki jest używany dla urządzeń mobilnych", + "logo_font": "Ma zastosowanie tylko wtedy, gdy logo nie jest wybrane", + "manage_countries_regions": "[Zarządzaj krajami/regionami](/admin/settings/markets)", + "manage_languages": "[Zarządzaj językami](/admin/settings/languages)", + "transparent_background": "Sprawdź każdy szablon, w którym zastosowano przezroczyste tło, pod kątem czytelności", + "aspect_ratio_adjusted": "Dostosowano w niektórych układach", + "auto_open_cart_drawer": "Gdy ta opcja jest aktywna, szuflada koszyka otworzy się automatycznie po dodaniu produktu do koszyka.", + "custom_liquid": "Dodaj fragmenty kodu aplikacji lub inny kod, aby utworzyć zaawansowane dostosowania. [Dowiedz się więcej](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "Dotyczy tylko obrazów", + "hover_effects": "Dotyczy kart produktów i kolekcji", + "pills_usage": "Używane przez zastosowane filtry, kody rabatowe i sugestie wyszukiwania" + }, + "categories": { + "product_list": "Polecana kolekcja", + "basic": "Basic", + "collection": "Kolekcja", + "collection_list": "Lista kolekcji", + "footer": "Stopka", + "forms": "Formularze", + "header": "Nagłówek", + "layout": "Układ", + "links": "Linki", + "product": "Produkt", + "banners": "Banery", + "collections": "Kolekcje", + "custom": "Niestandardowy", + "decorative": "Ozdobne", + "products": "Produkty", + "other_sections": "Inny", + "storytelling": "Opowiadanie historii" + } +} diff --git a/locales/pt-BR.json b/locales/pt-BR.json new file mode 100644 index 000000000..b6a5ba59f --- /dev/null +++ b/locales/pt-BR.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Carregar vídeo: {{ description }}", + "sold_out": "Esgotado", + "email_signup": { + "label": "E-mail", + "placeholder": "E-mail", + "success": "Obrigado por se inscrever!" + }, + "filter": "Filtrar", + "payment_methods": "Formas de pagamento", + "contact_form": { + "name": "Nome", + "email": "E-mail", + "phone": "Telefone", + "comment": "Comentário", + "post_success": "Agradecemos seu contato. Retornaremos o mais rápido possível.", + "error_heading": "Ajuste o seguinte:" + } + }, + "accessibility": { + "play_model": "Reproduzir modelo 3D", + "play_video": "Reproduzir vídeo", + "unit_price": "Preço unitário", + "country_results_count": "{{ count }} resultados", + "slideshow_pause": "Pausar apresentação de slides", + "slideshow_play": "Reproduzir apresentação de slides", + "remove_item": "Remover {{ title}}", + "skip_to_text": "Pular para o conteúdo", + "skip_to_product_info": "Pular para as informações do produto", + "skip_to_results_list": "Ir para a lista de resultados", + "new_window": "Abre em uma nova janela.", + "close_dialog": "Fechar caixa de diálogo", + "reset_search": "Reinicializar pesquisa", + "search_results_count": "{{ count }} resultados de pesquisa encontrados para \"{{ query }}\"", + "search_results_no_results": "Não encontramos resultados para \"{{ query }}\"", + "slideshow_next": "Próximo slide", + "slideshow_previous": "Slide anterior", + "filters": "Filtros", + "filter_count": { + "one": "{{ count }} filtro aplicado", + "other": "{{ count }} filtros aplicados", + "many": "{{ count }} filtros aplicados" + }, + "account": "Abrir menu da conta", + "cart": "Carrinho", + "cart_count": "Total de itens no carrinho", + "menu": "Menu", + "country_region": "País/Região", + "slide_status": "Slide {{ index }} de {{ length }}", + "scroll_to": "Rolar até {{ title }}", + "loading_product_recommendations": "Carregando recomendações de produtos", + "discount": "Aplicar um código de desconto", + "discount_applied": "Código de desconto aplicado: {{ code }}", + "open_cart_drawer": "Abrir carrinho", + "inventory_status": "Status do estoque", + "pause_video": "Pausar o vídeo", + "find_country": "Localizar o país", + "localization_region_and_language": "Abrir seletor de região e idioma", + "open_search_modal": "Abrir pesquisa", + "decrease_quantity": "Diminuir a quantidade", + "increase_quantity": "Aumentar a quantidade", + "rating": "A classificação deste produto é {{ rating }} de 5", + "quantity": "Quantidade", + "nested_product": "{{ product_title }} para {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Adicionar ao carrinho", + "clear_all": "Limpar tudo", + "remove": "Remover", + "view_in_your_space": "Ver em seu espaço", + "show_filters": "Filtrar", + "clear": "Limpar", + "continue_shopping": "Voltar à loja", + "log_in_html": "Já tem conta? Faça login para finalizar a compra mais rápido.", + "see_items": { + "one": "Ver {{ count }} item", + "other": "Ver {{ count }} itens", + "many": "Ver {{ count }} itens" + }, + "view_all": "Ver tudo", + "add": "Adicionar", + "choose": "Escolher", + "added": "Adicionado", + "show_less": "Exibir menos", + "show_more": "Exibir mais", + "close": "Fechar", + "more": "Mais", + "reset": "Restaurar", + "zoom": "Zoom", + "close_dialog": "Fechar caixa de diálogo", + "back": "Voltar", + "log_in": "Fazer login", + "log_out": "Sair", + "remove_discount": "Remover desconto {{ code }}", + "enter_using_password": "Entrar usando a senha", + "submit": "Enviar", + "enter_password": "Insira a senha", + "view_store_information": "Ver as informações da loja", + "apply": "Aplicar", + "sign_in_options": "Outras opções de login", + "sign_up": "Criar conta", + "open_image_in_full_screen": "Abrir imagem em tela cheia", + "sort": "Classificar", + "show_all_options": "Mostrar todas as opções" + }, + "content": { + "reviews": "avaliações", + "language": "Idioma", + "localization_region_and_language": "Região e idioma", + "no_results_found": "Nenhum resultado encontrado", + "cart_total": "Total do carrinho", + "your_cart_is_empty": "O carrinho está vazio", + "cart_estimated_total": "Total estimado", + "seller_note": "Instruções especiais", + "cart_subtotal": "Subtotal", + "discounts": "Descontos", + "discount": "Desconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Tributos de importação e outros tributos incluídos. Descontos e frete calculados no checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Tributos de importação e outros tributos incluídos. Descontos e frete calculados no checkout.", + "taxes_included_shipping_at_checkout_with_policy_html": "Tributos incluídos. Descontos e frete calculados no checkout.", + "taxes_included_shipping_at_checkout_without_policy": "Tributos incluídos. Descontos e frete calculados no checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Tributos de importação incluídos. Tributos, descontos e frete calculados no checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Tributos de importação incluídos. Tributos, descontos e frete calculados no checkout.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Tributos, descontos e frete calculados no checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Tributos, descontos e frete calculados no checkout.", + "checkout": "Finalizar a compra", + "cart_title": "Cart", + "product_image": "Imagem do produto", + "product_information": "Informações do produto", + "product_total": "Total de produtos", + "quantity": "Quantidade", + "price": "Preço", + "price_regular": "Preço normal", + "price_compare_at": "Comparação de preços", + "price_sale": "Preço promocional", + "duties_and_taxes_included": "Tributos de importação e outros tributos incluídos.", + "duties_included": "Tributos de importação incluídos.", + "shipping_policy_html": "Frete calculado no checkout.", + "taxes_included": "Tributos incluídos.", + "product_badge_sold_out": "Esgotado", + "product_badge_sale": "Promoção", + "search_input_label": "Pesquisa", + "search_input_placeholder": "Pesquisa", + "search_results": "Resultados da pesquisa", + "search_results_label": "Resultados da pesquisa", + "search_results_no_results": "Sem resultado para \"{{ terms }}\". Tente outra pesquisa.", + "search_results_resource_articles": "Posts do blog", + "search_results_resource_collections": "Coleções", + "search_results_resource_pages": "Páginas", + "search_results_resource_products": "Produtos", + "search_results_resource_queries": "Sugestões de pesquisa", + "search_results_view_all": "Ver tudo", + "search_results_view_all_button": "Ver tudo", + "search_results_resource_products_count": { + "one": "{{ count }} produto", + "other": "{{ count }} produtos", + "many": "{{ count }} produtos" + }, + "grid_view": { + "default_view": "Padrão", + "grid_fieldset": "Grade da coluna", + "single_item": "Único", + "zoom_out": "Menos zoom" + }, + "unavailable": "Indisponível", + "collection_placeholder": "Título da coleção", + "product_card_placeholder": "Título do produto", + "recently_viewed_products": "Visto recentemente", + "product_count": "Contagem de produtos", + "item_count": { + "one": "{{ count }} item", + "other": "{{ count }} itens", + "many": "{{ count }} itens" + }, + "errors": "Erros", + "search": "Pesquisa", + "search_results_no_results_check_spelling": "Sem resultado para \"{{ terms }}\". Verifique a ortografia ou use uma palavra ou frase diferente.", + "featured_products": "Produtos em destaque", + "no_products_found": "Nenhum produto encontrado.", + "price_from": "A partir de {{ price }}", + "use_fewer_filters_html": "Tente usar menos filtros ou limpar tudo.", + "filters": "Filtros", + "price_filter_html": "O maior preço é {{ price }}", + "read_more": "Leia mais...", + "blog_details_separator": "|", + "account_title": "Conta", + "account_title_personalized": "Olá, {{ first_name }}", + "account_orders": "Pedidos", + "account_profile": "Perfil", + "discount_code": "Código de desconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Tributos de importação e outros tributos incluídos. Frete calculado no checkout.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Tributos de importação e outros tributos incluídos. Frete calculado no checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Tributos de importação incluídos. Frete calculado no checkout.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Tributos de importação incluídos. Frete calculado no checkout.", + "pickup_available_at_html": "Retirada disponível em {{ location }}", + "pickup_available_in": "Retirada disponível às {{ pickup_time }}", + "pickup_not_available": "Retirada indisponível no momento", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Tributos e frete calculados no checkout.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Tributos e frete calculados no checkout.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Tributos incluídos. Frete calculado no checkout.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Tributos incluídos. Frete calculado no checkout.", + "wrong_password": "Senha incorreta", + "view_more_details": "Ver mais informações", + "page_placeholder_title": "Título da página", + "page_placeholder_content": "Selecione uma página para exibir o conteúdo.", + "placeholder_image": "Imagem do marcador de posição", + "inventory_low_stock": "Estoque baixo", + "inventory_in_stock": "Em estoque", + "inventory_out_of_stock": "Sem estoque", + "inventory_low_stock_show_count": { + "one": "Tempo restante: {{ count }}", + "other": "Tempo restante: {{ count }}", + "many": "Tempo restante: {{ count }}" + }, + "powered_by": "Esta loja terá a tecnologia da", + "store_owner_link_html": "Você é titular da loja? Faça login aqui", + "shipping_discount_error": "Os descontos no frete são exibidos no checkout após a adição de um endereço.", + "discount_code_error": "O código de desconto não pode ser aplicado ao seu carrinho.", + "shipping_policy": "Frete calculado no checkout." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Use o código do cartão-presente online ou o código QR na loja", + "title": "O saldo no cartão-presente da loja {{ shop }} é de {{ value }}.", + "subtext": "Seu cartão-presente", + "shop_link": "Visitar loja virtual", + "add_to_apple_wallet": "Adicionar ao app Wallet da Apple", + "qr_image_alt": "Código QR (faça a leitura para resgatar o cartão-presente)", + "copy_code": "Copiar código do cartão-presente", + "expiration_date": "Expira em {{ expires_on }}", + "copy_code_success": "Código copiado", + "expired": "Vencido" + } + }, + "placeholders": { + "password": "Senha", + "search": "Pesquisa", + "product_title": "Título do produto", + "collection_title": "Título da coleção" + }, + "products": { + "product": { + "add_to_cart": "Adicionar ao carrinho", + "added_to_cart": "Adicionado ao carrinho", + "adding_to_cart": "Adicionando...", + "add_to_cart_error": "Erro ao adicionar ao carrinho", + "sold_out": "Esgotado", + "unavailable": "Indisponível" + } + }, + "fields": { + "separator": "para" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} comentário", + "other": "{{ count }} comentários", + "many": "{{ count }} comentários" + } + }, + "comment_form": { + "email": "E-mail", + "error": "O comentário não foi publicado. Faça o seguinte:", + "heading": "Deixe um comentário", + "message": "Mensagem", + "moderated": "Os comentários precisam ser aprovados antes da publicação.", + "name": "Nome", + "post": "Publicar comentário", + "success_moderated": "O comentário foi publicado, aguardando moderação", + "success": "Comentário publicado" + } + } +} diff --git a/locales/pt-BR.schema.json b/locales/pt-BR.schema.json new file mode 100644 index 000000000..882152c98 --- /dev/null +++ b/locales/pt-BR.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Bordas", + "collapsible_row": "Linha recolhível", + "colors": "Cores", + "custom_section": "Seção personalizada", + "icon": "Ícone", + "logo_and_favicon": "Logo e favicon", + "overlapping_blocks": "Blocos sobrepostos", + "product_buy_buttons": "Botões Comprar", + "product_description": "Descrição", + "product_price": "Preço", + "product_variant_picker": "Seletor de variante", + "slideshow": "Apresentação de slides", + "typography": "Tipografia", + "video": "Vídeo", + "slideshow_controls": "Controles para apresentação de slides", + "size": "Tamanho", + "spacing": "Espaçamento", + "product_recommendations": "Produtos recomendados", + "product_media": "Mídias do produto", + "featured_collection": "Coleção em destaque", + "add_to_cart": "Adicionar ao carrinho", + "email_signup": "Assinante de e-mail", + "submit_button": "Botão Enviar", + "grid_layout_selector": "Seletor de layout de grade", + "image": "Imagem", + "list_items": "Itens da lista", + "facets": "Facetas", + "variants": "Variantes", + "product_cards": "Cartões de produtos", + "styles": "Estilos", + "buttons": "Botões", + "inputs": "Entradas", + "primary_button": "Botão principal", + "secondary_button": "Botão secundário", + "popovers": "Pop-overs", + "marquee": "Faixa", + "alternating_content_rows": "Linhas alternadas", + "pull_quote": "Citação em destaque", + "contact_form": "Formulário de contato", + "featured_product": "Destaques do produto", + "icons_with_text": "Ícones com texto", + "accelerated_checkout": "checkout acelerado", + "accordion": "Menus sanfona", + "accordion_row": "Linha sanfona", + "animations": "Animações", + "announcement": "Comunicado", + "announcement_bar": "Barra de avisos", + "badges": "Selos", + "button": "Botão", + "cart": "Carrinho", + "cart_items": "Itens do carrinho", + "cart_products": "Produtos do carrinho", + "cart_title": "Carrinho", + "collection": "Coleção", + "collection_card": "Cartão de coleção", + "collection_columns": "Colunas de coleção", + "collection_container": "Coleção", + "collection_description": "Descrição de coleção", + "collection_image": "Imagem da coleção", + "collection_info": "Informações da coleção", + "collection_list": "Lista de coleções", + "collections": "Coleções", + "content": "Conteúdo", + "content_grid": "Grade de conteúdo", + "details": "Informações", + "divider": "Divisor", + "filters": "Filtragem e organização", + "follow_on_shop": "Seguir no Shop", + "footer": "Rodapé", + "footer_utilities": "Utilitários do rodapé", + "group": "Grupo", + "header": "Cabeçalho", + "heading": "Título", + "icons": "Ícones", + "image_with_text": "Imagem com texto", + "input": "Entrada", + "logo": "Logo", + "magazine_grid": "Grade de revistas", + "media": "Mídias", + "menu": "Menu", + "mobile_layout": "Layout em dispositivos móveis", + "payment_icons": "Ícones de pagamento", + "popup_link": "Link de pop-up", + "predictive_search": "Pesquisar pop-over", + "predictive_search_empty": "Pesquisa preditiva vazia", + "price": "Preço", + "product": "Produto", + "product_card": "Cartão de produto", + "product_card_media": "Mídias", + "product_card_rendering": "Renderização de cartão de produto", + "product_grid": "Grade", + "product_grid_main": "Grade de produtos", + "product_image": "Imagem do produto", + "product_information": "Informações do produto", + "product_list": "Coleção em destaque", + "product_review_stars": "Estrelas de avaliação", + "quantity": "Quantidade", + "row": "Linha", + "search": "Pesquisa", + "section": "Seção", + "selected_variants": "Variantes selecionadas", + "shop_the_look": "Comprar o look", + "slide": "Slide", + "social_media_links": "Links de redes sociais", + "spacer": "Separador", + "steps": "Etapas", + "summary": "Resumo", + "swatches": "Amostras", + "testimonials": "Depoimentos", + "text": "Texto", + "title": "Título", + "utilities": "Serviços públicos", + "search_input": "Termos de pesquisa", + "search_results": "Resultados da pesquisa", + "read_only": "Somente leitura", + "collection_title": "Título da coleção", + "collections_bento": "Lista de coleções: Bento", + "faq_section": "Perguntas frequentes", + "hero": "Imagem de destaque", + "jumbo_text": "Texto do Jumbo", + "view_all_button": "Ver tudo", + "video_section": "Vídeo", + "blog": "Blog", + "blog_posts": "Posts do blog", + "custom_liquid": "Liquid personalizado", + "blog_post": "Post do blog", + "caption": "Legenda", + "collection_card_image": "Imagem", + "collection_links": "Links de coleção", + "collection_links_spotlight": "Links de coleção: Destaque", + "collection_links_text": "Links de coleção: Texto", + "collections_carousel": "Lista de coleções: Carrossel", + "collections_editorial": "Lista de coleções: editorial", + "collections_grid": "Lista de coleções: Grade", + "copyright": "Direitos autorais", + "count": "Contagem", + "divider_section": "Divisor", + "drawers": "Menus deslizantes", + "editorial": "Editorial", + "editorial_jumbo_text": "Editorial: texto do Jumbo", + "hero_marquee": "Principal: marca de seleção", + "input_fields": "Campos de entrada", + "local_pickup": "Retirada no local", + "marquee_section": "Marca de seleção", + "media_with_text": "Mídia com texto", + "page": "Página", + "page_content": "Conteúdo", + "page_layout": "Layout de página", + "policy_list": "Links para políticas", + "prices": "Preços", + "products_carousel": "Coleção em destaque: carrossel", + "products_editorial": "Coleção em destaque: editorial", + "products_grid": "Coleção em destaque: grade", + "social_link": "Link de redes sociais", + "split_showcase": "Dividir mostruário", + "variant_pickers": "Seletores de variante", + "pills": "Pílulas", + "product_title": "Título do produto", + "large_logo": "Logo grande", + "product_list_button": "Botão \"Ver tudo\"", + "product_inventory": "Estoque de produtos", + "description": "Descrição" + }, + "settings": { + "alignment": "Alinhamento", + "autoplay": "Reprodução automática", + "background": "Plano de fundo", + "border_radius": "Raio dos cantos", + "border_width": "Espessura da borda", + "borders": "Bordas", + "bottom_padding": "Preenchimento inferior", + "button": "Botão", + "color": "Cor", + "colors": "Cores", + "content_alignment": "Alinhamento de conteúdo", + "content_direction": "Direção do conteúdo", + "content_position": "Posição do conteúdo", + "cover_image_size": "Tamanho da imagem de capa", + "cover_image": "Imagem de capa", + "custom_minimum_height": "Altura mínima personalizada", + "custom_width": "Largura personalizada", + "enable_video_looping": "Loop de vídeo", + "favicon": "Favicon", + "font_family": "Família de fontes", + "gap": "Lacuna", + "geometric_translate_y": "Translação geométrica Y", + "heading": "Título", + "icon": "Ícone", + "image": "Image", + "image_icon": "Ícone de imagem", + "image_opacity": "Opacidade da imagem", + "image_position": "Posição da imagem", + "image_ratio": "Proporção da imagem", + "label": "Etiqueta", + "line_height": "Altura da linha", + "link": "Link", + "layout_gap": "Lacuna de layout", + "make_section_full_width": "Definir seção com largura total", + "minimum_height": "Altura mínima", + "opacity": "Opacidade", + "overlay_opacity": "Opacidade de sobreposição", + "padding": "Preenchimento", + "primary_color": "Links", + "product": "Produto", + "section_width": "Largura da seção", + "size": "Tamanho", + "slide_spacing": "Intervalo entre slides", + "slide_width": "Largura do slide", + "slideshow_fullwidth": "Slides com largura total", + "style": "Estilo", + "text": "Texto", + "text_case": "Caixa", + "top_padding": "Preenchimento superior", + "video": "Vídeo", + "video_alt_text": "Texto alternativo", + "video_loop": "Repetir vídeo", + "video_position": "Posição do vídeo", + "width": "Largura", + "z_index": "Índice Z", + "limit_content_width": "Limitar a largura do conteúdo", + "color_scheme": "Esquema de cores", + "inherit_color_scheme": "Herdar esquema de cores", + "product_count": "Contagem de produtos", + "product_type": "Tipo de produto", + "content_width": "Largura do conteúdo", + "collection": "Coleção", + "enable_sticky_content": "Conteúdo persistente no desktop", + "error_color": "Erro", + "success_color": "Sucesso", + "primary_font": "Fonte principal", + "secondary_font": "Fonte secundária", + "tertiary_font": "Fonte terciária", + "columns": "Colunas", + "items_to_show": "Itens a mostrar", + "layout": "Layout", + "layout_type": "Tipo", + "show_grid_layout_selector": "Mostrar o seletor de layout de grade", + "view_more_show": "Mostrar o botão \"Ver mais\"", + "image_gap": "Lacuna entre imagens", + "width_desktop": "Largura em desktop", + "width_mobile": "Largura em dispositivos móveis", + "border_style": "Estilo da borda", + "height": "Altura", + "thickness": "Espessura", + "stroke": "Traço", + "filter_style": "Filtrar estilo", + "swatches": "Amostras", + "quick_add_colors": "Adição rápida de cores", + "divider_color": "Divisor", + "border_opacity": "Opacidade da borda", + "hover_background": "Fundo ao passar o cursor", + "hover_borders": "Bordas ao passar o cursor", + "hover_text": "Texto ao passar o cursor", + "primary_hover_color": "Links ao passar o cursor", + "primary_button_text": "Texto do botão principal", + "primary_button_background": "Fundo do botão principal", + "primary_button_border": "Borda do botão principal", + "secondary_button_text": "Texto do botão secundário", + "secondary_button_background": "Fundo do botão secundário", + "secondary_button_border": "Borda do botão secundário", + "shadow_color": "Sombra", + "limit_media_to_screen_height": "Ajustar à altura da tela", + "video_autoplay": "Reprodução automática", + "video_cover_image": "Imagem de capa", + "video_external_url": "URL", + "video_source": "Fonte", + "first_row_media_position": "Posição da mídia na primeira linha", + "accordion": "Menus sanfona", + "aspect_ratio": "Proporção", + "auto_rotate_announcements": "Girar automaticamente os comunicados", + "auto_rotate_slides": "Girar automaticamente os slides", + "background_color": "Cor de fundo", + "badge_corner_radius": "Raio dos cantos", + "badge_position": "Posição em cartões", + "badge_sale_color_scheme": "Promoção", + "badge_sold_out_color_scheme": "Esgotado", + "behavior": "Comportamento", + "blur": "Desfoque de sombra", + "border": "Borda", + "bottom": "Parte inferior", + "card_image_height": "Altura da imagem do produto", + "carousel_on_mobile": "Carrossel em dispositivos móveis", + "cart_count": "Contagem de carrinhos", + "cart_items": "Itens do carrinho", + "cart_related_products": "Produtos relacionados", + "cart_title": "Carrinho", + "cart_total": "Total do carrinho", + "cart_type": "Tipo", + "case": "Caixa", + "checkout_buttons": "Botões de checkout acelerado", + "collection_list": "Coleções", + "collection_templates": "Modelos de coleção", + "content": "Conteúdo", + "corner_radius": "Raio dos cantos", + "country_region": "País/Região", + "currency_code": "Código da moeda", + "custom_height": "Altura personalizada", + "custom_mobile_size": "Tamanho personalizado do dispositivo móvel", + "desktop_height": "Altura para desktop", + "direction": "Direção", + "display": "Exibição", + "divider_thickness": "Espessura do divisor", + "divider": "Divisor", + "dividers": "Divisores", + "drop_shadow": "Sombra projetada", + "empty_state_collection_info": "Exibido antes de inserir uma pesquisa", + "empty_state_collection": "Coleção de estado vazio", + "enable_filtering": "Filtros", + "enable_grid_density": "Controle de layout de grade", + "enable_sorting": "Organização", + "enable_zoom": "Habilitar zoom", + "equal_columns": "Colunas iguais", + "expand_first_group": "Expandir primeiro grupo", + "extend_media_to_screen_edge": "Estender mídia até a borda da tela", + "extend_summary": "Estender até a borda da tela", + "extra_large": "Extragrande", + "extra_small": "Extrapequeno", + "fixed_height": "Altura do dispositivo", + "fixed_width": "Largura do dispositivo", + "flag": "Bandeira", + "font_price": "Fonte do preço", + "font_weight": "Peso da fonte", + "font": "Fonte", + "full_width_first_image": "Primeira imagem de largura total", + "full_width_on_mobile": "Largura total em dispositivos móveis", + "heading_preset": "Predefinição de título", + "hide_padding": "Ocultar preenchimento", + "hide_unselected_variant_media": "Ocultar mídia de variante não selecionada", + "horizontal_gap": "Lacuna horizontal", + "horizontal_offset": "Compensação horizontal de sombra", + "hover_behavior": "Comportamento ao passar o cursor", + "icon_background": "Plano de fundo do ícone", + "icons": "Ícones", + "image_border_radius": "Raio de canto da imagem", + "installments": "Parcelamento", + "integrated_button": "Botão integrado", + "language_selector": "Seletor de idioma", + "large": "Grande", + "left_padding": "Preenchimento à esquerda", + "left": "Esquerda", + "letter_spacing": "Espaçamento entre letras", + "limit_product_details_width": "Limitar largura das informações de produto", + "link_preset": "Predefinição de link", + "links": "Links", + "logo_font": "Fonte do logo", + "logo": "Logo", + "loop": "Loop", + "make_details_sticky_desktop": "Persistente no desktop", + "max_width": "Largura máxima", + "media_height": "Altura da mídia", + "media_overlay": "Sobreposição de mídia", + "media_position": "Posição da mídia", + "media_type": "Tipo de mídia", + "media_width": "Largura da mídia", + "menu": "Menu", + "mobile_columns": "Colunas em dispositivos móveis", + "mobile_height": "Altura em dispositivos móveis", + "mobile_logo_image": "Logo em dispositivo móvel", + "mobile_quick_add": "Adição rápida em dispositivos móveis", + "motion_direction": "Direção", + "motion": "Movimento", + "movement_direction": "Direção de movimento", + "navigation_bar_color_scheme": "Esquema de cores da barra de navegação", + "navigation_bar": "Barra de navegação", + "navigation": "Navegação", + "open_new_tab": "Abrir link em uma nova aba", + "overlay_color": "Cor de sobreposição", + "overlay": "Sobreposição", + "padding_bottom": "Preenchimento inferior", + "padding_horizontal": "Preenchimento horizontal", + "padding_top": "Preenchimento superior", + "page_width": "Largura da página", + "pagination": "Paginação", + "percent_height": "Altura percentual", + "percent_size_mobile": "Tamanho percentual", + "percent_size": "Tamanho percentual", + "percent_width": "Largura percentual", + "pixel_size_mobile": "Tamanho do pixel", + "pixel_size": "Tamanho do pixel", + "placement": "Posicionamento", + "position": "Posição", + "preset": "Predefinição", + "product_cards": "Cartões de produtos", + "product_pages": "Páginas de produtos", + "product_templates": "Modelos de produtos", + "products": "Produtos", + "quick_add": "Adição rápida", + "ratio": "Proporção", + "regular": "Regular", + "review_count": "Revisar contagem", + "right": "Direita", + "row_height": "Altura da linha", + "row": "Linha", + "seller_note": "Permitir observação para o vendedor", + "shape": "Formato", + "show_as_accordion": "Exibir como sanfona em dispositivos móveis", + "show_sale_price_first": "Exibir preço promocional primeiro", + "show_tax_info": "Informação de tributos", + "show": "Exibir", + "size_mobile": "Tamanho do dispositivo móvel", + "small": "Pequeno", + "speed": "Velocidade", + "statement": "Extrato", + "sticky_header": "Cabeçalho fixo", + "text_hierarchy": "Hierarquia de texto", + "text_presets": "Predefinições de texto", + "title": "Título", + "top": "Parte superior", + "type": "Tipo", + "type_preset": "Predefinição de texto", + "underline_thickness": "Espessura do sublinhado", + "unit": "Unidade", + "variant_images": "Imagens de variantes", + "vendor": "Fabricante", + "vertical_gap": "Lacuna vertical", + "vertical_offset": "Compensação vertical de sombra", + "vertical_on_mobile": "Vertical em dispositivo móveis", + "view_all_as_last_card": "\"Ver tudo\" como último cartão", + "weight": "Peso", + "wrap": "Ajustar", + "read_only": "Somente leitura", + "always_stack_buttons": "Sempre empilhe botões", + "custom_mobile_width": "Largura personalizada no dispositivo móvel", + "gradient_direction": "Direção do gradiente", + "headings": "Títulos", + "overlay_style": "Estilo da sobreposição", + "shadow_opacity": "Opacidade da sombra", + "show_filter_label": "Etiquetas de texto para filtros aplicados", + "show_swatch_label": "Etiquetas de texto para amostras", + "transparent_background": "Fundo transparente", + "hide_logo_on_home_page": "Ocultar logo na página inicial", + "account": "Conta", + "align_baseline": "Alinhar linha de base do texto", + "add_discount_code": "Permitir descontos no carrinho", + "background_overlay": "Sobreposição de plano de fundo", + "background_media": "Mídia de fundo", + "border_thickness": "Espessura da borda", + "bottom_row": "Linha inferior", + "button_text_case": "Estilo do texto", + "button_text_weight": "Peso do texto", + "card_size": "Tamanho do cartão", + "auto_open_cart_drawer": "\"Adicionar ao carrinho\" automaticamente abre o carrinho deslizante", + "collection_count": "Contagem de coleções", + "collection_title_case": "Caixa do título de coleção", + "custom_liquid": "Código Liquid", + "default": "Padrão", + "default_logo": "Logo padrão", + "divider_width": "Largura do divisor", + "horizontal_padding": "Preenchimento horizontal", + "inverse": "Inverso", + "inverse_logo": "Logo inverso", + "layout_style": "Estilo", + "length": "Comprimento", + "mobile_card_size": "Tamanho do cartão em dispositivos móveis", + "mobile_pagination": "Paginação móvel", + "open_row_by_default": "Abrir linha como padrão", + "page": "Página", + "page_transition_enabled": "Transição da página", + "product_and_card_title_case": "Caixa do título do produto e cartão", + "product_title_case": "Caixa do título do produto", + "right_padding": "Preenchimento à direita", + "search": "Pesquisa", + "search_icon": "Ícone de pesquisa", + "search_position": "Posição", + "search_row": "Linha", + "show_author": "Autoria", + "show_alignment": "Mostrar alinhamento", + "show_count": "Mostrar contagem", + "show_date": "Data", + "show_pickup_availability": "Exibir disponibilidade de retirada", + "show_search": "Exibir pesquisa", + "text_label_case": "Caixa da etiqueta do texto", + "use_inverse_logo": "Usar logo inverso", + "vertical_padding": "Preenchimento vertical", + "visibility": "Visibilidade", + "product_corner_radius": "Raio do canto do produto", + "card_corner_radius": "Raio do canto do cartão", + "alignment_mobile": "Alinhamento em dispositivos móveis", + "animation_repeat": "Repetir animação", + "blurred_reflection": "Reflexão desfocada", + "card_hover_effect": "Efeito ao passar o cartão", + "effects": "Efeitos", + "inventory_threshold": "Limite de estoque baixo", + "reflection_opacity": "Opacidade da reflexão", + "show_inventory_quantity": "Mostrar quantidade de estoque baixo", + "transition_to_main_product": "Transição do cartão do produto para a página do produto", + "show_second_image_on_hover": "Exibir segunda imagem ao passar o cursor", + "media": "Mídia", + "product_card_carousel": "Mostrar carrossel", + "media_fit": "Ajuste da mídia", + "scroll_speed": "Tempo para o próximo comunicado" + }, + "options": { + "adapt_to_image": "Adaptar à imagem", + "apple": "Maçã", + "arrow": "Seta", + "auto": "Automático", + "banana": "Banana", + "bottle": "Garrafa", + "box": "Caixa", + "buttons": "Botões", + "carrot": "Cenoura", + "center": "Centro", + "chat_bubble": "Balão de chat", + "clipboard": "Prancheta", + "contain": "Contém", + "counter": "Contador", + "cover": "Capa", + "custom": "Personalizado", + "dairy_free": "Sem lactose", + "dairy": "Laticínios", + "default": "Padrão", + "dropdowns": "Menus suspensos", + "dots": "Pontos", + "dryer": "Secador", + "end": "Término", + "eye": "Olho", + "facebook": "Facebook", + "fill": "Preenchimento", + "fire": "Fogo", + "fit": "Ajuste", + "full": "Total", + "full_and_page": "Plano de fundo em tela cheia, conteúdo limitado pela largura da página", + "gluten_free": "Sem glúten", + "heading": "Título", + "heart": "Coração", + "horizontal": "Horizontal", + "instagram": "Instagram", + "iron": "Ferro", + "landscape": "Paisagem", + "large": "Grande", + "leaf": "Folha", + "leather": "Couro", + "lg": "G", + "lightning_bolt": "Relâmpago", + "link": "Link", + "lipstick": "Batom", + "lock": "Cadeado", + "lowercase": "minúscula", + "m": "M", + "map_pin": "Marcador de mapa", + "medium": "Médio", + "none": "Nenhuma", + "numbers": "Números", + "nut_free": "Sem nozes", + "outline": "Contorno", + "page": "Página", + "pants": "Calças", + "paw_print": "Pegada de animal", + "pepper": "Pimenta", + "perfume": "Perfume", + "pinterest": "Pinterest", + "plane": "Avião", + "plant": "Planta", + "portrait": "Retrato", + "price_tag": "Etiqueta de preço", + "question_mark": "Ponto de interrogação", + "recycle": "Reciclar", + "return": "Retorno", + "ruler": "Régua", + "s": "P", + "sentence": "Sentença", + "serving_dish": "Travessa", + "shirt": "Camisa", + "shoe": "Sapato", + "silhouette": "Silhueta", + "small": "Pequena", + "snapchat": "Snapchat", + "snowflake": "Floco de neve", + "solid": "Sólido", + "space_between": "Espaço entre", + "square": "Quadrada", + "star": "Estrela", + "start": "Início", + "stopwatch": "Cronômetro", + "tiktok": "TikTok", + "truck": "Caminhão", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Letras maiúsculas", + "vertical": "Vertical", + "vimeo": "Vimeo", + "washing": "Lavagem", + "circle": "Círculo", + "swatches": "Amostras", + "full_and_page_offset_left": "Plano de fundo em tela cheia, conteúdo limitado pela largura da página, compensação esquerda", + "full_and_page_offset_right": "Plano de fundo em tela cheia, conteúdo limitado pela largura da página, compensação direita", + "offset_left": "Compensação esquerda", + "offset_right": "Compensação direita", + "page_center_aligned": "Página, alinhamento no centro", + "page_left_aligned": "Página, alinhamento à esquerda", + "page_right_aligned": "Página, alinhamento à direita", + "button": "Botão", + "caption": "Legenda", + "h1": "Título 1", + "h2": "Título 2", + "h3": "Título 3", + "h4": "Título 4", + "h5": "Título 5", + "h6": "Título 6", + "paragraph": "Parágrafo", + "primary": "Principal", + "secondary": "Secundária", + "tertiary": "Terciária", + "chevron_left": "Chevron para esquerda", + "chevron_right": "Chevron para direita", + "diamond": "Diamante", + "grid": "Grade", + "parallelogram": "Paralelogramo", + "rounded": "Arredondado", + "fit_content": "Ajuste", + "pills": "Pílulas", + "heavy": "Grosso", + "thin": "Fino", + "drawer": "Menu deslizante", + "preview": "Pré-visualizar", + "text": "Texto", + "video_uploaded": "Upload concluído", + "video_external_url": "URL externo", + "aspect_ratio": "Proporção", + "fixed": "Fixo", + "pixel": "Pixel", + "percent": "Percentual", + "above_carousel": "Acima do carrossel", + "all": "Tudo", + "up": "Para cima", + "down": "Para baixo", + "always": "Sempre", + "arrows_large": "Setas grandes", + "arrows": "Setas", + "balance": "Saldo", + "bento": "Bento", + "black": "Preto", + "bluesky": "Bluesky", + "body_large": "Corpo (grande)", + "body_regular": "Corpo (regular)", + "body_small": "Corpo (pequeno)", + "bold": "Negrito", + "bottom_left": "Canto inferior esquerdo", + "bottom_right": "Canto inferior direito", + "bottom": "Parte inferior", + "capitalize": "Letra maiúscula", + "caret": "Cursor", + "carousel": "Carrossel", + "check_box": "Caixa de seleção", + "chevron_large": "Chevrons grandes", + "chevron": "Chevron", + "chevrons": "Chevrons", + "classic": "Clássico", + "collection_images": "Imagens da coleção", + "color": "Cor", + "complementary": "Complementar", + "dissolve": "Dissolver", + "dotted": "Pontilhado", + "editorial": "Editorial", + "extra_large": "Extragrande", + "extra_small": "Extrapequeno", + "featured_collections": "Coleções em destaque", + "featured_products": "Produtos em destaque", + "font_primary": "Principal", + "font_secondary": "Secundária", + "font_tertiary": "Terciária", + "forward": "Avançar", + "full_screen": "Tela cheia", + "gradient": "Gradiente", + "heading_extra_large": "Cabeçalho (extragrande)", + "heading_extra_small": "Cabeçalho (extrapequeno)", + "heading_large": "Cabeçalho (grande)", + "heading_regular": "Cabeçalho (regular)", + "heading_small": "Cabeçalho (pequeno)", + "icon": "Ícone", + "image": "Image", + "input": "Entrada", + "inside_carousel": "Dentro do carrossel", + "inverse_large": "Inverso grande", + "inverse": "Inverso", + "large_arrows": "Setas grandes", + "large_chevrons": "Chevrons grandes", + "left": "Esquerda", + "light": "Claro", + "linkedin": "LinkedIn", + "loose": "Solto", + "media_first": "Mídia primeiro", + "media_second": "Mídia em segundo lugar", + "modal": "Modal", + "narrow": "Estreita", + "never": "Nunca", + "next_to_carousel": "Ao lado do carrossel", + "normal": "Normal", + "nowrap": "Sem ajustar", + "off_media": "Na mídia", + "on_media": "Fora da mídia", + "on_scroll_up": "Na rolagem da página para cima", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Em formato de pílula", + "plus": "Plus", + "pretty": "Bonito(a)", + "price": "Preço", + "primary_style": "Estilo principal", + "rectangle": "Retângulo", + "regular": "Regular", + "related": "Relacionado", + "reverse": "Inverso", + "rich_text": "Rich text", + "right": "Direita", + "secondary_style": "Estrilo secundário", + "semibold": "Seminegrito", + "shaded": "Sombreado", + "show_second_image": "Mostrar segundo imagem", + "single": "Único", + "slide_left": "Deslizar para a esquerda", + "slide_up": "Deslizar para cima", + "spotify": "Spotify", + "stack": "Empilhado", + "text_only": "Apenas texto", + "threads": "Threads", + "thumbnails": "Miniaturas", + "tight": "Fixo", + "top_left": "Canto superior esquerdo", + "top_right": "Canto superior direito", + "top": "Parte superior", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Sublinhado", + "video": "Vídeo", + "wide": "Larga", + "youtube": "YouTube", + "accent": "Destaque", + "below_image": "Abaixo da imagem", + "body": "Corpo", + "button_primary": "Botão principal", + "button_secondary": "Botão secundário", + "compact": "Compacto", + "crop_to_fit": "Cortar para caber", + "hidden": "Oculto", + "hint": "Dica", + "maintain_aspect_ratio": "Manter proporção", + "off": "Desativado", + "on_image": "Na imagem", + "social_bluesky": "Rede social: Bluesky", + "social_facebook": "Rede social: Facebook", + "social_instagram": "Rede social: Instagram", + "social_linkedin": "Rede social: LinkedIn", + "social_pinterest": "Rede social: Pinterest", + "social_snapchat": "Rede social: Snapchat", + "social_spotify": "Rede social: Spotify", + "social_threads": "Rede social: Threads", + "social_tiktok": "Rede social: TikTok", + "social_tumblr": "Rede social: Tumblr", + "social_twitter": "Rede social: X (Twitter)", + "social_whatsapp": "Rede social: WhatsApp", + "social_vimeo": "Rede social: Vimeo", + "social_youtube": "Rede social: YouTube", + "spotlight": "Spotlight", + "standard": "Padrão", + "subheading": "Subtítulo", + "blur": "Desfoque", + "lift": "Elevação", + "reveal": "Revelar", + "scale": "Escala", + "subtle_zoom": "Zoom" + }, + "content": { + "advanced": "Avançado", + "background_image": "Imagem de fundo", + "background_video": "Vídeo de fundo", + "block_size": "Tamanho do bloco", + "borders": "Bordas", + "describe_the_video_for": "Descreva o vídeo para clientes que usam leitores de tela. [Saiba mais](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Tamanho da seção", + "slideshow_width": "Largura do slide", + "typography": "Tipografia", + "width_is_automatically_optimized": "A largura é otimizada automaticamente para dispositivos móveis.", + "complementary_products": "Os produtos complementares precisam ser configurados usando o app Search & Discovery. [Saiba mais](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "As colunas são otimizadas automaticamente para dispositivos móveis", + "content_width": "A largura do conteúdo só se aplica quando a largura da seção estiver configurada para largura total.", + "adjustments_affect_all_content": "Aplicável a todo o conteúdo neste bloco", + "responsive_font_sizes": "Os tamanhos são dimensionados automaticamente para todos os tamanhos de tela", + "buttons": "Botões", + "swatches": "Amostras", + "variant_settings": "Configurações de variante", + "background": "Plano de fundo", + "appearance": "Aparência", + "arrows": "Setas", + "body_size": "Tamanho do corpo", + "mobile_size": "Tamanho do dispositivo móvel", + "bottom_row_appearance": "Aparência da linha inferior", + "cards_layout": "Layout de cartões", + "carousel_navigation": "Navegação em carrossel", + "carousel_pagination": "Paginação em carrossel", + "copyright": "Direitos autorais", + "edit_logo_in_theme_settings": "Editar logo nas [configurações do tema ](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Editar formato do preço nas [configurações do tema ](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Editar estilo da variante nas [configurações do tema ](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "As inscrições adicionam [perfis de cliente](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Para mostrar o botão, o canal de vendas Shop precisa ser instalado e o Shop Pay ativado. [Saiba mais](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Fontes", + "grid": "Grade", + "heading_size": "Tamanho do título", + "image": "Imagem", + "input": "Entrada", + "layout": "Layout", + "link": "Link", + "link_padding": "Preenchimento do link", + "localization": "Localização", + "logo": "Logo", + "margin": "Margem", + "media": "Mídias", + "media_1": "Mídia 1", + "media_2": "Mídia 2", + "menu": "Menu", + "mobile_layout": "Layout em dispositivos móveis", + "padding": "Preenchimento", + "padding_desktop": "Preenchimento de desktop", + "paragraph": "Parágrafo", + "policies": "Políticas", + "popup": "Pop-up", + "search": "Pesquisa", + "section_layout": "Layout da seção", + "size": "Tamanho", + "social_media": "Redes sociais", + "submit_button": "Botão Enviar", + "text_presets": "Predefinições de texto", + "transparent_background": "Fundo transparente", + "typography_primary": "Tipografia principal", + "typography_secondary": "Tipografia secundária", + "typography_tertiary": "Tipografia terciária", + "mobile_width": "Largura no dispositivo móvel", + "width": "Largura", + "images": "Imagens", + "visibility": "Visibilidade", + "carousel": "Carrossel", + "colors": "Cores", + "collection_page": "Página de coleção", + "copyright_info": "Saiba como [editar sua declaração de direitos autorais](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Conta de cliente", + "edit_empty_state_collection_in_theme_settings": "Editar coleção de estado vazio nas [configurações do tema ](/editor?context=theme&category=search)", + "grid_layout": "Layout de grade", + "home_page": "Página inicial", + "inverse_logo_info": "Usado quando o fundo transparente do cabeçalho é definido como Inverso", + "manage_customer_accounts": "[Gerencie a visibilidade](/admin/settings/customer_accounts) nas configurações de conta de cliente. Contas legadas não aceitas.", + "manage_policies": "[Gerenciar políticas](/admin/settings/legal)", + "product_page": "Página do produto", + "text": "Texto", + "thumbnails": "Miniaturas", + "visible_if_collection_has_more_products": "Visível se a coleção tiver mais produtos que os mostrados", + "app_required_for_ratings": "É necessário um app para classificações de produtos. [Saiba mais](https://help.shopify.com/manual/apps)", + "icon": "Ícone", + "manage_store_name": "[Gerenciar nome da loja](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Exibe a coleção da seção principal", + "resource_reference_collection_card_image": "Exibe a imagem da coleção principal", + "resource_reference_collection_title": "Exibe o título da coleção principal", + "resource_reference_product": "Conecta-se automaticamente ao produto principal", + "resource_reference_product_card": "Exibe o produto da seção principal", + "resource_reference_product_inventory": "Exibe o estoque do produto principal", + "resource_reference_product_price": "Exibe o preço do produto principal", + "resource_reference_product_recommendations": "Exibe recomendações com base no produto principal", + "resource_reference_product_review": "Exibe avaliações do produto principal", + "resource_reference_product_swatches": "Exibe amostras do produto principal", + "resource_reference_product_title": "Exibe o título do produto principal", + "resource_reference_product_variant_picker": "Exibe variantes do produto principal", + "resource_reference_product_media": "Exibe a mídia do produto principal", + "product_media": "Mídias do produto", + "section_link": "Link da seção" + }, + "html_defaults": { + "share_information_about_your": "

Compartilhe informações sobre a marca com clientes. Descreva um produto, faça comunicados ou dê as boas-vindas aos clientes na loja.

" + }, + "text_defaults": { + "button_label": "Comprar agora", + "collapsible_row": "Linha recolhível", + "heading": "Título", + "email_signup_button_label": "Assinar", + "accordion_heading": "Cabeçalho sanfona", + "contact_form_button_label": "Enviar", + "popup_link": "Link de pop-up", + "sign_up": "Criar conta", + "welcome_to_our_store": "Boas-vindas à nossa loja", + "be_bold": "Ouse.", + "shop_our_latest_arrivals": "Conheça as novidades da loja!" + }, + "info": { + "video_alt_text": "Descreva o vídeo para usuários de tecnologia assistiva", + "video_autoplay": "Por padrão, os vídeos serão silenciados", + "video_external": "Usar URL do YouTube ou do Vimeo", + "link_info": "Opcional: permite a opção de clicar no ícone", + "carousel_layout_on_mobile": "O Carrossel é usado em dispositivos móveis", + "carousel_hover_behavior_not_supported": "O \"Carrossel\" ao passar o cursor não está disponível quando o tipo \"Carrossel\" for selecionado no nível da seção.", + "checkout_buttons": "Permite que os compradores finalizem a compra mais rápido e pode melhorar a conversão. [Saiba mais](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Título personalizado", + "edit_presets_in_theme_settings": "Editar predefinições nas [configurações do tema ](/editor?context=theme&category=typography)", + "enable_filtering_info": "Personalize os filtros com o [app Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "O layout da grade é usado para dispositivos móveis", + "logo_font": "Aplica-se somente quando não há nenhum logo selecionado", + "manage_countries_regions": "[Gerenciar países/regiões](/admin/settings/markets)", + "manage_languages": "[Gerenciar idiomas](/admin/settings/languages)", + "transparent_background": "Analise cada modelo em que é aplicado o fundo transparente por questões de legibilidade", + "aspect_ratio_adjusted": "Ajuste feito em alguns layouts", + "auto_open_cart_drawer": "Ao ativar, o carrinho de compras deslizante será aberto automaticamente quando um produto for adicionado.", + "custom_liquid": "Adicione snippets de app ou outros códigos do Liquid para criar personalizações avançadas. [Saiba mais](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Usado para filtros aplicados, códigos de desconto e sugestões de pesquisa", + "applies_on_image_only": "Aplica-se apenas a imagens", + "hover_effects": "Aplica-se a cartões de produto e coleção" + }, + "categories": { + "basic": "Basic", + "collection": "Coleção", + "collection_list": "Lista de coleções", + "footer": "Rodapé", + "forms": "Formulários", + "header": "Cabeçalho", + "layout": "Layout", + "links": "Links", + "product": "Produto", + "product_list": "Coleção em destaque", + "banners": "Banners", + "collections": "Coleções", + "custom": "Personalizado", + "decorative": "Decorativo", + "products": "Produtos", + "other_sections": "Outro", + "storytelling": "Storytelling" + } +} diff --git a/locales/pt-PT.json b/locales/pt-PT.json new file mode 100644 index 000000000..7cdbd5367 --- /dev/null +++ b/locales/pt-PT.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Carregar vídeo: {{ description }}", + "sold_out": "Esgotado", + "email_signup": { + "label": "E-mail", + "placeholder": "Endereço de e-mail", + "success": "Agradecemos a sua subscrição!" + }, + "filter": "Filtrar", + "payment_methods": "Métodos de pagamento", + "contact_form": { + "name": "Nome", + "email": "E-mail", + "phone": "Telefone", + "comment": "Comentário", + "post_success": "Agradecemos o seu contacto. Responder-lhe-emos logo que possível.", + "error_heading": "Ajuste o seguinte:" + } + }, + "accessibility": { + "play_model": "Reproduzir modelo 3D", + "play_video": "Reproduzir o vídeo", + "unit_price": "Preço unitário", + "country_results_count": "{{ count }} resultados", + "slideshow_pause": "Pausar apresentação de diapositivos", + "slideshow_play": "Reproduzir apresentação de diapositivos", + "remove_item": "Remover {{ title}}", + "skip_to_text": "Saltar para o conteúdo", + "skip_to_product_info": "Saltar para a informação do produto", + "skip_to_results_list": "Saltar para lista de resultados", + "new_window": "Abrirá numa nova janela.", + "close_dialog": "Fechar caixa de diálogo", + "reset_search": "Repor pesquisa", + "search_results_count": "{{ count }} resultados de pesquisa encontrados para \"{{ query }}\"", + "search_results_no_results": "Não foram encontrados resultados para \"{{ query }}\"", + "slideshow_next": "Diapositivo seguinte", + "slideshow_previous": "Diapositivo anterior", + "filters": "Filtros", + "filter_count": { + "one": "{{ count }} filtro aplicado", + "other": "{{ count }} filtros aplicados", + "many": "{{ count }} filtros aplicados" + }, + "account": "Abrir menu da conta", + "cart": "Carrinho", + "cart_count": "Total de itens no carrinho", + "menu": "Menu", + "country_region": "País/região", + "slide_status": "Diapositivo {{ index }} de {{ length }}", + "scroll_to": "Percorrer até {{ title }}", + "loading_product_recommendations": "A carregar recomendações de produto", + "discount": "Aplicar um código de desconto", + "discount_applied": "Código de desconto aplicado: {{ code }}", + "open_cart_drawer": "Abrir carrinho", + "pause_video": "Colocar vídeo em pausa", + "inventory_status": "Estado do inventário", + "localization_region_and_language": "Abrir seletor de região e idioma", + "open_search_modal": "Abrir pesquisa", + "find_country": "Localizar país", + "decrease_quantity": "Diminuir quantidade", + "increase_quantity": "Aumentar quantidade", + "rating": "A classificação deste produto é de {{ rating }}/5", + "quantity": "Quantidade", + "nested_product": "{{ product_title }} para {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Adicionar ao carrinho", + "clear_all": "Limpar tudo", + "remove": "Remover", + "view_in_your_space": "Ver no seu espaço", + "show_filters": "Filtrar", + "clear": "Limpar", + "continue_shopping": "Continuar a comprar", + "log_in_html": "Tem uma conta? Inicie sessão para finalizar a compra mais rápido.", + "see_items": { + "one": "Ver {{ count }} item", + "other": "Ver {{ count }} itens", + "many": "Ver {{ count }} itens" + }, + "view_all": "Ver tudo", + "add": "Adicionar", + "choose": "Escolher", + "added": "Adicionado", + "show_less": "Mostrar menos", + "show_more": "Mostrar mais", + "close": "Fechar", + "more": "Mais", + "reset": "Repor", + "zoom": "Zoom", + "close_dialog": "Fechar caixa de diálogo", + "back": "Voltar", + "log_in": "Iniciar sessão", + "log_out": "Terminar sessão", + "remove_discount": "Remover desconto {{ code }}", + "enter_using_password": "Entrar com palavra-passe", + "submit": "Submeter", + "enter_password": "Introduzir palavra-passe", + "view_store_information": "Ver as informações da loja", + "apply": "Aplicar", + "open_image_in_full_screen": "Abrir imagem em ecrã inteiro", + "sign_in_options": "Outras opções de início de sessão", + "sign_up": "Registar-se", + "sort": "Ordenar", + "show_all_options": "Mostrar todas as opções" + }, + "content": { + "reviews": "avaliações", + "language": "Idioma", + "localization_region_and_language": "Região e idioma", + "no_results_found": "Não foram encontrados resultados", + "cart_total": "Total do carrinho", + "your_cart_is_empty": "O seu carrinho está vazio", + "product_image": "Imagem de produto", + "product_information": "Informações de produto", + "quantity": "Quantidade", + "product_total": "Total de produto", + "cart_estimated_total": "Total estimado", + "seller_note": "Instruções especiais", + "cart_subtotal": "Subtotal", + "discounts": "Descontos", + "discount": "Desconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Encargos e impostos incluídos. Descontos e envio calculados na finalização da compra.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Encargos e impostos incluídos. Descontos e envio calculados na finalização da compra.", + "taxes_included_shipping_at_checkout_with_policy_html": "Impostos incluídos. Descontos e envio calculados na finalização da compra.", + "taxes_included_shipping_at_checkout_without_policy": "Impostos incluídos. Descontos e envio calculados na finalização da compra.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Encargos incluídos. Impostos, descontos e envio calculados na finalização da compra.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Encargos incluídos. Impostos, descontos e envio calculados na finalização da compra.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Impostos, descontos e envio calculados na finalização da compra.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Impostos, descontos e envio calculados na finalização da compra.", + "checkout": "Finalizar a compra", + "cart_title": "Carrinho", + "price": "Preço", + "price_regular": "Preço normal", + "price_compare_at": "Preço comparado", + "price_sale": "Preço de saldo", + "duties_and_taxes_included": "Encargos e impostos incluídos.", + "duties_included": "Encargos incluídos.", + "shipping_policy_html": "Envio calculado na finalização da compra.", + "taxes_included": "Impostos incluídos.", + "product_badge_sold_out": "Esgotado", + "product_badge_sale": "Saldo", + "search_input_label": "Pesquisar", + "search_input_placeholder": "Pesquisar", + "search_results": "Resultados da pesquisa", + "search_results_label": "Resultados da pesquisa", + "search_results_no_results": "Nenhum resultado encontrado para \"{{ terms }}\". Experimente outra pesquisa.", + "search_results_resource_articles": "Publicações no blogue", + "search_results_resource_collections": "Coleções", + "search_results_resource_pages": "Páginas", + "search_results_resource_products": "Produtos", + "search_results_resource_queries": "Sugestões de pesquisa", + "search_results_view_all": "Ver tudo", + "search_results_view_all_button": "Ver tudo", + "search_results_resource_products_count": { + "one": "{{ count }} produto", + "other": "{{ count }} produtos", + "many": "{{ count }} produtos" + }, + "grid_view": { + "default_view": "Predefinição", + "grid_fieldset": "Grelha de coluna", + "single_item": "Único", + "zoom_out": "Menos zoom" + }, + "unavailable": "Indisponível", + "collection_placeholder": "Título da coleção", + "product_card_placeholder": "Título do produto", + "recently_viewed_products": "Vistos recentemente", + "product_count": "Número de produtos", + "item_count": { + "one": "{{ count }} item", + "other": "{{ count }} itens", + "many": "{{ count }} itens" + }, + "errors": "Erros", + "search": "Pesquisar", + "search_results_no_results_check_spelling": "Nenhum resultado encontrado para \"{{ terms }}\". Verifique a ortografia ou utilize outra palavra ou expressão.", + "featured_products": "Produtos em destaque", + "price_from": "Desde {{ price }}", + "filters": "Filtros", + "no_products_found": "Nenhum produto encontrado.", + "price_filter_html": "O preço mais alto é {{ price }}", + "use_fewer_filters_html": "Experimente utilizar menos filtros ou limpar todos os filtros.", + "blog_details_separator": "|", + "account_title": "Conta", + "account_title_personalized": "Olá, {{ first_name }}", + "account_orders": "Encomendas", + "account_profile": "Perfil", + "discount_code": "Código de desconto", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Encargos e impostos incluídos. Os portes são calculados na finalização da compra.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Encargos e impostos incluídos. Os portes são calculados na finalização da compra.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Encargos incluídos. Os portes são calculados na finalização da compra.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Encargos incluídos. Os portes são calculados na finalização da compra.", + "pickup_available_at_html": "Recolha disponível em {{ location }}", + "pickup_available_in": "Recolha disponível, {{ pickup_time }}", + "pickup_not_available": "Recolha atualmente indisponível", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Ler mais...", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Impostos e portes calculados na finalização da compra.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Impostos e portes calculados na finalização da compra.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Impostos incluídos. Os portes são calculados na finalização da compra.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Impostos incluídos. Os portes são calculados na finalização da compra.", + "wrong_password": "Palavra-passe incorreta", + "view_more_details": "Ver mais informações", + "page_placeholder_title": "Título da página", + "page_placeholder_content": "Selecione uma página para apresentar o conteúdo.", + "powered_by": "Esta loja terá tecnologia", + "store_owner_link_html": "É o proprietário da loja? Inicie sessão aqui", + "shipping_discount_error": "Os descontos de envio são apresentados na finalização da compra após adicionar um endereço", + "discount_code_error": "O código de desconto não pode ser aplicado ao seu carrinho", + "inventory_low_stock": "Stock reduzido", + "inventory_in_stock": "Em stock", + "inventory_out_of_stock": "Esgotado", + "placeholder_image": "Imagem de marcador de posição", + "shipping_policy": "Portes calculados na finalização da compra.", + "inventory_low_stock_show_count": { + "one": "{{ count }} restante(s)", + "other": "{{ count }} restante(s)", + "many": "{{ count }} restante(s)" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Utilize o código do cartão de oferta online ou o código QR na loja", + "title": "Aqui está o seu saldo do cartão de oferta de {{ value }} para {{ shop }}!", + "subtext": "O seu cartão de oferta", + "shop_link": "Visite a loja online", + "add_to_apple_wallet": "Adicionar a Apple Wallet", + "qr_image_alt": "Código QR — digitalizar para resgatar cartão de oferta", + "copy_code": "Copiar código de cartão-de oferta", + "expiration_date": "Expira em {{ expires_on }}", + "copy_code_success": "Código copiado com sucesso", + "expired": "Expirado" + } + }, + "placeholders": { + "password": "Palavra-passe", + "search": "Pesquisar", + "product_title": "Título do produto", + "collection_title": "Título da coleção" + }, + "products": { + "product": { + "add_to_cart": "Adicionar ao carrinho", + "added_to_cart": "Adicionado ao carrinho", + "adding_to_cart": "A adicionar...", + "add_to_cart_error": "Erro ao adicionar ao carrinho", + "sold_out": "Esgotado", + "unavailable": "Indisponível" + } + }, + "fields": { + "separator": "a" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} comentário", + "other": "{{ count }} comentários", + "many": "{{ count }} comentários" + } + }, + "comment_form": { + "email": "E-mail", + "error": "Falha ao publicar comentário, resolva o seguinte:", + "heading": "Deixe um comentário", + "message": "Mensagem", + "moderated": "Tenha em atenção que os comentários necessitam de ser aprovados antes de serem publicados.", + "name": "Nome", + "post": "Publicar comentário", + "success_moderated": "Comentário publicado, a aguardar moderação", + "success": "Comentário publicado" + } + } +} diff --git a/locales/pt-PT.schema.json b/locales/pt-PT.schema.json new file mode 100644 index 000000000..22508e94e --- /dev/null +++ b/locales/pt-PT.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Limites", + "collapsible_row": "Linha recolhível", + "colors": "Cores", + "custom_section": "Secção personalizada", + "icon": "Ícone", + "logo_and_favicon": "Logótipo e favicon", + "overlapping_blocks": "Blocos sobrepostos", + "product_buy_buttons": "Botões de compra", + "product_description": "Descrição", + "product_price": "Preço", + "product_variant_picker": "Seletor de variante", + "slideshow": "Apresentação de diapositivos", + "typography": "Tipografia", + "video": "Vídeo", + "slideshow_controls": "Controlos da apresentação de slides", + "size": "Tamanho", + "spacing": "Espaçamento", + "product_recommendations": "Produtos recomendados", + "product_media": "Conteúdo multimédia do produto", + "featured_collection": "Coleção em destaque", + "add_to_cart": "Adicionar ao carrinho", + "email_signup": "Registo de e-mail", + "submit_button": "Botão Submeter", + "grid_layout_selector": "Seletor de esquema de grelha", + "image": "Imagem", + "list_items": "Itens da lista", + "facets": "Facetas", + "variants": "Variantes", + "styles": "Estilos", + "product_cards": "Cartões de produtos", + "buttons": "Botões", + "inputs": "Entradas", + "primary_button": "Botão principal", + "secondary_button": "Botão secundário", + "popovers": "Pop-overs", + "marquee": "Marcador", + "pull_quote": "Obter orçamento", + "contact_form": "Formulário de contacto", + "featured_product": "Destaques do produto", + "icons_with_text": "Ícones com texto", + "alternating_content_rows": "Linhas alternadas", + "product_list": "Coleção em destaque", + "spacer": "Espaçador", + "accelerated_checkout": "Finalização da compra acelerada", + "accordion": "Acordeão", + "accordion_row": "Linha acordeão", + "animations": "Animações", + "announcement": "Anúncio", + "announcement_bar": "Barra de anúncio", + "badges": "Selos", + "button": "Botão", + "cart": "Carrinho", + "cart_items": "Itens do carrinho", + "cart_products": "Produtos do carrinho", + "cart_title": "Carrinho", + "collection": "Coleção", + "collection_card": "Cartão de coleção", + "collection_columns": "Colunas de coleção", + "collection_container": "Coleção", + "collection_description": "Descrição de coleção", + "collection_image": "Imagem da coleção", + "collection_info": "Informação de coleção", + "collection_list": "Lista de coleções", + "collections": "Coleções", + "content": "Conteúdo", + "content_grid": "Grelha de conteúdo", + "details": "Detalhes", + "divider": "Divisor", + "filters": "Filtragem e ordenação", + "follow_on_shop": "Seguir na Shop", + "footer": "Rodapé", + "footer_utilities": "Utilitários de rodapé", + "group": "Grupo", + "header": "Cabeçalho", + "heading": "Título", + "icons": "Ícones", + "image_with_text": "Imagem com texto", + "input": "Entrada", + "logo": "Logótipo", + "magazine_grid": "Grelha de revista", + "media": "Conteúdo multimédia", + "menu": "Menu", + "mobile_layout": "Esquema para dispositivo móvel", + "payment_icons": "Ícones de pagamento", + "popup_link": "Ligação pop-up", + "predictive_search": "Pesquisar pop-over", + "predictive_search_empty": "Pesquisa preditiva vazia", + "price": "Preço", + "product": "Produto", + "product_card": "Cartão de produto", + "product_card_media": "Conteúdo multimédia", + "product_card_rendering": "Renderização de cartão de produto", + "product_grid": "Grelha", + "product_grid_main": "Grelha de produtos", + "product_image": "Imagem de produto", + "product_information": "Informações de produto", + "product_review_stars": "Estrelas de avaliação", + "quantity": "Quantidade", + "row": "Linha", + "search": "Pesquisar", + "section": "Secção", + "selected_variants": "Variantes selecionadas", + "shop_the_look": "Visual Shop", + "slide": "Diapositivo", + "social_media_links": "Ligações de redes sociais", + "steps": "Passos", + "summary": "Resumo", + "swatches": "Paletas", + "testimonials": "Depoimentos", + "text": "Texto", + "title": "Título", + "utilities": "Utilitários", + "search_input": "Entrada de pesquisa", + "search_results": "Resultados da pesquisa", + "read_only": "Só de leitura", + "collection_title": "Título da coleção", + "collections_bento": "Lista de coleções: Bento", + "faq_section": "FAQ", + "hero": "Hero", + "jumbo_text": "Texto Jumbo", + "view_all_button": "Ver tudo", + "video_section": "Vídeo", + "custom_liquid": "Liquid personalizado", + "blog": "Blogue", + "blog_post": "Publicação de blogue", + "blog_posts": "Publicações no blogue", + "caption": "Legenda", + "collection_card_image": "Imagem", + "collection_links": "Ligações de coleção", + "collection_links_spotlight": "Ligações de coleção: Spotlight", + "collection_links_text": "Ligações de coleção: Texto", + "collections_carousel": "Lista de coleções: Carrossel", + "collections_editorial": "Lista de coleções: Editorial", + "collections_grid": "Lista de coleções: Grelha", + "copyright": "Direitos de autor", + "count": "Contagem", + "divider_section": "Divisor", + "drawers": "Gavetas", + "editorial": "Editorial", + "editorial_jumbo_text": "Editorial: Texto Jumbo", + "hero_marquee": "Hero: Marcador", + "input_fields": "Campos de entrada", + "local_pickup": "Recolha local", + "marquee_section": "Marcador", + "media_with_text": "Conteúdo multimédia com texto", + "page": "Página", + "page_content": "Conteúdo", + "page_layout": "Esquema da página", + "policy_list": "Ligações para políticas", + "prices": "Preços", + "products_carousel": "Coleção em destaque: Carrossel", + "products_editorial": "Coleção em destaque: Editorial", + "products_grid": "Coleção em destaque: Grelha", + "social_link": "Ligação para redes sociais", + "split_showcase": "Apresentação dividida", + "variant_pickers": "Seletores de variantes", + "pills": "Forma de comprimidos", + "product_title": "Título do produto", + "large_logo": "Logótipo grande", + "product_list_button": "Botão Ver tudo", + "product_inventory": "Inventário de produtos", + "description": "Descrição" + }, + "settings": { + "alignment": "Alinhamento", + "autoplay": "Reprodução automática", + "background": "Fundo", + "border_radius": "Raio do canto", + "border_width": "Espessura do limite", + "borders": "Limites", + "bottom_padding": "Preenchimento inferior", + "button": "Botão", + "color": "Cor", + "colors": "Cores", + "content_alignment": "Alinhamento de conteúdo", + "content_direction": "Direção do conteúdo", + "content_position": "Posição do conteúdo", + "cover_image_size": "Tamanho da imagem de capa", + "cover_image": "Imagem de capa", + "custom_minimum_height": "Altura mínima personalizada", + "custom_width": "Largura personalizada", + "enable_video_looping": "Loop de vídeo", + "favicon": "Favicon", + "font_family": "Família de tipo de letra", + "gap": "Intervalo", + "geometric_translate_y": "Tradução Y geométrica", + "heading": "Cabeçalho", + "icon": "Ícone", + "image": "Imagem", + "image_icon": "Ícone de imagem", + "image_opacity": "Opacidade da imagem", + "image_position": "Posição da imagem", + "image_ratio": "Proporção de imagem", + "label": "Etiqueta", + "line_height": "Altura de linha", + "link": "Ligação", + "layout_gap": "Intervalo do esquema", + "make_section_full_width": "Tornar a secção em largura total", + "minimum_height": "Altura mínima", + "opacity": "Opacidade", + "overlay_opacity": "Opacidade de sobreposição", + "padding": "Preenchimento", + "primary_color": "Ligações", + "product": "Produto", + "section_width": "Largura da secção", + "size": "Tamanho", + "slide_spacing": "Intervalo do diapositivo", + "slide_width": "Largura do diapositivo", + "slideshow_fullwidth": "Diapositivos de largura total", + "style": "Estilo", + "text": "Texto", + "text_case": "Caixa", + "top_padding": "Preenchimento superior", + "video": "Vídeo", + "video_alt_text": "Texto alternativo", + "video_loop": "Repetir vídeo", + "video_position": "Posição do vídeo", + "width": "Largura", + "z_index": "Índice Z", + "limit_content_width": "Limitar largura do conteúdo", + "color_scheme": "Esquema de cores", + "inherit_color_scheme": "Herdar esquema de cores", + "product_count": "Contagem de produtos", + "product_type": "Tipo de produto", + "content_width": "Largura do conteúdo", + "collection": "Coleção", + "enable_sticky_content": "Conteúdo fixador no ambiente de trabalho", + "error_color": "Erro", + "success_color": "Sucesso", + "primary_font": "Tipo de letra principal", + "secondary_font": "Tipo de letra secundário", + "tertiary_font": "Tipo de letra terciário", + "columns": "Colunas", + "items_to_show": "Itens a apresentar", + "layout": "Esquema", + "layout_type": "Tipo", + "show_grid_layout_selector": "Mostrar seletor de esquema de grelha", + "view_more_show": "Mostrar o botão Ver mais", + "image_gap": "Intervalo de imagem", + "width_desktop": "Largura para computador", + "width_mobile": "Largura para dispositivo móvel", + "border_style": "Estilo da borda", + "height": "Altura", + "thickness": "Espessura", + "stroke": "Traço", + "filter_style": "Filtrar estilo", + "swatches": "Paletas", + "quick_add_colors": "Adição rápida de cores", + "divider_color": "Divisor", + "border_opacity": "Opacidade de borda", + "hover_background": "Fundo ao passar o cursor", + "hover_borders": "Contorno ao passar o cursor", + "hover_text": "Texto ao passar o cursor", + "primary_hover_color": "Ligação ao passar o cursor", + "primary_button_text": "Texto do botão principal", + "primary_button_background": "Fundo do botão principal", + "primary_button_border": "Contorno do botão principal", + "secondary_button_text": "Texto do botão secundário", + "secondary_button_background": "Fundo do botão secundário", + "secondary_button_border": "Contorno do botão secundário", + "shadow_color": "Sombra", + "limit_media_to_screen_height": "Ajustar à altura do ecrã", + "mobile_logo_image": "Logótipo móvel", + "video_autoplay": "Reprodução automática", + "video_cover_image": "Imagem de capa", + "video_external_url": "URL", + "video_source": "Fonte", + "first_row_media_position": "Posição do conteúdo multimédia na primeira linha", + "background_color": "Cor de fundo", + "hide_padding": "Ocultar preenchimento", + "logo_font": "Tipo de letra do logótipo", + "size_mobile": "Tamanho para móvel", + "pixel_size_mobile": "Tamanho em píxeis", + "percent_size_mobile": "Tamanho em percentagem", + "unit": "Unidade", + "custom_mobile_size": "Tamanho para móvel personalizado", + "fixed_height": "Altura de píxel", + "fixed_width": "Largura de píxel", + "percent_height": "Altura em percentagem", + "percent_width": "Largura em percentagem", + "percent_size": "Tamanho em percentagem", + "pixel_size": "Tamanho em píxeis", + "accordion": "Acordeão", + "aspect_ratio": "Relação de altura/largura", + "auto_rotate_announcements": "Rotação automática de anúncios", + "auto_rotate_slides": "Rotação automática de diapositivos", + "badge_corner_radius": "Raio do canto", + "badge_position": "Posição nos cartões", + "badge_sale_color_scheme": "Venda", + "badge_sold_out_color_scheme": "Esgotado", + "behavior": "Comportamento", + "blur": "Sombra desfocada", + "border": "Limite", + "bottom": "Inferior", + "card_image_height": "Altura da imagem de produto", + "carousel_on_mobile": "Carrossel em dispositivo móvel", + "cart_count": "Contagem de carrinhos", + "cart_items": "Itens do carrinho", + "cart_related_products": "Produtos relacionados", + "cart_title": "Carrinho", + "cart_total": "Total do carrinho", + "cart_type": "Tipo", + "case": "Caixa", + "checkout_buttons": "Botões de finalização de compra acelerada", + "collection_list": "Coleções", + "collection_templates": "Modelos de coleção", + "content": "Conteúdo", + "corner_radius": "Raio do canto", + "country_region": "País/região", + "currency_code": "Código da moeda", + "custom_height": "Altura personalizada", + "desktop_height": "Altura para computador", + "direction": "Direção", + "display": "Exibição", + "divider_thickness": "Espessura do divisor", + "divider": "Divisor", + "dividers": "Divisores", + "drop_shadow": "Sombra projetada", + "empty_state_collection_info": "Apresentado antes da introdução de uma pesquisa", + "empty_state_collection": "Coleção de estado vazio", + "enable_filtering": "Filtros", + "enable_grid_density": "Controlo de esquema de grelha", + "enable_sorting": "Ordenação", + "enable_zoom": "Ativar zoom", + "equal_columns": "Colunas iguais", + "expand_first_group": "Expandir primeiro grupo", + "extend_media_to_screen_edge": "Estender conteúdo multimédia até à borda do ecrã", + "extend_summary": "Estender até à borda do ecrã", + "extra_large": "Extra grande", + "extra_small": "Extra pequeno", + "flag": "Sinalizar", + "font_price": "Tipo de letra do preço", + "font_weight": "Peso do tipo de letra", + "font": "Tipo de letra", + "full_width_first_image": "Largura total primeira imagem", + "full_width_on_mobile": "Largura total em dispositivo móvel", + "heading_preset": "Predefinição de título", + "hide_unselected_variant_media": "Ocultar conteúdo multimédia de variante não selecionada", + "horizontal_gap": "Intervalo horizontal", + "horizontal_offset": "Desvio horizontal da sombra", + "hover_behavior": "Comportamento ao passar o cursor", + "icon_background": "Fundo do ícone", + "icons": "Ícones", + "image_border_radius": "Raio de canto da imagem", + "installments": "Prestações", + "integrated_button": "Botão integrado", + "language_selector": "Seletor de idioma", + "large": "Grande", + "left_padding": "Preenchimento esquerdo", + "left": "Esquerda", + "letter_spacing": "Espaçamento entre letras", + "limit_product_details_width": "Limitar largura dos detalhes do produto", + "link_preset": "Predefinição de ligação", + "links": "Ligações", + "logo": "Logótipo", + "loop": "Repetição", + "make_details_sticky_desktop": "Fixador para computador", + "max_width": "Largura máx", + "media_height": "Altura do conteúdo multimédia", + "media_overlay": "Sobreposição do conteúdo multimédia", + "media_position": "Posição do conteúdo multimédia", + "media_type": "Tipo de conteúdo multimédia", + "media_width": "Largura do conteúdo multimédia", + "menu": "Menu", + "mobile_columns": "Colunas em dispositivos móveis", + "mobile_height": "Altura em dispositivo móvel", + "mobile_quick_add": "Adição rápida de dispositivo móvel", + "motion_direction": "Direção de movimento", + "motion": "Movimento", + "movement_direction": "Direção de movimento", + "navigation_bar_color_scheme": "Esquema de cores da barra de navegação", + "navigation_bar": "Barra de navegação", + "navigation": "Navegação", + "open_new_tab": "Abrir ligação em novo separador", + "overlay_color": "Cor de sobreposição", + "overlay": "Sobreposição", + "padding_bottom": "Preenchimento inferior", + "padding_horizontal": "Preenchimento horizontal", + "padding_top": "Preenchimento superior", + "page_width": "Largura da página", + "pagination": "Paginação", + "placement": "Posicionamento", + "position": "Posição", + "preset": "Predefinição", + "product_cards": "Cartões de produtos", + "product_pages": "Páginas de produtos", + "product_templates": "Modelos de produto", + "products": "Produtos", + "quick_add": "Adição rápida", + "ratio": "Proporção", + "regular": "Normal", + "review_count": "Contagem de avaliações", + "right": "Direita", + "row_height": "Altura da linha", + "row": "Linha", + "seller_note": "Permitir nota ao vendedor", + "shape": "Forma", + "show_as_accordion": "Mostrar como acordeão em dispositivo móvel", + "show_sale_price_first": "Mostrar preço de saldo primeiro", + "show_tax_info": "Informações tributárias", + "show": "Mostrar", + "small": "Pequeno", + "speed": "Velocidade", + "statement": "Extrato", + "sticky_header": "Cabeçalho fixo", + "text_hierarchy": "Hierarquia de texto", + "text_presets": "Predefinições de texto", + "title": "Título", + "top": "Superior", + "type": "Tipo", + "type_preset": "Predefinição de texto", + "underline_thickness": "Espessura do sublinhado", + "variant_images": "Imagens da variante", + "vendor": "Fornecedor", + "vertical_gap": "Intervalo vertical", + "vertical_offset": "Desvio vertical da sombra", + "vertical_on_mobile": "Vertical para dispositivo móvel", + "view_all_as_last_card": "\"Ver tudo\" como último cartão", + "weight": "Peso", + "wrap": "Envolvimento", + "read_only": "Só de leitura", + "always_stack_buttons": "Empilhar sempre botões", + "custom_mobile_width": "Largura para dispositivo móvel personalizada", + "gradient_direction": "Direção de gradiente", + "overlay_style": "Estilo da sobreposição", + "shadow_opacity": "Opacidade da sombra", + "show_filter_label": "Etiquetas de texto para filtros aplicados", + "show_swatch_label": "Etiquetas de texto para paletas", + "transparent_background": "Fundo transparente", + "account": "Conta", + "align_baseline": "Alinhar baseline de texto", + "add_discount_code": "Permitir descontos no carrinho", + "background_overlay": "Sobreposição de fundo", + "background_media": "Conteúdo multimédia de fundo", + "border_thickness": "Espessura do limite", + "bottom_row": "Linha inferior", + "button_text_case": "Texto em maiúsculas/minúsculas", + "button_text_weight": "Peso do texto", + "card_size": "Tamanho do cartão", + "auto_open_cart_drawer": "\"Adicionar ao carrinho\" abre automaticamente uma gaveta", + "collection_count": "Número de coleções", + "custom_liquid": "Código Liquid", + "default": "Predefinição", + "default_logo": "Logótipo padrão", + "divider_width": "Largura do divisor", + "headings": "Títulos", + "hide_logo_on_home_page": "Ocultar logótipo na página inicial", + "horizontal_padding": "Preenchimento horizontal", + "inverse": "Invertido", + "inverse_logo": "Logótipo invertido", + "layout_style": "Estilo", + "length": "Comprimento", + "mobile_card_size": "Tamanho de cartão para dispositivo móvel", + "mobile_pagination": "Paginação móvel", + "open_row_by_default": "Abrir linha por predefinição", + "page": "Página", + "page_transition_enabled": "Transição de página", + "right_padding": "Preenchimento direito", + "search": "Pesquisar", + "search_icon": "Ícone de pesquisa", + "search_position": "Posição", + "search_row": "Linha", + "show_author": "Autor", + "show_alignment": "Mostrar alinhamento", + "show_count": "Mostrar contagem", + "show_date": "Data", + "show_pickup_availability": "Mostrar disponibilidade de recolha", + "show_search": "Mostrar pesquisa", + "use_inverse_logo": "Utilizar logótipo invertido", + "vertical_padding": "Preenchimento vertical", + "visibility": "Visibilidade", + "product_corner_radius": "Raio de canto do produto", + "card_corner_radius": "Raio de canto do cartão", + "alignment_mobile": "Alinhamento em dispositivos móveis", + "animation_repeat": "Repetir animação", + "blurred_reflection": "Reflexo desfocado", + "card_hover_effect": "Efeito ao passar o rato no cartão", + "collection_title_case": "Formato de maiúsculas iniciais da coleção", + "effects": "Efeitos", + "inventory_threshold": "Limiar de stock baixo", + "product_and_card_title_case": "Formato de maiúsculas iniciais do produto e cartão", + "product_title_case": "Formato de maiúsculas iniciais do produto", + "reflection_opacity": "Opacidade do reflexo", + "show_inventory_quantity": "Mostrar quantidade de stock baixo", + "text_label_case": "Formato de maiúsculas iniciais das etiquetas de texto", + "transition_to_main_product": "Transição entre cartão de produto e página de produto", + "show_second_image_on_hover": "Mostrar segunda imagem ao passar o rato", + "media": "Conteúdo multimédia", + "product_card_carousel": "Mostrar carrossel", + "media_fit": "Ajuste do conteúdo multimédia", + "scroll_speed": "Deslocar para o próximo anúncio" + }, + "options": { + "adapt_to_image": "Adaptar à imagem", + "apple": "Maçã", + "arrow": "Seta", + "auto": "Automático", + "banana": "Banana", + "bottle": "Garrafa", + "box": "Caixa", + "buttons": "Botões", + "carrot": "Cenoura", + "center": "Centro", + "chat_bubble": "Bolha de conversa", + "clipboard": "Área de transferência", + "contain": "Contém", + "counter": "Contador", + "cover": "Capa", + "custom": "Personalizado", + "dairy_free": "Sem produtos lácteos", + "dairy": "Produtos lácteos", + "default": "Predefinição", + "dropdowns": "Menus pendentes", + "dots": "Pontos", + "dryer": "Secador", + "end": "Fim", + "eye": "Olho", + "facebook": "Facebook", + "fill": "Preencher", + "fire": "Fogo", + "fit": "Ajustar", + "full": "Completo", + "full_and_page": "Fundo completo, conteúdo de largura de página", + "gluten_free": "Sem glúten", + "heading": "Título", + "heart": "Coração", + "horizontal": "Horizontal", + "instagram": "Instagram", + "iron": "Ferro", + "landscape": "Horizontal", + "large": "Grande", + "leaf": "Folha", + "leather": "Couro", + "lg": "L", + "lightning_bolt": "Relâmpago", + "link": "Ligação", + "lipstick": "Batom", + "lock": "Cadeado", + "lowercase": "minúsculas", + "m": "M", + "map_pin": "Marcador de mapa", + "medium": "Médio", + "none": "Nenhum(a)", + "numbers": "Números", + "nut_free": "Sem frutos de casca rija", + "outline": "Contorno", + "page": "Página", + "pants": "Calças", + "paw_print": "Marca de pata", + "pepper": "Pimenta", + "perfume": "Perfume", + "pinterest": "Pinterest", + "plane": "Avião", + "plant": "Planta", + "portrait": "Vertical", + "price_tag": "Etiqueta de preço", + "question_mark": "Ponto de interrogação", + "recycle": "Reciclar", + "return": "Devolução", + "ruler": "Régua", + "s": "S", + "sentence": "Frase", + "serving_dish": "Prato", + "shirt": "Camisa", + "shoe": "Sapato", + "silhouette": "Silhueta", + "small": "Pequeno", + "snapchat": "Snapchat", + "snowflake": "Floco de neve", + "solid": "Sólido", + "space_between": "Espaço entre", + "square": "Quadrado", + "star": "Estrela", + "start": "Início", + "stopwatch": "Cronómetro", + "tiktok": "TikTok", + "truck": "Camião", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Maiúsculas", + "vertical": "Vertical", + "vimeo": "Vimeo", + "washing": "Lavar", + "circle": "Círculo", + "swatches": "Paletas", + "full_and_page_offset_left": "Fundo completo, conteúdo limitado à largura da página, ajustado à esquerda", + "full_and_page_offset_right": "Fundo completo, conteúdo limitado à largura da página, ajustado à direita", + "offset_left": "Ajustado à esquerda", + "offset_right": "Ajustado à direita", + "page_center_aligned": "Página, alinhado ao centro", + "page_left_aligned": "Página, alinhado à esquerda", + "page_right_aligned": "Página, alinhado à direita", + "button": "Botão", + "caption": "Legenda", + "h1": "Título 1", + "h2": "Título 2", + "h3": "Título 3", + "h4": "Título 4", + "h5": "Título 5", + "h6": "Título 6", + "paragraph": "Parágrafo", + "primary": "Principal", + "secondary": "Secundário", + "tertiary": "Terciário", + "chevron_left": "Divisa para a esquerda", + "chevron_right": "Divisa para a direita", + "diamond": "Diamante", + "grid": "Grelha", + "parallelogram": "Paralelograma", + "rounded": "Arredondado", + "fit_content": "Ajustar", + "pills": "Forma de comprimidos", + "heavy": "Grosso", + "thin": "Fino", + "drawer": "Gaveta", + "preview": "Pré-visualização", + "text": "Texto", + "video_uploaded": "Carregado", + "video_external_url": "URL externo", + "up": "Para cima", + "down": "Para baixo", + "gradient": "Gradiente", + "aspect_ratio": "Relação de altura/largura", + "fixed": "Fixo", + "pixel": "Píxeis", + "percent": "Percentagem", + "above_carousel": "Por cima do carrossel", + "all": "Tudo", + "always": "Sempre", + "arrows_large": "Setas grandes", + "arrows": "Setas", + "balance": "Saldo", + "bento": "Bento", + "black": "Preto", + "bluesky": "Bluesky", + "body_large": "Corpo (Grande)", + "body_regular": "Corpo (Normal)", + "body_small": "Corpo (Pequeno)", + "bold": "Negrito", + "bottom_left": "Canto inferior esquerdo", + "bottom_right": "Canto inferior direito", + "bottom": "Inferior", + "capitalize": "Capitalizar", + "caret": "Caret", + "carousel": "Carrossel", + "check_box": "Caixa de seleção", + "chevron_large": "Divisas grandes", + "chevron": "Divisa", + "chevrons": "Divisas", + "classic": "Clássico", + "collection_images": "Imagens da coleção", + "color": "Cor", + "complementary": "Complementar", + "dissolve": "Dissolver", + "dotted": "Pontilhado", + "editorial": "Editorial", + "extra_large": "Extra grande", + "extra_small": "Extra pequeno", + "featured_collections": "Coleções em destaque", + "featured_products": "Produtos em destaque", + "font_primary": "Principal", + "font_secondary": "Secundário", + "font_tertiary": "Terciário", + "forward": "Avançar", + "full_screen": "Ecrã inteiro", + "heading_extra_large": "Título (Extra grande)", + "heading_extra_small": "Título (Extra pequeno)", + "heading_large": "Título (Grande)", + "heading_regular": "Título (Normal)", + "heading_small": "Título (Pequeno)", + "icon": "Ícone", + "image": "Imagem", + "input": "Entrada", + "inside_carousel": "Carrossel interior", + "inverse_large": "Invertido grande", + "inverse": "Invertido", + "large_arrows": "Setas grandes", + "large_chevrons": "Divisas grandes", + "left": "Esquerda", + "light": "Claro", + "linkedin": "LinkedIn", + "loose": "Solto", + "media_first": "Conteúdo multimédia primeiro", + "media_second": "Conteúdo multimédia segundo", + "modal": "Modal", + "narrow": "Estreito", + "never": "Nunca", + "next_to_carousel": "Junto ao carrossel", + "normal": "Normal", + "nowrap": "Sem passagem de linha", + "off_media": "Fora do conteúdo multimédia", + "on_media": "No conteúdo multimédia", + "on_scroll_up": "Ao rodar a roda do rato para cima", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Comprimido", + "plus": "Plus", + "pretty": "Bonito", + "price": "Preço", + "primary_style": "Estilo primário", + "rectangle": "Retângulo", + "regular": "Normal", + "related": "Relacionado", + "reverse": "Inverter", + "rich_text": "Texto formatado", + "right": "Direita", + "secondary_style": "Estilo secundário", + "semibold": "Seminegrito", + "shaded": "Sombreado", + "show_second_image": "Mostrar segunda imagem", + "single": "Único", + "slide_left": "Deslizar para a esquerda", + "slide_up": "Deslizar para cima", + "spotify": "Spotify", + "stack": "Stack", + "text_only": "Só texto", + "threads": "Threads", + "thumbnails": "Miniaturas", + "tight": "Apertado", + "top_left": "Canto superior esquerdo", + "top_right": "Canto superior direito", + "top": "Superior", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Sublinhado", + "video": "Vídeo", + "wide": "Largo", + "youtube": "YouTube", + "accent": "Destaque", + "below_image": "Abaixo da imagem", + "body": "Corpo", + "button_primary": "Botão principal", + "button_secondary": "Botão secundário", + "compact": "Compacta", + "crop_to_fit": "Recortar para ajustar", + "hidden": "Oculto", + "hint": "Dica", + "maintain_aspect_ratio": "Manter proporção", + "off": "Desativar", + "on_image": "Na imagem", + "social_bluesky": "Social: Bluesky", + "social_facebook": "Social: Facebook", + "social_instagram": "Social: Instagram", + "social_linkedin": "Social: LinkedIn", + "social_pinterest": "Social: Pinterest", + "social_snapchat": "Social: Snapchat", + "social_spotify": "Social: Spotify", + "social_threads": "Social: Threads", + "social_tiktok": "Social: TikTok", + "social_tumblr": "Social: Tumblr", + "social_twitter": "Social: X (Twitter)", + "social_whatsapp": "Social: WhatsApp", + "social_vimeo": "Social: Vimeo", + "social_youtube": "Social: YouTube", + "spotlight": "Spotlight", + "standard": "Normal", + "subheading": "Subtítulo", + "blur": "Desfocar", + "lift": "Elevar", + "reveal": "Revelar", + "scale": "Expandir", + "subtle_zoom": "Zoom" + }, + "content": { + "advanced": "Avançado", + "background_image": "Imagem de fundo", + "background_video": "Vídeo de fundo", + "block_size": "Tamanho do bloco", + "borders": "Limites", + "describe_the_video_for": "Descreve o vídeo para que seja acessível a clientes que usam leitores de ecrã. [Saber mais](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Tamanho da secção", + "slideshow_width": "Largura do diapositivo", + "typography": "Tipografia", + "width_is_automatically_optimized": "A largura é otimizada automaticamente para dispositivos móveis.", + "complementary_products": "Os produtos complementares têm de ser configurados utilizando a aplicação Search & Discovery. [Saber mais](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "As colunas serão otimizadas automaticamente para dispositivos móveis", + "content_width": "Largura do conteúdo apenas aplicável se a largura da secção estiver definida para largura total.", + "adjustments_affect_all_content": "Aplicável a todo o conteúdo neste bloco", + "responsive_font_sizes": "Os tamanhos são dimensionados automaticamente para todos os tamanhos de ecrã", + "buttons": "Botões", + "swatches": "Paletas", + "variant_settings": "Definições de variante", + "background": "Fundo", + "cards_layout": "Esquema de cartões", + "section_layout": "Esquema de secção", + "mobile_size": "Tamanho para móvel", + "appearance": "Aspeto", + "arrows": "Setas", + "body_size": "Tamanho do corpo", + "bottom_row_appearance": "Aspeto da linha inferior", + "carousel_navigation": "Navegação tipo carrossel", + "carousel_pagination": "Paginação tipo carrossel", + "copyright": "Direitos de autor", + "edit_logo_in_theme_settings": "Editar logótipo em [definições de tema](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Editar formatação de preço em [definições de tema](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Editar estilo de variante em [definições de tema](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Adição de registos [perfis de clientes](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Para o botão aparecer, o canal Shop tem de ser instalado e o Shop Pay tem de ser ativado. [Saber mais](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Tipos de letra", + "grid": "Grelha", + "heading_size": "Tamanho do título", + "image": "Imagem", + "input": "Entrada", + "layout": "Esquema", + "link": "Ligação", + "link_padding": "Preenchimento de ligação", + "localization": "Localização", + "logo": "Logótipo", + "margin": "Margem", + "media": "Conteúdo multimédia", + "media_1": "Conteúdo multimédia 1", + "media_2": "Conteúdo multimédia 2", + "menu": "Menu", + "mobile_layout": "Esquema para dispositivo móvel", + "padding": "Preenchimento", + "padding_desktop": "Preenchimento para computador", + "paragraph": "Parágrafo", + "policies": "Políticas", + "popup": "Pop-up", + "search": "Pesquisar", + "size": "Tamanho", + "social_media": "Redes sociais", + "submit_button": "Botão Submeter", + "text_presets": "Predefinições de texto", + "transparent_background": "Fundo transparente", + "typography_primary": "Tipografia principal", + "typography_secondary": "Tipografia secundária", + "typography_tertiary": "Tipografia terciária", + "mobile_width": "Largura para dispositivo móvel", + "width": "Largura", + "carousel": "Carrossel", + "colors": "Cores", + "collection_page": "Página de coleção", + "copyright_info": "Saiba como [editar a sua declaração de direitos de autor](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Conta de cliente", + "edit_empty_state_collection_in_theme_settings": "Editar coleção de estado vazio em [definições de tema](/editor?context=theme&category=search)", + "grid_layout": "Esquema de grelha", + "home_page": "Página inicial", + "images": "Imagens", + "inverse_logo_info": "Utilizado quando o fundo transparente do cabeçalho é definido para Invertido", + "manage_customer_accounts": "[Gerir visibilidade](/admin/settings/customer_accounts) nas definições de contas de cliente. As contas legadas não são suportadas.", + "manage_policies": "[Gerir políticas](/admin/settings/legal)", + "product_page": "Página do produto", + "text": "Texto", + "thumbnails": "Miniaturas", + "visibility": "Visibilidade", + "visible_if_collection_has_more_products": "Visível se a coleção tiver mais produtos do que os mostrados", + "app_required_for_ratings": "É necessária uma aplicação para as classificações de produto. [Saber mais](https://help.shopify.com/manual/apps)", + "icon": "Ícone", + "resource_reference_collection_card": "Apresenta a coleção da secção principal", + "resource_reference_collection_card_image": "Apresenta a imagem da coleção principal", + "resource_reference_collection_title": "Apresenta o título da coleção principal", + "resource_reference_product": "Ligação automática ao produto principal", + "resource_reference_product_card": "Apresenta o produto da secção principal", + "resource_reference_product_inventory": "Apresenta o inventário do produto principal", + "resource_reference_product_price": "Apresenta o preço do produto principal", + "resource_reference_product_recommendations": "Apresenta recomendações com base no produto principal", + "resource_reference_product_review": "Apresenta avaliações do produto principal", + "resource_reference_product_swatches": "Apresenta as paletas do produto principal", + "resource_reference_product_title": "Apresenta o título do produto principal", + "resource_reference_product_variant_picker": "Apresenta variantes do produto principal", + "resource_reference_product_media": "Mostra o conteúdo multimédia do produto principal", + "product_media": "Conteúdo multimédia do produto", + "manage_store_name": "[Gerir o nome da loja](/admin/settings/general?edit=storeName)", + "section_link": "Ligação para a secção" + }, + "html_defaults": { + "share_information_about_your": "

Partilhe informações sobre a sua marca com os clientes. Descreva um produto, faça comunicados ou dê as boas-vindas aos clientes da loja.

" + }, + "text_defaults": { + "button_label": "Comprar agora", + "collapsible_row": "Linha recolhível", + "heading": "Título", + "email_signup_button_label": "Subscrever", + "accordion_heading": "Título acordeão", + "contact_form_button_label": "Submeter", + "popup_link": "Ligação pop-up", + "sign_up": "Registe-se", + "welcome_to_our_store": "Bem-vindo à nossa loja", + "be_bold": "Seja arrojado.", + "shop_our_latest_arrivals": "Compre as nossas novidades mais recentes!" + }, + "info": { + "video_alt_text": "Descreva o vídeo para utilizadores de tecnologia de apoio", + "video_autoplay": "O som dos vídeos estará desativado por predefinição", + "video_external": "Utilizar um URL do YouTube ou Vimeo", + "carousel_layout_on_mobile": "O carrossel é utilizado num dispositivo móvel", + "link_info": "Opcional: torna o ícone clicável", + "carousel_hover_behavior_not_supported": "Movimento \"Carrossel\" de passar o cursor não é suportado quando o tipo \"Carrossel\" é selecionado no nível de secção", + "grid_layout_on_mobile": "O esquema de grelha é utilizado para dispositivos móveis", + "logo_font": "Apenas aplicável quando não é selecionado um logótipo", + "checkout_buttons": "Permite que os compradores finalizem a compra mais rapidamente e pode melhorar a conversão. [Saber mais](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Título personalizado", + "edit_presets_in_theme_settings": "Editar predefinições em [definições de tema](/editor?context=theme&category=typography)", + "enable_filtering_info": "Personalizar filtros com a [aplicação Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "manage_countries_regions": "[Gerir países/regiões](/admin/settings/markets)", + "manage_languages": "[Gerir idiomas](/admin/settings/languages)", + "transparent_background": "Reveja cada modelo em que é aplicado um fundo transparente para melhor legibilidade", + "aspect_ratio_adjusted": "Ajustado em alguns esquemas", + "auto_open_cart_drawer": "Quando ativado, o painel deslizante do carrinho abre-se automaticamente quando um produto é adicionado ao carrinho.", + "custom_liquid": "Adicione fragmentos de aplicação ou outro código para criar personalizações avançadas. [Saber mais](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Utilizado para filtros aplicados, códigos de desconto e sugestões de pesquisa", + "applies_on_image_only": "Apenas aplicável às imagens", + "hover_effects": "Aplicável a cartões de produto e coleção" + }, + "categories": { + "basic": "Basic", + "collection": "Coleção", + "collection_list": "Lista de coleções", + "footer": "Rodapé", + "forms": "Formulários", + "header": "Cabeçalho", + "layout": "Esquema", + "links": "Ligações", + "product": "Produto", + "product_list": "Coleção em destaque", + "banners": "Faixas", + "collections": "Coleções", + "custom": "Personalizado", + "decorative": "Decorativo", + "products": "Produtos", + "other_sections": "Outro", + "storytelling": "Contar uma história" + } +} diff --git a/locales/ro.json b/locales/ro.json new file mode 100644 index 000000000..63d4b0f3f --- /dev/null +++ b/locales/ro.json @@ -0,0 +1,277 @@ +{ + "blocks": { + "load_video": "Încarcă clipul video: {{ description }}", + "sold_out": "Stoc epuizat", + "email_signup": { + "label": "E-mail", + "placeholder": "Adresă de e-mail", + "success": "Mulțumim pentru că te-ai abonat!" + }, + "filter": "Filtrează", + "contact_form": { + "name": "Nume", + "email": "Adresă de e-mail", + "phone": "Telefon", + "comment": "Comentariu", + "post_success": "Îți mulțumim că ne-ai contactat. Vom reveni cât mai curând posibil.", + "error_heading": "Ajustează următoarele:" + }, + "payment_methods": "Metode de plată" + }, + "accessibility": { + "play_model": "Redă modelul 3D", + "play_video": "Redă videoclipul", + "unit_price": "Preț unitar", + "country_results_count": "{{ count }} rezultate", + "slideshow_pause": "Întrerupe prezentarea de diapozitive", + "slideshow_play": "Redă prezentarea de diapozitive", + "remove_item": "Elimină {{ title}}", + "skip_to_text": "Salt la conținut", + "skip_to_product_info": "Salt la informațiile despre produs", + "skip_to_results_list": "Salt la lista de rezultate", + "new_window": "Se deschide într-o fereastră nouă.", + "slideshow_next": "Diapozitivul următor", + "slideshow_previous": "Diapozitivul anterior", + "close_dialog": "Închide dialogul", + "reset_search": "Resetează căutarea", + "search_results_count": "{{ count }} rezultate ale căutării găsite pentru „{{ query }}”", + "search_results_no_results": "Nu s-au găsit rezultate pentru „{{ query }}”", + "filters": "Filtre", + "filter_count": { + "one": "{{ count }} filtru aplicat", + "other": "{{ count }} filtre aplicate", + "few": "{{ count }} filtre aplicate" + }, + "account": "Deschide meniul Cont", + "cart": "Coș", + "cart_count": "Total articole în coș", + "menu": "Meniu", + "country_region": "Țară/regiune", + "slide_status": "Diapozitivul {{ index }} din {{ length }}", + "scroll_to": "Derulează la {{ title }}", + "loading_product_recommendations": "Se încarcă recomandările de produse", + "discount": "Aplică un cod de reducere", + "discount_applied": "Cod de reducere aplicat: {{ code }}", + "open_cart_drawer": "Deschide coșul", + "pause_video": "Pune pe pauză videoclipul", + "inventory_status": "Stare inventar", + "find_country": "Găsește țara", + "localization_region_and_language": "Deschide instrumentul de selectare a regiunii și limbii", + "open_search_modal": "Deschide fereastra de căutare", + "decrease_quantity": "Scade cantitatea", + "increase_quantity": "Crește cantitatea", + "quantity": "Cantitate", + "rating": "Evaluarea acestui produs este de {{ rating }} din 5", + "nested_product": "{{ product_title }} pentru {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Adaugă în coș", + "clear_all": "Golește tot", + "remove": "Elimină", + "view_in_your_space": "Vezi în spațiul tău", + "show_filters": "Filtrează", + "clear": "Golește", + "continue_shopping": "Continuă cumpărăturile", + "log_in_html": "Ai un cont? Conectează-te pentru a finaliza comanda mai rapid.", + "see_items": { + "one": "Vezi {{ count }} articol", + "other": "Vezi {{ count }} articole", + "few": "Vezi {{ count }} articole" + }, + "view_all": "Afișează tot", + "add": "Adaugă", + "choose": "Alege", + "added": "Adăugat", + "show_less": "Afișează mai puțin", + "show_more": "Afișează mai mult", + "close": "Închide", + "more": "Mai multe", + "zoom": "Zoom", + "close_dialog": "Închide dialogul", + "reset": "Resetează", + "remove_discount": "Elimină codul de reducere {{ code }}", + "enter_using_password": "Accesează folosind parola", + "submit": "Trimite", + "enter_password": "Introdu parola", + "view_store_information": "Vezi informațiile despre magazin", + "apply": "Aplică", + "back": "Înapoi", + "log_in": "Conectează-te", + "log_out": "Deconectează-te", + "open_image_in_full_screen": "Deschide imaginea în modul ecran complet", + "sign_in_options": "Alte opțiuni de conectare", + "sign_up": "Înscrie-te", + "sort": "Sortează", + "show_all_options": "Afișează toate opțiunile" + }, + "content": { + "reviews": "recenzii", + "language": "Limba", + "localization_region_and_language": "Regiunea și limba", + "no_results_found": "Nu s-a găsit niciun rezultat", + "cart_total": "Total coș de cumpărături", + "your_cart_is_empty": "Coșul tău de cumpărături este gol", + "product_image": "Imagine produs", + "product_information": "Informații despre produs", + "quantity": "Cantitate", + "product_total": "Total produs", + "cart_estimated_total": "Total estimat", + "seller_note": "Instrucțiuni speciale", + "cart_subtotal": "Subtotal", + "discounts": "Reduceri", + "discount": "Reducere", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Taxe și taxe vamale incluse. Reducerile și transportul sunt calculate la finalizarea comenzii.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Taxe și taxe vamale incluse. Reducerile și transportul sunt calculate la finalizarea comenzii.", + "taxes_included_shipping_at_checkout_with_policy_html": "Taxe incluse. Reducerile și transportul sunt calculate la finalizarea comenzii.", + "taxes_included_shipping_at_checkout_without_policy": "Taxe incluse. Reducerile și transportul sunt calculate la finalizarea comenzii.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Taxe vamale incluse. Taxele, reducerile și transportul sunt calculate la finalizarea comenzii.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Taxe vamale incluse. Taxele, reducerile și transportul sunt calculate la finalizarea comenzii.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Taxele, reducerile și transportul sunt calculate la finalizarea comenzii.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Taxele, reducerile și transportul sunt calculate la finalizarea comenzii.", + "checkout": "Finalizează comanda", + "cart_title": "Coș", + "price": "Preț", + "price_regular": "Preț obișnuit", + "price_compare_at": "Compararea prețurilor", + "price_sale": "Preț la ofertă", + "duties_and_taxes_included": "Taxele vamale și impozitele sunt incluse.", + "duties_included": "Taxe vamale incluse.", + "shipping_policy_html": "Taxele de expediere sunt calculate la finalizarea comenzii.", + "taxes_included": "Impozite incluse.", + "product_badge_sold_out": "Stoc epuizat", + "product_badge_sale": "Promoție", + "grid_view": { + "default_view": "Implicit", + "grid_fieldset": "Grilă de coloane", + "single_item": "Singur", + "zoom_out": "Micșorează" + }, + "search_input_label": "Caută", + "search_input_placeholder": "Caută", + "search_results": "Rezultatele căutării", + "search_results_label": "Rezultatele căutării", + "search_results_no_results": "Nu s-au găsit rezultate pentru „{{ terms }}”. Încearcă o altă căutare.", + "search_results_resource_articles": "Postări pe blog", + "search_results_resource_collections": "Colecții", + "search_results_resource_pages": "Pagini", + "search_results_resource_products": "Produse", + "search_results_resource_queries": "Caută sugestii", + "search_results_view_all": "Vezi tot", + "search_results_view_all_button": "Vezi tot", + "search_results_resource_products_count": { + "one": "{{ count }} produs", + "other": "{{ count }} produse", + "few": "{{ count }} produse" + }, + "unavailable": "Indisponibil", + "recently_viewed_products": "Vizualizate recent", + "collection_placeholder": "Titlul colecției", + "product_card_placeholder": "Titlul produsului", + "product_count": "Număr de produse", + "item_count": { + "one": "{{ count }} articol", + "other": "{{ count }} articole", + "few": "{{ count }} articole" + }, + "errors": "Erori", + "price_from": "Începând de la {{ price }}", + "search": "Caută", + "search_results_no_results_check_spelling": "Nu s-au găsit rezultate pentru „{{ terms }}”. Verifică ortografia sau folosește un alt cuvânt sau o altă expresie.", + "featured_products": "Produse recomandate", + "no_products_found": "Nu s-au găsit produse.", + "use_fewer_filters_html": "Încearcă să folosești mai puține filtre sau șterge toate filtrele.", + "blog_details_separator": "|", + "filters": "Filtre", + "price_filter_html": "Cel mai mare preț este {{ price }}", + "discount_code": "Cod de reducere", + "pickup_available_at_html": "Ridicare disponibilă la {{ location }}", + "pickup_available_in": "Ridicare disponibilă, {{ pickup_time }}", + "pickup_not_available": "Ridicarea nu este disponibilă momentan", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Citește mai mult...", + "wrong_password": "Parolă incorectă", + "account_title": "Cont", + "account_title_personalized": "Salut, {{ first_name }}", + "account_orders": "Comenzi", + "account_profile": "Profil", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Taxele și taxele vamale sunt incluse. Transportul este calculat la momentul efectuării plății.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Taxele și taxele vamale sunt incluse. Transportul este calculat la momentul efectuării plății.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Taxe vamale incluse. Transportul este calculat la momentul efectuării plății.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Taxe vamale incluse. Transportul este calculat la momentul efectuării plății.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Taxele și costul transportului sunt calculate la momentul efectuării plății.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Taxele și costul transportului sunt calculate la momentul efectuării plății.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Taxe incluse. Transportul este calculat la momentul efectuării plății.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Taxe incluse. Transportul este calculat la momentul efectuării plății.", + "view_more_details": "Vezi mai multe detalii", + "page_placeholder_title": "Titlul paginii", + "page_placeholder_content": "Selectează o pagină pentru a afișa conținutul acesteia.", + "placeholder_image": "Imagine substituent", + "powered_by": "Acest magazin va fi oferit de", + "store_owner_link_html": "Ești proprietarul magazinului? Conectează-te aici", + "shipping_discount_error": "Reducerile pentru transport sunt afișate pe pagina de efectuare a plății, după ce ai adăugat adresa", + "discount_code_error": "Codul de reducere nu poate fi aplicat coșului tău de cumpărături", + "inventory_low_stock": "Stoc redus", + "inventory_in_stock": "În stoc", + "inventory_out_of_stock": "Stoc epuizat", + "shipping_policy": "Transportul este calculat la momentul efectuării plății.", + "inventory_low_stock_show_count": { + "one": "{{ count }} rămas", + "other": "{{ count }} rămas", + "few": "{{ count }} rămas" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Folosește codul cardului cadou online sau codul QR în magazin", + "title": "Iată soldul aferent cardurilor cadou, în valoare de {{ value }}, pentru {{ shop }}!", + "subtext": "Cardul tău cadou", + "shop_link": "Vizitează magazinul online", + "add_to_apple_wallet": "Adaugă la Apple Wallet", + "qr_image_alt": "Cod QR – scanează pentru valorificarea cardului cadou", + "copy_code": "Copiază codul cardului cadou", + "expiration_date": "Expiră pe {{ expires_on }}", + "copy_code_success": "Codul a fost copiat cu succes", + "expired": "Expirat" + } + }, + "placeholders": { + "password": "Parolă", + "search": "Caută", + "product_title": "Titlul produsului", + "collection_title": "Titlul colecției" + }, + "products": { + "product": { + "add_to_cart": "Adaugă în coș", + "added_to_cart": "Adăugat în coș", + "adding_to_cart": "Se adaugă...", + "add_to_cart_error": "Eroare la adăugarea în coș", + "sold_out": "Stoc epuizat", + "unavailable": "Indisponibil" + } + }, + "fields": { + "separator": "la" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} comentariu", + "other": "{{ count }} comentarii", + "few": "{{ count }} comentarii" + } + }, + "comment_form": { + "email": "Adresă de e-mail", + "error": "Comentariul nu s-a putut publica, remediază următoarele probleme:", + "heading": "Lasă un comentariu", + "message": "Mesaj", + "moderated": "Nu uita: comentariile trebuie aprobate înainte de publicare.", + "name": "Nume", + "post": "Postează comentariul", + "success_moderated": "Comentariul a fost postat, se așteaptă moderarea", + "success": "Comentariu postat" + } + } +} diff --git a/locales/ru.json b/locales/ru.json new file mode 100644 index 000000000..9cdfffff9 --- /dev/null +++ b/locales/ru.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Загрузить видео: {{ description }}", + "sold_out": "Продано", + "email_signup": { + "label": "Электронный адрес", + "placeholder": "Адрес электронной почты", + "success": "Спасибо, что подписались!" + }, + "filter": "Фильтровать", + "payment_methods": "Способы оплаты", + "contact_form": { + "name": "Имя", + "email": "Электронный адрес", + "phone": "Телефон", + "comment": "Комментарий", + "post_success": "Спасибо за обращение. Мы свяжемся с вами как можно скорее.", + "error_heading": "Измените следующие элементы:" + } + }, + "accessibility": { + "play_model": "Открыть объемную модель", + "play_video": "Воспроизвести видео", + "unit_price": "Цена за единицу", + "country_results_count": "Результаты: {{ count }}", + "slideshow_pause": "Приостановить показ слайд-шоу", + "slideshow_play": "Воспроизвести слайд-шоу", + "remove_item": "Удалить «{{ title}}»", + "skip_to_text": "Перейти к контенту", + "skip_to_product_info": "Перейти к информации о продукте", + "skip_to_results_list": "Перейти к списку результатов", + "new_window": "Откроется в новом окне.", + "slideshow_next": "Следующий слайд", + "slideshow_previous": "Предыдущий слайд", + "close_dialog": "Закрыть диалоговое окно", + "reset_search": "Сбросить поиск", + "search_results_count": "Найдено {{ count }} результата(-ов) по запросу «{{ query }}»", + "search_results_no_results": "По запросу «{{ query }}» ничего не найдено", + "filters": "Фильтры", + "account": "Скрыть меню учетной записи", + "cart": "Корзина", + "cart_count": "Всего товаров в корзине", + "filter_count": { + "one": "Применен {{ count }} фильтр", + "other": "Применены {{ count }} фильтра(-ов)", + "few": "Применены {{ count }} фильтра(-ов)", + "many": "Применены {{ count }} фильтра(-ов)" + }, + "menu": "Меню", + "country_region": "Страна/регион", + "slide_status": "Слайд {{ index }} из {{ length }}", + "scroll_to": "Прокрутить до {{ title }}", + "loading_product_recommendations": "Загрузка рекомендаций товаров", + "discount": "Применить промокод", + "discount_applied": "Примененный промокод : {{ code }}", + "open_cart_drawer": "Открыть корзину", + "inventory_status": "Статус ассортимента", + "pause_video": "Приостановить видео", + "find_country": "Найти страну", + "localization_region_and_language": "Открыть выбор региона и языка", + "open_search_modal": "Открыть поиск", + "decrease_quantity": "Убрать позиции", + "increase_quantity": "Добавить позиции", + "quantity": "Количество", + "rating": "Рейтинг этого продукта {{ rating }} из 5", + "nested_product": "{{ product_title }} для товара \"{{ parent_title }}\"" + }, + "actions": { + "add_to_cart": "Добавить в корзину", + "clear_all": "Удалить все", + "remove": "Удалить", + "view_in_your_space": "Просматривайте в реальных условиях", + "show_filters": "Фильтровать", + "clear": "Очистить", + "continue_shopping": "Продолжить покупки", + "log_in_html": "Уже есть учетная запись? Войдите, чтобы быстро оформить заказ.", + "see_items": { + "one": "Смотреть {{ count }} товар", + "other": "Смотреть {{ count }} товара(-ов)", + "few": "Смотреть {{ count }} товара(-ов)", + "many": "Смотреть {{ count }} товара(-ов)" + }, + "view_all": "Посмотреть все", + "add": "Добавить", + "choose": "Выбрать", + "added": "Добавлено", + "show_less": "Показать меньше", + "show_more": "Показать больше", + "close": "Закрыть", + "more": "Еще", + "zoom": "Увеличить", + "close_dialog": "Закрыть диалоговое окно", + "reset": "Сбросить", + "enter_using_password": "Войти с помощью пароля", + "submit": "Отправить", + "enter_password": "Введите пароль", + "back": "Назад", + "log_in": "Войти в систему", + "log_out": "Выйти", + "remove_discount": "Удалить скидку {{ code }}", + "view_store_information": "Сведения о магазине", + "apply": "Применить", + "sign_in_options": "Другие способы входа", + "sign_up": "Регистрация", + "open_image_in_full_screen": "Открыть изображение во весь экран", + "sort": "Сортировать", + "show_all_options": "Показать все варианты" + }, + "content": { + "reviews": "отз.", + "no_results_found": "Результатов не найдено", + "language": "Язык", + "localization_region_and_language": "Регион и язык", + "cart_total": "Итого по корзине", + "your_cart_is_empty": "Корзина пуста", + "product_image": "Изображение товара", + "product_information": "Информация о товаре", + "quantity": "Количество", + "product_total": "Итого", + "cart_estimated_total": "Ориентировочная общая сумма", + "seller_note": "Особые примечания", + "cart_subtotal": "Промежуточный итог", + "discounts": "Скидки", + "discount": "Скидка", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Пошлины и налоги включены. Скидки и стоимость доставки рассчитываются при оформлении заказа.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Пошлины и налоги включены. Скидки и стоимость доставки рассчитываются при оформлении заказа.", + "taxes_included_shipping_at_checkout_with_policy_html": "Налоги включены. Скидки и стоимость доставки рассчитываются при оформлении заказа.", + "taxes_included_shipping_at_checkout_without_policy": "Налоги включены. Скидки и стоимость доставки рассчитываются при оформлении заказа.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Пошлины включены. Налоги, скидки и стоимость доставки рассчитываются при оформлении заказа.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Пошлины включены. Налоги, скидки и стоимость доставки рассчитываются при оформлении заказа.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Налоги, скидки и стоимость доставки рассчитываются при оформлении заказа.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Налоги, скидки и стоимость доставки рассчитываются при оформлении заказа.", + "checkout": "Оформить заказ", + "cart_title": "Корзина", + "price": "Цена", + "price_regular": "Обычная цена", + "price_compare_at": "Сравнить по цене", + "price_sale": "Цена со скидкой", + "duties_and_taxes_included": "Пошлины и налоги включены.", + "duties_included": "Пошлины включены.", + "shipping_policy_html": "Стоимость доставки рассчитывается при оформлении заказа.", + "taxes_included": "Налоги включены.", + "product_badge_sold_out": "Распродано", + "product_badge_sale": "Распродажа", + "search_input_label": "Поиск", + "search_input_placeholder": "Поиск", + "search_results": "Результаты поиска", + "search_results_label": "Результаты поиска", + "search_results_no_results": "По запросу «{{ terms }}» ничего не найдено. Попробуйте другой поисковый запрос.", + "search_results_resource_articles": "Статьи в блоге", + "search_results_resource_collections": "Коллекции", + "search_results_resource_pages": "Страницы", + "search_results_resource_products": "Товары", + "search_results_resource_queries": "Рекомендации по поиску", + "search_results_view_all": "Посмотреть все", + "search_results_view_all_button": "Посмотреть все", + "search_results_resource_products_count": { + "one": "{{ count }} товар", + "other": "Товаров: {{ count }}", + "few": "Товаров: {{ count }}", + "many": "Товаров: {{ count }}" + }, + "grid_view": { + "default_view": "По умолчанию", + "grid_fieldset": "Сетка столбцов", + "single_item": "Одиночный", + "zoom_out": "Уменьшить" + }, + "recently_viewed_products": "Недавно просмотренные", + "unavailable": "Недоступно", + "collection_placeholder": "Название коллекции", + "product_card_placeholder": "Название продукта", + "product_count": "Количество товаров", + "item_count": { + "one": "{{ count }} товар", + "other": "{{ count }} товаров", + "few": "{{ count }} товаров", + "many": "{{ count }} товаров" + }, + "errors": "Ошибки", + "price_from": "От {{ price }}", + "featured_products": "Рекомендуемые продукты", + "filters": "Фильтры", + "no_products_found": "Продукты не найдены.", + "price_filter_html": "Максимальная цена: {{ price }}", + "use_fewer_filters_html": "Попробуйте использовать меньше фильтров или сбросьте все фильтры.", + "search": "Поиск", + "search_results_no_results_check_spelling": "По запросу «{{ terms }}» ничего не найдено. Проверьте правописание или выберите другие слова либо фразу.", + "blog_details_separator": "|", + "read_more": "Подробнее...", + "wrong_password": "Неправильный пароль", + "account_title": "Учетная запись", + "account_title_personalized": "Здравствуйте, {{ first_name }}!", + "account_orders": "Заказы", + "account_profile": "Профиль", + "discount_code": "Промокод", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Пошлины и налоги включены. Стоимость доставки рассчитывается при оформлении заказа.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Пошлины и налоги включены. Стоимость доставки рассчитывается при оформлении заказа.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Пошлины включены. Стоимость доставки рассчитывается при оформлении заказа.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Пошлины включены. Стоимость доставки рассчитывается при оформлении заказа.", + "pickup_available_at_html": "Самовывоз доступен: {{ location }}", + "pickup_available_in": "Доступен самовывоз, {{ pickup_time }}", + "pickup_not_available": "В настоящее время самовывоз недоступен", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Налоги и стоимость доставки, рассчитанные при оформлении заказа.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Налоги и стоимость доставки, рассчитанные при оформлении заказа.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Налоги включены. Стоимость доставки рассчитывается при оформлении заказа.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Налоги включены. Стоимость доставки рассчитывается при оформлении заказа.", + "view_more_details": "Подробнее", + "inventory_low_stock": "Заканчивается", + "inventory_in_stock": "В наличии", + "inventory_out_of_stock": "Нет в наличии", + "page_placeholder_title": "Заголовок страницы", + "page_placeholder_content": "Выберите страницу для отображения ее содержимого.", + "placeholder_image": "Изображение-заполнитель", + "inventory_low_stock_show_count": { + "one": "Осталось: {{ count }}", + "other": "Осталось: {{ count }}", + "few": "Осталось: {{ count }}", + "many": "Осталось: {{ count }}" + }, + "powered_by": "Этот магазин работает на платформе", + "store_owner_link_html": "Вы владелец магазина? Войдите здесь", + "shipping_discount_error": "Скидки на доставку отображаются при оформлении и оплате заказа после добавления адреса", + "discount_code_error": "Код скидки не может быть применен к вашей корзине", + "shipping_policy": "Стоимость доставки рассчитывается при оформлении заказа." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Используйте код подарочной карты онлайн или отсканируйте QR-код в магазине", + "title": "Вот ваша подарочная карта с номиналом {{ value }} для магазина {{ shop }}!", + "subtext": "Ваша подарочная карта", + "shop_link": "Посетить онлайн-магазин", + "add_to_apple_wallet": "Добавить в Apple Wallet", + "qr_image_alt": "Отсканируйте QR-код, чтобы использовать подарочную карту", + "copy_code": "Скопировать код подарочной карты", + "expiration_date": "Срок действия истекает {{ expires_on }}", + "copy_code_success": "Код скопирован", + "expired": "Срок действия истек" + } + }, + "placeholders": { + "password": "Пароль", + "search": "Поиск", + "product_title": "Название продукта", + "collection_title": "Название коллекции" + }, + "products": { + "product": { + "add_to_cart": "Добавить в корзину", + "added_to_cart": "Товар добавлен в корзину", + "adding_to_cart": "Добавление...", + "add_to_cart_error": "Возникла ошибка при добавлении в корзину", + "sold_out": "Продано", + "unavailable": "Недоступно" + } + }, + "fields": { + "separator": "–" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "Комментариев: {{ count }}", + "other": "Комментариев: {{ count }}", + "few": "Комментариев: {{ count }}", + "many": "Комментариев: {{ count }}" + } + }, + "comment_form": { + "email": "Электронный адрес", + "error": "Не удалось опубликовать комментарий, исправьте следующее:", + "heading": "Комментировать", + "message": "Сообщение", + "moderated": "Обратите внимание, что комментарии проходят проверку перед публикацией.", + "name": "Имя", + "post": "Добавить комментарий", + "success_moderated": "Комментарий отправлен на модерацию", + "success": "Комментарий опубликован" + } + } +} diff --git a/locales/sk.json b/locales/sk.json new file mode 100644 index 000000000..92acddb76 --- /dev/null +++ b/locales/sk.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Načítať video: {{ description }}", + "sold_out": "Vypredané", + "email_signup": { + "label": "E-mail", + "placeholder": "E-mailová adresa", + "success": "Ďakujeme, že ste sa prihlásili na odber správ." + }, + "filter": "Filtrovať", + "payment_methods": "Spôsoby platby", + "contact_form": { + "name": "Meno", + "email": "E-mail", + "phone": "Telefón", + "comment": "Komentár", + "post_success": "Ďakujeme, že ste nás kontaktovali. Budeme sa vám venovať čo najskôr.", + "error_heading": "Upravte tieto údaje:" + } + }, + "accessibility": { + "play_model": "Prehrať 3D model", + "play_video": "Prehrať video", + "unit_price": "Jednotková cena", + "country_results_count": "Počet výsledkov: {{ count }}", + "slideshow_pause": "Pozastaviť prezentáciu", + "slideshow_play": "Prehrať prezentáciu", + "remove_item": "Odstrániť štítok {{ title}}", + "skip_to_text": "Prejsť na obsah", + "skip_to_product_info": "Prejsť na informácie o produkte", + "skip_to_results_list": "Prejsť na zoznam výsledkov", + "new_window": "Otvorí sa v novom okne.", + "slideshow_next": "Nasledujúca snímka", + "slideshow_previous": "Predchádzajúca snímka", + "close_dialog": "Zavrieť dialógové okno", + "reset_search": "Resetovať vyhľadávanie", + "search_results_count": "{{ count }} nájdené výsledky vyhľadávania pre „{{ query }}“", + "search_results_no_results": "Pre výraz „{{ query }}“ sa nenašli žiadne výsledky", + "filters": "Filtre", + "filter_count": { + "one": "{{ count }} použitý filter", + "other": "Použité filtre: {{ count }}", + "few": "Použité filtre: {{ count }}", + "many": "Použité filtre: {{ count }}" + }, + "account": "Otvoriť ponuku konta", + "cart": "Košík", + "cart_count": "Celkový počet položiek v košíku", + "menu": "Ponuka", + "country_region": "Krajina/oblasť", + "slide_status": "Snímka {{ index }} z {{ length }}", + "scroll_to": "Posunúť sa na {{ title }}", + "loading_product_recommendations": "Načítavajú sa odporúčané produkty", + "discount": "Použiť zľavový kód", + "discount_applied": "Použitý zľavový kód: {{ code }}", + "open_cart_drawer": "Otvoriť košík", + "inventory_status": "Stav zásob", + "pause_video": "Pozastaviť video", + "find_country": "Nájsť krajinu", + "localization_region_and_language": "Otvoriť výber oblasti a jazyka", + "open_search_modal": "Otvoriť vyhľadávanie", + "decrease_quantity": "Znížiť množstvo", + "increase_quantity": "Zvýšiť množstvo", + "rating": "Hodnotenie tohto produktu je {{ rating }} z 5", + "quantity": "Množstvo", + "nested_product": "{{ product_title }} pre {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Pridať do košíka", + "clear_all": "Vymazať všetko", + "remove": "Odstrániť", + "view_in_your_space": "Zobraziť vo vašom priestore", + "show_filters": "Filtrovať", + "clear": "Vymazať", + "continue_shopping": "Pokračovať v nákupe", + "log_in_html": "Máte konto? Prihláste sa a prejdite pokladňou rýchlejšie.", + "see_items": { + "one": "Zobraziť {{ count }} položku", + "other": "Zobraziť {{ count }} položky/položiek", + "few": "Zobraziť {{ count }} položky/položiek", + "many": "Zobraziť {{ count }} položky/položiek" + }, + "view_all": "Zobraziť všetko", + "add": "Pridať", + "choose": "Vybrať", + "added": "Pridané", + "show_less": "Zobraziť menej", + "show_more": "Zobraziť viac", + "close": "Zavrieť", + "more": "Viac", + "zoom": "Priblíženie", + "close_dialog": "Zavrieť dialógové okno", + "reset": "Resetovať", + "enter_using_password": "Zadajte s použitím hesla", + "submit": "Odoslať", + "enter_password": "Zadajte heslo", + "remove_discount": "Odobrať zľavový {{ code }}", + "view_store_information": "Zobraziť informácie o obchode", + "back": "Späť", + "log_in": "Prihlásiť sa", + "log_out": "Odhlásiť sa", + "apply": "Použiť", + "sign_in_options": "Ďalšie možnosti prihlásenia", + "sign_up": "Zaregistrovať sa", + "open_image_in_full_screen": "Otvoriť obrázok na celú obrazovku", + "sort": "Zoradiť", + "show_all_options": "Zobraziť všetky možnosti" + }, + "content": { + "reviews": "recenz.", + "no_results_found": "Nenašli sa žiadne výsledky", + "language": "Jazyk", + "localization_region_and_language": "Oblasť a jazyk", + "cart_total": "Celková suma v košíku", + "your_cart_is_empty": "Váš košík je prázdny", + "product_image": "Obrázok produktu", + "product_information": "Informácie o produkte", + "quantity": "Množstvo", + "product_total": "Celková suma za tento produkt", + "cart_estimated_total": "Odhadovaná celková suma", + "seller_note": "Špeciálne pokyny", + "cart_subtotal": "Medzisúčet", + "discounts": "Zľavy", + "discount": "Zľava", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Vrátane ciel a daní. Zľavy a doprava sa vypočítajú pri platbe.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Vrátane ciel a daní. Zľavy a doprava sa vypočítajú pri platbe.", + "taxes_included_shipping_at_checkout_with_policy_html": "Vrátane daní. Zľavy a doprava sa vypočítajú pri platbe.", + "taxes_included_shipping_at_checkout_without_policy": "Vrátane daní. Zľavy a doprava sa vypočítajú pri platbe.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Vrátane ciel. Dane, zľavy a doprava sa vypočítajú pri platbe.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Vrátane ciel. Dane, zľavy a doprava sa vypočítajú pri platbe.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Dane, zľavy a doprava sa vypočítajú pri platbe.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Dane, zľavy a doprava sa vypočítajú pri platbe.", + "cart_title": "Košík", + "price": "Cena", + "price_regular": "Normálna cena", + "price_compare_at": "Porovnať podľa ceny", + "price_sale": "Cena po zľave", + "checkout": "Platba", + "duties_and_taxes_included": "Vrátane ciel a daní.", + "duties_included": "Vrátane ciel.", + "shipping_policy_html": "Doprava sa vypočíta v pokladni.", + "taxes_included": "Vrátane daní.", + "product_badge_sold_out": "Vypredané", + "product_badge_sale": "Zľava", + "search_input_label": "Vyhľadať", + "search_input_placeholder": "Vyhľadať", + "search_results": "Výsledky vyhľadávania", + "search_results_label": "Výsledky vyhľadávania", + "search_results_no_results": "Pre „{{ terms }}“ sa nenašli žiadne výsledky. Vyskúšať iné hľadanie.", + "search_results_resource_articles": "Blogový príspevok", + "search_results_resource_collections": "Kolekcie", + "search_results_resource_pages": "Stránky", + "search_results_resource_products": "Produkty", + "search_results_resource_queries": "Návrhy na vyhľadávanie", + "search_results_view_all": "Zobraziť všetko", + "search_results_view_all_button": "Zobraziť všetko", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} produkty", + "few": "{{ count }} produkty", + "many": "{{ count }} produkty" + }, + "grid_view": { + "default_view": "Predvolený", + "grid_fieldset": "Stĺpcová mriežka", + "single_item": "Jeden", + "zoom_out": "Oddialiť" + }, + "recently_viewed_products": "Nedávno zobrazené", + "unavailable": "Nedostupné", + "collection_placeholder": "Názov kolekcie", + "product_card_placeholder": "Názov produktu", + "product_count": "Počet produktov", + "item_count": { + "one": "{{ count }} položka", + "other": "Položky: {{ count }}", + "few": "Položky: {{ count }}", + "many": "Položky: {{ count }}" + }, + "errors": "Chyby", + "price_from": "Od {{ price }}", + "search": "Hľadať", + "search_results_no_results_check_spelling": "Pre výraz „{{ terms }}“ sa nenašli žiadne výsledky. Skontrolujte pravopis alebo použite iné slovo či slovné spojenie.", + "featured_products": "Odporúčané produkty", + "no_products_found": "Nenašli sa žiadne produkty.", + "use_fewer_filters_html": "Skúste použiť menej filtrov alebo vymazať všetky filtre.", + "filters": "Filtre", + "price_filter_html": "Najvyššia cena je {{ price }}", + "blog_details_separator": "|", + "read_more": "Prečítať si viac...", + "wrong_password": "Heslo je nesprávne", + "discount_code": "Zľavový kód", + "pickup_available_at_html": "K dispozícii na vyzdvihnutie na adrese {{ location }}", + "pickup_available_in": "K dispozícii na vyzdvihnutie o {{ pickup_time }}", + "pickup_not_available": "Aktuálne nedostupné na vyzdvihnutie", + "pickup_ready_in": "{{ pickup_time }}", + "account_title": "Konto", + "account_title_personalized": "Dobrý deň, {{ first_name }},", + "account_orders": "Objednávky", + "account_profile": "Profil", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Vrátane ciel a daní. Doprava sa vypočíta pri platbe.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Vrátane ciel a daní. Doprava sa vypočíta pri platbe.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Vrátane ciel. Doprava sa vypočíta pri platbe.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Vrátane ciel. Doprava sa vypočíta pri platbe.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Dane a doprava sa vypočítajú pri platbe.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Dane a doprava sa vypočítajú pri platbe.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Vrátane daní. Doprava sa vypočíta pri platbe.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Vrátane daní. Doprava sa vypočíta pri platbe.", + "view_more_details": "Zobraziť viac podrobností", + "inventory_low_stock": "Nízky stav zásob", + "inventory_in_stock": "Skladom", + "inventory_out_of_stock": "Vypredané", + "inventory_low_stock_show_count": { + "one": "Zostáva {{ count }}", + "other": "Zostáva {{ count }}", + "few": "Zostáva {{ count }}", + "many": "Zostáva {{ count }}" + }, + "powered_by": "Tento obchod bude prevádzkovať", + "store_owner_link_html": "Ste vlastníkom obchodu? Prihláste sa tu", + "shipping_discount_error": "Zľavy na dopravu sa zobrazia pri platbe po pridaní adresy", + "discount_code_error": "Zľavový kód nie je vo vašom košíku možné použiť", + "page_placeholder_title": "Názov stránky", + "page_placeholder_content": "Výberom stránky zobrazíte jej obsah.", + "placeholder_image": "Obrázok zástupného objektu", + "shipping_policy": "Doprava sa vypočíta v pokladni." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Použite online kód darčekového poukazu alebo QR kód v obchode", + "title": "Váš darčekový poukaz v hodnote {{ value }} do obchodu {{ shop }}!", + "subtext": "Váš darčekový poukaz", + "shop_link": "Navštíviť online obchod", + "add_to_apple_wallet": "Pridať do aplikácie Apple Wallet", + "qr_image_alt": "QR kód – naskenujte ho a uplatnite si darčekový poukaz", + "copy_code": "Kopírovať kód darčekového poukazu", + "expiration_date": "Platnosť skončí {{ expires_on }}", + "copy_code_success": "Kód sa úspešne skopíroval", + "expired": "Platnosť uplynula" + } + }, + "placeholders": { + "password": "Heslo", + "search": "Vyhľadať", + "product_title": "Názov produktu", + "collection_title": "Názov kolekcie" + }, + "products": { + "product": { + "add_to_cart": "Pridať do košíka", + "added_to_cart": "Pridané do košíka", + "adding_to_cart": "Pridávanie...", + "add_to_cart_error": "Chyba pri pridávaní do košíka", + "sold_out": "Vypredané", + "unavailable": "Nedostupné" + } + }, + "fields": { + "separator": "k" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentár", + "other": "{{ count }} komentárov", + "few": "{{ count }} komentárov", + "many": "{{ count }} komentárov" + } + }, + "comment_form": { + "email": "E-mail", + "error": "Komentár sa nepodarilo uverejniť, opravte nasledujúce chyby:", + "heading": "Pridať komentár", + "message": "Správa", + "moderated": "Upozorňujeme, že komentáre musia byť pred publikovaním schválené.", + "name": "Meno", + "post": "Uverejniť komentár", + "success_moderated": "Komentár zverejnený, čaká na schválenie", + "success": "Komentár zverejnený" + } + } +} diff --git a/locales/sl.json b/locales/sl.json new file mode 100644 index 000000000..873725439 --- /dev/null +++ b/locales/sl.json @@ -0,0 +1,283 @@ +{ + "blocks": { + "load_video": "Naloži videoposnetek: {{ description }}", + "sold_out": "Razprodano", + "email_signup": { + "label": "E-pošta", + "placeholder": "E-poštni naslov", + "success": "Hvala za prijavo!" + }, + "filter": "Filter", + "payment_methods": "Načini plačila", + "contact_form": { + "name": "Ime", + "email": "E-poštni naslov", + "phone": "Telefonska številka", + "comment": "Komentar", + "post_success": "Hvala za vaše sporočilo. Z vami bomo v stiku takoj, ko bo mogoče.", + "error_heading": "Prilagodite naslednje:" + } + }, + "accessibility": { + "play_model": "Predvajaj 3D-model", + "play_video": "Predvajaj videoposnetek", + "unit_price": "Cena na enoto", + "country_results_count": "Št. rezultatov: {{ count }}", + "slideshow_pause": "Zaustavi diaprojekcijo", + "slideshow_play": "Predvajaj diaprojekcijo", + "remove_item": "Odstrani: {{ title}}", + "skip_to_text": "Preskoči na vsebino", + "skip_to_product_info": "Preskoči na informacije o izdelku", + "skip_to_results_list": "Preskoči na seznam rezultatov", + "new_window": "Odpre se v novem oknu.", + "slideshow_next": "Naslednji diapozitiv", + "slideshow_previous": "Prejšnji diapozitiv", + "close_dialog": "Zapri pogovorno okno", + "reset_search": "Ponastavi iskanje", + "search_results_count": "Št. najdenih rezultatov za poizvedbo »{{ query }}«: {{ count }}", + "search_results_no_results": "Za »{{ query }}« ni bilo mogoče najti nobenega rezultata", + "filters": "Filtri", + "filter_count": { + "one": "{{ count }} filter je uporabljen", + "other": "Št. uporabljenih filtrov: {{ count }}", + "few": "Št. uporabljenih filtrov: {{ count }}", + "two": "Št. uporabljenih filtrov: {{ count }}" + }, + "account": "Odpri meni za račun", + "cart": "Košarica", + "cart_count": "Skupno število izdelkov v košarici", + "menu": "Meni", + "country_region": "Država/regija", + "slide_status": "Diapozitiv {{ index }} od {{ length }}", + "scroll_to": "Pomaknite se na {{ title }}", + "loading_product_recommendations": "Nalaganje priporočil za izdelke", + "discount": "Uporabi kodo za popust", + "discount_applied": "Uporabljena koda za popust: {{ code }}", + "open_cart_drawer": "Odpri košarico", + "inventory_status": "Status zaloge", + "pause_video": "Zaustavi videoposnetek", + "find_country": "Poišči državo", + "localization_region_and_language": "Odpri izbirnik za regijo in jezik", + "open_search_modal": "Odpri iskanje", + "decrease_quantity": "Zmanjšaj količino", + "increase_quantity": "Povečaj količino", + "quantity": "Količina", + "rating": "Ocena tega izdelka je {{ rating }} od 5", + "nested_product": "{{ product_title }} za {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Dodaj v košarico", + "clear_all": "Počisti vse", + "remove": "Odstrani", + "view_in_your_space": "Prikaži v prostoru", + "show_filters": "Filter", + "clear": "Počisti", + "continue_shopping": "Nadaljuj nakup", + "log_in_html": "Imate račun? Za hitrejši zaključek nakupa se prijavite.", + "see_items": { + "one": "Prikaži {{ count }} artikel", + "other": "Prikaži {{ count }} artiklov", + "few": "Prikaži {{ count }} artiklov", + "two": "Prikaži {{ count }} artiklov" + }, + "view_all": "Prikaži vse", + "add": "Dodaj", + "choose": "Izberi", + "added": "Dodano", + "show_less": "Prikaži manj", + "show_more": "Prikaži več", + "close": "Zapri", + "more": "Več", + "zoom": "Povečava", + "close_dialog": "Zapri pogovorno okno", + "reset": "Ponastavi", + "back": "Nazaj", + "log_in": "Vpis", + "log_out": "Odjava", + "remove_discount": "Odstrani popust {{ code }}", + "enter_using_password": "Vstop z geslom", + "submit": "Pošlji", + "enter_password": "Vnesite geslo", + "view_store_information": "Prikaži podatke o trgovini", + "apply": "Uporabi", + "sign_in_options": "Druge možnosti za vpis", + "sign_up": "Prijava", + "open_image_in_full_screen": "Odpri sliko v celozaslonskem načinu", + "sort": "Razvrsti", + "show_all_options": "Prikaži vse možnosti" + }, + "content": { + "reviews": "ocen.", + "no_results_found": "Nobenega rezultata ni bilo mogoče najti", + "language": "Jezik", + "localization_region_and_language": "Regija in jezik", + "cart_total": "Skupni znesek košarice", + "your_cart_is_empty": "Vaša košarica je prazna", + "product_image": "Slika izdelka", + "product_information": "Informacije o izdelku", + "quantity": "Količina", + "product_total": "Skupno za izdelek", + "cart_estimated_total": "Predvideni skupni znesek", + "seller_note": "Posebna navodila", + "cart_subtotal": "Vmesna vsota", + "discounts": "Popusti", + "discount": "Popust", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Dajatve in davki so vključeni. Popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Dajatve in davki so vključeni. Popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "taxes_included_shipping_at_checkout_with_policy_html": "Davki so vključeni. Popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "taxes_included_shipping_at_checkout_without_policy": "Davki so vključeni. Popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Dajatve so vključene. Davki, popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Dajatve so vključene. Davki, popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Davki, popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Davki, popusti in strošek dostave se obračunajo ob zaključku nakupa.", + "checkout": "Zaključi nakup", + "cart_title": "Košarica", + "price": "Cena", + "price_regular": "Redna cena", + "price_compare_at": "Primerjava cene", + "price_sale": "Znižana cena", + "duties_and_taxes_included": "Dajatve in davki vključeni.", + "duties_included": "Dajatve vključene.", + "shipping_policy_html": "Dostava se obračuna ob zaključku nakupa.", + "taxes_included": "Davki vključeni.", + "product_badge_sold_out": "Razprodano", + "product_badge_sale": "Znižanje", + "search_input_label": "Išči", + "search_input_placeholder": "Išči", + "search_results": "Rezultati iskanja", + "search_results_label": "Rezultati iskanja", + "search_results_no_results": "Za »{{ terms }}« ni bilo mogoče najti nobenega rezultata. Poskusite z novim iskanjem.", + "search_results_resource_articles": "Objave v spletnem dnevniku", + "search_results_resource_collections": "Zbirke", + "search_results_resource_pages": "Strani", + "search_results_resource_products": "Izdelki", + "search_results_resource_queries": "Predlogi za iskanje", + "search_results_view_all": "Prikaži vse", + "search_results_view_all_button": "Prikaži vse", + "search_results_resource_products_count": { + "one": "{{ count }} izdelek", + "other": "Št. izdelkov: {{ count }}", + "few": "Št. izdelkov: {{ count }}", + "two": "Št. izdelkov: {{ count }}" + }, + "grid_view": { + "default_view": "Privzeto", + "grid_fieldset": "Mreža v stolpcih", + "single_item": "Enojno", + "zoom_out": "Pomanjšaj" + }, + "recently_viewed_products": "Nedavno ogledano", + "unavailable": "Ni na voljo", + "collection_placeholder": "Naslov zbirke", + "product_card_placeholder": "Naslov izdelka", + "product_count": "Število izdelkov", + "item_count": { + "one": "{{ count }} artikel", + "other": "Št. artiklov: {{ count }}", + "few": "Št. artiklov: {{ count }}", + "two": "Št. artiklov: {{ count }}" + }, + "errors": "Napake", + "price_from": "Od {{ price }}", + "featured_products": "Izpostavljeni izdelki", + "search": "Išči", + "search_results_no_results_check_spelling": "Za »{{ terms }}« ni bilo mogoče najti nobenega rezultata. Preverite črkovanje ali uporabite drugo besedo ali frazo.", + "filters": "Filtri", + "no_products_found": "Nobenega izdelka ni bilo mogoče najti.", + "price_filter_html": "Najvišja cena je {{ price }}", + "use_fewer_filters_html": "Poskusite uporabiti manj filtrov ali počistite vse filtre.", + "blog_details_separator": "|", + "read_more": "Več o tem", + "account_title": "Račun", + "account_title_personalized": "Pozdravljeni, {{ first_name }}", + "account_orders": "Naročila", + "account_profile": "Profil", + "discount_code": "Koda za popust", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Dajatve in davki so vključeni. Dostava se obračuna ob zaključku nakupa.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Dajatve in davki so vključeni. Dostava se obračuna ob zaključku nakupa.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Dajatve so vključene. Dostava se obračuna ob zaključku nakupa.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Dajatve so vključene. Dostava se obračuna ob zaključku nakupa.", + "pickup_available_at_html": "Prevzem je mogoč na prevzemnem mestu {{ location }}", + "pickup_available_in": "Prevzem je mogoč, {{ pickup_time }}", + "pickup_not_available": "Prevzem trenutno ni mogoč", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Davki in dostava se obračunajo ob zaključku nakupa.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Davki in dostava se obračunajo ob zaključku nakupa.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Davki so vključeni. Dostava se obračuna ob zaključku nakupa.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Davki so vključeni. Dostava se obračuna ob zaključku nakupa.", + "wrong_password": "Geslo ni pravilno", + "view_more_details": "Prikaži več podrobnosti", + "inventory_low_stock": "Majhna zaloga", + "inventory_in_stock": "Na zalogi", + "inventory_out_of_stock": "Ni na zalogi", + "page_placeholder_title": "Naslov strani", + "page_placeholder_content": "Izberite stran za prikaz njene vsebine.", + "placeholder_image": "Začasna slika", + "inventory_low_stock_show_count": { + "one": "Preostalo: {{ count }}", + "other": "Preostalo: {{ count }}", + "few": "Preostalo: {{ count }}", + "two": "Preostalo: {{ count }}" + }, + "discount_code_error": "Kode popusta ni mogoče uporabiti za vašo košarico", + "shipping_policy": "Dostava se obračuna ob zaključku nakupa.", + "powered_by": "To trgovino bo omogočala platforma", + "store_owner_link_html": "Ali ste lastnik te trgovine? Prijavite se tukaj", + "shipping_discount_error": "Popusti za dostavo so prikazani ob zaključku nakupa po dodajanju naslova" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Uporabite kodo darilnega bona v spletu ali kodo QR v trgovini", + "title": "To je darilni bon v vrednosti {{ value }} za trgovino {{ shop }}!", + "subtext": "Vaš darilni bon", + "shop_link": "Obišči spletno trgovino", + "add_to_apple_wallet": "Dodaj v Apple Wallet", + "qr_image_alt": "Koda QR – optično jo preberite za unovčenje darilnega bona", + "copy_code": "Kopiraj kodo darilnega bona", + "expiration_date": "Poteče {{ expires_on }}", + "copy_code_success": "Koda je uspešno kopirana", + "expired": "Poteklo" + } + }, + "placeholders": { + "password": "Geslo", + "search": "Išči", + "product_title": "Naslov izdelka", + "collection_title": "Naslov zbirke" + }, + "products": { + "product": { + "add_to_cart": "Dodaj v košarico", + "added_to_cart": "Dodano v košarico", + "adding_to_cart": "Dodajanje ...", + "add_to_cart_error": "Pri dodajanju v košarico je prišlo do napake", + "sold_out": "Razprodano", + "unavailable": "Ni na voljo" + } + }, + "fields": { + "separator": "do" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} komentar", + "other": "Št. komentarjev: {{ count }}", + "few": "Št. komentarjev: {{ count }}", + "two": "Št. komentarjev: {{ count }}" + } + }, + "comment_form": { + "email": "E-poštni naslov", + "error": "Objava komentarja ni uspela, preverite naslednje:", + "heading": "Napišite komentar", + "message": "Sporočilo", + "moderated": "Upoštevajte, da morajo biti komentarji pred objavo odobreni.", + "name": "Ime", + "post": "Objavi komentar", + "success_moderated": "Komentar je bil objavljen, čakanje na odobritev", + "success": "Komentar je bil objavljen" + } + } +} diff --git a/locales/sv.json b/locales/sv.json new file mode 100644 index 000000000..a0a39635a --- /dev/null +++ b/locales/sv.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Ladda video: {{ description }}", + "sold_out": "Slutsåld", + "email_signup": { + "label": "E-post", + "placeholder": "E-postadress", + "success": "Tack för att du prenumererar!" + }, + "filter": "Filter", + "payment_methods": "Betalningsmetoder", + "contact_form": { + "name": "Namn", + "email": "E-post", + "phone": "Telefon", + "comment": "Kommentar", + "post_success": "Tack för att du kontaktar oss. Vi återkommer till dig så snart som möjligt.", + "error_heading": "Justera följande:" + } + }, + "accessibility": { + "play_model": "Spela 3D-modell", + "play_video": "Spela video", + "unit_price": "Enhetspris", + "country_results_count": "{{ count }} resultat", + "slideshow_pause": "Pausa bildspelet", + "slideshow_play": "Spela bildspel", + "remove_item": "Ta bort {{ title}}", + "skip_to_text": "Gå vidare till innehåll", + "skip_to_product_info": "Hoppa till produktinformation", + "skip_to_results_list": "Gå vidare till resultatlista", + "new_window": "Öppnas i ett nytt fönster.", + "slideshow_next": "Nästa bild", + "slideshow_previous": "Föregående bild", + "close_dialog": "Stäng dialogruta", + "reset_search": "Återställ sökning", + "search_results_count": "{{ count }} sökresultat hittades för ”{{ query }}”", + "search_results_no_results": "Inga resultat hittades för ”{{ query }}”", + "filters": "Filter", + "filter_count": { + "one": "{{ count }} filter tillämpas", + "other": "{{ count }} filter tillämpas" + }, + "account": "Öppna kontomeny", + "cart": "Varukorg", + "cart_count": "Totalt antal artiklar i varukorgen", + "menu": "Meny", + "country_region": "Land/region", + "slide_status": "Bild {{ index }} av {{ length }}", + "scroll_to": "Rulla till {{ title }}", + "loading_product_recommendations": "Läser in produktrekommendationer", + "discount": "Använd rabattkod", + "discount_applied": "Tillämpad rabattkod: {{ code }}", + "open_cart_drawer": "Öppna varukorg", + "pause_video": "Pausa video", + "inventory_status": "Lagerstatus", + "find_country": "Hitta land", + "localization_region_and_language": "Öppna region- och språkväljare", + "open_search_modal": "Öppna sök", + "decrease_quantity": "Minska kvantitet", + "increase_quantity": "Öka kvantitet", + "quantity": "Kvantitet", + "rating": "Betyget för den här produkten är {{ rating }} av 5", + "nested_product": "{{ product_title }} för {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Lägg till i varukorgen", + "clear_all": "Rensa alla", + "remove": "Ta bort", + "view_in_your_space": "Visa i ditt utrymme", + "show_filters": "Filter", + "clear": "Rensa", + "continue_shopping": "Fortsätt handla", + "log_in_html": "Har du ett konto? Logga in för att betala snabbare.", + "see_items": { + "one": "Se {{ count }} artikel", + "other": "Se {{ count }} artiklar" + }, + "view_all": "Visa alla", + "add": "Lägg till", + "choose": "Välj", + "added": "Tillagd", + "show_less": "Visa färre", + "show_more": "Visa fler", + "close": "Stäng", + "more": "Mer", + "reset": "Återställ", + "zoom": "Zoom", + "close_dialog": "Stäng dialogruta", + "submit": "Skicka", + "remove_discount": "Ta bort rabatt {{ code }}", + "enter_using_password": "Ange lösenord för att komma in", + "enter_password": "Ange lösenord", + "view_store_information": "Visa butiksinformation", + "back": "Backa", + "log_in": "Logga in", + "log_out": "Logga ut", + "apply": "Tillämpa", + "open_image_in_full_screen": "Öppna bilden i helskärm", + "sign_in_options": "Andra inloggningsalternativ", + "sign_up": "Registrera dig", + "sort": "Sortera", + "show_all_options": "Visa alla alternativ" + }, + "content": { + "reviews": "recensioner", + "language": "Språk", + "localization_region_and_language": "Region och språk", + "no_results_found": "Inga resultat hittades", + "cart_total": "Summa varukorg", + "your_cart_is_empty": "Din varukorg är tom", + "product_image": "Produktbild", + "product_information": "Produktinformation", + "quantity": "Kvantitet", + "product_total": "Produkter totalt", + "cart_estimated_total": "Beräknad totalsumma", + "seller_note": "Särskilda instruktioner", + "cart_subtotal": "Delsumma", + "discounts": "Rabatter", + "discount": "Rabatt", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Tullavgifter och skatter ingår. Rabatter och fraktkostnad beräknas i kassan.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Tullavgifter och skatter ingår. Rabatter och fraktkostnad beräknas i kassan.", + "taxes_included_shipping_at_checkout_with_policy_html": "Skatter ingår. Rabatter och fraktkostnad beräknas i kassan.", + "taxes_included_shipping_at_checkout_without_policy": "Skatter ingår. Rabatter och fraktkostnad beräknas i kassan.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Tullavgifter ingår. Skatter, rabatter och fraktkostnad beräknas i kassan.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Tullavgifter ingår. Skatter, rabatter och fraktkostnad beräknas i kassan.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Skatter, rabatter och fraktkostnad beräknas i kassan.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Skatter, rabatter och fraktkostnad beräknas i kassan.", + "checkout": "Betala", + "cart_title": "Varukorg", + "price": "Pris", + "price_regular": "Ordinarie pris", + "price_compare_at": "Jämförpris", + "price_sale": "Reapris", + "duties_and_taxes_included": "Tullavgifter och skatter ingår.", + "duties_included": "Tullavgifter ingår.", + "shipping_policy_html": "Frakt beräknas i kassan.", + "taxes_included": "Skatter ingår.", + "product_badge_sold_out": "Slutsåld", + "product_badge_sale": "Rea", + "search_input_label": "Sökning", + "search_input_placeholder": "Sök", + "search_results": "Sökresultat", + "search_results_label": "Sökresultat", + "search_results_no_results": "Inga resultat hittades för ”{{ terms }}”. Försök med en annan sökning.", + "search_results_resource_articles": "Bloggposter", + "search_results_resource_collections": "Produktserier", + "search_results_resource_pages": "Sidor", + "search_results_resource_products": "Produkter", + "search_results_resource_queries": "Sökförslag", + "search_results_view_all": "Visa alla", + "search_results_view_all_button": "Visa alla", + "search_results_resource_products_count": { + "one": "{{ count }} produkt", + "other": "{{ count }} produkter" + }, + "grid_view": { + "default_view": "Standard", + "grid_fieldset": "Kolumnrutnät", + "single_item": "Enkel", + "zoom_out": "Zooma ut" + }, + "unavailable": "Inte tillgängligt", + "collection_placeholder": "Produktseriens namn", + "product_card_placeholder": "Produktnamn", + "recently_viewed_products": "Nyligen visade", + "product_count": "Produktantal", + "item_count": { + "one": "{{ count }} artikel", + "other": "{{ count }} artiklar" + }, + "errors": "Fel", + "price_from": "Från {{ price }}", + "search": "Sökning", + "search_results_no_results_check_spelling": "Inga resultat hittades för \"{{ terms }}\". Kontrollera stavningen eller använd ett annat ord eller fras.", + "featured_products": "Utvalda produkter", + "filters": "Filter", + "no_products_found": "Inga produkter hittades", + "price_filter_html": "Det högsta priset är {{ price }}", + "use_fewer_filters_html": "Prova att använda färre filter eller rensa alla filter.", + "blog_details_separator": "|", + "read_more": "Läs mer ...", + "discount_code": "Rabattkod", + "pickup_available_at_html": "Hämtning tillgänglig på {{ location }}", + "pickup_available_in": "Hämtning tillgänglig, {{ pickup_time }}", + "pickup_not_available": "Hämtning är inte tillgänglig just nu", + "pickup_ready_in": "{{ pickup_time }}", + "wrong_password": "Fel lösenord", + "account_title": "Konto", + "account_title_personalized": "Hej {{ first_name }}!", + "account_orders": "Ordrar", + "account_profile": "Profil", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Tullavgifter och skatter ingår. Frakt beräknas i kassan.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Tullavgifter och skatter ingår. Frakt beräknas i kassan.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Tullavgifter ingår. Frakt beräknas i kassan.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Tullavgifter ingår. Frakt beräknas i kassan.", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Moms och frakt beräknas i kassan.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Skatt och frakt beräknas i kassan.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Skatter ingår. Frakt beräknas i kassan.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Skatter ingår. Frakt beräknas i kassan.", + "view_more_details": "Visa fler uppgifter", + "page_placeholder_title": "Sidrubrik", + "page_placeholder_content": "Välj en sida om du vill visa dess innehåll.", + "placeholder_image": "Platshållarbild", + "powered_by": "Denna butik kommer att drivas av", + "store_owner_link_html": "Är du butiksägaren? Logga in här", + "shipping_discount_error": "Leveransrabatter visas i kassan när du lägger till en adress", + "discount_code_error": "Rabattkoden kan inte tillämpas på din varukorg", + "inventory_low_stock": "Låg lagernivå", + "inventory_in_stock": "I lager", + "inventory_out_of_stock": "Slut i lager", + "shipping_policy": "Fraktkostnad beräknas i kassan.", + "inventory_low_stock_show_count": { + "one": "{{ count }} kvar", + "other": "{{ count }} kvar" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Använd presentkortskoden online eller QR-koden i butik", + "title": "Här är ditt presentkort värt {{ value }} för {{ shop }}!", + "subtext": "Ditt presentkort", + "shop_link": "Besök webbshop", + "add_to_apple_wallet": "Lägg till i Apple Wallet", + "qr_image_alt": "QR-kod – skanna för att lösa in presentkort", + "copy_code": "Kopiera presentkortskod", + "expiration_date": "Går ut {{ expires_on }}", + "copy_code_success": "Koden kopierades", + "expired": "Har utgått" + } + }, + "placeholders": { + "password": "Lösenord", + "search": "Sök", + "product_title": "Produktnamn", + "collection_title": "Produktseriens namn" + }, + "products": { + "product": { + "add_to_cart": "Lägg till i varukorgen", + "added_to_cart": "Tillagd i varukorgen", + "adding_to_cart": "Lägger till ...", + "add_to_cart_error": "Det uppstod ett fel när artikeln skulle läggas till i varukorgen", + "sold_out": "Slutsåld", + "unavailable": "Inte tillgängliga" + } + }, + "fields": { + "separator": "till" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} kommentar", + "other": "{{ count }} kommentarer" + } + }, + "comment_form": { + "email": "E-postadress", + "error": "Kommentaren publicerades inte. Åtgärda följande:", + "heading": "Lämna en kommentar", + "message": "Meddelande", + "moderated": "Notera att kommentarer behöver godkännas innan de publiceras.", + "name": "Namn", + "post": "Publicera kommentar", + "success_moderated": "Kommentaren har publicerats, väntar på moderering", + "success": "Kommentaren har publicerats" + } + } +} diff --git a/locales/sv.schema.json b/locales/sv.schema.json new file mode 100644 index 000000000..24e480a9b --- /dev/null +++ b/locales/sv.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Gränser", + "collapsible_row": "Rad som kan döljas", + "colors": "Färger", + "custom_section": "Anpassat avsnitt", + "icon": "Ikon", + "logo_and_favicon": "Logotyp och favoritikon", + "overlapping_blocks": "Överlappande block", + "product_buy_buttons": "Köpknappar", + "product_description": "Beskrivning", + "product_price": "Pris", + "product_variant_picker": "Variantväljare", + "slideshow": "Bildspel", + "typography": "Typografi", + "video": "Video", + "slideshow_controls": "Bildspelskontroller", + "size": "Storlek", + "spacing": "Radavstånd", + "product_recommendations": "Rekommenderade produkter", + "product_media": "Produktmedia", + "featured_collection": "Utvald produktserie", + "add_to_cart": "Lägg till i varukorgen", + "email_signup": "E-postregistrering", + "submit_button": "Knappen Skicka", + "grid_layout_selector": "Väljare för rutnäts-layout", + "image": "Bild", + "list_items": "Listartiklar", + "facets": "Aspekter", + "variants": "Varianter", + "styles": "Stilar", + "product_cards": "Produktkort", + "primary_button": "Primär knapp", + "secondary_button": "Sekundär knapp", + "buttons": "Knappar", + "inputs": "Inmatningar", + "popovers": "Popovers", + "marquee": "Marquee", + "pull_quote": "Citat", + "contact_form": "Kontaktformulär", + "featured_product": "Produktegenskaper som lyfts fram", + "icons_with_text": "Ikoner med text", + "alternating_content_rows": "Alternerande rader", + "jumbo_text": "Jumbo-text", + "accelerated_checkout": "Snabbkassa", + "accordion": "Dragspel", + "accordion_row": "Dragspelsrad", + "animations": "Animeringar", + "announcement": "Meddelande", + "announcement_bar": "Meddelandefält", + "badges": "Brickor", + "button": "Knapp", + "cart": "Varukorg", + "cart_items": "Varukorgsartiklar", + "cart_products": "Varukorgsprodukter", + "cart_title": "Varukorg", + "collection": "Produktserie", + "collection_card": "Produktseriekort", + "collection_columns": "Produktseriekolumner", + "collection_container": "Produktserie", + "collection_description": "Produktseriebeskrivning", + "collection_image": "Produktseriebild", + "collection_info": "Produktserieinformation", + "collection_list": "Produktserielista", + "collections": "Produktserier", + "content": "Innehåll", + "content_grid": "Innehållsrutnät", + "details": "Uppgifter", + "divider": "Avgränsare", + "filters": "Filtrering och sortering", + "follow_on_shop": "Följ på Shop", + "footer": "Sidfot", + "footer_utilities": "Sidfotsverktyg", + "group": "Grupp", + "header": "Sidhuvud", + "heading": "Rubrik", + "icons": "Ikoner", + "image_with_text": "Bild med text", + "input": "Indata", + "logo": "Logotyp", + "magazine_grid": "Tidskriftsrutnät", + "media": "Media", + "menu": "Meny", + "mobile_layout": "Mobil layout", + "payment_icons": "Betalningsikoner", + "popup_link": "Popup-länk", + "predictive_search": "Sök-popover", + "predictive_search_empty": "Prediktiv sökning tom", + "price": "Pris", + "product": "Produkt", + "product_card": "Produktkort", + "product_card_media": "Media", + "product_card_rendering": "Produktkortsrendering", + "product_grid": "Rutnät", + "product_grid_main": "Produktrutnät", + "product_image": "Produktbild", + "product_information": "Produktinformation", + "product_list": "Utvald produktserie", + "product_review_stars": "Recensionsstjärnor", + "quantity": "Kvantitet", + "row": "Rad", + "search": "Sökning", + "section": "Avsnitt", + "selected_variants": "Valda varianter", + "shop_the_look": "Köp looken", + "slide": "Bild", + "social_media_links": "Länkar till sociala medier", + "spacer": "Separator", + "steps": "Steg", + "summary": "Sammanfattning", + "swatches": "Prover", + "testimonials": "Omdömen", + "text": "Text", + "title": "Titel", + "utilities": "Verktyg", + "search_input": "Sökinmatning", + "search_results": "Sökresultat", + "read_only": "Skrivskyddad", + "collection_title": "Produktseriens namn", + "collections_bento": "Produktserielista: Bento", + "collection_links": "Produktserielänkar", + "count": "Antal", + "faq_section": "Vanliga frågor", + "hero": "Hero", + "view_all_button": "Visa alla", + "video_section": "Video", + "product_title": "Produktnamn", + "custom_liquid": "Anpassa Liquid", + "blog": "Blogg", + "blog_post": "Bloggpost", + "blog_posts": "Bloggposter", + "caption": "Bildtext", + "collection_card_image": "Bild", + "collection_links_spotlight": "Produktserielänkar: Spotlight", + "collection_links_text": "Produktserielänkar: Text", + "collections_carousel": "Produktserielista: Karusell", + "collections_editorial": "Produktserielista: Redaktionell", + "collections_grid": "Produktserielista: Rutnät", + "copyright": "Upphovsrätt", + "divider_section": "Avgränsare", + "drawers": "Lådor", + "editorial": "Redaktionellt", + "editorial_jumbo_text": "Redaktionellt: Jumbo-text", + "hero_marquee": "Hero: Marquee", + "input_fields": "Inmatningsfält", + "local_pickup": "Lokal upphämtning", + "marquee_section": "Marquee", + "media_with_text": "Media med text", + "page": "Sida", + "page_content": "Innehåll", + "page_layout": "Sidlayout", + "policy_list": "Policylänkar", + "prices": "Priser", + "product_list_button": "Visa alla-knapp", + "products_carousel": "Utvald produktserie: karusell", + "products_editorial": "Utvald produktserie: redaktionell", + "products_grid": "Utvald produktserie: rutnät", + "social_link": "Länk till sociala medier", + "split_showcase": "Split-showcase", + "variant_pickers": "Variantväljare", + "pills": "Knappar", + "large_logo": "Stor logotyp", + "product_inventory": "Produktlager", + "description": "Beskrivning" + }, + "settings": { + "alignment": "Justering", + "autoplay": "Automatisk uppspelning", + "background": "Bakgrund", + "border_radius": "Hörnradie", + "border_width": "Kanttjocklek", + "borders": "Gränser", + "bottom_padding": "Nedre padding", + "button": "Knapp", + "color": "Färg", + "colors": "Färger", + "content_alignment": "Innehållsjustering", + "content_direction": "Innehållets riktning", + "content_position": "Innehållets position", + "cover_image_size": "Storlek på omslagsbild", + "cover_image": "Omslagsbild", + "custom_minimum_height": "Anpassad minimihöjd", + "custom_width": "Anpassad bredd", + "enable_video_looping": "Videoslingor", + "favicon": "Favoritikon", + "font_family": "Teckensnittsfamilj", + "gap": "Avstånd", + "geometric_translate_y": "Geometrisk translation Y", + "heading": "Rubrik", + "icon": "Ikon", + "image": "Bild", + "image_icon": "Bildikon", + "image_opacity": "Bildopacitet", + "image_position": "Bildposition", + "image_ratio": "Bildförhållande", + "label": "Etikett", + "line_height": "Radhöjd", + "link": "Länk", + "layout_gap": "Layoutavstånd", + "make_section_full_width": "Ge avsnittet full bredd", + "minimum_height": "Minimihöjd", + "opacity": "Opacitet", + "overlay_opacity": "Överlagring av opacitet", + "padding": "Utfyllnad", + "primary_color": "Länkar", + "product": "Produkt", + "section_width": "Avsnittsbredd", + "size": "Storlek", + "slide_spacing": "Bildavstånd", + "slide_width": "Bildbredd", + "slideshow_fullwidth": "Bilder med full bredd", + "style": "Stil", + "text": "Text", + "text_case": "Låda", + "top_padding": "Övre padding", + "video": "Video", + "video_alt_text": "Alternativtext", + "video_loop": "Slinga video", + "video_position": "Placering av video", + "width": "Bredd", + "z_index": "Z-index", + "limit_content_width": "Begränsa bredden för innehållet", + "color_scheme": "Färgschema", + "inherit_color_scheme": "Behåll färgschema", + "product_count": "Produktantal", + "product_type": "Produkttyp", + "content_width": "Innehållets bredd", + "collection": "Produktserie", + "enable_sticky_content": "Fast innehåll på dator", + "error_color": "Fel", + "success_color": "Klart", + "primary_font": "Primärt teckensnitt", + "secondary_font": "Sekundärt teckensnitt", + "tertiary_font": "Tertiärt teckensnitt", + "columns": "Kolumner", + "items_to_show": "Artiklar att visa", + "layout": "Layout", + "layout_type": "Typ", + "show_grid_layout_selector": "Visa väljare för rutnäts-layout", + "view_more_show": "Visa \"Visa fler\"-knappen", + "image_gap": "Mellanrum mellan bilder", + "width_desktop": "Bredd för dator", + "width_mobile": "Bredd för mobil", + "border_style": "Linjestil", + "height": "Höjd", + "thickness": "Tjocklek", + "stroke": "Streck", + "filter_style": "Filterstil", + "swatches": "Prover", + "quick_add_colors": "Snabbinfoga färger", + "divider_color": "Avgränsare", + "border_opacity": "Kantens genomskinlighet", + "hover_background": "Hovra över bakgrund", + "hover_borders": "Hovra över kanter", + "hover_text": "Hovra över text", + "primary_hover_color": "Hovra över länkar", + "primary_button_text": "Primär knapptext", + "primary_button_background": "Primär knappbakgrund", + "primary_button_border": "Primär knappkant", + "secondary_button_text": "Primär knapptext", + "secondary_button_background": "Sekundär knappbakgrund", + "secondary_button_border": "Sekundär knappkant", + "shadow_color": "Skugga", + "mobile_logo_image": "Logotyp på mobil", + "video_autoplay": "Automatisk uppspelning", + "video_cover_image": "Omslagsbild", + "video_external_url": "URL", + "video_source": "Källa", + "shadow_opacity": "Skuggopacitet", + "show_filter_label": "Textetiketter för tillämpade filter", + "show_swatch_label": "Textetiketter för prover", + "first_row_media_position": "Första radens media-position", + "accordion": "Dragspel", + "aspect_ratio": "Bildförhållande", + "auto_rotate_announcements": "Rotera meddelanden automatiskt", + "auto_rotate_slides": "Rotera bilder automatiskt", + "background_color": "Bakgrundsfärg", + "badge_corner_radius": "Hörnradie", + "badge_position": "Position på kort", + "badge_sale_color_scheme": "Rea", + "badge_sold_out_color_scheme": "Slutsåld", + "behavior": "Beteende", + "blur": "Suddig skugga", + "border": "Kant", + "bottom": "Längst ner", + "card_image_height": "Produktbildens höjd", + "carousel_on_mobile": "Karusell på mobil", + "cart_count": "Varukorgsantal", + "cart_items": "Varukorgsartiklar", + "cart_related_products": "Relaterade produkter", + "cart_title": "Varukorg", + "cart_total": "Summa varukorg", + "cart_type": "Typ", + "case": "Låda", + "checkout_buttons": "Knappar för snabbkassa", + "collection_list": "Produktserier", + "collection_templates": "Mallar för produktserier", + "content": "Innehåll", + "corner_radius": "Hörnradie", + "country_region": "Land/region", + "currency_code": "Valutakod", + "custom_height": "Anpassad höjd", + "custom_mobile_size": "Anpassad mobilstorlek", + "desktop_height": "Höjd på dator", + "direction": "Riktning", + "display": "Visning", + "divider_thickness": "Avgränsartjocklek", + "divider": "Avgränsare", + "dividers": "Avgränsare", + "drop_shadow": "Kastskugga", + "empty_state_collection_info": "Visas innan en sökning anges", + "empty_state_collection": "Empty state-produktserie", + "enable_filtering": "Filter", + "enable_grid_density": "Reglage för rutnätslayout", + "enable_sorting": "Sortering", + "enable_zoom": "Aktivera zoom", + "equal_columns": "Lika stora kolumner", + "expand_first_group": "Öppna första gruppen", + "extend_media_to_screen_edge": "Öppna media till skärmkant", + "extend_summary": "Öppna till skärmkant", + "extra_large": "Extra stor", + "extra_small": "Extra liten", + "fixed_height": "Pixelhöjd", + "fixed_width": "Pixelbredd", + "flag": "Flagga", + "font_price": "Prisets teckensnitt", + "font_weight": "Typvikt", + "font": "Teckensnitt", + "full_width_first_image": "Första bild i full bredd", + "full_width_on_mobile": "Full bredd på mobil", + "heading_preset": "Rubrikförinställning", + "hide_padding": "Dölj utfyllnad", + "hide_unselected_variant_media": "Dölj variantmedia som inte har valts", + "horizontal_gap": "Horisontellt mellanrum", + "horizontal_offset": "Skugga för horisontell kompensation", + "hover_behavior": "Hovringsbeteende", + "icon_background": "Ikonbakgrund", + "icons": "Ikoner", + "image_border_radius": "Hörnradie för bild", + "installments": "Avbetalningar", + "integrated_button": "Integrerad knapp", + "language_selector": "Språkväljare", + "large": "Stor", + "left_padding": "Utfyllnad till vänster", + "left": "Vänster", + "letter_spacing": "Teckenavstånd", + "limit_media_to_screen_height": "Begränsa till skärmhöjd", + "limit_product_details_width": "Begränsa vidd för produktuppgifter", + "link_preset": "Länkförinställning", + "links": "Länkar", + "logo_font": "Teckensnitt för logotyp", + "logo": "Logotyp", + "loop": "Loop", + "make_details_sticky_desktop": "Fast på dator", + "max_width": "Maxbredd", + "media_height": "Mediehöjd", + "media_overlay": "Medieöverlagring", + "media_position": "Medieposition", + "media_type": "Medietyp", + "media_width": "Mediebredd", + "menu": "Meny", + "mobile_columns": "Kolumn för mobil", + "mobile_height": "Höjd för mobil", + "mobile_quick_add": "Lägg till direkt för mobil", + "motion_direction": "Rörelsedetektering", + "motion": "Rörelse", + "movement_direction": "Rörelseriktning", + "navigation_bar_color_scheme": "Färgschema för navigeringsfält", + "navigation_bar": "Navigeringsfält", + "navigation": "Navigering", + "open_new_tab": "Öppna länk i ny flik", + "overlay_color": "Överlagringsfärg", + "overlay": "Överlagring", + "padding_bottom": "Utfyllnad under", + "padding_horizontal": "Utfyllnad horisontellt", + "padding_top": "Utfyllnad ovan", + "page_width": "Sidbredd", + "pagination": "Paginering", + "percent_height": "Procentuell höjd", + "percent_size_mobile": "Procentuell storlek", + "percent_size": "Procentuell storlek", + "percent_width": "Procentuell bredd", + "pixel_size_mobile": "Pixelstorlek", + "pixel_size": "Pixelstorlek", + "placement": "Placering", + "position": "Position", + "preset": "Förinställning", + "product_cards": "Produktkort", + "product_pages": "Produktsidor", + "product_templates": "Produktmallar", + "products": "Produkter", + "quick_add": "Lägg till direkt", + "ratio": "Förhållande", + "regular": "Normal", + "review_count": "Granska antal", + "right": "Höger", + "row_height": "Radhöjd", + "row": "Rad", + "seller_note": "Tillåt anteckning till säljare", + "shape": "Form", + "show_as_accordion": "Visa som dragspel på mobil", + "show_sale_price_first": "Visa reapris först", + "show_tax_info": "Skatteinformation", + "show": "Visa", + "size_mobile": "Mobilstorlek", + "small": "Liten", + "speed": "Hastighet", + "statement": "Kontoutdrag", + "sticky_header": "Fast sidhuvud", + "text_hierarchy": "Texthierarki", + "text_presets": "Textförinställningar", + "title": "Titel", + "top": "Högst upp", + "type": "Typ", + "type_preset": "Textförinställning", + "underline_thickness": "Tjocklek för understrykning", + "unit": "Enhet", + "variant_images": "Bilder för varianter", + "vendor": "Säljare", + "vertical_gap": "Vertikalt mellanrum", + "vertical_offset": "Skugga för vertikal kompensation", + "vertical_on_mobile": "Vertikalt på mobil", + "view_all_as_last_card": "”Visa alla” som sista kort", + "weight": "Vikt", + "wrap": "Radbrytning", + "read_only": "Skrivskyddad", + "always_stack_buttons": "Stapla alltid knappar", + "custom_mobile_width": "Anpassad mobilbredd", + "gradient_direction": "Gradientriktning", + "horizontal_padding": "Horisontell utfyllnad", + "overlay_style": "Överlagringsstil", + "show_count": "Visa antal", + "transparent_background": "Transparent bakgrund", + "vertical_padding": "Vertikal utfyllnad", + "visibility": "Synlighet", + "account": "Konto", + "align_baseline": "Justera baslinje för text", + "add_discount_code": "Tillåt rabatter i varukorgen", + "background_overlay": "Bakgrundsöverlagring", + "background_media": "Bakgrundsmedia", + "border_thickness": "Kanttjocklek", + "bottom_row": "Understa rad", + "button_text_case": "Skiftläge", + "button_text_weight": "Typsnittsvikt", + "card_size": "Kortstorlek", + "auto_open_cart_drawer": "\"Lägg till i varukorg\" öppnar varukorgspanelen automatiskt", + "collection_count": "Antal produktserier", + "collection_title_case": "Skiftläge för produktseriens namn", + "custom_liquid": "Liquid-kod", + "default": "Standard", + "default_logo": "Standardlogotyp", + "divider_width": "Avgränsarbredd", + "headings": "Rubriker", + "hide_logo_on_home_page": "Dölj logotypen på startsidan", + "inverse": "Omvänd", + "inverse_logo": "Omvänd logotyp", + "layout_style": "Stil", + "length": "Längd", + "mobile_card_size": "Storlek på mobilkort", + "mobile_pagination": "Mobil paginering", + "open_row_by_default": "Öppna raden som standard", + "page": "Sida", + "page_transition_enabled": "Sidövergång", + "product_and_card_title_case": "Skiftläge för produkter och kort", + "product_title_case": "Skiftläge för produkter", + "right_padding": "Utfyllnad till höger", + "search": "Sök", + "search_icon": "Sökikon", + "search_position": "Position", + "search_row": "Rad", + "show_author": "Författare", + "show_alignment": "Visa justering", + "show_date": "Datum", + "show_pickup_availability": "Visa tillgänglighet för upphämtning", + "show_search": "Visa sökning", + "text_label_case": "Skiftläge för för textetiketter", + "use_inverse_logo": "Använd omvänd logotyp", + "product_corner_radius": "Produktens hörnradie", + "card_corner_radius": "Kortets hörnradie", + "alignment_mobile": "Justering på mobilen", + "animation_repeat": "Upprepa animering", + "blurred_reflection": "Suddig reflektion", + "card_hover_effect": "Korthovringseffekt", + "effects": "Effekter", + "inventory_threshold": "Tröskel för låg lagernivå", + "reflection_opacity": "Reflektionens opacitet", + "show_inventory_quantity": "Visa antal i lager vid låg lagernivå", + "transition_to_main_product": "Övergång från produktkort till produktsida", + "show_second_image_on_hover": "Visa den andra bilden vid hovring", + "media": "Media", + "product_card_carousel": "Visa karusell", + "media_fit": "Mediaanpassning", + "scroll_speed": "Tid till nästa meddelande" + }, + "options": { + "adapt_to_image": "Anpassa till bild", + "apple": "Äpple", + "arrow": "Pil", + "auto": "Automatisk", + "banana": "Banan", + "bottle": "Flaska", + "box": "Låda", + "buttons": "Knappar", + "carrot": "Morot", + "center": "Mitten", + "chat_bubble": "Chattbubbla", + "clipboard": "Urklipp", + "contain": "Innehåller", + "counter": "Räknare", + "cover": "Omslag", + "custom": "Anpassa", + "dairy_free": "Fri från mejeriprodukter", + "dairy": "Mejeriprodukt", + "default": "Standard", + "dropdowns": "Rullgardinsmenyer", + "dots": "Prickar", + "dryer": "Torkare", + "end": "Slut", + "eye": "Öga", + "facebook": "Facebook", + "fill": "Fyll", + "fire": "Eld", + "fit": "Anpassa", + "full": "Heltäckande", + "full_and_page": "Heltäckande bakgrund, innehåll samma bredd som sidan", + "gluten_free": "Glutenfri", + "heading": "Rubrik", + "heart": "Hjärta", + "horizontal": "Liggande", + "instagram": "Instagram", + "iron": "Strykjärn", + "landscape": "Landskap", + "large": "Stor", + "leaf": "Blad", + "leather": "Läder", + "lg": "LG", + "lightning_bolt": "Blixt", + "link": "Länk", + "lipstick": "Läppstift", + "lock": "Lås", + "lowercase": "gemener", + "m": "M", + "map_pin": "Kartnål", + "medium": "Medelstor", + "none": "Inga", + "numbers": "Siffror", + "nut_free": "Utan nötter", + "outline": "Kontur", + "page": "Sida", + "pants": "Byxor", + "paw_print": "Tassavtryck", + "pepper": "Peppar", + "perfume": "Parfym", + "pinterest": "Pinterest", + "plane": "Flygplan", + "plant": "Växt", + "portrait": "Porträtt", + "price_tag": "Prislapp", + "question_mark": "Frågetecken", + "recycle": "Återvinn", + "return": "Gå tillbaka", + "ruler": "Linjal", + "s": "S", + "sentence": "Mening", + "serving_dish": "Serveringsfat", + "shirt": "Skjorta", + "shoe": "Sko", + "silhouette": "Siluett", + "small": "Liten", + "snapchat": "Snapchat", + "snowflake": "Snöflinga", + "solid": "Tjock", + "space_between": "Mellanrum mellan", + "square": "Fyrkantig", + "star": "Stjärna", + "start": "Start", + "stopwatch": "Stoppur", + "tiktok": "TikTok", + "truck": "Lastbil", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "Versaler", + "vertical": "Stående", + "vimeo": "Vimeo", + "washing": "Tvätt", + "circle": "Cirkel", + "swatches": "Prover", + "full_and_page_offset_left": "Heltäckande bakgrund, innehåll med sidobredd, förskjutning till vänster", + "full_and_page_offset_right": "Heltäckande bakgrund, innehåll med sidobredd, förskjutning till höger", + "offset_left": "Förskjutning till vänster", + "offset_right": "Förskjutning till höger", + "page_center_aligned": "Sida, centrerad", + "page_left_aligned": "Sida, vänsterställd", + "page_right_aligned": "Sida, högerställd", + "button": "Knapp", + "caption": "Rubrik", + "h1": "Rubrik 1", + "h2": "Rubrik 2", + "h3": "Rubrik 3", + "h4": "Rubrik 4", + "h5": "Rubrik 5", + "h6": "Rubrik 6", + "paragraph": "Stycke", + "primary": "Primär", + "secondary": "Sekundär", + "tertiary": "Tertiär", + "chevron_left": "Sparre vänster", + "chevron_right": "Sparre höger", + "diamond": "Diamant", + "grid": "Rutnät", + "parallelogram": "Parallelogram", + "rounded": "Rundad", + "fit_content": "Anpassa", + "pills": "Brickor", + "heavy": "Tjock", + "thin": "Tunn", + "drawer": "Låda", + "preview": "Förhandsgranska", + "text": "Text", + "video_uploaded": "Uppladdad", + "video_external_url": "Extern URL", + "aspect_ratio": "Bildförhållande", + "fixed": "Fast", + "pixel": "Pixel", + "percent": "Procent", + "above_carousel": "Över karusell", + "all": "Alla", + "up": "Upp", + "down": "Ner", + "always": "Alltid", + "arrows_large": "Stora pilar", + "arrows": "Pilar", + "balance": "Saldo", + "bento": "Bento", + "black": "Svart", + "bluesky": "Bluesky", + "body_large": "Brödtext (stor)", + "body_regular": "Brödtext (normal)", + "body_small": "Brödtext (liten)", + "bold": "Fet", + "bottom_left": "Längst ner till vänster", + "bottom_right": "Längst ner till höger", + "bottom": "Längst ner", + "capitalize": "Gör versalt", + "caret": "Insättningstecken", + "carousel": "Karusell", + "check_box": "Kryssruta", + "chevron_large": "Stora chevrontecken", + "chevron": "Chevrontecken", + "chevrons": "Chevrontecken", + "classic": "Klassisk", + "collection_images": "Kategoribilder", + "color": "Färg", + "complementary": "Kompletterande", + "dissolve": "Lös upp", + "dotted": "Streckad", + "editorial": "Redaktionell", + "extra_large": "Extra stor", + "extra_small": "Extra liten", + "featured_collections": "Utvalda produktserier", + "featured_products": "Utvalda produkter", + "font_primary": "Primär", + "font_secondary": "Sekundär", + "font_tertiary": "Tertiär", + "forward": "Framåt", + "full_screen": "Helskärm", + "gradient": "Gradient", + "heading_extra_large": "Rubrik (extra stor)", + "heading_extra_small": "Rubrik (extra liten)", + "heading_large": "Rubrik (stor)", + "heading_regular": "Rubrik (normal)", + "heading_small": "Rubrik (liten)", + "icon": "Ikon", + "image": "Bild", + "input": "Indata", + "inside_carousel": "I karusell", + "inverse_large": "Omvänd stor", + "inverse": "Omvänd", + "large_arrows": "Stora pilar", + "large_chevrons": "Stora chevrontecken", + "left": "Vänster", + "light": "Magert", + "linkedin": "LinkedIn", + "loose": "Gles", + "media_first": "Media först", + "media_second": "Media andra", + "modal": "Spärrande fönster", + "narrow": "Smal", + "never": "Aldrig", + "next_to_carousel": "Bredvid karusell", + "normal": "Normal", + "nowrap": "Ingen radbrytning", + "off_media": "Utanför media", + "on_media": "I media", + "on_scroll_up": "Vid bläddring uppåt", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Oval", + "plus": "Plus", + "pretty": "Snygg", + "price": "Pris", + "primary_style": "Primär stil", + "rectangle": "Rektangel", + "regular": "Normal", + "related": "Relaterad", + "reverse": "Omvänd", + "rich_text": "RTF", + "right": "Höger", + "secondary_style": "Sekundär stil", + "semibold": "Halvfet", + "shaded": "Skuggad", + "show_second_image": "Visa andra bild", + "single": "Enkel", + "slide_left": "Bild till vänster", + "slide_up": "Bild uppåt", + "spotify": "Spotify", + "stack": "Stack", + "text_only": "Endast text", + "threads": "Threads", + "thumbnails": "Miniatyrbilder", + "tight": "Tät", + "top_left": "Överst till vänster", + "top_right": "Överst till höger", + "top": "Högst upp", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Understrykning", + "video": "Video", + "wide": "Bred", + "youtube": "YouTube", + "below_image": "Under bild", + "hidden": "Dold", + "on_image": "På bild", + "spotlight": "Spotlight", + "accent": "Accent", + "body": "Brödtext", + "button_primary": "Primär knapp", + "button_secondary": "Sekundär knapp", + "compact": "Komprimerad", + "crop_to_fit": "Beskär för att passa", + "hint": "Tips", + "maintain_aspect_ratio": "Bibehåll bildförhållande", + "off": "Av", + "social_bluesky": "Socialt: Bluesky", + "social_facebook": "Socialt: Facebook", + "social_instagram": "Socialt: Instagram", + "social_linkedin": "Socialt: LinkedIn", + "social_pinterest": "Socialt: Pinterest", + "social_snapchat": "Socialt: Snapchat", + "social_spotify": "Socialt: Spotify", + "social_threads": "Socialt: Threads", + "social_tiktok": "Socialt: TikTok", + "social_tumblr": "Socialt: Tumblr", + "social_twitter": "Socialt: X (Twitter)", + "social_whatsapp": "Socialt: WhatsApp", + "social_vimeo": "Socialt: Vimeo", + "social_youtube": "Socialt: YouTube", + "standard": "Standard", + "subheading": "Underrubrik", + "blur": "Gör suddig", + "lift": "Lyft", + "reveal": "Visa", + "scale": "Skala", + "subtle_zoom": "Zooma" + }, + "content": { + "advanced": "Avancerat", + "background_image": "Bakgrundsbild", + "background_video": "Bakgrundsvideo", + "block_size": "Blockstorlek", + "borders": "Kantlinjer", + "describe_the_video_for": "Beskriv videon för kunder som använder skärmläsare. [Mer information](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "Avsnitsstorlek", + "slideshow_width": "Bildbredd", + "typography": "Typografi", + "width_is_automatically_optimized": "Bredden optimeras automatiskt för mobilen.", + "complementary_products": "Kompletterande produkter måste konfigureras med Search & Discovery-appen. [Mer information](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Kolumner optimeras automatiskt för mobilen", + "content_width": "Sidobredd tillämpas endast när avsnittsbredden är inställd till full bredd.", + "adjustments_affect_all_content": "Gäller allt innehåll i det här blocket", + "responsive_font_sizes": "Storleken justeras automatiskt för att passa alla skärmstorlekar", + "buttons": "Knappar", + "swatches": "Prover", + "variant_settings": "Variant-inställningar", + "background": "Bakgrund", + "appearance": "Utseende", + "arrows": "Pilar", + "body_size": "Storlek för brödtext", + "mobile_size": "Mobilstorlek", + "bottom_row_appearance": "Utseende på understa rad", + "cards_layout": "Kortlayout", + "carousel_navigation": "Karusellnavigering", + "carousel_pagination": "Karusellpaginering", + "copyright": "Upphovsrätt", + "edit_logo_in_theme_settings": "Redigera logotypen i [temainställningarna](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "Redigera prisformateringen i [temainställningarna](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "Redigera varianters utseende i [temainställningarna](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "Lägg till registreringar [kundprofiler](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "För att knappen ska visas måste Shop-kanalen vara installerad och Shop Pay vara aktiverat. [Mer information](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Teckensnitt", + "grid": "Rutnät", + "heading_size": "Rubrikstorlek", + "image": "Bild", + "input": "Indata", + "layout": "Layout", + "link": "Länk", + "link_padding": "Länkutfyllnad", + "localization": "Lokalisering", + "logo": "Logotyp", + "margin": "Marginal", + "media": "Media", + "media_1": "Media 1", + "media_2": "Media 2", + "menu": "Meny", + "mobile_layout": "Mobil layout", + "padding": "Utfyllnad", + "padding_desktop": "Utfyllnad för dator", + "paragraph": "Stycke", + "policies": "Policyer", + "popup": "Popup", + "search": "Sökning", + "section_layout": "Avsnittslayout", + "size": "Storlek", + "social_media": "Sociala medier", + "submit_button": "Knappen Skicka", + "text_presets": "Textförinställningar", + "transparent_background": "Transparent bakgrund", + "typography_primary": "Primär typografi", + "typography_secondary": "Sekundär typografi", + "typography_tertiary": "Tertiär typografi", + "mobile_width": "Mobilbredd", + "width": "Bredd", + "visible_if_collection_has_more_products": "Syns om produktserien har fler produkter än vad som visas", + "carousel": "Karusell", + "colors": "Färger", + "collection_page": "Produktseriesida", + "copyright_info": "Läs om hur du [redigerar upphovsrättsinformationen](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "Kundkonto", + "edit_empty_state_collection_in_theme_settings": "Redigera tomt tillstånd för kollektion i [temainställningar](/editor?context=theme&category=search)", + "grid_layout": "Rutnätslayout", + "home_page": "Startsida", + "images": "Bilder", + "inverse_logo_info": "Används när transparent bakgrund för sidhuvud är inställd på Omvänd", + "manage_customer_accounts": "[Hantera synlighet](/admin/settings/customer_accounts) i inställningarna för kundkonton. Äldre konton stöds inte.", + "manage_policies": "[Hantera policyer](/admin/settings/legal)", + "product_page": "Produktsida", + "text": "Text", + "thumbnails": "Miniatyrbilder", + "visibility": "Synlighet", + "app_required_for_ratings": "En app krävs för produktbetyg. [Mer information](https://help.shopify.com/manual/apps)", + "icon": "Ikon", + "manage_store_name": "[Hantera butiksnamn](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Visar produktserie från överordnat avsnitt", + "resource_reference_collection_card_image": "Visar bild från överordnad produktserie", + "resource_reference_collection_title": "Visar titel från överordnad produktserie", + "resource_reference_product": "Ansluter automatiskt till överordnad produkt", + "resource_reference_product_card": "Visar produkt från överordnat avsnitt", + "resource_reference_product_inventory": "Visar lager från överordnad produkt", + "resource_reference_product_price": "Visar pris från överordnad produkt", + "resource_reference_product_recommendations": "Visar rekommendationer baserad på överordnad produkt", + "resource_reference_product_review": "Visar recensioner från överordnad produkt", + "resource_reference_product_swatches": "Visar prover från överordnad produkt", + "resource_reference_product_title": "Visar titel från överordnad produkt", + "resource_reference_product_variant_picker": "Visar varianter från överordnad produkt", + "resource_reference_product_media": "Visar media från överordnad produkt", + "product_media": "Produktmedia", + "section_link": "Länk till avsnitt" + }, + "html_defaults": { + "share_information_about_your": "

Dela information om ditt varumärke med dina kunder. Beskriv en produkt, gör tillkännagivanden eller välkomna kunder till din butik.

" + }, + "text_defaults": { + "button_label": "Shoppa nu", + "collapsible_row": "Rad som kan döljas", + "heading": "Rubrik", + "email_signup_button_label": "Prenumerera", + "be_bold": "Var djärv.", + "accordion_heading": "Dragspelssidhuvud", + "contact_form_button_label": "Skicka", + "popup_link": "Popup-länk", + "sign_up": "Registrera dig", + "welcome_to_our_store": "Välkommen till vår butik", + "shop_our_latest_arrivals": "Handla våra senaste nyheter!" + }, + "info": { + "video_alt_text": "Beskriv videon för användare av hjälpmedelsteknik", + "video_autoplay": "Videor har ljudet avstängt som standard", + "video_external": "Använd en YouTube- eller en Vimeo-URL", + "carousel_layout_on_mobile": "Karusell används på mobil", + "link_info": "Valfritt: gör ikonen klickbar", + "carousel_hover_behavior_not_supported": "Karusellhovring stöds inte när karuselltyp väljs på avsnittsnivå", + "checkout_buttons": "Snabbar upp kassan för köpare och kan förbättra konverteringen. [Mer information](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Anpassad rubrik", + "edit_presets_in_theme_settings": "Redigera förinställningar i [temainställningarna](/editor?context=theme&category=typography)", + "enable_filtering_info": "Anpassa filter med [Search & Discovery-appen](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "grid_layout_on_mobile": "Rutnätslayout används för mobil", + "logo_font": "Gäller bara om ingen logotyp har valts", + "manage_countries_regions": "[Hantera länder/regioner](/admin/settings/markets)", + "manage_languages": "[Hantera språk](/admin/settings/languages)", + "transparent_background": "Granska varje mall där transparent bakgrund tillämpas beträffande läslighet", + "aspect_ratio_adjusted": "Justerat i vissa layouter", + "auto_open_cart_drawer": "När detta är aktiverat öppnas varukorgspanelen automatiskt när en produkt läggs till i varukorgen.", + "custom_liquid": "Lägg till appfragment eller annan kod för att skapa avancerade anpassningar. [Mer information](https://shopify.dev/docs/api/liquid)", + "pills_usage": "Används för använda filter, rabattkoder och sökförslag", + "applies_on_image_only": "Gäller endast för bilder", + "hover_effects": "Gäller produkt- och produktseriekort" + }, + "categories": { + "basic": "Basic", + "collection": "Produktserie", + "collection_list": "Produktserielista", + "footer": "Sidfot", + "forms": "Formulär", + "header": "Sidhuvud", + "layout": "Layout", + "links": "Länkar", + "product": "Produkt", + "product_list": "Utvald produktserie", + "banners": "Banners", + "collections": "Produktserier", + "custom": "Anpassad", + "decorative": "Dekorativ", + "products": "Produkter", + "other_sections": "Övrigt", + "storytelling": "Berättande" + } +} diff --git a/locales/th.json b/locales/th.json new file mode 100644 index 000000000..4e4870b6d --- /dev/null +++ b/locales/th.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "โหลดวิดีโอ: {{ description }}", + "sold_out": "ขายหมดแล้ว", + "email_signup": { + "label": "อีเมล", + "placeholder": "อีเมล", + "success": "ขอขอบคุณที่สมัครรับข้อมูล" + }, + "filter": "ตัวกรอง", + "payment_methods": "วิธีการชำระเงิน", + "contact_form": { + "name": "ชื่อ", + "email": "อีเมล", + "phone": "โทรศัพท์", + "comment": "ความคิดเห็น", + "post_success": "ขอบคุณที่ติดต่อเรา เราจะติดต่อกลับหาคุณโดยเร็วที่สุด", + "error_heading": "โปรดแก้ไขข้อมูลดังต่อไปนี้" + } + }, + "accessibility": { + "play_model": "เล่นโมเดล 3 มิติ", + "play_video": "เล่นวิดีโอ", + "unit_price": "ราคาต่อหน่วย", + "country_results_count": "ผลลัพธ์ {{ count }} รายการ", + "slideshow_pause": "หยุดสไลด์โชว์ชั่วคราว", + "slideshow_play": "เล่นสไลด์โชว์", + "remove_item": "ลบ {{ title}}", + "skip_to_text": "ข้ามไปยังเนื้อหา", + "skip_to_product_info": "ข้ามไปยังข้อมูลสินค้า", + "skip_to_results_list": "ข้ามไปที่รายการผลลัพธ์", + "new_window": "เปิดในหน้าต่างใหม่", + "slideshow_next": "สไลด์ถัดไป", + "slideshow_previous": "สไลด์ก่อนหน้า", + "close_dialog": "ปิดกล่องโต้ตอบ", + "reset_search": "รีเซ็ตการค้นหา", + "search_results_count": "พบผลลัพธ์การค้นหาจำนวน {{ count }} รายการสำหรับ \"{{ query }}\"", + "search_results_no_results": "ไม่พบผลลัพธ์สำหรับ “{{ query }}”", + "filters": "ตัวกรอง", + "filter_count": { + "one": "ใช้ตัวกรอง {{ count }} ตัวกรองแล้ว", + "other": "ใช้ตัวกรอง {{ count }} ตัวกรองแล้ว" + }, + "account": "เปิดเมนูบัญชี", + "cart": "ตะกร้าสินค้า", + "cart_count": "สินค้าทั้งหมดในตะกร้าสินค้า", + "menu": "เมนู", + "country_region": "ประเทศ/ภูมิภาค", + "slide_status": "สไลด์ที่ {{ index }} จาก {{ length }}", + "scroll_to": "เลื่อนไปที่ {{ title }}", + "loading_product_recommendations": "กำลังโหลดการแนะนำสินค้า", + "discount": "ใช้รหัสส่วนลด", + "discount_applied": "ใช้รหัสส่วนลดแล้ว: {{ code }}", + "open_cart_drawer": "เปิดตะกร้าสินค้า", + "inventory_status": "สถานะสินค้าคงคลัง", + "pause_video": "หยุดวิดีโอชั่วคราว", + "find_country": "ค้นหาประเทศ", + "localization_region_and_language": "เปิดตัวเลือกภูมิภาคและภาษา", + "open_search_modal": "เปิดการค้นหา", + "decrease_quantity": "ลดจำนวน", + "increase_quantity": "เพิ่มจำนวน", + "quantity": "จำนวน", + "rating": "คะแนนสำหรับสินค้านี้คือ {{ rating }} จาก 5", + "nested_product": "{{ product_title }} สำหรับ {{ parent_title }}" + }, + "actions": { + "add_to_cart": "เพิ่มลงในตะกร้าสินค้า", + "clear_all": "ล้างทั้งหมด", + "remove": "ลบออก", + "view_in_your_space": "ดูในพื้นที่ของคุณ", + "show_filters": "ตัวกรอง", + "clear": "ล้าง", + "continue_shopping": "เลือกซื้อต่อ", + "log_in_html": "หากมีบัญชีผู้ใช้อยู่แล้ว เข้าสู่ระบบเพื่อชำระเงินได้รวดเร็วขึ้น", + "see_items": { + "one": "ดูสินค้า {{ count }} รายการ", + "other": "ดูสินค้า {{ count }} รายการ" + }, + "view_all": "ดูทั้งหมด", + "add": "เพิ่ม", + "choose": "เลือก", + "added": "เพิ่มแล้ว", + "show_less": "แสดงน้อยลง", + "show_more": "แสดงมากขึ้น", + "close": "ปิด", + "more": "เพิ่มเติม", + "reset": "รีเซ็ต", + "zoom": "ซูม", + "close_dialog": "ปิดกล่องโต้ตอบ", + "remove_discount": "ลบ {{ code }} ส่วนลด", + "enter_using_password": "ป้อนโดยใช้รหัสผ่าน", + "submit": "ส่ง", + "enter_password": "ป้อนรหัสผ่าน", + "view_store_information": "ดูข้อมูลร้านค้า", + "back": "ย้อนกลับ", + "log_in": "ลงชื่อเข้าใช้", + "log_out": "ออกจากระบบ", + "apply": "ใช้", + "sign_in_options": "ตัวเลือกอื่นๆ ในการลงชื่อเข้าใช้", + "sign_up": "ลงทะเบียน", + "open_image_in_full_screen": "เปิดรูปภาพแบบเต็มหน้าจอ", + "sort": "จัดเรียง", + "show_all_options": "แสดงตัวเลือกทั้งหมด" + }, + "content": { + "reviews": "รีวิว", + "language": "ภาษา", + "localization_region_and_language": "ภูมิภาคและภาษา", + "no_results_found": "ไม่พบผลลัพธ์", + "cart_total": "ยอดรวมของตะกร้า", + "your_cart_is_empty": "ตะกร้าสินค้าของคุณว่างอยู่", + "product_image": "รูปภาพสินค้า", + "product_information": "ข้อมูลสินค้า", + "quantity": "จำนวน", + "product_total": "สินค้าทั้งหมด", + "cart_estimated_total": "ยอดรวมโดยประมาณ", + "seller_note": "คำแนะนำพิเศษ", + "cart_subtotal": "ยอดรวมย่อย", + "discounts": "ส่วนลด", + "discount": "ส่วนลด", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "รวมภาษีและอากรแล้ว ระบบจะคำนวณส่วนลดและค่าจัดส่งในขั้นตอนการชำระเงิน", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "รวมภาษีและอากรแล้ว ระบบจะคำนวณส่วนลดและค่าจัดส่งในขั้นตอนการชำระเงิน", + "taxes_included_shipping_at_checkout_with_policy_html": "รวมภาษีแล้ว ระบบจะคำนวณส่วนลดและค่าจัดส่งในขั้นตอนการชำระเงิน", + "taxes_included_shipping_at_checkout_without_policy": "รวมภาษีแล้ว ระบบจะคำนวณส่วนลดและค่าจัดส่งในขั้นตอนการชำระเงิน", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "รวมอากรแล้ว ระบบจะคำนวณภาษี ส่วนลด และค่าจัดส่งในขั้นตอนการชำระเงิน", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "รวมอากรแล้ว ระบบจะคำนวณภาษี ส่วนลด และค่าจัดส่งในขั้นตอนการชำระเงิน", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "ระบบจะคำนวณภาษี ส่วนลด และค่าจัดส่งในขั้นตอนการชำระเงิน", + "taxes_at_checkout_shipping_at_checkout_without_policy": "ระบบจะคำนวณภาษี ส่วนลด และค่าจัดส่งในขั้นตอนการชำระเงิน", + "checkout": "ชำระเงิน", + "cart_title": "ตะกร้าสินค้า", + "price": "ราคา", + "price_regular": "ราคาปกติ", + "price_compare_at": "ราคาเปรียบเทียบ", + "price_sale": "ราคาโปรโมชัน", + "duties_and_taxes_included": "รวมภาษีและอากรแล้ว", + "duties_included": "รวมอากรแล้ว", + "shipping_policy_html": "ค่าจัดส่งที่คำนวณในขั้นตอนชำระเงิน", + "taxes_included": "รวมภาษีแล้ว", + "product_badge_sold_out": "ขายหมดแล้ว", + "product_badge_sale": "ลดราคา", + "search_input_label": "การค้นหา", + "search_input_placeholder": "ค้นหา", + "search_results": "ผลลัพธ์การค้นหา", + "search_results_label": "ผลลัพธ์การค้นหา", + "search_results_no_results": "ไม่พบผลการค้นหาสำหรับ \"{{ terms }}\" ลองใช้คำค้นหาอื่น", + "search_results_resource_articles": "โพสต์บล็อก", + "search_results_resource_collections": "คอลเลกชัน", + "search_results_resource_pages": "หน้า", + "search_results_resource_products": "สินค้า", + "search_results_resource_queries": "คำแนะนำการค้นหา", + "search_results_view_all": "ดูทั้งหมด", + "search_results_view_all_button": "ดูทั้งหมด", + "search_results_resource_products_count": { + "one": "สินค้า {{ count }} รายการ", + "other": "สินค้า {{ count }} รายการ" + }, + "grid_view": { + "default_view": "ค่าเริ่มต้น", + "grid_fieldset": "คอลัมน์กริด", + "single_item": "แบบเดี่ยว", + "zoom_out": "ซูมออก" + }, + "recently_viewed_products": "ที่ดูครั้งล่าสุด", + "unavailable": "ไม่พร้อมใช้งาน", + "collection_placeholder": "ชื่อคอลเลกชัน", + "product_card_placeholder": "ชื่อสินค้า", + "product_count": "จำนวนสินค้า", + "item_count": { + "one": "{{ count }} รายการ", + "other": "{{ count }} รายการ" + }, + "errors": "ข้อผิดพลาด", + "price_from": "จาก {{ price }}", + "featured_products": "สินค้าที่แนะนำ", + "no_products_found": "ไม่พบสินค้า", + "use_fewer_filters_html": "ลองใช้ตัวกรองน้อยลง หรือล้างตัวกรองทั้งหมด", + "search": "การค้นหา", + "search_results_no_results_check_spelling": "ไม่พบผลลัพธ์สำหรับ “{{ terms }}” ตรวจสอบการสะกดคำหรือลองค้นหาคำหรือประโยคอื่น", + "filters": "ตัวกรอง", + "price_filter_html": "ราคาสูงสุดคือ {{ price }}", + "blog_details_separator": "|", + "discount_code": "รหัสส่วนลด", + "pickup_available_at_html": "รับสินค้าได้ที่ {{ location }}", + "pickup_available_in": "รับสินค้าได้เวลา {{ pickup_time }}", + "pickup_not_available": "ไม่สามารถรับสินค้าในขณะนี้", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "อ่านเพิ่มเติม...", + "wrong_password": "รหัสผ่านไม่ถูกต้อง", + "account_title": "บัญชีผู้ใช้", + "account_title_personalized": "สวัสดี {{ first_name }}", + "account_orders": "คำสั่งซื้อ", + "account_profile": "โปรไฟล์", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "รวมภาษีและอากรแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "รวมภาษีและอากรแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "รวมอากรแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "รวมอากรแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "ภาษีและค่าจัดส่งที่คำนวณในขั้นตอนการชำระเงิน", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "ภาษีและค่าจัดส่งที่คิดคำนวณในระหว่างขั้นตอนการชำระเงิน", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "รวมภาษีแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "รวมภาษีแล้ว ค่าจัดส่งจะคำนวณในขั้นตอนชำระเงิน", + "view_more_details": "ดูรายละเอียดเพิ่มเติม", + "inventory_low_stock": "สต็อกสินค้าเหลือน้อย", + "inventory_in_stock": "มีในสต็อก", + "inventory_out_of_stock": "หมดสต็อก", + "page_placeholder_title": "ชื่อหน้า", + "page_placeholder_content": "เลือกหน้าที่ต้องการแสดงเนื้อหา", + "placeholder_image": "รูปภาพตัวยึดตำแหน่ง", + "inventory_low_stock_show_count": { + "one": "เหลือ {{ count }} รายการ", + "other": "เหลือ {{ count }} รายการ" + }, + "shipping_discount_error": "ส่วนลดค่าจัดส่งจะปรากฏในขั้นตอนชำระเงินหลังจากเพิ่มที่อยู่", + "discount_code_error": "ไม่สามารถใช้รหัสส่วนลดกับตะกร้าสินค้าของคุณได้", + "shipping_policy": "คำนวณค่าจัดส่งในขั้นตอนการชำระเงิน", + "powered_by": "ร้านค้านี้จะได้รับการสนับสนุนจาก", + "store_owner_link_html": "หากคุณเป็นเจ้าของร้าน เข้าสู่ระบบที่นี่" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "ใช้รหัสบัตรของขวัญทางออนไลน์หรือใช้คิวอาร์โค้ดในร้านค้า", + "title": "นี่คือยอดคงเหลือในบัตรของขวัญมูลค่า {{ value }} สำหรับใช้ที่ {{ shop }}!", + "subtext": "บัตรของขวัญของคุณ", + "shop_link": "เยี่ยมชมร้านค้าออนไลน์", + "add_to_apple_wallet": "เพิ่มลงใน Apple Wallet", + "qr_image_alt": "สแกนคิวอาร์โค้ดเพื่อแลกใช้บัตรของขวัญ", + "copy_code": "คัดลอกรหัสบัตรของขวัญ", + "expiration_date": "หมดอายุเมื่อ {{ expires_on }}", + "copy_code_success": "คัดลอกรหัสสำเร็จ", + "expired": "หมดอายุแล้ว" + } + }, + "placeholders": { + "password": "รหัสผ่าน", + "search": "การค้นหา", + "product_title": "ชื่อสินค้า", + "collection_title": "ชื่อคอลเลกชัน" + }, + "products": { + "product": { + "add_to_cart": "เพิ่มลงในตะกร้าสินค้า", + "added_to_cart": "เพิ่มลงในตะกร้าสินค้าแล้ว", + "adding_to_cart": "กำลังเพิ่ม...", + "add_to_cart_error": "เกิดข้อผิดพลาดขณะเพิ่มสินค้าในตะกร้า", + "sold_out": "ขายหมดแล้ว", + "unavailable": "ไม่พร้อมจำหน่าย" + } + }, + "fields": { + "separator": "ถึง" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} ความคิดเห็น", + "other": "{{ count }} ความคิดเห็น" + } + }, + "comment_form": { + "email": "อีเมล", + "error": "ไม่สามารถโพสต์ความคิดเห็นได้ กรุณาแก้ไขสิ่งต่อไปนี้", + "heading": "แสดงความคิดเห็น", + "message": "ข้อความ", + "moderated": "โปรดทราบว่าความคิดเห็นจะต้องได้รับการอนุมัติก่อนที่จะได้รับการเผยแพร่", + "name": "ชื่อ", + "post": "โพสต์ความคิดเห็น", + "success_moderated": "ความคิดเห็นถูกโพสต์แล้ว กำลังรอการตรวจสอบ", + "success": "ความคิดเห็นถูกโพสต์แล้ว" + } + } +} diff --git a/locales/th.schema.json b/locales/th.schema.json new file mode 100644 index 000000000..01cd62c98 --- /dev/null +++ b/locales/th.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "ขอบ", + "collapsible_row": "แถวที่ย่อได้", + "colors": "สี", + "custom_section": "ส่วนที่กำหนดเอง", + "icon": "ไอคอน", + "logo_and_favicon": "โลโก้และ Favicon", + "overlapping_blocks": "บล็อกที่ซ้อนทับกัน", + "product_buy_buttons": "ปุ่มซื้อ", + "product_description": "คำอธิบาย", + "product_price": "ราคา", + "product_variant_picker": "รายการตัวเลือกสินค้า", + "slideshow": "สไลด์โชว์", + "typography": "ตัวพิมพ์", + "video": "วิดีโอ", + "slideshow_controls": "การควบคุมสไลด์โชว์", + "size": "ขนาด", + "spacing": "การเว้นระยะห่าง", + "product_recommendations": "สินค้าที่แนะนำ", + "product_media": "สื่อประกอบสินค้า", + "featured_collection": "คอลเลกชันเด่น", + "add_to_cart": "เพิ่มลงในตะกร้าสินค้า", + "email_signup": "การลงทะเบียนอีเมล", + "submit_button": "ปุ่มส่ง", + "grid_layout_selector": "ตัวเลือกเลย์เอาต์แบบกริด", + "image": "รูปภาพ", + "list_items": "สินค้าในรายการ", + "facets": "ส่วน", + "variants": "ตัวเลือกสินค้า", + "styles": "สไตล์", + "product_cards": "การ์ดข้อมูลสินค้า", + "buttons": "ปุ่ม", + "inputs": "อินพุต", + "primary_button": "ปุ่มหลัก", + "secondary_button": "ปุ่มรอง", + "popovers": "ป๊อปโอเวอร์", + "pull_quote": "ข้อความโดดเด่น", + "contact_form": "แบบฟอร์มการติดต่อ", + "featured_product": "จุดเด่นของสินค้า", + "icons_with_text": "ไอคอนที่มีข้อความ", + "marquee": "ข้อความวิ่ง", + "accelerated_checkout": "การชำระเงินอย่างรวดเร็ว", + "accordion": "แอคคอร์เดียน", + "accordion_row": "แถวแบบแอคคอร์เดียน", + "animations": "ภาพเคลื่อนไหว", + "announcement": "การประกาศ", + "announcement_bar": "แถบประกาศ", + "badges": "เครื่องหมาย", + "button": "ปุ่ม", + "cart": "ตะกร้าสินค้า", + "cart_items": "รายการในตะกร้าสินค้า", + "cart_products": "สินค้าในตะกร้าสินค้า", + "cart_title": "ตะกร้าสินค้า", + "collection": "คอลเลกชัน", + "collection_card": "บัตรคอลเลกชัน", + "collection_columns": "คอลัมน์คอลเลกชัน", + "collection_container": "คอลเลกชัน", + "collection_description": "คำอธิบายคอลเลกชัน", + "collection_image": "รูปภาพคอลเลกชัน", + "collection_info": "ข้อมูลคอลเลกชัน", + "collection_list": "รายการคอลเลกชัน", + "collections": "คอลเลกชัน", + "collections_bento": "รายการคอลเลกชัน: Bento", + "collections_carousel": "รายการคอลเลกชัน: ภาพสไลด์", + "collections_grid": "รายการคอลเลกชัน: กริด", + "content": "เนื้อหา", + "content_grid": "กริดเนื้อหา", + "details": "รายละเอียด", + "divider": "ตัวแบ่ง", + "divider_section": "ตัวแบ่ง", + "faq_section": "คำถามที่พบบ่อย", + "filters": "การกรองและการจัดเรียง", + "follow_on_shop": "ติดตามบน Shop", + "footer": "ส่วนท้าย", + "footer_utilities": "เครื่องมือสำหรับส่วนท้าย", + "group": "กลุ่ม", + "header": "ส่วนหัว", + "heading": "หัวเรื่อง", + "hero": "Hero", + "icons": "ไอคอน", + "image_with_text": "รูปภาพพร้อมข้อความ", + "input": "อินพุต", + "logo": "โลโก้", + "magazine_grid": "กริดนิตยสาร", + "media": "สื่อ", + "menu": "เมนู", + "mobile_layout": "เลย์เอาต์สำหรับมือถือ", + "payment_icons": "ไอคอนการชำระเงิน", + "popup_link": "ลิงค์ป๊อปอัพ", + "predictive_search": "ค้นหาป๊อปโอเวอร์", + "predictive_search_empty": "การค้นหาที่คาดการณ์ว่างเปล่า", + "price": "ราคา", + "product": "สินค้า", + "product_card": "บัตรสินค้า", + "product_card_media": "สื่อ", + "product_card_rendering": "การแสดงบัตรสินค้า", + "product_grid": "กริด", + "product_grid_main": "กริดสินค้า", + "product_image": "รูปภาพสินค้า", + "product_information": "ข้อมูลสินค้า", + "product_review_stars": "ดาวรีวิว", + "quantity": "ปริมาณ", + "row": "แถว", + "search": "การค้นหา", + "section": "ส่วน", + "selected_variants": "ตัวเลือกสินค้าที่เลือก", + "shop_the_look": "ช้อปตามลุคนี้", + "slide": "สไลด์", + "social_media_links": "ลิงก์โซเชียลมีเดีย", + "steps": "ขั้นตอน", + "summary": "ข้อมูลสรุป", + "swatches": "ตัวอย่าง", + "testimonials": "คำชมจากลูกค้า", + "text": "ข้อความ", + "title": "ชื่อ", + "utilities": "สาธารณูปโภค", + "video_section": "วิดีโอ", + "alternating_content_rows": "แถวสลับสี", + "products_carousel": "คอลเลกชันแนะนำ: ภาพสไลด์", + "products_grid": "คอลเลกชันแนะนำ: กริด", + "spacer": "ตัวเว้นวรรค", + "jumbo_text": "ข้อความขนาดใหญ่มาก", + "product_list": "คอลเลกชันแนะนำ", + "search_input": "ค้นหาอินพุต", + "search_results": "ผลลัพธ์การค้นหา", + "read_only": "อ่านอย่างเดียว", + "collection_title": "ชื่อคอลเลกชัน", + "view_all_button": "ดูทั้งหมด", + "page_layout": "เลย์เอาต์ของหน้า", + "product_title": "ชื่อสินค้า", + "custom_liquid": "Liquid แบบกำหนดเอง", + "blog": "บล็อก", + "blog_post": "บล็อกโพสต์", + "blog_posts": "โพสต์บล็อก", + "caption": "คำบรรยาย", + "collection_card_image": "รูปภาพ", + "collection_links": "ลิงก์คอลเลกชัน", + "collection_links_spotlight": "ลิงก์คอลเลกชัน: รายการที่นิยม", + "collection_links_text": "ลิงก์คอลเลกชัน: ข้อความ", + "collections_editorial": "รายการคอลเลกชัน: นิตยสาร", + "copyright": "ลิขสิทธิ์", + "count": "จำนวน", + "drawers": "แถบตัวเลือกแบบซ่อนได้", + "editorial": "รูปแบบบทความ", + "editorial_jumbo_text": "รูปแบบบทความ: ข้อความขนาดใหญ่", + "hero_marquee": "ส่วนแสดงหลัก: ข้อความเลื่อน", + "input_fields": "ฟิลด์ป้อนข้อมูล", + "local_pickup": "การรับสินค้าที่ร้าน", + "marquee_section": "ข้อความเลื่อน", + "media_with_text": "สื่อที่มีข้อความ", + "page": "หน้า", + "page_content": "เนื้อหา", + "policy_list": "ลิงก์นโยบาย", + "prices": "ราคา", + "product_list_button": "ดูปุ่มทั้งหมด", + "products_editorial": "คอลเลกชันแนะนำ: นิตยสาร", + "product_inventory": "สินค้าคงคลัง", + "social_link": "ลิงก์โซเชียลมีเดีย", + "split_showcase": "การแสดงผลแบบแบ่งส่วน", + "variant_pickers": "รายการตัวเลือกสินค้า", + "pills": "ทรงเม็ดยา", + "large_logo": "โลโก้ขนาดใหญ่", + "description": "คำอธิบาย" + }, + "settings": { + "alignment": "การจัดแนว", + "autoplay": "เล่นอัตโนมัติ", + "background": "พื้นหลัง", + "border_radius": "รัศมีมุม", + "border_width": "ความหนาของขอบ", + "borders": "ขอบ", + "bottom_padding": "พื้นที่ว่างด้านล่าง", + "button": "ปุ่ม", + "color": "สี", + "colors": "สี", + "content_alignment": "การจัดวางเนื้อหา", + "content_direction": "แนวหน้ากระดาษของเนื้อหา", + "content_position": "ตำแหน่งของเนื้อหา", + "cover_image_size": "ขนาดรูปภาพหน้าปก", + "cover_image": "รูปภาพหน้าปก", + "custom_minimum_height": "ความสูงขั้นต่ำแบบกำหนดเอง", + "custom_width": "ความกว้างแบบกำหนดเอง", + "enable_video_looping": "การวนซ้ำวิดีโอ", + "favicon": "Favicon", + "font_family": "ตระกูลแบบอักษร", + "gap": "ช่องว่าง", + "geometric_translate_y": "แปล Y ในทางเรขาคณิต", + "heading": "หัวเรื่อง", + "icon": "ไอคอน", + "image": "รูปภาพ", + "image_icon": "ไอคอนรูปภาพ", + "image_opacity": "ความทึบของรูปภาพ", + "image_position": "ตำแหน่งรูปภาพ", + "image_ratio": "อัตราส่วนรูปภาพ", + "label": "ป้ายกำกับ", + "line_height": "ความสูงของเส้น", + "link": "ลิงก์", + "layout_gap": "ช่องว่างของเลย์เอาต์", + "make_section_full_width": "ทำส่วนให้เป็นแบบเต็มความกว้าง", + "minimum_height": "ความสูงขั้นต่ำ", + "opacity": "ความทึบ", + "overlay_opacity": "ความทึบของการวางซ้อน", + "padding": "ระยะห่าง", + "primary_color": "ลิงก์", + "product": "สินค้า", + "section_width": "ความกว้างของส่วน", + "size": "ขนาด", + "slide_spacing": "ช่องว่างสไลด์", + "slide_width": "ความกว้างของสไลด์", + "slideshow_fullwidth": "สไลด์ที่ใช้ความกว้างเต็มหน้า", + "style": "รูปแบบ", + "text": "ข้อความ", + "text_case": "เคส", + "top_padding": "พื้นที่ว่างด้านบน", + "video": "วิดีโอ", + "video_alt_text": "ข้อความแสดงแทน", + "video_loop": "การวนซ้ำวิดีโอ", + "video_position": "ตำแหน่งวิดีโอ", + "width": "ความกว้าง", + "z_index": "ดัชนี Z", + "limit_content_width": "จำกัดความกว้างของเนื้อหา", + "color_scheme": "รูปแบบสี", + "inherit_color_scheme": "นำรูปแบบสีก่อนหน้ามาใช้", + "product_count": "จำนวนสินค้า", + "product_type": "ประเภทสินค้า", + "content_width": "ความกว้างของเนื้อหา", + "collection": "คอลเลกชัน", + "enable_sticky_content": "เนื้อหาแบบติดบนเดสก์ท็อป", + "error_color": "ข้อผิดพลาด", + "success_color": "สำเร็จ", + "primary_font": "แบบอักษรหลัก", + "secondary_font": "แบบอักษรรอง", + "tertiary_font": "แบบอักษรตติยภูมิ", + "columns": "จำนวนคอลัมน์", + "items_to_show": "รายการสินค้าที่จะแสดง", + "layout": "เลย์เอาต์", + "layout_type": "ประเภท", + "show_grid_layout_selector": "แสดงตัวเลือกเลย์เอาต์แบบกริด", + "view_more_show": "แสดงปุ่มดูเพิ่มเติม", + "image_gap": "ช่องว่างระหว่างรูปภาพ", + "width_desktop": "ความกว้างของเดสก์ท็อป", + "width_mobile": "ความกว้างของมือถือ", + "border_style": "สไตล์ขอบ", + "height": "ความสูง", + "thickness": "ความหนา", + "stroke": "เส้น", + "filter_style": "สไตล์ของตัวกรอง", + "swatches": "ตัวอย่าง", + "quick_add_colors": "ระบุสีอย่างง่าย", + "divider_color": "ตัวแบ่ง", + "border_opacity": "ความทึบของขอบ", + "hover_background": "พื้นหลังเมื่อวางเมาส์", + "hover_borders": "ขอบเมื่อวางเมาส์", + "hover_text": "ข้อความเมื่อวางเมาส์", + "primary_hover_color": "ลิงก์เมื่อวางเมาส์", + "primary_button_text": "ข้อความของปุ่มหลัก", + "primary_button_background": "พื้นหลังของปุ่มหลัก", + "primary_button_border": "ขอบของปุ่มหลัก", + "secondary_button_text": "ข้อความของปุ่มรอง", + "secondary_button_background": "พื้นหลังของปุ่มรอง", + "secondary_button_border": "ขอบของปุ่มรอง", + "shadow_color": "เงา", + "video_autoplay": "เล่นอัตโนมัติ", + "video_cover_image": "รูปภาพหน้าปก", + "video_external_url": "URL", + "video_source": "แหล่งที่มา", + "accordion": "แอคคอร์เดียน", + "aspect_ratio": "อัตราส่วนภาพ", + "auto_rotate_announcements": "เปลี่ยนประกาศอัตโนมัติ", + "auto_rotate_slides": "หมุนสไลด์อัตโนมัติ", + "badge_corner_radius": "รัศมีมุม", + "badge_position": "ตำแหน่งบนบัตร", + "badge_sale_color_scheme": "ลดราคา", + "badge_sold_out_color_scheme": "ขายหมดแล้ว", + "behavior": "พฤติกรรม", + "blur": "การเบลอเงา", + "border": "ขอบ", + "bottom": "ด้านล่าง", + "carousel_on_mobile": "ภาพสไลด์บนมือถือ", + "cart_count": "จำนวนตะกร้าสินค้า", + "cart_items": "รายการสินค้าในตะกร้า", + "cart_related_products": "สินค้าที่เกี่ยวข้อง", + "cart_title": "ตะกร้าสินค้า", + "cart_total": "ยอดรวมตะกร้าสินค้า", + "cart_type": "ประเภท", + "case": "เคส", + "checkout_buttons": "ปุ่มชำระเงินแบบเร่งด่วน", + "collection_list": "คอลเลกชัน", + "collection_templates": "เทมเพลตคอลเลกชัน", + "content": "เนื้อหา", + "corner_radius": "รัศมีมุม", + "country_region": "ประเทศ/ภูมิภาค", + "currency_code": "รหัสสกุลเงิน", + "custom_height": "ความสูงที่กำหนดเอง", + "desktop_height": "ความสูงของเดสก์ท็อป", + "direction": "ทิศทาง", + "display": "การแสดงผล", + "divider": "ตัวแบ่ง", + "divider_thickness": "ความหนาของตัวแบ่ง", + "dividers": "ตัวแบ่ง", + "drop_shadow": "เงาตกกระทบ", + "empty_state_collection": "คอลเลกชันสถานะว่าง", + "empty_state_collection_info": "แสดงก่อนที่จะป้อนการค้นหา", + "enable_filtering": "ตัวกรอง", + "enable_grid_density": "การควบคุมเลย์เอาต์แบบกริด", + "enable_sorting": "การจัดเรียง", + "enable_zoom": "เปิดใช้งานการซูม", + "equal_columns": "คอลัมน์เท่ากัน", + "expand_first_group": "ขยายกลุ่มแรก", + "extend_media_to_screen_edge": "ขยายสื่อถึงขอบหน้าจอ", + "extend_summary": "ขยายไปถึงขอบหน้าจอ", + "extra_large": "ใหญ่พิเศษ", + "extra_small": "เล็กพิเศษ", + "flag": "ธง", + "font": "แบบอักษร", + "font_price": "แบบอักษรราคา", + "font_weight": "ความหนาตัวอักษร", + "full_width_first_image": "ภาพแรกเต็มความกว้าง", + "full_width_on_mobile": "เต็มความกว้างบนมือถือ", + "heading_preset": "ส่วนหัวที่ตั้งไว้ล่วงหน้า", + "hide_unselected_variant_media": "ซ่อนสื่อของตัวเลือกสินค้าที่ไม่ได้เลือก", + "horizontal_gap": "ช่องว่างแนวนอน", + "horizontal_offset": "ออฟเซตเงาแนวนอน", + "hover_behavior": "พฤติกรรมเมื่อวางเมาส์", + "icon_background": "พื้นหลังไอคอน", + "icons": "ไอคอน", + "image_border_radius": "รัศมีมุมภาพ", + "installments": "การผ่อนชำระ", + "integrated_button": "ปุ่มที่ผสานการทำงาน", + "language_selector": "ตัวเลือกภาษา", + "large": "ใหญ่", + "left": "ด้านซ้าย", + "left_padding": "พื้นที่ว่างด้านซ้าย", + "letter_spacing": "ระยะห่างตัวอักษร", + "limit_media_to_screen_height": "จำกัดความสูงของหน้าจอ", + "limit_product_details_width": "จำกัดความกว้างของรายละเอียดสินค้า", + "link_preset": "ลิงก์ที่ตั้งไว้ล่วงหน้า", + "links": "ลิงก์", + "logo": "โลโก้", + "loop": "ลูป", + "make_details_sticky_desktop": "ติดบนเดสก์ท็อป", + "max_width": "ความกว้างสูงสุด", + "media_height": "ความสูงของสื่อ", + "media_overlay": "การวางซ้อนสื่อ", + "media_position": "ตำแหน่งสื่อ", + "media_type": "ประเภทสื่อ", + "media_width": "ความกว้างของสื่อ", + "menu": "เมนู", + "mobile_columns": "คอลัมน์ในมือถือ", + "mobile_height": "ความสูงในมือถือ", + "mobile_logo_image": "โลโก้บนมือถือ", + "mobile_quick_add": "เพิ่มด่วนบนมือถือ", + "motion": "การเคลื่อนไหว", + "motion_direction": "ทิศทางการเคลื่อนไหว", + "movement_direction": "ทิศทางการเคลื่อนย้าย", + "navigation": "การนำทาง", + "navigation_bar": "แถบนำทาง", + "navigation_bar_color_scheme": "รูปแบบสีของแถบนำทาง", + "open_new_tab": "เปิดลิงก์ในแท็บใหม่", + "overlay": "การวางซ้อน", + "overlay_color": "สีซ้อนทับ", + "padding_bottom": "ระยะห่างด้านล่าง", + "padding_horizontal": "ระยะห่างแนวนอน", + "padding_top": "ระยะห่างด้านบน", + "page_width": "ความกว้างของหน้า", + "pagination": "การแบ่งหน้า", + "placement": "การจัดวาง", + "position": "ตำแหน่ง", + "preset": "ค่าที่ตั้งไว้ล่วงหน้า", + "product_cards": "บัตรสินค้า", + "product_pages": "หน้าสินค้า", + "product_templates": "เทมเพลตสินค้า", + "products": "สินค้า", + "quick_add": "เพิ่มด่วน", + "ratio": "อัตราส่วน", + "regular": "ตัวปกติ", + "review_count": "จำนวนรีวิว", + "right": "ด้านขวา", + "row": "แถว", + "row_height": "ความสูงของแถว", + "seller_note": "อนุญาตให้แจ้งผู้ขาย", + "shape": "รูปทรง", + "show": "แสดง", + "show_as_accordion": "แสดงเป็นแอคคอร์เดียนบนมือถือ", + "show_filter_label": "ป้ายกำกับข้อความสำหรับตัวกรองที่ใช้", + "show_sale_price_first": "แสดงราคาโปรโมชันก่อน", + "show_swatch_label": "ป้ายกำกับข้อความสำหรับตัวอย่าง", + "show_tax_info": "ข้อมูลภาษี", + "small": "เล็ก", + "speed": "ความเร็ว", + "statement": "ใบแจ้งยอด", + "sticky_header": "ส่วนหัวแบบยึดตำแหน่ง", + "text_hierarchy": "ลำดับขั้นของข้อความ", + "text_presets": "การตั้งข้อความไว้ล่วงหน้า", + "title": "ชื่อ", + "top": "ด้านบน", + "type": "ประเภท", + "type_preset": "การตั้งข้อความไว้ล่วงหน้า", + "underline_thickness": "ความหนาของขีดเส้นใต้", + "variant_images": "รูปภาพตัวเลือกสินค้า", + "vendor": "ผู้ขาย", + "vertical_gap": "ช่องว่างแนวตั้ง", + "vertical_offset": "ออฟเซตเงาแนวตั้ง", + "vertical_on_mobile": "แนวตั้งบนมือถือ", + "view_all_as_last_card": "\"ดูทั้งหมด\" เป็นการ์ดสุดท้าย", + "weight": "น้ำหนัก", + "wrap": "ตัดบรรทัด", + "first_row_media_position": "ตำแหน่งของสื่อในแถวแรก", + "card_image_height": "ความสูงของรูปภาพสินค้า", + "background_color": "สีพื้นหลัง", + "size_mobile": "ขนาดมือถือ", + "pixel_size_mobile": "ขนาดพิกเซล", + "percent_size_mobile": "ขนาดเปอร์เซ็นต์", + "unit": "หน่วย", + "custom_mobile_size": "ขนาดมือถือแบบกำหนดเอง", + "fixed_height": "ความสูงพิกเซล", + "fixed_width": "ความกว้างพิกเซล", + "percent_height": "ความสูงเปอร์เซ็นต์", + "percent_width": "ความกว้างเปอร์เซ็นต์", + "percent_size": "ขนาดเปอร์เซ็นต์", + "pixel_size": "ขนาดพิกเซล", + "always_stack_buttons": "เรียงปุ่มซ้อนกันเสมอ", + "custom_mobile_width": "ความกว้างของมือถือแบบกำหนดเอง", + "shadow_opacity": "ความทึบของเงา", + "hide_padding": "ซ่อนระยะห่าง", + "logo_font": "แบบอักษรโลโก้", + "read_only": "อ่านอย่างเดียว", + "gradient_direction": "ทิศทางการไล่ระดับ", + "headings": "หัวเรื่อง", + "overlay_style": "รูปแบบการวางซ้อน", + "transparent_background": "พื้นหลังโปร่งใส", + "account": "บัญชีผู้ใช้", + "alignment_mobile": "การจัดวางบนมือถือ", + "align_baseline": "จัดแนวเส้นฐานข้อความ", + "add_discount_code": "อนุญาตให้ใช้ส่วนลดในตะกร้าสินค้า", + "background_overlay": "การวางซ้อนพื้นหลัง", + "background_media": "สื่อพื้นหลัง", + "border_thickness": "ความหนาของขอบ", + "bottom_row": "แถวล่าง", + "button_text_case": "ตัวอักษรของข้อความ", + "button_text_weight": "น้ำหนักของข้อความ", + "card_size": "ขนาดบัตร", + "auto_open_cart_drawer": "เมื่อ \"เพิ่มลงในตะกร้าสินค้า\" ลิ้นชักจะเปิดโดยอัตโนมัติ", + "collection_count": "จำนวนคอลเลกชัน", + "custom_liquid": "โค้ด Liquid", + "default": "ค่าเริ่มต้น", + "default_logo": "โลโก้เริ่มต้น", + "divider_width": "ความกว้างของตัวแบ่ง", + "hide_logo_on_home_page": "ซ่อนโลโก้ในหน้าหลัก", + "horizontal_padding": "ระยะขอบแนวนอน", + "inventory_threshold": "เกณฑ์สินค้าในสต็อกเหลือน้อย", + "inverse": "กลับสี", + "inverse_logo": "โลโก้กลับสี", + "layout_style": "รูปแบบ", + "length": "ความยาว", + "mobile_card_size": "ขนาดบัตรสำหรับมือถือ", + "mobile_pagination": "การแบ่งหน้าบนมือถือ", + "open_row_by_default": "เปิดแถวตามค่าเริ่มต้น", + "page": "หน้า", + "page_transition_enabled": "การเปลี่ยนหน้า", + "right_padding": "พื้นที่ว่างด้านขวา", + "search": "ค้นหา", + "search_icon": "ไอคอนค้นหา", + "search_position": "ตำแหน่ง", + "search_row": "แถว", + "show_author": "ผู้เขียน", + "show_alignment": "แสดงการจัดแนว", + "show_count": "แสดงจำนวน", + "show_date": "วันที่", + "show_inventory_quantity": "แสดงจำนวนสินค้าในสต็อกเหลือน้อย", + "show_pickup_availability": "แสดงความพร้อมในการรับสินค้า", + "show_search": "แสดงการค้นหา", + "use_inverse_logo": "ใช้โลโก้กลับสี", + "vertical_padding": "ระยะขอบแนวตั้ง", + "visibility": "การแสดงผล", + "product_corner_radius": "รัศมีมุมผลิตภัณฑ์", + "card_corner_radius": "รัศมีมุมบัตร", + "animation_repeat": "ทำซ้ำภาพเคลื่อนไหว", + "blurred_reflection": "ภาพสะท้อนที่เบลอ", + "card_hover_effect": "เอฟเฟ็กต์เมื่อวางเมาส์ที่บัตร", + "collection_title_case": "เคสชื่อคอลเลกชัน", + "effects": "เอฟเฟ็กต์", + "product_and_card_title_case": "เคสชื่อสินค้าและชื่อบัตร", + "product_title_case": "เคสชื่อสินค้า", + "reflection_opacity": "ความทึบแสงของภาพสะท้อน", + "text_label_case": "เคสป้ายกำกับข้อความ", + "transition_to_main_product": "การเปลี่ยนจากบัตรสินค้าไปยังหน้าสินค้า", + "show_second_image_on_hover": "แสดงรูปภาพที่สองเมื่อนำเมาส์ไปวาง", + "media": "สื่อ", + "product_card_carousel": "แสดงภาพสไลด์", + "media_fit": "ปรับขนาดสื่อให้พอดี", + "scroll_speed": "ระยะเวลาจนถึงการประกาศครั้งถัดไป" + }, + "options": { + "adapt_to_image": "ปรับตามรูปภาพ", + "apple": "แอปเปิ้ล", + "arrow": "ลูกศร", + "auto": "อัตโนมัติ", + "banana": "กล้วย", + "bottle": "ขวด", + "box": "กล่อง", + "buttons": "ปุ่ม", + "carrot": "แครอท", + "center": "กึ่งกลาง", + "chat_bubble": "ช่องแชท", + "clipboard": "คลิปบอร์ด", + "contain": "ประกอบด้วย", + "counter": "ตัวนับ", + "cover": "หน้าปก", + "custom": "กำหนดเอง", + "dairy_free": "ปราศจากผลิตภัณฑ์นม", + "dairy": "ผลิตภัณฑ์นม", + "default": "ค่าเริ่มต้น", + "dropdowns": "ดรอปดาวน์", + "dots": "จุด", + "dryer": "เครื่องเป่า", + "end": "สิ้นสุด", + "eye": "ดวงตา", + "facebook": "Facebook", + "fill": "การเติมสี", + "fire": "ไฟ", + "fit": "ความแน่นหลวม", + "full": "เต็ม", + "full_and_page": "พื้นหลังแบบเต็ม เนื้อหาที่พอดีกับความกว้างของหน้า", + "gluten_free": "ปราศจากกลูเตน", + "heading": "หัวเรื่อง", + "heart": "หัวใจ", + "horizontal": "แนวนอน", + "instagram": "Instagram", + "iron": "เหล็ก", + "landscape": "แนวนอน", + "large": "ใหญ่", + "leaf": "ใบไม้", + "leather": "หนัง", + "lg": "L", + "lightning_bolt": "สายฟ้า", + "link": "ลิงก์", + "lipstick": "ลิปสติก", + "lock": "ล็อก", + "lowercase": "ตัวอักษรพิมพ์เล็ก", + "m": "M", + "map_pin": "หมุดแผนที่", + "medium": "ปานกลาง", + "none": "ไม่มี", + "numbers": "ตัวเลข", + "nut_free": "ปราศจากถั่ว", + "outline": "เส้นขอบ", + "page": "หน้า", + "pants": "กางเกง", + "paw_print": "รอยเท้าสัตว์", + "pepper": "พริกไทย", + "perfume": "น้ำหอม", + "pinterest": "Pinterest", + "plane": "เครื่องบิน", + "plant": "ต้นไม้", + "portrait": "แนวตั้ง", + "price_tag": "ป้ายราคา", + "question_mark": "เครื่องหมายคำถาม", + "recycle": "รีไซเคิล", + "return": "ย้อนกลับ", + "ruler": "ไม้บรรทัด", + "s": "S", + "sentence": "ประโยค", + "serving_dish": "จานเสิร์ฟ", + "shirt": "เสื้อเชิ้ต", + "shoe": "รองเท้า", + "silhouette": "ภาพเงา", + "small": "เล็ก", + "snapchat": "Snapchat", + "snowflake": "เกล็ดหิมะ", + "solid": "ทึบ", + "space_between": "ช่องว่างระหว่างกัน", + "square": "จัตุรัส", + "star": "ดาว", + "start": "เริ่ม", + "stopwatch": "นาฬิกาจับเวลา", + "tiktok": "TikTok", + "truck": "รถบรรทุก", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "ตัวพิมพ์ใหญ่", + "vertical": "แนวตั้ง", + "vimeo": "Vimeo", + "washing": "การล้าง", + "circle": "วงกลม", + "swatches": "ตัวอย่าง", + "full_and_page_offset_left": "พื้นหลังแบบเต็ม เนื้อหาที่พอดีกับความกว้างของหน้า และออฟเซตด้านซ้าย", + "full_and_page_offset_right": "พื้นหลังแบบเต็ม เนื้อหาที่พอดีกับความกว้างของหน้า และออฟเซตด้านขวา", + "offset_left": "ออฟเซตด้านซ้าย", + "offset_right": "ออฟเซตด้านขวา", + "page_center_aligned": "หน้า จัดกึ่งกลาง", + "page_left_aligned": "หน้า จัดชิดซ้าย", + "page_right_aligned": "หน้า จัดชิดขวา", + "button": "ปุ่ม", + "caption": "คำบรรยาย", + "h1": "หัวเรื่อง 1", + "h2": "หัวเรื่อง 2", + "h3": "หัวเรื่อง 3", + "h4": "หัวเรื่อง 4", + "h5": "หัวเรื่อง 5", + "h6": "หัวเรื่อง 6", + "paragraph": "ย่อหน้า", + "primary": "หลัก", + "secondary": "สำรอง", + "tertiary": "ตติยภูมิ", + "chevron_left": "บั้งชี้ไปทางซ้าย", + "chevron_right": "บั้งชี้ไปทางขวา", + "diamond": "เพชร", + "grid": "กริด", + "parallelogram": "สี่เหลี่ยมด้านขนาน", + "rounded": "โค้งมน", + "fit_content": "พอดี", + "pills": "ทรงเม็ดยา", + "heavy": "หนา", + "thin": "บาง", + "drawer": "แถบตัวเลือกแบบซ่อนได้", + "preview": "ดูตัวอย่าง", + "text": "ข้อความ", + "video_uploaded": "อัปโหลดแล้ว", + "video_external_url": "URL ภายนอก", + "above_carousel": "ภาพสไลด์ด้านบน", + "all": "ทั้งหมด", + "always": "แสดงเสมอ", + "arrows": "ลูกศร", + "arrows_large": "ลูกศรขนาดใหญ่", + "balance": "ยอดคงเหลือ", + "bento": "เบนโตะ", + "black": "สีดำ", + "bluesky": "Bluesky", + "body_large": "เนื้อหา (ใหญ่)", + "body_regular": "เนื้อหา (ปกติ)", + "body_small": "เนื้อหา (เล็ก)", + "bold": "ตัวหนา", + "bottom": "ด้านล่าง", + "bottom_left": "ซ้ายล่าง", + "bottom_right": "ขวาล่าง", + "capitalize": "ใช้ตัวพิมพ์ใหญ่", + "caret": "แคเร็ต", + "carousel": "ภาพสไลด์", + "check_box": "ช่องกาเครื่องหมาย", + "chevron": "ลูกศรชี้ลง", + "chevron_large": "ลูกศรชี้ลงขนาดใหญ่", + "chevrons": "ลูกศรชี้ลง", + "classic": "คลาสสิก", + "collection_images": "รูปภาพคอลเลกชัน", + "color": "สี", + "complementary": "สินค้าเสริม", + "dissolve": "แบบละลาย", + "dotted": "แบบจุด", + "editorial": "นิตยสาร", + "extra_large": "ขนาดใหญ่พิเศษ", + "extra_small": "เล็กพิเศษ", + "featured_collections": "คอลเลกชันแนะนำ", + "featured_products": "สินค้าที่แนะนำ", + "font_primary": "หลัก", + "font_secondary": "สำรอง", + "font_tertiary": "ตติยภูมิ", + "forward": "ต่อไป", + "full_screen": "โหมดเต็มหน้าจอ", + "heading_extra_large": "ส่วนหัว (ใหญ่พิเศษ)", + "heading_extra_small": "ส่วนหัว (เล็กพิเศษ)", + "heading_large": "ส่วนหัว (ใหญ่)", + "heading_regular": "ส่วนหัว (ปกติ)", + "heading_small": "ส่วนหัว (เล็ก)", + "icon": "ไอคอน", + "image": "รูปภาพ", + "input": "อินพุต", + "inside_carousel": "ภายในภาพสไลด์", + "inverse": "กลับด้าน", + "inverse_large": "กลับด้าน ขนาดใหญ่", + "large_arrows": "ลูกศรขนาดใหญ่", + "large_chevrons": "ลูกศรชี้ลงขนาดใหญ่", + "left": "ด้านซ้าย", + "light": "ตัวบาง", + "linkedin": "LinkedIn", + "loose": "หลวม", + "media_first": "สื่ออันดับแรก", + "media_second": "สื่ออันดับสอง", + "modal": "โมดอล", + "narrow": "แคบ", + "never": "ไม่แสดง", + "next_to_carousel": "ข้างภาพสไลด์", + "normal": "ปกติ", + "nowrap": "ไม่ต้องตัดข้อความ", + "off_media": "อยู่นอกสื่อ", + "on_media": "อยู่บนสื่อ", + "on_scroll_up": "เมื่อเลื่อนขึ้น", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "ทรงเม็ดยา", + "plus": "Plus", + "pretty": "สวยงาม", + "price": "ราคา", + "primary_style": "สไตล์หลัก", + "rectangle": "สี่เหลี่ยมผืนผ้า", + "regular": "ตัวปกติ", + "related": "ที่เกี่ยวข้อง", + "reverse": "ย้อนกลับ", + "rich_text": "ข้อความที่มีรูปแบบ", + "right": "ด้านขวา", + "secondary_style": "สไตล์รอง", + "semibold": "กึ่งหนา", + "shaded": "แรเงา", + "show_second_image": "แสดงภาพที่สอง", + "single": "แบบเดี่ยว", + "slide_left": "ไปสไลด์ซ้าย", + "slide_up": "สไลด์ขึ้น", + "spotify": "Spotify", + "stack": "ซ้อน", + "text_only": "ข้อความเท่านั้น", + "threads": "Threads", + "thumbnails": "รูปภาพขนาดย่อ", + "tight": "แน่น", + "top": "ด้านบน", + "top_left": "ซ้ายบน", + "top_right": "ขวาบน", + "two_number": "2", + "two_thirds": "2/3", + "underline": "ขีดเส้นใต้", + "video": "วิดีโอ", + "wide": "กว้าง", + "youtube": "YouTube", + "aspect_ratio": "อัตราส่วนภาพ", + "up": "ขึ้น", + "down": "ลง", + "gradient": "การไล่ระดับสี", + "fixed": "แบบคงที่", + "pixel": "พิกเซล", + "percent": "เปอร์เซ็นต์", + "below_image": "ด้านล่างของภาพ", + "on_image": "บนภาพ", + "accent": "การเน้น", + "body": "เนื้อหา", + "button_primary": "ปุ่มหลัก", + "button_secondary": "ปุ่มรอง", + "compact": "กะทัดรัด", + "crop_to_fit": "ครอบตัดให้พอดี", + "hidden": "ซ่อน", + "hint": "คำใบ้", + "maintain_aspect_ratio": "รักษาอัตราส่วนภาพ", + "off": "ปิด", + "social_bluesky": "โซเชียล: Bluesky", + "social_facebook": "โซเชียล: Facebook", + "social_instagram": "โซเชียล: Instagram", + "social_linkedin": "โซเชียล: LinkedIn", + "social_pinterest": "โซเชียล: Pinterest", + "social_snapchat": "โซเชียล: Snapchat", + "social_spotify": "โซเชียล: Spotify", + "social_threads": "โซเชียล: Threads", + "social_tiktok": "โซเชียล: TikTok", + "social_tumblr": "โซเชียล: Tumblr", + "social_twitter": "โซเชียล: X (Twitter)", + "social_whatsapp": "โซเชียล: WhatsApp", + "social_vimeo": "โซเชียล: Vimeo", + "social_youtube": "โซเชียล: YouTube", + "spotlight": "รายการที่นิยม", + "standard": "มาตรฐาน", + "subheading": "หัวเรื่องย่อย", + "blur": "เบลอ", + "lift": "ยกนูน", + "reveal": "เปิดเผย", + "scale": "ขยายสเกล", + "subtle_zoom": "ซูม" + }, + "content": { + "advanced": "Advanced", + "background_image": "รูปภาพพื้นหลัง", + "background_video": "วิดีโอพื้นหลัง", + "block_size": "ขนาดบล็อก", + "borders": "ขอบ", + "describe_the_video_for": "อธิบายวิดีโอให้กับลูกค้าที่ใช้โปรแกรมอ่านหน้าจอ [ดูข้อมูลเพิ่มเติม](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "ขนาดส่วน", + "slideshow_width": "ความกว้างของสไลด์", + "typography": "ตัวพิมพ์", + "width_is_automatically_optimized": "ระบบจะปรับความกว้างให้เหมาะสมกับมือถือโดยอัตโนมัติ", + "complementary_products": "ต้องตั้งค่าสินค้าเสริมโดยใช้แอป Search & Discovery [ดูข้อมูลเพิ่มเติม](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "คอลัมน์จะปรับขนาดให้เหมาะสมกับมือถือโดยอัตโนมัติ", + "content_width": "ความกว้างของเนื้อหาจะสามารถใช้ได้เมื่อตั้งค่าความกว้างของส่วนเป็นเต็มความกว้าง", + "adjustments_affect_all_content": "นำไปใช้กับเนื้อหาทั้งหมดในบล็อกนี้", + "responsive_font_sizes": "ขนาดจะมีการปรับขยายสเกลให้เหมาะสมกับหน้าจอทุกขนาดโดยอัตโนมัติ", + "buttons": "ปุ่ม", + "swatches": "ตัวอย่าง", + "variant_settings": "การตั้งค่าตัวเลือกสินค้า", + "background": "พื้นหลัง", + "appearance": "รูปลักษณ์", + "arrows": "ลูกศร", + "body_size": "ขนาดของส่วนเนื้อหา", + "bottom_row_appearance": "รูปลักษณ์ของแถวล่าง", + "carousel_navigation": "การนำทางภาพสไลด์", + "carousel_pagination": "การแบ่งหน้าภาพสไลด์", + "copyright": "ลิขสิทธิ์", + "edit_logo_in_theme_settings": "แก้ไขโลโก้ใน [การตั้งค่าธีม](/editor?context=theme&category=logo%20and%20favicon)", + "edit_price_in_theme_settings": "แก้ไขการจัดรูปแบบราคาใน [การตั้งค่าธีม](/editor?context=theme&category=currency%20code)", + "edit_variants_in_theme_settings": "แก้ไขรูปแบบสไตล์ตัวเลือกสินค้าใน [การตั้งค่าธีม](/editor?context=theme&category=variants)", + "email_signups_create_customer_profiles": "เพิ่มการสมัครใช้งาน [โปรไฟล์ลูกค้า](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "หากต้องการให้ปุ่มแสดงขึ้นมา จะต้องติดตั้งช่องทาง Shop และเปิดใช้งาน Shop Pay [ดูข้อมูลเพิ่มเติม](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "แบบอักษร", + "grid": "กริด", + "heading_size": "ขนาดของส่วนหัว", + "image": "รูปภาพ", + "input": "อินพุต", + "layout": "เลย์เอาต์", + "link": "ลิงก์", + "link_padding": "ระยะห่างของลิงก์", + "localization": "การแปลเป็นภาษาท้องถิ่น", + "logo": "โลโก้", + "margin": "อัตรา", + "media": "สื่อ", + "media_1": "สื่อ 1", + "media_2": "สื่อ 2", + "menu": "เมนู", + "mobile_layout": "เลย์เอาต์สำหรับมือถือ", + "padding": "ระยะห่าง", + "padding_desktop": "ระยะห่างของเดสก์ท็อป", + "paragraph": "ย่อหน้า", + "policies": "นโยบาย", + "popup": "ป๊อปอัพ", + "search": "การค้นหา", + "size": "ขนาด", + "social_media": "โซเชียลมีเดีย", + "submit_button": "ปุ่มส่ง", + "text_presets": "การตั้งข้อความไว้ล่วงหน้า", + "transparent_background": "พื้นหลังโปร่งใส", + "typography_primary": "ตัวพิมพ์หลัก", + "typography_secondary": "ตัวพิมพ์รอง", + "typography_tertiary": "ตัวพิมพ์ตติยภูมิ", + "mobile_size": "ขนาดมือถือ", + "mobile_width": "ความกว้างของมือถือ", + "width": "ความกว้าง", + "cards_layout": "เลย์เอาต์บัตร", + "section_layout": "เลย์เอาต์ส่วน", + "visible_if_collection_has_more_products": "แสดงผลหากคอลเลกชันมีสินค้ามากกว่าที่แสดงไว้", + "carousel": "ภาพสไลด์", + "colors": "สี", + "collection_page": "หน้าคอลเลกชัน", + "copyright_info": "ดูวิธี [แก้ไขคำชี้แจงเกี่ยวกับลิขสิทธิ์](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "บัญชีผู้ใช้ของลูกค้า", + "edit_empty_state_collection_in_theme_settings": "แก้ไขคอลเลกชันสถานะว่างใน [การตั้งค่าธีม](/editor?context=theme&category=search)", + "grid_layout": "เลย์เอาต์แบบกริด", + "home_page": "หน้าแรก", + "images": "รูปภาพ", + "inverse_logo_info": "ใช้เมื่อพื้นหลังส่วนหัวแบบโปร่งใสถูกตั้งค่าเป็น กลับสี", + "manage_customer_accounts": "[จัดการการแสดงผล](/admin/settings/customer_accounts)ในการตั้งค่าบัญชีผู้ใช้ของลูกค้า ไม่รองรับบัญชีผู้ใช้แบบเดิม", + "manage_policies": "[จัดการนโยบาย](/admin/settings/legal)", + "product_page": "หน้าสินค้า", + "text": "ข้อความ", + "thumbnails": "รูปภาพขนาดย่อ", + "visibility": "การแสดงผล", + "app_required_for_ratings": "จำเป็นต้องมีแอปสำหรับการรีวิวสินค้า [ดูข้อมูลเพิ่มเติม](https://help.shopify.com/manual/apps)", + "icon": "ไอคอน", + "manage_store_name": "[จัดการชื่อร้านค้า](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "แสดงคอลเลกชันจากส่วนหลัก", + "resource_reference_collection_card_image": "แสดงภาพจากคอลเลกชันหลัก", + "resource_reference_collection_title": "แสดงชื่อจากคอลเลกชันหลัก", + "resource_reference_product": "เชื่อมต่อกับสินค้าหลักโดยอัตโนมัติ", + "resource_reference_product_card": "แสดงสินค้าจากส่วนหลัก", + "resource_reference_product_inventory": "แสดงสินค้าคงคลังจากสินค้าหลัก", + "resource_reference_product_price": "แสดงราคาจากสินค้าหลัก", + "resource_reference_product_recommendations": "แสดงการแนะนำตามสินค้าหลัก", + "resource_reference_product_review": "แสดงรีวิวจากสินค้าหลัก", + "resource_reference_product_swatches": "แสดงตัวอย่างจากสินค้าหลัก", + "resource_reference_product_title": "แสดงชื่อจากสินค้าหลัก", + "resource_reference_product_variant_picker": "แสดงตัวเลือกสินค้าจากสินค้าหลัก", + "product_media": "สื่อประกอบสินค้า", + "resource_reference_product_media": "แสดงสื่อจากสินค้าหลัก", + "section_link": "ลิงก์ไปยังส่วน" + }, + "html_defaults": { + "share_information_about_your": "

แชร์ข้อมูลเกี่ยวกับแบรนด์ของคุณให้ลูกค้าทราบ โดยอธิบายคุณสมบัติของสินค้า แชร์ประกาศ หรือกล่าวต้อนรับลูกค้าสู่ร้านค้าของคุณ

" + }, + "text_defaults": { + "button_label": "ซื้อสินค้า", + "collapsible_row": "แถวที่ย่อได้", + "heading": "หัวเรื่อง", + "email_signup_button_label": "สมัครใช้งาน", + "accordion_heading": "ส่วนหัวแบบแอคคอร์เดียน", + "contact_form_button_label": "ส่ง", + "popup_link": "ลิงค์ป๊อปอัพ", + "sign_up": "ลงทะเบียน", + "welcome_to_our_store": "ยินดีต้อนรับสู่ร้านค้าของเรา", + "be_bold": "โดดเด่น", + "shop_our_latest_arrivals": "ซื้อสินค้ามาใหม่ล่าสุดของเรา!" + }, + "info": { + "video_alt_text": "อธิบายวิดีโอสำหรับผู้ใช้เทคโนโลยีช่วยเหลือ", + "video_autoplay": "วิดีโอจะถูกปิดเสียงตามค่าเริ่มต้น", + "video_external": "ใช้ URL ของ YouTube หรือ Vimeo", + "carousel_layout_on_mobile": "ภาพสไลด์นำไปใช้บนมือถือ", + "link_info": "ตัวเลือกเสริม ทำให้ไอคอนสามารถคลิกได้", + "checkout_buttons": "ช่วยให้ผู้ซื้อชำระเงินได้เร็วขึ้นและสามารถปรับปรุงคอนเวอร์ชันได้ [ดูข้อมูลเพิ่มเติม](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "ส่วนหัวแบบกำหนดเอง", + "edit_presets_in_theme_settings": "แก้ไขค่าที่ตั้งไว้ล่วงหน้าใน [การตั้งค่าธีม](/editor?context=theme&category=typography)", + "enable_filtering_info": "ปรับแต่งตัวกรองด้วย [แอป Search & Discovery](https://help.shopify.com/manual/online-store/search-and-discovery/filters)", + "manage_countries_regions": "[จัดการประเทศ/ภูมิภาค](/admin/settings/markets)", + "manage_languages": "[จัดการภาษา](/admin/settings/languages)", + "transparent_background": "ตรวจสอบเทมเพลตแต่ละอันที่ใช้พื้นหลังโปร่งใสเพื่อให้สามารถอ่านได้", + "carousel_hover_behavior_not_supported": "ไม่รองรับการเลื่อนเมาส์ไปที่ \"ภาพสไลด์\" เมื่อเลือกประเภท \"ภาพสไลด์\" ในระดับส่วน", + "grid_layout_on_mobile": "เลย์เอาต์แบบกริดใช้สำหรับมือถือ", + "logo_font": "ใช้ได้เฉพาะเมื่อไม่ได้เลือกโลโก้", + "aspect_ratio_adjusted": "ปรับในบางเลย์เอาต์แล้ว", + "auto_open_cart_drawer": "เมื่อเปิดใช้งาน ตะกร้าสินค้าแบบเลื่อนด้านข้างจะเปิดโดยอัตโนมัติเมื่อมีการเพิ่มสินค้าลงในตะกร้าสินค้า", + "custom_liquid": "เพิ่มส่วนย่อยของแอปหรือโค้ดอื่นๆ เพื่อสร้างการปรับแต่งขั้นสูง [ดูข้อมูลเพิ่มเติม](https://shopify.dev/docs/api/liquid)", + "pills_usage": "ใช้สำหรับตัวกรองที่นำไปใช้ รหัสส่วนลด และคำแนะนำการค้นหา", + "applies_on_image_only": "ใช้กับรูปภาพเท่านั้น", + "hover_effects": "ใช้กับบัตรสินค้าและบัตรคอลเลกชัน" + }, + "categories": { + "basic": "Basic", + "collection": "คอลเลกชัน", + "collection_list": "รายการคอลเลกชัน", + "footer": "ส่วนท้าย", + "forms": "แบบฟอร์ม", + "header": "ส่วนหัว", + "layout": "เลย์เอาต์", + "links": "ลิงก์", + "product": "สินค้า", + "product_list": "คอลเลกชันแนะนำ", + "banners": "แบนเนอร์", + "collections": "คอลเลกชัน", + "custom": "กำหนดเอง", + "decorative": "ตกแต่ง", + "products": "สินค้า", + "other_sections": "อื่นๆ", + "storytelling": "การเล่าเรื่องราว" + } +} diff --git a/locales/tr.json b/locales/tr.json new file mode 100644 index 000000000..299d12bac --- /dev/null +++ b/locales/tr.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Videoyu yükle: {{ description }}", + "sold_out": "Tükendi", + "email_signup": { + "label": "E-posta", + "placeholder": "E-posta adresi", + "success": "Abone olduğunuz için teşekkür ederiz!" + }, + "filter": "Filtrele", + "payment_methods": "Ödeme yöntemleri", + "contact_form": { + "name": "Ad", + "email": "E-posta", + "phone": "Telefon", + "comment": "Yorum", + "post_success": "Bizimle iletişime geçtiğiniz için teşekkür ederiz. Mümkün olan en kısa sürede size dönüş yapacağız.", + "error_heading": "Lütfen aşağıdakileri düzenleyin:" + } + }, + "accessibility": { + "play_model": "3B modeli oynat", + "play_video": "Videoyu oynat", + "unit_price": "Birim fiyatı", + "country_results_count": "{{ count }} sonuç", + "slideshow_pause": "Slayt gösterisini duraklat", + "slideshow_play": "Slayt gösterisini oynat", + "remove_item": "Şunu kaldır: {{ title}}", + "skip_to_text": "İçeriğe atla", + "skip_to_product_info": "Ürün bilgisine atla", + "skip_to_results_list": "Sonuçlar listesine geç", + "new_window": "Yeni bir pencerede açılır.", + "slideshow_next": "Sonraki slayt", + "slideshow_previous": "Önceki slayt", + "close_dialog": "İletişim kutusunu kapat", + "reset_search": "Aramayı sıfırla", + "search_results_count": "\"{{ query }}\" için {{ count }} arama sonucu bulundu", + "search_results_no_results": "\"{{ query }}\" için sonuç bulunamadı", + "filters": "Filtreler", + "account": "Hesap menüsünü aç", + "cart": "Sepet", + "cart_count": "Sepetteki toplam ürün sayısı", + "filter_count": { + "one": "{{ count }} filtre uygulandı", + "other": "{{ count }} filtre uygulandı" + }, + "menu": "Menü", + "country_region": "Ülke/Bölge", + "slide_status": "Slayt {{ index }}/{{ length }}", + "scroll_to": "{{ title }} bölümüne git", + "loading_product_recommendations": "Ürün önerileri yükleniyor", + "discount": "İndirim kodu uygula", + "discount_applied": "Uygulanan indirim kodu: {{ code }}", + "open_cart_drawer": "Sepeti aç", + "pause_video": "Videoyu duraklat", + "inventory_status": "Envanter durumu", + "find_country": "Ülke bul", + "localization_region_and_language": "Bölge ve dil seçiciyi aç", + "open_search_modal": "Aramayı aç", + "decrease_quantity": "Adedi azalt", + "increase_quantity": "Adedi artır", + "quantity": "Adet", + "rating": "Bu ürünün puanı 5 üzerinden {{ rating }}", + "nested_product": "{{ parent_title }} için {{ product_title }}" + }, + "actions": { + "add_to_cart": "Sepete ekle", + "clear_all": "Tümünü temizle", + "remove": "Kaldır", + "view_in_your_space": "Kendi alanınızda görüntüleyin", + "show_filters": "Filtrele", + "clear": "Temizle", + "continue_shopping": "Alışverişe devam et", + "log_in_html": "Hesabınız var mı? Daha hızlı ödeme yapmak için oturum açın.", + "see_items": { + "one": "{{ count }} ürün görüntüle", + "other": "{{ count }} ürün görüntüle" + }, + "view_all": "Tümünü görüntüle", + "add": "Ekle", + "choose": "Seç", + "added": "Eklendi", + "show_less": "Daha az göster", + "show_more": "Daha fazla göster", + "close": "Kapat", + "more": "Diğer", + "reset": "Sıfırla", + "zoom": "Yakınlaştırma", + "close_dialog": "İletişim kutusunu kapat", + "back": "Geri", + "log_in": "Giriş yapın", + "log_out": "Oturumu kapat", + "remove_discount": "{{ code }} indirimini kaldır", + "enter_using_password": "Parola kullanarak girin", + "submit": "Gönder", + "enter_password": "Parolayı girin", + "view_store_information": "Mağaza bilgilerini görüntüle", + "apply": "Uygula", + "open_image_in_full_screen": "Görseli tam ekranda aç", + "sign_in_options": "Diğer giriş yapma seçenekleri", + "sign_up": "Kaydol", + "sort": "Sırala", + "show_all_options": "Tüm seçenekleri göster" + }, + "content": { + "reviews": "değerlendirme", + "language": "Dil", + "localization_region_and_language": "Bölge ve dil", + "no_results_found": "Sonuç bulunamadı", + "cart_total": "Sepet toplamı", + "your_cart_is_empty": "Sepetiniz boş", + "product_image": "Ürün görseli", + "product_information": "Ürün bilgileri", + "quantity": "Adet", + "product_total": "Ürün toplamı", + "cart_estimated_total": "Tahmini toplam", + "seller_note": "Özel talimatlar", + "cart_subtotal": "Alt toplam", + "discounts": "İndirimler", + "discount": "İndirim", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Vergiler ve gümrük vergileri dahil. Ödeme sayfasında hesaplanan indirimler ve kargo.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Vergiler ve gümrük vergileri dahil. Ödeme sayfasında hesaplanan indirimler ve kargo.", + "taxes_included_shipping_at_checkout_with_policy_html": "Vergiler dahil. Ödeme sayfasında hesaplanan indirimler ve kargo.", + "taxes_included_shipping_at_checkout_without_policy": "Vergiler dahil. Ödeme sayfasında hesaplanan indirimler ve kargo.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Gümrük vergileri dahil. Ödeme sayfasında hesaplanan vergiler, indirimler ve kargo.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Gümrük vergileri dahil. Ödeme sayfasında hesaplanan vergiler, indirimler ve kargo.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Ödeme sayfasında hesaplanan vergiler, indirimler ve kargo.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Ödeme sayfasında hesaplanan vergiler, indirimler ve kargo.", + "checkout": "Ödeme", + "cart_title": "Sepet", + "price": "Fiyat", + "price_regular": "Normal fiyat", + "price_compare_at": "Karşılaştırma fiyatı", + "price_sale": "İndirimli fiyat", + "duties_and_taxes_included": "Vergiler ve gümrük vergileri dahildir.", + "duties_included": "Gümrük vergileri dahildir.", + "shipping_policy_html": "Kargo, ödeme sayfasında hesaplanır.", + "taxes_included": "Vergiler dahildir.", + "product_badge_sold_out": "Tükendi", + "product_badge_sale": "İndirimde", + "search_input_label": "Ara", + "search_input_placeholder": "Ara", + "search_results": "Arama sonuçları", + "search_results_label": "Arama sonuçları", + "search_results_no_results": "\"{{ terms }}\" için sonuç bulunamadı. Başka bir arama deneyin", + "search_results_resource_articles": "Blog gönderileri", + "search_results_resource_collections": "Koleksiyonlar", + "search_results_resource_pages": "Sayfalar", + "search_results_resource_products": "Ürünler", + "search_results_resource_queries": "Arama önerileri", + "search_results_view_all": "Tümünü görüntüle", + "search_results_view_all_button": "Tümünü görüntüle", + "search_results_resource_products_count": { + "one": "{{ count }} ürün", + "other": "{{ count }} ürün" + }, + "grid_view": { + "default_view": "Varsayılan", + "grid_fieldset": "Sütun ızgarası", + "single_item": "Tek", + "zoom_out": "Uzaklaştır" + }, + "recently_viewed_products": "Son görüntülenen", + "unavailable": "Mevcut değil", + "collection_placeholder": "Koleksiyon başlığı", + "product_card_placeholder": "Ürün başlığı", + "product_count": "Ürün sayısı", + "item_count": { + "one": "{{ count }} ürün", + "other": "{{ count }} ürün" + }, + "errors": "Hatalar", + "price_from": "{{ price }} tutarından başlayan fiyatlarla", + "featured_products": "Öne çıkan ürünler", + "search": "Ara", + "search_results_no_results_check_spelling": "\"{{ terms }}\" için sonuç bulunamadı. Yazım hatası olmadığını doğrulayın veya farklı bir kelime ya da ifade kullanın.", + "filters": "Filtreler", + "no_products_found": "Ürün bulunamadı.", + "price_filter_html": "En yüksek fiyat: {{ price }}", + "use_fewer_filters_html": "Daha az filtre kullanmayı veya tüm filtreleri kaldırmayı deneyin.", + "blog_details_separator": "|", + "read_more": "Devamını oku...", + "account_title": "Hesap", + "account_title_personalized": "Merhaba {{ first_name }}", + "account_orders": "Siparişler", + "account_profile": "Profil", + "discount_code": "İndirim kodu", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Vergiler ve gümrük vergileri dahil. Kargo, ödeme sayfasında hesaplanır.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Vergiler ve gümrük vergileri dahil. Kargo, ödeme sayfasında hesaplanır.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Gümrük vergileri dahil. Kargo, ödeme sayfasında hesaplanır.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Gümrük vergileri dahil. Kargo, ödeme sayfasında hesaplanır.", + "pickup_available_at_html": "{{ location }} konumunda teslim alım yapılabilir", + "pickup_available_in": "{{ pickup_time }} saatinde teslim alım yapılabilir", + "pickup_not_available": "Şu anda teslim alım yapılamıyor", + "pickup_ready_in": "{{ pickup_time }}", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Vergiler ve kargo ücreti, ödeme sayfasında hesaplanır.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Vergiler ve Kargo, ödeme sayfasında hesaplanır.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Vergiler dahil. Kargo, ödeme sayfasında hesaplanır.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Vergiler dahil. Kargo, ödeme sayfasında hesaplanır.", + "wrong_password": "Yanlış parola", + "view_more_details": "Daha fazla ayrıntı görüntüle", + "powered_by": "Bu mağaza için destek sağlayan:", + "store_owner_link_html": "Mağaza sahibi misiniz? Buradan oturum açın", + "shipping_discount_error": "Kargo indirimleri, adres eklendikten sonra ödeme sayfasında gösterilir", + "discount_code_error": "Sepetinize indirim kodu uygulanamıyor", + "inventory_low_stock": "Stok düzeyi düşük", + "inventory_in_stock": "Stokta", + "inventory_out_of_stock": "Stokta yok", + "page_placeholder_title": "Sayfa başlığı", + "page_placeholder_content": "İçeriğini görüntülemek istediğiniz sayfayı seçin.", + "placeholder_image": "Yer tutucu görseli", + "shipping_policy": "Kargo, ödeme sayfasında hesaplanır.", + "inventory_low_stock_show_count": { + "one": "{{ count }} kaldı", + "other": "{{ count }} kaldı" + } + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Hediye kartı kodunu online olarak veya QR kodunu mağazada kullanın", + "title": "İşte {{ shop }} için {{ value }} tutarındaki hediye kartı bakiyeniz!", + "subtext": "Hediye kartınız", + "shop_link": "Online mağazayı ziyaret edin", + "add_to_apple_wallet": "Apple Wallet'a ekle", + "qr_image_alt": "QR kodu: Hediye kartını kullanmak için tarayın", + "copy_code": "Hediye kartı kodunu kopyala", + "expiration_date": "Sona erme tarihi: {{ expires_on }}", + "copy_code_success": "Kod başarıyla kopyalandı", + "expired": "Son kullanma tarihi dolmuş" + } + }, + "placeholders": { + "password": "Parola", + "search": "Ara", + "product_title": "Ürün başlığı", + "collection_title": "Koleksiyon başlığı" + }, + "products": { + "product": { + "add_to_cart": "Sepete ekle", + "added_to_cart": "Sepete eklendi", + "adding_to_cart": "Ekleniyor...", + "add_to_cart_error": "Sepete eklenirken hata oluştu", + "sold_out": "Tükendi", + "unavailable": "Kullanılamıyor" + } + }, + "fields": { + "separator": "-" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} yorum", + "other": "{{ count }} yorum" + } + }, + "comment_form": { + "email": "E-posta", + "error": "Yorum gönderilemedi, lütfen şunları kontrol edin:", + "heading": "Yorum bırakın", + "message": "Mesaj", + "moderated": "Yorumların yayınlanabilmesi için onaylanması gerektiğini lütfen unutmayın.", + "name": "Ad", + "post": "Yorumu gönder", + "success_moderated": "Yorum gönderildi, onay bekliyor", + "success": "Yorum gönderildi" + } + } +} diff --git a/locales/tr.schema.json b/locales/tr.schema.json new file mode 100644 index 000000000..650587223 --- /dev/null +++ b/locales/tr.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "Kenarlıklar", + "collapsible_row": "Daraltılabilir satır", + "custom_section": "Özel bölüm", + "icon": "Simge", + "logo_and_favicon": "Logo ve favicon", + "product_buy_buttons": "Satın al düğmeleri", + "product_description": "Açıklama", + "product_price": "Fiyat", + "slideshow": "Slayt gösterisi", + "typography": "Baskı", + "video": "Video", + "colors": "Renkler", + "overlapping_blocks": "Çakışan bloklar", + "product_variant_picker": "Varyasyon seçici", + "slideshow_controls": "Slayt gösterisi denetimleri", + "size": "Boyut", + "spacing": "Boşluk", + "product_recommendations": "Önerilen ürünler", + "product_media": "Ürün medyası", + "featured_collection": "Öne çıkan koleksiyon", + "add_to_cart": "Sepete ekle", + "email_signup": "E-posta kaydı", + "submit_button": "Gönder düğmesi", + "grid_layout_selector": "Izgara düzeni seçicisi", + "image": "Görsel", + "list_items": "Liste öğeleri", + "facets": "Bölümler", + "variants": "Varyasyonlar", + "product_cards": "Ürün kartları", + "styles": "Stiller", + "buttons": "Düğmeler", + "inputs": "Girdiler", + "primary_button": "Birincil düğme", + "secondary_button": "İkincil düğme", + "popovers": "Popover", + "pull_quote": "Alıntı", + "contact_form": "İletişim formu", + "featured_product": "Ürün vurgusu", + "icons_with_text": "Metin içeren simgeler", + "marquee": "Kayan yazı", + "products_carousel": "Öne çıkan koleksiyon: Carousel", + "products_grid": "Öne çıkan koleksiyon: Izgara", + "alternating_content_rows": "Sırayla değişen satırlar", + "product_list": "Öne çıkan koleksiyon", + "spacer": "Aralayıcı", + "accelerated_checkout": "Hızlı ödeme", + "accordion": "Akordeon", + "accordion_row": "Akordeon satırı", + "animations": "Animasyonlar", + "announcement": "Duyuru", + "announcement_bar": "Duyuru çubuğu", + "badges": "Rozetler", + "button": "Düğme", + "cart": "Sepet", + "cart_items": "Sepet ürünleri", + "cart_products": "Sepet ürünleri", + "cart_title": "Sepet", + "collection": "Koleksiyon", + "collection_card": "Koleksiyon kartı", + "collection_columns": "Koleksiyon sütunları", + "collection_container": "Koleksiyon", + "collection_description": "Koleksiyon açıklaması", + "collection_image": "Koleksiyon görseli", + "collection_info": "Koleksiyon bilgileri", + "collection_list": "Koleksiyon listesi", + "collections": "Koleksiyonlar", + "collections_bento": "Koleksiyon listesi: Bento", + "collections_carousel": "Koleksiyon listesi: Carousel", + "collections_grid": "Koleksiyon listesi: Izgara", + "content": "İçerik", + "content_grid": "İçerik ızgarası", + "details": "Ayrıntılar", + "divider": "Ayırıcı", + "divider_section": "Ayırıcı", + "faq_section": "SSS", + "filters": "Filtreleme ve sıralama", + "follow_on_shop": "Shop'ta takip edin", + "footer": "Altbilgi", + "footer_utilities": "Altbilgi yardımcı araçları", + "group": "Grup", + "header": "Üstbilgi", + "heading": "Başlık", + "hero": "Hero", + "icons": "Simgeler", + "image_with_text": "Metin içeren görsel", + "input": "Girdi", + "logo": "Logo", + "magazine_grid": "Dergi ızgarası", + "media": "Medya", + "menu": "Menü", + "mobile_layout": "Mobil düzen", + "payment_icons": "Ödeme simgeleri", + "popup_link": "Açılır pencere bağlantısı", + "predictive_search": "Arama açılır penceresi", + "predictive_search_empty": "Tahmini arama boş", + "price": "Fiyat", + "product": "Ürün", + "product_card": "Ürün kartı", + "product_card_media": "Medya", + "product_card_rendering": "Ürün kartı işleme", + "product_grid": "Izgara", + "product_grid_main": "Ürün ızgarası", + "product_image": "Ürün görseli", + "product_information": "Ürün bilgileri", + "product_review_stars": "Değerlendirme yıldızları", + "quantity": "Adet", + "row": "Satır", + "search": "Ara", + "section": "Bölüm", + "selected_variants": "Seçilen varyasyonlar", + "shop_the_look": "Bu tarz için alışverişe başlayın", + "slide": "Slayt", + "social_media_links": "Sosyal medya bağlantıları", + "steps": "Adımlar", + "summary": "Özet", + "swatches": "Numune parçalar", + "testimonials": "Kullanıcı Görüşleri", + "text": "Metin", + "title": "Başlık", + "utilities": "Yardımcı araçlar", + "video_section": "Video", + "jumbo_text": "Jumbo metin", + "collection_title": "Koleksiyon başlığı", + "view_all_button": "Tümünü görüntüle", + "search_input": "Girdi arayın", + "search_results": "Arama sonuçları", + "read_only": "Salt okunur", + "collection_links": "Koleksiyon bağlantıları", + "count": "Sayı", + "custom_liquid": "Özel liquid", + "blog": "Blog", + "blog_post": "Blog gönderisi", + "blog_posts": "Blog gönderileri", + "caption": "Alt yazı", + "collection_card_image": "Görsel", + "collection_links_spotlight": "Koleksiyon bağlantıları: Spotlight", + "collection_links_text": "Koleksiyon bağlantıları: Metin", + "collections_editorial": "Koleksiyon listesi: Editoryal", + "copyright": "Telif hakkı", + "drawers": "Çekmeceler", + "editorial": "Başyazı", + "editorial_jumbo_text": "Başyazı: Büyük metin", + "hero_marquee": "Hero: Kayan yazı", + "input_fields": "Giriş alanları", + "local_pickup": "Mağazadan teslim alım", + "marquee_section": "Kayan yazı", + "media_with_text": "Metin içeren medya", + "page": "Sayfa", + "page_content": "İçerik", + "page_layout": "Sayfa düzeni", + "policy_list": "Politika bağlantıları", + "prices": "Fiyatlar", + "products_editorial": "Öne çıkan koleksiyon: Editoryal", + "social_link": "Sosyal medya bağlantısı", + "split_showcase": "Split showcase", + "variant_pickers": "Varyasyon seçiciler", + "product_title": "Ürün başlığı", + "large_logo": "Büyük logo", + "product_list_button": "Tümünü görüntüle düğmesi", + "product_inventory": "Ürün envanteri", + "pills": "Seçenekler", + "description": "Açıklama" + }, + "settings": { + "autoplay": "Otomatik oynatma", + "background": "Arka plan", + "border_radius": "Köşe yarıçapı", + "border_width": "Kenarlık kalınlığı", + "borders": "Kenarlıklar", + "bottom_padding": "Alt dolgu", + "color": "Renk", + "content_direction": "İçerik yönü", + "content_position": "İçerik konumu", + "cover_image_size": "Kapak görseli boyutu", + "cover_image": "Kapak görseli", + "custom_width": "Özel genişlik", + "enable_video_looping": "Video döngüsü", + "favicon": "Favicon", + "heading": "Başlık", + "icon": "Simge", + "image_icon": "Görsel simgesi", + "make_section_full_width": "Bölümü tam genişlikli yap", + "overlay_opacity": "Yer paylaşımı opaklığı", + "padding": "Dolgu", + "product": "Ürün", + "text": "Metin", + "top_padding": "Üst dolgu", + "video": "Video", + "video_alt_text": "Alternatif metin", + "video_loop": "Video döngüsü", + "video_position": "Video konumu", + "width": "Genişlik", + "alignment": "Hizalama", + "button": "Düğme", + "colors": "Renkler", + "content_alignment": "İçerik hizalaması", + "custom_minimum_height": "Özel minimum yükseklik", + "font_family": "Yazı tipi ailesi", + "gap": "Aralık", + "geometric_translate_y": "Geometrik çeviri Y", + "image": "Görsel", + "image_opacity": "Görsel opaklığı", + "image_position": "Görsel konumu", + "image_ratio": "Görsel oranı", + "label": "Etiket", + "line_height": "Satır yüksekliği", + "link": "Bağlantı", + "layout_gap": "Düzen aralığı", + "minimum_height": "Minimum yükseklik", + "opacity": "Opaklık", + "primary_color": "Bağlantılar", + "section_width": "Bölüm genişliği", + "size": "Boyut", + "slide_spacing": "Slayt aralığı", + "slide_width": "Slayt genişliği", + "slideshow_fullwidth": "Tam genişlikte slaytlar", + "style": "Stil", + "text_case": "Büyük/küçük harf durumu", + "z_index": "Z endeksi", + "limit_content_width": "İçerik genişliğini sınırla", + "color_scheme": "Renk şeması", + "inherit_color_scheme": "Renk şemasını devral", + "product_count": "Ürün sayısı", + "product_type": "Ürün türü", + "content_width": "İçerik genişliği", + "collection": "Koleksiyon", + "enable_sticky_content": "Masaüstünde sabit içeriği etkinleştir", + "error_color": "Hata", + "success_color": "Başarılı", + "primary_font": "Birincil yazı tipi", + "secondary_font": "İkincil yazı tipi", + "tertiary_font": "Üçüncül yazı tipi", + "columns": "Sütunlar", + "items_to_show": "Gösterilecek öğeler", + "layout": "Düzen", + "layout_type": "Tür", + "show_grid_layout_selector": "Izgara düzeni seçicisini göster", + "view_more_show": "Daha fazlasını görüntüle düğmesini göster", + "image_gap": "Görsel aralığı", + "width_desktop": "Masaüstü genişliği", + "width_mobile": "Mobil ekran genişliği", + "border_style": "Kenarlık stili", + "height": "Yükseklik", + "thickness": "Kalınlık", + "stroke": "Biçim", + "filter_style": "Filtre stili", + "swatches": "Numune parçalar", + "quick_add_colors": "Hızlı renk ekleme", + "divider_color": "Ayırıcı", + "border_opacity": "Sınır opaklığı", + "hover_background": "Arka planı vurgula", + "hover_borders": "Sınırı vurgula", + "hover_text": "Metni vurgula", + "primary_hover_color": "Bağlantıyı vurgula", + "primary_button_text": "Birincil düğme metni", + "primary_button_background": "Birincil düğme arka planı", + "primary_button_border": "Birincil düğme sınırı", + "secondary_button_text": "İkincil düğme metni", + "secondary_button_background": "İkincil düğme arka planı", + "secondary_button_border": "İkincil düğme sınırı", + "shadow_color": "Gölge", + "video_autoplay": "Otomatik oynatma", + "video_cover_image": "Kapak görseli", + "video_external_url": "URL", + "video_source": "Kaynak", + "card_image_height": "Ürün görseli yüksekliği", + "background_color": "Arka plan rengi", + "first_row_media_position": "Birinci satır medya konumu", + "hide_padding": "Dolguyu gizle", + "size_mobile": "Mobil boyutu", + "pixel_size_mobile": "Piksel boyutu", + "percent_size_mobile": "Yüzde boyutu", + "unit": "Birim", + "custom_mobile_size": "Özel mobil boyutu", + "fixed_height": "Piksel yüksekliği", + "fixed_width": "Piksel genişliği", + "percent_height": "Yüzde yüksekliği", + "percent_width": "Yüzde genişliği", + "percent_size": "Yüzde boyutu", + "pixel_size": "Piksel boyutu", + "logo_font": "Logo yazı tipi", + "accordion": "Akordeon", + "aspect_ratio": "En-boy oranı", + "auto_rotate_announcements": "Duyuruları otomatik olarak döndür", + "auto_rotate_slides": "Slaytları otomatik olarak döndür", + "badge_corner_radius": "Köşe yarıçapı", + "badge_position": "Kartlardaki konum", + "badge_sale_color_scheme": "Satış", + "badge_sold_out_color_scheme": "Tükendi", + "behavior": "Davranış", + "blur": "Bulanık gölge", + "border": "Kenarlık", + "bottom": "Alt", + "carousel_on_mobile": "Mobil cihazlarda carousel", + "cart_count": "Sepet sayısı", + "cart_items": "Sepet ürünleri", + "cart_related_products": "Alakalı ürünler", + "cart_title": "Sepet", + "cart_total": "Sepet toplamı", + "cart_type": "Tür", + "case": "Büyük/küçük harf durumu", + "checkout_buttons": "Hızlı ödeme düğmeleri", + "collection_list": "Koleksiyonlar", + "collection_templates": "Koleksiyon şablonları", + "content": "İçerik", + "corner_radius": "Köşe yarıçapı", + "country_region": "Ülke/Bölge", + "currency_code": "Para birimi kodu", + "custom_height": "Özel yükseklik", + "desktop_height": "Masaüstü yüksekliği", + "direction": "Yön", + "display": "Görüntü", + "divider_thickness": "Ayırıcı kalınlığı", + "divider": "Ayırıcı", + "dividers": "Ayırıcılar", + "drop_shadow": "Gölgeleme", + "empty_state_collection_info": "Arama girilmeden önce gösterilir", + "empty_state_collection": "Boş durum koleksiyonu", + "enable_filtering": "Filtreler", + "enable_grid_density": "Izgara düzeni kontrolü", + "enable_sorting": "Sıralama", + "enable_zoom": "Yakınlaştırmayı etkinleştir", + "equal_columns": "Eşit sütunlar", + "expand_first_group": "Birinci grubu genişlet", + "extend_media_to_screen_edge": "Medyayı ekran kenarına genişlet", + "extend_summary": "Ekran kenarına genişlet", + "extra_large": "Çok büyük", + "extra_small": "Çok küçük", + "flag": "Bayrak", + "font_price": "Fiyat yazı tipi", + "font_weight": "Yazı tipi ağırlığı", + "font": "Yazı tipi", + "full_width_first_image": "Tam genişliğe sahip birinci görsel", + "full_width_on_mobile": "Mobil cihazlarda tam genişlik", + "heading_preset": "Başlık ön ayarı", + "hide_unselected_variant_media": "Seçimi kaldırılmış varyasyon medyasını gizle", + "horizontal_gap": "Yatay boşluk", + "horizontal_offset": "Gölge yatay dengelemesi", + "hover_behavior": "Üzerine gitme davranışı", + "icon_background": "Simge arka planı", + "icons": "Simgeler", + "image_border_radius": "Görsel köşe yarıçapı", + "installments": "Taksitler", + "integrated_button": "Entegre düğme", + "language_selector": "Dil seçici", + "large": "Büyük", + "left_padding": "Sol dolgu", + "left": "Sol", + "letter_spacing": "Harf boşluğu", + "limit_media_to_screen_height": "Ekran yüksekliğiyle sınırla", + "limit_product_details_width": "Ürün bilgileri genişliğini sınırla", + "link_preset": "Bağlantı ön ayarı", + "links": "Bağlantılar", + "logo": "Logo", + "loop": "Döngü", + "make_details_sticky_desktop": "Masaüstünde sabit", + "max_width": "Maksimum genişlik", + "media_height": "Medya yüksekliği", + "media_overlay": "Medya yer paylaşımı", + "media_position": "Medya konumu", + "media_type": "Medya türü", + "media_width": "Medya genişliği", + "menu": "Menü", + "mobile_columns": "Mobil sütunlar", + "mobile_height": "Mobil yükseklik", + "mobile_logo_image": "Mobil logo", + "mobile_quick_add": "Mobil hızlı ekleme", + "motion_direction": "Motion yönü", + "motion": "Motion", + "movement_direction": "Hareket yönü", + "navigation_bar_color_scheme": "Gezinme çubuğu renk şeması", + "navigation_bar": "Gezinme çubuğu", + "navigation": "Gezinme", + "open_new_tab": "Bağlantıyı yeni sekmede aç", + "overlay_color": "Yer paylaşımı rengi", + "overlay": "Yer paylaşımlı", + "padding_bottom": "Alt dolgu", + "padding_horizontal": "Yatay dolgu", + "padding_top": "Üst dolgu", + "page_width": "Sayfa genişliği", + "pagination": "Sayfalara ayırma", + "placement": "Yerleşim", + "position": "Konum", + "preset": "Ön ayar", + "product_cards": "Ürün kartları", + "product_pages": "Ürün sayfaları", + "product_templates": "Ürün şablonları", + "products": "Ürünler", + "quick_add": "Hızlı ekle", + "ratio": "Oran", + "regular": "Normal", + "review_count": "Değerlendirme sayısı", + "right": "Sağ", + "row_height": "Satır yüksekliği", + "row": "Satır", + "seller_note": "Satıcı için nota izin ver", + "shape": "Şekil", + "show_as_accordion": "Mobil cihazlarda akordeon olarak göster", + "show_sale_price_first": "Önce indirimli fiyatı göster", + "show_tax_info": "Vergi bilgileri", + "show": "Göster", + "small": "Küçük", + "speed": "Hız", + "statement": "Hesap özeti", + "sticky_header": "Sabit üstbilgi", + "text_hierarchy": "Metin hiyerarşisi", + "text_presets": "Metin ön ayarları", + "title": "Başlık", + "top": "Üst", + "type_preset": "Metin ön ayarı", + "type": "Tür", + "underline_thickness": "Alt çizgi kalınlığı", + "variant_images": "Varyasyon görselleri", + "vendor": "Satıcı", + "vertical_gap": "Dikey boşluk", + "vertical_offset": "Gölge dikey dengelemesi", + "vertical_on_mobile": "Mobil cihazlarda dikey", + "view_all_as_last_card": "Son kart olarak \"Tümünü görüntüle\"", + "weight": "Ağırlık", + "wrap": "Kaydır", + "shadow_opacity": "Gölge opaklığı", + "show_filter_label": "Uygulanan filtreler için metin etiketleri", + "show_swatch_label": "Numune parçalar için metin etiketleri", + "always_stack_buttons": "Düğmeleri her zaman yığ", + "transparent_background": "Şeffaf arka plan", + "gradient_direction": "Gradyan yönü", + "overlay_style": "Yer paylaşımı stili", + "custom_mobile_width": "Özel mobil ekran genişliği", + "read_only": "Salt okunur", + "headings": "Başlıklar", + "horizontal_padding": "Yatay dolgu", + "show_count": "Sayıyı göster", + "vertical_padding": "Dikey dolgu", + "visibility": "Görünürlük", + "account": "Hesap", + "align_baseline": "Metin taban çizgisini hizala", + "add_discount_code": "Sepette indirimlere izin ver", + "background_overlay": "Arka plan yer paylaşımı", + "background_media": "Arka plan medyası", + "border_thickness": "Kenarlık kalınlığı", + "bottom_row": "Alt satır", + "button_text_case": "Metin büyük/küçük harfi", + "button_text_weight": "Metin ağırlığı", + "auto_open_cart_drawer": "\"Sepete ekle\", çekmeceyi otomatik olarak açar", + "collection_count": "Koleksiyon sayısı", + "custom_liquid": "Liquid kodu", + "default": "Varsayılan", + "default_logo": "Varsayılan logo", + "divider_width": "Ayırıcı genişliği", + "hide_logo_on_home_page": "Ana sayfada logoyu gizle", + "inverse": "Ters", + "inverse_logo": "Ters logo", + "layout_style": "Stil", + "length": "Uzunluk", + "mobile_pagination": "Mobil cihazlar için sayfalara ayırma", + "open_row_by_default": "Varsayılan olarak satırı aç", + "page_transition_enabled": "Sayfa geçişi", + "search": "Ara", + "search_icon": "Arama simgesi", + "search_position": "Konum", + "search_row": "Satır", + "show_author": "Yazar", + "show_alignment": "Hizalamayı göster", + "show_date": "Tarih", + "show_pickup_availability": "Teslim alım için stok durumunu göster", + "show_search": "Aramayı göster", + "use_inverse_logo": "Ters logo kullan", + "product_corner_radius": "Ürün köşe yarıçapı", + "card_corner_radius": "Kart köşe yarıçapı", + "alignment_mobile": "Mobil hizalama", + "animation_repeat": "Animasyonu tekrarla", + "blurred_reflection": "Bulanık yansıma", + "card_hover_effect": "Kart üzerine gelme efekti", + "card_size": "Kart boyutu", + "collection_title_case": "Koleksiyon başlığı büyük/küçük harf durumu", + "effects": "Efektler", + "inventory_threshold": "Düşük stok eşiği", + "mobile_card_size": "Mobil kart boyutu", + "page": "Sayfa", + "product_and_card_title_case": "Ürün ve kart başlığı büyük/küçük harf durumu", + "product_title_case": "Ürün başlığı büyük/küçük harf durumu", + "reflection_opacity": "Yansıma opaklığı", + "right_padding": "Sağ iç boşluk", + "show_inventory_quantity": "Düşük stok miktarını göster", + "text_label_case": "Metin etiketi büyük/küçük harf durumu", + "transition_to_main_product": "Ürün kartı - ürün sayfası geçişi", + "media": "Medya", + "product_card_carousel": "Döngüyü göster", + "show_second_image_on_hover": "Üzerine gelindiğinde ikinci görseli göster", + "media_fit": "Medya sığdırma", + "scroll_speed": "Sonraki duyuruya kaydır" + }, + "options": { + "adapt_to_image": "Görsele uyarla", + "apple": "Elma", + "arrow": "Ok", + "banana": "Muz", + "bottle": "Şişe", + "box": "Kutu", + "buttons": "Düğmeler", + "carrot": "Havuç", + "center": "Orta", + "chat_bubble": "Sohbet balonu", + "clipboard": "Pano", + "contain": "Dahil et", + "counter": "Sayaç", + "cover": "Kapak", + "custom": "Özel", + "dairy_free": "Süt ürünü içermez", + "dairy": "Süt ürünü", + "dropdowns": "Açılır menüler", + "dots": "Noktalar", + "dryer": "Kurutucu", + "end": "Bitiş", + "eye": "Göz", + "facebook": "Facebook", + "fire": "Ateş", + "gluten_free": "Glütensiz", + "heart": "Kalp", + "horizontal": "Yatay", + "instagram": "Instagram", + "iron": "Ütü", + "large": "Büyük", + "leaf": "Yaprak", + "leather": "Deri", + "lightning_bolt": "Şimşek", + "lipstick": "Ruj", + "lock": "Kilit", + "map_pin": "Harita pini", + "medium": "Orta", + "none": "Yok", + "numbers": "Numaralar", + "nut_free": "Kabuklu yemişsiz", + "pants": "Pantolon", + "paw_print": "Pati izi", + "pepper": "Biber", + "perfume": "Parfüm", + "pinterest": "Pinterest", + "plane": "Uçak", + "plant": "Bitki", + "price_tag": "Fiyat etiketi", + "question_mark": "Soru işareti", + "recycle": "Geri dönüşüm", + "return": "İade", + "ruler": "Cetvel", + "serving_dish": "Servis tabağı", + "shirt": "Gömlek", + "shoe": "Ayakkabı", + "silhouette": "Silüet", + "small": "Küçük", + "snapchat": "Snapchat", + "snowflake": "Kar tanesi", + "star": "Yıldız", + "start": "Başlangıç", + "stopwatch": "Kronometre", + "tiktok": "TikTok", + "truck": "Kamyon", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "vertical": "Dikey", + "vimeo": "Vimeo", + "washing": "Yıkama", + "auto": "Otomatik", + "default": "Varsayılan", + "fill": "Doldur", + "fit": "Sığdır", + "full": "Tam", + "full_and_page": "Tam arka plan, sayfa genişliğinde içerik", + "heading": "Başlık", + "landscape": "Yatay", + "lg": "LG", + "link": "Bağlantı", + "lowercase": "küçük harf", + "m": "M", + "outline": "Dış çizgi", + "page": "Sayfa", + "portrait": "Portre", + "s": "S", + "sentence": "Cümle", + "solid": "Sabit", + "space_between": "Aradaki boşluk", + "square": "Kare", + "uppercase": "Büyük harf", + "circle": "Daire", + "swatches": "Numune parçalar", + "full_and_page_offset_left": "Tam arka plan, sayfa genişliğinde içerik, soldan dengeleme", + "full_and_page_offset_right": "Tam arka plan, sayfa genişliğinde içerik, sağdan dengeleme", + "offset_left": "Soldan dengeleme", + "offset_right": "Sağdan dengeleme", + "page_center_aligned": "Sayfa, ortaya hizalanmış", + "page_left_aligned": "Sayfa, sola hizalanmış", + "page_right_aligned": "Sayfa, sağa hizalanmış", + "button": "Düğme", + "caption": "Alt yazı", + "h1": "1. Başlık", + "h2": "2. Başlık", + "h3": "3. Başlık", + "h4": "4. Başlık", + "h5": "5. Başlık", + "h6": "6. Başlık", + "paragraph": "Paragraf", + "primary": "Birincil", + "secondary": "İkincil", + "tertiary": "Üçüncül", + "chevron_left": "Sola ok", + "chevron_right": "Sağa ok", + "diamond": "Baklava", + "grid": "Izgara", + "parallelogram": "Paralelkenar", + "rounded": "Yuvarlanmış", + "fit_content": "Sığdır", + "pills": "Seçenekler", + "heavy": "Ağır", + "thin": "İnce", + "drawer": "Çekmece", + "preview": "Önizleme", + "text": "Metin", + "video_uploaded": "Yüklendi", + "video_external_url": "Harici URL", + "up": "Yukarı", + "down": "Aşağı", + "gradient": "Gradyan", + "fixed": "Sabit", + "pixel": "Piksel", + "percent": "Yüzde", + "aspect_ratio": "En-boy oranı", + "above_carousel": "Carousel'in üzerinde", + "all": "Tümü", + "always": "Her zaman", + "arrows_large": "Büyük oklar", + "arrows": "Oklar", + "balance": "Bakiye", + "bento": "Bento", + "black": "Siyah", + "bluesky": "Bluesky", + "body_large": "Gövde (Büyük)", + "body_regular": "Gövde (Normal)", + "body_small": "Gövde (Küçük)", + "bold": "Kalın", + "bottom_left": "Sol alt", + "bottom_right": "Sağ alt", + "bottom": "Alt", + "capitalize": "Büyük harf yap", + "caret": "Şapka işareti", + "carousel": "Carousel", + "check_box": "Onay kutusu", + "chevron_large": "Büyük açılı ayraçlar", + "chevron": "Açılı ayraç", + "chevrons": "Açılı ayraçlar", + "classic": "Klasik", + "collection_images": "Koleksiyon görselleri", + "color": "Renk", + "complementary": "Tamamlayıcı", + "dissolve": "Çözülme", + "dotted": "Noktalı", + "editorial": "Başyazı", + "extra_large": "Çok büyük", + "extra_small": "Çok küçük", + "featured_collections": "Öne çıkan koleksiyonlar", + "featured_products": "Öne çıkan ürünler", + "font_primary": "Birincil", + "font_secondary": "İkincil", + "font_tertiary": "Üçüncül", + "forward": "İleri", + "full_screen": "Tam ekran", + "heading_extra_large": "Başlık (Çok büyük)", + "heading_extra_small": "Başlık (Çok küçük)", + "heading_large": "Başlık (Büyük)", + "heading_regular": "Başlık (Normal)", + "heading_small": "Başlık (Küçük)", + "icon": "Simge", + "image": "Görsel", + "input": "Girdi", + "inside_carousel": "Carousel'in içinde", + "inverse_large": "Ters büyük", + "inverse": "Ters", + "large_arrows": "Büyük oklar", + "large_chevrons": "Büyük açılı ayraçlar", + "left": "Sol", + "light": "Açık", + "linkedin": "LinkedIn", + "loose": "Gevşek", + "media_first": "Birinci medya", + "media_second": "İkinci medya", + "modal": "Mod", + "narrow": "Dar", + "never": "Hiçbir zaman", + "next_to_carousel": "Carousel'in yanında", + "normal": "Normal", + "nowrap": "Kaydırma yok", + "off_media": "Medya kapalı", + "on_media": "Medya açık", + "on_scroll_up": "Yukarı kaydırıldığında", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "Hap şeklinde", + "plus": "Plus", + "pretty": "Sevimli", + "price": "Fiyat", + "primary_style": "Birincil stil", + "rectangle": "Dikdörtgen", + "regular": "Normal", + "related": "Alakalı", + "reverse": "Ters çevir", + "rich_text": "Zengin metin", + "right": "Sağ", + "secondary_style": "İkincil stil", + "semibold": "Yarı kalın", + "shaded": "Gölgeli", + "show_second_image": "İkinci görseli göster", + "single": "Tek", + "slide_left": "Sola kaydır", + "slide_up": "Yukarı kaydır", + "spotify": "Spotify", + "stack": "Yığın", + "text_only": "Yalnızca metin", + "threads": "Threads", + "thumbnails": "Küçük resimler", + "tight": "Sıkı", + "top_left": "Sol üst", + "top_right": "Sağ üst", + "top": "Üst", + "two_number": "2", + "two_thirds": "2/3", + "underline": "Altı çizili", + "video": "Video", + "wide": "Geniş", + "youtube": "YouTube", + "below_image": "Görselin altı", + "hidden": "Gizli", + "on_image": "Görselin üzeri", + "spotlight": "Spotlight", + "accent": "Vurgu", + "body": "Gövde", + "button_primary": "Birincil düğme", + "button_secondary": "İkincil düğme", + "compact": "Kompakt", + "crop_to_fit": "Sığacak şekilde kırp", + "hint": "İpucu", + "maintain_aspect_ratio": "En boy oranını koru", + "off": "Kapalı", + "social_bluesky": "Sosyal medya: Bluesky", + "social_facebook": "Sosyal medya: Facebook", + "social_instagram": "Sosyal medya: Instagram", + "social_linkedin": "Sosyal medya: LinkedIn", + "social_pinterest": "Sosyal medya: Pinterest", + "social_snapchat": "Sosyal medya: Snapchat", + "social_spotify": "Sosyal medya: Spotify", + "social_threads": "Sosyal medya: Threads", + "social_tiktok": "Sosyal medya: TikTok", + "social_tumblr": "Sosyal medya: Tumblr", + "social_twitter": "Sosyal medya: X (Twitter)", + "social_whatsapp": "Sosyal medya: WhatsApp", + "social_vimeo": "Sosyal medya: Vimeo", + "social_youtube": "Sosyal medya: YouTube", + "standard": "Standart", + "subheading": "Alt başlık", + "blur": "Bulanıklaştır", + "lift": "Yükseltme", + "reveal": "Göster", + "scale": "Ölçek", + "subtle_zoom": "Yakınlaştırma" + }, + "content": { + "background_video": "Arka plan videosu", + "describe_the_video_for": "Ekran okuyucu kullanan müşteriler için videoyu açıklayın. [Daha fazla bilgi edinin](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "width_is_automatically_optimized": "Genişlik, mobil cihazlar için otomatik olarak optimize edilir.", + "advanced": "Gelişmiş", + "background_image": "Arka plan resmi", + "block_size": "Blok boyutu", + "borders": "Kenarlıklar", + "section_size": "Bölüm boyutu", + "slideshow_width": "Slayt genişliği", + "typography": "Tipografi", + "complementary_products": "Search & Discovery uygulaması kullanılarak tamamlayıcı ürünler ayarlanmalıdır. [Daha fazla bilgi edinin](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "Sütunlar, mobil cihazlar için otomatik olarak optimize edilir", + "content_width": "İçerik genişliği yalnızca bölüm genişliği tam genişliğe ayarlandığında uygulanır.", + "adjustments_affect_all_content": "Bu bloktaki tüm içeriklere uygulanır", + "responsive_font_sizes": "Boyutlar, tüm ekran boyutlarına göre otomatik olarak ölçeklenir", + "buttons": "Düğmeler", + "swatches": "Numune parçalar", + "variant_settings": "Varyasyon ayarları", + "background": "Arka plan", + "cards_layout": "Kartlar düzeni", + "section_layout": "Bölüm düzeni", + "mobile_size": "Mobil boyutu", + "appearance": "Görünüm", + "arrows": "Oklar", + "body_size": "Gövde boyutu", + "bottom_row_appearance": "Alt satır görünümü", + "carousel_navigation": "Carousel gezinmesi", + "carousel_pagination": "Carousel sayfalara ayırma", + "copyright": "Telif Hakkı", + "edit_logo_in_theme_settings": "Logonuzu [tema ayarları](/editor?context=theme&category=logo%20and%20favicon) bölümünde düzenleyin", + "edit_price_in_theme_settings": "Fiyat biçimlendirmesini [tema ayarları](/editor?context=theme&category=currency%20code) bölümünde düzenleyin", + "edit_variants_in_theme_settings": "Varyasyon stilini [tema ayarları](/editor?context=theme&category=variants) bölümünde düzenleyin", + "email_signups_create_customer_profiles": "Kayıt ekleme [müşteri profilleri](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "Düğmenin gösterilmesi için Shop kanalı yüklenmiş ve Shop Pay etkinleştirilmiş olmalıdır. [Daha fazla bilgi edinin](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "Yazı Tipleri", + "grid": "Izgara", + "heading_size": "Başlık boyutu", + "image": "Görsel", + "input": "Girdi", + "layout": "Düzen", + "link": "Bağlantı", + "link_padding": "Bağlantı dolgusu", + "localization": "Yerelleştirme", + "logo": "Logo", + "margin": "Kenar boşluğu", + "media": "Medya", + "media_1": "Medya 1", + "media_2": "Medya 2", + "menu": "Menü", + "mobile_layout": "Mobil düzen", + "padding": "Dolgu", + "padding_desktop": "Masaüstü dolgusu", + "paragraph": "Paragraf", + "policies": "Politikalar", + "popup": "Açılır pencere", + "search": "Ara", + "size": "Boyut", + "social_media": "Sosyal medya", + "submit_button": "Gönder düğmesi", + "text_presets": "Metin ön ayarları", + "transparent_background": "Şeffaf arka plan", + "typography_primary": "Birincil tipografi", + "typography_secondary": "İkincil tipografi", + "typography_tertiary": "Üçüncül tipografi", + "mobile_width": "Mobil ekran genişliği", + "width": "Genişlik", + "carousel": "Carousel", + "colors": "Renkler", + "collection_page": "Koleksiyon sayfası", + "copyright_info": "[Telif hakkı beyanınızı düzenleme](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message) hakkında bilgi edinin", + "customer_account": "Müşteri hesabı", + "edit_empty_state_collection_in_theme_settings": "Boş durum koleksiyonunu [tema ayarları](/editor?context=theme&category=search)] bölümünden düzenleyin", + "home_page": "Ana sayfa", + "images": "Görseller", + "inverse_logo_info": "Şeffaf üstbilgi arka planı, Ters olarak ayarlandığında kullanılır", + "manage_customer_accounts": "Müşteri hesabı ayarlarında [görünürlüğü yönetme](/admin/settings/customer_accounts). Eski hesaplarda desteklenmez.", + "manage_policies": "[Politikaları yönetme](/admin/settings/legal)", + "product_page": "Ürün sayfası", + "text": "Metin", + "thumbnails": "Küçük resimler", + "visibility": "Görünürlük", + "visible_if_collection_has_more_products": "Koleksiyonda gösterilenden daha fazla ürün varsa görünür", + "grid_layout": "Izgara düzeni", + "app_required_for_ratings": "Ürün derecelendirmeleri için bir uygulama gereklidir. [Daha fazla bilgi edinin](https://help.shopify.com/manual/apps)", + "icon": "Simge", + "manage_store_name": "[Mağaza adını yönet](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "Ana bölümdeki koleksiyonu görüntüler", + "resource_reference_collection_card_image": "Ana koleksiyondaki görseli görüntüler", + "resource_reference_collection_title": "Ana koleksiyondaki başlığı görüntüler", + "resource_reference_product": "Ana ürüne otomatik olarak bağlanır", + "resource_reference_product_card": "Ana bölümdeki ürünü görüntüler", + "resource_reference_product_inventory": "Ana üründeki envanteri görüntüler", + "resource_reference_product_price": "Ana üründeki fiyatı görüntüler", + "resource_reference_product_recommendations": "Ana ürünü temel alan önerileri görüntüler", + "resource_reference_product_review": "Ana üründeki değerlendirmeleri görüntüler", + "resource_reference_product_swatches": "Ana üründeki numune parçaları görüntüler", + "resource_reference_product_title": "Ana üründeki başlığı görüntüler", + "resource_reference_product_variant_picker": "Ana üründeki varyasyonları görüntüler", + "resource_reference_product_media": "Ana üründeki medyayı görüntüler", + "product_media": "Ürün medyası", + "section_link": "Bölüm bağlantısı" + }, + "html_defaults": { + "share_information_about_your": "

Müşterilerinizle markanız hakkında bilgi paylaşın. Ürün açıklaması girin, duyuru paylaşın veya mağazanıza gelen müşterileri karşılayın.

" + }, + "text_defaults": { + "collapsible_row": "Daraltılabilir satır", + "button_label": "Şimdi satın al", + "heading": "Başlık", + "email_signup_button_label": "Abone ol", + "accordion_heading": "Akordeon başlığı", + "contact_form_button_label": "Gönder", + "popup_link": "Açılır pencere bağlantısı", + "sign_up": "Kaydol", + "welcome_to_our_store": "Mağazamıza hoş geldiniz", + "be_bold": "Kalın yazılarla cesaretinizi sergileyin.", + "shop_our_latest_arrivals": "Yeni gelen ürünleri incele!" + }, + "info": { + "video_alt_text": "Yardımcı teknoloji kullanan kişiler için videonun içeriğini tarif et", + "video_autoplay": "Videolar varsayılan olarak sessize alınır", + "video_external": "YouTube veya Vimeo URL'si kullanın", + "carousel_layout_on_mobile": "Carousel, mobil cihazlarda kullanılır", + "carousel_hover_behavior_not_supported": "\"Carousel\" türü, bölüm seviyesinde seçildiğinde \"Carousel\" üzerine gelerek vurgulama desteği bulunmamaktadır", + "link_info": "İsteğe bağlı: simgeyi tıklanabilir hale getirir", + "grid_layout_on_mobile": "Mobil için ızgara düzeni kullanılır", + "logo_font": "Bir logo seçilmediğinde geçerli olur", + "checkout_buttons": "Alıcıların daha hızlı ödeme yapmasına olanak sağlar ve dönüşümü artırabilir. [Daha fazla bilgi edinin](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "Özel başlık", + "edit_presets_in_theme_settings": "Ön ayarları [tema ayarları](/editor?context=theme&category=typography) bölümünde düzenleyin", + "enable_filtering_info": "Filtreleri [Search & Discovery uygulaması](https://help.shopify.com/manual/online-store/search-and-discovery/filters) ile kişiselleştirin", + "manage_countries_regions": "[Ülkeleri/bölgeleri yönet](/admin/settings/markets)", + "manage_languages": "[Dilleri yönet](/admin/settings/languages)", + "transparent_background": "Okunabilirlik için şeffaf arka plan uygulanmış her bir şablonu inceleyin", + "aspect_ratio_adjusted": "Bazı düzenlerde ayarlandı", + "auto_open_cart_drawer": "Etkinleştirildiğinde sepete ürün eklenmesi durumunda sepet çekmecesi otomatik olarak açılır.", + "custom_liquid": "Gelişmiş kişiselleştirmeler oluşturmak için uygulama parçacıkları veya başka bir kod ekleyin. [Daha fazla bilgi edinin](https://shopify.dev/docs/api/liquid)", + "applies_on_image_only": "Yalnızca görseller için geçerlidir", + "hover_effects": "Ürün ve koleksiyon kartları için geçerlidir", + "pills_usage": "Uygulanan filtreler, indirim kodları ve arama önerileri için kullanılır" + }, + "categories": { + "product_list": "Öne çıkan koleksiyon", + "basic": "Basic", + "collection": "Koleksiyon", + "collection_list": "Koleksiyon listesi", + "footer": "Altbilgi", + "forms": "Formlar", + "header": "Üstbilgi", + "layout": "Düzen", + "links": "Bağlantılar", + "product": "Ürün", + "banners": "Banner'lar", + "collections": "Koleksiyonlar", + "custom": "Özel", + "decorative": "Dekoratif", + "products": "Ürünler", + "other_sections": "Diğer", + "storytelling": "Hikaye anlatıcılığı" + } +} diff --git a/locales/vi.json b/locales/vi.json new file mode 100644 index 000000000..8223f2810 --- /dev/null +++ b/locales/vi.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "Tải video: {{ description }}", + "sold_out": "Hết hàng", + "email_signup": { + "label": "Email", + "placeholder": "Địa chỉ email", + "success": "Cảm ơn bạn đã đăng ký!" + }, + "filter": "Bộ lọc", + "payment_methods": "Phương thức thanh toán", + "contact_form": { + "name": "Tên", + "email": "Email", + "phone": "Điện thoại", + "comment": "Nhận xét", + "post_success": "Cảm ơn bạn đã liên hệ với chúng tôi. Chúng tôi sẽ liên hệ lại với bạn trong thời gian sớm nhất.", + "error_heading": "Vui lòng điều chỉnh các mục sau:" + } + }, + "accessibility": { + "play_model": "Phát mô hình 3D", + "play_video": "Phát video", + "unit_price": "Đơn giá", + "country_results_count": "{{ count }} kết quả", + "slideshow_pause": "Tạm dừng bản trình chiếu", + "slideshow_play": "Phát bản trình chiếu", + "remove_item": "Xóa {{ title}}", + "skip_to_text": "Chuyển đến nội dung", + "skip_to_product_info": "Chuyển đến thông tin sản phẩm", + "skip_to_results_list": "Chuyển đến danh sách kết quả", + "new_window": "Mở trong cửa sổ mới.", + "close_dialog": "Đóng hộp thoại", + "reset_search": "Đặt lại tìm kiếm", + "search_results_count": "Đã tìm thấy {{ count }} kết quả cho \"{{ query }}\"", + "search_results_no_results": "Không tìm thấy kết quả cho \"{{ query }}\"", + "slideshow_next": "Trang chiếu sau", + "slideshow_previous": "Trang chiếu trước", + "filters": "Bộ lọc", + "filter_count": { + "one": "Đã áp dụng {{ count }} bộ lọc", + "other": "Đã áp dụng {{ count }} bộ lọc" + }, + "account": "Mở menu tài khoản", + "cart": "Giỏ hàng", + "cart_count": "Tổng mặt hàng trong giỏ hàng", + "menu": "Menu", + "country_region": "Quốc gia/Khu vực", + "slide_status": "Trang chiếu {{ index }}/{{ length }}", + "scroll_to": "Cuộn đến {{ title }}", + "loading_product_recommendations": "Đang tải đề xuất sản phẩm", + "discount": "Áp dụng một mã giảm giá", + "discount_applied": "Đã áp dụng mã giảm giá: {{ code }}", + "open_cart_drawer": "Mở giỏ hàng", + "inventory_status": "Trạng thái hàng trong kho", + "pause_video": "Tạm dừng video", + "find_country": "Tìm quốc gia", + "localization_region_and_language": "Mở bộ chọn khu vực và ngôn ngữ", + "open_search_modal": "Mở công cụ tìm kiếm", + "decrease_quantity": "Giảm số lượng", + "increase_quantity": "Tăng số lượng", + "rating": "Sản phẩm này được đánh giá {{ rating }}/5", + "quantity": "Số lượng", + "nested_product": "{{ product_title }} cho {{ parent_title }}" + }, + "actions": { + "add_to_cart": "Thêm vào giỏ hàng", + "clear_all": "Xóa tất cả", + "remove": "Xóa", + "view_in_your_space": "Xem tại không gian của bạn", + "show_filters": "Bộ lọc", + "clear": "Xóa", + "continue_shopping": "Tiếp tục mua sắm", + "log_in_html": "Bạn đã có tài khoản? Đăng nhập để thanh toán nhanh hơn.", + "see_items": { + "one": "Xem {{ count }} mặt hàng", + "other": "Xem {{ count }} mặt hàng" + }, + "view_all": "Xem tất cả", + "add": "Thêm", + "choose": "Chọn", + "added": "Đã thêm", + "show_less": "Ẩn bớt", + "show_more": "Hiển thị thêm", + "close": "Đóng", + "more": "Thêm", + "reset": "Đặt lại", + "zoom": "Thu phóng", + "close_dialog": "Đóng hộp thoại", + "back": "Quay lại", + "log_in": "Đăng nhập", + "log_out": "Đăng xuất", + "remove_discount": "Xóa mã giảm giá {{ code }}", + "enter_using_password": "Vào bằng mật khẩu", + "submit": "Gửi", + "enter_password": "Nhập mật khẩu", + "view_store_information": "Xem thông tin cửa hàng", + "apply": "Áp dụng", + "sign_in_options": "Các tùy chọn đăng nhập khác", + "sign_up": "Đăng ký", + "open_image_in_full_screen": "Mở hình ảnh ở chế độ toàn màn hình", + "sort": "Sắp xếp", + "show_all_options": "Hiển thị tất cả tùy chọn" + }, + "content": { + "reviews": "đánh giá", + "language": "Ngôn ngữ", + "localization_region_and_language": "Khu vực và ngôn ngữ", + "no_results_found": "Không tìm thấy kết quả nào", + "cart_total": "Tổng số tiền trong giỏ hàng", + "your_cart_is_empty": "Giỏ hàng của bạn đang trống", + "product_image": "Hình ảnh sản phẩm", + "product_information": "Thông tin sản phẩm", + "quantity": "Số lượng", + "product_total": "Tổng sản phẩm", + "cart_estimated_total": "Tổng số tiền ước tính", + "seller_note": "Hướng dẫn đặc biệt", + "cart_subtotal": "Tổng phụ", + "discounts": "Giảm giá", + "discount": "Giảm giá", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "Đã bao gồm thuế và thuế nhập khẩu. Ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "Đã bao gồm thuế và thuế nhập khẩu. Ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "taxes_included_shipping_at_checkout_with_policy_html": "Đã bao gồm thuế. Ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "taxes_included_shipping_at_checkout_without_policy": "Đã bao gồm thuế. Ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "Đã bao gồm thuế nhập khẩu. Thuế, ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "Đã bao gồm thuế nhập khẩu. Thuế, ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "Thuế, ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "taxes_at_checkout_shipping_at_checkout_without_policy": "Thuế, ưu đãi giảm giá và phí vận chuyển được tính khi thanh toán.", + "checkout": "Thanh toán", + "cart_title": "Giỏ hàng", + "price": "Giá", + "price_regular": "Giá thông thường", + "price_compare_at": "Giá gốc", + "price_sale": "Giá ưu đãi", + "duties_and_taxes_included": "Đã bao gồm thuế và thuế nhập khẩu.", + "duties_included": "Đã bao gồm thuế nhập khẩu.", + "shipping_policy_html": "Phí vận chuyển được tính khi thanh toán.", + "taxes_included": "Đã bao gồm thuế.", + "product_badge_sold_out": "Đã bán hết", + "product_badge_sale": "Giảm giá", + "search_input_label": "Tìm kiếm", + "search_input_placeholder": "Tìm kiếm", + "search_results": "Kết quả tìm kiếm", + "search_results_label": "Kết quả tìm kiếm", + "search_results_no_results": "Không tìm thấy kết quả cho \"{{ terms }}\". Hãy thử cụm từ tìm kiếm khác.", + "search_results_resource_articles": "Bài viết blog", + "search_results_resource_collections": "Bộ sưu tập", + "search_results_resource_pages": "Trang", + "search_results_resource_products": "Sản phẩm", + "search_results_resource_queries": "Gợi ý tìm kiếm", + "search_results_view_all": "Xem tất cả", + "search_results_view_all_button": "Xem tất cả", + "search_results_resource_products_count": { + "one": "{{ count }} sản phẩm", + "other": "{{ count }} sản phẩm" + }, + "grid_view": { + "default_view": "Mặc định", + "grid_fieldset": "Lưới cột", + "single_item": "Đơn", + "zoom_out": "Thu nhỏ" + }, + "recently_viewed_products": "Đã xem gần đây", + "unavailable": "Không có sẵn", + "collection_placeholder": "Tiêu đề bộ sưu tập", + "product_card_placeholder": "Tiêu đề sản phẩm", + "product_count": "Số lượng sản phẩm", + "item_count": { + "one": "{{ count }} mặt hàng", + "other": "{{ count }} mặt hàng" + }, + "errors": "Lỗi", + "featured_products": "Sản phẩm nổi bật", + "price_from": "Từ {{ price }}", + "search": "Tìm kiếm", + "search_results_no_results_check_spelling": "Không tìm thấy kết quả cho \"{{ terms }}\". Hãy kiểm tra chính tả hoặc sử dụng một từ hoặc cụm từ khác.", + "filters": "Bộ lọc", + "no_products_found": "Không tìm thấy sản phẩm nào.", + "price_filter_html": "Giá cao nhất là {{ price }}", + "use_fewer_filters_html": "Hãy thử sử dụng ít bộ lọc hơn hoặc xóa tất cả bộ lọc.", + "blog_details_separator": "|", + "account_title": "Tài khoản", + "account_title_personalized": "Xin chào {{ first_name }}", + "account_orders": "Đơn hàng", + "account_profile": "Hồ sơ", + "discount_code": "Mã giảm giá", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Đã bao gồm thuế và thuế nhập khẩu. Phí vận chuyển được tính khi thanh toán.", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "Đã bao gồm thuế và thuế nhập khẩu. Phí vận chuyển được tính khi thanh toán.", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Đã bao gồm thuế nhập khẩu. Phí vận chuyển được tính khi thanh toán.", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Đã bao gồm thuế nhập khẩu. Phí vận chuyển được tính khi thanh toán.", + "pickup_available_at_html": "Có thể nhận hàng tại {{ location }}", + "pickup_available_in": "Có thể nhận hàng tại chỗ, {{ pickup_time }}", + "pickup_not_available": "Hiện không có sẵn dịch vụ nhận hàng tại chỗ", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "Đọc thêm...", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "Thuế và phí vận chuyển được tính khi thanh toán.", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "Thuế và phí vận chuyển được tính khi thanh toán.", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "Đã bao gồm thuế. Phí vận chuyển được tính khi thanh toán.", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "Đã bao gồm thuế. Phí vận chuyển được tính khi thanh toán.", + "wrong_password": "Sai mật khẩu!", + "view_more_details": "Xem thêm thông tin", + "inventory_low_stock": "Sắp hết hàng", + "inventory_in_stock": "Còn hàng", + "inventory_out_of_stock": "Hết hàng", + "page_placeholder_title": "Tiêu đề trang", + "page_placeholder_content": "Chọn một trang để hiển thị nội dung.", + "placeholder_image": "Hình ảnh phần giữ chỗ", + "inventory_low_stock_show_count": { + "one": "Còn {{ count }}", + "other": "Còn {{ count }}" + }, + "powered_by": "Cửa hàng này sẽ được cung cấp bởi", + "store_owner_link_html": "Bạn có phải chủ cửa hàng không? Đăng nhập tại đây", + "shipping_discount_error": "Ưu đãi giảm giá vận chuyển được hiển thị tại trang thanh toán sau khi thêm địa chỉ", + "discount_code_error": "Không thể áp dụng mã giảm giá cho giỏ hàng của bạn", + "shipping_policy": "Phí vận chuyển được tính khi thanh toán." + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "Sử dụng mã thẻ quà tặng trực tuyến hoặc mã QR tại cửa hàng", + "title": "Đây là số dư thẻ quà tặng trị giá {{ value }} của bạn cho {{ shop }}!", + "subtext": "Thẻ quà tặng của bạn", + "shop_link": "Truy cập cửa hàng trực tuyến", + "add_to_apple_wallet": "Thêm vào Apple Wallet", + "qr_image_alt": "Mã QR — quét để đổi thẻ quà tặng", + "copy_code": "Sao chép mã thẻ quà tặng", + "expiration_date": "Hết hạn vào {{ expires_on }}", + "copy_code_success": "Đã sao chép mã thành công", + "expired": "Đã hết hạn" + } + }, + "placeholders": { + "password": "Mật khẩu", + "search": "Tìm kiếm", + "product_title": "Tiêu đề sản phẩm", + "collection_title": "Tiêu đề bộ sưu tập" + }, + "products": { + "product": { + "add_to_cart": "Thêm vào giỏ hàng", + "added_to_cart": "Đã thêm vào giỏ hàng", + "adding_to_cart": "Đang thêm...", + "add_to_cart_error": "Lỗi khi thêm vào giỏ hàng", + "sold_out": "Hết hàng", + "unavailable": "Không khả dụng" + } + }, + "fields": { + "separator": "đến" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} nhận xét", + "other": "{{ count }} nhận xét" + } + }, + "comment_form": { + "email": "Email", + "error": "Không thể đăng nhận xét, vui lòng xử lý các vấn đề sau:", + "heading": "Để lại nhận xét", + "message": "Thông báo", + "moderated": "Xin lưu ý, nhận xét cần được phê duyệt trước khi được đăng.", + "name": "Tên", + "post": "Gửi nhận xét", + "success_moderated": "Nhận xét đã được đăng, đang chờ kiểm duyệt", + "success": "Nhận xét đã được đăng" + } + } +} diff --git a/locales/zh-CN.json b/locales/zh-CN.json new file mode 100644 index 000000000..e300c4fad --- /dev/null +++ b/locales/zh-CN.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "加载视频:{{ description }}", + "sold_out": "售罄", + "email_signup": { + "label": "电子邮件", + "placeholder": "电子邮件地址", + "success": "感谢您的订阅!" + }, + "filter": "筛选条件", + "payment_methods": "付款方式", + "contact_form": { + "name": "名称", + "email": "电子邮件", + "phone": "电话", + "comment": "评论", + "post_success": "感谢您联系我们。我们会尽快回复您。", + "error_heading": "请调整以下内容:" + } + }, + "accessibility": { + "play_model": "演示 3D 模型", + "play_video": "播放视频", + "unit_price": "单价", + "country_results_count": "{{ count }} 个结果", + "slideshow_pause": "暂停幻灯片", + "slideshow_play": "播放幻灯片", + "remove_item": "删除 {{ title}}", + "skip_to_text": "跳到内容", + "skip_to_product_info": "跳至产品信息", + "skip_to_results_list": "跳到结果列表", + "new_window": "在新窗口中打开。", + "slideshow_next": "下一张幻灯片", + "slideshow_previous": "上一张幻灯片", + "close_dialog": "关闭对话框", + "reset_search": "重置搜索", + "search_results_count": "找到“{{ query }}”的 {{ count }} 条搜索结果", + "search_results_no_results": "未找到“{{ query }}”的相关结果", + "filters": "筛选条件", + "account": "打开账户菜单", + "cart": "购物车", + "cart_count": "购物车中的商品总数", + "filter_count": { + "one": "已应用 {{ count }} 个筛选条件", + "other": "已应用 {{ count }} 个筛选条件" + }, + "menu": "菜单", + "country_region": "国家/地区", + "slide_status": "第 {{ index }} 张幻灯片,共 {{ length }} 张", + "scroll_to": "滚动到 {{ title }}", + "loading_product_recommendations": "加载产品推荐", + "discount": "应用折扣码", + "discount_applied": "已应用折扣码:{{ code }}", + "open_cart_drawer": "打开购物车", + "inventory_status": "库存状态", + "pause_video": "暂停视频", + "localization_region_and_language": "打开区域和语言选择器", + "open_search_modal": "打开搜索", + "find_country": "查找国家/地区", + "decrease_quantity": "减少数量", + "increase_quantity": "增加数量", + "quantity": "数量", + "rating": "此产品的评分是 {{ rating }}/5", + "nested_product": "{{ product_title }}({{ parent_title }})" + }, + "actions": { + "add_to_cart": "添加到购物车", + "clear_all": "全部清除", + "remove": "删除", + "view_in_your_space": "在您的空间中查看", + "show_filters": "筛选条件", + "clear": "清除", + "continue_shopping": "继续购物", + "log_in_html": "已有账户?登录以快速结账。", + "see_items": { + "one": "查看 {{ count }} 件商品", + "other": "查看 {{ count }} 件商品" + }, + "view_all": "查看全部", + "add": "添加", + "choose": "选择", + "added": "已添加", + "show_less": "显示部分", + "show_more": "显示更多", + "close": "关闭", + "more": "更多", + "reset": "重置", + "zoom": "缩放", + "close_dialog": "关闭对话框", + "back": "返回", + "log_in": "登录", + "log_out": "登出", + "remove_discount": "删除折扣 {{ code }}", + "enter_using_password": "使用密码进入", + "submit": "提交", + "enter_password": "输入密码", + "view_store_information": "查看商店信息", + "apply": "应用", + "sign_in_options": "其他登录选项", + "sign_up": "注册", + "open_image_in_full_screen": "全屏打开图片", + "sort": "排序", + "show_all_options": "显示所有选项" + }, + "content": { + "reviews": "评价", + "no_results_found": "未找到结果", + "language": "语言", + "localization_region_and_language": "区域和语言", + "cart_total": "购物车总金额", + "your_cart_is_empty": "您的购物车为空", + "product_image": "产品图片", + "product_information": "产品信息", + "quantity": "数量", + "product_total": "产品总计", + "cart_estimated_total": "预计总额", + "seller_note": "特殊说明", + "cart_subtotal": "小计", + "discounts": "折扣", + "discount": "折扣", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "已含关税和税费。结账时计算折扣和运费。", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "已含关税和税费。结账时计算折扣和运费。", + "taxes_included_shipping_at_checkout_with_policy_html": "已含税费。结账时计算折扣和运费。", + "taxes_included_shipping_at_checkout_without_policy": "已含税费。结账时计算折扣和运费。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "已含关税。结账时计算税费、折扣和运费。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "已含关税。结账时计算税费、折扣和运费。", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "结账时计算税费、折扣和运费。", + "taxes_at_checkout_shipping_at_checkout_without_policy": "结账时计算税费、折扣和运费。", + "checkout": "结账", + "cart_title": "购物车", + "price": "价格", + "price_regular": "常规价格", + "price_compare_at": "原价", + "price_sale": "促销价", + "duties_and_taxes_included": "已含关税和税费。", + "duties_included": "已含关税。", + "shipping_policy_html": "结账时计算的运费。", + "taxes_included": "已含税费。", + "product_badge_sold_out": "售罄", + "product_badge_sale": "促销", + "grid_view": { + "default_view": "默认", + "grid_fieldset": "列网格", + "single_item": "单个", + "zoom_out": "缩小" + }, + "search_input_label": "搜索", + "search_input_placeholder": "搜索", + "search_results": "搜索结果", + "search_results_label": "搜索结果", + "search_results_no_results": "未找到“{{ terms }}”的相关结果。尝试其他搜索词。", + "search_results_resource_articles": "博客文章", + "search_results_resource_collections": "产品系列", + "search_results_resource_pages": "页面", + "search_results_resource_products": "产品", + "search_results_resource_queries": "搜索建议", + "search_results_view_all": "查看全部", + "search_results_view_all_button": "查看全部", + "search_results_resource_products_count": { + "one": "{{ count }} 件产品", + "other": "{{ count }} 件产品" + }, + "recently_viewed_products": "最近的浏览记录", + "unavailable": "不可用", + "collection_placeholder": "产品系列标题", + "product_card_placeholder": "产品标题", + "product_count": "产品数量", + "item_count": { + "one": "{{ count }} 件商品", + "other": "{{ count }} 件商品" + }, + "errors": "错误", + "search": "搜索", + "search_results_no_results_check_spelling": "未找到“{{ terms }}”的相关结果。请检查拼写或使用其他词或短语。", + "featured_products": "特色产品", + "no_products_found": "找不到产品。", + "price_from": "{{ price }} 起", + "use_fewer_filters_html": "尝试减少使用的筛选条件数量,或清除所有筛选条件。", + "filters": "筛选条件", + "price_filter_html": "最高价格为 {{ price }}", + "blog_details_separator": "|", + "read_more": "阅读详细内容…", + "account_title": "账户", + "account_title_personalized": "您好,{{ first_name }}", + "account_orders": "订单", + "account_profile": "资料", + "discount_code": "折扣码", + "pickup_available_at_html": "{{ location }} 提供取货服务", + "pickup_available_in": "提供取货服务:{{ pickup_time }}", + "pickup_not_available": "目前无法提供取货服务", + "pickup_ready_in": "{{ pickup_time }}", + "wrong_password": "密码错误", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "已含关税和税费。结账时计算运费。", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "已含关税和税费。结账时计算运费。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "已含关税。结账时计算运费。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "已含关税。结账时计算运费。", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "结账时计算的税费和运费。", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "结账时计算的税费和运费。", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "已含税费。结账时计算运费。", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "已含税费。结账时计算运费。", + "view_more_details": "查看更多详细信息", + "inventory_low_stock": "低库存", + "inventory_in_stock": "现货", + "inventory_out_of_stock": "缺货", + "page_placeholder_title": "页面标题", + "page_placeholder_content": "选择一个页面来显示其内容。", + "placeholder_image": "占位符图像", + "inventory_low_stock_show_count": { + "one": "剩余 {{ count }}", + "other": "剩余 {{ count }}" + }, + "shipping_discount_error": "添加地址后,结账时会显示运费折扣", + "discount_code_error": "折扣码无法应用于您的购物车", + "shipping_policy": "结账时计算运费。", + "powered_by": "此商店依托", + "store_owner_link_html": "您是否为店主?在此处登录" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "在线使用礼品卡代码或在店内使用二维码", + "title": "您的 {{ shop }} 的礼品卡余额为 {{ value }}!", + "subtext": "您的礼品卡", + "shop_link": "访问在线商店", + "add_to_apple_wallet": "添加到 Apple Wallet", + "qr_image_alt": "二维码 — 扫描兑换礼品卡", + "copy_code": "复制礼品卡代码", + "expiration_date": "过期日期:{{ expires_on }}", + "copy_code_success": "已成功复制代码", + "expired": "已过期" + } + }, + "placeholders": { + "password": "密码", + "search": "搜索", + "product_title": "产品标题", + "collection_title": "产品系列标题" + }, + "products": { + "product": { + "add_to_cart": "添加到购物车", + "added_to_cart": "添加到购物车", + "adding_to_cart": "正在添加...", + "add_to_cart_error": "添加到购物车时出错", + "sold_out": "售罄", + "unavailable": "不可售" + } + }, + "fields": { + "separator": "到" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} 条评论", + "other": "{{ count }} 条评论" + } + }, + "comment_form": { + "email": "电子邮件", + "error": "评论无法发布,请解决以下问题:", + "heading": "发表评论", + "message": "消息", + "moderated": "请注意,评论必须在发布之前获得批准。", + "name": "名称", + "post": "发布评论", + "success_moderated": "评论已发布,等待审核", + "success": "评论已发布" + } + } +} diff --git a/locales/zh-CN.schema.json b/locales/zh-CN.schema.json new file mode 100644 index 000000000..427929840 --- /dev/null +++ b/locales/zh-CN.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "边框", + "collapsible_row": "可折叠行", + "colors": "颜色", + "custom_section": "自定义分区", + "icon": "图标", + "logo_and_favicon": "logo 和网站图标", + "overlapping_blocks": "重叠块", + "product_buy_buttons": "购买按钮", + "product_description": "描述", + "product_price": "价格", + "product_variant_picker": "多属性选择器", + "slideshow": "幻灯片", + "typography": "版式", + "video": "视频", + "slideshow_controls": "幻灯片控件", + "size": "尺寸", + "spacing": "间距", + "product_recommendations": "推荐产品", + "product_media": "产品媒体文件", + "featured_collection": "特色产品系列", + "add_to_cart": "添加到购物车", + "email_signup": "电子邮件注册信息", + "submit_button": "提交按钮", + "grid_layout_selector": "网格布局选择器", + "image": "图片", + "list_items": "列表项", + "facets": "方面", + "variants": "多属性", + "styles": "样式", + "product_cards": "产品卡", + "buttons": "按钮", + "inputs": "输入", + "primary_button": "主要按钮", + "secondary_button": "辅助按钮", + "popovers": "弹出窗口", + "marquee": "选取框", + "pull_quote": "引用摘要", + "contact_form": "联系表", + "featured_product": "产品亮点", + "icons_with_text": "带文本的图标", + "product_list": "精选系列", + "spacer": "分隔区", + "alternating_content_rows": "交替行", + "accelerated_checkout": "快捷结账", + "accordion": "手风琴样式菜单", + "accordion_row": "手风琴样式菜单行", + "animations": "动画", + "announcement": "公告", + "announcement_bar": "公告栏", + "badges": "徽章", + "button": "按钮", + "cart": "购物车", + "cart_items": "购物车商品", + "cart_products": "购物车产品", + "cart_title": "购物车", + "collection": "产品系列", + "collection_card": "产品系列卡", + "collection_columns": "产品系列列", + "collection_container": "产品系列", + "collection_description": "产品系列描述", + "collection_image": "产品系列图片", + "collection_info": "产品系列信息", + "collection_list": "产品系列列表", + "collections": "产品系列", + "content": "内容", + "content_grid": "内容网格", + "details": "详细信息", + "divider": "分隔符", + "filters": "筛选和排序", + "follow_on_shop": "在 Shop 中关注", + "footer": "页脚", + "footer_utilities": "页脚工具", + "group": "组", + "header": "标头", + "heading": "标题", + "icons": "图标", + "image_with_text": "带文本的图片", + "input": "输入", + "logo": "logo", + "magazine_grid": "杂志网格", + "media": "媒体文件", + "menu": "菜单", + "mobile_layout": "移动设备布局", + "payment_icons": "付款图标", + "popup_link": "弹出窗口链接", + "predictive_search": "搜索弹出窗口", + "predictive_search_empty": "预测搜索为空", + "price": "价格", + "product": "产品", + "product_card": "产品卡", + "product_card_media": "媒体文件", + "product_card_rendering": "产品卡呈现", + "product_grid": "网格", + "product_grid_main": "产品网格", + "product_image": "产品图片", + "product_information": "产品信息", + "product_review_stars": "评论星级", + "quantity": "数量", + "row": "行", + "search": "搜索", + "section": "分区", + "selected_variants": "已选择的多属性", + "shop_the_look": "Shop 外观", + "slide": "幻灯片", + "social_media_links": "社交媒体链接", + "steps": "步骤", + "summary": "摘要", + "swatches": "样本", + "testimonials": "感言", + "text": "文本", + "title": "标题", + "utilities": "实用程序", + "search_input": "搜索输入", + "search_results": "搜索结果", + "read_only": "只读", + "collection_title": "产品系列标题", + "collections_bento": "产品系列列表:Bento", + "faq_section": "常见问题解答", + "hero": "主页横幅", + "jumbo_text": "巨型文本", + "view_all_button": "查看全部", + "video_section": "视频", + "page_layout": "页面布局", + "product_title": "产品标题", + "custom_liquid": "自定义 liquid", + "blog": "博客", + "blog_post": "博客文章", + "blog_posts": "博客文章", + "caption": "大标题", + "collection_card_image": "图片", + "collection_links": "产品系列链接", + "collection_links_spotlight": "产品系列链接:Spotlight", + "collection_links_text": "产品系列链接:文本", + "collections_carousel": "产品系列列表:轮播", + "collections_editorial": "产品系列列表:编辑", + "collections_grid": "产品系列列表:网格", + "copyright": "版权", + "count": "计数", + "divider_section": "分隔符", + "drawers": "抽屉菜单", + "editorial": "编辑样式布局", + "editorial_jumbo_text": "编辑样式布局:巨型文本", + "hero_marquee": "主页横幅:选取框", + "input_fields": "输入字段", + "local_pickup": "到店取货", + "marquee_section": "选取框", + "media_with_text": "带文本的媒体文件", + "page": "页面", + "page_content": "内容", + "policy_list": "政策链接", + "prices": "价格", + "product_list_button": "查看全部按钮", + "products_carousel": "精选系列:轮播", + "products_editorial": "精选系列:编辑", + "products_grid": "精选系列:网格", + "product_inventory": "产品库存", + "social_link": "社交媒体链接", + "split_showcase": "拆分展示", + "variant_pickers": "多属性选择器", + "pills": "椭圆形框", + "large_logo": "大 logo", + "description": "描述" + }, + "settings": { + "alignment": "对齐方式", + "autoplay": "自动播放", + "background": "背景", + "border_radius": "圆角半径", + "border_width": "边框厚度", + "borders": "边框", + "bottom_padding": "底部填充", + "button": "按钮", + "color": "颜色", + "colors": "颜色", + "content_alignment": "内容对齐方式", + "content_direction": "内容方向", + "content_position": "内容位置", + "cover_image_size": "封面图片大小", + "cover_image": "封面图片", + "custom_minimum_height": "自定义最小高度", + "custom_width": "自定义宽度", + "enable_video_looping": "视频循环", + "favicon": "网站图标", + "font_family": "字体系列", + "gap": "间隔", + "geometric_translate_y": "几何转换 Y", + "heading": "标题", + "icon": "图标", + "image": "图片", + "image_icon": "图片图标", + "image_opacity": "图片不透明度", + "image_position": "图片位置", + "image_ratio": "图片比", + "label": "标签", + "line_height": "行高", + "link": "链接", + "layout_gap": "布局间隔", + "make_section_full_width": "使分区展示全宽", + "minimum_height": "最小高度", + "opacity": "不透明度", + "overlay_opacity": "叠加不透明度", + "padding": "填充", + "primary_color": "链接", + "product": "产品", + "section_width": "分区宽度", + "size": "尺寸", + "slide_spacing": "幻灯片间距", + "slide_width": "幻灯片宽度", + "slideshow_fullwidth": "全宽幻灯片", + "style": "样式", + "text": "文本", + "text_case": "盒", + "top_padding": "顶部填充", + "video": "视频", + "video_alt_text": "替代文本", + "video_loop": "循环播放视频", + "video_position": "视频位置", + "width": "宽", + "z_index": "Z-index", + "limit_content_width": "限制内容宽度", + "color_scheme": "配色方案", + "inherit_color_scheme": "继承配色方案", + "product_count": "产品数量", + "product_type": "产品类型", + "content_width": "内容宽度", + "collection": "产品系列", + "enable_sticky_content": "台式设备上的粘性内容", + "error_color": "错误", + "success_color": "成功", + "primary_font": "一级字体", + "secondary_font": "二级字体", + "tertiary_font": "三级字体", + "columns": "列", + "items_to_show": "要显示的列", + "layout": "布局", + "layout_type": "类型", + "show_grid_layout_selector": "显示网格布局选择器", + "view_more_show": "显示“查看全部”按钮", + "image_gap": "图片间距", + "width_desktop": "台式电脑宽度", + "width_mobile": "移动设备宽度", + "border_style": "边框样式", + "height": "高度", + "thickness": "厚度", + "stroke": "线条", + "filter_style": "筛选样式", + "swatches": "样本", + "quick_add_colors": "快速添加颜色", + "divider_color": "分隔符", + "border_opacity": "边框不透明度", + "hover_background": "悬停背景", + "hover_borders": "悬停边框", + "hover_text": "悬停文本", + "primary_hover_color": "悬停链接", + "primary_button_text": "主要按钮文本", + "primary_button_background": "主要按钮背景", + "primary_button_border": "主要按钮边框", + "secondary_button_text": "辅助按钮文本", + "secondary_button_background": "辅助按钮背景", + "secondary_button_border": "辅助按钮边框", + "shadow_color": "阴影", + "limit_media_to_screen_height": "限制为屏幕高度", + "mobile_logo_image": "移动设备上的 logo", + "video_autoplay": "自动播放", + "video_cover_image": "封面图片", + "video_external_url": "URL", + "video_source": "源", + "background_color": "背景色", + "hide_padding": "隐藏填充", + "size_mobile": "移动端尺寸", + "pixel_size_mobile": "像素尺寸", + "percent_size_mobile": "百分比尺寸", + "unit": "单位", + "custom_mobile_size": "自定义移动端尺寸", + "fixed_height": "像素高度", + "fixed_width": "像素宽度", + "percent_height": "百分比高度", + "percent_width": "百分比宽度", + "percent_size": "百分比尺寸", + "pixel_size": "像素尺寸", + "first_row_media_position": "第一行媒体文件位置", + "accordion": "手风琴样式菜单", + "aspect_ratio": "纵横比", + "auto_rotate_announcements": "自动循环展示公告", + "auto_rotate_slides": "自动旋转幻灯片", + "badge_corner_radius": "圆角半径", + "badge_position": "在卡上的位置", + "badge_sale_color_scheme": "促销", + "badge_sold_out_color_scheme": "售罄", + "behavior": "行为", + "blur": "阴影模糊", + "border": "边框", + "bottom": "底部", + "card_image_height": "产品图片高度", + "carousel_on_mobile": "移动设备上的轮播", + "cart_count": "购物车计数", + "cart_items": "购物车商品", + "cart_related_products": "相关产品", + "cart_title": "购物车", + "cart_total": "购物车总计", + "cart_type": "类型", + "case": "盒", + "checkout_buttons": "快捷结账按钮", + "collection_list": "产品系列", + "collection_templates": "产品系列模板", + "content": "内容", + "corner_radius": "圆角半径", + "country_region": "国家/地区", + "currency_code": "货币代码", + "custom_height": "自定义高度", + "desktop_height": "台式电脑高度", + "direction": "方向", + "display": "显示", + "divider_thickness": "分隔符厚度", + "divider": "分隔符", + "dividers": "分隔符", + "drop_shadow": "投影阴影", + "empty_state_collection_info": "在输入搜索之前显示", + "empty_state_collection": "空状态产品系列", + "enable_filtering": "筛选条件", + "enable_grid_density": "网格布局控制", + "enable_sorting": "排序", + "enable_zoom": "启用缩放", + "equal_columns": "同等列", + "expand_first_group": "展开第一个组", + "extend_media_to_screen_edge": "将媒体文件延伸到屏幕边缘", + "extend_summary": "延伸到屏幕边缘", + "extra_large": "特大", + "extra_small": "特小", + "flag": "标记", + "font_price": "价格字体", + "font_weight": "字体粗细", + "font": "字体", + "full_width_first_image": "第一张全宽图片", + "full_width_on_mobile": "移动设备上的全宽", + "heading_preset": "标题预设", + "hide_unselected_variant_media": "隐藏未选择的多属性媒体文件", + "horizontal_gap": "水平间距", + "horizontal_offset": "阴影水平偏移", + "hover_behavior": "悬停行为", + "icon_background": "图标背景", + "icons": "图标", + "image_border_radius": "图片圆角半径", + "installments": "分期付款", + "integrated_button": "集成按钮", + "language_selector": "语言选择器", + "large": "大", + "left_padding": "左侧填充", + "left": "左侧", + "letter_spacing": "字母间距", + "limit_product_details_width": "限制产品详细信息宽度", + "link_preset": "链接预设", + "links": "链接", + "logo_font": "logo 字体", + "logo": "logo", + "loop": "循环播放", + "make_details_sticky_desktop": "台式电脑上的粘性内容", + "max_width": "最大宽度", + "media_height": "媒体文件高度", + "media_overlay": "媒体文件叠加", + "media_position": "媒体文件位置", + "media_type": "媒体文件类型", + "media_width": "媒体文件宽度", + "menu": "菜单", + "mobile_columns": "移动设备列", + "mobile_height": "移动设备高度", + "mobile_quick_add": "移动设备快速添加", + "motion_direction": "动作方向", + "motion": "动作", + "movement_direction": "移动方向", + "navigation_bar_color_scheme": "导航栏配色方案", + "navigation_bar": "导航栏", + "navigation": "导航", + "open_new_tab": "在新标签中打开链接", + "overlay_color": "叠加颜色", + "overlay": "叠加", + "padding_bottom": "下填充", + "padding_horizontal": "水平填充", + "padding_top": "上填充", + "page_width": "页面宽度", + "pagination": "分页", + "placement": "放置", + "position": "位置", + "preset": "预设", + "product_cards": "产品卡", + "product_pages": "产品页面", + "product_templates": "产品模板", + "products": "产品", + "quick_add": "快速添加", + "ratio": "比例", + "regular": "常规", + "review_count": "评论数量", + "right": "右侧", + "row_height": "行高度", + "row": "行", + "seller_note": "允许给卖家发备注", + "shape": "形状", + "show_as_accordion": "在移动设备上显示为手风琴样式菜单", + "show_sale_price_first": "先显示促销价", + "show_tax_info": "税务信息", + "show": "显示", + "small": "小", + "speed": "速度", + "statement": "对账单", + "sticky_header": "粘性标头", + "text_hierarchy": "文本层次结构", + "text_presets": "文本预设", + "title": "标题", + "top": "顶部", + "type": "类型", + "type_preset": "文本预设", + "underline_thickness": "下划线厚度", + "variant_images": "多属性图片", + "vendor": "厂商", + "vertical_gap": "垂直间距", + "vertical_offset": "阴影垂直偏移", + "vertical_on_mobile": "在移动设备上垂直", + "view_all_as_last_card": "“查看全部”为最后一张卡", + "weight": "重量", + "wrap": "换行", + "read_only": "只读", + "always_stack_buttons": "始终堆栈按钮", + "custom_mobile_width": "自定义移动设备宽度", + "gradient_direction": "梯度方向", + "headings": "标题", + "overlay_style": "叠加样式", + "shadow_opacity": "阴影不透明度", + "show_filter_label": "已应用筛选条件的文本标签", + "show_swatch_label": "样本文本标签", + "transparent_background": "透明背景", + "account": "账户", + "alignment_mobile": "移动设备对齐方式", + "align_baseline": "Align 文本的 Baseline", + "animation_repeat": "重复动画", + "add_discount_code": "允许购物车折扣", + "background_overlay": "背景叠加", + "background_media": "背景媒体文件", + "border_thickness": "边框厚度", + "bottom_row": "底部行", + "button_text_case": "文本大小写", + "button_text_weight": "文本粗细", + "card_hover_effect": "卡悬停效果", + "card_size": "卡尺寸", + "auto_open_cart_drawer": "“添加到购物车”自动打开抽屉", + "collection_count": "产品系列数量", + "collection_title_case": "产品系列标题大小写格式", + "custom_liquid": "Liquid 代码", + "default": "默认", + "default_logo": "默认 logo", + "divider_width": "分隔线宽度", + "effects": "效果", + "hide_logo_on_home_page": "在主页上隐藏 logo", + "horizontal_padding": "水平内边距", + "inventory_threshold": "低库存阈值", + "inverse": "反转色", + "inverse_logo": "反转色 logo", + "layout_style": "样式", + "length": "长度", + "mobile_card_size": "移动卡尺寸", + "mobile_pagination": "移动分页", + "open_row_by_default": "默认打开行", + "page": "页面", + "page_transition_enabled": "页面转换", + "product_and_card_title_case": "产品和卡片标题大小写格式", + "product_title_case": "产品标题大小写格式", + "right_padding": "右侧填充", + "search": "搜索", + "search_icon": "搜索图标", + "search_position": "位置", + "search_row": "行", + "show_author": "作者", + "show_alignment": "显示对齐方式", + "show_count": "显示计数", + "show_date": "日期", + "show_inventory_quantity": "显示低库存数量", + "show_pickup_availability": "显示取货服务提供情况", + "show_search": "显示搜索", + "text_label_case": "文本标签大小写格式", + "transition_to_main_product": "产品卡到产品页面转换", + "use_inverse_logo": "使用反转色 logo", + "vertical_padding": "垂直内边距", + "visibility": "可见性", + "product_corner_radius": "产品圆角半径", + "card_corner_radius": "卡片圆角半径", + "blurred_reflection": "模糊的倒影", + "reflection_opacity": "倒影不透明度", + "show_second_image_on_hover": "在悬停时显示第二张图片", + "media": "媒体文件", + "product_card_carousel": "显示轮播", + "media_fit": "媒体文件适应", + "scroll_speed": "下次公告时间" + }, + "options": { + "adapt_to_image": "适应图片", + "apple": "苹果", + "arrow": "箭头", + "auto": "自动", + "banana": "香蕉", + "bottle": "瓶子", + "box": "盒子", + "buttons": "按钮", + "carrot": "胡萝卜", + "center": "居中", + "chat_bubble": "聊天泡泡", + "clipboard": "剪贴板", + "contain": "包含", + "counter": "计数器", + "cover": "封面", + "custom": "自定义", + "dairy_free": "不含乳制品", + "dairy": "乳制品", + "default": "默认", + "dropdowns": "下拉菜单", + "dots": "点", + "dryer": "吹风机", + "end": "结束", + "eye": "眼睛", + "facebook": "Facebook", + "fill": "填充", + "fire": "火", + "fit": "适应", + "full": "全屏", + "full_and_page": "全屏背景,页宽内容", + "gluten_free": "无麸质", + "heading": "标题", + "heart": "心形", + "horizontal": "水平", + "instagram": "Instagram", + "iron": "铁", + "landscape": "横向", + "large": "大", + "leaf": "树叶", + "leather": "皮革", + "lg": "L", + "lightning_bolt": "闪电束", + "link": "链接", + "lipstick": "口红", + "lock": "锁", + "lowercase": "小写", + "m": "M", + "map_pin": "图钉", + "medium": "中", + "none": "无", + "numbers": "数字", + "nut_free": "不含坚果", + "outline": "轮廓", + "page": "页面", + "pants": "裤装", + "paw_print": "爪印", + "pepper": "胡椒粉", + "perfume": "香水", + "pinterest": "Pinterest", + "plane": "飞机", + "plant": "绿植", + "portrait": "纵向", + "price_tag": "价格标签", + "question_mark": "问号", + "recycle": "回收利用", + "return": "退货", + "ruler": "直尺", + "s": "S", + "sentence": "句子", + "serving_dish": "餐盘", + "shirt": "衬衫", + "shoe": "鞋", + "silhouette": "剪影", + "small": "小", + "snapchat": "Snapchat", + "snowflake": "雪花", + "solid": "实心", + "space_between": "间距", + "square": "方形", + "star": "星星", + "start": "开始", + "stopwatch": "秒表", + "tiktok": "TikTok", + "truck": "卡车", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "大写", + "vertical": "垂直", + "vimeo": "Vimeo", + "washing": "洗涤剂", + "circle": "圆形", + "swatches": "样本", + "full_and_page_offset_left": "全屏背景,页宽内容,左偏移", + "full_and_page_offset_right": "全屏背景,页宽内容,右偏移", + "offset_left": "左偏移", + "offset_right": "右偏移", + "page_center_aligned": "页面,居中对齐", + "page_left_aligned": "页面,左对齐", + "page_right_aligned": "页面,右对齐", + "button": "按钮", + "caption": "大标题", + "h1": "标题 1", + "h2": "标题 2", + "h3": "标题 3", + "h4": "标题 4", + "h5": "标题 5", + "h6": "标题 6", + "paragraph": "段落", + "primary": "一级", + "secondary": "二级", + "tertiary": "三级", + "chevron_left": "向左 V 形", + "chevron_right": "向右 V 形", + "diamond": "菱形", + "grid": "网格", + "parallelogram": "平行四边形", + "rounded": "圆形", + "fit_content": "适应", + "pills": "椭圆形框", + "heavy": "粗", + "thin": "细", + "drawer": "抽屉", + "preview": "预览", + "text": "文本", + "video_uploaded": "已上传", + "video_external_url": "外部 URL", + "up": "向上", + "down": "向下", + "gradient": "渐变", + "fixed": "固定", + "pixel": "像素", + "percent": "百分比", + "above_carousel": "轮播上方", + "all": "全部", + "always": "始终", + "arrows_large": "大箭头", + "arrows": "箭头", + "aspect_ratio": "纵横比", + "balance": "Balance", + "bento": "Bento", + "black": "黑色", + "bluesky": "Bluesky", + "body_large": "正文(大)", + "body_regular": "正文(常规)", + "body_small": "正文(小)", + "bold": "粗体", + "bottom_left": "左下方", + "bottom_right": "右下方", + "bottom": "底部", + "capitalize": "大写", + "caret": "脱字符号", + "carousel": "轮播", + "check_box": "复选框", + "chevron_large": "大 V 形标志", + "chevron": "V 形标志", + "chevrons": "V 形标志", + "classic": "经典", + "collection_images": "产品系列图片", + "color": "颜色", + "complementary": "互补", + "dissolve": "叠化", + "dotted": "点线", + "editorial": "编辑样式布局", + "extra_large": "特大", + "extra_small": "特小", + "featured_collections": "特色产品系列", + "featured_products": "特色产品", + "font_primary": "主要", + "font_secondary": "二级", + "font_tertiary": "三级", + "forward": "前进", + "full_screen": "全屏", + "heading_extra_large": "标题(特大)", + "heading_extra_small": "标题(特小)", + "heading_large": "标题(大)", + "heading_regular": "标题(常规)", + "heading_small": "标题(小)", + "icon": "图标", + "image": "图片", + "input": "输入", + "inside_carousel": "轮播内部", + "inverse_large": "反转色(大)", + "inverse": "反转色", + "large_arrows": "大箭头", + "large_chevrons": "大 V 形标志", + "left": "左侧", + "light": "浅色", + "linkedin": "LinkedIn", + "loose": "松散", + "media_first": "媒体文件第一", + "media_second": "媒体文件第二", + "modal": "模态窗口", + "narrow": "窄", + "never": "永不", + "next_to_carousel": "轮播旁", + "normal": "正常", + "nowrap": "不换行", + "off_media": "媒体文件关", + "on_media": "媒体文件开", + "on_scroll_up": "向上滚动时", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "椭圆形", + "plus": "Plus", + "pretty": "漂亮", + "price": "价格", + "primary_style": "主要样式", + "rectangle": "矩形", + "regular": "常规", + "related": "相关", + "reverse": "逆转", + "rich_text": "富文本", + "right": "右侧", + "secondary_style": "辅助样式", + "semibold": "半粗体", + "shaded": "阴影", + "show_second_image": "显示第二张图片", + "single": "单个", + "slide_left": "向左滑动", + "slide_up": "向上滑动", + "spotify": "Spotify", + "stack": "堆栈", + "text_only": "仅文本", + "threads": "Threads", + "thumbnails": "缩略图", + "tight": "紧凑", + "top_left": "左上方", + "top_right": "右上方", + "top": "顶部", + "two_number": "2", + "two_thirds": "2/3", + "underline": "下划线", + "video": "视频", + "wide": "宽", + "youtube": "YouTube", + "accent": "主题色", + "below_image": "图片下方", + "blur": "模糊", + "body": "正文", + "button_primary": "主要按钮", + "button_secondary": "辅助按钮", + "compact": "简洁", + "crop_to_fit": "裁剪调整", + "hidden": "隐藏", + "hint": "提示", + "lift": "提升", + "maintain_aspect_ratio": "维持纵横比", + "off": "关", + "on_image": "图片上方", + "reveal": "显示", + "scale": "扩大规模", + "social_bluesky": "社交媒体:Bluesky", + "social_facebook": "社交媒体:Facebook", + "social_instagram": "社交媒体:Instagram", + "social_linkedin": "社交媒体:LinkedIn", + "social_pinterest": "社交媒体:Pinterest", + "social_snapchat": "社交媒体:Snapchat", + "social_spotify": "社交媒体:Spotify", + "social_threads": "社交媒体:Threads", + "social_tiktok": "社交媒体:TikTok", + "social_tumblr": "社交媒体:Tumblr", + "social_twitter": "社交媒体:X (Twitter)", + "social_whatsapp": "社交媒体:WhatsApp", + "social_vimeo": "社交媒体:Vimeo", + "social_youtube": "社交媒体:YouTube", + "spotlight": "聚焦", + "standard": "标准", + "subheading": "副标题", + "subtle_zoom": "缩放" + }, + "content": { + "advanced": "高级", + "background_image": "背景图片", + "background_video": "背景视频", + "block_size": "块尺寸", + "borders": "边框", + "describe_the_video_for": "为使用屏幕阅读器的客户描述视频。[详细了解](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "分区尺寸", + "slideshow_width": "幻灯片宽度", + "typography": "版式", + "width_is_automatically_optimized": "宽度会针对移动设备进行自动优化。", + "complementary_products": "必须使用 Search & Discovery 应用设置互补产品。[详细了解](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "列会针对移动设备进行自动优化", + "content_width": "只有将分区宽度设置为全宽时,内容宽度才适用。", + "adjustments_affect_all_content": "应用于此块中的所有内容", + "responsive_font_sizes": "尺寸自动缩放,适合各种屏幕尺寸", + "buttons": "按钮", + "swatches": "样本", + "variant_settings": "多属性设置", + "background": "背景", + "cards_layout": "卡片布局", + "section_layout": "分区布局", + "mobile_size": "移动端尺寸", + "appearance": "外观", + "arrows": "箭头", + "body_size": "正文大小", + "bottom_row_appearance": "底行外观", + "carousel_navigation": "轮播导航", + "carousel_pagination": "轮播分页", + "copyright": "版权", + "edit_logo_in_theme_settings": "在[模板设置](/editor?context=theme&category=logo%20and%20favicon)中编辑 logo", + "edit_price_in_theme_settings": "在[模板设置](/editor?context=theme&category=currency%20code)中编辑价格格式", + "edit_variants_in_theme_settings": "在[模板设置](/editor?context=theme&category=variants)中编辑多属性样式", + "email_signups_create_customer_profiles": "注册添加[客户资料](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "若要显示此按钮,则必须安装 Shop 渠道并激活 Shop Pay。[详细了解](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "字体", + "grid": "网格", + "heading_size": "标题大小", + "image": "图片", + "input": "输入", + "layout": "布局", + "link": "链接", + "link_padding": "链接填充", + "localization": "本地化", + "logo": "logo", + "margin": "边距", + "media": "媒体文件", + "media_1": "媒体文件 1", + "media_2": "媒体文件 2", + "menu": "菜单", + "mobile_layout": "移动设备布局", + "padding": "填充", + "padding_desktop": "台式电脑填充", + "paragraph": "段落", + "policies": "政策", + "popup": "弹出窗口", + "search": "搜索", + "size": "大小", + "social_media": "社交媒体", + "submit_button": "提交按钮", + "text_presets": "文本预设", + "transparent_background": "透明背景", + "typography_primary": "主要版式", + "typography_secondary": "次要版式", + "typography_tertiary": "三级版式", + "mobile_width": "移动设备宽度", + "width": "宽度", + "visible_if_collection_has_more_products": "如果产品系列中的产品未全部显示,则显示", + "carousel": "轮播", + "colors": "颜色", + "collection_page": "产品系列页面", + "copyright_info": "了解如何[编辑您的版权声明](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "客户账户", + "edit_empty_state_collection_in_theme_settings": "在[模板设置](/editor?context=theme&category=search)中编辑空状态的产品系列", + "grid_layout": "网格布局", + "home_page": "主页", + "images": "图片", + "inverse_logo_info": "当透明标头背景设置为反转色时使用", + "manage_customer_accounts": "在客户账户设置中[管理可见性](/admin/settings/customer_accounts)。不支持旧版账户。", + "manage_policies": "[管理政策](/admin/settings/legal)", + "product_page": "产品页面", + "text": "文本", + "thumbnails": "缩略图", + "visibility": "可见性", + "app_required_for_ratings": "需要通过应用来进行产品评分。[了解详情](https://help.shopify.com/manual/apps)", + "icon": "图标", + "manage_store_name": "[管理商店名称](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "显示父分区的产品系列", + "resource_reference_collection_card_image": "显示父产品系列的图片", + "resource_reference_collection_title": "显示父产品系列的标题", + "resource_reference_product": "自动连接到父产品", + "resource_reference_product_card": "显示父分区的产品", + "resource_reference_product_inventory": "显示父产品的库存", + "resource_reference_product_price": "显示父产品的价格", + "resource_reference_product_recommendations": "显示基于父产品的推荐", + "resource_reference_product_review": "显示父产品的评论", + "resource_reference_product_swatches": "显示父产品的样本", + "resource_reference_product_title": "显示父产品的标题", + "resource_reference_product_variant_picker": "显示父产品的多属性", + "resource_reference_product_media": "显示父产品的媒体文件", + "product_media": "产品媒体文件", + "section_link": "分区链接" + }, + "html_defaults": { + "share_information_about_your": "

与客户分享有关您品牌的信息。描述产品、发布公告或欢迎客户访问您的商店。

" + }, + "text_defaults": { + "button_label": "立即购买", + "collapsible_row": "可折叠行", + "heading": "标题", + "email_signup_button_label": "订阅", + "accordion_heading": "手风琴样式菜单标题", + "contact_form_button_label": "提交", + "popup_link": "弹出窗口链接", + "sign_up": "注册", + "welcome_to_our_store": "欢迎访问我们的商店", + "be_bold": "勇敢。", + "shop_our_latest_arrivals": "选购新品!" + }, + "info": { + "video_alt_text": "为辅助技术用户描述视频", + "video_autoplay": "视频将默认静音", + "video_external": "使用 YouTube 或 Vimeo URL", + "carousel_layout_on_mobile": "可在移动设备上使用轮播", + "link_info": "可选:使图标可点击", + "carousel_hover_behavior_not_supported": "当在分区级别选择“轮播”类型时,不支持“轮播”悬停", + "checkout_buttons": "加快客户的结账速度,提高转化率。[详细了解](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "自定义标题", + "edit_presets_in_theme_settings": "在[模板设置](/editor?context=theme&category=typography)中编辑预设", + "enable_filtering_info": "使用 [Search & Discovery 应用](https://help.shopify.com/manual/online-store/search-and-discovery/filters) 自定义筛选条件", + "grid_layout_on_mobile": "网格布局用于移动设备", + "logo_font": "仅当未选中 logo 时适用", + "manage_countries_regions": "[管理国家/地区](/admin/settings/markets)", + "manage_languages": "[管理语言](/admin/settings/languages)", + "transparent_background": "检查已应用透明背景的每个模板的可读性", + "aspect_ratio_adjusted": "在某些布局中进行了调整", + "auto_open_cart_drawer": "启用后,当产品添加到购物车时,购物车抽屉会自动打开。", + "custom_liquid": "添加应用代码片段或其他代码以创建高级自定义。[详细了解](https://shopify.dev/docs/api/liquid)", + "hover_effects": "应用于产品和产品系列卡", + "pills_usage": "用于应用的筛选条件、折扣码和搜索建议", + "applies_on_image_only": "仅适用于图像" + }, + "categories": { + "basic": "Basic", + "collection": "产品系列", + "collection_list": "产品系列列表", + "footer": "页脚", + "forms": "表单", + "header": "标头", + "layout": "布局", + "links": "链接", + "product": "产品", + "product_list": "精选系列", + "banners": "条幅", + "collections": "产品系列", + "custom": "自定义", + "decorative": "装饰", + "products": "产品", + "other_sections": "其他", + "storytelling": "故事讲述" + } +} diff --git a/locales/zh-TW.json b/locales/zh-TW.json new file mode 100644 index 000000000..7982fcd11 --- /dev/null +++ b/locales/zh-TW.json @@ -0,0 +1,271 @@ +{ + "blocks": { + "load_video": "載入影片:{{ description }}", + "sold_out": "售罄", + "email_signup": { + "label": "電子郵件", + "placeholder": "電子郵件地址", + "success": "感謝您的訂閱!" + }, + "filter": "篩選條件", + "payment_methods": "付款方式", + "contact_form": { + "name": "名稱", + "email": "電子郵件", + "phone": "電話", + "comment": "留言", + "post_success": "感謝您聯絡我們。我們會盡快回覆您。", + "error_heading": "請調整以下內容:" + } + }, + "accessibility": { + "play_model": "播放 3D 模型", + "play_video": "播放影片", + "unit_price": "單價", + "country_results_count": "{{ count }} 項結果", + "slideshow_pause": "暫停素材輪播", + "slideshow_play": "播放素材輪播", + "remove_item": "移除 {{ title}}", + "skip_to_text": "跳至內容", + "skip_to_product_info": "跳到商品資訊", + "skip_to_results_list": "跳到結果清單", + "new_window": "在新視窗中開啟。", + "slideshow_next": "下一張投影片", + "slideshow_previous": "上一張投影片", + "close_dialog": "關閉對話", + "reset_search": "重設搜尋條件", + "search_results_count": "找到 {{ count }} 筆「{{ query }}」的搜尋結果", + "search_results_no_results": "找不到「{{ query }}」的相關結果", + "filters": "篩選條件", + "account": "開啟帳戶選單", + "cart": "購物車", + "cart_count": "購物車內品項總數", + "filter_count": { + "one": "已套用 {{ count }} 個篩選條件", + "other": "已套用 {{ count }} 個篩選條件" + }, + "menu": "選單", + "country_region": "國家/地區", + "slide_status": "第 {{ index }} 張投影片,共 {{ length }} 張", + "scroll_to": "捲動至 {{ title }}", + "loading_product_recommendations": "正在載入商品推薦", + "discount": "套用折扣代碼", + "discount_applied": "套用的折扣代碼:{{ code }}", + "open_cart_drawer": "開啟購物車", + "inventory_status": "庫存狀態", + "pause_video": "暫停影片", + "find_country": "尋找國家/地區", + "localization_region_and_language": "開啟地區和語言選擇器", + "open_search_modal": "開啟購物車搜尋", + "decrease_quantity": "減少數量", + "increase_quantity": "增加數量", + "quantity": "數量", + "rating": "本商品的評分為 {{ rating }}/5", + "nested_product": "適用於 {{ parent_title }} 的 {{ product_title }}" + }, + "actions": { + "add_to_cart": "加入購物車", + "clear_all": "全部清除", + "remove": "移除", + "view_in_your_space": "在您的空間中檢視", + "show_filters": "篩選條件", + "clear": "清除", + "continue_shopping": "繼續購物", + "log_in_html": "已有帳號?登入以加速結帳。", + "see_items": { + "one": "查看 {{ count }} 個品項", + "other": "查看 {{ count }} 個品項" + }, + "view_all": "檢視全部", + "add": "新增", + "choose": "選擇", + "added": "已新增", + "show_less": "顯示較少", + "show_more": "顯示更多", + "close": "關閉", + "more": "更多", + "reset": "重設", + "zoom": "縮放", + "close_dialog": "關閉對話", + "apply": "套用", + "back": "返回", + "log_in": "登入", + "log_out": "登出", + "remove_discount": "移除折扣 {{ code }}", + "enter_using_password": "使用密碼輸入", + "submit": "提交", + "enter_password": "輸入密碼", + "view_store_information": "檢視商店資訊", + "sign_in_options": "其他登入選項", + "open_image_in_full_screen": "全螢幕開啟圖片", + "sign_up": "註冊", + "sort": "排序", + "show_all_options": "顯示所有選項" + }, + "content": { + "reviews": "評論", + "no_results_found": "找不到結果", + "language": "語言", + "localization_region_and_language": "地區和語言", + "cart_total": "購物車總金額", + "your_cart_is_empty": "您的購物車是空的", + "cart_estimated_total": "估計總金額", + "seller_note": "特別指示", + "cart_subtotal": "小計", + "discounts": "折扣", + "discount": "折扣", + "duties_and_taxes_included_shipping_at_checkout_with_policy_html": "已包含關稅和稅額。結帳時計算折扣和運費。", + "duties_and_taxes_included_shipping_at_checkout_without_policy": "已包含關稅和稅額。結帳時計算折扣和運費。", + "taxes_included_shipping_at_checkout_with_policy_html": "已包含稅額。結帳時計算折扣和運費。", + "taxes_included_shipping_at_checkout_without_policy": "已包含稅額。結帳時計算折扣和運費。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html": "已包含關稅。結帳時計算稅額、折扣和運費。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy": "已包含關稅。結帳時計算稅額、折扣和運費。", + "taxes_at_checkout_shipping_at_checkout_with_policy_html": "結帳時計算稅額、折扣和運費。", + "taxes_at_checkout_shipping_at_checkout_without_policy": "結帳時計算稅額、折扣和運費。", + "checkout": "結帳", + "cart_title": "購物車", + "product_image": "產品圖片", + "product_information": "產品資訊", + "product_total": "商品總數", + "quantity": "數量", + "price": "價格", + "price_regular": "定價", + "price_compare_at": "比較售價", + "price_sale": "促銷價", + "duties_and_taxes_included": "已包含關稅和稅額。", + "duties_included": "已包含關稅。", + "shipping_policy_html": "結帳時計算運費。", + "taxes_included": "已包含稅額。", + "product_badge_sold_out": "售罄", + "product_badge_sale": "特賣", + "search_input_label": "搜尋", + "search_input_placeholder": "搜尋", + "search_results": "搜尋結果", + "search_results_label": "搜尋結果", + "search_results_no_results": "找不到「{{ terms }}」的相關結果。請試著搜尋其他內容。", + "search_results_resource_articles": "網誌文章", + "search_results_resource_collections": "商品系列", + "search_results_resource_pages": "頁面", + "search_results_resource_products": "商品", + "search_results_resource_queries": "搜尋建議", + "search_results_view_all": "檢視全部", + "search_results_view_all_button": "檢視全部", + "search_results_resource_products_count": { + "one": "{{ count }} 項商品", + "other": "{{ count }} 項商品" + }, + "grid_view": { + "default_view": "預設", + "grid_fieldset": "欄網格", + "single_item": "單一", + "zoom_out": "縮小" + }, + "unavailable": "不適用", + "collection_placeholder": "商品系列標題", + "product_card_placeholder": "產品名稱", + "recently_viewed_products": "最近檢視的項目", + "product_count": "商品數量", + "item_count": { + "one": "{{ count }} 個品項", + "other": "{{ count }} 個品項" + }, + "errors": "錯誤", + "search": "搜尋", + "search_results_no_results_check_spelling": "找不到「{{ terms }}」的相關結果。請檢查拼字或使用其他字詞。", + "featured_products": "精選商品", + "price_from": "從 {{ price }} 起", + "filters": "篩選條件", + "no_products_found": "找不到任何商品。", + "price_filter_html": "最高價格為 {{ price }}", + "use_fewer_filters_html": "嘗試使用較少的篩選條件,或清除所有篩選條件。", + "blog_details_separator": "|", + "account_title": "帳號", + "account_title_personalized": "{{ first_name }},您好!", + "account_orders": "訂單", + "account_profile": "個人檔案", + "discount_code": "折扣代碼", + "duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "已包含關稅和稅額。結帳時計算運費。", + "duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts": "已包含關稅和稅額。結帳時計算運費。", + "duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "已包含關稅。結帳時計算運費。", + "duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "已包含關稅。結帳時計算運費。", + "pickup_available_at_html": "可提供取貨服務的地點:{{ location }}", + "pickup_available_in": "可提供取貨服務的時間:{{ pickup_time }}", + "pickup_not_available": "目前無法提供取貨服務", + "pickup_ready_in": "{{ pickup_time }}", + "read_more": "繼續閱讀…", + "taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html": "結帳時計算稅額和運費。", + "taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts": "結帳時計算稅額和運費。", + "taxes_included_shipping_at_checkout_with_policy_without_discounts_html": "已包含稅額。結帳時計算運費。", + "taxes_included_shipping_at_checkout_without_policy_without_discounts": "已包含稅額。結帳時計算運費。", + "view_more_details": "檢視更多詳細資訊", + "wrong_password": "密碼錯誤", + "inventory_low_stock": "庫存不足", + "inventory_in_stock": "有庫存", + "inventory_out_of_stock": "無庫存", + "inventory_low_stock_show_count": { + "one": "尚餘 {{ count }}", + "other": "尚餘 {{ count }}" + }, + "powered_by": "本商店技術支援來自", + "store_owner_link_html": "您是商店擁有人嗎?請在此登入", + "shipping_discount_error": "新增地址後,結帳時將顯示運費折扣", + "discount_code_error": "折扣代碼無法套用至您的購物車", + "page_placeholder_title": "頁面標題", + "page_placeholder_content": "選取一個頁面,即可顯示其內容。", + "placeholder_image": "佔位符圖片", + "shipping_policy": "結帳時計算運費。" + }, + "gift_cards": { + "issued": { + "how_to_use_gift_card": "請在網路商店使用禮品卡代碼或在實體商店使用 QR 碼", + "title": "這是您在 {{ shop }} 餘額為 {{ value }} 的禮品卡!", + "subtext": "您的禮品卡", + "shop_link": "造訪網路商店", + "add_to_apple_wallet": "加入 Apple 錢包", + "qr_image_alt": "QR 碼:掃描以兌換禮品卡", + "copy_code": "複製禮品卡代碼", + "expiration_date": "於 {{ expires_on }}到期", + "copy_code_success": "已成功複製代碼", + "expired": "已到期" + } + }, + "placeholders": { + "password": "密碼", + "search": "搜尋", + "product_title": "產品名稱", + "collection_title": "商品系列標題" + }, + "products": { + "product": { + "add_to_cart": "加入購物車", + "added_to_cart": "已放入購物車", + "adding_to_cart": "正在新增…", + "add_to_cart_error": "加入購物車時發生錯誤", + "sold_out": "售罄", + "unavailable": "無可用資料" + } + }, + "fields": { + "separator": "至" + }, + "blogs": { + "article": { + "comment_author_separator": "•", + "comments_heading": { + "one": "{{ count }} 則留言", + "other": "{{ count }} 則留言" + } + }, + "comment_form": { + "email": "電子郵件", + "error": "無法發布留言,請處理以下問題:", + "heading": "發表留言", + "message": "訊息", + "moderated": "請注意,留言須先通過審核才能發布。", + "name": "名稱", + "post": "發布留言", + "success_moderated": "已發布留言,正等待審核", + "success": "已發布留言" + } + } +} diff --git a/locales/zh-TW.schema.json b/locales/zh-TW.schema.json new file mode 100644 index 000000000..2afa2e20d --- /dev/null +++ b/locales/zh-TW.schema.json @@ -0,0 +1,929 @@ +{ + "names": { + "404": "404", + "borders": "邊框", + "collapsible_row": "可折疊的橫列", + "colors": "顏色", + "custom_section": "顧客區段", + "icon": "圖示", + "logo_and_favicon": "標誌和 Favicon", + "overlapping_blocks": "重疊區塊", + "product_buy_buttons": "購買按鈕", + "product_description": "說明", + "product_price": "價格", + "product_variant_picker": "子類選擇器", + "slideshow": "素材輪播", + "typography": "字體", + "video": "影片", + "slideshow_controls": "素材輪播控制", + "size": "尺寸", + "spacing": "間距", + "product_recommendations": "推薦商品", + "product_media": "商品多媒體檔案", + "featured_collection": "精選商品系列", + "add_to_cart": "加入購物車", + "email_signup": "電子郵件訂閱", + "submit_button": "提交按鈕", + "grid_layout_selector": "網格版面配置選擇器", + "image": "圖片", + "list_items": "清單項目", + "facets": "面向", + "variants": "子類", + "styles": "樣式", + "product_cards": "商品卡", + "primary_button": "主要按鈕", + "secondary_button": "次要按鈕", + "popovers": "彈出視窗", + "buttons": "按鈕", + "inputs": "輸入", + "marquee": "跑馬燈", + "alternating_content_rows": "摺疊列", + "pull_quote": "強調引言", + "contact_form": "聯絡表單", + "featured_product": "商品重點說明", + "icons_with_text": "附文字圖示", + "accelerated_checkout": "加速結帳作業", + "accordion": "摺疊式", + "accordion_row": "摺疊列", + "animations": "動畫", + "announcement": "公告", + "announcement_bar": "公告列", + "badges": "徽章", + "button": "按鈕", + "cart": "購物車", + "cart_items": "購物車品項", + "cart_products": "購物車商品", + "cart_title": "購物車", + "collection": "商品系列", + "collection_card": "商品系列卡片", + "collection_columns": "商品系列欄位", + "collection_container": "商品系列", + "collection_description": "商品系列說明", + "collection_image": "商品系列圖片", + "collection_info": "商品系列資訊", + "collection_list": "商品系列清單", + "collections": "商品系列", + "content": "內容", + "content_grid": "內容網格", + "details": "詳情", + "divider": "分隔線", + "filters": "篩選與排序", + "follow_on_shop": "在 Shop 上追蹤", + "footer": "頁尾", + "footer_utilities": "頁尾工具", + "group": "群組", + "header": "頁首", + "heading": "標題", + "icons": "圖示", + "image_with_text": "附文字圖片", + "input": "輸入", + "logo": "標誌", + "magazine_grid": "雜誌式網格", + "media": "多媒體檔案", + "menu": "選單", + "mobile_layout": "行動裝置版面配置", + "payment_icons": "付款圖示", + "popup_link": "彈出式視窗連結", + "predictive_search": "搜尋彈出視窗", + "predictive_search_empty": "搜尋預測無結果", + "price": "價格", + "product": "產品", + "product_card": "商品卡片", + "product_card_media": "多媒體檔案", + "product_card_rendering": "商品卡片渲染", + "product_grid": "網格", + "product_grid_main": "商品網格", + "product_image": "商品圖片", + "product_information": "商品資訊", + "product_list": "精選系列", + "product_review_stars": "檢視星評", + "quantity": "數量", + "row": "列", + "search": "搜尋", + "section": "區段", + "selected_variants": "已選取子類", + "shop_the_look": "商店外觀", + "slide": "投影片", + "social_media_links": "社群媒體連結", + "spacer": "空白區域", + "steps": "步驟", + "summary": "摘要", + "swatches": "色樣", + "testimonials": "推薦文", + "text": "文字", + "title": "標題", + "utilities": "工具", + "search_input": "搜尋輸入", + "search_results": "搜尋結果", + "read_only": "唯讀", + "collection_title": "商品系列標題", + "collections_bento": "商品系列清單:便當式", + "faq_section": "常見問題", + "hero": "主頁", + "jumbo_text": "特大字體", + "view_all_button": "檢視全部", + "video_section": "影片", + "custom_liquid": "自訂 Liquid", + "blog": "網誌", + "blog_post": "網誌文章", + "blog_posts": "網誌文章", + "caption": "說明文字", + "collection_card_image": "圖片", + "collection_links": "商品系列連結", + "collection_links_spotlight": "商品系列連結:矚目焦點", + "collection_links_text": "商品系列連結:文字", + "collections_carousel": "商品系列清單:輪播", + "collections_editorial": "商品系列清單:編輯", + "collections_grid": "商品系列清單:網格", + "copyright": "著作權", + "count": "計數", + "divider_section": "分隔線", + "drawers": "收銀機", + "editorial": "編輯風格", + "editorial_jumbo_text": "編輯風格:特大字體", + "hero_marquee": "主圖:跑馬燈", + "input_fields": "輸入欄位", + "local_pickup": "到店取貨", + "marquee_section": "跑馬燈", + "media_with_text": "附文字的多媒體檔案", + "page": "頁面", + "page_content": "內容", + "page_layout": "頁面版面配置", + "policy_list": "政策連結", + "prices": "價格", + "products_carousel": "精選系列:輪播", + "products_editorial": "精選系列:編輯", + "products_grid": "精選系列:網格", + "social_link": "社群媒體連結", + "split_showcase": "分欄展示", + "variant_pickers": "子類選擇器", + "pills": "圓角", + "product_title": "產品名稱", + "large_logo": "大型標誌", + "product_list_button": "「檢視全部」按鈕", + "product_inventory": "產品庫存", + "description": "說明" + }, + "settings": { + "alignment": "對齊方式", + "autoplay": "自動播放", + "background": "背景", + "border_radius": "圓角半徑", + "border_width": "邊框厚度", + "borders": "邊框", + "bottom_padding": "底部邊框間距", + "button": "按鈕", + "color": "顏色", + "colors": "顏色", + "content_alignment": "內容對齊", + "content_direction": "內容導向", + "content_position": "內容位置", + "cover_image_size": "封面圖片尺寸", + "cover_image": "封面圖片", + "custom_minimum_height": "自訂高度下限", + "custom_width": "自訂寬度", + "enable_video_looping": "影片循環播放功能", + "favicon": "Favicon", + "font_family": "字型系列", + "gap": "差距", + "geometric_translate_y": "幾何平移 (Y 軸)", + "heading": "標題", + "icon": "圖示", + "image": "圖片", + "image_icon": "圖片圖示", + "image_opacity": "圖片透明度", + "image_position": "圖片位置", + "image_ratio": "圖片比例", + "label": "標籤", + "line_height": "行高", + "link": "連結", + "layout_gap": "版面配置差距", + "make_section_full_width": "讓區段以全寬度呈現", + "minimum_height": "高度下限", + "opacity": "透明度", + "overlay_opacity": "疊加層不透明度", + "padding": "邊框間距", + "primary_color": "連結", + "product": "商品", + "section_width": "區段寬度", + "size": "尺寸", + "slide_spacing": "投影片間距", + "slide_width": "投影片寬度", + "slideshow_fullwidth": "完整寬度投影片", + "style": "樣式", + "text": "文字", + "text_case": "情境", + "top_padding": "頂端邊框間距", + "video": "影片", + "video_alt_text": "替代文字", + "video_loop": "循環播放影片", + "video_position": "影片位置", + "width": "寬度", + "z_index": "Z-index", + "limit_content_width": "限制內容寬度", + "color_scheme": "顏色配置", + "inherit_color_scheme": "沿用顏色配置", + "product_count": "商品數量", + "product_type": "產品類型", + "content_width": "內容寬度", + "collection": "商品系列", + "enable_sticky_content": "電腦版中的黏性內容", + "error_color": "錯誤", + "success_color": "成功", + "primary_font": "主要字型", + "secondary_font": "次要字型", + "tertiary_font": "第三級字型", + "columns": "欄", + "items_to_show": "要顯示的項目", + "layout": "版面配置", + "layout_type": "類型", + "show_grid_layout_selector": "顯示網格版面配置選擇器", + "view_more_show": "顯示「檢視全部」按鈕", + "image_gap": "影像間距", + "width_desktop": "桌面裝置寬度", + "width_mobile": "行動裝置寬度", + "border_style": "邊框樣式", + "height": "高度", + "thickness": "厚度", + "stroke": "筆觸", + "filter_style": "篩選條件樣式", + "swatches": "色樣", + "quick_add_colors": "快速新增顏色", + "divider_color": "分隔線", + "border_opacity": "邊框不透明度", + "hover_background": "暫留背景", + "hover_borders": "暫留邊框", + "hover_text": "暫留文字", + "primary_hover_color": "暫留連結", + "primary_button_text": "主要按鈕文字", + "primary_button_background": "主要按鈕背景", + "primary_button_border": "主要按鈕邊框", + "secondary_button_text": "次要按鈕文字", + "secondary_button_background": "次要按鈕背景", + "secondary_button_border": "次要按鈕邊框", + "shadow_color": "陰影", + "mobile_logo_image": "行動版標誌", + "video_autoplay": "自動播放", + "video_cover_image": "封面圖片", + "video_external_url": "網址", + "video_source": "來源", + "first_row_media_position": "首列多媒體檔案位置", + "accordion": "摺疊式", + "aspect_ratio": "寬高比", + "auto_rotate_announcements": "自動輪播公告", + "auto_rotate_slides": "自動輪播投影片", + "background_color": "背景顏色", + "badge_corner_radius": "圓角半徑", + "badge_position": "卡片上的位置", + "badge_sale_color_scheme": "特賣", + "badge_sold_out_color_scheme": "售罄", + "behavior": "行為", + "blur": "陰影模糊", + "border": "邊框", + "bottom": "底部", + "card_image_height": "產品圖片高度", + "carousel_on_mobile": "行動裝置輪播", + "cart_count": "購物車數量", + "cart_items": "購物車品項", + "cart_related_products": "相關商品", + "cart_title": "購物車", + "cart_total": "購物車總金額", + "cart_type": "類型", + "case": "情境", + "checkout_buttons": "加速結帳作業按鈕", + "collection_list": "商品系列", + "collection_templates": "商品系列範本", + "content": "內容", + "corner_radius": "圓角半徑", + "country_region": "國家/地區", + "currency_code": "幣別代碼", + "custom_height": "自訂高度", + "custom_mobile_size": "自訂行動版尺寸", + "desktop_height": "桌面版裝置高度", + "direction": "方向", + "display": "顯示", + "divider_thickness": "分隔線厚度", + "divider": "分隔線", + "dividers": "分隔線", + "drop_shadow": "陰影效果", + "empty_state_collection_info": "在輸入搜尋內容之前顯示", + "empty_state_collection": "空白狀態商品系列", + "enable_filtering": "篩選條件", + "enable_grid_density": "網格版面配置控制項", + "enable_sorting": "排序", + "enable_zoom": "啟用縮放功能", + "equal_columns": "平均分配欄寬", + "expand_first_group": "展開第一群組", + "extend_media_to_screen_edge": "將多媒體檔案延伸至螢幕邊緣", + "extend_summary": "延伸至螢幕邊緣", + "extra_large": "超大", + "extra_small": "超小", + "fixed_height": "像素高度", + "fixed_width": "像素寬度", + "flag": "旗子", + "font_price": "價格字型", + "font_weight": "字型粗細", + "font": "字型", + "full_width_first_image": "全寬度的首張圖片", + "full_width_on_mobile": "行動裝置的全寬度", + "heading_preset": "標題預設內容", + "hide_padding": "隱藏邊框間距", + "hide_unselected_variant_media": "隱藏未選取的子類多媒體檔案", + "horizontal_gap": "水平間距", + "horizontal_offset": "陰影水平位移", + "hover_behavior": "暫留行為", + "icon_background": "圖示背景", + "icons": "圖示", + "image_border_radius": "圖片圓角半徑", + "installments": "分期付款", + "integrated_button": "整合的按鈕", + "language_selector": "語言選擇器", + "large": "大", + "left_padding": "左側邊框間距", + "left": "左側", + "letter_spacing": "字母間距", + "limit_media_to_screen_height": "限制為螢幕高度", + "limit_product_details_width": "限制商品詳情的寬度", + "link_preset": "連結預設內容", + "links": "連結", + "logo_font": "標誌字型", + "logo": "標誌", + "loop": "循環播放", + "make_details_sticky_desktop": "桌面裝置固定顯示", + "max_width": "寬度上限", + "media_height": "多媒體檔案高度", + "media_overlay": "多媒體檔案疊加層", + "media_position": "多媒體檔案位置", + "media_type": "多媒體檔案類型", + "media_width": "多媒體檔案寬度", + "menu": "選單", + "mobile_columns": "行動裝置欄", + "mobile_height": "行動裝置高度", + "mobile_quick_add": "行動裝置快速新增", + "motion_direction": "動作方向", + "motion": "動作", + "movement_direction": "變動方向", + "navigation_bar_color_scheme": "導覽列顏色配置", + "navigation_bar": "導覽列", + "navigation": "導覽", + "open_new_tab": "在新分頁中開啟連結", + "overlay_color": "疊加層顏色", + "overlay": "疊加層", + "padding_bottom": "下邊框間距", + "padding_horizontal": "水平邊框間距", + "padding_top": "上邊框間距", + "page_width": "頁面寬度", + "pagination": "分頁", + "percent_height": "百分比高度", + "percent_size_mobile": "百分比尺寸", + "percent_size": "百分比尺寸", + "percent_width": "百分比寬度", + "pixel_size_mobile": "像素尺寸", + "pixel_size": "像素尺寸", + "placement": "位置", + "position": "位置", + "preset": "預設內容", + "product_cards": "商品卡片", + "product_pages": "產品頁面", + "product_templates": "商品範本", + "products": "商品", + "quick_add": "快速新增", + "ratio": "比例", + "regular": "標準", + "review_count": "檢視數量", + "right": "右側", + "row_height": "列高度", + "row": "列", + "seller_note": "允許向賣家備註", + "shape": "形狀", + "show_as_accordion": "在行動裝置顯示為摺疊式", + "show_sale_price_first": "先顯示促銷價", + "show_tax_info": "稅務資訊", + "show": "顯示", + "size_mobile": "行動版尺寸", + "small": "小", + "speed": "速度", + "statement": "對帳單", + "sticky_header": "固定式頁首", + "text_hierarchy": "文字層級", + "text_presets": "文字預設內容", + "title": "標題", + "top": "頂部", + "type": "類型", + "type_preset": "文字預設內容", + "underline_thickness": "底線厚度", + "unit": "單位", + "variant_images": "子類圖片", + "vendor": "廠商", + "vertical_gap": "垂直間距", + "vertical_offset": "陰影垂直位移", + "vertical_on_mobile": "行動裝置垂直顯示", + "view_all_as_last_card": "「檢視全部」為最後卡片", + "weight": "重量", + "wrap": "包圍", + "read_only": "唯讀", + "always_stack_buttons": "一律堆疊按鈕", + "custom_mobile_width": "自訂行動裝置寬度", + "gradient_direction": "漸層方向", + "overlay_style": "疊加層風格", + "shadow_opacity": "陰影透明度", + "show_filter_label": "已套用篩選條件的文字標籤", + "show_swatch_label": "色樣的文字標籤", + "transparent_background": "透明背景", + "account": "帳號", + "align_baseline": "對齊文字基準線", + "add_discount_code": "允許購物車折扣", + "background_overlay": "背景疊加層", + "background_media": "背景多媒體檔案", + "border_thickness": "邊框厚度", + "bottom_row": "底行", + "button_text_case": "文字大小寫", + "button_text_weight": "字重", + "card_size": "卡片尺寸", + "auto_open_cart_drawer": "「加入購物車」自動開啟導覽匣", + "collection_count": "商品系列數量", + "custom_liquid": "Liquid 程式碼", + "default": "預設", + "default_logo": "預設標誌", + "divider_width": "分隔線寬度", + "headings": "標題", + "hide_logo_on_home_page": "隱藏首頁上的標誌", + "horizontal_padding": "水平內距", + "inverse": "對比色", + "inverse_logo": "對比色標誌", + "layout_style": "樣式", + "length": "長度", + "mobile_card_size": "行動版卡片尺寸", + "mobile_pagination": "行動版分頁", + "open_row_by_default": "預設開啟資料列", + "page_transition_enabled": "換頁", + "right_padding": "右側內距", + "search": "搜尋", + "search_icon": "搜尋圖示", + "search_position": "位置", + "search_row": "列", + "show_author": "作者", + "show_alignment": "顯示對齊方式", + "show_count": "顯示計數", + "show_date": "日期", + "show_pickup_availability": "顯示取貨服務供應情況", + "show_search": "顯示搜尋", + "use_inverse_logo": "使用對比色標誌", + "vertical_padding": "垂直內距", + "visibility": "可見性", + "product_corner_radius": "商品圓角半徑", + "card_corner_radius": "卡片圓角半徑", + "alignment_mobile": "行動版對齊方式", + "animation_repeat": "重播動畫", + "blurred_reflection": "模糊反射", + "card_hover_effect": "卡片懸停效果", + "collection_title_case": "商品系列名稱案例", + "effects": "效果", + "inventory_threshold": "上架庫存過低門檻", + "page": "頁面", + "product_and_card_title_case": "商品與卡片名稱案例", + "product_title_case": "產品名稱案例", + "reflection_opacity": "反射不透明度", + "show_inventory_quantity": "顯示上架庫存偏低的商品", + "text_label_case": "文字標籤案例", + "transition_to_main_product": "產品卡片到產品頁面的過渡", + "show_second_image_on_hover": "游標暫留時顯示次要圖片", + "media": "多媒體檔案", + "product_card_carousel": "顯示輪播", + "media_fit": "多媒體檔案最適大小", + "scroll_speed": "捲動到下一個公告" + }, + "options": { + "adapt_to_image": "配合圖片", + "apple": "蘋果", + "arrow": "箭頭", + "auto": "自動", + "banana": "香蕉", + "bottle": "瓶子", + "box": "信箱", + "buttons": "按鈕", + "carrot": "胡蘿蔔", + "center": "置中", + "chat_bubble": "聊天泡泡", + "clipboard": "剪貼簿", + "contain": "包含", + "counter": "計數器", + "cover": "封面", + "custom": "自訂", + "dairy_free": "不含乳製品", + "dairy": "含乳製品", + "default": "預設", + "dropdowns": "下拉式選單", + "dots": "圓點", + "dryer": "吹風機", + "end": "結束", + "eye": "眼睛", + "facebook": "Facebook", + "fill": "填滿", + "fire": "火", + "fit": "符合", + "full": "完整", + "full_and_page": "完整背景,內容頁面寬度受限", + "gluten_free": "無麩質", + "heading": "標題", + "heart": "紅心", + "horizontal": "水平", + "instagram": "Instagram", + "iron": "鐵", + "landscape": "橫向", + "large": "大", + "leaf": "葉片", + "leather": "皮革", + "lg": "LG", + "lightning_bolt": "閃電", + "link": "連結", + "lipstick": "口紅", + "lock": "鎖", + "lowercase": "小寫", + "m": "M", + "map_pin": "地圖圖釘", + "medium": "中", + "none": "無", + "numbers": "數字", + "nut_free": "無堅果", + "outline": "外框", + "page": "頁面", + "pants": "長褲", + "paw_print": "爪印", + "pepper": "胡椒", + "perfume": "香水", + "pinterest": "Pinterest", + "plane": "飛機", + "plant": "植物", + "portrait": "直向", + "price_tag": "價格標籤", + "question_mark": "問號", + "recycle": "回收", + "return": "退貨", + "ruler": "尺", + "s": "S", + "sentence": "句子", + "serving_dish": "料理盤", + "shirt": "襯衫", + "shoe": "鞋子", + "silhouette": "剪影", + "small": "小", + "snapchat": "Snapchat", + "snowflake": "雪花", + "solid": "純色", + "space_between": "間距", + "square": "正方形", + "star": "星星", + "start": "開始", + "stopwatch": "碼表", + "tiktok": "TikTok", + "truck": "卡車", + "tumblr": "Tumblr", + "twitter": "X (Twitter)", + "uppercase": "大寫", + "vertical": "垂直", + "vimeo": "Vimeo", + "washing": "洗滌", + "circle": "圓形", + "swatches": "色樣", + "full_and_page_offset_left": "完整背景,頁面寬度內容,向左偏移", + "full_and_page_offset_right": "完整背景,頁面寬度內容,向右偏移", + "offset_left": "向左偏移", + "offset_right": "向右偏移", + "page_center_aligned": "頁面,置中對齊", + "page_left_aligned": "頁面,靠左對齊", + "page_right_aligned": "頁面,靠右對齊", + "button": "按鈕", + "caption": "說明文字", + "h1": "標題 1", + "h2": "標題 2", + "h3": "標題 3", + "h4": "標題 4", + "h5": "標題 5", + "h6": "標題 6", + "paragraph": "段落", + "primary": "主要", + "secondary": "次要", + "tertiary": "第三級", + "chevron_left": "> 形箭頭向左", + "chevron_right": "> 形箭頭向右", + "diamond": "菱形", + "grid": "網格", + "parallelogram": "平行四邊形", + "rounded": "圓弧", + "fit_content": "最適大小", + "pills": "圓角", + "heavy": "粗體", + "thin": "細體", + "drawer": "收銀機", + "preview": "預覽", + "text": "文字", + "video_uploaded": "已上傳", + "video_external_url": "外部網址", + "aspect_ratio": "寬高比", + "fixed": "固定", + "pixel": "像素", + "percent": "百分比", + "above_carousel": "上方輪播", + "all": "全部", + "up": "向上", + "down": "向下", + "always": "一律顯示", + "arrows_large": "大箭頭", + "arrows": "箭頭", + "balance": "平衡", + "bento": "便當式", + "black": "黑色", + "bluesky": "Bluesky", + "body_large": "內文 (大)", + "body_regular": "內文 (標準)", + "body_small": "內文 (小)", + "bold": "粗體", + "bottom_left": "左下角", + "bottom_right": "右下角", + "bottom": "底部", + "capitalize": "大寫", + "caret": "插入符號", + "carousel": "輪播", + "check_box": "核取方塊", + "chevron_large": "大 > 形箭頭", + "chevron": "> 形箭頭", + "chevrons": "> 形箭頭", + "classic": "經典", + "collection_images": "商品系列圖片", + "color": "顏色", + "complementary": "互補", + "dissolve": "淡溶", + "dotted": "點狀", + "editorial": "編輯風格", + "extra_large": "超大", + "extra_small": "超小", + "featured_collections": "精選商品系列", + "featured_products": "精選商品", + "font_primary": "主要", + "font_secondary": "次要", + "font_tertiary": "第三", + "forward": "往前", + "full_screen": "全螢幕", + "gradient": "漸層", + "heading_extra_large": "標題 (超大)", + "heading_extra_small": "標題 (超小)", + "heading_large": "標題 (大)", + "heading_regular": "標題 (標準)", + "heading_small": "標題 (小)", + "icon": "圖示", + "image": "圖片", + "input": "輸入", + "inside_carousel": "內部輪播", + "inverse_large": "反向放大字級", + "inverse": "反向字級", + "large_arrows": "大箭頭", + "large_chevrons": "大 > 形箭頭", + "left": "左側", + "light": "淺色", + "linkedin": "LinkedIn", + "loose": "寬松", + "media_first": "多媒體檔案優先顯示", + "media_second": "多媒體檔案次要顯示", + "modal": "互動視窗", + "narrow": "窄", + "never": "永不", + "next_to_carousel": "輪播旁", + "normal": "一般", + "nowrap": "禁止換行", + "off_media": "關閉多媒體檔案", + "on_media": "開啟多媒體檔案", + "on_scroll_up": "向上捲動時", + "one_half": "1/2", + "one_number": "1", + "one_third": "1/3", + "pill": "圓角", + "plus": "Plus", + "pretty": "美觀樣式", + "price": "價格", + "primary_style": "主要樣式", + "rectangle": "長方形", + "regular": "標準", + "related": "相關", + "reverse": "反向", + "rich_text": "RTF 文字", + "right": "右側", + "secondary_style": "次要樣式", + "semibold": "次粗", + "shaded": "陰影區域", + "show_second_image": "顯示次要圖片", + "single": "單一", + "slide_left": "投影片左側", + "slide_up": "投影片上方", + "spotify": "Spotify", + "stack": "堆疊", + "text_only": "純文字", + "threads": "Threads", + "thumbnails": "縮圖", + "tight": "緊密", + "top_left": "左上方", + "top_right": "右上方", + "top": "頂部", + "two_number": "2", + "two_thirds": "2/3", + "underline": "底線", + "video": "影片", + "wide": "寬", + "youtube": "YouTube", + "accent": "強調色", + "below_image": "圖片下方", + "body": "內文", + "button_primary": "主要按鈕", + "button_secondary": "次要按鈕", + "compact": "精簡", + "crop_to_fit": "裁剪以符合畫面", + "hidden": "已隱藏", + "hint": "提示", + "maintain_aspect_ratio": "保持寬高比", + "off": "關閉", + "on_image": "圖片上", + "social_bluesky": "社群平台:Bluesky", + "social_facebook": "社群平台:Facebook", + "social_instagram": "社群平台:Instagram", + "social_linkedin": "社群平台:LinkedIn", + "social_pinterest": "社群平台:Pinterest", + "social_snapchat": "社群平台:Snapchat", + "social_spotify": "社群平台:Spotify", + "social_threads": "社群平台:Threads", + "social_tiktok": "社群平台:TikTok", + "social_tumblr": "社群平台:Tumblr", + "social_twitter": "社群平台:X (Twitter)", + "social_whatsapp": "社群平台:WhatsApp", + "social_vimeo": "社群平台:Vimeo", + "social_youtube": "社群平台: YouTube", + "spotlight": "矚目焦點", + "standard": "標準", + "subheading": "子標題", + "blur": "模糊", + "lift": "提升", + "reveal": "顯示", + "scale": "縮放比例", + "subtle_zoom": "縮放" + }, + "content": { + "advanced": "進階", + "background_image": "背景圖片", + "background_video": "背景影片", + "block_size": "區塊尺寸", + "borders": "邊框", + "describe_the_video_for": "為使用螢幕助讀程式的顧客說明該影片。[瞭解詳情](https://help.shopify.com/manual/online-store/themes/theme-structure/theme-features#video-block)", + "section_size": "區段尺寸", + "slideshow_width": "投影片寬度", + "typography": "字體", + "width_is_automatically_optimized": "會自動調整為行動版最佳寬度。", + "complementary_products": "配套商品必須使用 Search & Discovery 應用程式進行設定。[瞭解詳情](https://help.shopify.com/manual/online-store/search-and-discovery)", + "mobile_column_optimization": "行動版的圖片會自動調整欄位", + "content_width": "僅在區段寬度設為全寬度時,內容寬度才適用。", + "adjustments_affect_all_content": "套用於此區塊中的所有內容", + "responsive_font_sizes": "尺寸會根據所有螢幕尺寸自動縮放", + "buttons": "按鈕", + "swatches": "色樣", + "variant_settings": "子類設定", + "background": "背景", + "appearance": "外觀", + "arrows": "箭頭", + "body_size": "內文尺寸", + "mobile_size": "行動版尺寸", + "bottom_row_appearance": "底部列的外觀", + "cards_layout": "卡片版面配置", + "carousel_navigation": "輪播導覽", + "carousel_pagination": "輪播分頁", + "copyright": "著作權", + "edit_logo_in_theme_settings": "在 [佈景主題設定](/editor?context=theme&category=logo%20and%20favicon) 中編輯標誌", + "edit_price_in_theme_settings": "在 [佈景主題設定](/editor?context=theme&category=currency%20code) 中編輯價格格式", + "edit_variants_in_theme_settings": "在 [佈景主題設定](/editor?context=theme&category=variants) 中編輯子類樣式", + "email_signups_create_customer_profiles": "註冊新增 [顧客個檔](https://help.shopify.com/manual/customers)", + "follow_on_shop_eligiblity": "若要顯示按鈕,必須安裝 Shop 管道並啟用 Shop Pay。[瞭解詳情](https://help.shopify.com/en/manual/online-store/themes/customizing-themes/add-shop-buttons)", + "fonts": "字型", + "grid": "網格", + "heading_size": "標題大小", + "image": "圖片", + "input": "輸入", + "layout": "版面配置", + "link": "連結", + "link_padding": "連結的邊框間距", + "localization": "本地化", + "logo": "標誌", + "margin": "毛利率", + "media": "多媒體檔案", + "media_1": "多媒體檔案 1", + "media_2": "多媒體檔案 2", + "menu": "選單", + "mobile_layout": "行動裝置版面配置", + "padding": "邊框間距", + "padding_desktop": "桌面裝置邊框間距", + "paragraph": "段落", + "policies": "政策", + "popup": "彈出式視窗", + "search": "搜尋", + "section_layout": "區段版面配置", + "size": "尺寸", + "social_media": "社群媒體", + "submit_button": "提交按鈕", + "text_presets": "文字預設內容", + "transparent_background": "透明背景", + "typography_primary": "主要字體", + "typography_secondary": "次要字體", + "typography_tertiary": "第三字體", + "mobile_width": "行動裝置寬度", + "width": "寬度", + "carousel": "輪播", + "colors": "顏色", + "collection_page": "商品系列頁面", + "copyright_info": "瞭解如何[編輯著作權聲明](https://help.shopify.com/manual/online-store/themes/customizing-themes/remove-powered-by-shopify-message)", + "customer_account": "顧客帳號", + "edit_empty_state_collection_in_theme_settings": "在 [佈景主題設定](/editor?context=theme&category=search) 中編輯空白狀態商品系列", + "grid_layout": "網格式版面配置", + "home_page": "首頁", + "images": "圖片", + "inverse_logo_info": "當透明頁首背景設為對比色時使用", + "manage_customer_accounts": "[在顧客帳號設定中管理可見性](/admin/settings/customer_accounts)。不支援舊版帳號。", + "manage_policies": "[管理政策](/admin/settings/legal)", + "product_page": "產品頁面", + "text": "文字", + "thumbnails": "縮圖", + "visibility": "可見性", + "visible_if_collection_has_more_products": "當商品系列的商品數量超過顯示數量時將可見", + "app_required_for_ratings": "需要應用程式,方可顯示商品評價。[瞭解詳情](https://help.shopify.com/manual/apps)", + "icon": "圖示", + "manage_store_name": "[管理商店名稱](/admin/settings/general?edit=storeName)", + "resource_reference_collection_card": "顯示上層區段的商品系列", + "resource_reference_collection_card_image": "顯示上層商品系列的圖片", + "resource_reference_collection_title": "顯示上層商品系列的名稱", + "resource_reference_product": "自動連結至上層商品", + "resource_reference_product_card": "顯示上層區段的商品", + "resource_reference_product_inventory": "顯示上層商品的庫存", + "resource_reference_product_price": "顯示上層商品的價格", + "resource_reference_product_recommendations": "根據上層商品顯示推薦", + "resource_reference_product_review": "顯示上層商品的評論", + "resource_reference_product_swatches": "顯示上層商品的色樣", + "resource_reference_product_title": "顯示上層商品的名稱", + "resource_reference_product_variant_picker": "顯示上層商品的子類", + "resource_reference_product_media": "顯示上層商品的多媒體檔案", + "product_media": "商品多媒體檔案", + "section_link": "區段連結" + }, + "html_defaults": { + "share_information_about_your": "

和顧客分享品牌資訊、描述商品、進行公告,或歡迎顧客光臨您的商店。

" + }, + "text_defaults": { + "button_label": "來去逛逛", + "collapsible_row": "可折疊的橫列", + "heading": "標題", + "email_signup_button_label": "訂閱", + "accordion_heading": "摺疊式標題", + "contact_form_button_label": "提交", + "popup_link": "彈出式視窗連結", + "sign_up": "註冊", + "welcome_to_our_store": "歡迎來到我們的商店", + "be_bold": "粗體。", + "shop_our_latest_arrivals": "購買我們的最新到貨商品!" + }, + "info": { + "link_info": "選用:使圖示可點按", + "carousel_layout_on_mobile": "行動裝置上會顯示輪播", + "video_alt_text": "請為使用輔助技術的使用者説明影片內容", + "video_autoplay": "影片將預設為靜音", + "video_external": "使用 YouTube 或 Vimeo 網址", + "carousel_hover_behavior_not_supported": "於區段層級選取「輪播」類型時,將不支援「輪播」暫留效果", + "checkout_buttons": "讓買家能夠更快速地結帳,並有助於提高轉換率。[瞭解詳情](https://help.shopify.com/manual/online-store/dynamic-checkout)", + "custom_heading": "自訂標題", + "edit_presets_in_theme_settings": "在 [佈景主題設定](/editor?context=theme&category=typography) 中編輯預設內容", + "enable_filtering_info": "使用 [Search & Discovery 應用程式](https://help.shopify.com/manual/online-store/search-and-discovery/filters) 自訂篩選條件", + "grid_layout_on_mobile": "網格版面配置用於行動裝置", + "logo_font": "僅適用於未選擇標誌的情況", + "manage_countries_regions": "[管理國家/地區](/admin/settings/markets)", + "manage_languages": "[管理語言](/admin/settings/languages)", + "transparent_background": "檢視每個套用透明背景的範本,以確保易讀性", + "aspect_ratio_adjusted": "已在部分版面配置中調整", + "auto_open_cart_drawer": "啟用後,當商品加入購物車時,購物車導覽匣會自動開啟。", + "custom_liquid": "新增應用程式程式碼片段或其他程式碼,以建立進階自訂內容。[瞭解詳情](https://shopify.dev/docs/api/liquid)", + "pills_usage": "用於顯示已套用的篩選條件、折扣代碼與搜尋建議", + "applies_on_image_only": "僅適用於圖片", + "hover_effects": "適用於商品及商品系列卡片" + }, + "categories": { + "basic": "基礎", + "collection": "商品系列", + "collection_list": "商品系列清單", + "footer": "頁尾", + "forms": "表單", + "header": "頁首", + "layout": "版面配置", + "links": "連結", + "product": "產品", + "product_list": "精選系列", + "banners": "橫幅", + "collections": "商品系列", + "custom": "自訂", + "decorative": "裝飾性", + "products": "產品", + "other_sections": "其他", + "storytelling": "故事行銷" + } +} diff --git a/release-notes.md b/release-notes.md new file mode 100644 index 000000000..3ed2ae6d4 --- /dev/null +++ b/release-notes.md @@ -0,0 +1,34 @@ +This release focuses on improving the user interface with updated product cards, better mobile compatibility, and performance enhancements. Key changes include fixing iOS-specific issues, updating the product display components, and optimizing the overall user experience across different browsers and devices. + +## What's Changed + +### Changed + +- Fixed user account transition whilst reworking to popover +- Renamed Product List section to Featured Collection +- Changed default aspect ratio from Portrait to Auto for product/collection cards +- Updated product cards +- Changed placeholder images + +### Fixes and improvements + +- Fixed featured products scroll on iOS +- Fixed quick-add causing unresponsive UI on iOS 16 +- Fixed zoom on input fields in iOS +- Fixed quick add variant picker layout in Safari +- Fixed product cards overflowList on Safari +- Restored Custom Liquid block option for product cards +- Swatches border is no longer cut off in editorial featured collection +- Fixed swatches on quick add modal +- Fixed swatch availability on product cards +- Restored predictive search category titles +- Fixed mega menu featured collections alignment for single item +- Fixed Header menu overflow logicon first edit +- Fixed featured content in header menu for all products and all collections +- Updated speed label to scroll to next announcement +- Cleaned up header hovers +- Improved page transition performance +- Improved slideshow image loading time +- Changed placeholders to display on live site +- Fixed carousel navigation icons not displaying background shapes +- Fixed text color in signup input diff --git a/sections/_blocks.liquid b/sections/_blocks.liquid new file mode 100644 index 000000000..d58fddd4b --- /dev/null +++ b/sections/_blocks.liquid @@ -0,0 +1,427 @@ +{% # import schema from '../schemas/sections/_blocks' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'section', section: section, children: children %} + +{% schema %} +{ + "name": "t:names.section", + "class": "section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ section.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "full-screen", + "label": "t:options.full_screen" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "" + }, + { + "type": "range", + "id": "section_height_custom", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "default": 50, + "unit": "%", + "visible_if": "{{ section.settings.section_height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.background_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ section.settings.toggle_overlay and section.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.custom_section", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/sections/collection-links.liquid b/sections/collection-links.liquid new file mode 100644 index 000000000..b43be4fb6 --- /dev/null +++ b/sections/collection-links.liquid @@ -0,0 +1,371 @@ +{% # import schema from '../schemas/sections/collection-links.js' %} + +{% liquid + assign collection_list = section.settings.collection_list + + if collection_list == blank + assign limit = 4 + + for i in (1..4) + assign collection_list = collection_list | append: ', ' + endfor + + assign collection_list = collection_list | split: ',' + endif + + assign active_collection = collection_list | find: 'id', collection.id | default: collection_list.first +%} + + + +
+
+ + + + {% case section.settings.layout %} + {% when 'spotlight' %} + {% capture slides %} + {% for collection in collection_list limit: limit %} + {% liquid + assign current = false + + if collection.id == active_collection.id + assign current = true + endif + %} + + {% capture slide %} + {% # theme-check-disable UniqueStaticBlockId %} + {% content_for 'block', + type: '_collection-link', + id: 'link', + closest.collection: collection, + index: forloop.index0, + current: current, + image_only: true + %} + {% # theme-check-enable UniqueStaticBlockId %} + {% endcapture %} + + {% render 'slideshow-slide', children: slide, index: forloop.index0 %} + {% endfor %} + {% endcapture %} + + {% render 'slideshow', + slides: slides, + slide_count: collection_list.size, + class: 'collection-links__images', + ref: 'slideshow' + %} + {% endcase %} + +
+ +{% # theme-check-disable ValidBlockTarget %} +{% stylesheet %} + collection-links-component { + --alignment: flex-start; + + display: grid; + align-items: center; + grid-gap: var(--gap-3xl); + + &:has([ratio='portrait']) { + --template-column-ratio: 0.8fr; + } + + &:has([ratio='square']) { + --template-column-ratio: 1fr; + } + + &:has([ratio='landscape']) { + --template-column-ratio: 1.4fr; + } + + &[alignment='center'] { + --alignment: center; + + .text-block { + text-align: center; + } + } + + &[alignment='right'] { + --alignment: flex-end; + + .text-block { + text-align: right; + } + } + + &[layout='spotlight'] { + position: relative; + grid-template-columns: 1fr var(--template-column-ratio); + grid-template-areas: 'text image'; + + &[reverse] { + grid-template-areas: 'image text'; + grid-template-columns: var(--template-column-ratio) 1fr; + } + + .collection-links__container { + align-items: var(--alignment); + } + + @media (max-width: 749px) { + grid-template-columns: 1fr; + grid-template-areas: 'text' 'image'; + grid-gap: var(--gap-2xl); + + .collection-links__container { + gap: clamp(var(--gap-xs), 1vw, var(--gap-xl)) var(--gap-2xl); + justify-content: var(--alignment); + } + } + } + + &[layout='text'] { + grid-gap: 0; + grid-template-areas: 'text'; + + .collection-links__container { + gap: clamp(var(--gap-xs), 1vw, var(--gap-xl)) var(--gap-2xl); + flex-wrap: wrap; + flex-direction: row; + justify-content: var(--alignment); + } + } + } + + .collection-links__container { + display: flex; + gap: var(--gap-md); + flex-direction: column; + } + + .collection-links__images { + overflow: hidden; + grid-area: image; + + @media (max-width: 749px) { + image-block { + max-width: 100%; + } + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.collection_links", + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "collection_list", + "id": "collection_list", + "label": "t:settings.collection_list" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "layout", + "label": "t:settings.layout", + "options": [ + { + "value": "spotlight", + "label": "t:options.spotlight" + }, + { + "value": "text", + "label": "t:options.text" + } + ], + "default": "spotlight" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "left" + }, + { + "type": "select", + "id": "image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "right", + "visible_if": "{{ section.settings.layout == \"spotlight\" }}" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 40 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 40 + } + ], + "presets": [ + { + "name": "t:names.collection_links_spotlight", + "category": "t:categories.collections", + "blocks": { + "link": { + "type": "_collection-link", + "static": true, + "blocks": { + "title": { + "type": "_inline-collection-title", + "name": "t:names.title", + "static": true, + "settings": { + "font": "var(--font-subheading--family)" + } + }, + "image": { + "type": "_image", + "static": true, + "settings": { + "height": "large", + "ratio": "square" + } + } + } + } + } + }, + { + "name": "t:names.collection_links_text", + "category": "t:categories.collections", + "settings": { + "layout": "text", + "alignment": "center" + }, + "blocks": { + "link": { + "type": "_collection-link", + "static": true, + "blocks": { + "title": { + "type": "_inline-collection-title", + "name": "t:names.title", + "static": true, + "settings": { + "font": "var(--font-subheading--family)" + } + }, + "image": { + "type": "_image", + "static": true, + "settings": { + "height": "medium" + } + } + } + } + } + } + ] +} +{% endschema %} +{% # theme-check-enable ValidBlockTarget %} diff --git a/sections/collection-list.liquid b/sections/collection-list.liquid new file mode 100644 index 000000000..34db6b47b --- /dev/null +++ b/sections/collection-list.liquid @@ -0,0 +1,970 @@ +{% # import schema from '../schemas/sections/collection-list.js' %} + +{% liquid + if section.settings.collection_list != blank + assign section_collections = section.settings.collection_list + assign max_items = section.settings.collection_list.count + elsif section.settings.layout_type == 'editorial' + assign max_items = section.settings.max_collections + elsif section.settings.layout_type == 'bento' + assign max_items = 4 + elsif section.settings.layout_type == 'carousel' + assign max_items = section.settings.columns | plus: 2 + elsif section.settings.layout_type == 'grid' + assign max_items = section.settings.columns + endif + + case section.settings.layout_type + when 'grid' + assign classes = 'resource-list--grid' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--resource-list-row-gap-desktop: ' | append: section.settings.rows_gap | append: 'px;' + echo '--resource-list-columns: repeat(' | append: section.settings.columns | append: ', 1fr);' + echo '--resource-list-columns-mobile: repeat(' | append: section.settings.mobile_columns | append: ', 1fr);' + echo '--column-count-mobile: ' | append: section.settings.mobile_columns | append: ';' + endcapture + when 'bento' + assign classes = 'resource-list--bento' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.bento_gap | append: 'px;' + echo '--bento-gap: var(--resource-list-column-gap);' + endcapture + when 'carousel' + assign classes = 'resource-list__carousel' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--column-count: ' | append: section.settings.columns | append: ';' + echo '--column-count-mobile: 1;' + echo '--mobile-card-size: ' | append: section.settings.mobile_card_size | append: ';' + endcapture + endcase +%} + +
+ +
+
+ {%- content_for 'blocks' -%} +
+ + {% if section_collections == null %} + {% for i in (1..max_items) %} + {% assign section_collections = section_collections | append: ', ' %} + {% endfor %} + + {% assign section_collections = section_collections | split: ',' %} + {% endif %} + + {% capture list_items %} + {% for collection in section_collections limit: max_items %} +
+ {% content_for 'block', type: '_collection-card', id: 'static-collection-card', closest.collection: collection %} +
+ {% unless forloop.last %} + + {% endunless %} + {% endfor %} + {% endcapture %} + + {% liquid + # Create an array from the list items to be used for different layout types + assign list_items_array = list_items | strip | split: '' + %} + +
+ {% case section.settings.layout_type %} + {% when 'grid' %} + {{ list_items }} + {% when 'bento' %} + {% render 'bento-grid', items: list_items_array %} + {% when 'carousel' %} + {% render 'resource-list-carousel', + ref: 'collectionListCarousel', + slides: list_items_array, + slide_count: max_items, + settings: section.settings, + slide_width_max: '450px' + %} + {% when 'editorial' %} + {% render 'editorial-collection-grid', items: list_items_array %} + {% endcase %} +
+ + {% if section.settings.layout_type != 'carousel' and section.settings.carousel_on_mobile %} + {% liquid + assign mobile_carousel_gap = section.settings.columns_gap + if section.settings.layout_type == 'bento' + assign mobile_carousel_gap = section.settings.bento_gap + endif + %} + + {% endif %} +
+ +{% schema %} +{ + "name": "t:names.collection_list", + "class": "ui-test-collection-list", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "collection_list", + "id": "collection_list", + "label": "t:settings.collection_list" + }, + { + "type": "header", + "content": "t:content.cards_layout" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.layout_type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + }, + { + "value": "bento", + "label": "t:options.bento" + }, + { + "value": "editorial", + "label": "t:options.editorial" + } + ], + "default": "grid" + }, + { + "type": "checkbox", + "id": "carousel_on_mobile", + "label": "t:settings.carousel_on_mobile", + "default": false, + "visible_if": "{{ section.settings.layout_type != 'carousel' }}" + }, + { + "type": "range", + "id": "columns", + "label": "t:settings.columns", + "min": 1, + "max": 8, + "step": 1, + "default": 4, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "select", + "id": "mobile_columns", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "1", + "label": "t:options.one_number" + }, + { + "value": "2", + "label": "t:options.two_number" + } + ], + "default": "2", + "visible_if": "{{ section.settings.layout_type == 'grid' and section.settings.carousel_on_mobile == false }}" + }, + { + "type": "select", + "id": "mobile_card_size", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "60cqw", + "label": "t:options.one_number" + }, + { + "value": "44cqw", + "label": "t:options.two_number" + } + ], + "default": "60cqw", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "range", + "id": "columns_gap", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "range", + "id": "bento_gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'bento' }}" + }, + { + "type": "range", + "id": "rows_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid'}}" + }, + { + "type": "range", + "id": "max_collections", + "label": "t:settings.collection_count", + "min": 1, + "max": 16, + "step": 1, + "default": 4, + "visible_if": "{{ section.settings.layout_type == 'editorial' }}" + }, + { + "type": "header", + "content": "t:content.carousel_navigation", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icon", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.arrows_large" + }, + { + "value": "chevron_large", + "label": "t:options.chevron_large" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrow", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_shape", + "label": "t:settings.icon_background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "none", + "visible_if": "{{ section.settings.icons_style != 'none' and section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.collections_bento", + "category": "t:categories.collections", + "settings": { + "layout_type": "bento", + "bento_gap": 8, + "section_width": "page-width", + "carousel_on_mobile": false, + "padding-block-start": 24, + "padding-block-end": 24 + }, + "blocks": { + "group_Lg9LkF": { + "type": "group", + "name": "t:names.header", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 16, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text_bc98Wh": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

Shop by collection

", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 16, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text_bc98Wh"] + }, + "static-collection-card": { + "type": "_collection-card", + "name": "t:names.collection_card", + "static": true, + "settings": { + "horizontal_alignment": "flex-start", + "vertical_alignment": "flex-end", + "placement": "on_image", + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0 + }, + "blocks": { + "collection-card-image": { + "type": "_collection-card-image", + "name": "t:names.collection_card_image", + "static": true, + "settings": { + "image_ratio": "adapt" + } + }, + "collection-title": { + "type": "collection-title", + "name": "t:names.collection_title", + "settings": { + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "background": true, + "background_color": "#ffffff", + "padding-block-start": 4, + "padding-block-end": 4, + "padding-inline-start": 8, + "padding-inline-end": 8 + } + } + }, + "block_order": ["collection-title"] + } + }, + "block_order": ["group_Lg9LkF"] + }, + { + "name": "t:names.collections_grid", + "category": "t:categories.collections", + "blocks": { + "group_Lg9LkF": { + "type": "group", + "name": "t:names.header", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text_bc98Wh": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

Shop by collection

", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 16, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text_bc98Wh"] + }, + "static-collection-card": { + "type": "_collection-card", + "name": "t:names.collection_card", + "static": true, + "settings": { + "horizontal_alignment": "flex-start", + "vertical_alignment": "flex-start", + "placement": "on_image", + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0 + }, + "blocks": { + "collection-card-image": { + "type": "_collection-card-image", + "name": "t:names.collection_card_image", + "static": true, + "settings": { + "image_ratio": "adapt" + } + }, + "collection-title": { + "type": "collection-title", + "name": "t:names.collection_title", + "settings": { + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "background": true, + "background_color": "#ffffff", + "padding-block-start": 4, + "padding-block-end": 4, + "padding-inline-start": 8, + "padding-inline-end": 8 + } + } + }, + "block_order": ["collection-title"] + } + }, + "block_order": ["group_Lg9LkF"], + "settings": { + "collection_list": [], + "layout_type": "grid", + "carousel_on_mobile": false, + "columns": 3, + "mobile_columns": "2", + "columns_gap": 8, + "rows_gap": 8, + "icons_style": "arrow", + "icons_shape": "none", + "section_width": "page-width", + "gap": 12, + "color_scheme": "", + "padding-block-start": 48, + "padding-block-end": 48 + } + }, + { + "name": "t:names.collections_carousel", + "category": "t:categories.collections", + "blocks": { + "group_EYUh3J": { + "type": "group", + "name": "t:names.header", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fit", + "custom_width": 100, + "width_mobile": "fit", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text_nQEaGV": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

Shop by collection

", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 16, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text_nQEaGV"] + }, + "static-collection-card": { + "type": "_collection-card", + "name": "t:names.collection_card", + "static": true, + "settings": { + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "placement": "below_image", + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0 + }, + "blocks": { + "collection-card-image": { + "type": "_collection-card-image", + "name": "t:names.collection_card_image", + "static": true, + "settings": { + "image_ratio": "adapt" + } + }, + "collection-title": { + "type": "collection-title", + "name": "t:names.collection_title", + "settings": { + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["collection-title"] + } + }, + "block_order": ["group_EYUh3J"], + "settings": { + "collection_list": [], + "layout_type": "carousel", + "carousel_on_mobile": false, + "columns": 3, + "mobile_columns": "2", + "columns_gap": 8, + "rows_gap": 8, + "icons_style": "arrow", + "icons_shape": "circle", + "section_width": "page-width", + "gap": 12, + "color_scheme": "", + "padding-block-start": 48, + "padding-block-end": 48 + } + }, + { + "name": "t:names.collections_editorial", + "category": "t:categories.collections", + "blocks": { + "group": { + "type": "group", + "name": "t:names.header", + "settings": { + "link": "", + "open_in_new_tab": false, + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "align_baseline": false, + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "toggle_overlay": false, + "overlay_color": "#00000026", + "overlay_style": "solid", + "gradient_direction": "to top", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

Shop by collection

", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": {} + } + }, + "block_order": ["text"] + }, + "static-collection-card": { + "type": "_collection-card", + "name": "t:names.collection_card", + "static": true, + "settings": { + "placement": "below_image", + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "collection_card_gap": 8, + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0 + }, + "blocks": { + "collection-title": { + "type": "collection-title", + "name": "t:names.collection_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "h5", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": {} + }, + "collection-card-image": { + "type": "_collection-card-image", + "name": "t:names.collection_card_image", + "static": true, + "settings": { + "image_ratio": "adapt", + "toggle_overlay": false, + "overlay_color": "#00000026", + "overlay_style": "solid", + "gradient_direction": "to top", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0 + }, + "blocks": {} + } + }, + "block_order": ["collection-title"] + } + }, + "block_order": ["group"], + "settings": { + "collection_list": [], + "layout_type": "editorial", + "carousel_on_mobile": false, + "columns": 3, + "mobile_columns": "2", + "columns_gap": 8, + "bento_gap": 8, + "rows_gap": 8, + "max_collections": 4, + "icons_style": "arrow", + "icons_shape": "none", + "section_width": "page-width", + "gap": 64, + "color_scheme": "", + "padding-block-start": 48, + "padding-block-end": 48 + } + } + ] +} +{% endschema %} diff --git a/sections/custom-liquid.liquid b/sections/custom-liquid.liquid new file mode 100644 index 000000000..b02a06680 --- /dev/null +++ b/sections/custom-liquid.liquid @@ -0,0 +1,75 @@ +{% # import schema from '../schemas/sections/custom-liquid' %} + +
+
+ {{ section.settings.custom_liquid }} +
+ +{% schema %} +{ + "name": "t:names.custom_liquid", + "settings": [ + { + "type": "liquid", + "id": "custom_liquid", + "label": "t:settings.custom_liquid", + "info": "t:info.custom_liquid" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.custom_liquid", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/sections/divider.liquid b/sections/divider.liquid new file mode 100644 index 000000000..2c378c9cf --- /dev/null +++ b/sections/divider.liquid @@ -0,0 +1,132 @@ +{% # import schema from '../schemas/sections/divider.js' %} + +{% assign full_width = false %} + +{% if section.settings.width_percent == 100 and section.settings.section_width == 'full-width' %} + {% assign full_width = true %} +{% endif %} + +
+
+ {% render 'divider', id: section.id, settings: section.settings, attributes: true, full_width: full_width %} +
+ +{% schema %} +{ + "name": "t:names.divider", + "settings": [ + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "full-width" + }, + { + "type": "range", + "id": "thickness", + "label": "t:settings.thickness", + "min": 0.5, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 1 + }, + { + "type": "select", + "id": "corner_radius", + "label": "t:settings.border_radius", + "options": [ + { + "value": "square", + "label": "t:options.square" + }, + { + "value": "rounded", + "label": "t:options.rounded" + } + ], + "default": "square", + "visible_if": "{{ section.settings.thickness > 1 and section.settings.width_percent != 100 or section.settings.section_width == \"page-width\"}}" + }, + { + "type": "range", + "id": "width_percent", + "label": "t:settings.length", + "min": 5, + "max": 100, + "step": 1, + "unit": "%", + "default": 100 + }, + { + "type": "select", + "id": "alignment_horizontal", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "center", + "visible_if": "{{ section.settings.width_percent < 100 }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16 + } + ], + "presets": [ + { + "name": "t:names.divider_section", + "category": "t:categories.layout" + } + ] +} +{% endschema %} diff --git a/sections/featured-product.liquid b/sections/featured-product.liquid new file mode 100644 index 000000000..10bab30ad --- /dev/null +++ b/sections/featured-product.liquid @@ -0,0 +1,193 @@ +{% # import schema from '../schemas/sections/featured-product' %} + + + +
+ + +{% stylesheet %} + .featured-product-section .section-content-wrapper { + grid-template-columns: 1fr; + display: grid; + overflow: hidden; + + @media (min-width: 750px) { + grid-template-columns: 1fr 1fr; + } + } + + /* Here I should maybe set the width to auto when the ratio is set to adapt */ + .featured-product-section .product-media-container.constrain-height { + /* arbitrary offset value based on average theme spacing and header height */ + --viewport-offset: 400px; + --constrained-min-height: var(--visual-preview--height, 80dvh); + + @media screen and (min-width: 750px) { + --viewport-offset: 300px; + } + } + + .featured-product-section .product-grid__card { + --padding-block: 20px; + --padding-inline: 20px; + + @media screen and (min-width: 750px) { + --padding-block: 40px; + --padding-inline: 40px; + } + } + + @media screen and (max-width: 749px) { + .featured-product-section .media-block { + order: -1; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.featured_product", + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "product", + "id": "product", + "label": "t:settings.product" + }, + { + "type": "select", + "id": "layout", + "label": "t:settings.media_position", + "options": [ + { + "value": "media-left", + "label": "t:options.left" + }, + { + "value": "media-right", + "label": "t:options.right" + } + ], + "default": "media-left" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.featured_product", + "category": "t:categories.products", + "settings": { + "color_scheme": "scheme-3" + }, + "blocks": { + "media": { + "type": "_media-without-appearance", + "static": true, + "name": "t:names.product_media" + }, + "featured-product": { + "type": "_featured-product", + "static": true, + "name": "t:names.product", + "blocks": { + "featured-product-title": { + "type": "product-title", + "name": "t:names.title", + "static": true, + "settings": { + "type_preset": "h5", + "width": "100%" + } + }, + "featured-product-price": { + "type": "_featured-product-price", + "name": "t:names.price", + "static": true + }, + "featured-product-gallery": { + "type": "_featured-product-gallery", + "name": "t:names.image", + "static": true + }, + "featured-product-swatches": { + "type": "swatches", + "name": "t:names.swatches", + "static": true, + "settings": { + "hide_padding": true + } + } + } + } + } + } + ] +} +{% endschema %} diff --git a/sections/footer-group.json b/sections/footer-group.json new file mode 100644 index 000000000..038833353 --- /dev/null +++ b/sections/footer-group.json @@ -0,0 +1,246 @@ +/* + * ------------------------------------------------------------ + * IMPORTANT: The contents of this file are auto-generated. + * + * This file may be updated by the Shopify admin theme editor + * or related systems. Please exercise caution as any changes + * made to this file may be overwritten. + * ------------------------------------------------------------ + */ +{ + "type": "footer", + "name": "t:names.footer", + "sections": { + "footer": { + "type": "footer", + "blocks": { + "group_wErUQf": { + "type": "group", + "name": "Join the club", + "settings": { + "content_direction": "row", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "flex-end", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 24, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "group_TwfRJd": { + "type": "group", + "name": "t:names.group", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 8, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text_pF6rVi": { + "type": "text", + "name": "Heading", + "settings": { + "text": "

Join the club

", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "type_preset": "h3", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "text_HafH7P": { + "type": "text", + "name": "Text", + "settings": { + "text": "

Sign up for exclusive deals and early access to new products.

", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": [ + "text_pF6rVi", + "text_HafH7P" + ] + }, + "email_signup_C94MfE": { + "type": "email-signup", + "name": "t:names.email_signup", + "settings": { + "width": "custom", + "custom_width": 50, + "inherit_color_scheme": true, + "color_scheme": "scheme-1", + "border_style": "all", + "border_width": 1, + "border_radius": 39, + "input_type_preset": "paragraph", + "style_class": "button-secondary", + "display_type": "arrow", + "label": "Sign up", + "integrated_button": true, + "button_type_preset": "paragraph", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": [ + "group_TwfRJd", + "email_signup_C94MfE" + ] + }, + "footer_utilities_zVWazC": { + "type": "footer-utilities", + "name": "t:names.footer_utilities", + "settings": { + "divider_thickness": 1, + "padding-block-start": 12, + "padding-block-end": 0 + }, + "blocks": { + "social_icons": { + "type": "_footer-social-icons", + "static": true, + "settings": {}, + "blocks": { + "social_link_insta": { + "type": "_social-link", + "name": "Instagram", + "settings": { + "link": "https://www.instagram.com/shopify" + } + }, + "social_link_threads": { + "type": "_social-link", + "name": "Threads", + "settings": { + "link": "https://www.threads.net/@shopify" + } + }, + "social_link_tiktok": { + "type": "_social-link", + "name": "TikTok", + "settings": { + "link": "https://www.tiktok.com/@shopify" + } + }, + "social_link_twitter": { + "type": "_social-link", + "name": "Twitter", + "settings": { + "link": "https://www.twitter.com/shopify" + } + }, + "social_link_youtube": { + "type": "_social-link", + "name": "YouTube", + "settings": { + "link": "https://www.youtube.com/shopify" + } + } + }, + "block_order": [ + "social_link_insta", + "social_link_threads", + "social_link_tiktok", + "social_link_twitter", + "social_link_youtube" + ] + } + } + } + }, + "block_order": [ + "group_wErUQf", + "footer_utilities_zVWazC" + ], + "name": "t:names.footer", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "center", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "center", + "gap": 64, + "section_width": "page-width", + "section_height": "", + "color_scheme": "scheme-5", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "padding-block-start": 64, + "padding-block-end": 16 + } + } + }, + "order": [ + "footer" + ] +} diff --git a/sections/footer.liquid b/sections/footer.liquid new file mode 100644 index 000000000..5829635f0 --- /dev/null +++ b/sections/footer.liquid @@ -0,0 +1,374 @@ +{% # import schema from '../schemas/sections/footer' %} + +
+
+ {% render 'background-media', + background_media: section.settings.background_media, + background_video: section.settings.video, + background_video_position: section.settings.video_position, + background_image: section.settings.background_image, + background_image_position: section.settings.background_image_position + %} + +
+ {% content_for 'blocks' %} +
+
+ +{% schema %} +{ + "name": "t:names.footer", + "class": "section-wrapper", + "tag": "footer", + "blocks": [ + { + "type": "_divider" + }, + { + "type": "@app" + }, + { + "type": "button" + }, + { + "type": "email-signup" + }, + { + "type": "follow-on-shop" + }, + { + "type": "footer-utilities" + }, + { + "type": "group" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "menu" + }, + { + "type": "payment-icons" + }, + { + "type": "text" + }, + { + "type": "logo" + }, + { + "type": "jumbo-text" + } + ], + "enabled_on": { + "groups": ["footer"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ section.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "full-screen", + "label": "t:options.full_screen" + } + ], + "default": "" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/header-announcements.liquid b/sections/header-announcements.liquid new file mode 100644 index 000000000..188920fbf --- /dev/null +++ b/sections/header-announcements.liquid @@ -0,0 +1,219 @@ +{% # import schema from '../schemas/sections/header-announcements.js' %} + +{% if section.blocks.size > 1 %} + +{% endif %} + +
+ + +{% stylesheet %} + .announcement-bar { + border-block-end: var(--border-bottom-width) solid var(--color-border); + } + + .announcement-bar__slider { + display: flex; + flex-direction: row; + align-items: center; + position: relative; + + @media screen and (max-width: 749px) { + grid-column: 1 / -1; + } + } + + .announcement-bar__slides { + display: grid; + grid: [stack] auto / [stack] auto; + width: calc(100% - var(--button-size) * 2); + max-width: 680px; + margin-inline: auto; + } + + .announcement-bar__slides > * { + grid-area: stack; + } + + .announcement-bar__slide { + transition: opacity 0.5s ease-in-out, visibility 0.5s ease-in-out; + + &[aria-hidden='true'] { + opacity: 0; + visibility: hidden; + } + } + + .announcement-bar__slider slideshow-arrows { + padding: 0; + mix-blend-mode: normal; + } + + .announcement-bar__slider slideshow-arrows .slideshow-control { + color: var(--color-foreground); + } + + .announcement-bar__slider .slideshow-control { + display: flex; + padding: 0; + width: var(--button-size); + height: var(--button-size); + align-items: center; + justify-content: center; + opacity: 1; + animation: none; + + @media screen and (min-width: 750px) { + --slideshow-control-offset: calc((var(--button-size) - var(--icon-size-xs)) / 2); + + .section--page-width &.slideshow-control--previous { + transform: translateX(var(--slideshow-control-offset)); + } + } + } + + .announcement-bar__slider .slideshow-control .svg-wrapper { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .announcement-bar__slide { + place-content: center; + } + + .announcement-bar__text:first-child { + margin: 0; + } + + .announcement-bar__link { + position: absolute; + inset: 0; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.announcement_bar", + "blocks": [ + { + "type": "_announcement" + } + ], + "enabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "range", + "id": "speed", + "label": "t:settings.scroll_speed", + "min": 2, + "max": 10, + "default": 5, + "unit": "sec" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.section_width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "default": "scheme-4", + "label": "t:settings.color_scheme" + }, + { + "type": "range", + "id": "divider_width", + "label": "t:settings.divider_thickness", + "min": 0, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 15 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 15 + } + ], + "presets": [ + { + "name": "t:names.announcement_bar", + "blocks": { + "announcement_1": { + "type": "_announcement" + } + }, + "block_order": ["announcement_1"] + } + ] +} +{% endschema %} diff --git a/sections/header-group.json b/sections/header-group.json new file mode 100644 index 000000000..3c753b424 --- /dev/null +++ b/sections/header-group.json @@ -0,0 +1,93 @@ +/* + * ------------------------------------------------------------ + * IMPORTANT: The contents of this file are auto-generated. + * + * This file may be updated by the Shopify admin theme editor + * or related systems. Please exercise caution as any changes + * made to this file may be overwritten. + * ------------------------------------------------------------ + */ +{ + "type": "header", + "name": "t:names.header", + "sections": { + "header_section": { + "type": "header", + "blocks": { + "header-logo": { + "type": "_header-logo", + "static": true, + "settings": { + "hide_logo_on_home_page": false, + "custom_height": 12, + "custom_height_mobile": 12, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": {} + }, + "header-menu": { + "type": "_header-menu", + "static": true, + "settings": { + "menu": "main-menu", + "menu_style": "featured_products", + "featured_products_aspect_ratio": "4 / 5", + "featured_collections_aspect_ratio": "16 / 9", + "image_border_radius": 0, + "color_scheme": "", + "menu_font_style": "inverse", + "type_font_primary_link": "primary", + "type_font_primary_size": "0.875rem", + "type_case_primary_link": "none", + "type_font_secondary_link": "secondary", + "type_case_secondary_link": "none", + "type_font_tertiary_link": "secondary", + "type_case_tertiary_link": "none", + "navigation_bar": false, + "color_scheme_navigation_bar": "", + "drawer_accordion": false, + "drawer_accordion_expand_first": false, + "drawer_dividers": false + }, + "blocks": {} + } + }, + "settings": { + "logo_position": "left", + "menu_position": "left", + "menu_row": "top", + "show_search": true, + "search_position": "right", + "search_row": "top", + "show_country": true, + "country_selector_style": false, + "show_language": true, + "localization_font": "heading", + "localization_font_size": "0.875rem", + "localization_position": "right", + "localization_row": "top", + "section_width": "page-width", + "section_height": "standard", + "enable_sticky_header": "always", + "divider_width": 0, + "divider_size": "page-width", + "border_width": 0, + "color_scheme_top": "", + "color_scheme_bottom": "", + "color_scheme_transparent": "scheme-6", + "enable_transparent_header_home": true, + "home_color_scheme": "inverse", + "enable_transparent_header_product": false, + "product_color_scheme": "default", + "enable_transparent_header_collection": false, + "collection_color_scheme": "default" + } + } + }, + "order": [ + "header_section" + ] +} diff --git a/sections/header.liquid b/sections/header.liquid new file mode 100644 index 000000000..b08e3d725 --- /dev/null +++ b/sections/header.liquid @@ -0,0 +1,1056 @@ +{% # import schema from '../schemas/sections/header' %} + +{% liquid + assign order = 'logo,menu,localization,search,mobile_search,actions' + + if shop.customer_accounts_enabled + assign order = 'mobile_search,logo,menu,localization,search,actions' + endif + + assign rows = 'top,bottom' | split: ',' + assign search_style = 'none' + + if section.settings.show_search + assign search_style = 'modal' + endif + + if section.settings.enable_transparent_header_home and template.name == 'index' + assign transparent = 'always' + assign transparent_color_scheme = section.settings.home_color_scheme + elsif section.settings.enable_transparent_header_product and template.name == 'product' + assign transparent = 'always' + assign transparent_color_scheme = section.settings.product_color_scheme + elsif section.settings.enable_transparent_header_collection and template.name == 'collection' + assign transparent = 'always' + assign transparent_color_scheme = section.settings.collection_color_scheme + endif + + if section.settings.enable_sticky_header == 'always' + assign sticky = 'always' + elsif section.settings.enable_sticky_header == 'scroll-up' + assign sticky = 'scroll-up' + endif + + if transparent and sticky + assign transparent = 'not-sticky' + endif + + if transparent + if transparent_color_scheme == 'inverse' + assign transparent_color_scheme = 'color-' | append: section.settings.color_scheme_transparent + else + assign transparent_color_scheme = 'color-' | append: section.settings.color_scheme_top + endif + endif + + capture logo + content_for 'block', type: '_header-logo', id: 'header-logo' + endcapture + + capture menu + content_for 'block', type: '_header-menu', id: 'header-menu' + endcapture + + capture mobile_menu + content_for 'block', type: '_header-menu', id: 'header-menu', variant: 'mobile' + endcapture + + capture navigation_bar + content_for 'block', type: '_header-menu', id: 'header-menu', variant: 'navigation_bar', transparent: transparent + endcapture + + capture actions + render 'header-actions' + endcapture + + if shop.customer_accounts_enabled + assign search_class = 'mobile:hidden' + endif + + if section.settings.search_position == 'left' + if shop.customer_accounts_enabled + assign order = 'mobile_search,logo,search,menu,localization,actions' + else + assign order = 'logo,search,menu,localization,mobile_search,actions' + endif + endif + capture search + render 'search', style: search_style, class: search_class + endcapture + + # Skip mobile search under specific conditions: + # Always render if search_row is bottom + # Don't render when shop.customer_accounts_enabled is false and search_position is left and search_style is not none + assign skip_mobile_search = false + if shop.customer_accounts_enabled == false and section.settings.search_position == 'left' and search_style != 'none' + assign skip_mobile_search = true + endif + + if section.settings.search_row == 'bottom' or search_style != 'none' and skip_mobile_search == false + # Mobile search duplicate for when search is not in the right order for mobile layout + capture mobile_search + render 'search', class: 'desktop:hidden', style: search_style + endcapture + endif + + assign show_language = section.settings.show_language + if localization.available_languages.size <= 1 + assign show_language = false + endif + + assign show_country = section.settings.show_country + if localization.available_countries.size <= 1 + assign show_country = false + endif + + if show_country or show_language + capture localization_markup + render 'dropdown-localization', show_country: show_country, show_language: show_language, country_style: section.settings.country_selector_style, localization_position: section.settings.localization_position + endcapture + endif + + assign bottom_row_blocks = '' + + if section.settings.menu_row == 'bottom' + assign bottom_row_blocks = bottom_row_blocks | append: 'menu,' + endif + + if section.settings.search_style != 'none' + if section.settings.search_row == 'bottom' + assign bottom_row_blocks = bottom_row_blocks | append: 'search,' + endif + endif + + if section.settings.show_country or section.settings.show_language + if section.settings.localization_row == 'bottom' + assign bottom_row_blocks = bottom_row_blocks | append: 'localization,' + endif + endif + + assign bottom_row_blocks = bottom_row_blocks | split: ',' | compact + + if section.settings.section_height == 'compact' + assign header_height_class = ' header--compact' + endif + + if bottom_row_blocks.size > 0 and section.settings.color_scheme_top.settings.background.rgb == section.settings.color_scheme_bottom.settings.background.rgb and section.settings.divider_width == 0 + assign collapse_header_paddings_class = 'header--collapse-row-paddings' + endif + + assign class = 'header' + + if transparent_color_scheme + assign class = class | append: ' ' | append: transparent_color_scheme + endif + + if section.settings.color_scheme_top.settings.background.alpha != 1 + assign class = class | append: ' ' | append: 'header--inherit-color-scheme-on-menu-open' + endif + + if header_height_class + assign class = class | append: ' ' | append: header_height_class + endif + + if collapse_header_paddings_class + assign class = class | append: ' ' | append: collapse_header_paddings_class + endif +%} + + + + + {% for row in rows %} + {% liquid + assign scheme = 'color_scheme_' | append: row + assign class = 'header__row header__row--[row] color-[row_scheme] section section--full-width-margin section--[section-width]' | replace: '[row]', row | replace: '[row_scheme]', section.settings[scheme] | replace: '[section-width]', section.settings.section_width + + case row + when 'top' + assign first = mobile_menu + + if bottom_row_blocks.size > 0 and section.settings.divider_size == 'page-width' + assign class = class | append: ' divider--page-width' + endif + + if bottom_row_blocks.size > 0 + assign border_bottom_setting_id = 'divider_width' + else + assign border_bottom_setting_id = 'border_width' + endif + when 'bottom' + assign first = '' + assign class = class | append: ' mobile:hidden' + + assign border_bottom_setting_id = 'border_width' + endcase + + assign style = '--border-bottom-width: [width]px; ' | replace: '[width]', section.settings[border_bottom_setting_id] + + if row == 'top' + assign style = style | append: '--border-bottom-width-mobile: [width]px; ' | replace: '[width]', section.settings.border_width + endif + %} + + {% capture content %} + {% render 'header-row', + row: row, + order: order, + settings: section.settings, + first: first, + logo: logo, + menu: menu, + actions: actions, + localization: localization_markup, + search: search, + mobile_search: mobile_search + %} + {% endcapture %} + + {% assign content = content | strip %} + {% if content != blank %} +
+
+ {{ content }} +
+
+ {% endif %} + {% endfor %} + + {% if navigation_bar != blank %} +
+ {{ navigation_bar }} +
+ {% endif %} +
+ + + +{% stylesheet %} + body { + --header-height: 0px; + --header-group-height: var(--header-height); + --transparent-header-offset-boolean: 0; /* stylelint-disable-line declaration-property-value-disallowed-list */ + } + + body:has(> #header-group > header) { + --header-height: 60px; + } + + body:has(> #header-group:empty) { + --header-group-height: 0px; + } + + .header[transparent] { + --language-button-background-color: transparent; + --language-button-border-color: transparent; + + /* used to apply transparency to .header__row, will only ever be transparent or unset */ + --header-bg-color: transparent; + + /* used to display the appropriate logo based on transparency state */ + --header-logo-display: none; + --header-logo-inverse-display: block; + + position: absolute; + top: 0; + left: 0; + right: 0; + + /* transparent color scheme on .header should never apply its background color */ + background-color: transparent; + z-index: var(--layer-overlay); + + &[transparent='not-sticky'][data-sticky-state='active'], + /* Only show opaque background when hovering over menu items with children (mega menu) + Multiple selectors for performance: each simple :has() check is faster than one complex selector with multiple conditions */ + &:has(.mega-menu__list:hover), + &:has(.menu-list__link[aria-haspopup]:is(:hover, [aria-expanded='true'], [data-animating])), + &:has(.menu-list__list-item[slot='overflow'] .menu-list__link:is(:hover, [aria-expanded='true'], [data-animating])) { + --header-logo-display: unset; + --header-logo-inverse-display: unset; + --header-bg-color: unset; + --color-foreground: inherit; + --color-foreground-rgb: inherit; + --color-background: inherit; + --color-background-rgb: inherit; + --color-border: inherit; + --color-border-rgb: inherit; + + .header__row { + /* Faster transition for "in" animation */ + transition: color var(--animation-values-fast), border-color var(--animation-values-fast), + background-color var(--animation-values-fast); + } + } + + .header__row { + /* Slower transition for "out" animation */ + transition: color var(--animation-values-slow), border-color var(--animation-values-slow), + background-color var(--animation-values-slow); + } + } + + :is(.header[transparent]:not([data-sticky-state='active']), .header[transparent='always'][data-sticky-state='active']) + .header__row:not( + :has( + .mega-menu__list:hover, + .menu-list__link[aria-haspopup]:is(:hover, [aria-expanded='true'], [data-animating]), + .menu-list__list-item[slot='overflow'] .menu-list__link:is(:hover, [aria-expanded='true'], [data-animating]) + ) + ) { + /* while transparent, header-row ignores its color-scheme settings, pull from the header-component */ + --color-foreground: inherit; + --color-foreground-rgb: inherit; + --color-border: inherit; + --color-border-rgb: inherit; + --color-primary-button-background: inherit; + --color-primary-button-text: inherit; + } + + .header--inherit-color-scheme-on-menu-open:has(.mega-menu__list:hover) .header__row, + .header--inherit-color-scheme-on-menu-open:has( + .menu-list__link[aria-haspopup]:is(:hover, [aria-expanded='true'], [data-animating]) + ) + .header__row, + .header--inherit-color-scheme-on-menu-open:has( + .menu-list__list-item[slot='overflow'] .menu-list__link:is(:hover, [aria-expanded='true'], [data-animating]) + ) + .header__row { + --color-foreground: inherit; + --color-foreground-rgb: inherit; + --color-background: inherit; + --color-background-rgb: inherit; + --color-border: inherit; + --color-border-rgb: inherit; + } + + .header-section { + position: relative; + } + + #header-group:has(#header-component[sticky]) { + display: contents; + } + + .header-section:has(> #header-component[sticky='always']), + .header-section:has(> #header-component[sticky='scroll-up'][data-sticky-state='active']) { + position: sticky; + + /* Use -1 instead of 0 so intersection observer can track sticky state */ + top: -1px; + z-index: var(--layer-sticky); + } + + .header[data-sticky-state] { + transition: opacity var(--animation-speed) var(--animation-easing); + opacity: 1; + } + + .header[data-sticky-state='active'] { + view-transition-name: sticky-header; + } + + .header[data-sticky-state='idle'], + .header[data-sticky-state='active'][data-animating] { + opacity: 0; + } + + .header__row { + position: relative; + + /* will default to bg from its color scheme unless --header-bg-color is transparent */ + background-color: var(--header-bg-color, var(--color-background)); + } + + .header__row--top:not(.divider--page-width), + .header__row--top.divider--page-width .header__columns, + .header__row--bottom { + border-bottom: var(--border-bottom-width) solid var(--color-border); + } + + @media screen and (max-width: 749px) { + .header__row--top:not(.divider--page-width), + .header__row--top.divider--page-width .header__columns { + border-bottom-width: var(--border-bottom-width-mobile); + } + } + + .header__row.divider--page-width:not(.section--page-width) .header__columns { + @media screen and (min-width: 750px) { + padding-inline-start: 0; + padding-inline-end: 0; + margin-inline-start: var(--page-margin); + margin-inline-end: var(--page-margin); + } + } + + .header__column { + display: flex; + align-items: center; + + /* on mobile, header__column nodes are ignored to create a new grid-template-area based on all visible content */ + @media screen and (max-width: 749px) { + display: contents; + } + } + + .header__column--left, + .header__column--center { + gap: var(--gap-xl); + grid-area: left; + } + + .header__column--center { + justify-content: center; + grid-area: center; + + header-menu:only-child .overflow-menu::part(list) { + justify-content: center; + } + } + + .header__column--right { + gap: var(--gap-xl); + justify-content: flex-end; + grid-area: right; + + .overflow-menu::part(list) { + justify-content: flex-end; + } + } + + .header__columns { + /* Three column layout */ + --header-left: 1fr; + --header-center: auto; + --header-right: 1fr; + --header-template-columns: var(--header-left) var(--header-center) var(--header-right); + + /* Mobile layout */ + --header-mobile-bookend: 44px; + + display: grid; + grid-template-areas: 'left center right'; + grid-gap: var(--gap-xl); + grid-template-columns: var(--header-template-columns); + + /* If menu is in center column */ + &:has(.header__column--center header-menu) { + --header-center: auto; + --header-left: minmax(max-content, 1fr); + --header-right: minmax(max-content, 1fr); + } + + /* If there is no center column, make the column the menu is in grow eagerly */ + &:where(:not(:has(.header__column--center))) { + @media screen and (min-width: 750px) { + --header-template-columns: var(--header-left) var(--header-right); + + grid-template-areas: 'left right'; + } + + /* If the header-menu is in the right column */ + &:has(.header__column--right header-menu) { + --header-right: auto; + --header-left: minmax(max-content, 1fr); + } + + /* If the header-menu is in the left column */ + &:has(.header__column--left header-menu) { + --header-left: auto; + --header-right: minmax(max-content, 1fr); + } + } + + @media screen and (max-width: 749px) { + --header-template-columns: var(--header-mobile-bookend) var(--header-mobile-bookend) 1fr + var(--header-mobile-bookend) var(--header-mobile-bookend); + + grid-template-areas: 'leftA leftB center rightA rightB'; + grid-column: span 3; + column-gap: 0; + align-items: center; + padding-block: 0; + padding-inline: 0 var(--padding-3xs); + + .header-logo { + grid-area: center; + } + + &:not(:has(header-actions)) .search-action { + grid-area: leftB; + } + + &:not(:has(.account-actions)) .search-action { + grid-area: rightA; + } + + .search-action { + grid-area: leftB; + } + + header-actions { + grid-area: rightB; + } + } + } + + /* Single column layout if there are no columns within */ + .header__columns:not(:has(.header__column)) { + grid-template-columns: 1fr; + } + + /* Column-specific dimming effect when any interactive element is hovered + Multiple selectors for performance: each simple :has() check is faster than one complex selector with multiple conditions */ + .header__column:has(header-menu:hover), + .header__column:has(.header-actions__action:hover), + .header__column:has(.dropdown-localization__button:hover), + .header__column:has(.header__icon--menu:hover) { + header-menu:not(:hover), + .header-actions__action:not(:hover), + .dropdown-localization__button:not(:hover), + .header__icon--menu:not(:hover) { + opacity: var(--opacity-subdued-text); + transition: opacity var(--animation-speed) var(--animation-easing); + } + } + + /* Ensure smooth transitions for all interactive elements */ + header-menu, + .header-actions__action, + .dropdown-localization__button, + .header__icon--menu { + transition: opacity var(--animation-speed) var(--animation-easing); + } + + /* Extend hover area through padding to prevent flickering on actual menu items */ + .menu-list__list-item:where(:not([slot='overflow'])) > .menu-list__link[aria-haspopup], + .menu-list__list-item:where(:not([slot='overflow'])) > .menu-list__link, + .menu-list__list-item:where(:not([slot='overflow'])) > button.menu-list__link { + margin-block: calc(-2 * var(--header-padding)); + padding-block: calc(2 * var(--header-padding)); + margin-inline: calc(-1 * var(--gap-xl) / 2); + padding-inline: calc(var(--gap-xl) / 2); + } + + /* Set header paddings based on height setting */ + .header { + --header-padding: var(--padding-sm); + --font-paragraph--line-height: 1; + } + + .header.header--compact { + --header-padding: var(--padding-2xs); + } + + .header__columns { + --padding-block-start: var(--header-padding); + --padding-block-end: var(--header-padding); + } + + .header:not(.header--compact) .header__row--bottom { + --header-padding: var(--padding-xs); + } + + .header--collapse-row-paddings { + .header__row--top .header__columns { + --padding-block-end: 0px; + } + + .header__row--bottom .header__columns { + --padding-block-start: 0px; + } + } + + /* When the header is transparent, add a margin to a potential header-section below it */ + .header-section:has(.header[transparent]) + .shopify-section { + margin-top: var(--header-height); + } + + /* When the header is transparent, and when there is no header-section below it, offset the first main-section with + * the height of the header + */ + + main > .shopify-section:first-child .section:not(.disable-section-top-offset) { + &.spacing-style, + .spacing-style { + --section-top-offset: calc(var(--header-height) * var(--transparent-header-offset-boolean)); + + /* Any nested sections should not be offset */ + :is(.spacing-style, .inherit-spacing) { + --section-top-offset: 0px; + } + } + + /* Make sticky content immediately stick to the top of the page */ + .sticky-content { + margin-top: calc(var(--header-height) * var(--transparent-header-offset-boolean) * -1); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.header", + "tag": "header", + "class": "header-section", + "settings": [ + { + "type": "header", + "content": "t:content.logo" + }, + { + "type": "select", + "id": "logo_position", + "label": "t:settings.position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "center" + }, + { + "type": "header", + "content": "t:content.menu" + }, + { + "type": "select", + "id": "menu_position", + "label": "t:settings.position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "left" + }, + { + "type": "select", + "id": "menu_row", + "label": "t:settings.row", + "options": [ + { + "value": "top", + "label": "t:options.top" + }, + { + "value": "bottom", + "label": "t:options.bottom" + } + ], + "default": "top" + }, + { + "type": "header", + "content": "t:content.customer_account" + }, + { + "type": "paragraph", + "content": "t:content.manage_customer_accounts" + }, + { + "type": "header", + "content": "t:content.search" + }, + { + "type": "checkbox", + "id": "show_search", + "label": "t:settings.search_icon", + "default": true + }, + { + "type": "select", + "id": "search_position", + "label": "t:settings.search_position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "right", + "visible_if": "{{ section.settings.show_search }}" + }, + { + "type": "select", + "id": "search_row", + "label": "t:settings.search_row", + "options": [ + { + "value": "top", + "label": "t:options.top" + }, + { + "value": "bottom", + "label": "t:options.bottom" + } + ], + "default": "top", + "visible_if": "{{ section.settings.show_search }}" + }, + { + "type": "header", + "content": "t:content.localization" + }, + { + "type": "checkbox", + "id": "show_country", + "label": "t:settings.country_region", + "info": "t:info.manage_countries_regions", + "default": true + }, + { + "type": "checkbox", + "id": "country_selector_style", + "label": "t:settings.flag", + "default": true, + "visible_if": "{{ section.settings.show_country }}" + }, + { + "type": "checkbox", + "id": "show_language", + "label": "t:settings.language_selector", + "info": "t:info.manage_languages", + "default": true + }, + { + "type": "select", + "id": "localization_font", + "label": "t:settings.font", + "options": [ + { + "value": "heading", + "label": "t:options.heading" + }, + { + "value": "subheading", + "label": "t:options.subheading" + }, + { + "value": "body", + "label": "t:options.body" + }, + { + "value": "accent", + "label": "t:options.accent" + } + ], + "default": "heading", + "visible_if": "{{ section.settings.show_country or section.settings.show_language }}" + }, + { + "type": "select", + "id": "localization_font_size", + "label": "t:settings.size", + "options": [ + { + "value": "0.625rem", + "label": "10px" + }, + { + "value": "0.75rem", + "label": "12px" + }, + { + "value": "0.875rem", + "label": "14px" + }, + { + "value": "1rem", + "label": "16px" + }, + { + "value": "1.125rem", + "label": "18px" + } + ], + "default": "1rem" + }, + { + "type": "select", + "id": "localization_position", + "label": "t:settings.position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "right", + "visible_if": "{{ section.settings.show_country or section.settings.show_language }}" + }, + { + "type": "select", + "id": "localization_row", + "label": "t:settings.row", + "options": [ + { + "value": "top", + "label": "t:options.top" + }, + { + "value": "bottom", + "label": "t:options.bottom" + } + ], + "default": "top", + "visible_if": "{{ section.settings.show_country or section.settings.show_language }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ] + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "compact", + "label": "t:options.compact" + }, + { + "value": "standard", + "label": "t:options.standard" + } + ], + "default": "standard" + }, + { + "type": "select", + "id": "enable_sticky_header", + "label": "t:settings.sticky_header", + "options": [ + { + "value": "always", + "label": "t:options.always" + }, + { + "value": "scroll-up", + "label": "t:options.on_scroll_up" + }, + { + "value": "never", + "label": "t:options.never" + } + ], + "default": "always" + }, + { + "type": "range", + "id": "divider_width", + "label": "t:settings.divider_thickness", + "min": 0, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 0, + "visible_if": "{{ section.settings.menu_row == 'bottom' or section.settings.localization_row == 'bottom' or section.settings.search_row == 'bottom' }}" + }, + { + "type": "select", + "id": "divider_size", + "label": "t:settings.divider_width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "visible_if": "{{ section.settings.divider_width > 0 and section.settings.menu_row == 'bottom' or section.settings.localization_row == 'bottom' or section.settings.search_row == 'bottom' }}" + }, + { + "type": "range", + "id": "border_width", + "label": "t:settings.border_width", + "min": 0, + "max": 5, + "step": 0.5, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.colors" + }, + { + "type": "color_scheme", + "id": "color_scheme_top", + "label": "t:settings.default", + "default": "primary" + }, + { + "type": "color_scheme", + "id": "color_scheme_bottom", + "label": "t:settings.bottom_row", + "default": "primary", + "visible_if": "{{ section.settings.menu_row == 'bottom' or section.settings.localization_row == 'bottom' or section.settings.search_row == 'bottom' }}" + }, + { + "type": "color_scheme", + "id": "color_scheme_transparent", + "label": "t:settings.inverse", + "default": "primary", + "visible_if": "{{ section.settings.enable_transparent_header_home or section.settings.enable_transparent_header_product or section.settings.enable_transparent_header_collection }}" + }, + { + "type": "header", + "content": "t:content.home_page" + }, + { + "type": "checkbox", + "id": "enable_transparent_header_home", + "label": "t:settings.transparent_background", + "default": false + }, + { + "type": "select", + "id": "home_color_scheme", + "label": "t:settings.color_scheme", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "inverse", + "label": "t:options.inverse" + } + ], + "default": "default", + "visible_if": "{{ section.settings.enable_transparent_header_home }}" + }, + { + "type": "header", + "content": "t:content.product_page" + }, + { + "type": "checkbox", + "id": "enable_transparent_header_product", + "label": "t:settings.transparent_background", + "default": false + }, + { + "type": "select", + "id": "product_color_scheme", + "label": "t:settings.color_scheme", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "inverse", + "label": "t:options.inverse" + } + ], + "default": "default", + "visible_if": "{{ section.settings.enable_transparent_header_product }}" + }, + { + "type": "header", + "content": "t:content.collection_page" + }, + { + "type": "checkbox", + "id": "enable_transparent_header_collection", + "label": "t:settings.transparent_background", + "default": false + }, + { + "type": "select", + "id": "collection_color_scheme", + "label": "t:settings.color_scheme", + "options": [ + { + "value": "default", + "label": "t:options.default" + }, + { + "value": "inverse", + "label": "t:options.inverse" + } + ], + "default": "default", + "visible_if": "{{ section.settings.enable_transparent_header_collection }}" + } + ], + "presets": [] +} +{% endschema %} diff --git a/sections/hero.liquid b/sections/hero.liquid new file mode 100644 index 000000000..31b769732 --- /dev/null +++ b/sections/hero.liquid @@ -0,0 +1,940 @@ +{% # import schema from '../schemas/sections/hero' %} + +{% liquid + assign media_count = 0 + if section.settings.image_1 != blank and section.settings.image_2 != blank + assign media_width_desktop = 100 | divided_by: 2 | append: 'vw' + else + assign media_width_desktop = '100vw' + endif + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '832, 1200, 1600, 1920, 2560, 3840' + + assign has_image_1 = false + assign has_image_2 = false + assign has_video_1 = false + assign has_video_2 = false + assign has_image = false + assign has_video = false + assign has_video_multiple = false + assign has_media = false + assign media_type_1 = section.settings.media_type_1 + assign media_type_2 = section.settings.media_type_2 + if section.settings.image_1 != blank and media_type_1 == 'image' + assign has_image_1 = true + endif + if section.settings.image_2 != blank and media_type_2 == 'image' + assign has_image_2 = true + endif + if section.settings.video_1 != blank and media_type_1 == 'video' + assign has_video_1 = true + endif + if section.settings.video_2 != blank and media_type_2 == 'video' + assign has_video_2 = true + endif + + if has_image_1 or has_image_2 + assign has_image = true + endif + if has_video_1 or has_video_2 + assign has_video = true + endif + if has_video_1 and has_video_2 + assign has_video_multiple = true + endif + if has_image or has_video + assign has_media = true + endif + + assign alpha = section.settings.overlay_color.alpha + assign is_transparent = true + if alpha == 1 and section.settings.toggle_overlay + assign is_transparent = false + endif + + assign fetch_priority = 'auto' + + if section.index == 1 + assign fetch_priority = 'high' + endif +%} + +{% capture media %} + {%- if has_image_1 -%} + {% assign media_count = media_count | plus: 1 %} + {{ + section.settings.image_1 + | image_url: width: 3840 + | image_tag: + width: section.settings.image_1.width, + widths: widths, + height: section.settings.image_1.height, + alt: section.settings.image_1.alt, + class: 'hero__image', + sizes: sizes, + fetchpriority: fetch_priority + }} + {%- endif -%} + + {%- if has_video_1 -%} + {% assign media_count = media_count | plus: 1 %} + {%- if section.settings.video_1.preview_image -%} + {% liquid + assign fetch_priority_poster = false + if section.index == 1 + assign fetch_priority_poster = 'high' + endif + %} + {{ + section.settings.video_1.preview_image + | image_url: width: 3840 + | image_tag: + width: section.settings.video_1.preview_image.width, + widths: widths, + height: section.settings.video_1.preview_image.height, + alt: section.settings.video_1.alt, + class: 'hero__video-poster', + sizes: sizes, + fetchpriority: fetch_priority_poster + }} + {%- endif -%} + {{ + section.settings.video_1 + | video_tag: + poster: nil, + autoplay: true, + loop: true, + controls: false, + muted: true, + class: 'hero__video' + }} + {%- endif -%} + + {%- if has_image_2 -%} + {% assign media_count = media_count | plus: 1 %} + {{ + section.settings.image_2 + | image_url: width: 3840 + | image_tag: + width: section.settings.image_2.width, + widths: widths, + height: section.settings.image_2.height, + alt: section.settings.image_2.alt, + class: 'hero__image', + sizes: sizes, + fetchpriority: fetch_priority + }} + {%- endif -%} + + {%- if has_video_2 -%} + {% assign media_count = media_count | plus: 1 %} + {%- if section.settings.video_2.preview_image -%} + {{ + section.settings.video_2.preview_image + | image_url: width: 3840 + | image_tag: + width: section.settings.video_2.preview_image.width, + widths: widths, + height: section.settings.video_2.preview_image.height, + alt: section.settings.video_2.alt, + class: 'hero__video-poster', + sizes: sizes + }} + {%- endif -%} + {{ + section.settings.video_2 + | video_tag: + poster: nil, + autoplay: true, + loop: true, + controls: false, + muted: true, + class: 'hero__video' + }} + {%- endif -%} + + {% if has_media == false and is_transparent %} + {{ 'hero-apparel-1' | placeholder_svg_tag: 'hero__image' }} + {%- endif -%} +{% endcapture %} + +{% capture media_blurred %} + {% if has_image_1 %} + {{ + section.settings.image_1 + | image_url: width: 3840 + | image_tag: + width: section.settings.image_1.width, + widths: widths, + height: section.settings.image_1.height, + alt: '', + class: 'hero__image', + sizes: sizes + }} + {% endif %} + {% if has_image_2 %} + {{ + section.settings.image_2 + | image_url: width: 3840 + | image_tag: + width: section.settings.image_2.width, + widths: widths, + height: section.settings.image_2.height, + alt: '', + class: 'hero__image', + sizes: sizes + }} + {% endif %} + {% if has_media == false and is_transparent %} + {{ 'hero-apparel-1' | placeholder_svg_tag: 'hero__image' }} + {% endif %} +{% endcapture %} + +
+ {% if section.settings.blurred_reflection %} + {% unless has_video_multiple or is_transparent == false %} +
+ {{ media_blurred }} +
+ {% endunless %} + {% endif %} + + {% comment %} + Hardcoded to section--full-width bc the media has to be full width in all cases. + hero__content-wrapper applies section_width. + {% endcomment %} + +
+ {%- if section.settings.link != blank -%} + + {%- endif -%} +
+ {% liquid + if section.settings.toggle_overlay + render 'overlay', settings: section.settings + endif + %} + {{ media }} +
+
+ {% content_for 'blocks' %} +
+
+
+ +{% stylesheet %} + .hero-wrapper { + --hero-height-offset: 0px; + } + + body:has(> #header-group > .header-section > #header-component[transparent]):not( + :has(> #header-group > .header-section + .shopify-section) + ) + .hero-wrapper:first-child { + --hero-height-offset: var(--header-group-height, 0); + } + + .hero { + position: relative; + min-height: calc(var(--hero-min-height) - var(--hero-height-offset)); + } + + .hero[data-shopify-visual-preview] { + --hero-min-height: 600px; + + min-height: 600px; + } + + .hero__container { + position: relative; + overflow: hidden; + border: var(--hero-border-width) var(--hero-border-style) rgb(var(--color-border-rgb) / var(--hero-border-opacity)); + min-height: inherit; + align-items: var(--vertical-alignment-mobile); + justify-content: var(--horizontal-alignment); + z-index: var(--layer-base); + + @media screen and (min-width: 750px) { + align-items: var(--vertical-alignment); + } + } + + .hero__content-wrapper.page-width { + grid-column: 2 / 3; + } + + .hero__content-wrapper { + position: relative; + inset: 0; + z-index: var(--layer-flat); + } + + .hero__content-wrapper .group-block-content { + position: relative; + } + + .hero__media-wrapper { + position: absolute; + inset: 0; + display: grid; + grid-column: 1 / -1; + grid-template-columns: repeat(var(--hero-media-count, 1), 1fr); + } + + .hero--auto .hero__image, + .hero--auto .hero__video { + aspect-ratio: var(--hero-media-aspect-ratio); + } + + .hero--no-blocks-auto-height { + :is(.hero__image, .hero__video) { + width: 100%; + aspect-ratio: auto; + } + + .hero__media-wrapper { + /* When there are no blocks and the height is auto, allow the image to appear. */ + position: relative; + } + } + + .hero__image, + .hero__video, + .hero__video-poster { + height: 100%; + width: 100%; + object-fit: cover; + object-position: center center; + overflow: hidden; + position: relative; + z-index: var(--layer-base); + } + + .hero__video-poster { + position: absolute; + } + + .hero__link { + position: absolute; + inset: 0; + grid-column: 1 / -1; + } + + .hero__media-wrapper, + .hero__content-wrapper { + pointer-events: none; + + :is(a, button, input, textarea, select) { + pointer-events: auto; + } + } + + .hero__content-wrapper--design-mode * { + pointer-events: auto; + } + + .hero[data-blur-shadow='true'] { + --blurred-reflection-filter-saturate: saturate(1.5); + --blurred-reflection-mask-image: linear-gradient(to bottom, black 0%, black 60%, transparent 100%); + --blurred-reflection-box-shadow: rgb(0 0 0 / 5%) 0 0 1rem; + --blurred-reflection-filter-blur: blur(20px); + --blurred-reflection-scale: scale(2, 1.25); + --blurred-reflection-padding-block-end: 60px; + } + + .hero[data-blur-shadow='true'] .hero__container { + overflow: inherit; + } + + .hero[data-blur-shadow='true'] .hero__container::before { + content: ''; + position: absolute; + inset: 0; + box-shadow: var(--blurred-reflection-box-shadow); + mix-blend-mode: overlay; + pointer-events: none; + z-index: -1; + } + + .hero__blurred-image { + position: absolute; + inset: 0; + z-index: -1; + mask-image: var(--blurred-reflection-mask-image); + filter: var(--blurred-reflection-filter-saturate); + pointer-events: none; + transform: translateY(50%); + overflow: hidden; + } + + .hero__blurred-image img, + .hero__blurred-image svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center center; + filter: var(--blurred-reflection-filter-blur); + opacity: var(--blur-opacity); + transform: var(--blurred-reflection-scale); + padding-block-end: var(--blurred-reflection-padding-block-end); + + &:not(:only-child) { + width: 50%; + + &:last-child { + right: 0; + left: auto; + } + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.hero", + "tag": "section", + "class": "hero-wrapper section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "text" + }, + { + "type": "button" + }, + { + "type": "logo" + }, + { + "type": "jumbo-text" + }, + { + "type": "spacer" + }, + { + "type": "group" + }, + { + "type": "_marquee" + } + ], + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.media" + }, + { + "type": "select", + "id": "media_type_1", + "label": "t:settings.type", + "options": [ + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "image" + }, + { + "type": "image_picker", + "id": "image_1", + "label": "t:settings.image", + "visible_if": "{{ section.settings.media_type_1 == 'image' }}" + }, + { + "type": "video", + "id": "video_1", + "label": "t:settings.video", + "visible_if": "{{ section.settings.media_type_1 == 'video' }}" + }, + { + "type": "header", + "content": "t:content.media_2" + }, + { + "type": "select", + "id": "media_type_2", + "label": "t:settings.type", + "options": [ + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "image" + }, + { + "type": "image_picker", + "id": "image_2", + "label": "t:settings.image", + "visible_if": "{{ section.settings.media_type_2 == 'image' }}" + }, + { + "type": "video", + "id": "video_2", + "label": "t:settings.video", + "visible_if": "{{ section.settings.media_type_2 == 'video' }}" + }, + { + "type": "header", + "content": "t:content.section_link" + }, + { + "type": "url", + "id": "link", + "label": "t:settings.link" + }, + { + "type": "checkbox", + "id": "open_in_new_tab", + "label": "t:settings.open_new_tab", + "default": false + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ section.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "auto", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "full-screen", + "label": "t:options.full_screen" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "medium" + }, + { + "type": "range", + "id": "section_height_custom", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "default": 50, + "unit": "%", + "visible_if": "{{ section.settings.section_height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.media_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ section.settings.toggle_overlay and section.settings.overlay_style == 'gradient' }}" + }, + { + "type": "checkbox", + "id": "blurred_reflection", + "label": "t:settings.blurred_reflection", + "default": false, + "info": "t:info.applies_on_image_only" + }, + { + "type": "range", + "id": "reflection_opacity", + "label": "t:settings.reflection_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "default": 75, + "visible_if": "{{ section.settings.blurred_reflection }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.hero", + "category": "t:categories.banners", + "blocks": { + "text_1": { + "type": "text", + "settings": { + "text": "

New arrivals

", + "type_preset": "h1", + "max_width": "narrow" + } + }, + "text_2": { + "type": "text", + "settings": { + "text": "

Made with care and unconditionally loved by our customers.

", + "max_width": "narrow", + "padding-block-end": 32 + } + }, + "button": { + "type": "button", + "name": "t:names.button", + "settings": { + "label": "Shop Now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["text_1", "text_2", "button"], + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "gap": 16, + "section_height": "large", + "color_scheme": "scheme-5", + "padding-block-start": 40, + "padding-block-end": 40, + "toggle_overlay": true, + "overlay_style": "gradient" + } + }, + { + "name": "t:names.hero_marquee", + "category": "t:categories.banners", + "blocks": { + "spacer": { + "type": "spacer", + "settings": { + "size": "pixel", + "pixel_size": 24 + } + }, + "marquee": { + "type": "_marquee", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

Explore our latest products.

", + "type_preset": "h1" + } + } + }, + "block_order": ["text"] + }, + "button": { + "type": "button", + "settings": { + "label": "Shop Now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["spacer", "marquee", "button"], + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "space-between", + "gap": 32, + "section_height": "large", + "color_scheme": "scheme-5", + "padding-block-start": 0, + "padding-block-end": 40, + "toggle_overlay": true, + "overlay_style": "gradient" + } + } + ] +} +{% endschema %} diff --git a/sections/main-404.liquid b/sections/main-404.liquid new file mode 100644 index 000000000..c9f44c047 --- /dev/null +++ b/sections/main-404.liquid @@ -0,0 +1,188 @@ +{% # import schema from '../schemas/sections/main-404' %} + +
+
+
+
+ {% content_for 'blocks' %} +
+
+
+ +{% schema %} +{ + "name": "t:names.404", + "class": "section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + } + ], + "default": "column", + "visible_if": "{{ section.settings.horizontal_alignment_flex_direction_column == 'fake-value' }}" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "full-screen", + "label": "t:options.full_screen" + } + ], + "default": "" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "center" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/main-blog-post.liquid b/sections/main-blog-post.liquid new file mode 100644 index 000000000..422bc9171 --- /dev/null +++ b/sections/main-blog-post.liquid @@ -0,0 +1,171 @@ +{% # import schema from '../schemas/sections/main-blog-post.js' %} + +
+
+
+
+ {%- content_for 'block', id: 'blog-post-title', type: 'text' %} + {%- content_for 'block', id: 'blog-post-details', type: '_blog-post-info-text' %} +
+ + {%- content_for 'block', id: 'blog-post-image', type: 'image' %} + {%- content_for 'block', id: 'blog-post-content', type: '_blog-post-content' %} + + {% if blog.comments_enabled? %} +
+

{{- 'blogs.article.comments_heading' | t: count: article.comments_count -}}

+ +
+ {% paginate article.comments by 10 %} + {% for comment in article.comments %} +
+ {{ comment.content }} +
+ {{- comment.author -}} + {{- 'blogs.article.comment_author_separator' | t -}} + + {{- comment.created_at | time_tag: format: 'date' -}} + +
+
+ {% endfor %} + +
+ {{- paginate | default_pagination -}} +
+ {% endpaginate %} +
+ + {% render 'blog-comment-form', article: article, section_id: section.id %} +
+ {% endif %} +
+
+ + + +{% stylesheet %} + .blog-post-comments-container { + width: 100%; + max-width: var(--normal-content-width); + margin: 0 auto; + } + + .blog-post-comments { + display: flex; + flex-direction: column; + gap: var(--gap-3xl); + } + + .blog-post-comment__author { + display: flex; + align-items: center; + gap: var(--gap-2xs); + margin-top: var(--margin-md); + font-size: var(--font-size--body-sm); + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .blog-post-comments-pagination { + display: flex; + justify-content: center; + gap: var(--gap-2xs); + } + + .blog-post-comments-pagination, + .blog-post-comments-pagination a { + color: var(--color-foreground); + } + + .blog-post-comments-pagination .current { + color: var(--color-foreground); + } + + .blog-post-comments-pagination .current, + .blog-post-comments-pagination a { + display: block; + padding: var(--padding-2xs) var(--padding-xs); + } + + .blog-post-comments-pagination .current, + .blog-post-comments-pagination a:hover { + border-bottom: 1px solid var(--color-foreground); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.blog_post", + "class": "section-wrapper", + "settings": [ + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + } + ], + "default": "column", + "visible_if": "{{ section.settings.gap < 0 }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [] +} +{% endschema %} diff --git a/sections/main-blog.liquid b/sections/main-blog.liquid new file mode 100644 index 000000000..d14cc7cde --- /dev/null +++ b/sections/main-blog.liquid @@ -0,0 +1,206 @@ +{% # import schema from '../schemas/sections/main-blog' %} + + + + +
+
+ {% content_for 'blocks' %} + + {%- paginate blog.articles by 12 -%} + +
+ {% for article in blog.articles %} +
+ {% content_for 'block', id: 'static-blog-post-card', type: '_blog-post-card', article: article %} +
+ {% endfor %} +
+ + {%- endpaginate -%} +
+
+ +{% stylesheet %} + /** + * Blog posts page layout + */ + .blog-posts { + --page-content-width: var(--narrow-page-width); + --page-width: calc(var(--page-content-width) + (var(--page-margin) * 2)); + --columns-gap: 36px; + --rows-gap: 36px; + } + + .blog-posts-container { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 1rem; + width: 100%; + column-gap: var(--columns-gap); + row-gap: var(--rows-gap); + } + + /** + * Apart from the first and second rows in the grid, all remaining blog posts + * are arranged in a three-column layout: + * +------------+------------+-------------+ + * | | | | + * | (span 2) | (span 2) | (span 2) | + * | | | | + * +------------+------------+-------------+ + */ + .blog-post-item { + --blog-post-card-scale: 0.6; + + grid-column: span 2; + + @media screen and (max-width: 749px) { + --blog-post-card-scale: 0.5; + + grid-column: span 6; + } + } + + /** + * The second row of blog posts has two columns: + * +-------------------+-------------------+ + * | | | + * | (column span 3) | (column span 3) | + * | | | + * +-------------------+-------------------+ + */ + .blog-post-item:nth-child(2), + .blog-post-item:nth-child(3) { + --blog-post-card-scale: 0.8; + + grid-column: span 3; + + @media screen and (max-width: 749px) { + --blog-post-card-scale: 0.5; + + grid-column: span 6; + } + } + + /** + * The first row of blog posts has only one column: + * +---------------------------------------+ + * | | + * | (1 column span 6) | + * | | + * +---------------------------------------+ + */ + .blog-post-item:first-child { + --blog-post-card-scale: 1; + + grid-column: span 6; + } + + /** + * When there's no image, the blog post item has a border. + */ + .blog-post-item { + border: 1px solid rgb(var(--color-foreground-rgb) / var(--opacity-20)); + padding: 0 1rem 1rem; + } + + .blog-post-item:has(.blog-post-card__image-container) { + border: none; + padding: 0; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.blog_posts", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/main-cart.liquid b/sections/main-cart.liquid new file mode 100644 index 000000000..4e6082f75 --- /dev/null +++ b/sections/main-cart.liquid @@ -0,0 +1,200 @@ +{% # import schema from '../schemas/sections/main-cart.js' %} + + +
+
+
+
+ {%- content_for 'block', id: 'cart-page-title', type: '_cart-title' %} +
+ +
+ {%- content_for 'block', id: 'cart-page-items', type: '_cart-products' %} +
+ + {%- unless cart.empty? -%} +
+ {%- content_for 'block', id: 'cart-page-summary', type: '_cart-summary' -%} +
+ {%- endunless -%} + +
+ {%- content_for 'blocks' -%} +
+
+
+
+ +{% stylesheet %} + .cart-page { + --cart-font-size--2xs: var(--font-size--2xs); + --cart-font-size--xs: var(--font-size--xs); + --cart-font-size--sm: var(--font-size--sm); + --cart-font-size--md: var(--font-size--md); + --cart-font-size--2xl: var(--font-size--2xl); + + display: grid; + grid-template-columns: 1fr; + gap: 0 var(--padding-5xl); + } + + .cart-page--empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .cart-page--empty .cart-page__title, + .cart-page--empty .cart-page__more-blocks { + margin-top: var(--margin-6xl); + } + + .cart-page__more-blocks { + width: 100%; + } + + .cart-page--empty .cart-title { + text-align: center; + } + + .cart-page__main { + grid-column: 1; + } + + .cart-page__summary { + padding-top: var(--padding-xl); + } + + @media screen and (min-width: 750px) { + .cart-page { + grid-template-columns: 1fr min(50vw, var(--sidebar-width)); + grid-template-rows: min-content min-content 1fr; + } + + .cart-page__summary { + display: grid; + height: 100%; + grid-column: 2; + grid-row: 1 / -1; + align-self: stretch; + grid-template-rows: subgrid; + padding-top: 0; + + /* needed to support blurred effect from hero section */ + position: relative; + } + + .section--page-width .cart-page:has(.cart__container--extend) { + grid-column: 2 / 4; + grid-template-columns: 1fr minmax( + var(--sidebar-width), + calc((100vw - var(--page-width)) / 2 + var(--sidebar-width)) + ); + } + + .cart__container--extend { + height: 100%; + } + } + + @media screen and (min-width: 1400px) { + .cart-page { + grid-template-columns: 1fr var(--sidebar-width); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.cart", + "disabled_on": { + "groups": ["header", "footer"] + }, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + } + ], + "settings": [ + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/main-collection-list.liquid b/sections/main-collection-list.liquid new file mode 100644 index 000000000..0b4e2083b --- /dev/null +++ b/sections/main-collection-list.liquid @@ -0,0 +1,405 @@ +{% # import schema from '../schemas/sections/main-collection-list.js' %} + +{% liquid + assign section_collections = collections + assign max_items = 20 + + case section.settings.layout_type + when 'grid' + assign classes = 'resource-list--grid' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--resource-list-row-gap-desktop: ' | append: section.settings.rows_gap | append: 'px;' + echo '--resource-list-columns: repeat(' | append: section.settings.columns | append: ', 1fr);' + echo '--resource-list-columns-mobile: repeat(' | append: section.settings.mobile_columns | append: ', 1fr);' + echo '--column-count-mobile: ' | append: section.settings.mobile_columns | append: ';' + endcapture + when 'bento' + assign classes = 'resource-list--bento' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.bento_gap | append: 'px;' + echo '--bento-gap: var(--resource-list-column-gap);' + endcapture + when 'carousel' + assign classes = 'resource-list__carousel' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--column-count: ' | append: section.settings.columns | append: ';' + echo '--column-count-mobile: 1;' + endcapture + endcase +%} + +
+ +
+
+ {%- content_for 'blocks' -%} +
+ + {% if section_collections == null %} + {% for i in (1..max_items) %} + {% assign section_collections = section_collections | append: ', ' %} + {% endfor %} + + {% assign section_collections = section_collections | split: ',' %} + {% endif %} + + {% capture list_items %} + {% for collection in section_collections limit: max_items %} +
+ {% content_for 'block', type: '_collection-card', id: 'static-collection-card', closest.collection: collection %} +
+ {% unless forloop.last %} + + {% endunless %} + {% endfor %} + {% endcapture %} + + {% liquid + # Create an array from the list items to be used for different layout types + assign list_items_array = list_items | strip | split: '' + %} + +
+ {% case section.settings.layout_type %} + {% when 'grid' %} + {{ list_items }} + {% when 'bento' %} + {% render 'bento-grid', items: list_items_array %} + {% when 'carousel' %} + {% render 'resource-list-carousel', + ref: 'collectionListCarousel', + slides: list_items_array, + slide_count: max_items, + settings: section.settings, + slide_width_max: '450px' + %} + {% when 'editorial' %} + {% render 'editorial-collection-grid', items: list_items_array %} + {% endcase %} +
+ + {% if section.settings.layout_type != 'carousel' and section.settings.carousel_on_mobile %} + {% liquid + assign mobile_carousel_gap = section.settings.columns_gap + if section.settings.layout_type == 'bento' + assign mobile_carousel_gap = section.settings.bento_gap + endif + %} + + {% endif %} +
+ +{% schema %} +{ + "name": "t:names.collection_list", + "class": "ui-test-collection-list", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.cards_layout" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.layout_type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + }, + { + "value": "bento", + "label": "t:options.bento" + }, + { + "value": "editorial", + "label": "t:options.editorial" + } + ], + "default": "grid" + }, + { + "type": "checkbox", + "id": "carousel_on_mobile", + "label": "t:settings.carousel_on_mobile", + "default": false, + "visible_if": "{{ section.settings.layout_type != 'carousel' }}" + }, + { + "type": "range", + "id": "columns", + "label": "t:settings.columns", + "min": 1, + "max": 8, + "step": 1, + "default": 4, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "select", + "id": "mobile_columns", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "1", + "label": "t:options.one_number" + }, + { + "value": "2", + "label": "t:options.two_number" + } + ], + "default": "2", + "visible_if": "{{ section.settings.layout_type == 'grid' and section.settings.carousel_on_mobile == false }}" + }, + { + "type": "range", + "id": "columns_gap", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "range", + "id": "bento_gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'bento' }}" + }, + { + "type": "range", + "id": "rows_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid'}}" + }, + { + "type": "range", + "id": "max_collections", + "label": "t:settings.collection_count", + "min": 1, + "max": 16, + "step": 1, + "default": 4, + "visible_if": "{{ section.settings.layout_type == 'editorial' }}" + }, + { + "type": "header", + "content": "t:content.carousel_navigation", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icon", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.arrows_large" + }, + { + "value": "chevron_large", + "label": "t:options.chevron_large" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrow", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_shape", + "label": "t:settings.icon_background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "none", + "visible_if": "{{ section.settings.icons_style != 'none' and section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/main-collection.liquid b/sections/main-collection.liquid new file mode 100644 index 000000000..12cb65b8c --- /dev/null +++ b/sections/main-collection.liquid @@ -0,0 +1,309 @@ +{% # import schema from '../schemas/sections/main-collection' %} + + + +{% javascript %} + const url = new URL(window.location.href); + if (url.hash) { + document.addEventListener( + 'DOMContentLoaded', + () => { + const card = document.getElementById(url.hash.slice(1)); + if (card) { + card.scrollIntoView({ behavior: 'instant' }); + } + }, + { once: true } + ); + } +{% endjavascript %} + +{% comment %} We always render this full-width, as the child blocks have width: page/full settings {% endcomment %} +
+ + {% render 'skip-to-content-link', href: '#ResultsList', text: 'accessibility.skip_to_results_list' %} + +
+ {% content_for 'block', + type: 'filters', + id: 'filters', + results: collection, + results_size: collection.products_count + %} + + {% paginate collection.products by 24 %} + {% capture children %} + {% for product in collection.products %} +
  • + {% # theme-check-disable %} + {% content_for 'block', type: '_product-card', id: 'product-card', closest.product: product %} + {% # theme-check-enable %} +
  • + {% endfor %} + {% endcapture %} + + {% render 'product-grid', + section: section, + children: children, + products: collection.products, + paginate: paginate + %} + {% endpaginate %} +
    +
    + +{% stylesheet %} + .main-collection-grid { + grid-column: var(--grid-column--mobile); + + @media screen and (min-width: 750px) { + grid-column: var(--grid-column--desktop); + } + } + + .collection-wrapper { + @media screen and (min-width: 750px) { + grid-template-columns: + 1fr repeat( + var(--centered-column-number), + minmax(0, calc((var(--page-width) - var(--page-margin) * 2) / var(--centered-column-number))) + ) + 1fr; + } + } + + .collection-wrapper:has(.facets-block-wrapper--full-width), + .collection-wrapper:has(.collection-wrapper--full-width) { + @media screen and (min-width: 750px) { + grid-column: 1 / -1; + grid-template-columns: + minmax(var(--page-margin), 1fr) repeat( + var(--centered-column-number), + minmax(0, calc((var(--page-width) - var(--page-margin) * 2) / var(--centered-column-number))) + ) + minmax(var(--page-margin), 1fr); + } + } + + .collection-wrapper:has(.facets--vertical) .facets-block-wrapper--vertical:not(.hidden) ~ .main-collection-grid { + @media screen and (min-width: 750px) { + grid-column: var(--facets-vertical-col-width) / var(--full-width-column-number); + } + } + + .collection-wrapper:has(.facets-block-wrapper--vertical:not(#filters-drawer)):has(.collection-wrapper--full-width) { + @media screen and (min-width: 750px) { + grid-column: 1 / -1; + grid-template-columns: 0fr repeat(var(--centered-column-number), minmax(0, 1fr)) 0fr; + } + } + + :is(.collection-wrapper--full-width, .collection-wrapper--full-width-on-mobile) + [product-grid-view='default'] + .product-grid__card { + @media screen and (max-width: 749px) { + padding-inline-start: max(var(--padding-xs), var(--padding-inline-start)); + padding-inline-end: max(var(--padding-xs), var(--padding-inline-end)); + } + } + + :is(.collection-wrapper--full-width, .collection-wrapper--full-width-on-mobile) + [product-grid-view='mobile-single'] + .product-grid__card { + @media screen and (max-width: 749px) { + padding-inline-start: max(var(--padding-xs), var(--padding-inline-start)); + padding-inline-end: max(var(--padding-xs), var(--padding-inline-end)); + } + } + + /* Make product media go edge-to-edge by using negative margins */ + :is(.collection-wrapper--full-width) .card-gallery, + :is(.collection-wrapper--full-width-on-mobile) .card-gallery { + @media screen and (max-width: 749px) { + margin-inline-start: calc(-1 * max(var(--padding-xs), var(--padding-inline-start))); + margin-inline-end: calc(-1 * max(var(--padding-xs), var(--padding-inline-end))); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.collection_container", + "enabled_on": { + "templates": ["collection"] + }, + "settings": [ + { + "type": "select", + "id": "layout_type", + "label": "t:settings.type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "organic", + "label": "t:options.editorial" + } + ], + "default": "grid" + }, + { + "type": "select", + "id": "product_card_size", + "label": "t:settings.card_size", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "extra-large", + "label": "t:options.extra_large" + } + ], + "default": "medium", + "visible_if": "{{ section.settings.layout_type == 'grid' }}" + }, + { + "type": "select", + "id": "mobile_product_card_size", + "label": "t:settings.mobile_card_size", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "large", + "label": "t:options.large" + } + ], + "default": "small" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "product_grid_width", + "label": "t:settings.width", + "options": [ + { + "value": "centered", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "centered" + }, + { + "type": "checkbox", + "id": "full_width_on_mobile", + "label": "t:settings.full_width_on_mobile", + "default": true, + "visible_if": "{{ section.settings.product_grid_width != 'full-width' }}" + }, + { + "type": "range", + "id": "columns_gap_horizontal", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "columns_gap_vertical", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8 + } + ], + "presets": [] +} +{% endschema %} diff --git a/sections/main-page.liquid b/sections/main-page.liquid new file mode 100644 index 000000000..1b1bf3ee6 --- /dev/null +++ b/sections/main-page.liquid @@ -0,0 +1,96 @@ +{% # import schema from '../schemas/sections/main-page' %} + +
    +
    +
    + {% content_for 'blocks' %} +
    +
    + +{% schema %} +{ + "name": "t:names.page", + "class": "section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + } + ], + "default": "column", + "visible_if": "{{ section.settings.gap < 0 }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/marquee.liquid b/sections/marquee.liquid new file mode 100644 index 000000000..a5de49bf0 --- /dev/null +++ b/sections/marquee.liquid @@ -0,0 +1,192 @@ +{% # import schema from '../schemas/sections/marquee' %} + + + +{% assign gap_between_elements = section.settings.gap_between_elements %} + +
    + +
    +
    +
    + {% content_for 'blocks' %} +
    +
    +
    +
    + +{% stylesheet %} + marquee-component { + display: block; + width: 100%; + overflow: hidden; + } + + .marquee__wrapper { + display: flex; + gap: var(--marquee-gap); + width: fit-content; + white-space: nowrap; + } + + .marquee__content { + min-width: max-content; + display: flex; + gap: var(--marquee-gap); + } + + .marquee__content :is(p, h1, h2, h3, h4, h5, h6) { + white-space: nowrap; + } + + .marquee__content .marquee__repeated-items * { + max-width: none; + } + + .marquee__repeated-items { + min-width: max-content; + display: flex; + gap: var(--marquee-gap); + align-items: center; + justify-content: center; + } + + .marquee__repeated-items > * { + align-content: center; + } + + @media (prefers-reduced-motion: no-preference) { + marquee-component:not([data-disabled]) .marquee__wrapper { + animation: marquee-motion var(--marquee-speed) linear infinite var(--marquee-direction); + } + } + + @keyframes marquee-motion { + to { + transform: translate3d(calc(-50% - (var(--marquee-gap) / 2)), 0, 0); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.marquee", + "disabled_on": { + "groups": ["header", "footer"] + }, + "blocks": [ + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "logo" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "select", + "id": "movement_direction", + "label": "t:settings.motion_direction", + "options": [ + { + "value": "reverse", + "label": "t:options.forward" + }, + { + "value": "normal", + "label": "t:options.reverse" + } + ], + "default": "normal" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + }, + { + "type": "range", + "id": "gap_between_elements", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 24 + } + ], + "presets": [ + { + "name": "t:names.marquee_section", + "category": "t:categories.banners", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    We make things that work better and last longer.

    ", + "type_preset": "custom", + "font": "var(--font-body--family)", + "font_size": "var(--font-size--h2)", + "line_height": "tight", + "letter_spacing": "tight", + "case": "none", + "wrap": "nowrap", + "width": "fit-content" + } + } + }, + "block_order": ["text"] + } + ] +} +{% endschema %} diff --git a/sections/media-with-content.liquid b/sections/media-with-content.liquid new file mode 100644 index 000000000..39b7b84a6 --- /dev/null +++ b/sections/media-with-content.liquid @@ -0,0 +1,434 @@ +{% # import schema from '../schemas/sections/media-with-content' %} + +{% liquid + assign media_class_modifier = 'media-with-content--' | append: section.settings.media_width + + if section.settings.extend_media and section.settings.section_width == 'page-width' + assign media_class_modifier = media_class_modifier | append: ' media-with-content--media-extend' + endif + + if section.settings.media_position == 'right' + assign media_class_modifier = media_class_modifier | append: ' media-with-content--media-right' + endif +%} + +
    +
    + {% content_for 'block', type: '_media-without-appearance', id: 'media' %} + + {% content_for 'block', type: '_content-without-appearance', id: 'content' %} +
    + +{% stylesheet %} + .section--page-width { + &.media-with-content { + grid-template-areas: 'margin-left media margin-right' 'margin-left content margin-right'; + + @media screen and (min-width: 750px) { + /* Wide proportion is media 3.5 parts, content 2.5 parts. Which equals 7|5. So divide the central column by 7+5 and multiply accordingly */ + --media-with-content-grid-columns: var(--full-page-grid-margin) + calc((var(--full-page-grid-central-column-width) / 12) * 7) + calc((var(--full-page-grid-central-column-width) / 12) * 5) var(--full-page-grid-margin); + + grid-template-areas: 'margin-left media content margin-right'; + } + } + + &.media-with-content--media-right { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: var(--full-page-grid-margin) + calc((var(--full-page-grid-central-column-width) / 12) * 5) + calc((var(--full-page-grid-central-column-width) / 12) * 7) var(--full-page-grid-margin); + + grid-template-areas: 'margin-left content media margin-right'; + } + } + + &.media-with-content--medium { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: var(--full-page-grid-margin) + repeat(2, calc(var(--full-page-grid-central-column-width) / 2)) var(--full-page-grid-margin); + } + } + + &.media-with-content--narrow.media-with-content--media-right { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: var(--full-page-grid-margin) + calc((var(--full-page-grid-central-column-width) / 3) * 2) + calc(var(--full-page-grid-central-column-width) / 3) var(--full-page-grid-margin); + } + } + + &.media-with-content--narrow { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: var(--full-page-grid-margin) + calc(var(--full-page-grid-central-column-width) / 3) + calc((var(--full-page-grid-central-column-width) / 3) * 2) var(--full-page-grid-margin); + } + } + } + + .section--full-width { + &.media-with-content--media-right { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: 2.5fr 3.5fr; + + grid-template-areas: 'content media'; + } + } + + &.media-with-content--medium { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: 1fr 1fr; + } + } + + &.media-with-content--narrow { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: 2fr 4fr; + } + } + + &.media-with-content--narrow.media-with-content--media-right { + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: 4fr 2fr; + } + } + } + + /* Keep the CSS specificity lower assuming that liquid won't assign this class with a full width section */ + .media-with-content.media-with-content--media-extend { + grid-template-columns: var(--media-with-content-grid-columns); + grid-template-areas: 'media media media' 'margin-left content margin-right'; + + @media screen and (min-width: 750px) { + grid-template-areas: 'media media content margin-right'; + } + } + + .media-with-content--media-extend.media-with-content--media-right { + @media screen and (min-width: 750px) { + grid-template-areas: 'margin-left content media media'; + } + } + + .media-with-content--media-right { + @media screen and (min-width: 750px) { + grid-template-areas: 'margin-left content media media'; + } + } + + .media-with-content { + --media-with-content-grid-columns: var(--full-page-grid-with-margins); + + grid-template-columns: var(--media-with-content-grid-columns); + grid-template-areas: 'media media media' 'content content content'; + + @media screen and (min-width: 750px) { + --media-with-content-grid-columns: 3.5fr 2.5fr; + + /* Default desktop layout is wide media, on the left, in full page section */ + grid-template-areas: 'media content'; + } + + .media-block { + grid-area: media; + } + + .media-with-content__content { + grid-area: content; + } + + /* Inner blocks spacing */ + .media-with-content__content > .group-block-content { + padding-inline: var(--page-margin); + padding-block: calc(2 * var(--page-margin)); + + @media screen and (min-width: 750px) { + padding-block: var(--page-margin); + } + } + + &.section--page-width .media-with-content__content > .group-block-content { + padding-inline: 0; + + @media screen and (min-width: 750px) { + padding-inline-start: var(--page-margin); + } + } + + &.section--page-width.media-with-content--media-right .media-with-content__content > .group-block-content { + padding-inline-end: var(--page-margin); + padding-inline-start: 0; + } + } + + .media-with-content[data-shopify-visual-preview] { + --hero-min-height: 500px; + + min-height: 500px; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.media_with_text", + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "select", + "id": "media_position", + "label": "t:settings.media_position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "left" + }, + { + "type": "select", + "id": "media_width", + "label": "t:settings.media_width", + "options": [ + { + "value": "narrow", + "label": "t:options.narrow" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "wide", + "label": "t:options.wide" + } + ], + "default": "wide" + }, + { + "type": "select", + "id": "media_height", + "label": "t:settings.media_height", + "options": [ + { + "value": "auto", + "label": "t:options.auto" + }, + { + "value": "50svh", + "label": "t:options.small" + }, + { + "value": "60svh", + "label": "t:options.medium" + }, + { + "value": "80svh", + "label": "t:options.large" + }, + { + "value": "100svh", + "label": "t:options.full_screen" + } + ], + "default": "80svh" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.section_width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "full-width" + }, + { + "type": "checkbox", + "id": "extend_media", + "label": "t:settings.extend_media_to_screen_edge", + "default": true, + "visible_if": "{{ section.settings.section_width == 'page-width' }}" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-3" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.editorial", + "category": "t:categories.storytelling", + "settings": { + "media_width": "medium", + "media_height": "60svh", + "color_scheme": "scheme-4" + }, + "blocks": { + "media": { + "type": "_media-without-appearance", + "static": true + }, + "content": { + "type": "_content-without-appearance", + "static": true, + "settings": { + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "space-between" + }, + "blocks": { + "caption": { + "type": "text", + "name": "t:names.caption", + "settings": { + "text": "

    Bestseller

    ", + "type_preset": "h6" + } + }, + "group": { + "type": "group", + "settings": { + "height": "fit" + }, + "blocks": { + "heading": { + "type": "text", + "name": "t:names.heading", + "settings": { + "text": "

    Our signature product

    ", + "type_preset": "h3" + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Made with care and unconditionally loved by our customers, this signature bestseller exceeds all expectations.

    ", + "max_width": "narrow", + "type_preset": "rte" + } + } + }, + "block_order": ["heading", "text"] + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all", + "style_class": "link" + } + } + }, + "block_order": ["caption", "group", "button"] + } + } + }, + { + "name": "t:names.editorial_jumbo_text", + "category": "t:categories.storytelling", + "settings": { + "media_position": "right", + "media_width": "medium", + "media_height": "60svh", + "color_scheme": "scheme-3" + }, + "blocks": { + "media": { + "type": "_media-without-appearance", + "static": true + }, + "content": { + "type": "_content-without-appearance", + "static": true, + "settings": { + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "flex-end" + }, + "blocks": { + "caption": { + "type": "jumbo-text", + "name": "t:names.jumbo_text", + "settings": { + "text": "Up\nThe\nAnte", + "font": "heading", + "alignment": "right", + "line_height": "0.8", + "letter_spacing": "-0.03em", + "case": "uppercase" + } + } + }, + "block_order": ["caption"] + } + } + } + ] +} +{% endschema %} diff --git a/sections/password.liquid b/sections/password.liquid new file mode 100644 index 000000000..c1852b831 --- /dev/null +++ b/sections/password.liquid @@ -0,0 +1,531 @@ +{% # import schema from '../schemas/sections/password' %} + +
    +
    +
    + {% render 'background-media', + background_media: section.settings.background_media, + background_video: section.settings.video, + background_video_position: section.settings.video_position, + background_image: section.settings.background_image, + background_image_position: section.settings.background_image_position + %} + +
    + {% content_for 'blocks' %} +
    +
    +
    + +{% stylesheet %} + .section--password { + --section-min-height: calc(100svh - 8rem); + } + + .password-enter { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--gap-sm); + padding-block: var(--padding-xl); + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: var(--layer-overlay); + } + + .password-enter__powered-by { + margin: 0; + display: flex; + align-items: center; + gap: var(--padding-xs); + height: 1em; + + a { + display: flex; + } + + svg { + display: inline; + height: 1.3em; + color: var(--color-foreground); + } + } + + .password-enter__links { + display: flex; + align-items: center; + gap: var(--gap-2xl); + + @media screen and (max-width: 749px) { + flex-direction: column; + gap: var(--gap-sm); + } + } + + .password-enter__admin-link { + margin: 0; + } + + /* Adjust padding when preview bar is present to ensure button visibility */ + body:has(#PBarNextFrameWrapper) .password-enter { + padding-bottom: var(--padding-6xl); + } + + .password-enter__button { + height: var(--minimum-touch-target); + background-color: transparent; + color: var(--color-primary); + cursor: pointer; + text-decoration: underline; + + &:hover { + color: var(--color-primary-hover); + text-decoration: none; + } + } + + .password-dialog { + max-width: 100vw; + max-height: 100svh; + width: 100vw; + height: 100svh; + border: none; + transition: opacity var(--animation-values), display var(--animation-speed) allow-discrete, + overlay var(--animation-speed) allow-discrete; + + &::backdrop { + display: none; + } + } + + .password-dialog[open] { + opacity: 1; + top: 0; + left: 0; + } + + @starting-style { + .password-dialog[open] { + opacity: 0; + } + } + + .password-dialog:not([open]) { + opacity: 0; + } + + @starting-style { + .password-dialog:not([open]) { + opacity: 1; + } + } + + .password-dialog__close-button { + cursor: pointer; + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + } + + .password-dialog__header { + position: absolute; + top: 0; + right: 0; + padding: var(--padding-lg); + z-index: var(--layer-raised); + } + + .password-dialog__content { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: var(--padding-lg); + height: 100%; + transition: transform var(--animation-values); + } + + .password-dialog__content .email-signup__message { + padding-block-start: var(--padding-xl); + } + + .password-dialog[open] .password-dialog__content { + transform: translateY(0); + } + + @starting-style { + .password-dialog[open] .password-dialog__content { + transform: translateY(1em); + } + } + + .password-dialog:not([open]) .password-dialog__content { + transform: translateY(1em); + } + + @starting-style { + .password-dialog:not([open]) .password-dialog__content { + transform: translateY(0); + } + } + + .storefront-password-form { + max-width: 400px; + width: 100%; + } + + .email-signup__input-group, + .password-dialog__submit-button { + width: 100%; + + @media screen and (min-width: 750px) { + width: auto; + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.section", + "class": "section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ section.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/predictive-search-empty.liquid b/sections/predictive-search-empty.liquid new file mode 100644 index 000000000..5c4f65292 --- /dev/null +++ b/sections/predictive-search-empty.liquid @@ -0,0 +1,11 @@ +{% # import schema from '../schemas/sections/predictive-search-empty.js' %} + +{% render 'predictive-search-empty-state', products_test_id: 'products-list-default--reset' %} + +{% schema %} +{ + "name": "t:names.predictive_search_empty", + "class": "predictive-search-empty-section", + "settings": [] +} +{% endschema %} diff --git a/sections/predictive-search.liquid b/sections/predictive-search.liquid new file mode 100644 index 000000000..5af834794 --- /dev/null +++ b/sections/predictive-search.liquid @@ -0,0 +1,1221 @@ +{% # import schema from '../schemas/sections/predictive-search.js' %} + +{%- if predictive_search.performed or search.performed -%} +
    +
    + {% if predictive_search.performed %} + {% assign search_results_count = predictive_search.resources.products.size + | plus: predictive_search.resources.pages.size + | plus: predictive_search.resources.articles.size + | plus: predictive_search.resources.collections.size + | plus: predictive_search.resources.queries.size + %} + {% else %} + {% assign search_results_count = search.results_count %} + {% endif %} + +
    + {%- if predictive_search.performed and search_results_count > 0 -%} + {{ 'accessibility.search_results_count' | t: count: search_results_count, query: predictive_search.terms }} + {%- elsif predictive_search.performed and search_results_count == 0 -%} + {{ 'accessibility.search_results_no_results' | t: query: predictive_search.terms }} + {%- endif -%} +
    + + {% if predictive_search.performed %} + {%- if search_results_count > 0 -%} + {% assign shared_results_index = 0 %} + {% if predictive_search.resources.queries.size > 0 %} + {% assign shared_results_index = shared_results_index + | plus: predictive_search.resources.collections.size + %} + + {% endif %} + {% if predictive_search.resources.products.size > 0 %} + {%- liquid + assign title = 'content.search_results_resource_products' | t + assign products = predictive_search.resources.products + render 'predictive-search-products-list', title: title, products: products + -%} + {% endif %} + + {% if predictive_search.resources.collections.size > 0 %} + {% assign shared_results_index = shared_results_index | plus: predictive_search.resources.articles.size %} + {% assign resource_title = 'content.search_results_resource_collections' | t %} + + {% render 'predictive-search-resource-carousel', + title: resource_title, + resource_type: 'collection', + resources: predictive_search.resources.collections + %} + {% endif %} + + {% if predictive_search.resources.pages.size > 0 %} + {% assign shared_results_index = shared_results_index | plus: predictive_search.resources.products.size %} + {% assign resource_title = 'content.search_results_resource_pages' | t %} + + {% render 'predictive-search-resource-carousel', + title: resource_title, + resource_type: 'page', + resources: predictive_search.resources.pages + %} + {% endif %} + + {% if predictive_search.resources.articles.size > 0 %} + {% assign shared_results_index = shared_results_index | plus: predictive_search.resources.pages.size %} + {% assign resource_title = 'content.search_results_resource_articles' | t %} + + {% render 'predictive-search-resource-carousel', + title: resource_title, + resource_type: 'article', + resources: predictive_search.resources.articles + %} + {% endif %} + {% else %} +

    + {{ 'content.search_results_no_results' | t: terms: predictive_search.terms }} +

    + {% endif %} + {% else %} + {% assign shared_results_index = 0 %} + {%- liquid + assign title = 'content.recently_viewed_products' | t + assign products = search.results + + comment + Searching for recently viewed products by id doesn't preserve the order of the products. + To work around this, we get the product ids into an array then use that to reorder them. + endcomment + if search.terms contains 'id:' + assign new_products_ids = search.terms | replace: 'id:', '' | split: ' OR ' + endif + render 'predictive-search-products-list', title: title, products: products, order_ids: new_products_ids, limit: 4 + -%} + {% endif %} + + {% if predictive_search.performed %} + {%- if search_results_count > 0 -%} + {% assign total_results = predictive_search.resources.products.size + | plus: predictive_search.resources.collections.size + | plus: predictive_search.resources.pages.size + | plus: predictive_search.resources.articles.size + %} + {% assign single_result_url = null %} + {% if total_results == 1 %} + {% if predictive_search.resources.products.size == 1 %} + {% assign single_result_url = predictive_search.resources.products.first.url %} + {% elsif predictive_search.resources.collections.size == 1 %} + {% assign single_result_url = predictive_search.resources.collections.first.url %} + {% elsif predictive_search.resources.pages.size == 1 %} + {% assign single_result_url = predictive_search.resources.pages.first.url %} + {% elsif predictive_search.resources.articles.size == 1 %} + {% assign single_result_url = predictive_search.resources.articles.first.url %} + {% endif %} + {% endif %} + + {% if single_result_url %} +
    + {% endif %} + {% endif %} + {% endif %} +
    +
    +{%- endif -%} + +{% stylesheet %} + predictive-search-component { + --resource-card-corner-radius: var(--product-corner-radius); + + display: flex; + width: 100%; + position: relative; + margin-inline: auto; + align-items: center; + background-color: var(--color-background); + z-index: var(--layer-heightened); + } + + input[type='search']::-webkit-search-decoration { + -webkit-appearance: none; /* stylelint-disable-line */ + } + + .predictive-search-dropdown { + display: flex; + flex-direction: column; + position: relative; + top: 0; + left: 0; + right: 0; + z-index: var(--layer-base); + } + + :not(:is(dialog)) > predictive-search-component { + @media screen and (min-width: 750px) { + max-width: min(40dvw, 650px); + } + } + + :not(:is(dialog)) > predictive-search-component .predictive-search__close-modal-button { + display: none; + } + + .search-action .predictive-search { + z-index: calc(var(--layer-header-menu) + 2); + } + + .search-action .search-modal .predictive-search { + z-index: var(--layer-window-overlay); + } + + .predictive-search--right { + margin-right: 0; + margin-left: auto; + } + + .predictive-search--left { + margin-right: auto; + margin-left: 0; + } + + :not(:is(dialog)) > predictive-search-component.predictive-search--floating { + width: min(40dvw, 650px); + position: absolute; + top: var(--search-top, unset); + right: var(--search-right, unset); + left: var(--search-left, unset); + } + + .predictive-search-form { + position: relative; + width: 100%; + align-self: flex-start; + } + + .predictive-search-form__content-wrapper { + position: absolute; + top: 100%; + width: 100%; + left: 0; + z-index: var(--layer-raised); + display: flex; + flex-direction: column; + border-radius: 0 0 var(--search-border-radius) var(--search-border-radius); + transition: box-shadow var(--animation-speed) var(--animation-easing); + transform: translateZ(0); + will-change: transform, opacity; + overflow: hidden; + + @media screen and (max-width: 749px) { + border-radius: 0; + } + + @media screen and (min-width: 750px) { + max-height: var(--modal-max-height); + height: var(--predictive-search-results-height, auto); + } + } + + /* Add new rule to apply bottom padding only when search button exists */ + .predictive-search-form__content-wrapper:has([data-search-results]):not(:has(.predictive-search-results__no-results)) + > .predictive-search-form__content { + padding-block-end: var(--padding-6xl); + } + + .header__column--right .predictive-search-form__content-wrapper { + right: 0; + left: unset; + } + + .search-modal .predictive-search-form__content-wrapper { + width: 100%; + } + + :not(:is(dialog)) + > predictive-search-component:not(.predictive-search--expanded) + .predictive-search-form__content-wrapper { + display: none; + } + + .predictive-search-form__header-inner:has(.search-input:focus-visible) { + outline: var(--focus-outline-width) solid var(--color-foreground); + outline-offset: calc(var(--focus-outline-offset) * -1); + } + + .predictive-search-results__inner { + --title-font-size: var(--font-size--md); + --title-margin-block: var(--margin-xs); + --list-item-padding-block: var(--padding-sm); + + flex-grow: 1; + overflow-y: auto; + padding-block: var(--padding-lg); + container-type: inline-size; + color: var(--color-foreground); + } + + .predictive-search-results__inner > * { + padding-inline: var(--padding-xl); + } + + .predictive-search-results__list { + --slide-width: 27.5%; + --slideshow-gap: var(--gap-md); + + /* Make space for the outline to be visible */ + padding-block-start: var(--border-width-sm); + } + + .predictive-search-results__list:last-child { + margin-block-end: 0; + } + + .predictive-search-results__resource-header { + display: flex; + padding-inline: var(--padding-xl); + justify-content: space-between; + align-items: center; + height: 32px; + } + + .predictive-search-results__resource-header .svg-wrapper { + width: var(--icon-size-xs); + } + + .predictive-search-results__list-item { + padding-inline: var(--padding-sm); + padding-block: var(--list-item-padding-block); + border-radius: var(--style-border-radius-popover); + scroll-margin-block: var(--padding-xl); + + &:first-child { + /* scroll-margin to match font + padding + margin on .predictive-search-results__title */ + scroll-margin-block-start: calc( + var(--title-font-size) + var(--title-margin-block) + var(--list-item-padding-block) + ); + } + + &:not(:has(.predictive-search-results__list-item-link--pill))[aria-selected='true'].keyboard-focus { + background-color: rgb(var(--color-primary-rgb) / var(--opacity-20)); + transform: translateY(0); + } + } + + .predictive-search-results__list-item:has(.predictive-search-results__list-item-link--pill) { + width: fit-content; + padding: 0; + } + + .predictive-search-results__list-item-link { + display: grid; + grid-template-columns: auto 1fr; + grid-column-gap: var(--gap-xl); + align-items: center; + } + + .predictive-search-results__list-item-link--pill { + display: block; + padding: var(--padding-2xs) var(--padding-sm); + } + + .predictive-search-results__list-item[aria-selected='true'] .predictive-search-results__list-item-link--pill { + background-color: rgb(var(--color-primary-rgb) / var(--opacity-20)); + } + + .predictive-search-results__list-item-link--no-media { + grid-template-columns: 1fr; + } + + .predictive-search-results__list-item-image, + .predictive-search-results__list-item-icon { + width: 100%; + border-radius: var(--product-corner-radius); + background-color: rgb(var(--color-primary-rgb) / var(--opacity-20)); + margin: auto; + object-fit: cover; + } + + .predictive-search-results__list-item-details { + display: flex; + flex-direction: column; + text-decoration: none; + overflow: hidden; + } + + .predictive-search-results__list-item-content { + font-size: var(--font-size-xs); + color: rgb(var(--color-primary-rgb) / var(--opacity-subdued-text)); + text-overflow: ellipsis; + overflow: hidden; + text-wrap: nowrap; + } + + .header[transparent] :is(.predictive-search):not(:focus-within) { + background-color: transparent; + } + + .header[transparent] .predictive-search-form__header-inner { + border-color: var(--color-foreground); + } + + .predictive-search-form__header .search-input { + border-radius: var(--style-border-radius-inputs); + padding-block: var(--padding-sm); + font-size: var(--font-size--md); + + &:hover { + background-color: transparent; + } + } + + .predictive-search__icon { + position: absolute; + left: var(--margin-xl); + top: auto; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + color: rgb(var(--color-foreground-rgb) / var(--opacity-60)); + + @media screen and (min-width: 750px) { + left: var(--margin-md); + } + } + + .predictive-search__icon > svg { + width: var(--icon-size-md); + height: var(--icon-size-md); + } + + .predictive-search__reset-button { + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + min-width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + padding: 0; + background: transparent; + color: var(--color-foreground); + opacity: 1; + transition: opacity var(--animation-speed) var(--animation-easing), + visibility var(--animation-speed) var(--animation-easing); + + &:hover { + color: var(--color-foreground); + } + + &:active { + transform: scale(0.9); + transition: transform 100ms var(--animation-timing-active); + } + + @media screen and (max-width: 749px) { + margin-right: var(--margin-md); + } + } + + .predictive-search__reset-button[hidden] { + opacity: 0; + pointer-events: none; + visibility: hidden; + } + + .predictive-search__reset-button-icon { + display: flex; + align-items: center; + justify-content: center; + width: var(--icon-size-lg); + height: var(--icon-size-lg); + transition: background-color var(--animation-speed-medium) ease-in-out, + transform var(--animation-speed-medium) var(--animation-timing-bounce); + border-radius: 50%; + + &:hover { + background-color: rgb(var(--color-primary-hover-rgb) / var(--opacity-8)); + } + } + + .predictive-search__reset-button:active .predictive-search__reset-button-icon { + transform: scale(0.85); + transition-timing-function: var(--animation-timing-active); + transition-duration: 100ms; + } + + .predictive-search__reset-button svg { + width: var(--icon-size-md); + height: var(--icon-size-md); + } + + .predictive-search__reset-button-text { + display: none; + } + + .predictive-search-form__content { + max-height: 50dvh; + overflow-y: auto; + background-color: var(--color-background); + + /* Firefox */ + scrollbar-width: none; + + /* Webkit browsers */ + &::-webkit-scrollbar { + display: none; + } + } + + .search-modal__content .predictive-search-form__content { + max-height: var(--modal-max-height); + } + + .predictive-search-results__no-results:last-child { + margin-block: var(--margin-lg); + text-align: center; + } + + .predictive-search__search-button { + margin: auto; + z-index: var(--layer-raised); + transition: transform var(--animation-speed-medium) var(--animation-timing-bounce), + box-shadow var(--animation-speed-medium) var(--animation-timing-hover); + transform-origin: center; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgb(0 0 0 / var(--opacity-5)); + } + + &:active { + transform: scale(0.97); + transition: transform 100ms var(--animation-timing-active); + box-shadow: none; + } + } + + .predictive-search:has(.predictive-search-dropdown) .search-input { + outline-color: transparent; + } + + .predictive-search-form__header { + display: flex; + position: sticky; + top: 0; + z-index: var(--layer-heightened); + width: 100%; + align-items: center; + background-color: var(--color-input-background); + border-radius: var(--style-border-radius-inputs); + + @media screen and (max-width: 749px) { + padding: var(--padding-2xs) var(--padding-sm); + } + } + + .predictive-search-form__header-inner { + background: var(--color-background); + border: var(--search-border-width) solid var(--color-border); + color: var(--color-foreground); + border-radius: var(--style-border-radius-popover); + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + + @media screen and (max-width: 749px) { + border-radius: var(--style-border-radius-inputs); + border: none; + } + } + + .predictive-search-form__header-inner:focus-within { + outline: 0; + outline-offset: var(--focus-outline-offset); + + @media screen and (min-width: 750px) { + outline: var(--focus-outline-width) solid var(--color-primary); + } + } + + .predictive-search:has(.predictive-search-dropdown) .predictive-search-form__header-inner:focus-within { + border-top-color: transparent; + border-right-color: transparent; + border-left-color: transparent; + + @media screen and (max-width: 749px) { + border-bottom-color: transparent; + } + } + + .predictive-search:has(.predictive-search-dropdown[aria-expanded='true']) + .predictive-search-form__header-inner:focus-within { + border-top-color: transparent; + border-right-color: transparent; + border-left-color: transparent; + border-radius: var(--search-border-radius); + + @media screen and (max-width: 749px) { + border-radius: var(--style-border-radius-inputs); + } + } + + .search-action .predictive-search:has(.predictive-search-dropdown) .predictive-search-form__header:focus-within { + border-radius: var(--search-border-radius) var(--search-border-radius) 0 0; + transition: box-shadow var(--animation-speed) var(--animation-easing); + background-color: var(--color-background); + + @media screen and (max-width: 749px) { + border-radius: var(--style-border-radius-inputs) var(--style-border-radius-inputs) 0 0; + } + } + + .predictive-search__close-modal-button:hover { + --button-color: var(--color-foreground); + --button-background-color: transparent; + } + + .predictive-search__close-modal-button { + --button-color: var(--color-foreground); + --button-background-color: transparent; + + display: flex; + justify-content: center; + align-items: center; + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + margin-inline-start: var(--margin-sm); + padding: 0; + box-shadow: none; + + &:active { + transform: scale(0.8); + transition: transform 100ms var(--animation-timing-active); + } + + .svg-wrapper, + svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + @media screen and (min-width: 750px) { + display: none; + } + } + + .predictive-search-form__footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + + @media screen and (min-width: 750px) { + --to-top-gradient-background: linear-gradient( + to top, + rgb(var(--color-background-rgb) / var(--opacity-90)), + rgb(var(--color-background-rgb) / var(--opacity-80)), + rgb(var(--color-background-rgb) / var(--opacity-40)), + transparent + ); + + padding-block: var(--padding-xs) var(--padding-lg); + background-image: var(--to-top-gradient-background); + } + } + + .dialog-modal .predictive-search-form__header { + border: 0; + border-radius: 0; + background-color: var(--color-background); + border-bottom: var(--style-border-width) solid var(--color-border); + + @media screen and (min-width: 750px) { + padding: var(--padding-2xs) var(--padding-2xs) 0; + border-bottom: var(--search-border-width) solid var(--color-border); + } + + @media screen and (max-width: 749px) { + transition: box-shadow 0.2s ease; + box-shadow: none; + } + } + + @media screen and (max-width: 749px) { + .dialog-modal .predictive-search__close-modal-button { + padding-inline-start: var(--margin-xs); + margin-inline-start: 0; + } + } + + .dialog-modal[open] { + @media screen and (max-width: 749px) { + border-radius: 0; + } + } + + .dialog-modal .predictive-search-form__header:has(.predictive-search-form__header-inner:focus-within) { + @media screen and (min-width: 750px) { + border-bottom-color: transparent; + } + } + + .dialog-modal .predictive-search-form__header-inner { + @media screen and (min-width: 750px) { + border: 0; + } + } + + @media screen and (max-width: 749px) { + .dialog-modal { + .predictive-search__reset-button-icon { + display: none; + } + + .predictive-search__reset-button-text { + display: block; + } + + .predictive-search-form__content { + /* The parent has overflow auto, we want to prevent a double scrollbar during animation */ + max-height: 100%; + } + + .predictive-search-form__content-wrapper { + box-shadow: none; + } + + .predictive-search-form__header { + box-shadow: none; + } + + .predictive-search-form__footer { + padding-block: var(--padding-2xl); + } + } + } + + /* Styles for the snippets */ + + .predictive-search-results__pill mark { + background-color: transparent; + font-weight: 200; + color: rgb(var(--color-foreground-rgb) / var(--opacity-80)); + } + + .predictive-search-results__pill:focus, + .predictive-search-results__pill:hover, + .predictive-search-results__card--query:is([aria-selected='true'], :focus-within) .predictive-search-results__pill { + --pill-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-8)); + + background-color: var(--pill-background-color); + outline: var(--border-width-sm) solid var(--color-border); + border: var(--border-width-sm); + text-decoration: none; + } + + .predictive-search-results__pill { + font-weight: 500; + white-space: nowrap; + color: var(--color-foreground); + } + + .predictive-search-results__title { + display: flex; + justify-content: space-between; + align-items: center; + font-size: var(--font-size--body-md); + font-weight: 500; + margin-block: var(--margin-sm) var(--margin-xs); + width: 100%; + text-transform: var(--title-case); + + &:first-of-type { + margin-block-start: 0; + } + + @media screen and (max-width: 749px) { + margin-block: var(--margin-lg) var(--margin-sm); + } + } + + .predictive-search-results__resource-header .predictive-search-results__title { + margin-block-end: 0; + } + + .predictive-search-results__resource-header:has(slideshow-controls) .predictive-search-results__title { + margin-block-end: 0; + } + + .predictive-search-results__wrapper { + display: flex; + overflow-x: auto; + overflow-y: hidden; + padding-block-end: var(--padding-sm); + padding-inline: 0; + scroll-snap-type: x mandatory; + scroll-padding: 0 var(--padding-xl); + scrollbar-width: none; + -ms-overflow-style: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .predictive-search-results__wrapper slideshow-slides { + --gutter-slide-width: var(--padding-xl); + + padding-block: var(--padding-3xs); + gap: var(--gap-md); + } + + .predictive-search-results__wrapper-products { + display: grid; + grid-template-columns: repeat(2, 1fr); + padding-block-end: var(--padding-sm); + gap: var(--gap-md); + transition: height var(--animation-speed-medium) var(--animation-easing); + + @container (min-width: 550px) { + grid-template-columns: repeat(4, 1fr); + } + } + + .predictive-search-results__wrapper-products:last-child { + padding-block-end: var(--padding-lg); + + @media screen and (min-width: 750px) { + padding-block-end: var(--padding-sm); + } + } + + .predictive-search-results__wrapper-queries { + margin-bottom: var(--margin-lg); + padding-inline: var(--padding-xl); + gap: var(--gap-2xs); + } + + .predictive-search-results__card { + flex: 0 0 auto; + scroll-snap-align: start; + scroll-margin-block: calc(var(--title-font-size) + var(--title-margin-block) + var(--padding-sm)) + calc(var(--padding-xl) + var(--button-padding-block) * 2); + transition: transform var(--animation-speed-medium) var(--animation-timing-default), + background-color var(--animation-speed-medium) var(--animation-timing-hover), + border-color var(--animation-speed-medium) var(--animation-timing-hover); + + &:nth-last-child(3) { + scroll-snap-align: end; + } + + &:active { + transform: scale(0.97); + transition: transform 100ms var(--animation-timing-active); + } + } + + .predictive-search-results__card--product, + .recently-viewed-wrapper .predictive-search-results__card--product { + &:hover { + background-color: var(--card-bg-hover); + border-radius: var(--product-corner-radius); + padding: calc(var(--padding-2xs) + 2px); + margin: calc((var(--padding-2xs) + 2px) * -1); + } + + &:is([aria-selected='true'].keyboard-focus, &:focus-visible, &:has(.resource-card:focus-visible)) { + background-color: var(--card-bg-hover); + padding: calc(var(--padding-2xs) + 1px); + margin: calc((var(--padding-2xs) + 1px) * -1); + outline: var(--border-width-sm) solid var(--color-border); + border-radius: calc(var(--product-corner-radius) + 1px); + border-color: var(--card-border-focus); + } + + &:active { + transform: scale(0.97); + transition: transform 100ms var(--animation-timing-active); + } + } + + .predictive-search-results__card:not(.predictive-search-results__card--product) { + padding: var(--padding-sm); + border: var(--border-width-sm) solid var(--color-border); + border-radius: var(--card-corner-radius); + width: 60cqi; + content-visibility: visible; + + @media screen and (min-width: 750px) { + width: 27.5cqi; + } + + &:hover { + border-color: var(--card-border-hover); + background-color: var(--card-bg-hover); + } + + &[aria-selected='true'].keyboard-focus { + border-color: var(--card-border-hover); + background-color: var(--card-bg-hover); + } + + &:active { + transform: scale(0.97); + transition: transform var(--animation-speed-medium) var(--animation-timing-active); + } + } + + @keyframes search-element-scale-in { + 0% { + transform: scale(0.95); + opacity: 0; + } + + 40% { + opacity: 1; + } + + 100% { + transform: scale(1); + opacity: 1; + } + } + + @keyframes search-element-scale-out { + 0% { + transform: scale(1); + opacity: 1; + } + + 100% { + transform: scale(0.95); + opacity: 0; + } + } + + @keyframes search-element-slide-in-top { + from { + margin-top: calc(var(--modal-top-margin) + var(--padding-sm)); + opacity: 0; + } + + to { + margin-top: var(--modal-top-margin); + opacity: 1; + } + } + + @keyframes search-element-slide-out-top { + from { + margin-top: var(--modal-top-margin); + opacity: 1; + } + + to { + margin-top: calc(var(--modal-top-margin) + var(--padding-sm)); + opacity: 0; + } + } + + @keyframes content-slide { + from { + transform: translateY(var(--slide-from, 0)); + opacity: var(--slide-opacity-from, 1); + } + + to { + transform: translateY(var(--slide-to, 0)); + opacity: var(--slide-opacity-to, 1); + } + } + + .recently-viewed-wrapper .predictive-search-results__card { + opacity: 1; + transform: translateY(0); + transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); + } + + .recently-viewed-wrapper.removing .predictive-search-results__card { + opacity: 0; + transform: translateY(-10px); + pointer-events: none; + } + + .predictive-search-results__resource-header slideshow-controls { + @media screen and (max-width: 749px) { + display: none; + } + } + + .predictive-search-results__list slideshow-arrows { + @media screen and (max-width: 749px) { + display: none; + } + } + + .predictive-search-dropdown .predictive-search-results__list-item-image, + .predictive-search-dropdown .predictive-search-results__list-item-icon { + width: 100%; + border-radius: var(--product-corner-radius); + background-color: rgb(var(--color-primary-rgb) / var(--opacity-20)); + margin: auto; + object-fit: cover; + } + + .predictive-search-results__list-item, + .predictive-search-results__no-results, + .predictive-search-results__wrapper, + .predictive-search-results__wrapper-products .predictive-search-results__card { + animation: search-element-slide-up var(--animation-speed-medium) var(--animation-timing-bounce) backwards; + } + + slideshow-slide .resource-card { + animation-delay: 0ms !important; + } + + .predictive-search-results__wrapper-products .predictive-search-results__card:nth-child(1) { + animation-delay: 30ms; + } + + .predictive-search-results__wrapper-products .predictive-search-results__card:nth-child(2) { + animation-delay: 60ms; + } + + .predictive-search-results__wrapper-products .predictive-search-results__card:nth-child(3) { + animation-delay: 90ms; + } + + .predictive-search-results__wrapper-products .predictive-search-results__card:nth-child(4) { + animation-delay: 120ms; + } + + .predictive-search-results__wrapper-products .predictive-search-results__card:nth-child(n + 5) { + animation-delay: 150ms; + } + + .predictive-search-results__list, + .predictive-search-results__wrapper { + animation-duration: var(--animation-speed-medium); + } + + .predictive-search-results__list-item { + animation-delay: calc(30ms * var(--nth-child, 1) + 50ms); + } + + .predictive-search-results__wrapper-queries { + animation-delay: 50ms; + } + + .predictive-search-results__wrapper-products { + animation-delay: 50ms; + } + + .predictive-search-results__list:nth-of-type(2) { + animation-delay: 150ms; + } + + .predictive-search-results__list:nth-of-type(3) { + animation-delay: 200ms; + } + + .predictive-search-results__list:nth-of-type(4) { + animation-delay: 250ms; + } + + [data-resource-type] { + animation-delay: 0ms !important; + } + + .predictive-search-results__no-results { + animation-delay: 100ms; + } + + .predictive-search-results__list-item.removing, + .predictive-search-results__no-results.removing, + .predictive-search-results__wrapper.removing { + animation: search-element-slide-down var(--animation-speed-medium) var(--animation-timing-fade-out) forwards; + } + + .predictive-search-results__card.removing { + animation: fadeOut var(--animation-speed-medium) var(--animation-timing-fade-out) forwards; + } + + .predictive-search-results__wrapper { + transition: opacity var(--animation-speed-medium) var(--animation-timing-fade-in); + } + + .predictive-search__reset-button { + transition: opacity var(--animation-speed-medium) var(--animation-timing-fade-out), + visibility var(--animation-speed-medium) var(--animation-timing-fade-out); + } + + .predictive-search-results__no-results { + transition: opacity var(--animation-speed-medium) var(--animation-timing-fade-in); + } + + @keyframes search-element-slide-up { + from { + opacity: 0; + transform: translateY(8px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } + + @keyframes search-element-slide-down { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(8px); + } + } + + .recently-viewed-wrapper { + display: grid; + grid-template-rows: auto auto; + max-height: 1000px; + opacity: 1; + overflow: visible; + transition: max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1); + transform-origin: top center; + transform: translateY(0); + } + + .recently-viewed-wrapper.removing { + max-height: 0; + opacity: 0; + transform: translateY(-10px); + transition: max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), + transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); + pointer-events: none; + } + + .recently-viewed-wrapper.removing .predictive-search-results__card { + transition: none; + transform: none; + opacity: 1; + } + + .recently-viewed-wrapper > * { + transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1); + } + + .predictive-search-results__clear.button-unstyled { + color: var(--color-foreground); + opacity: 0.5; + transition: opacity var(--animation-speed-medium) var(--animation-easing); + padding: 0; + margin-left: var(--margin-sm); + + &:hover { + opacity: 1; + } + } + + .search-input, + .search-input:is(:focus, :focus-visible, :focus-within), + .predictive-search-form__header *:is(:focus, :focus-visible) { + outline: none !important; + box-shadow: none !important; + } + + .predictive-search-form__header-inner:has(.search-input:is(:focus, :focus-visible)), + .predictive-search-form__header:focus-within, + .predictive-search-form__header-inner:focus-within { + outline: none !important; + box-shadow: none !important; + border-color: var(--color-border) !important; + } + + .predictive-search:has(.predictive-search-dropdown) .predictive-search-form__header-inner:focus-within { + border-top-color: transparent; + border-right-color: transparent; + border-left-color: transparent; + + @media screen and (max-width: 749px) { + border-bottom-color: transparent; + } + } + + .predictive-search-form__header { + border-radius: var(--style-border-radius-inputs); + border: var(--search-border-width) solid var(--color-border); + } + + .predictive-search-results__card--query { + transition: transform var(--animation-speed-medium) var(--animation-timing-bounce); + transform-origin: center; + + &:active { + transform: scale(0.97); + } + } + + .predictive-search-results__pill { + transition: background-color var(--animation-speed-medium) var(--animation-timing-hover), + box-shadow var(--animation-speed-medium) var(--animation-timing-bounce), + transform var(--animation-speed-medium) var(--animation-timing-bounce); + margin: 2px; + + &:hover { + transform: scale(1.03); + box-shadow: 0 2px 5px rgb(0 0 0 / var(--opacity-8)); + } + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.predictive_search", + "settings": [], + "blocks": [ + { + "type": "@theme" + } + ] +} +{% endschema %} diff --git a/sections/product-information.liquid b/sections/product-information.liquid new file mode 100644 index 000000000..3e463b8f1 --- /dev/null +++ b/sections/product-information.liquid @@ -0,0 +1,390 @@ +{% # import schema from '../schemas/sections/product-information' %} + +{% liquid + if section.settings.desktop_media_position == 'left' + assign render_order = 'media,product-details' + else + assign render_order = 'product-details,media' + endif + + assign product_has_media = true + if closest.product.media.size == 0 + assign product_has_media = false + endif + + assign product_grid_class = 'product-information__grid' + + if product_has_media == false + assign product_grid_class = product_grid_class | append: ' product-information--media-none' + elsif section.settings.desktop_media_position == 'right' + assign product_grid_class = product_grid_class | append: ' product-information--media-right' + else + assign product_grid_class = product_grid_class | append: ' product-information--media-left' + endif + + if section.settings.equal_columns + assign product_grid_class = product_grid_class | append: ' product-information__grid--half' + + if section.settings.limit_details_width + assign product_grid_class = product_grid_class | append: ' product-information__grid--limit-details' + endif + endif + + case section.settings.content_width + when 'content-center-aligned' + assign content_width = 'page-width' + when 'content-full-width' + assign content_width = 'full-width' + endcase +%} + + + +
    +
    + {% if section.settings.desktop_media_position == 'left' and product_has_media %} + {% assign product_href = '#ProductInformation-' | append: section.id %} + {% render 'skip-to-content-link', href: product_href, text: 'accessibility.skip_to_product_info' %} + {% endif %} +
    + {% assign render_order_array = render_order | split: ',' %} + {% capture media %} +
    + {%- content_for 'block', + type: '_product-media-gallery', + id: 'media-gallery', + closest.product: closest.product + -%} +
    + {% endcapture %} + + {% capture details %} + {% content_for 'block', + type: '_product-details', + id: 'product-details', + closest.product: closest.product + %} + {% endcapture %} + + {% for block in render_order_array %} + {% if block == 'media' and product_has_media %} + {{ media }} + {% elsif block == 'product-details' %} + {{ details }} + {% endif %} + {% endfor %} +
    + + {% content_for 'blocks' %} +
    + +{% stylesheet %} + .product-information { + gap: var(--gap) 0; + } + + /* Base grid layout */ + .product-information__grid { + display: grid; + grid-template-columns: subgrid; + grid-column: 1 / -1; + } + + /* Default column positions */ + .product-details { + order: 1; + } + + .product-information__media { + order: 0; + width: 0; + min-width: 100%; + } + + /* Mobile styles */ + @media screen and (max-width: 749px) { + .product-information__media { + grid-column: 1 / -1; + } + + .product-details { + grid-column: 2 / 3; + } + } + + /* Desktop styles */ + @media screen and (min-width: 750px) { + .product-information__grid { + grid-column: 2; + } + + /* Position when there is no media */ + .product-information__grid.product-information--media-none, + .product-information__grid:has(.product-information__media:empty) { + .product-details { + width: var(--narrow-content-width); + margin: 0 auto; + } + } + + /* Position when there is media */ + .product-information__grid:not(:has(.product-information__media:empty)) { + /* Media on the left side */ + &.product-information--media-left { + grid-template-columns: 1fr min(50vw, var(--sidebar-width)); + + .product-information__media { + padding-right: calc(var(--gap, 0) / 2); + } + + .product-details { + padding-left: calc(var(--gap, 0) / 2); + } + + &:has(.media-gallery--extend) { + grid-column: 1 / 3; + } + } + + /* Media on the right side */ + &.product-information--media-right { + grid-template-columns: min(50vw, var(--sidebar-width)) 1fr; + + .product-information__media { + padding-left: calc(var(--gap, 0) / 2); + order: 1; + } + + .product-details { + padding-right: calc(var(--gap, 0) / 2); + order: 0; + } + + &:has(.media-gallery--extend) { + grid-column: 2 / -1; + } + } + + /* Equal width columns */ + &.product-information__grid--half, + &.product-information__grid--half:has(.media-gallery--extend) { + grid-column: 1 / -1; + grid-template-columns: + var(--full-page-grid-margin) calc(var(--full-page-grid-central-column-width) / 2) calc( + var(--full-page-grid-central-column-width) / 2 + ) + var(--full-page-grid-margin); + + &.product-information--media-left { + .product-information__media { + grid-column: 2 / 3; + + &:has(.media-gallery--extend) { + grid-column: 1 / 3; + } + } + + .product-details { + grid-column: 3 / 4; + } + } + + &.product-information--media-right { + .product-information__media { + grid-column: 3 / 4; + + &:has(.media-gallery--extend) { + grid-column: 3 / -1; + } + } + + .product-details { + grid-column: 2 / 3; + } + } + } + } + + /* Handle full width section */ + .section--full-width { + .product-information__grid:not(:has(.product-information__media:empty)), + .product-information__grid:not(:has(.product-information__media:empty)) { + &.product-information--media-left, + &.product-information--media-right { + grid-column: 1 / -1; + } + + &.product-information--media-left .product-details { + padding-inline-end: var(--padding-lg); + } + + &.product-information--media-right .product-details { + padding-inline-start: var(--padding-lg); + } + + &.product-information__grid--half.product-information--media-left { + .product-information__media { + grid-column: 1 / 3; + } + + .product-details { + grid-column: 3 / -1; + } + } + + &.product-information__grid--half.product-information--media-right { + .product-information__media { + grid-column: 3 / -1; + } + + .product-details { + grid-column: 1 / 3; + } + } + } + } + } + + /* Wider sidebar for large screens */ + @media screen and (min-width: 1200px) { + .product-information__grid:not( + .product-information__grid--half, + :has(.product-information__media:empty) + ).product-information--media-left { + grid-template-columns: 2fr 1fr; + } + + .product-information__grid:not( + .product-information__grid--half, + :has(.product-information__media:empty) + ).product-information--media-right { + grid-template-columns: 1fr 2fr; + } + } + + .product-information__grid--limit-details .product-details > .group-block { + max-width: var(--sidebar-width); + } + + /* If the header is sticky, make product details content stick underneath the header */ + body:has(#header-group #header-component[data-sticky-state='active']) .product-details.sticky-content--desktop { + --sticky-header-offset: var(--header-height); + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_information", + "blocks": [ + { + "type": "@app" + } + ], + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_width", + "label": "t:settings.width", + "options": [ + { + "value": "content-center-aligned", + "label": "t:options.page" + }, + { + "value": "content-full-width", + "label": "t:options.full" + } + ], + "default": "content-center-aligned" + }, + { + "type": "select", + "id": "desktop_media_position", + "label": "t:settings.media_position", + "options": [ + { + "value": "left", + "label": "t:options.left" + }, + { + "value": "right", + "label": "t:options.right" + } + ], + "default": "left" + }, + { + "type": "checkbox", + "id": "equal_columns", + "label": "t:settings.equal_columns", + "default": false + }, + { + "type": "checkbox", + "id": "limit_details_width", + "label": "t:settings.limit_product_details_width", + "default": false, + "visible_if": "{{ section.settings.equal_columns }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 48, + "step": 4, + "unit": "px", + "default": 16 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [] +} +{% endschema %} diff --git a/sections/product-list.liquid b/sections/product-list.liquid new file mode 100644 index 000000000..5efd4e4ed --- /dev/null +++ b/sections/product-list.liquid @@ -0,0 +1,943 @@ +{% # import schema from '../schemas/sections/product-list.js' %} + +{% liquid + assign max_items = section.settings.max_products + + if section.settings.collection != blank and shop.products_count != 0 + assign section_products = section.settings.collection.products + assign max_items = section_products.size | at_most: section.settings.max_products + endif + + case section.settings.layout_type + when 'grid' + assign classes = 'resource-list--grid' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--resource-list-row-gap-desktop: ' | append: section.settings.rows_gap | append: 'px;' + echo '--resource-list-columns: repeat(' | append: section.settings.columns | append: ', 1fr);' + echo '--resource-list-columns-mobile: repeat(' | append: section.settings.mobile_columns | append: ', 1fr);' + endcapture + when 'carousel' + assign classes = 'resource-list__carousel' + capture styles + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--column-count: ' | append: section.settings.columns | append: ';' + echo '--column-count-mobile: ' | append: section.settings.mobile_columns | append: ';' + echo '--mobile-card-size: ' | append: section.settings.mobile_card_size | append: ';' + endcapture + endcase +%} + +
    +
    +
    + {%- content_for 'block', type: '_product-list-content', id: 'static-header' -%} +
    + + {% capture list_items %} + {% for i in (1..max_items) %} + {% if section_products.size > 0 %} + {% assign index = forloop.index0 %} + {% assign product = section_products[index] %} + {% else %} + {% assign product = null %} + {% endif %} +
    + {% content_for 'block', type: '_product-card', id: 'static-product-card', closest.product: product %} +
    + + {% unless forloop.last %} + + {% endunless %} + + {% endfor %} + {% endcapture %} + + {% liquid + # Create an array from the list items to be used for different layout types + assign list_items_array = list_items | strip | split: '' + %} + +
    + {% case section.settings.layout_type %} + {% when 'grid' %} + {{ list_items }} + {% when 'carousel' %} + {% render 'resource-list-carousel', + ref: 'resourceListCarousel', + slides: list_items_array, + slide_count: max_items, + settings: section.settings + %} + {% when 'editorial' %} + {% render 'editorial-product-grid', items: list_items_array %} + {% endcase %} +
    + + {% if section.settings.carousel_on_mobile and section.settings.layout_type != 'carousel' %} + {% liquid + assign mobile_carousel_gap = section.settings.columns_gap + %} +
    + {% render 'resource-list-carousel', + ref: 'resourceListCarouselMobile', + slides: list_items_array, + slide_count: max_items, + settings: section.settings + %} +
    + {% endif %} + +
    + {%- content_for 'blocks' -%} +
    +
    + +{% schema %} +{ + "name": "t:names.product_list", + "class": "ui-test-product-list", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "collection", + "id": "collection", + "label": "t:settings.collection" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.layout_type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + }, + { + "value": "editorial", + "label": "t:options.editorial" + } + ], + "default": "grid" + }, + { + "type": "checkbox", + "id": "carousel_on_mobile", + "label": "t:settings.carousel_on_mobile", + "default": false, + "visible_if": "{{ section.settings.layout_type != 'carousel' }}" + }, + { + "type": "range", + "id": "max_products", + "label": "t:settings.product_count", + "min": 1, + "max": 16, + "step": 1, + "default": 4 + }, + { + "type": "range", + "id": "columns", + "label": "t:settings.columns", + "min": 1, + "max": 8, + "step": 1, + "default": 4, + "visible_if": "{{ section.settings.layout_type != 'editorial' }}" + }, + { + "type": "select", + "id": "mobile_columns", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "1", + "label": "t:options.one_number" + }, + { + "value": "2", + "label": "t:options.two_number" + } + ], + "default": "2", + "visible_if": "{{ section.settings.layout_type == 'grid' and section.settings.carousel_on_mobile == false }}" + }, + { + "type": "select", + "id": "mobile_card_size", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "60cqw", + "label": "t:options.one_number" + }, + { + "value": "44cqw", + "label": "t:options.two_number" + } + ], + "default": "60cqw", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "range", + "id": "columns_gap", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "range", + "id": "rows_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8, + "visible_if": "{{ section.settings.layout_type == 'grid'}}" + }, + { + "type": "header", + "content": "t:content.carousel_navigation", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icon", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.arrows_large" + }, + { + "value": "chevron_large", + "label": "t:options.chevron_large" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrow", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_shape", + "label": "t:settings.icon_background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "none", + "visible_if": "{{ section.settings.icons_style != 'none' and section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.products_grid", + "category": "t:categories.products", + "settings": { + "collection": "", + "max_products": 8, + "layout_type": "grid", + "carousel_on_mobile": false, + "columns": 4, + "mobile_columns": "2", + "columns_gap": 8, + "rows_gap": 24, + "icons_style": "arrow", + "icons_shape": "none", + "section_width": "page-width", + "gap": 28, + "color_scheme": "scheme-1", + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "static-header": { + "type": "_product-list-content", + "name": "t:names.header", + "static": true, + "settings": { + "content_direction": "row", + "vertical_on_mobile": false, + "horizontal_alignment": "space-between", + "vertical_alignment": "flex-end", + "align_baseline": true, + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product_list_text": { + "type": "_product-list-text", + "name": "t:names.collection_title", + "settings": { + "text": "

    {{ closest.collection.title }}

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_list_button": { + "type": "_product-list-button", + "name": "t:names.product_list_button", + "settings": { + "label": "View all", + "open_in_new_tab": false, + "style_class": "link", + "width": "fit-content", + "custom_width": 100, + "width_mobile": "fit-content", + "custom_width_mobile": 100 + } + } + }, + "block_order": ["product_list_text", "product_list_button"] + }, + "static-product-card": { + "type": "_product-card", + "name": "t:names.product_card", + "static": true, + "settings": { + "product_card_gap": 4, + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "name": "t:names.product_card_media", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + }, + "block_order": [] + }, + { + "name": "t:names.products_carousel", + "category": "t:categories.products", + "settings": { + "collection": "", + "max_products": 6, + "layout_type": "carousel", + "carousel_on_mobile": false, + "columns": 4, + "mobile_columns": "2", + "columns_gap": 8, + "rows_gap": 24, + "icons_style": "arrow", + "icons_shape": "circle", + "section_width": "page-width", + "gap": 28, + "color_scheme": "scheme-1", + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "static-header": { + "type": "_product-list-content", + "name": "t:names.header", + "static": true, + "settings": { + "content_direction": "row", + "vertical_on_mobile": false, + "horizontal_alignment": "space-between", + "vertical_alignment": "flex-end", + "align_baseline": true, + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product_list_text": { + "type": "_product-list-text", + "name": "t:names.collection_title", + "settings": { + "text": "

    {{ closest.collection.title }}

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_list_button": { + "type": "_product-list-button", + "name": "t:names.product_list_button", + "settings": { + "label": "View all", + "open_in_new_tab": false, + "style_class": "link", + "width": "fit-content", + "custom_width": 100, + "width_mobile": "fit-content", + "custom_width_mobile": 100 + } + } + }, + "block_order": ["product_list_text", "product_list_button"] + }, + "static-product-card": { + "type": "_product-card", + "name": "t:names.product_card", + "static": true, + "settings": { + "product_card_gap": 4, + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "name": "t:names.product_card_media", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + }, + "block_order": [] + }, + { + "name": "t:names.products_editorial", + "category": "t:categories.products", + "settings": { + "collection": "", + "layout_type": "editorial", + "carousel_on_mobile": false, + "max_products": 4, + "columns": 4, + "mobile_columns": "2", + "columns_gap": 8, + "rows_gap": 24, + "icons_style": "arrow", + "icons_shape": "none", + "section_width": "page-width", + "horizontal_alignment": "flex-start", + "gap": 64, + "color_scheme": "scheme-1", + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "static-header": { + "type": "_product-list-content", + "name": "t:names.header", + "static": true, + "settings": { + "content_direction": "row", + "vertical_on_mobile": false, + "horizontal_alignment": "space-between", + "vertical_alignment": "flex-end", + "align_baseline": true, + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product_list_text": { + "type": "_product-list-text", + "name": "t:names.collection_title", + "settings": { + "text": "

    {{ closest.collection.title }}

    ", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_list_button": { + "type": "_product-list-button", + "name": "t:names.product_list_button", + "settings": { + "label": "View all", + "open_in_new_tab": false, + "style_class": "link", + "width": "fit-content", + "custom_width": 100, + "width_mobile": "fit-content", + "custom_width_mobile": 100 + } + } + }, + "block_order": ["product_list_text", "product_list_button"] + }, + "static-product-card": { + "type": "_product-card", + "name": "t:names.product_card", + "static": true, + "settings": { + "product_card_gap": 4, + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "name": "t:names.product_card_media", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + }, + "block_order": [] + } + ] +} +{% endschema %} diff --git a/sections/product-recommendations.liquid b/sections/product-recommendations.liquid new file mode 100644 index 000000000..590af721f --- /dev/null +++ b/sections/product-recommendations.liquid @@ -0,0 +1,561 @@ +{% # import schema from '../schemas/sections/product-recommendations.js' %} + + +{% liquid + case section.settings.layout_type + when 'grid' + assign classes = 'resource-list--grid' + when 'carousel' + assign classes = 'resource-list__carousel' + endcase + + capture styles + echo '--column-count-mobile: ' | append: section.settings.mobile_columns | append: ';' + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--resource-list-row-gap-desktop: ' | append: section.settings.rows_gap | append: 'px;' + echo '--resource-list-columns: repeat(' | append: section.settings.columns | append: ', 1fr);' + echo '--resource-list-columns-mobile: repeat(' | append: section.settings.mobile_columns | append: ', 1fr);' + echo '--resource-list-column-gap-desktop: ' | append: section.settings.columns_gap | append: 'px;' + echo '--column-count: ' | append: section.settings.columns | append: ';' + echo '--column-count-mobile: ' | append: section.settings.mobile_columns | append: ';' + endcapture +%} + + +
    +
    +
    + {% content_for 'blocks' %} +
    + + {%- if recommendations.performed or section.settings.product == blank -%} + {% liquid + if section.settings.product == blank + assign products = null + # Onboarding mode: Show placeholder products + for i in (1..section.settings.max_products) + assign products = products | append: ', ' + assign products = products | split: ',' + endfor + elsif recommendations.performed and recommendations.products_count == 0 + # No recommendations found, pull from catalog + if section.settings.recommendation_type == 'related' + assign products = collections.all.products | reject: 'id', section.settings.product.id + elsif section.settings.recommendation_type == 'complementary' + # Do not recommend the All collection as complementary products + assign products = null + endif + + else + assign products = recommendations.products + endif + %} + {% capture list_items %} + {% for product in products limit: section.settings.max_products %} +
    + {% content_for 'block', type: '_product-card', id: 'static-product-card', closest.product: product %} +
    + {% unless forloop.last %} + + {% endunless %} + {% endfor %} + {% endcapture %} + + {% liquid + # Create an array from the list items to be used in the carousel + assign slide_content = list_items | strip + assign slides = slide_content | split: '' + + if products != blank and products.size > 0 + assign has_recommendations = 'true' + else + assign has_recommendations = 'false' + endif + %} + +
    + {% case section.settings.layout_type %} + {% when 'grid' %} + {{ list_items }} + {% when 'carousel' %} + {% render 'resource-list-carousel', + ref: 'resourceListCarousel', + slides: slides, + slide_count: recommendations.products.size, + settings: section.settings + %} + {% endcase %} +
    + + {% if section.settings.carousel_on_mobile and section.settings.layout_type != 'carousel' %} + {% liquid + assign mobile_carousel_gap = section.settings.columns_gap + %} +
    + {% render 'resource-list-carousel', + ref: 'resourceListCarouselMobile', + slides: slides, + slide_count: recommendations.products.size, + settings: section.settings + %} +
    + {% endif %} + {%- else -%} +
    + {% for i in (1..section.settings.columns) %} +
    + {% endfor %} +
    + {%- endif -%} +
    +
    + +{% stylesheet %} + .product-recommendations__skeleton-item { + aspect-ratio: 3 / 4; + background-color: var(--color-foreground); + opacity: var(--skeleton-opacity); + border-radius: 4px; + } + + @media screen and (max-width: 749px) { + .product-recommendations__skeleton-item:nth-child(2n + 1) { + display: none; + } + } + + product-recommendations:has([data-has-recommendations='false']) { + display: none; + } +{% endstylesheet %} + +{% schema %} +{ + "name": "t:names.product_recommendations", + "disabled_on": { + "groups": ["header", "footer"] + }, + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "text" + }, + { + "type": "icon" + }, + { + "type": "image" + }, + { + "type": "button" + }, + { + "type": "video" + }, + { + "type": "group" + }, + { + "type": "spacer" + }, + { + "type": "_divider" + } + ], + "settings": [ + { + "type": "product", + "id": "product", + "label": "t:settings.product" + }, + { + "type": "select", + "id": "recommendation_type", + "label": "t:settings.type", + "options": [ + { + "value": "related", + "label": "t:options.related" + }, + { + "value": "complementary", + "label": "t:options.complementary" + } + ], + "default": "related" + }, + { + "type": "paragraph", + "content": "t:content.complementary_products" + }, + { + "type": "header", + "content": "t:content.cards_layout" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.layout_style", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "carousel", + "label": "t:options.carousel" + } + ], + "default": "grid" + }, + { + "type": "checkbox", + "id": "carousel_on_mobile", + "label": "t:settings.carousel_on_mobile", + "default": false, + "visible_if": "{{ section.settings.layout_type == 'grid' }}" + }, + { + "type": "range", + "id": "max_products", + "label": "t:settings.product_count", + "min": 3, + "max": 10, + "step": 1, + "default": 4 + }, + { + "type": "range", + "id": "columns", + "label": "t:settings.columns", + "min": 1, + "max": 8, + "step": 1, + "default": 4 + }, + { + "type": "select", + "id": "mobile_columns", + "label": "t:settings.mobile_columns", + "options": [ + { + "value": "1", + "label": "t:options.one_number" + }, + { + "value": "2", + "label": "t:options.two_number" + } + ], + "default": "2", + "visible_if": "{{ section.settings.layout_type == 'grid' and section.settings.carousel_on_mobile == false }}" + }, + { + "type": "range", + "id": "columns_gap", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16, + "visible_if": "{{ section.settings.layout_type == 'grid' or section.settings.layout_type == 'carousel' }}" + }, + { + "type": "range", + "id": "rows_gap", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 16, + "visible_if": "{{ section.settings.layout_type == 'grid' }}" + }, + { + "type": "header", + "content": "t:content.carousel_navigation", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_style", + "label": "t:settings.icon", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.arrows_large" + }, + { + "value": "chevron_large", + "label": "t:options.chevron_large" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrow", + "visible_if": "{{ section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "select", + "id": "icons_shape", + "label": "t:settings.icon_background", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "circle", + "label": "t:options.circle" + }, + { + "value": "square", + "label": "t:options.square" + } + ], + "default": "none", + "visible_if": "{{ section.settings.icons_style != 'none' and section.settings.layout_type == 'carousel' or section.settings.carousel_on_mobile == true }}" + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.product_recommendations", + "category": "t:categories.products", + "settings": { + "product": "{{ closest.product }}", + "recommendation_type": "related", + "layout_type": "grid", + "carousel_on_mobile": false, + "max_products": 4, + "columns": 4, + "mobile_columns": "2", + "columns_gap": 12, + "rows_gap": 24, + "icons_style": "arrow", + "icons_shape": "none", + "section_width": "page-width", + "gap": 28, + "color_scheme": "scheme-1", + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "header": { + "type": "text", + "name": "t:names.header", + "settings": { + "text": "

    Related products

    " + } + }, + "static-product-card": { + "type": "_product-card", + "name": "t:names.product_card", + "static": true, + "settings": { + "product_card_gap": 4 + }, + "blocks": { + "product-card-gallery": { + "type": "_product-card-gallery", + "name": "t:names.product_card_media", + "settings": { + "image_ratio": "adapt", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "product_title": { + "type": "product-title", + "name": "t:names.product_title", + "settings": { + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "color": "var(--color-foreground)", + "background": false, + "background_color": "#00000026", + "corner_radius": 0, + "padding-block-start": 4, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "price": { + "type": "price", + "name": "t:names.product_price", + "settings": { + "show_sale_price_first": true, + "show_installments": false, + "show_tax_info": false, + "type_preset": "h6", + "width": "100%", + "alignment": "left", + "font": "var(--font-body--family)", + "font_size": "1rem", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "color": "var(--color-foreground)", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["product-card-gallery", "product_title", "price"] + } + }, + "block_order": ["header"] + } + ] +} +{% endschema %} diff --git a/sections/search-header.liquid b/sections/search-header.liquid new file mode 100644 index 000000000..3a6d0e2ff --- /dev/null +++ b/sections/search-header.liquid @@ -0,0 +1,83 @@ +{% # import schema from '../schemas/sections/search-header.js' %} + +
    +
    +
    + {% assign heading_text = 'content.search' | t %} + + {% if search.performed %} + {% assign heading_text = 'content.search_results' | t %} + {% endif %} + + {% capture heading_text %} +

    {{ heading_text }}

    + {% endcapture %} + + {% content_for 'block', id: 'heading', type: '_heading', text: heading_text %} + {% content_for 'block', id: 'search', type: '_search-input' %} +
    +
    + +{% schema %} +{ + "name": "t:names.search", + "settings": [ + { + "type": "select", + "id": "alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ] +} +{% endschema %} diff --git a/sections/search-results.liquid b/sections/search-results.liquid new file mode 100644 index 000000000..0097bcaff --- /dev/null +++ b/sections/search-results.liquid @@ -0,0 +1,221 @@ +{% # import schema from '../schemas/sections/search-results.js' %} + + + +
    + + {% render 'skip-to-content-link', href: '#ResultsList', text: 'accessibility.skip_to_results_list' %} + +
    + {% paginate search.results by 24 %} + {% if search.results_count > 0 %} + {% content_for 'block', type: 'filters', id: 'filters', results: search, results_size: search.results_count %} + {% assign products = search.results | where: 'object_type', 'product' %} + {% else %} + {% assign collection = settings.empty_state_collection | default: collections.all %} + {% assign default_title = 'content.search_results_resource_products' | t %} + {% assign title = settings.empty_state_collection.title | default: default_title %} + {% assign products = collection.products %} + {% endif %} + + {% capture children %} + {% for product in products %} +
  • + {% content_for 'block', type: '_product-card', id: 'product-card', closest.product: product %} +
  • + {% endfor %} + {% endcapture %} + + {% render 'product-grid', + section: section, + children: children, + products: products, + paginate: paginate, + title: title + %} + {% endpaginate %} +
    +
    + +{% schema %} +{ + "name": "t:names.search_results", + "settings": [ + { + "type": "paragraph", + "content": "t:content.edit_empty_state_collection_in_theme_settings" + }, + { + "type": "select", + "id": "layout_type", + "label": "t:settings.type", + "options": [ + { + "value": "grid", + "label": "t:options.grid" + }, + { + "value": "organic", + "label": "t:options.editorial" + } + ], + "default": "grid" + }, + { + "type": "select", + "id": "product_card_size", + "label": "t:settings.card_size", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "extra-large", + "label": "t:options.extra_large" + } + ], + "default": "medium", + "visible_if": "{{ section.settings.layout_type == 'grid' }}" + }, + { + "type": "select", + "id": "mobile_product_card_size", + "label": "t:settings.mobile_card_size", + "options": [ + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "large", + "label": "t:options.large" + } + ], + "default": "small" + }, + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "product_grid_width", + "label": "t:settings.width", + "options": [ + { + "value": "centered", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "centered" + }, + { + "type": "checkbox", + "id": "full_width_on_mobile", + "label": "t:settings.full_width_on_mobile", + "default": true, + "visible_if": "{{ section.settings.product_grid_width != 'full-width' }}" + }, + { + "type": "range", + "id": "columns_gap_horizontal", + "label": "t:settings.horizontal_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "columns_gap_vertical", + "label": "t:settings.vertical_gap", + "min": 0, + "max": 50, + "step": 1, + "unit": "px", + "default": 16 + }, + { + "type": "range", + "id": "padding-inline-start", + "label": "t:settings.left_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-inline-end", + "label": "t:settings.right_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "header", + "content": "t:content.section_layout" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom_padding", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 8 + } + ], + "presets": [] +} +{% endschema %} diff --git a/sections/section-rendering-product-card.liquid b/sections/section-rendering-product-card.liquid new file mode 100644 index 000000000..eea8cce91 --- /dev/null +++ b/sections/section-rendering-product-card.liquid @@ -0,0 +1,63 @@ +{% # import schema from '../schemas/sections/section-rendering-product-card.js' %} + +{% liquid + if product == blank + assign product = closest.product + endif + + if settings.transition_to_main_product + assign featured_media_url = product.selected_or_first_available_variant.featured_image | image_url: width: 500 + if featured_media_url == blank + assign featured_media_url = product.featured_media.preview_image | image_url: width: 500 + endif + endif + + assign url = product.selected_or_first_available_variant.url + unless url + assign url = product.first_available_variant.url + endunless + unless url + assign url = product.url + endunless +%} + +{%- if settings.transition_to_main_product -%} + +{%- endif -%} + + + + {% render 'variant-quick-add', product_resource: product %} + {% render 'variant-swatches', product_resource: product, has_option_selected: true %} + + + {% render 'price', product_resource: product, show_unit_price: true %} + + + +{%- if settings.transition_to_main_product -%} + +{%- endif -%} + +{% schema %} +{ + "name": "t:names.product_card_rendering", + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "product", + "id": "product", + "label": "t:settings.product" + } + ] +} +{% endschema %} diff --git a/sections/section.liquid b/sections/section.liquid new file mode 100644 index 000000000..552adc6f5 --- /dev/null +++ b/sections/section.liquid @@ -0,0 +1,1326 @@ +{% # import schema from '../schemas/sections/section' %} + +{% capture children %} + {% content_for 'blocks' %} +{% endcapture %} + +{% render 'section', section: section, children: children %} + +{% schema %} +{ + "name": "t:names.section", + "class": "section-wrapper", + "blocks": [ + { + "type": "@theme" + }, + { + "type": "@app" + }, + { + "type": "_divider" + } + ], + "disabled_on": { + "groups": ["header"] + }, + "settings": [ + { + "type": "header", + "content": "t:content.layout" + }, + { + "type": "select", + "id": "content_direction", + "label": "t:settings.direction", + "options": [ + { + "value": "column", + "label": "t:options.vertical" + }, + { + "value": "row", + "label": "t:options.horizontal" + } + ], + "default": "column" + }, + { + "type": "checkbox", + "id": "vertical_on_mobile", + "label": "t:settings.vertical_on_mobile", + "default": true, + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "horizontal_alignment", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'row' }}" + }, + { + "type": "checkbox", + "id": "align_baseline", + "label": "t:settings.align_baseline", + "default": false, + "visible_if": "{{ section.settings.vertical_alignment == 'flex-end' }}" + }, + { + "type": "select", + "id": "horizontal_alignment_flex_direction_column", + "label": "t:settings.alignment", + "options": [ + { + "value": "flex-start", + "label": "t:options.left" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.right" + } + ], + "default": "flex-start", + "visible_if": "{{ section.settings.content_direction != 'row' }}" + }, + { + "type": "select", + "id": "vertical_alignment_flex_direction_column", + "label": "t:settings.position", + "options": [ + { + "value": "flex-start", + "label": "t:options.top" + }, + { + "value": "center", + "label": "t:options.center" + }, + { + "value": "flex-end", + "label": "t:options.bottom" + }, + { + "value": "space-between", + "label": "t:options.space_between" + } + ], + "default": "center", + "visible_if": "{{ section.settings.content_direction == 'column' }}" + }, + { + "type": "range", + "id": "gap", + "label": "t:settings.gap", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 12 + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "page-width" + }, + { + "type": "select", + "id": "section_height", + "label": "t:settings.height", + "options": [ + { + "value": "", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + }, + { + "value": "full-screen", + "label": "t:options.full_screen" + }, + { + "value": "custom", + "label": "t:options.custom" + } + ], + "default": "" + }, + { + "type": "range", + "id": "section_height_custom", + "label": "t:settings.custom_height", + "min": 0, + "max": 100, + "step": 1, + "default": 50, + "unit": "%", + "visible_if": "{{ section.settings.section_height == 'custom' }}" + }, + { + "type": "header", + "content": "t:content.appearance" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "scheme-1" + }, + { + "type": "select", + "id": "background_media", + "label": "t:settings.background_media", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "image", + "label": "t:options.image" + }, + { + "value": "video", + "label": "t:options.video" + } + ], + "default": "none" + }, + { + "type": "video", + "id": "video", + "label": "t:settings.video", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "select", + "id": "video_position", + "label": "t:settings.video_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "contain", + "label": "t:options.contain" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'video' }}" + }, + { + "type": "image_picker", + "id": "background_image", + "label": "t:settings.image", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "background_image_position", + "label": "t:settings.image_position", + "options": [ + { + "value": "cover", + "label": "t:options.cover" + }, + { + "value": "fit", + "label": "t:options.fit" + } + ], + "default": "cover", + "visible_if": "{{ section.settings.background_media == 'image' }}" + }, + { + "type": "select", + "id": "border", + "label": "t:settings.borders", + "options": [ + { + "value": "none", + "label": "t:options.none" + }, + { + "value": "solid", + "label": "t:options.solid" + } + ], + "default": "none" + }, + { + "type": "range", + "id": "border_width", + "min": 0, + "max": 10, + "step": 0.5, + "unit": "px", + "label": "t:settings.border_width", + "default": 1, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_opacity", + "min": 0, + "max": 100, + "step": 1, + "unit": "%", + "label": "t:settings.border_opacity", + "default": 100, + "visible_if": "{{ section.settings.border != 'none' }}" + }, + { + "type": "range", + "id": "border_radius", + "label": "t:settings.border_radius", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "checkbox", + "id": "toggle_overlay", + "label": "t:settings.background_overlay" + }, + { + "type": "color", + "id": "overlay_color", + "label": "t:settings.overlay_color", + "alpha": true, + "default": "#00000026", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "overlay_style", + "label": "t:settings.overlay_style", + "options": [ + { + "value": "solid", + "label": "t:options.solid" + }, + { + "value": "gradient", + "label": "t:options.gradient" + } + ], + "default": "solid", + "visible_if": "{{ section.settings.toggle_overlay }}" + }, + { + "type": "select", + "id": "gradient_direction", + "label": "t:settings.gradient_direction", + "options": [ + { + "value": "to top", + "label": "t:options.up" + }, + { + "value": "to bottom", + "label": "t:options.down" + } + ], + "default": "to top", + "visible_if": "{{ section.settings.toggle_overlay and section.settings.overlay_style == 'gradient' }}" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.custom_section", + "category": "t:categories.layout", + "settings": { + "section_height": "small" + } + }, + { + "name": "t:names.faq_section", + "category": "t:categories.storytelling", + "blocks": { + "text": { + "type": "text", + "name": "t:names.heading", + "settings": { + "text": "

    Frequently asked questions

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "narrow", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "accordion": { + "type": "accordion", + "name": "t:names.accordion", + "settings": { + "icon": "caret", + "dividers": true, + "type_preset": "h5", + "inherit_color_scheme": true, + "color_scheme": "", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "accordion_row_1": { + "type": "_accordion-row", + "settings": { + "heading": "What is the return policy?" + }, + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    Our goal is for every customer to be totally satisfied with their purchase. If this isn’t the case, let us know and we’ll do our best to work with you to make it right.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text"] + }, + "accordion_row_2": { + "type": "_accordion-row", + "settings": { + "heading": "Are any purchases final sale?" + }, + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    We are unable to accept returns on certain items. These will be carefully marked before purchase.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text"] + }, + "accordion_row_3": { + "type": "_accordion-row", + "name": "t:names.accordion_dash_row", + "settings": { + "heading": "When will I get my order?" + }, + "blocks": { + "text": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

    We will work quickly to ship your order as soon as possible. Once your order has shipped, you will receive an email with further information. Delivery times vary depending on your location.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text"] + }, + "accordion_row_4": { + "type": "_accordion-row", + "name": "t:names.accordion_dash_row", + "settings": { + "heading": "Where are your products manufactured?" + }, + "blocks": { + "text": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

    Our products are manufactured both locally and globally. We carefully select our manufacturing partners to ensure our products are high quality and a fair value.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text"] + }, + "accordion_row_5": { + "type": "_accordion-row", + "name": "t:names.accordion_dash_row", + "settings": { + "heading": "How much does shipping cost?" + }, + "blocks": { + "text": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

    Shipping is calculated based on your location and the items in your order. You will always know the shipping price before you purchase.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + } + }, + "block_order": ["text"] + } + }, + "block_order": ["accordion_row_1", "accordion_row_2", "accordion_row_3", "accordion_row_4", "accordion_row_5"] + } + }, + "block_order": ["text", "accordion"], + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 32, + "section_width": "page-width", + "section_height": "", + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 48, + "padding-block-end": 48 + } + }, + { + "name": "t:names.video_section", + "category": "t:categories.storytelling", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 16, + "section_width": "page-width", + "section_height": "", + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 32, + "padding-block-end": 32 + }, + "blocks": { + "video": { + "type": "video", + "name": "t:names.video", + "settings": { + "video": "", + "custom_width": 100, + "custom_width_mobile": 100, + "aspect_ratio": "16/9", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "group": { + "type": "group", + "name": "Caption", + "settings": { + "content_direction": "row", + "vertical_on_mobile": true, + "horizontal_alignment": "space-between", + "vertical_alignment": "flex-end", + "align_baseline": true, + "horizontal_alignment_flex_direction_column": "flex-start", + "vertical_alignment_flex_direction_column": "center", + "gap": 12, + "width": "fill", + "custom_width": 100, + "width_mobile": "fill", + "custom_width_mobile": 100, + "height": "fit", + "custom_height": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "text": { + "type": "text", + "name": "t:names.text", + "settings": { + "text": "

    Take a look behind the scenes of our latest product launch.

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "fit-content", + "max_width": "normal", + "alignment": "left", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + } + }, + "button": { + "type": "button", + "name": "t:names.button", + "settings": { + "label": "Discover the collection", + "link": "shopify://collections/all", + "open_in_new_tab": false, + "style_class": "link", + "width": "fit-content", + "custom_width": 100, + "width_mobile": "fit-content", + "custom_width_mobile": 100 + } + } + }, + "block_order": ["text", "button"] + } + }, + "block_order": ["video", "group"] + }, + { + "name": "t:names.pull_quote", + "category": "t:categories.storytelling", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    At the heart of every product lies a unique story, driven by our passion for quality and innovation. Each item enhances your everyday life and sparks joy.

    ", + "type_preset": "h2", + "width": "100%", + "max_width": "narrow", + "alignment": "center" + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all", + "style_class": "link" + } + } + }, + "block_order": ["text", "button"], + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "gap": 16, + "padding-block-start": 64, + "padding-block-end": 64 + } + }, + { + "name": "t:names.contact_form", + "category": "t:categories.forms", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    Contact us

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + }, + "contact_form": { + "type": "contact-form", + "settings": { + "width": "custom", + "custom_width": 50, + "width_mobile": "custom", + "custom_width_mobile": 100, + "inherit_color_scheme": true, + "color_scheme": "", + "padding-block-start": 0, + "padding-block-end": 0, + "padding-inline-start": 0, + "padding-inline-end": 0 + }, + "blocks": { + "submit-button": { + "type": "contact-form-submit-button", + "static": true, + "settings": { + "label": "Submit", + "style_class": "button", + "width": "fit-content", + "custom_width": 100, + "width_mobile": "fit-content", + "custom_width_mobile": 100 + } + } + }, + "block_order": [] + } + }, + "block_order": ["text", "contact_form"], + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "center", + "gap": 32, + "section_width": "page-width", + "section_height": "", + "color_scheme": "scheme-1", + "background_media": "none", + "video_position": "cover", + "background_image_position": "cover", + "border": "none", + "border_width": 1, + "border_opacity": 100, + "border_radius": 0, + "padding-block-start": 32, + "padding-block-end": 32 + } + }, + { + "name": "t:names.email_signup", + "category": "t:categories.forms", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "gap": 16, + "color_scheme": "scheme-2", + "padding-block-start": 40, + "padding-block-end": 40 + }, + "blocks": { + "text_1": { + "type": "text", + "name": "t:names.heading", + "settings": { + "text": "

    Subscribe to our emails

    ", + "width": "100%", + "alignment": "center" + } + }, + "text_2": { + "type": "text", + "settings": { + "text": "

    Be the first to know about new collections and special offers.

    ", + "type_preset": "paragraph", + "width": "100%", + "alignment": "center" + } + }, + "email_signup": { + "type": "email-signup", + "settings": { + "width": "custom", + "custom_width": 50, + "style_class": "button-unstyled", + "display_type": "arrow", + "label": "Sign Up", + "integrated_button": true + } + } + }, + "block_order": ["text_1", "text_2", "email_signup"] + }, + { + "name": "t:names.icons_with_text", + "category": "t:categories.storytelling", + "blocks": { + "group_1": { + "type": "group", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "center", + "gap": 16, + "height": "fit", + "inherit_color_scheme": true + }, + "blocks": { + "icon": { + "type": "icon", + "settings": { + "icon": "eye", + "width": 32, + "link": "" + } + }, + "group": { + "type": "group", + "settings": { + "gap": 4 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

    Intentional design

    ", + "type_preset": "h3", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Everything we do starts with why

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + } + }, + "block_order": ["heading", "text"] + } + }, + "block_order": ["icon", "group"] + }, + "group_2": { + "type": "group", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "center", + "gap": 16, + "height": "fit", + "inherit_color_scheme": true + }, + "blocks": { + "icon": { + "type": "icon", + "settings": { + "icon": "heart", + "width": 32, + "link": "" + } + }, + "group": { + "type": "group", + "settings": { + "gap": 4 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

    Made with care

    ", + "type_preset": "h3", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    We believe in building better

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + } + }, + "block_order": ["heading", "text"] + } + }, + "block_order": ["icon", "group"] + }, + "group_3": { + "type": "group", + "settings": { + "content_direction": "column", + "vertical_on_mobile": true, + "horizontal_alignment": "flex-start", + "vertical_alignment": "center", + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "center", + "gap": 16, + "height": "fit", + "inherit_color_scheme": true + }, + "blocks": { + "icon": { + "type": "icon", + "settings": { + "icon": "silhouette", + "width": 32, + "link": "" + } + }, + "group": { + "type": "group", + "settings": { + "gap": 4 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

    A team with a goal

    ", + "type_preset": "h3", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Real people making great products

    ", + "type_preset": "rte", + "font": "var(--font-body--family)", + "font_size": "", + "line_height": "normal", + "letter_spacing": "normal", + "case": "none", + "wrap": "pretty", + "width": "100%", + "max_width": "normal", + "alignment": "center", + "padding-block-start": 0, + "padding-block-end": 0 + } + } + }, + "block_order": ["heading", "text"] + } + }, + "block_order": ["icon", "group"] + } + }, + "block_order": ["group_1", "group_2", "group_3"], + "settings": { + "content_direction": "row", + "vertical_on_mobile": true, + "gap": 16, + "section_width": "page-width", + "padding-block-start": 48, + "padding-block-end": 48 + } + }, + { + "name": "t:names.split_showcase", + "category": "t:categories.banners", + "blocks": { + "group_1": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "space-between", + "gap": 32, + "inherit_color_scheme": false, + "color_scheme": "scheme-5", + "background_media": "image", + "placeholder": "hero-apparel-2", + "height": "fill", + "padding-block-start": 40, + "padding-block-end": 40, + "padding-inline-start": 40, + "padding-inline-end": 40 + }, + "blocks": { + "spacer": { + "type": "spacer", + "settings": { + "size": "pixel", + "pixel_size": 16 + } + }, + "text_1": { + "type": "text", + "settings": { + "text": "

    New arrivals

    ", + "type_preset": "h3", + "width": "fit-content", + "alignment": "center" + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all", + "style_class": "link" + } + } + }, + "block_order": ["spacer", "text_1", "button"] + }, + "group_2": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "vertical_alignment_flex_direction_column": "space-between", + "gap": 32, + "inherit_color_scheme": false, + "color_scheme": "scheme-5", + "background_media": "image", + "placeholder": "hero-apparel-1", + "height": "fill", + "padding-block-start": 40, + "padding-block-end": 40, + "padding-inline-start": 40, + "padding-inline-end": 40 + }, + "blocks": { + "spacer": { + "type": "spacer", + "settings": { + "size": "pixel", + "pixel_size": 16 + } + }, + "text_1": { + "type": "text", + "settings": { + "text": "

    Bestsellers

    ", + "type_preset": "h3", + "width": "fit-content", + "alignment": "center" + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all", + "style_class": "link" + } + } + }, + "block_order": ["spacer", "text_1", "button"] + } + }, + "block_order": ["group_1", "group_2"], + "settings": { + "content_direction": "row", + "vertical_on_mobile": true, + "gap": 0, + "section_width": "full-width", + "section_height": "large" + } + }, + { + "name": "t:names.image_with_text", + "category": "t:categories.storytelling", + "settings": { + "content_direction": "row", + "gap": 32, + "padding-block-start": 40, + "padding-block-end": 40 + }, + "blocks": { + "image": { + "type": "image", + "settings": { + "image": "", + "image_ratio": "square" + } + }, + "group": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "flex-start", + "width": "custom" + }, + "blocks": { + "heading": { + "type": "text", + "name": "t:names.heading", + "settings": { + "text": "

    Our signature product.

    ", + "type_preset": "h3" + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Made with care and unconditionally loved by our customers, this signature bestseller exceeds all expectations.

    ", + "max_width": "narrow" + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["heading", "text", "button"] + } + }, + "block_order": ["image", "group"] + }, + { + "name": "t:names.large_logo", + "category": "t:categories.banners", + "blocks": { + "text": { + "type": "text", + "settings": { + "text": "

    Made with care and unconditionally loved by our customers, this signature bestseller exceeds all expectations.

    ", + "max_width": "narrow" + } + }, + "logo": { + "type": "logo", + "settings": { + "unit": "percent", + "percent_width": 100 + } + } + }, + "block_order": ["text", "logo"], + "settings": { + "vertical_alignment_flex_direction_column": "space-between", + "gap": 16, + "section_height": "medium", + "color_scheme": "scheme-3", + "padding-block-start": 40, + "padding-block-end": 40 + } + } + ] +} +{% endschema %} diff --git a/sections/slideshow.liquid b/sections/slideshow.liquid new file mode 100644 index 000000000..10a9ccee9 --- /dev/null +++ b/sections/slideshow.liquid @@ -0,0 +1,306 @@ +{% # import schema from '../schemas/sections/slideshow.js' %} + +{% if section.blocks.size > 1 %} + {% capture controls %} + {%- render 'slideshow-controls', + style: section.settings.slideshow_controls_style, + autoplay: section.settings.autoplay, + item_count: section.blocks.size, + show_arrows: false, + arrows_on_media: true, + controls_on_media: true, + pagination_position: 'center', + icon_style: section.settings.icons_style + -%} + {% endcapture %} +{% endif %} + +{% capture slides %} + {% content_for 'blocks' %} +{% endcapture %} + +{% liquid + assign slideshow_class = 'slideshow--single-media' + if section.blocks.size > 1 + assign slideshow_class = '' + endif + + assign show_arrows = true + if section.settings.icons_style == 'none' or section.blocks.size <= 1 + assign show_arrows = false + endif +%} + +
    + {% render 'slideshow', + class: slideshow_class, + controls: controls, + show_arrows: show_arrows, + icon_style: section.settings.icons_style, + autoplay: section.settings.autoplay, + autoplay_speed: section.settings.autoplay_speed, + slides: slides, + slide_count: section.blocks.size, + slide_size: section.settings.slide_height + %} +
    + +{% schema %} +{ + "name": "t:names.slideshow", + "class": "container-background-image", + "blocks": [ + { + "type": "_slide" + } + ], + "disabled_on": { + "groups": ["header", "footer"] + }, + "settings": [ + { + "type": "select", + "id": "icons_style", + "label": "t:settings.navigation", + "options": [ + { + "value": "arrow", + "label": "t:options.arrows" + }, + { + "value": "chevron", + "label": "t:options.chevrons" + }, + { + "value": "arrows_large", + "label": "t:options.large_arrows" + }, + { + "value": "chevron_large", + "label": "t:options.large_chevrons" + }, + { + "value": "none", + "label": "t:options.none" + } + ], + "default": "arrows_large" + }, + { + "type": "select", + "id": "slideshow_controls_style", + "label": "t:settings.pagination", + "options": [ + { + "value": "dots", + "label": "t:options.dots" + }, + { + "value": "counter", + "label": "t:options.counter" + } + ], + "default": "dots" + }, + { + "type": "color_scheme", + "id": "color_scheme", + "label": "t:settings.color_scheme", + "default": "primary" + }, + { + "type": "checkbox", + "id": "autoplay", + "label": "t:settings.auto_rotate_slides", + "default": false + }, + { + "type": "range", + "id": "autoplay_speed", + "label": "t:settings.speed", + "min": 3, + "max": 7, + "step": 1, + "unit": "s", + "default": 4, + "visible_if": "{{ section.settings.autoplay }}" + }, + { + "type": "header", + "content": "t:content.size" + }, + { + "type": "select", + "id": "section_width", + "label": "t:settings.width", + "options": [ + { + "value": "page-width", + "label": "t:options.page" + }, + { + "value": "full-width", + "label": "t:options.full" + } + ], + "default": "full-width" + }, + { + "type": "select", + "id": "slide_height", + "options": [ + { + "value": "auto", + "label": "t:options.auto" + }, + { + "value": "small", + "label": "t:options.small" + }, + { + "value": "medium", + "label": "t:options.medium" + }, + { + "value": "large", + "label": "t:options.large" + } + ], + "default": "medium", + "label": "t:settings.height" + }, + { + "type": "header", + "content": "t:content.padding" + }, + { + "type": "range", + "id": "padding-block-start", + "label": "t:settings.top", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + }, + { + "type": "range", + "id": "padding-block-end", + "label": "t:settings.bottom", + "min": 0, + "max": 100, + "step": 1, + "unit": "px", + "default": 0 + } + ], + "presets": [ + { + "name": "t:names.slideshow", + "category": "t:categories.storytelling", + "blocks": { + "slide_1": { + "type": "_slide", + "settings": { + "horizontal_alignment_flex_direction_column": "center" + }, + "blocks": { + "group": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "width": "custom", + "custom_width": 50, + "width_mobile": "custom", + "inherit_color_scheme": false, + "color_scheme": "scheme-6", + "custom_width_mobile": 85, + "padding-inline-start": 48, + "padding-inline-end": 48, + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

    New arrivals

    " + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Introducing our latest products, made especially for the season. Shop your favorites before they're gone!

    ", + "padding-block-end": 20 + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["heading", "text", "button"] + } + }, + "block_order": ["group"] + }, + "slide_2": { + "type": "_slide", + "settings": { + "horizontal_alignment_flex_direction_column": "center" + }, + "blocks": { + "group": { + "type": "group", + "settings": { + "horizontal_alignment_flex_direction_column": "center", + "width": "custom", + "custom_width": 50, + "width_mobile": "custom", + "inherit_color_scheme": false, + "color_scheme": "scheme-6", + "custom_width_mobile": 85, + "padding-inline-start": 48, + "padding-inline-end": 48, + "padding-block-start": 48, + "padding-block-end": 48 + }, + "blocks": { + "heading": { + "type": "text", + "settings": { + "text": "

    Bestsellers

    " + } + }, + "text": { + "type": "text", + "settings": { + "text": "

    Discover the bestsellers that have captured the hearts of our customers with their perfect blend of functionality and style.

    ", + "padding-block-end": 20 + } + }, + "button": { + "type": "button", + "settings": { + "label": "Shop now", + "link": "shopify://collections/all" + } + } + }, + "block_order": ["heading", "text", "button"] + } + }, + "block_order": ["group"] + } + }, + "block_order": ["slide_1", "slide_2"] + } + ] +} +{% endschema %} diff --git a/snippets/account-actions.liquid b/snippets/account-actions.liquid new file mode 100644 index 000000000..803f80f34 --- /dev/null +++ b/snippets/account-actions.liquid @@ -0,0 +1,194 @@ + + +{% stylesheet %} + .account-actions { + background-color: var(--color-background); + display: flex; + flex-direction: column; + position: relative; + transition: height var(--animation-values); + + &:has([data-active]) .account-actions__main-menu { + visibility: hidden; + } + } + + .account-actions__header { + padding: var(--padding-xl); + display: flex; + flex-direction: column; + gap: var(--gap-2xs); + } + + .account-actions__title { + /* Ideally we set the font-size here, but specificity issues make this necessary */ + --font-h5--size: var(--font-size--lg); + + margin: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .account-actions__email { + display: flex; + align-items: center; + gap: var(--gap-2xs); + color: rgb(var(--color-foreground-rgb) / var(--opacity-60)); + max-width: var(--account-actions-max-width); + word-break: break-all; + } + + .account-actions__sign-ins { + padding: var(--padding-xl); + padding-block-start: 0; + padding-block-end: var(--padding-md); + display: flex; + flex-direction: column; + gap: var(--gap-sm); + } + + .account-actions__sign-in-text { + display: inline; + } + + .account-actions__fallback-text { + display: none; + } + + .account-actions__sign-ins:not(:has(shop-login-button)) { + gap: 0; + + .account-actions__sign-in-text { + display: none; + } + + .account-actions__fallback-text { + display: block; + } + } + + /* Makes the shop login button radius match the theme settings */ + .account-actions__shop-login { + --buttons-radius: var(--style-border-radius-buttons-primary); + } + + .account-actions__nav { + padding: var(--padding-xl); + padding-block-start: 0; + } + + .account-actions__list { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--gap-sm); + width: 100%; + list-style: none; + margin: 0; + padding: 0; + + @media screen and (max-width: 300px) { + grid-template-columns: 1fr; + } + } + + .account-actions__link { + width: auto; + display: flex; + justify-content: center; + align-items: center; + gap: var(--gap-2xs); + } + + .account-actions__icon { + display: flex; + width: var(--icon-size-sm); + height: var(--icon-size-sm); + margin-block: -4px; + } +{% endstylesheet %} diff --git a/snippets/account-button.liquid b/snippets/account-button.liquid new file mode 100644 index 000000000..101c8ed84 --- /dev/null +++ b/snippets/account-button.liquid @@ -0,0 +1,90 @@ +{%- doc -%} + Renders an account button. + + @param {string} [tag] - The tag to use + @param {string} [popover_id] - The id of the popover to target + @param {string} [popover_action] - The id of the popover to target + @param {string} [attributes] - Additional attributes to add to the tag +{%- enddoc -%} + +{%- assign tag = tag | default: 'button' -%} +<{{ tag }} + class="account-button header-actions__action" + aria-label="{{ 'accessibility.account' | t }}" + {%- if popover_id -%} + popovertarget="{{ popover_id }}" + popovertargetaction="{{ popover_action | default: 'toggle' }}" + {%- endif -%} + ref="trigger" + {{ attributes }} +> + {%- if customer.has_avatar? -%} + {{ customer | avatar }} + {%- elsif customer.first_name or customer.email -%} + {%- liquid + assign initial = customer.email | first + + if customer.first_name != blank + assign initial = customer.first_name | first + endif + -%} + + {%- else -%} + + {%- endif -%} + + +{% stylesheet %} + .account-button { + color: var(--color-foreground); + appearance: none; + border: none; + background: none; + height: var(--button-size); + width: var(--button-size); + display: flex; + flex-wrap: wrap; + justify-content: center; + align-content: center; + transition: color var(--animation-speed) var(--animation-easing); + } + + .account-button__avatar { + --account-button-size: 1.625rem; + + display: flex; + align-items: center; + justify-content: center; + width: var(--account-button-size); + height: var(--account-button-size); + border-radius: var(--style-border-radius-50); + background-color: var(--color-primary-button-background); + font-size: var(--font-size--sm); + font-weight: 500; + color: var(--color-primary-button-text); + text-transform: uppercase; + line-height: 1; + } + + .account-button__icon { + color: currentColor; + display: inline-flex; + justify-content: center; + align-items: center; + } + + /* The shop avatar doesn't bubble the click event up to our button, so we need to prevent that or the button doesn't work */ + .account-button shop-user-avatar { + pointer-events: none; + } +{% endstylesheet %} diff --git a/snippets/account-drawer.liquid b/snippets/account-drawer.liquid new file mode 100644 index 000000000..fb605544a --- /dev/null +++ b/snippets/account-drawer.liquid @@ -0,0 +1,103 @@ +{%- doc -%} + Renders the account drawer, which is used for mobile users. +{%- enddoc -%} + + + + + +{% stylesheet %} + .account-drawer { + @media screen and (min-width: 750px) { + display: none; + } + } + + .account-drawer__dialog { + --animation-speed: 0.24s; + --dialog-drawer-opening-animation: account-drawer-slide-in; + --dialog-drawer-closing-animation: account-drawer-slide-out; + + height: fit-content; + margin: 0; + inset-block-end: 0; + inset-block-start: auto; + border-radius: 0; + padding: 0; + } + + .account-drawer__close-button { + position: absolute; + z-index: 1; + inset-block-start: var(--padding-xs); + inset-inline-end: var(--padding-xs); + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + color: var(--color-foreground); + background-color: transparent; + display: flex; + align-items: center; + justify-content: center; + } + + .account-drawer__close-button .svg-wrapper { + display: flex; + width: var(--button-size); + height: var(--button-size); + align-items: center; + justify-content: center; + } + + .account-drawer__close-button svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + @keyframes account-drawer-slide-in { + from { + transform: translateY(100%); + } + + to { + transform: translateY(0); + } + } + + @keyframes account-drawer-slide-out { + from { + transform: translateY(0); + } + + to { + transform: translateY(100%); + } + } +{% endstylesheet %} diff --git a/snippets/account-popover.liquid b/snippets/account-popover.liquid new file mode 100644 index 000000000..39f62ce6b --- /dev/null +++ b/snippets/account-popover.liquid @@ -0,0 +1,75 @@ +{%- doc -%} + Renders the account popover for desktop users, which appears when clicking the account icon. It contains links for account actions like login, logout, and viewing account details. + + @param {object} [settings] - The theme-level settings. + + @param {string} [settings.popover_color_scheme] - The color scheme for the popover panel. +{%- enddoc -%} + + +{% stylesheet %} + .account-popover { + --account-popover-min-width: 22rem; + --account-actions-max-width: 22rem; + } + + .account-popover__summary { + padding: 0; + + &:hover { + color: var(--color-foreground); + } + } + + .account-popover__panel { + --account-popover-opacity: 0; + --account-popover-y: 20px; + border-radius: var(--style-border-radius-popover); + margin: 0; + top: var(--header-height); + left: unset; + right: calc(var(--anchor-right) * 1px); + + width: max-content; + min-width: var(--account-popover-min-width); + box-shadow: var(--shadow-popover); + border: var(--style-border-popover); + background-color: var(--color-background); + overflow-y: hidden; + opacity: var(--account-popover-opacity); + translate: 0 var(--account-popover-y); + transition-property: display, opacity, translate; + transition-duration: 0.3s; + transition-timing-function: var(--ease-out-quad); + transition-behavior: allow-discrete; + + &:popover-open { + --account-popover-opacity: 1; + --account-popover-y: 0px; + } + } + + @starting-style { + .account-popover__panel { + --account-popover-opacity: 0; + --account-popover-y: 20px; + } + .account-popover__panel:popover-open { + --account-popover-opacity: 0; + --account-popover-y: 20px; + } + } +{% endstylesheet %} diff --git a/snippets/add-to-cart-button.liquid b/snippets/add-to-cart-button.liquid new file mode 100644 index 000000000..1bd5d25ed --- /dev/null +++ b/snippets/add-to-cart-button.liquid @@ -0,0 +1,118 @@ +{%- doc -%} + Renders an "Add to cart" button with dynamic text and state. It shows different text based on whether the product can be added to the cart and provides visual feedback when an item is added. + + @param {boolean} can_add_to_cart - Whether the product can be added to the cart. + @param {string} add_to_cart_text - The text to display on the button. + @param {object} product - The product object to be added to the cart. + @param {boolean} [icon_only_on_mobile] - If `true`, only the icon is shown on mobile devices. + @param {string} [class] - Additional CSS classes to apply to the button. + @param {string} [id] - The ID attribute for the button. +{%- enddoc -%} + +{%- liquid + assign default_add_to_cart_text = 'actions.add_to_cart' | t + assign product_variant_media = product.selected_or_first_available_variant.featured_media.preview_image | image_url: width: 100 + if product.selected_or_first_available_variant.featured_media.preview_image == blank + assign product_variant_media = product.featured_media.preview_image | image_url: width: 100 + endif +-%} + + + + + +{% stylesheet %} + .add-to-cart-text { + display: flex; + gap: var(--gap-2xs); + align-items: center; + justify-content: center; + animation-duration: var(--animation-speed); + animation-timing-function: var(--animation-easing); + animation-fill-mode: forwards; + transition: opacity var(--animation-speed) var(--animation-easing); + } + + .atc-added .add-to-cart-text { + animation-name: atc-slide-out; + } + + .add-to-cart-text--added { + position: absolute; + inset: 0; + animation-duration: var(--animation-speed); + animation-timing-function: var(--animation-easing); + animation-fill-mode: forwards; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: width var(--animation-speed) var(--animation-easing), + opacity var(--animation-speed) var(--animation-easing); + } + + .atc-added .add-to-cart-text--added { + animation-name: atc-slide-in; + } + + @keyframes atc-slide-in { + from { + opacity: 0; + transform: translateY(0.5em); + } + + to { + opacity: 1; + transform: translateY(0); + } + } + + @keyframes atc-slide-out { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(-1em); + opacity: 0; + } + } +{% endstylesheet %} diff --git a/snippets/background-image.liquid b/snippets/background-image.liquid new file mode 100644 index 000000000..a485f83d6 --- /dev/null +++ b/snippets/background-image.liquid @@ -0,0 +1,40 @@ +{%- doc -%} + Renders a background image + + @param {object} background_image - The background image + @param {string} background_image_position - The background image position + @param {string} section_id - The section ID + @param {string} block_id - The block ID + @param {number} [height] - The height of the background image +{%- enddoc -%} + +
    + {% liquid + assign media_width_desktop = '100vw' + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2000, 2500, 3000, 3500, 4000, 5000' + %} + + {%- if background_image != blank -%} + {% liquid + assign fetch_priority = 'auto' + if section and section.index == 1 + assign fetch_priority = 'high' + endif + %} + {{ + background_image + | image_url: width: 3840 + | image_tag: height: height, sizes: sizes, widths: widths, loading: 'eager', fetchpriority: fetch_priority + }} + {%- else -%} + {%- assign placeholder_name = placeholder | default: 'hero-apparel-2' -%} + {%- if placeholder_name == blank -%} + {%- assign placeholder_name = 'hero-apparel-2' -%} + {%- endif -%} + {{ placeholder_name | placeholder_svg_tag }} + {%- endif -%} +
    diff --git a/snippets/background-media.liquid b/snippets/background-media.liquid new file mode 100644 index 000000000..bfa19866b --- /dev/null +++ b/snippets/background-media.liquid @@ -0,0 +1,7 @@ +{% liquid + if background_media == 'video' + render 'background-video', background_video: background_video, background_video_position: background_video_position, section_id: section_id, block_id: block_id, placeholder: placeholder + elsif background_media == 'image' + render 'background-image', background_image: background_image, background_image_position: background_image_position, section_id: section_id, block_id: block_id, placeholder: placeholder + endif +%} diff --git a/snippets/background-video.liquid b/snippets/background-video.liquid new file mode 100644 index 000000000..7d9e898ea --- /dev/null +++ b/snippets/background-video.liquid @@ -0,0 +1,57 @@ +{%- doc -%} + Renders a video as a background for a section or block, with a fallback to a placeholder image if no video is provided. + + @param {object} background_video - The video object to be used as the background. + @param {string} background_video_position - The position of the video, e.g., 'center-center'. + @param {string} section_id - The ID of the parent section. + @param {string} block_id - The ID of the parent block, if applicable. +{%- enddoc -%} + +{% liquid + assign video_classes = 'video-background video-background--' | append: background_video_position +%} + +{%- if background_video != blank -%} + + {% liquid + assign media_width_desktop = 100 | append: 'vw' + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 750px) ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2000, 2500, 3000, 3500, 4000, 5000' + %} + {{ background_video.preview_image | image_url: width: 3840 | image_tag: width: 1100, widths: widths, sizes: sizes }} + + +{%- else -%} +
    + {%- assign placeholder_name = placeholder | default: 'hero-apparel-2' -%} + {%- if placeholder_name == blank -%} + {%- assign placeholder_name = 'hero-apparel-2' -%} + {%- endif -%} + {{ placeholder_name | placeholder_svg_tag }} +
    +{%- endif -%} + +{% stylesheet %} + @media (prefers-reduced-motion: reduce) { + video-background-component video { + display: none; + } + } +{% endstylesheet %} diff --git a/snippets/bento-grid.liquid b/snippets/bento-grid.liquid new file mode 100644 index 000000000..6acc1d4af --- /dev/null +++ b/snippets/bento-grid.liquid @@ -0,0 +1,210 @@ +{%- doc -%} + Takes an array of HTML strings and positions them in a bento box grid layout. + Bento boxes can hold up to 12 items; when more items are provided, a new box is created to maintain the layout structure. + + @param {string[]} items - An array of HTML strings, where each string is a collection list item. +{%- enddoc -%} + +{% liquid + assign odd_item_check = items.size | modulo: 12 + if odd_item_check == 1 + assign first_box_size = 11 + else + assign first_box_size = 12 + endif +%} + +{% for item in items %} + {% liquid + if first_box_size == 11 + assign item_modulo = forloop.index | modulo: 11 + if forloop.index == 12 + # Close the box and for a new one to start + assign item_modulo = forloop.index | modulo: 12 + assign item_modulo = 1 + endif + else + assign item_modulo = forloop.index | modulo: 12 + endif + %} + + {% # theme-check-disable UnclosedHTMLElement %} + {% if forloop.first or item_modulo == 1 %} +
    + {% endif %} + {% # theme-check-disable UnclosedHTMLElement %} + +
    + {{ item }} +
    + + {% if forloop.last or item_modulo == 0 %} +
    + {% endif %} +{% endfor %} + +{% stylesheet %} + .bento-box { + display: grid; + column-gap: var(--bento-gap); + row-gap: calc(var(--bento-gap) * 1.5); + width: 100%; + } + + .bento-box:has(.collection-card--image-bg) { + row-gap: var(--bento-gap); + } + + .bento-box ~ .bento-box { + padding-block-start: var(--bento-gap); + } + + @media (max-width: 900px) { + .bento-box { + grid-template-columns: repeat(2, 1fr); + } + + .bento-box__item:nth-child(3n + 1) { + grid-column: span 1; + } + + .bento-box__item:nth-child(3n + 2) { + grid-column: span 1; + } + + .bento-box__item:nth-child(3n + 3) { + grid-column: span 2; + } + + /* Ensure last items create a full row */ + .bento-box__item:last-child:nth-child(3n + 5) { + grid-column: span 1; + } + + .bento-box__item:last-child:nth-child(3n + 4) { + grid-column: span 2; + } + } + + @media (min-width: 901px) { + .bento-box { + grid-template-columns: repeat(12, 1fr); + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D E E E F F F' + 'G G G H H H I I I I I I' + 'J J J J K K K K L L L L'; + } + + .bento-box__item:nth-child(1) { + grid-area: A; + } + + .bento-box__item:nth-child(2) { + grid-area: B; + } + + .bento-box__item:nth-child(3) { + grid-area: C; + } + + .bento-box__item:nth-child(4) { + grid-area: D; + } + + .bento-box__item:nth-child(5) { + grid-area: E; + } + + .bento-box__item:nth-child(6) { + grid-area: F; + } + + .bento-box__item:nth-child(7) { + grid-area: G; + } + + .bento-box__item:nth-child(8) { + grid-area: H; + } + + .bento-box__item:nth-child(9) { + grid-area: I; + } + + .bento-box__item:nth-child(10) { + grid-area: J; + } + + .bento-box__item:nth-child(11) { + grid-area: K; + } + + .bento-box__item:nth-child(12) { + grid-area: L; + } + + /* === Overrides for specific cases === */ + + /* Exactly 1 item */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(1)) { + grid-template-areas: 'A A A A A A A A A A A A'; + } + + /* Exactly 2 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(2)) { + grid-template-areas: 'A A A A A A B B B B B B'; + } + + /* Exactly 4 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(4)) { + grid-template-areas: + 'A A A A B B B B B B B B' + 'C C C C C C C C D D D D'; + } + + /* Exactly 5 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(5)) { + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D E E E E E E'; + } + + /* Exactly 7 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(7)) { + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D D D D E E E' + 'F F F F F F G G G G G G'; + } + + /* Exactly 8 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(8)) { + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D E E E F F F' + 'G G G H H H H H H H H H'; + } + + /* Exactly 10 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(10)) { + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D E E E F F F' + 'G G G G G G G G G H H H' + 'I I I J J J J J J J J J'; + } + + /* Exactly 11 items */ + .bento-box:has(.bento-box__item:first-child:nth-last-child(11)) { + grid-template-areas: + 'A A A B B B B B B C C C' + 'D D D D D D E E E F F F' + 'G G G H H H I I I I I I' + 'J J J J K K K K K K K K'; + } + } +{% endstylesheet %} diff --git a/snippets/blog-comment-form.liquid b/snippets/blog-comment-form.liquid new file mode 100644 index 000000000..2812690a1 --- /dev/null +++ b/snippets/blog-comment-form.liquid @@ -0,0 +1,206 @@ +{%- doc -%} + Renders a comment form for a blog post. + + @param {object} [form] - The form object + @param {object} [article] - The article object + @param {string} [section_id] - The section ID +{%- enddoc -%} + +{% form 'new_comment', article %} +
    +

    {{- 'blogs.comment_form.heading' | t -}}

    + + {%- if form.errors -%} + + +
      + {%- for field in form.errors -%} +
    • + {%- if form.errors.translated_fields[field] contains 'author' -%} + + {{- 'blogs.comment_form.name' | t -}} + + {%- elsif form.errors.translated_fields[field] contains 'body' -%} + + {{- 'blogs.comment_form.message' | t -}} + + {%- else -%} + + {{- form.errors.translated_fields[field] | capitalize -}} + + {%- endif -%} + {{ form.errors.messages[field] }} +
    • + {%- endfor -%} +
    + {%- elsif form.posted_successfully? -%} + + {%- endif -%} + +
    +
    + + + +
    + +
    + + + +
    + +
    + + + +
    +
    + + {% if blog.moderated? %} +

    + {{- 'blogs.comment_form.moderated' | t -}} +

    + {% endif %} + + +
    +{% endform %} + +{% stylesheet %} + .blog-post-comments__form-container { + --comment-form-gap: var(--gap-md); + + width: 100%; + max-width: var(--normal-content-width); + margin: var(--margin-4xl) auto 0; + } + + .blog-post-comments__form { + display: grid; + grid-template-columns: 1fr; + gap: var(--comment-form-gap); + + @media screen and (min-width: 750px) { + grid-template-columns: 1fr 1fr; + } + } + + .blog-post-comments__form-input { + padding: var(--padding-lg) var(--padding-xl); + border: var(--style-border-width-inputs) solid var(--color-input-border); + } + + .blog-post-comments__form-input--textarea { + resize: vertical; + min-height: var(--input-textarea-min-height); + } + + .blog-post-comments__form-message { + display: flex; + align-items: center; + gap: var(--gap-xs); + } + + .blog-post-comments__form-body { + grid-column: 1 / -1; + } + + .blog-post-comments__form-input:focus-visible { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + .blog-post-comments__form-moderated { + font-size: var(--font-size--xs); + } + + .blog-post-comments__form-submit { + margin-block-start: var(--comment-form-gap); + } +{% endstylesheet %} diff --git a/snippets/border-override.liquid b/snippets/border-override.liquid new file mode 100644 index 000000000..94d8888f0 --- /dev/null +++ b/snippets/border-override.liquid @@ -0,0 +1,7 @@ +{%- comment -%} + Renders border override CSS +{%- endcomment -%} + +--border-width: {{ settings.border_width }}px; --border-style: {{ settings.border }}; --border-color: +rgb(var(--color-border-rgb) / {{ settings.border_opacity | divided_by: 100.0 }}); --border-radius: +{{ settings.border_radius }}px; {% if settings.border_radius > 0 %} overflow: hidden; {% endif %} diff --git a/snippets/button.liquid b/snippets/button.liquid new file mode 100644 index 000000000..c8ae53790 --- /dev/null +++ b/snippets/button.liquid @@ -0,0 +1,43 @@ +{%- doc -%} + Intended for use in a block similar to the button block. + + @param {string} link - link to render + @param {object} [block] - The block + + @example + {% render 'button', link: '/collections/all' %} +{%- enddoc -%} + + + {{ block.settings.label }} + + +{% stylesheet %} + .link { + text-decoration: none; + text-decoration-color: currentcolor; + + &:hover { + color: var(--color-primary-hover); + text-decoration-color: transparent; + } + } +{% endstylesheet %} diff --git a/snippets/card-gallery.liquid b/snippets/card-gallery.liquid new file mode 100644 index 000000000..bb9036c49 --- /dev/null +++ b/snippets/card-gallery.liquid @@ -0,0 +1,385 @@ +{%- doc -%} + Displays product images in a carousel. + Settings allow for a full slideshow, showing only the first image, or showing the second image when hovering. + Note: When the product card itself is in a carousel layout, the card-gallery's carousel is disabled with JavaScript. + + @param [children] - Additional content rendered below the card gallery + @param [section] - The section object the snippet is rendered in + @param [block] - The block object the snippet is rendered in + @param [has_applied_colour_filter] - Whether there's an applied colour filter +{%- enddoc -%} + +{% liquid + assign image_sizes = '(min-width: 750px) 50vw, 100vw' + # if the card-gallery has a section.settings.product_card_size: + # assume grid-template autofill(card-size, 1fr) and calculate the sizes attribute based on the minimum card size + + # if section has section.settings.columns: + # assume grid-template repeat(column-count, 1fr) and calculate the sizes attribute based on the number of columns +%} + +{% if section.settings.product_card_size %} + {% capture card_size %} + {% render 'util-product-grid-card-size' section: section %} + {% endcapture %} + {% assign card_size = card_size | strip | replace: 'px', '' | plus: 0 %} + {% capture sizes_attribute %} + {% render 'util-autofill-img-size-attr' card_size: card_size, card_gap: section.settings.columns_gap_horizontal %} + {% endcapture %} + {% assign image_sizes = sizes_attribute | strip %} +{% elsif section.settings.columns and section.settings.layout_type != 'editorial' %} + {% assign viewport_width = 100.0 | divided_by: section.settings.columns %} + {% assign sizes_attribute = '(min-width: 750px) [viewport_width]vw, 100vw' + | replace: '[viewport_width]', viewport_width + %} + {% assign image_sizes = sizes_attribute | strip %} +{% endif %} + +{% liquid + assign product = closest.product + + assign lazy_image_sizes = 'auto, ' | append: image_sizes + + assign image_ratio_setting = block.settings.image_ratio + assign temp_ratio = 1 + + if image_ratio_setting == 'landscape' + assign temp_ratio = '16 / 9' + elsif image_ratio_setting == 'portrait' + assign temp_ratio = '4 / 5' + elsif image_ratio_setting == 'square' + assign temp_ratio = '1' + elsif image_ratio_setting == 'adapt' + if product != blank + assign current_featured_image_for_ratio = product.featured_image + if current_featured_image_for_ratio == blank and product.featured_media.preview_image != blank + assign current_featured_image_for_ratio = product.featured_media.preview_image + endif + + if current_featured_image_for_ratio != blank and current_featured_image_for_ratio.aspect_ratio != null and current_featured_image_for_ratio.aspect_ratio > 0 + assign temp_ratio = current_featured_image_for_ratio.aspect_ratio + endif + endif + endif + + if temp_ratio != blank and temp_ratio != 0 and temp_ratio != '' + assign ratio = temp_ratio + else + assign ratio = 1 + endif + + assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' + assign selected_variant_image = product.selected_or_first_available_variant.image.src + + assign hover_behavior = 'carousel' + + if block.settings.image_ratio == 'adapt' and block.settings.constrain_to_viewport + if block.settings.constrain_to_viewport != '' + assign constrain_to_viewport = true + assign media_fit = block.settings.constrain_to_viewport + endif + endif +%} + + + +{% stylesheet %} + .card-gallery { + overflow: hidden; + container-type: inline-size; /* Make card-gallery a container */ + container-name: card-gallery-container; /* Optional: name the container */ + } + + .card-gallery__placeholder svg { + height: 100%; + width: 100%; + } + + .card-gallery svg { + aspect-ratio: var(--gallery-aspect-ratio, var(--ratio)); + } + + .product-card-gallery__title-placeholder { + padding: var(--padding-md); + font-size: var(--font-size--2xl); + line-height: var(--line-height--display-loose); + word-break: break-word; + color: var(--color-foreground); + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + aspect-ratio: var(--gallery-aspect-ratio); + border-radius: var(--product-corner-radius); + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } + + @media screen and (min-width: 750px) { + .product-grid[data-product-card-size='extra-large'] .product-card-gallery__title-placeholder { + padding: var(--padding-3xl); + font-size: var(--font-size--3xl); + } + + .product-grid[data-product-card-size='large'] .product-card-gallery__title-placeholder { + padding: var(--padding-2xl); + font-size: var(--font-size--2xl); + } + + .product-grid[data-product-card-size='medium'] .product-card-gallery__title-placeholder { + padding: var(--padding-xl); + font-size: var(--font-size--xl); + } + + .product-grid[data-product-card-size='small'] .product-card-gallery__title-placeholder { + padding: var(--padding-sm); + font-size: var(--font-size--lg); + } + + .product-grid[data-product-card-size='extra-large'] + .card-gallery:has(.product-badges--top-right .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-right: calc(var(--padding-3xl) + 50px); + } + + .product-grid[data-product-card-size='large'] + .card-gallery:has(.product-badges--top-right .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-right: calc(var(--padding-2xl) + 50px); + } + + .product-grid[data-product-card-size='medium'] + .card-gallery:has(.product-badges--top-right .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-right: calc(var(--padding-xl) + 50px); + } + + .product-grid[data-product-card-size='small'] + .card-gallery:has(.product-badges--top-right .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-right: calc(var(--padding-sm) + 50px); + } + + .product-grid[data-product-card-size='extra-large'] + .card-gallery:has(.product-badges--top-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-top: calc(var(--padding-3xl) + 40px); + } + + .product-grid[data-product-card-size='large'] + .card-gallery:has(.product-badges--top-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-top: calc(var(--padding-2xl) + 40px); + } + + .product-grid[data-product-card-size='medium'] + .card-gallery:has(.product-badges--top-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-top: calc(var(--padding-xl) + 40px); + } + + .product-grid[data-product-card-size='small'] + .card-gallery:has(.product-badges--top-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-top: calc(var(--padding-sm) + 40px); + } + + .product-grid[data-product-card-size='extra-large'] + .card-gallery:has(.product-badges--bottom-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-bottom: calc(var(--padding-3xl) + 40px); + } + + .product-grid[data-product-card-size='large'] + .card-gallery:has(.product-badges--bottom-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-bottom: calc(var(--padding-2xl) + 40px); + } + + .product-grid[data-product-card-size='medium'] + .card-gallery:has(.product-badges--bottom-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-bottom: calc(var(--padding-xl) + 40px); + } + + .product-grid[data-product-card-size='small'] + .card-gallery:has(.product-badges--bottom-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-bottom: calc(var(--padding-sm) + 40px); + } + } + + @media screen and (max-width: 749px) { + .product-card-gallery__title-placeholder { + font-size: var(--font-size--xl); + padding: var(--padding-md); + } + + .product-grid[data-product-card-size] + .card-gallery:has(.product-badges--top-right .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-right: calc(var(--padding-sm) + 50px); + } + + .product-grid[data-product-card-size] + .card-gallery:has(.product-badges--top-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-top: calc(var(--padding-sm) + 40px); + } + + .product-grid[data-product-card-size] + .card-gallery:has(.product-badges--bottom-left .product-badges__badge) + .product-card-gallery__title-placeholder { + padding-bottom: calc(var(--padding-sm) + 40px); + } + } + + [product-grid-view='zoom-out'] .card-gallery .product-card-gallery__title-placeholder { + padding: var(--padding-xs) !important; + font-size: var(--font-size--xs); + } +{% endstylesheet %} diff --git a/snippets/cart-bubble.liquid b/snippets/cart-bubble.liquid new file mode 100644 index 000000000..1954e41af --- /dev/null +++ b/snippets/cart-bubble.liquid @@ -0,0 +1,40 @@ +{%- doc -%} + @param [limit] - {number} + @param [live_region] - {boolean} + + The maximum number of items in the cart to display. If the number of items in the cart is greater than this limit, the + count will be displayed as "99+". +{%- enddoc -%} + +
    + + + + {{- 'accessibility.cart_count' | t -}} + : {{ cart.item_count }} + + + +
    diff --git a/snippets/cart-discount.liquid b/snippets/cart-discount.liquid new file mode 100644 index 000000000..91bd285d4 --- /dev/null +++ b/snippets/cart-discount.liquid @@ -0,0 +1,232 @@ +{%- doc -%} + Renders a cart discount form. + + @param {string} section_id - The section ID +{%- enddoc -%} + +{% liquid + assign discount_codes = cart.cart_level_discount_applications | where: 'type', 'discount_code' | map: 'title' + for item in cart.items + for allocation in item.line_level_discount_allocations + if allocation.discount_application.type == 'discount_code' + assign discount_codes = item.line_level_discount_allocations | slice: forloop.index0 | map: 'discount_application' | map: 'title' | concat: discount_codes + endif + endfor + endfor + + assign discount_codes = discount_codes | uniq +%} + + + +
    0 %} + open + {% endif %} + declarative-open + > + + {{ 'content.discount' | t }} + + + {{- 'icon-plus.svg' | inline_asset_content -}} + + + +
    +
    +
    + + + +
    +
    + +
      + {% for discount_code in discount_codes %} +
    • +

      + {{ discount_code }} +

      + +
    • + {% endfor %} +
    +
    +
    +
    +
    + +{% stylesheet %} + .cart-discount__input { + background-color: var(--color-input-background); + color: var(--color-input-text); + border-width: var(--style-border-width-inputs); + border-color: var(--color-input-border); + border-style: solid; + border-radius: var(--style-border-radius-inputs); + padding: var(--padding-sm) var(--padding-md); + height: 100%; + flex-grow: 1; + min-width: 0; + } + + .cart-discount__input::placeholder { + color: rgb(var(--color-input-text-rgb) / var(--opacity-subdued-text)); + } + + .cart-discount__label { + display: flex; + align-items: flex-start; + gap: var(--gap-2xs); + font-size: var(--cart-font-size--sm); + } + + .cart-discount__pill-code { + overflow: hidden; + max-width: 100px; + text-overflow: ellipsis; + white-space: nowrap; + margin: 0; + } + + .cart-discount { + width: 100%; + } + + .cart-discount__summary { + display: flex; + align-items: center; + justify-content: space-between; + } + + .cart-discount__summary:hover { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .cart-discount__codes { + display: none; + gap: var(--padding-xs); + flex-wrap: wrap; + list-style: none; + padding-inline: 0; + margin: 0; + } + + .cart-discount__codes:has(.cart-discount__pill) { + display: flex; + } + + .cart-discount__button { + height: 100%; + } + + .cart-discount__content { + height: calc(var(--button-size) + var(--padding-2xs) + var(--padding-sm)); + } + + .cart-discount__pill { + display: flex; + color: var(--color-foreground); + gap: var(--padding-xs); + align-items: center; + padding: var(--padding-xs) var(--padding-sm); + border-radius: var(--style-border-radius-pills); + background-color: var(--color-input-background); + text-transform: uppercase; + } + + .cart-discount__form { + display: flex; + gap: var(--padding-md); + align-items: center; + height: 100%; + padding-block: var(--padding-2xs) var(--padding-sm); + } + + :is(.cart-discount__pill-remove, .cart-discount__pill-remove:hover) { + --close-icon-opacity: 0.4; + + color: var(--color-foreground); + background-color: transparent; + pointer-events: all; + cursor: pointer; + height: 100%; + } + + .cart-discount__error { + display: flex; + align-items: center; + width: 100%; + padding-block: var(--padding-2xs) var(--padding-sm); + } + + .cart-discount__error .svg-wrapper { + flex-shrink: 0; + width: var(--icon-size-xs); + height: var(--icon-size-xs); + margin-inline: var(--margin-3xs) var(--margin-xs); + } + + .cart-discount__error-text { + margin-block-start: var(--margin-3xs); + } + + cart-discount-component { + display: flex; + } +{% endstylesheet %} diff --git a/snippets/cart-drawer.liquid b/snippets/cart-drawer.liquid new file mode 100644 index 000000000..01ed3481a --- /dev/null +++ b/snippets/cart-drawer.liquid @@ -0,0 +1,171 @@ +{%- doc -%} + Renders the cart drawer, a slide-out panel that displays the contents of the cart. It includes the cart icon that acts as a trigger. + + @param {object} [settings] - An object containing theme settings. + + @param {boolean} [settings.auto_open_cart_drawer] - If `true`, the cart drawer opens automatically after an item is + added. + @param {string} [settings.drawer_color_scheme] - The color scheme for the drawer. +{%- enddoc -%} + + + + + + + +
    + + {%- if cart.empty? -%} +
    + +
    + +
    + + {{ 'content.your_cart_is_empty' | t }} + + +
    + {% render 'cart-products' %} +
    +
    + {%- else -%} +
    + + {{ 'content.cart_title' | t }} + {% render 'cart-bubble' %} + + + +
    + +
    + + {% render 'cart-products' %} + + +
    + {% render 'cart-summary' %} +
    +
    + {%- endif -%} +
    +
    +
    +
    + +{% stylesheet %} + .cart-items-component { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + } + + .cart-drawer__heading .cart-bubble { + width: fit-content; + border-radius: var(--style-border-radius-buttons-primary); + aspect-ratio: auto; + padding: var(--cart-padding); + } + + .cart-drawer__heading .cart-bubble[data-maintain-ratio] { + aspect-ratio: 1; + min-width: 26px; + } + + .cart-drawer__header { + background-color: var(--color-background); + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: var(--cart-drawer-padding); + border-bottom: var(--style-border-width) solid none; + position: sticky; + top: 0; + z-index: 1; + + @media screen and (min-width: 750px) { + padding: var(--cart-drawer-padding-desktop); + } + } + + .cart-drawer__dialog { + overflow: hidden; + } + + .cart-drawer__inner { + height: 100%; + overflow: hidden; + } + + .cart-drawer__content { + height: calc(100% - var(--header-height)); + display: flex; + flex-direction: column; + } + + .cart-drawer__summary { + background-color: var(--color-background); + position: sticky; + bottom: 0; + z-index: 1; + } +{% endstylesheet %} diff --git a/snippets/cart-icon-component.liquid b/snippets/cart-icon-component.liquid new file mode 100644 index 000000000..a17f7c0bc --- /dev/null +++ b/snippets/cart-icon-component.liquid @@ -0,0 +1,32 @@ +{%- doc -%} + Renders the cart icon, which displays the number of items in the cart via a bubble. +{%- enddoc -%} + + + + {% render 'cart-bubble', limit: 100, live_region: true, test_id: test_id %} + + +{% stylesheet %} + cart-icon:has(.cart-bubble__text-count:empty) { + --cart-bubble-size: 10px; + --cart-bubble-top: 9px; + --cart-bubble-right: 9px; + + .svg-wrapper { + --cart-bubble-top: 4px; + --cart-bubble-right: 4px; + } + } +{% endstylesheet %} diff --git a/snippets/cart-note.liquid b/snippets/cart-note.liquid new file mode 100644 index 000000000..1f2e85c1a --- /dev/null +++ b/snippets/cart-note.liquid @@ -0,0 +1,38 @@ + + + + +
    + + + {{ 'content.seller_note' | t }} + + + + {{- 'icon-plus.svg' | inline_asset_content -}} + + + +
    + + +
    +
    +
    +
    diff --git a/snippets/cart-products.liquid b/snippets/cart-products.liquid new file mode 100644 index 000000000..73b31b589 --- /dev/null +++ b/snippets/cart-products.liquid @@ -0,0 +1,753 @@ + + +
    + {% if cart.empty? %} + {%- if shop.customer_accounts_enabled and customer == null -%} +

    + {{ 'actions.log_in_html' | t: link: routes.account_login_url }} +

    + {%- endif -%} + + + {{ 'actions.continue_shopping' | t }} + + {%- else -%} + +
    +
    + + + + + + + + + + + + + + {% for item in cart.items %} + + + + + + + + {% endfor %} + +
    + {{ 'content.cart_total' | t }} + {{ cart.total_price | money_with_currency }} +
    + {{ 'content.product_image' | t }} + + {{ 'content.product_information' | t }} + + {{ 'content.quantity' | t }} + + {{ 'content.product_total' | t }} +
    + {% if item.image -%} + {% liquid + assign ratio = 1 + assign border_opacity = settings.cart_thumbnail_border_opacity | divided_by: 100.0 + assign border_override = '--border-width: [cart_thumbnail_border_width]px; --border-style: [cart_thumbnail_border_style]; --border-color: rgb(var(--color-border-rgb) / [cart_thumbnail_border_opacity]); --border-radius: [cart_thumbnail_border_radius]px;' | replace: '[cart_thumbnail_border_width]', settings.cart_thumbnail_border_width | replace: '[cart_thumbnail_border_style]', settings.cart_thumbnail_border | replace: '[cart_thumbnail_border_opacity]', border_opacity | replace: '[cart_thumbnail_border_radius]', settings.cart_thumbnail_border_radius + + if settings.cart_thumbnail_border_radius > 0 + assign border_override = border_override | append: ' overflow: hidden;' + endif + if block.settings.image_ratio == 'portrait' + assign ratio = 0.8 + elsif block.settings.image_ratio == 'adapt' + assign ratio = item.image.aspect_ratio + endif + %} + + {%- liquid + echo item.image | image_url: width: 250 | image_tag: class: 'cart-items__media-image border-style', style: border_override + -%} + + {%- endif %} + +

    + + {{- item.product.title -}} + +

    + {% if item.product.vendor and block.settings.vendor %} +

    + {{ item.product.vendor }} +

    + {% endif %} + + {%- if item.item_components.size != 0 -%} +
      + {%- for component in item.item_components -%} +
    • + {{- component.title -}} + {%- if component.quantity > 1 -%} + × {{ component.quantity }} + {%- endif -%} +
    • + {%- endfor -%} +
    + {%- endif -%} + + {%- if item.product.has_only_default_variant == false + or item.properties.size != 0 + or item.selling_plan_allocation != null + -%} +
    + {%- if item.product.has_only_default_variant == false and item.item_components.size == 0 -%} + {%- for option in item.options_with_values -%} +
    +
    {{ option.name }}:
    +
    + {{- option.value -}} + {%- if forloop.last != true %}, {% endif -%} +
    +
    + {%- endfor -%} + {%- endif -%} + + {%- for property in item.properties -%} + {%- assign property_first_char = property.first | slice: 0 -%} + {%- if property.last != blank and property_first_char != '_' -%} +
    +
    {{ property.first }}:
    +
    + {%- if property.last contains '/uploads/' -%} + {{ property.last | split: '/' | last }} + {%- else -%} + {{ property.last }} + {%- endif -%} +
    +
    + {%- endif -%} + {%- endfor -%} +
    + + {% if item.selling_plan_allocation %} +

    {{ item.selling_plan_allocation.selling_plan.name }}

    + {% endif %} + {%- endif -%} + + {% if item.line_level_discount_allocations.size > 0 %} +
      + {%- for discount in item.line_level_discount_allocations -%} +
    • {{ discount.discount_application.title | escape }}
    • + {%- endfor -%} +
    + {% endif %} + +
    + {% if item.original_price != item.final_price %} + {{ 'content.price_sale' | t }} + {{ item.final_price | money }} + {{ 'content.price_regular' | t }} + + {% if item.variant.compare_at_price > item.original_price %} + {{ item.variant.compare_at_price | money }} + {% else %} + {{ item.original_price | money }} + {% endif %} + + {% else %} + {% if item.variant.compare_at_price > item.original_price %} + {{ 'content.price_sale' | t }} + {% else %} + {{ 'content.price' | t }} + {% endif %} + + {{ item.original_price | money }} + + {% if item.variant.compare_at_price > item.original_price %} + {{ 'content.price_regular' | t }} + {{ item.variant.compare_at_price | money }} + {% endif %} + {% endif %} +
    +
    + {% # Here I want to pass some arguments to the quantity block so it knows which value should the input be set to. Though quantity block could be a snippet instead %} + {% assign can_update_quantity = item.instructions.can_update_quantity + | default: true, allow_false: true + %} + {% render 'quantity-selector', + product: item.product, + in_cart_quantity: item.quantity, + line_index: item.index, + min: 0, + class: 'cart-primary-typography', + can_update_quantity: can_update_quantity + %} + + + + {%- liquid + if settings.currency_code_enabled_cart_items + assign price = item.final_line_price | money_with_currency + assign unit_price = item.unit_price | money_with_currency + else + assign price = item.final_line_price | money + assign unit_price = item.unit_price | money + endif + -%} + {{ price }} + {%- if item.unit_price_measurement -%} +
    + {% render 'unit-price', price: unit_price, measurement: item.unit_price_measurement %} +
    + {%- endif -%} +
    +
    +
    + {%- endif -%} +
    + +{% stylesheet %} + .cart-items { + --cart-item-media-width-min: 2.5rem; + --cart-item-media-width-max: 7.5rem; + + container-name: cart-items; + container-type: inline-size; + width: 100%; + } + + .cart-items-disabled { + pointer-events: none; + } + + .cart-items__table { + width: 100%; + } + + .cart-items__table * { + margin: 0; + } + + .cart-items__table-row { + --cart-item-price-width: 6rem; + + display: grid; + grid-template-columns: clamp(2.5rem, 15cqi, 7.5rem) minmax(0, 1fr) minmax(var(--cart-item-price-width), auto); + grid-template-areas: + 'media details price' + 'media quantity price' + 'media error error'; + column-gap: var(--gap-md); + align-items: start; + padding-bottom: var(--cart-items-gap); + margin-bottom: var(--margin-lg); + } + + .cart-items__table-row.cart-items__nested-line td:first-child { + width: 60%; + justify-self: right; + } + + html:active-view-transition-type(page-navigation) .cart-items__table-row { + view-transition-name: none !important; + } + + .cart-items__table-row.removing { + overflow: hidden; + animation: removeRow calc(var(--animation-speed) * 2) var(--animation-easing) forwards; + animation-delay: var(--animation-speed); + } + + @keyframes removeRow { + 0% { + height: var(--row-height); + } + + 100% { + opacity: 0; + height: 0; + padding-bottom: 0; + margin-bottom: 0; + border-color: transparent; + } + } + + .cart-items__table-row:last-child { + padding-bottom: 0; + } + + .cart-items--dividers .cart-items__table-row { + border-bottom: 1px solid var(--color-border); + margin-bottom: var(--cart-items-gap); + } + + .cart-items--dividers .cart-items__table-row:has(+ .cart-items__nested-line) { + border-bottom: none; + margin-bottom: 0; + } + + .cart-items--dividers .cart-items__table-row:last-child { + border-block-end: none; + padding-block-end: 0; + margin-bottom: 0; + } + + .cart-items__details { + grid-area: details; + color: rgb(var(--color-foreground-rgb) / var(--opacity-70)); + } + + .cart-items__details > * + *, + .cart-items__bundle li { + margin-block-start: var(--margin-2xs); + } + + .cart-items__details * { + font-size: var(--cart-font-size--sm); + } + + .cart-items__details a { + text-decoration: none; + } + + .cart-items__title { + font-size: var(--cart-font-size--md); + color: var(--color-foreground); + text-transform: var(--product-title-case); + } + + .cart-items__variant { + display: inline-block; + } + + .cart-items__quantity { + grid-area: quantity; + margin-block-start: var(--margin-xs); + display: flex; + align-items: center; + justify-content: flex-start; + gap: var(--gap-xs); + width: fit-content; + } + + .cart-items__quantity .quantity-selector { + display: inline-flex; + flex: 0 1 var(--quantity-selector-width); + font-size: var(--cart-font-size--sm); + height: auto; + } + + .cart-items__remove { + background-color: transparent; + color: var(--color-foreground); + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + justify-content: center; + box-shadow: none; + padding: 0; + } + + .cart-items__media { + grid-area: media; + padding: 0; + } + + .cart-items__price { + grid-area: price; + min-height: unset; + min-width: var(--cart-item-price-width); + text-align: end; + display: block; + font-size: var(--cart-font-size--md); + } + + .cart-items__price-unit { + font-size: var(--cart-font-size--xs); + } + + .cart-items__media-container { + display: flex; + aspect-ratio: var(--ratio); + position: relative; + width: 100%; + overflow: hidden; + } + + .cart-items__media-image { + aspect-ratio: inherit; + object-fit: cover; + object-position: center center; + width: 100%; + height: auto; + } + + .cart-items__empty-button { + margin-top: var(--margin-md); + padding-inline: var(--padding-4xl); + padding-block: var(--padding-lg); + } + + /* Error message */ + .cart-items__error { + display: flex; + align-items: flex-start; + width: 100%; + grid-area: error; + margin-block-start: var(--margin-xs); + opacity: 1; + overflow: hidden; + transform: translateY(0); + transition: opacity var(--drawer-animation-speed) var(--animation-easing), + transform var(--drawer-animation-speed) var(--animation-easing); + + @starting-style { + opacity: 0; + transform: translateY(-0.5rem); + } + } + + .cart-item__error { + display: flex; + align-items: flex-start; + width: 100%; + font-size: var(--cart-font-size--sm); + padding-block: var(--padding-2xs); + } + + .cart-item__error .svg-wrapper { + flex-shrink: 0; + width: var(--icon-size-xs); + height: var(--icon-size-xs); + margin-inline: var(--margin-3xs) var(--margin-xs); + margin-block-start: var(--margin-3xs); + } + + @container cart-items (min-width: 720px) { + .cart-items__table-row { + --cart-item-price-width: 6rem; + + grid-template-columns: 7.5rem 1fr 1fr minmax(var(--cart-item-price-width), auto); + grid-template-rows: min-content 1fr; + grid-template-areas: + 'media details quantity price' + 'media details error error'; + } + + .cart-items__quantity, + .cart-items__price { + grid-area: initial; + } + + .cart-items__quantity { + margin-top: 0; + } + + .cart-items__price { + min-height: var(--minimum-touch-target); + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: center; + } + } + + .cart__original-total-container, + .cart__total-container { + display: flex; + flex-direction: column; + } + + .cart__total-container { + row-gap: var(--gap-2xs); + + &:has(.cart__installments) { + row-gap: var(--gap-xs); + } + } + + .cart__original-total-container:empty { + display: none; + } + + .cart__summary-totals { + display: flex; + flex-direction: column; + gap: var(--gap-xl); + width: 100%; + border-block-start: none; + + &:has(> :first-child:not(.cart__original-total-container, .cart__total-container)) { + padding-block-start: 0; + border-block-start: none; + } + + @media screen and (min-width: 750px) { + padding-block-start: 0; + } + } + + .cart__original-total-container, + .cart__original-total-container * { + font-size: var(--cart-font-size--sm); + } + + .cart__total { + font-weight: var(--font-weight-bold); + } + + .cart__total-label { + font-size: var(--cart-font-size--sm); + } + + .cart__total-value { + font-size: var(--cart-font-size--2xl); + } + + .cart-primary-typography { + font-family: var(--cart-primary-font-family); + font-style: var(--cart-primary-font-style); + font-weight: var(--cart-primary-font-weight); + } + + .cart-secondary-typography { + font-family: var(--cart-secondary-font-family); + font-style: var(--cart-secondary-font-style); + font-weight: var(--cart-secondary-font-weight); + } + + .cart__ctas { + width: 100%; + display: grid; + gap: var(--checkout-button-gap); + grid-auto-flow: row; + grid-template-columns: 1fr; + } + + .cart__additional-checkout-buttons { + width: 100%; + } + + .cart__ctas .cart__checkout-button { + width: 100%; + height: clamp(25px, var(--height-buy-buttons), 55px); + padding-inline: var(--padding-4xl); + } + + shopify-accelerated-checkout-cart { + --shopify-accelerated-checkout-inline-alignment: center; + --shopify-accelerated-checkout-button-border-radius: var(--style-border-radius-buttons-primary); + } + + .cart-note { + width: 100%; + } + + .cart-note__inner { + padding-block: var(--padding-2xs) var(--padding-sm); + } + + .cart-note__summary { + display: flex; + align-items: center; + justify-content: space-between; + } + + .cart-note__summary:hover { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .cart-note__label { + display: flex; + align-items: flex-start; + gap: var(--gap-2xs); + font-size: var(--cart-font-size--sm); + } + + .cart-note__instructions { + color: var(--color-input-text); + background-color: var(--color-input-background); + border-width: var(--style-border-width-inputs); + border-color: var(--color-input-border); + transition: box-shadow var(--animation-speed) ease; + box-shadow: var(--input-box-shadow); + min-height: 5.5rem; + min-width: 100%; + max-width: 100%; + font-size: var(--cart-font-size--sm); + padding: max(4px, calc(var(--style-border-radius-inputs) * (1 - cos(45deg)))); + } + + .cart-note .svg-wrapper { + height: var(--icon-size-sm); + width: var(--icon-size-sm); + margin: 0; + } + + .cart-note .icon-plus { + height: var(--icon-size-xs); + width: var(--icon-size-xs); + } + + /* Remove animation */ + .remove-icon-bottom, + .remove-icon-top { + transition: transform var(--animation-speed) var(--animation-easing); + } + + .cart-items__remove:hover .remove-icon-top { + transform: translate(calc(-1 * var(--icon-stroke-width)), var(--icon-stroke-width)) rotate(-15deg); + } + + .cart-items__remove:is(:hover, :active) .remove-icon-bottom { + transform: translateY(var(--icon-stroke-width)); + } + + .cart-items__table-row.removing .remove-icon-bottom { + transform: translateY(0); + } + + .cart-items__table-row.removing .remove-icon-top { + animation: removeButtonClickedIconTop var(--animation-speed) var(--animation-easing) forwards; + } + + @keyframes removeButtonClickedIconTop { + 50% { + transform: translate(0, calc(-1 * var(--icon-stroke-width))); + } + + 100% { + transform: translate(0, 0); + } + } + + .cart-items__properties { + display: block; + margin-block-start: var(--margin-2xs); + } + + .cart-items__properties dt, + .cart-items__properties dd { + display: inline; + } +{% endstylesheet %} diff --git a/snippets/cart-summary.liquid b/snippets/cart-summary.liquid new file mode 100644 index 000000000..fe5e37cc8 --- /dev/null +++ b/snippets/cart-summary.liquid @@ -0,0 +1,126 @@ +{%- doc -%} + Renders the cart summary totals. +{%- enddoc -%} + +
    + {% # We need to keep this node in place to allow morphing to work properly # %} +
    + {%- if cart.cart_level_discount_applications.size > 0 -%} + + {{ 'content.cart_subtotal' | t }} + + {{- cart.original_total_price | money -}} + + +
    +
      + {%- for discount in cart.cart_level_discount_applications -%} +
    • + + {{- 'icon-discount.svg' | inline_asset_content -}} + {{ discount.title | escape }} + + -{{ discount.total_allocated_amount | money -}} + +
    • + {%- endfor -%} +
    +
    + {%- endif -%} +
    + + {% if settings.show_cart_note or settings.show_add_discount_code %} +
    + {% if settings.show_cart_note %} + {% render 'cart-note' %} + {% endif %} + + {% if settings.show_add_discount_code %} + {% render 'cart-discount', section_id: section.id %} + {% endif %} +
    + {% endif %} + + {%- liquid + if settings.currency_code_enabled_cart_total + assign total_price = cart.total_price | money_with_currency + else + assign total_price = cart.total_price | money + endif + -%} + +
    + + {{ 'content.cart_estimated_total' | t }} + + {{ total_price }} + + + {% if settings.show_installments %} + + {% form 'cart', cart %} + {{ form | payment_terms }} + {% endform %} + + {% endif %} +
    + {% render 'tax-info', has_discounts_enabled: settings.show_add_discount_code %} +
    +
    +
    + +
    + + + {% if additional_checkout_buttons and settings.show_accelerated_checkout_buttons %} +
    + {{ content_for_additional_checkout_buttons }} +
    + {% endif %} +
    + +{% stylesheet %} + .cart-actions { + display: flex; + flex-direction: column; + gap: var(--gap-2xs); + border-block: 1px solid var(--color-border); + padding-block: var(--padding-sm); + margin-block-start: var(--margin-3xs); + } + + .cart__summary-totals:not(:has(.cart-actions)) { + margin-block-start: var(--margin-3xs); + border-block-start: 1px solid var(--color-border); + padding-block-start: var(--margin-xl); + } + + .cart__installments { + color: var(--color-foreground); + } +{% endstylesheet %} diff --git a/snippets/checkbox.liquid b/snippets/checkbox.liquid new file mode 100644 index 000000000..0cd00456a --- /dev/null +++ b/snippets/checkbox.liquid @@ -0,0 +1,50 @@ +{%- doc -%} + Renders a checkbox input and label + + @param {string} id - input id attribute + @param {string} name - input name attribute + @param {string} value - input value attribute + @param {string} label - label text + @param {boolean} checked - whether the input is checked + @param {string} events - event attributes for the input, e.g. 'on:click="/action"' + @param {boolean} disabled - whether the input is disabled + @param {string} [inputRef] - input ref attribute for use with component framework + @param {string} [labelRef] - label ref attribute for use with component framework + @param {boolean} [autofocus] - whether the input should be autofocused +{%- enddoc -%} +
    + + +
    diff --git a/snippets/collection-card.liquid b/snippets/collection-card.liquid new file mode 100644 index 000000000..bb55d0937 --- /dev/null +++ b/snippets/collection-card.liquid @@ -0,0 +1,191 @@ +{%- doc -%} + This snippet is used to render a collection card. + To be used inside a block to inherit the block object settings. + + @param {string} card_image - The image to display in the collection card + @param {string} children - The content to render inside the collection card + @param {object} collection - The collection to render the card for + @param {object} block - The block object + @param {object} section - The section object + + @example + {% render 'collection-card', + card_image: card_image, + children: children, + block: block, + collection: collection, + section: section + %} +{%- enddoc -%} + +{% liquid + assign onboarding = false + + if collection == blank + assign onboarding = true + endif +%} + +
    + + {{ collection.title }} + +
    + {{ card_image }} +
    + {{ children }} +
    +
    +
    + +{% stylesheet %} + .collection-card { + --fixed-card-height: var(--height-small); + + width: 100%; + position: relative; + } + + .collection-card > svg { + height: 100%; + width: 100%; + aspect-ratio: var(--ratio); + } + + .collection-card__inner { + width: 100%; + overflow: hidden; + position: relative; + gap: var(--collection-card-gap); + display: flex; + flex-direction: column; + } + + .collection-card--image-bg .collection-card__inner { + height: 100%; + } + + .collection-card__inner { + z-index: var(--layer-flat); + pointer-events: none; + + a, + button { + /* only allow interactive elements to be clickable separate from .collection-card__link */ + pointer-events: auto; + } + } + + /* allow all blocks to be selectable in editor preview */ + .shopify-design-mode .collection-card__content * { + pointer-events: auto; + } + + .collection-card__content { + position: relative; + display: flex; + height: 100%; + width: 100%; + max-width: 100%; + gap: var(--collection-card-gap); + flex-direction: column; + align-items: var(--horizontal-alignment); + justify-content: var(--vertical-alignment); + } + + .collection-card__link { + position: absolute; + inset: 0; + + /* allows focus outline to have radius in supported browsers */ + border-radius: var(--border-radius); + } + + /* Nested image block rules */ + + .collection-card.collection-card--image-bg { + aspect-ratio: var(--ratio); + } + + .collection-card.collection-card--image-bg .collection-card__content { + padding: var(--padding-lg); + } + + /* Bento layout rules */ + .collection-card--image-height-fixed .collection-card__image { + height: var(--fixed-card-height); + width: 100%; + } + + .collection-card--image-height-fixed.collection-card--image-bg { + height: var(--fixed-card-height); + aspect-ratio: unset; + } + + .collection-card__image .image-block__image { + object-fit: cover; + width: 100%; + height: 100%; + max-width: 100%; + } + + .collection-card--image-bg .collection-card__image { + position: absolute; + width: 100%; + height: 100%; + } + + .collection-card__image svg { + height: 100%; + width: 100%; + } + + .resource-list:not(.hidden--desktop) .collection-card--flexible-aspect-ratio { + &.collection-card.collection-card--image-bg, + &.collection-card .placeholder-svg { + aspect-ratio: 99; + } + + .collection-card__image { + aspect-ratio: 99; + height: 100%; + } + + .collection-card__inner { + display: flex; + flex-direction: column; + height: 100%; + } + + .collection-card__content { + flex-shrink: 0; + } + + &:not(.collection-card--image-bg) .collection-card__content { + height: auto; + } + } +{% endstylesheet %} diff --git a/snippets/color-schemes.liquid b/snippets/color-schemes.liquid new file mode 100644 index 000000000..cfaacdac5 --- /dev/null +++ b/snippets/color-schemes.liquid @@ -0,0 +1,99 @@ +{% style %} + {% for scheme in settings.color_schemes -%} + {% assign scheme_classes = scheme_classes | append: ', .color-' | append: scheme.id %} + {% if forloop.index == 1 %} + :root, + {% endif %} + {% assign background_brightness = scheme.settings.background | color_brightness %} + {% if background_brightness < 64 %} + {% assign opacity_5_15 = 0.15 %} + {% assign opacity_10_25 = 0.25 %} + {% assign opacity_35_55 = 0.55 %} + {% assign opacity_40_60 = 0.60 %} + {% assign opacity_30_60 = 0.60 %} + {% else %} + {% assign opacity_5_15 = 0.05 %} + {% assign opacity_10_25 = 0.1 %} + {% assign opacity_35_55 = 0.35 %} + {% assign opacity_40_60 = 0.40 %} + {% assign opacity_30_60 = 0.30 %} + {% endif %} + .color-{{ scheme.id }} { + --color-background: rgb({{ scheme.settings.background.rgba }}); + /* RGB values only to apply different opacities - Relative color values are not supported in iOS < 16.4 */ + --color-background-rgb: {{ scheme.settings.background.rgb }}; + --opacity-5-15: {{ opacity_5_15 }}; + --opacity-10-25: {{ opacity_10_25 }}; + --opacity-35-55: {{ opacity_35_55 }}; + --opacity-40-60: {{ opacity_40_60 }}; + --opacity-30-60: {{ opacity_30_60 }}; + --color-foreground: rgb({{ scheme.settings.foreground.rgba }}); + --color-foreground-rgb: {{ scheme.settings.foreground.rgb }}; + --color-foreground-heading: rgb({{ scheme.settings.foreground_heading.rgba }}); + --color-foreground-heading-rgb: {{ scheme.settings.foreground_heading.rgb }}; + --color-primary: rgb({{ scheme.settings.primary.rgba }}); + --color-primary-rgb: {{ scheme.settings.primary.rgb }}; + --color-primary-hover: rgb({{ scheme.settings.primary_hover.rgba }}); + --color-primary-hover-rgb: {{ scheme.settings.primary_hover.rgb }}; + --color-border: rgb({{ scheme.settings.border.rgba }}); + --color-border-rgb: {{ scheme.settings.border.rgb }}; + --color-shadow: rgb({{ scheme.settings.shadow.rgba }}); + --color-shadow-rgb: {{ scheme.settings.shadow.rgb }}; + --color-primary-button-text: rgb({{ scheme.settings.primary_button_text.rgba }}); + --color-primary-button-background: rgb({{ scheme.settings.primary_button_background.rgba }}); + --color-primary-button-border: rgb({{ scheme.settings.primary_button_border.rgba }}); + --color-primary-button-hover-text: rgb({{ scheme.settings.primary_button_hover_text.rgba }}); + --color-primary-button-hover-background: rgb({{ scheme.settings.primary_button_hover_background.rgba }}); + --color-primary-button-hover-border: rgb({{ scheme.settings.primary_button_hover_border.rgba }}); + --color-secondary-button-text: rgb({{ scheme.settings.secondary_button_text.rgba }}); + --color-secondary-button-background: rgb({{ scheme.settings.secondary_button_background.rgba }}); + --color-secondary-button-border: rgb({{ scheme.settings.secondary_button_border.rgba }}); + --color-secondary-button-hover-text: rgb({{ scheme.settings.secondary_button_hover_text.rgba }}); + --color-secondary-button-hover-background: rgb({{ scheme.settings.secondary_button_hover_background.rgba }}); + --color-secondary-button-hover-border: rgb({{ scheme.settings.secondary_button_hover_border.rgba }}); + --color-input-background: rgb({{ scheme.settings.input_background.rgba }}); + --color-input-text: rgb({{ scheme.settings.input_text_color.rgba }}); + --color-input-text-rgb: {{ scheme.settings.input_text_color.rgb }}; + --color-input-border: rgb({{ scheme.settings.input_border_color.rgba }}); + --color-input-hover-background: rgb({{ scheme.settings.input_hover_background.rgba }}); + --color-variant-background: rgb({{ scheme.settings.variant_background_color.rgba }}); + --color-variant-border: rgb({{ scheme.settings.variant_border_color.rgba }}); + --color-variant-text: rgb({{ scheme.settings.variant_text_color.rgba }}); + --color-variant-text-rgb: {{ scheme.settings.variant_text_color.rgb }}; + --color-variant-hover-background: rgb({{ scheme.settings.variant_hover_background_color.rgba }}); + --color-variant-hover-text: rgb({{ scheme.settings.variant_hover_text_color.rgba }}); + --color-variant-hover-border: rgb({{ scheme.settings.variant_hover_border_color.rgba }}); + --color-selected-variant-background: rgb({{ scheme.settings.selected_variant_background_color.rgba }}); + --color-selected-variant-border: rgb({{ scheme.settings.selected_variant_border_color.rgba }}); + --color-selected-variant-text: rgb({{ scheme.settings.selected_variant_text_color.rgba }}); + --color-selected-variant-hover-background: rgb({{ scheme.settings.selected_variant_hover_background_color.rgba }}); + --color-selected-variant-hover-text: rgb({{ scheme.settings.selected_variant_hover_text_color.rgba }}); + --color-selected-variant-hover-border: rgb({{ scheme.settings.selected_variant_hover_border_color.rgba }}); + + --input-disabled-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10)); + --input-disabled-border-color: rgb(var(--color-foreground-rgb) / var(--opacity-5-15)); + --input-disabled-text-color: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + --color-foreground-muted: rgb(var(--color-foreground-rgb) / var(--opacity-60)); + --font-h1--color: var(--color-foreground-heading); + --font-h2--color: var(--color-foreground-heading); + --font-h3--color: var(--color-foreground-heading); + --font-h4--color: var(--color-foreground-heading); + --font-h5--color: var(--color-foreground-heading); + --font-h6--color: var(--color-foreground-heading); + + /* Shadows */ + {% if settings.drawer_drop_shadow %} + --shadow-drawer: 0px 4px 20px rgb(var(--color-shadow-rgb) / var(--opacity-15)); + {% endif %} + {% if settings.popover_drop_shadow %} + --shadow-blur: 20px; + --shadow-popover: 0px 4px 20px rgb(var(--color-shadow-rgb) / var(--opacity-15)); + {% endif %} + } + {% endfor %} + + {{ scheme_classes | prepend: 'body' }} { + color: var(--color-foreground); + background-color: var(--color-background); + } +{% endstyle %} diff --git a/snippets/contact-form.liquid b/snippets/contact-form.liquid new file mode 100644 index 000000000..27fc2f646 --- /dev/null +++ b/snippets/contact-form.liquid @@ -0,0 +1,170 @@ +{%- doc -%} + Renders a contact form with name, email, phone, and comment fields. + + @param {object} settings - Block settings, required for the 'spacing-style' and 'size-style' snippets. + @param {string} submit_button - HTML for the submit button, rendered via a `content_for` block. + + @example + {% render 'contact-form', settings: block.settings, submit_button: content_for_submit_button %} +{%- enddoc -%} + +
    + {% assign form_id = block.id | default: section.id | prepend: 'ContactForm-' %} + + {%- form 'contact', id: form_id, class: 'contact-form__form' -%} + {%- if form.errors -%} +
    + {{- 'icon-error.svg' | inline_asset_content -}} + + {{- form.errors.translated_fields.email | capitalize }} + {{ form.errors.messages.email -}} +
    + {%- endif -%} + + {%- if form.posted_successfully? -%} +
    + {{- 'icon-checkmark.svg' | inline_asset_content -}} + {{- 'blocks.contact_form.post_success' | t -}} +
    + {%- endif -%} + +
    + + + + + +
    + + + + + + + + {{ submit_button }} + {%- endform -%} +
    + +{% stylesheet %} + .contact-form__form { + display: flex; + flex-direction: column; + gap: var(--gap-md); + } + + .contact-form__form-row { + display: flex; + flex-direction: column; + gap: var(--gap-md); + + @media screen and (min-width: 750px) { + flex-direction: row; + align-items: center; + } + } + + .contact-form__input { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + color: var(--color-foreground); + background-color: var(--color-input-background); + padding: var(--padding-lg) var(--padding-xl); + border-radius: var(--style-border-radius-inputs); + border: var(--style-border-width-inputs) solid var(--color-input-border); + -webkit-font-smoothing: antialiased; + } + + .contact-form__input--textarea { + resize: vertical; + min-height: var(--input-textarea-min-height); + } + + .contact-form__error, + .contact-form__success { + display: flex; + align-items: center; + gap: var(--gap-xs); + } +{% endstylesheet %} diff --git a/snippets/divider.liquid b/snippets/divider.liquid new file mode 100644 index 000000000..27edd0d65 --- /dev/null +++ b/snippets/divider.liquid @@ -0,0 +1,54 @@ +{%- doc -%} + Renders a divider line, used to visually separate content. + + @param {string} id - A unique ID for the divider, linking it to a block or section. + @param {object} settings - An object containing style settings for the divider. + + @param {string} [settings.alignment_horizontal] - The horizontal alignment of the divider ('left', 'center', or + 'right'). Defaults to 'center'. + @param {number} [settings.thickness] - The thickness of the divider line in pixels. + @param {string} [settings.corner_radius] - The corner radius of the divider, e.g., 'rounded'. + @param {number} [settings.width_percent] - The width of the divider as a percentage of its container. + + @param {boolean} [full_width] - When `true`, the divider spans the full width of its container. + @param {boolean} [attributes] - When `true`, render block.shopify_attributes on the divider container. +{%- enddoc -%} + +
    + +
    + +{% stylesheet %} + .divider { + align-self: stretch; + display: flex; + align-items: center; + justify-content: var(--divider-justify-content); + } + + .divider__line { + border-bottom: var(--divider-border-thickness) solid var(--color-border); + border-right: var(--divider-border-thickness) solid var(--color-border); + border-radius: calc(var(--style-border-radius-sm) * var(--divider-border-rounded)); + flex-basis: var(--divider-flex-basis); + min-height: var(--divider-flex-basis); + } +{% endstylesheet %} diff --git a/snippets/drawer-localization.liquid b/snippets/drawer-localization.liquid new file mode 100644 index 000000000..bf24e2f68 --- /dev/null +++ b/snippets/drawer-localization.liquid @@ -0,0 +1,125 @@ +{%- doc -%} + Renders a localization component for the drawer. + The component must be used inside a component. It relies on event bindings from the parent component. + + @param {boolean} [show_country] - Whether to show the country selector + @param {boolean} [show_language] - Whether to show the language selector + @param {boolean} [country_style] - Whether to show the country flag + + @example + {% render 'drawer-localization', country_style: true %} +{%- enddoc -%} + +{% liquid + assign background_brightness = block.settings.color_scheme.settings.background | color_brightness + if background_brightness < 64 + assign flag_shadow_size = 4 + else + assign flag_shadow_size = 2 + endif + + assign localization_font = '--menu-localization-font: var(--font-[localization_font]--family); ' | replace: '[localization_font]', section.settings.localization_font + assign color_shadow = '--color-shadow: rgb(var(--color-foreground-rgb) / var(--opacity-10-25));' + assign form_style = localization_font | append: color_shadow +%} + +{% if show_language and show_country == false %} + +{% else %} + +
    + + + +
    +
    +{% endif %} diff --git a/snippets/dropdown-localization.liquid b/snippets/dropdown-localization.liquid new file mode 100644 index 000000000..e24383e38 --- /dev/null +++ b/snippets/dropdown-localization.liquid @@ -0,0 +1,92 @@ +{%- doc -%} + Determines whether to wrap the localization-form in a dropdown-component and passes variables to it. + + @param {boolean} [show_country] - Whether to show the country selector. + @param {boolean} [show_language] - Whether to show the language selector. + @param {string} [country_style] - The style of the country selector. + @param {string} localization_position - { 'right' | 'left' } The position of the localization picker. +{%- enddoc -%} + +{% liquid + assign background_brightness = section.settings.color_scheme.settings.background | color_brightness + if background_brightness < 64 + assign shadow_size = 4 + else + assign shadow_size = 2 + endif + + assign localization_font = '--menu-localization-font: var(--font-[localization_font]--family); ' | replace: '[localization_font]', section.settings.localization_font + assign localization_font_size = '--menu-localization-font-size: [localization_font_size]; ' | replace: '[localization_font_size]', section.settings.localization_font_size + assign color_shadow = '--color-shadow: rgb(var(--color-foreground-rgb) / var(--opacity-10-25));' + assign form_style = localization_font | append: localization_font_size | append: color_shadow +%} + +{% if show_language and show_country == false %} + +{% elsif show_country %} + + + + + +{% endif %} diff --git a/snippets/editorial-collection-grid.liquid b/snippets/editorial-collection-grid.liquid new file mode 100644 index 000000000..65e8f215e --- /dev/null +++ b/snippets/editorial-collection-grid.liquid @@ -0,0 +1,117 @@ +{%- doc -%} + Renders a grid and places items inside of it using an editorial layout. + + @param {object} items - An array of HTML strings for the collection list items + + @example + {% render 'editorial-collection-grid', items: items %} +{%- enddoc -%} + +
    +
    + + {% for item in items %} + {% liquid + assign current_grid_index = forloop.index0 | divided_by: 8 + assign current_item_index = forloop.index0 | modulo: 8 + + case current_item_index + when 0 + assign grid_column = '2 / span 4' + assign grid_row = 1 + assign grid_row_span = 5 + when 1 + assign grid_column = '7 / span 5' + assign grid_row = 3 + assign grid_row_span = 5 + when 2 + assign grid_column = '1 / span 8' + assign grid_row = 9 + assign grid_row_span = 6 + when 3 + assign grid_column = '3 / span 8' + assign grid_row = 16 + assign grid_row_span = 6 + when 4 + assign grid_column = '7 / span 5' + assign grid_row = 23 + assign grid_row_span = 5 + when 5 + assign grid_column = '2 / span 4' + assign grid_row = 25 + assign grid_row_span = 5 + when 6 + assign grid_column = '5 / span 8' + assign grid_row = 31 + assign grid_row_span = 6 + when 7 + assign grid_column = '2 / span 8' + assign grid_row = 38 + assign grid_row_span = 6 + endcase + + assign full_grid_rows = current_grid_index | times: 44 + assign grid_row = grid_row | plus: full_grid_rows + %} +
    + {{ item }} +
    + {% endfor %} +
    + +{% stylesheet %} + .editorial-collection__grid { + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-auto-rows: 1fr; + gap: var(--gap-xl); + + .resource-list__item, + .collection-card { + height: 100%; + } + } + + .editorial-collection__spacer { + aspect-ratio: 1; + } + + @media (max-width: 768px) { + .editorial-collection__grid { + display: flex; + flex-direction: column; + gap: var(--gap-2xl); + } + + .editorial-collection__spacer { + display: none; + } + + .editorial-collection__item-0 { + width: 66%; + align-self: flex-start; + aspect-ratio: 4 / 5; + } + + .editorial-collection__item-1 { + width: 83%; + align-self: flex-end; + aspect-ratio: 5 / 5; + } + + .editorial-collection__item-2 { + width: 83%; + align-self: flex-start; + aspect-ratio: 8 / 6; + } + + .editorial-collection__item-3 { + width: 100%; + align-self: center; + aspect-ratio: 8 / 6; + } + } +{% endstylesheet %} diff --git a/snippets/editorial-product-grid.liquid b/snippets/editorial-product-grid.liquid new file mode 100644 index 000000000..470917dd8 --- /dev/null +++ b/snippets/editorial-product-grid.liquid @@ -0,0 +1,124 @@ +{%- doc -%} + Renders a grid and places items inside of it using an editorial layout. + + @param {object} items - An array of HTML strings for the product list items + + @example + {% render 'editorial-product-grid', items: items %} +{%- enddoc -%} + +
    +
    + + {% for item in items %} + {% liquid + assign current_grid_index = forloop.index0 | divided_by: 8 + assign current_item_index = forloop.index0 | modulo: 8 + + case current_item_index + when 0 + assign grid_column = '1 / span 7' + assign grid_row = 1 + assign grid_row_span = 6 + when 1 + assign grid_column = '9 / span 4' + assign grid_row = 5 + assign grid_row_span = 5 + when 2 + assign grid_column = '2 / span 5' + assign grid_row = 8 + assign grid_row_span = 5 + when 3 + assign grid_column = '5 / span 8' + assign grid_row = 14 + assign grid_row_span = 6 + when 4 + assign grid_column = '1 / span 7' + assign grid_row = 21 + assign grid_row_span = 6 + when 5 + assign grid_column = '9 / span 4' + assign grid_row = 25 + assign grid_row_span = 5 + when 6 + assign grid_column = '2 / span 5' + assign grid_row = 28 + assign grid_row_span = 5 + when 7 + assign grid_column = '3 / span 8' + assign grid_row = 34 + assign grid_row_span = 6 + endcase + + assign full_grid_rows = current_grid_index | times: 40 + assign grid_row = grid_row | plus: full_grid_rows + %} +
    + {{ item }} +
    + {% endfor %} +
    + +{% stylesheet %} + .editorial-product__grid { + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-auto-rows: 1fr; + gap: var(--gap-xl); + + /* Make the aspect ratio super high on width, then increase the height of + * slideshow containers until they fill all the available space */ + .card-gallery { + --gallery-aspect-ratio: 99 !important; + } + + .card-gallery, + slideshow-component, + slideshow-container, + slideshow-slides { + height: 100%; + } + } + + .editorial-product__spacer { + aspect-ratio: 1; + } + + @media (max-width: 768px) { + .editorial-product__grid { + display: flex; + flex-direction: column; + gap: var(--gap-2xl); + } + + .editorial-product__spacer { + display: none; + } + + .editorial-product__item-0 { + width: 83%; + align-self: flex-start; + aspect-ratio: 7 / 6; + } + + .editorial-product__item-1 { + width: 83%; + align-self: flex-end; + aspect-ratio: 4 / 5; + } + + .editorial-product__item-2 { + width: 66%; + align-self: flex-start; + aspect-ratio: 5 / 5; + } + + .editorial-product__item-3 { + width: 100%; + aspect-ratio: 8 / 6; + } + } +{% endstylesheet %} diff --git a/snippets/facets-actions.liquid b/snippets/facets-actions.liquid new file mode 100644 index 000000000..702064ad4 --- /dev/null +++ b/snippets/facets-actions.liquid @@ -0,0 +1,220 @@ +{%- doc -%} + Renders the facets actions + + @param {string} results_url - the url to remove the filters + @param {boolean} is_active - whether the clear all button is active + @param {number} products_count - the number of products in the results + @param {string} [form_component] - the form component to use for the clear all button + @param {boolean} [should_show_clear_all] - whether to show the clear all button + @param {number} [shadow_opacity] - the opacity of the shadow for the sticky action bar +{%- enddoc -%} + +
    + {% if should_show_clear_all %} + + + + {% endif %} + + {% if products_count > 0 %} + + {% endif %} +
    + +{% stylesheet %} + /* Facets - Actions */ + .facets__actions { + --to-top-gradient-background: linear-gradient( + to top, + rgb(var(--color-background-rgb) / var(--opacity-90)), + rgb(var(--color-background-rgb) / var(--opacity-80)), + rgb(var(--color-background-rgb) / var(--opacity-40)), + transparent + ); + + order: 1; + position: sticky; + bottom: 0; + display: flex; + justify-content: space-between; + align-items: stretch; + gap: var(--gap-sm); + background-image: var(--to-top-gradient-background); + z-index: var(--facets-sticky-z-index); + padding-block-start: var(--padding-xs); + padding-block-end: var(--padding-md); + padding-inline: var(--padding-lg); + margin-top: auto; + } + + .facets:not(.facets--drawer) .facets__actions { + @media screen and (min-width: 750px) { + position: static; + } + } + + .facets--vertical .facets__actions { + padding-inline: 0; + justify-content: center; + } + + .facets--horizontal .facets__actions { + @media screen and (min-width: 750px) { + order: 0; + bottom: auto; + position: static; + padding: 0; + z-index: var(--layer-flat); + flex-shrink: 0; + align-items: center; + margin-top: initial; + background-image: none; + } + } + + .facets--horizontal .facets__actions--active::before { + @media screen and (min-width: 750px) { + content: ''; + border-inline-start: var(--style-border-width) solid var(--color-border); + height: var(--font-paragraph--size); + position: absolute; + } + } + + /* Clear button */ + .facets__clear { + display: none; + } + + .facets--horizontal .facets__clear { + @media screen and (min-width: 750px) { + width: 100%; + justify-content: flex-end; + padding: 0 var(--facets-clear-padding) var(--facets-clear-padding) 0; + cursor: pointer; + } + } + + .facets__clear--active { + @media screen and (min-width: 750px) { + display: flex; + } + } + + .clear-filter:hover { + text-decoration: underline; + background-color: transparent; + } + + /* Clear all button */ + .facets__clear-all { + display: none; + cursor: pointer; + min-width: var(--facets-clear-all-min-width); + transition: transform var(--animation-values), opacity var(--animation-values); + opacity: 0; + transform: translateY(100%); + flex-grow: 1; + padding-block: var(--padding-lg); + } + + .facets:not(.facets--drawer) .facets__clear-all { + box-shadow: none; + } + + .facets--horizontal .facets__clear-all { + @media screen and (min-width: 750px) { + --facets-clear-all-min-width: var(--minimum-touch-target); + --button-color: var(--color-primary); + + text-decoration: underline transparent 0.075em; + text-underline-offset: 0.125em; + width: auto; + transform: none; + opacity: 1; + height: var(--minimum-touch-target); + align-items: center; + flex-grow: 0; + transition: text-decoration-color var(--animation-speed) var(--animation-easing); + } + } + + .facets--horizontal .facets__clear-all:hover { + @media screen and (min-width: 750px) { + --button-color: var(--color-primary-hover); + } + } + + @starting-style { + .facets__clear-all { + opacity: 1; + transform: translateY(0); + } + } + + .facets__clear-all.active { + transform: translateY(0); + opacity: 1; + display: grid; + } + + .facets--horizontal .facets__clear-all.active { + @media screen and (min-width: 750px) { + padding-block: 0; + padding-inline: var(--facets-form-horizontal-gap); + background-color: transparent; + position: static; + transform: none; + } + } + + @starting-style { + .facets__clear-all.active { + opacity: 0; + transform: translateY(100%); + } + + .facets--horizontal .facets__clear-all.active { + @media screen and (min-width: 750px) { + opacity: 1; + transform: none; + } + } + } + + .facets__see-results { + min-width: var(--facets-see-results-min-width); + flex-grow: 1; + padding-block: var(--padding-lg); + } + + .facets:not(.facets--drawer) .facets__see-results { + @media screen and (min-width: 750px) { + display: none; + } + } +{% endstylesheet %} diff --git a/snippets/filter-remove-buttons.liquid b/snippets/filter-remove-buttons.liquid new file mode 100644 index 000000000..196270670 --- /dev/null +++ b/snippets/filter-remove-buttons.liquid @@ -0,0 +1,178 @@ +{%- doc -%} + Renders filter remove buttons. + + Accepts: + + @param {object} filters - The filters to render + @param {boolean} show_filter_label - Whether to show the filter label + @param {string} results_url - The results URL + @param {boolean} should_show_clear_all - Whether to show the clear all button +{%- enddoc -%} + +
    + {%- for filter in filters -%} + {%- liquid + assign is_first_filter = forloop.first + -%} + {% if filter.type == 'price_range' and filter.min_value.value != null or filter.max_value.value != null %} + {%- liquid + assign is_active = true + -%} + + {%- if filter.min_value.value != null and filter.max_value.value != null %} + {{- filter.min_value.value | money -}} + – + {{- filter.max_value.value | money -}} + {%- elsif filter.min_value.value != null -%} + {{ filter.min_value.value | money }}–{{ filter.range_max | money }} + {%- elsif filter.max_value.value != null -%} + {{- 0 | money -}} + – + {{- filter.max_value.value | money -}} + {%- endif -%} + + {{- 'icon-filters-close.svg' | inline_asset_content -}} + + {{ 'actions.remove' | t }} + + {% else %} + {%- for value in filter.active_values -%} + {%- liquid + assign is_active = true + -%} + + {% if value.swatch %} + {% render 'swatch', swatch: value.swatch, mode: 'pill' %} + {% endif %} + + {% if filter.type == 'boolean' or show_filter_label %} + {{ filter.label | escape }}: {{ value.label | escape }} + {% else %} + {{ value.label | escape }} + {% endif %} + + + {{- 'icon-filters-close.svg' | inline_asset_content -}} + + {{ 'actions.remove' | t }} + + {%- endfor -%} + {% endif %} + {%- endfor -%} + {% if should_show_clear_all and is_active %} + + + + {% endif %} +
    + +{% stylesheet %} + /* Facets - Remove buttons */ + .facets-remove { + --variant-picker-swatch-width: 20px; + --variant-picker-swatch-height: 20px; + + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--gap-xs); + padding: 0 var(--drawer-padding); + margin-block-start: var(--margin-2xs); + margin-block-end: var(--margin-md); + + @media screen and (min-width: 750px) { + --variant-picker-swatch-width: 16px; + --variant-picker-swatch-height: 16px; + + gap: var(--gap-2xs); + } + } + + .facets__clear-all-link { + --button-color: var(--color-primary); + + border: none; + background-color: transparent; + padding: var(--padding-xs); + min-width: fit-content; + color: var(--button-color); + transition: text-decoration-color var(--animation-speed) var(--animation-easing), + color var(--animation-speed) var(--animation-easing); + } + + .facets__clear-all-link:hover { + --button-color: var(--color-primary-hover); + + color: var(--button-color); + text-decoration-color: var(--button-color); + } + + .facets:not(.facets--drawer) .facets-remove--mobile-and-vertical { + @media screen and (min-width: 750px) { + padding: 0; + } + } + + .facets--horizontal .facets-remove--mobile-and-vertical { + @media screen and (min-width: 750px) { + display: none; + } + } + + .facets-remove:not(:has(facet-remove-component)) { + display: none; + margin: 0; + } + + .facets-remove__pill { + .svg-wrapper, + .swatch { + flex-shrink: 0; + } + } + + .facets--horizontal .facets-remove { + @media screen and (min-width: 750px) { + display: none; + } + } +{% endstylesheet %} diff --git a/snippets/filters-toggle.liquid b/snippets/filters-toggle.liquid new file mode 100644 index 000000000..8bbdfa3cd --- /dev/null +++ b/snippets/filters-toggle.liquid @@ -0,0 +1,149 @@ +{%- doc -%} + Renders the sorting component. + + @param {boolean} enable_filtering - Whether to enable filtering + @param {number} padding-block-start - The padding-block-start value + @param {number} padding-block-end - The padding-block-end value + @param {number} total_active_values - The total number of active values + @param {string} section_id - The section ID + @param {object} results - The results of the search + @param {string} sort_by - The current sort by +{%- enddoc -%} + +
    + {% if enable_filtering %} +
    + +
    + {% endif %} + +
    + {% if block.settings.enable_filtering == false and block.settings.enable_sorting %} + {% render 'sorting', + results: results, + sort_by: sort_by, + filter_style: block.settings.filter_style, + suffix: 'mobile', + section_id: section_id, + should_use_select_on_mobile: false + %} + {% endif %} + {% if block.settings.enable_grid_density %} + {% render 'grid-density-controls', viewport: 'mobile' %} + {% endif %} +
    +
    + +{% stylesheet %} + /* Facets - Toggle */ + .facets-toggle { + --icon-offset: -3px; + + display: flex; + justify-content: space-between; + align-items: center; + height: var(--minimum-touch-target); + margin: var(--facets-margin); + padding-block: var(--facets-inner-padding-block); + padding-inline: var(--facets-inner-padding-inline); + + @media screen and (min-width: 750px) { + display: none; + } + } + + .facets-toggle__wrapper { + margin-left: var(--icon-offset); + } + + .facets-toggle__button { + box-shadow: none; + + @media screen and (min-width: 750px) { + display: none; + } + } + + /* Filter count */ + .filter-count-bubble { + position: relative; + width: 20px; + aspect-ratio: 1; + border-radius: 50%; + display: grid; + line-height: normal; + place-content: center; + color: var(--color-foreground); + border: var(--icon-stroke-width) solid var(--color-background); + } + + .facets-mobile__title-wrapper .h3 { + margin-block-end: 0; + display: inline-flex; + align-items: center; + gap: var(--gap-xs); + } + + .facets-mobile__title-wrapper .filter-count-bubble { + width: 22px; + height: 22px; + } + + .facets-mobile__title-wrapper .filter-count-bubble__text { + font-size: var(--font-size--xs); + } + + .filter-count-bubble__background { + position: absolute; + inset: 0; + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10-25)); + border-radius: var(--style-border-radius-50); + } + + .filter-count-bubble__text { + font-size: 11px; + font-weight: var(--font-paragraph--weight); + aspect-ratio: 1 / 1; + } + + .facets-toggle--no-filters { + @media screen and (max-width: 749px) { + justify-content: unset !important; + + & > .facets-mobile-wrapper { + width: 100%; + } + } + } +{% endstylesheet %} diff --git a/snippets/fonts.liquid b/snippets/fonts.liquid new file mode 100644 index 000000000..e48f6a991 --- /dev/null +++ b/snippets/fonts.liquid @@ -0,0 +1,49 @@ +{%- unless settings.type_body_font.system? + and settings.type_subheading_font.system? + and settings.type_heading_font.system? +-%} + +{%- endunless -%} + +{% # theme-check-disable %} +{%- unless settings.type_body_font.system? -%} + +{%- endunless -%} +{%- unless settings.type_subheading_font.system? -%} + +{%- endunless -%} +{%- unless settings.type_heading_font.system? -%} + +{%- endunless -%} +{%- unless settings.type_accent_font.system? -%} + +{%- endunless -%} +{% # theme-check-enable %} diff --git a/snippets/gap-style.liquid b/snippets/gap-style.liquid new file mode 100644 index 000000000..99b91ea4f --- /dev/null +++ b/snippets/gap-style.liquid @@ -0,0 +1,25 @@ +{%- doc -%} + Renders the CSS variables for the `gap` styles needed for responsive scaling. + Intended for use with the `gap-style` class. + + @param {number} value - The base or desktop gap value to use, in pixels. + @param {string} [name] - The name of the CSS variable to set. Default: 'gap' + @param {number} [scale_min] - Value above which gap scaling will be applied. Default: 20 + @param {boolean} [disable_scaling] - If true, disables scaling and outputs the original value. + + @example +
    +{%- enddoc -%} + +{%- liquid + assign min = scale_min | default: 24 + assign name = name | default: 'gap' +-%} + +{%- if value != blank -%} + {%- if disable_scaling != true and value > min -%} + --{{ name }}: max({{ min }}px, calc(var(--gap-scale, 1.0) * {{ value }}px)); + {%- else -%} + --{{ name }}: {{ value }}px; + {%- endif -%} +{%- endif -%} diff --git a/snippets/grid-density-controls.liquid b/snippets/grid-density-controls.liquid new file mode 100644 index 000000000..2dbc5f169 --- /dev/null +++ b/snippets/grid-density-controls.liquid @@ -0,0 +1,179 @@ +{%- doc -%} + Renders the grid density controls. + + @param {string} viewport - The viewport to render the controls for, either 'mobile' or 'desktop'. + + @example + {% render 'grid-density-controls', viewport: 'desktop' %} +{%- enddoc -%} + +
    +
    + + {{ 'content.grid_view.grid_fieldset' | t }} + + + {% if viewport == 'mobile' %} + + + + + {% elsif viewport == 'desktop' %} + + + + {% endif %} +
    +
    + +{% stylesheet %} + .column-options-wrapper { + --icon-offset: -3px; + + display: flex; + gap: var(--gap-sm); + min-width: fit-content; + justify-content: flex-end; + height: var(--minimum-touch-target); + align-items: center; + margin-right: var(--icon-offset); + } + + .column-options-wrapper:only-child { + margin-left: auto; + } + + .facets__form-wrapper > .column-options-wrapper:first-child { + margin-left: auto; + } + + .facets .column-options-wrapper { + display: none; + + @media screen and (min-width: 750px) { + display: flex; + } + } + + .column-options { + display: flex; + flex-wrap: wrap; + gap: var(--gap-xs); + margin: 0; + padding: 0; + border: none; + + @media screen and (min-width: 750px) { + gap: var(--gap-2xs); + } + } + + .column-options__option { + display: none; + position: relative; + } + + .column-options__option:has(.column-picker-mobile--single), + .column-options__option:has(.column-picker-mobile--double) { + @media screen and (max-width: 749px) { + display: flex; + } + } + + .column-options__option:has(.column-picker--default), + .column-options__option:has(.column-picker--zoom-out) { + @media screen and (min-width: 750px) { + display: flex; + } + } + + .column-options__legend { + padding: 0; + margin: 0; + } + + .column-options__option-input { + /* this is a repeating pattern a bit with the variant picker buttons */ + + /* remove the checkbox from the page flow */ + position: absolute; + + /* set the dimensions to match those of the label */ + inset: 0; + + /* hide it */ + opacity: 0; + margin: 0; + cursor: pointer; + } + + .column-picker { + color: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + padding: var(--padding-2xs); + border-radius: var(--style-border-radius-xs); + transition: background-color var(--animation-speed) ease, color var(--animation-speed) ease; + } + + .column-options__option:hover .column-picker { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + } + + .column-options__option-input:checked ~ .column-picker { + color: rgb(var(--color-foreground-rgb)); + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + } +{% endstylesheet %} diff --git a/snippets/group.liquid b/snippets/group.liquid new file mode 100644 index 000000000..716a43aa6 --- /dev/null +++ b/snippets/group.liquid @@ -0,0 +1,90 @@ +{%- doc -%} + Renders block content for all blocks that extend the group block. + + @param {string} children - The DOM content of the group block. + @param {object} settings - The settings of the group block. + @param {string} shopify_attributes - String with Shopify attributes for the editor. + @param {string} [class] - Custom classes for the group block. + @param {string} [style] - Custom inline styles for the group block. + + @example + {% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %} +{%- enddoc -%} + +
    + {%- if settings.link != blank -%} + + {%- endif -%} + +
    + {% render 'background-media', + background_media: settings.background_media, + background_video: settings.video, + background_video_position: settings.video_position, + background_image: settings.background_image, + background_image_position: settings.background_image_position, + placeholder: settings.placeholder + %} + {% if settings.toggle_overlay %} + {% render 'overlay', settings: settings, layer: '0' %} + {% endif %} +
    + +
    + {{- children -}} +
    +
    + +{% stylesheet %} + .group-block__link { + position: absolute; + inset: 0; + } + + .group-block__link ~ :is(.group-block-content, .group-block__media-wrapper) { + pointer-events: none; + + :is(a, button, input, textarea, select) { + pointer-events: auto; + } + } + + /* Needs the .group-block__link ~ to be specific enough to take effect. */ + .group-block__link ~ .group-block-content--design-mode { + pointer-events: auto; + } +{% endstylesheet %} diff --git a/snippets/header-actions.liquid b/snippets/header-actions.liquid new file mode 100644 index 000000000..248106014 --- /dev/null +++ b/snippets/header-actions.liquid @@ -0,0 +1,280 @@ + + + + {% if shop.customer_accounts_enabled %} + {% render 'account-popover' %} + {% render 'account-drawer' %} + {% endif %} + + {% if settings.cart_type == 'drawer' and template.name != 'cart' %} + {% render 'cart-drawer' %} + {% else %} + + {% render 'cart-icon-component' %} + + {% endif %} + + +{% stylesheet %} + .cart-drawer { + --cart-drawer-padding: var(--padding-lg) var(--padding-xl); + --cart-drawer-padding-desktop: var(--padding-xl) var(--padding-2xl); + --cart-font-size--2xs: var(--font-size--2xs); + --cart-font-size--xs: var(--font-size--xs); + --cart-font-size--sm: var(--font-size--sm); + --cart-font-size--md: var(--font-size--md); + --cart-font-size--2xl: var(--font-size--2xl); + } + + .cart-drawer__dialog { + position: fixed; + border-radius: 0; + width: var(--sidebar-width); + max-width: 95vw; + height: 100%; + margin: 0 0 0 auto; + padding: 0; + border-left: var(--style-border-drawer); + box-shadow: var(--shadow-drawer); + background-color: var(--color-background); + } + + /* Needed to ensure the drawer is full height */ + .cart-drawer__dialog:modal { + max-height: 100dvh; + overflow-y: hidden; + } + + .cart-drawer__inner { + height: 100%; + } + + .cart-drawer__content { + padding: 0; + background-color: var(--color-background); + display: flex; + flex-direction: column; + flex-grow: 1; + overflow-y: auto; + } + + .cart-drawer__heading { + display: flex; + align-items: center; + gap: var(--gap-xs); + } + + .cart-drawer__close-button { + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + display: flex; + align-items: center; + justify-content: center; + margin-right: calc(var(--padding-sm) * -1); + } + + .cart-drawer__close-button svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .cart-drawer--empty .cart-drawer__content { + text-align: center; + min-height: auto; + } + + .cart-drawer--empty .cart-drawer__heading { + margin-bottom: var(--margin-md); + } + + .cart-drawer__items .cart-items__table-row { + padding-bottom: var(--gap-xl); + border-bottom: var(--style-border-width) solid var(--color-border); + margin-bottom: var(--gap-xl); + } + + .cart-drawer__items .cart-items__table-row:has(+ .cart-items__nested-line) { + border-bottom: none; + margin-bottom: 0; + } + + .cart-drawer__items .cart-items__table-row:last-child { + border-bottom: none; + } + + .cart-drawer__summary { + --cart-drawer-summary-padding: var(--padding-lg); + + display: flex; + flex-direction: column; + align-items: center; + gap: var(--gap-2xl); + padding: var(--cart-drawer-summary-padding); + margin-top: auto; + background-color: var(--color-background); + /* stylelint-disable-next-line color-named */ + mask-image: linear-gradient(to bottom, transparent, black var(--cart-drawer-summary-padding)); + + @media screen and (min-width: 750px) { + --cart-drawer-summary-padding: var(--padding-2xl); + } + } + + .cart-drawer__summary .cart__summary-totals:not(:has(.cart__original-total-container:empty)) { + border-block-start: var(--style-border-width) solid var(--color-border); + padding-block-start: var(--padding-2xl); + } + + .cart-drawer__summary .cart-note { + @media screen and (min-width: 750px) { + margin-block-start: var(--margin-3xs); + } + } + + .cart-drawer__heading--empty { + display: flex; + justify-content: center; + } + + .cart-drawer__items { + display: flex; + flex-direction: column; + padding-inline: var(--cart-drawer-padding); + overflow-y: auto; + + @media screen and (min-width: 750px) { + padding-inline: var(--cart-drawer-padding-desktop); + } + } + + .cart-drawer__items .cart-items__table-row { + padding-bottom: var(--gap-xl); + border-bottom: var(--style-border-width) solid var(--color-border); + margin-bottom: var(--gap-xl); + } + + .cart-drawer__items .cart-items__table-row:last-child { + border-bottom: none; + padding-block-end: 0; + margin-block-end: 0; + } + + .cart-drawer--empty .cart-drawer__inner { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100dvh; + margin-top: 0; + } + + .cart-drawer:not(:has(.cart-form)) .cart-drawer__content { + justify-content: center; + } + + .cart-drawer--empty .cart-drawer__header { + justify-content: right; + border-bottom: none; + padding-bottom: 0; + } + + .cart-drawer--empty .cart-drawer__heading { + text-align: center; + } + + .cart-drawer:not(:has(.cart-form)) .cart-items__wrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + } + + header-actions { + display: flex; + + @media screen and (max-width: 749px) { + justify-self: flex-end; + } + } + + .header__column--right header-actions { + margin-inline-start: calc(var(--gap-md) * -1); + } + + .header-actions__action { + --button-color: var(--color-foreground); + + cursor: pointer; + display: flex; + justify-content: center; + } + + .header-actions__action .svg-wrapper { + height: var(--button-size); + width: var(--button-size); + } + + .header-actions__action svg { + width: var(--icon-size-md); + height: var(--icon-size-md); + } + + .header-actions__cart-icon { + --cart-bubble-size: 20px; + --cart-bubble-top: 4.5px; + --cart-bubble-right: 2.5px; + + position: relative; + } + + .header-actions__cart-icon .cart-bubble { + position: absolute; + width: var(--cart-bubble-size, 20px); + top: var(--cart-bubble-top); + right: var(--cart-bubble-right); + } + + .header-actions__cart-icon .cart-bubble__text, + .cart-drawer__heading .cart-bubble__text { + font-family: var(--font-paragraph--family); + font-weight: var(--font-paragraph--weight); + } + + .header-actions__cart-icon.header-actions__cart-icon--has-cart svg { + /* Create donut mask where the cart bubble sits */ + mask: radial-gradient( + calc(var(--cart-bubble-size) + 2px) at calc(100% - var(--cart-bubble-right)) var(--cart-bubble-top), + transparent 45.45%, + white 45.45%, + white 100% + ); + } + + .cart-drawer__heading .cart-bubble__background { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10-25)); + } + + .cart-drawer__heading .cart-bubble__text { + color: var(--color-foreground); + font-size: var(--font-size--xs); + } + + .cart-bubble--animating .cart-bubble__background { + animation: grow var(--animation-speed) var(--animation-easing); + } + + .cart-bubble--animating .cart-bubble__text { + animation: cartBubbleSlideIn var(--animation-speed) var(--animation-easing); + } +{% endstylesheet %} diff --git a/snippets/header-drawer.liquid b/snippets/header-drawer.liquid new file mode 100644 index 000000000..9402aeaf1 --- /dev/null +++ b/snippets/header-drawer.liquid @@ -0,0 +1,1117 @@ +{%- doc -%} + Renders a header drawer menu triggered by the top details element. + + @param {object} linklist - The linklist to render + @param {string} [class] - Additional classes to add to the drawer + @param {string} [data_header_drawer_type] - The type of header drawer to render + @param {object} [block] - The block that can be used to provide settings + @param {object} [section] - The section that can be used to provide settings + + @example + {% render 'header-drawer', linklist: section.settings.menu, class: 'header-drawer--mobile' %} +{%- enddoc -%} + +{% liquid + assign max_featured_items = 4 + assign image_border_radius = block.settings.image_corner_radius + + if block.settings.menu_style == 'featured_collections' + assign ratio = block.settings.featured_collections_aspect_ratio + elsif block.settings.menu_style == 'featured_products' + assign ratio = block.settings.featured_products_aspect_ratio + endif +%} + + + + + + + +{% stylesheet %} + .header__icon--menu { + position: initial; + } + + @media screen and (min-width: 750px) { + .header--desktop header-menu + .header__drawer header-drawer { + display: none; + } + } + + .menu-drawer-container .header__icon--summary { + color: var(--color-foreground); + display: flex; + justify-content: center; + align-items: center; + padding: var(--padding-lg); + } + + .header__icon--summary .header-drawer-icon { + margin: auto; + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .header__drawer { + display: flex; + min-height: 60px; + align-items: center; + + @media screen and (min-width: 750px) { + min-height: 0; + } + } + + .header--compact .header__drawer { + min-height: var(--minimum-touch-target); + } + + .menu-drawer__navigation { + padding: 0; + + @media screen and (min-width: 750px) { + margin-top: var(--drawer-header-desktop-top); + } + } + + details:not([open]) .header__icon--menu .header-drawer-icon--close { + display: none; + } + + details[open] .header__icon--menu .header-drawer-icon--close { + @media screen and (min-width: 750px) { + display: none; + } + } + + details[open] .header__icon--menu .header-drawer-icon--open { + display: none; + + @media screen and (min-width: 750px) { + display: flex; + } + } + + .menu-drawer { + position: fixed; + transform: translateX(-100%); + visibility: hidden; + height: var(--drawer-height); + width: var(--drawer-width); + max-width: var(--drawer-max-width); + z-index: var(--layer-menu-drawer); + left: 0; + top: 0; + padding: 0; + background-color: var(--color-background); + overflow: auto; + display: flex; + border-right: var(--style-border-drawer); + box-shadow: var(--shadow-drawer); + flex-direction: column; + + @media screen and (min-width: 750px) { + width: 25rem; + } + + .header__drawer--desktop & { + height: 100vh; + } + } + + .menu-drawer:has(details[open]) { + overflow: initial; + } + + .menu-drawer__backdrop { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100dvh; + backdrop-filter: brightness(0.75); + z-index: var(--layer-heightened); + opacity: 0; + transition: opacity var(--drawer-animation-speed) ease; + + .menu-open & { + opacity: 1; + } + } + + .menu-drawer, + details[open] > .menu-drawer__submenu { + transition: transform var(--drawer-animation-speed) ease, visibility var(--drawer-animation-speed) ease, + opacity var(--drawer-animation-speed) ease; + } + + .menu-open > .menu-drawer, + .menu-open > .menu-drawer__submenu:not(.menu-drawer__menu--childlist) { + transform: translateX(0); + visibility: visible; + opacity: 1; + display: flex; + flex-direction: column; + will-change: transform; + } + + .menu-drawer__inner-container { + position: relative; + height: 100%; + } + + .menu-drawer__navigation-container { + display: grid; + grid-template-rows: 1fr auto; + align-content: space-between; + overflow-y: auto; + height: 100%; + } + + .menu-drawer__inner-submenu { + display: flex; + flex-direction: column; + height: 100%; + overflow-y: auto; + + @media screen and (min-width: 750px) { + margin-top: var(--drawer-header-desktop-top); + } + } + + .menu-drawer__nav-buttons { + display: flex; + justify-content: space-between; + align-items: center; + } + + .menu-drawer__menu { + --menu-drawer-inline-padding: calc(var(--padding-sm) + 7px); + + list-style: none; + padding-inline: var(--drawer-padding); + margin-inline: 0; + margin-block-start: 0; + } + + .menu-drawer__menu--grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--padding-sm); + padding-inline-end: var(--menu-drawer-inline-padding); + padding-block-start: var(--padding-xs); + } + + .menu-drawer__menu--childlist:not(.menu-drawer__menu--grid) { + flex-grow: 1; + } + + .menu-drawer__menu.has-submenu, + .menu-drawer__menu--childlist:not(:has(.menu-drawer__animated-element)) { + margin-block-end: var(--margin-xs); + + @media screen and (min-width: 750px) { + margin-block-end: 2.5rem; + } + } + + .menu-drawer__list-item--divider { + border-block-end: 1px solid var(--color-border); + } + + .menu-drawer__list-item--deep:not(.menu-drawer__list-item--divider) .menu-drawer__menu { + margin-block-start: -0.3rem; + } + + .menu-drawer__list-item--flat.menu-drawer__list-item--divider .menu-drawer__menu { + margin-block-start: -0.4rem; + } + + .menu-drawer__menu-container--divider { + border-block-end: 1px solid var(--color-border); + } + + .menu-drawer__menu > .menu-drawer__list-item { + display: flex; + min-height: calc(2 * var(--padding-lg) + var(--icon-size-xs)); + } + + .menu-drawer__list-item--deep .menu-drawer__list-item, + .menu-drawer__list-item--flat .menu-drawer__list-item { + min-height: auto; + } + + .menu-drawer__menu .menu-drawer__list-item--flat { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-block-end: var(--margin-md); + } + + .menu-drawer__menu--childlist .menu-drawer__list-item--flat { + margin-block-end: var(--margin-sm); + + @media screen and (min-width: 750px) { + margin-block-end: var(--margin-lg); + } + } + + .menu-drawer__menu--childlist .menu-drawer__list-item--flat.menu-drawer__list-item--divider { + margin-block-end: 0; + } + + .menu-drawer__list-item--flat .menu-drawer__menu--childlist { + width: 100%; + padding-inline-start: 0; + } + + .menu-drawer-container[open] .menu-drawer__animated-element { + animation: menu-drawer-nav-open var(--drawer-animation-speed) ease-in-out; + animation-delay: calc(var(--drawer-animation-speed) + (var(--menu-drawer-animation-index) - 1) * 0.1s); + animation-fill-mode: backwards; + } + + .menu-drawer__menu details, + .menu-drawer__menu-item, + .menu-drawer__menu accordion-custom { + width: 100%; + } + + .menu-drawer__list-item--divider .menu-drawer__menu-item:not(.menu-drawer__menu-item--child) { + min-height: calc(2 * var(--padding-lg) + var(--icon-size-xs)); + } + + .menu-drawer__menu-item--mainlist { + min-height: calc(2 * var(--padding-lg) + var(--icon-size-xs)); + font-family: var(--menu-top-level-font-family); + font-style: var(--menu-top-level-font-style); + font-weight: var(--menu-top-level-font-weight); + font-size: var(--menu-top-level-font-size); + line-height: var(--menu-top-level-font-line-height); + text-transform: var(--menu-top-level-font-case); + color: var(--menu-top-level-font-color); + justify-content: space-between; + + &:hover { + color: var(--menu-top-level-font-color); + } + } + + .menu-drawer__menu-item--parent { + font-family: var(--menu-parent-font-family); + font-style: var(--menu-parent-font-style); + font-weight: var(--menu-parent-font-weight); + font-size: var(--menu-parent-font-size); + line-height: var(--menu-parent-font-line-height); + text-transform: var(--menu-parent-font-case); + color: var(--menu-parent-font-color); + + &:hover { + color: var(--menu-parent-font-color); + } + } + + .menu-drawer__menu-item--child { + font-family: var(--menu-child-font-family); + font-style: var(--menu-child-font-style); + font-weight: var(--menu-child-font-weight); + font-size: var(--menu-child-font-size); + line-height: var(--menu-child-font-line-height); + text-transform: var(--menu-child-font-case); + color: var(--menu-child-font-color); + + &:hover { + color: var(--menu-child-font-color); + } + } + + .menu-drawer__menu--childlist summary.menu-drawer__menu-item { + display: flex; + width: 100%; + padding-inline-end: 0; + } + + .menu-drawer__list-item--deep .menu-drawer__menu, + .menu-drawer__menu--grandchildlist { + padding-inline-start: 0; + } + + .menu-drawer__list-item--deep .menu-drawer__menu { + padding-block-end: 0.5rem; + } + + .menu-drawer__list-item--deep.menu-drawer__list-item--divider .menu-drawer__menu { + padding-block-end: 0.3rem; + } + + .menu-drawer__list-item--flat.menu-drawer__list-item--divider .menu-drawer__menu--grandchildlist { + padding-block-end: 0.5rem; + } + + .menu-drawer__menu-item { + display: flex; + padding: var(--padding-2xs) 0; + position: relative; + text-decoration: none; + justify-content: space-between; + align-items: center; + } + + .menu-drawer__menu-item:has(> .menu-drawer__link-image) { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + row-gap: var(--padding-3xs); + padding: 0; + } + + .menu-drawer__link-image { + width: 100%; + position: relative; + aspect-ratio: 16 / 9; + object-fit: cover; + } + + /* Fix alignment for collection image mode links without images in drawer */ + /* Target menu items in grids that have images */ + .menu-drawer__menu--grid:has(.menu-drawer__link-image) .menu-drawer__menu-item:not(:has(> .menu-drawer__link-image)) { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + row-gap: var(--padding-3xs); + padding: 0; + } + + .menu-drawer__menu--grid:has(.menu-drawer__link-image) + .menu-drawer__menu-item:not(:has(> .menu-drawer__link-image))::before { + content: ''; + display: block; + width: 100%; + aspect-ratio: 16 / 9; + background-color: var(--color-foreground-muted); + opacity: 0.1; + border-radius: var(--menu-image-border-radius); + } + + .menu-drawer__close-button { + background-color: transparent; + color: var(--color-foreground); + padding: var(--padding-xl); + box-shadow: none; + will-change: transform; + } + + .menu-drawer__close-button .svg-wrapper, + .menu-drawer__close-button svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .menu-drawer__back-button { + display: flex; + width: 100%; + padding: var(--padding-md) var(--padding-xl); + border: none; + align-items: center; + color: var(--color-foreground); + background-color: transparent; + text-align: left; + text-decoration: none; + white-space: nowrap; + overflow-x: hidden; + line-height: 1.2; + box-shadow: none; + } + + .menu-drawer__menu-item-text { + overflow: hidden; + text-overflow: ellipsis; + } + + /** Styles when the country selector is hidden */ + .menu-drawer .language-selector:not(.menu-drawer__submenu *) { + width: fit-content; + padding-inline-start: 0; + + .localization-form__select { + text-align: left; + } + } + + .menu-drawer__menu-item > .svg-wrapper { + width: fit-content; + height: fit-content; + margin: 0; + padding-block: var(--padding-lg); + padding-inline-start: var(--padding-xl); + flex-shrink: 0; + } + + .menu-drawer__list-item--divider .menu-drawer__menu-item > .svg-wrapper { + padding-block: var(--padding-md); + } + + .menu-drawer svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .menu-drawer__submenu { + position: absolute; + width: 100%; + top: 0; + height: 100dvh; + left: 0; + background-color: var(--color-background); + z-index: var(--layer-flat); + transform: translateX(-5%); + visibility: hidden; + overflow-y: auto; + opacity: 0; + } + + .menu-drawer__back-button > .svg-wrapper { + margin-right: var(--padding-md); + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .menu-drawer__utility-links { + display: flex; + flex-direction: column; + padding: 0; + margin-block: auto var(--padding-sm); + margin-inline-start: var(--padding-xl); + background-color: rgb(var(--color-foreground) 0.03); + } + + .menu-drawer__account { + display: inline-flex; + align-items: center; + gap: var(--gap-xs); + text-decoration: none; + height: 44px; + font-size: 1.4rem; + color: rgb(var(--color-foreground)); + } + + .menu-drawer__account svg { + height: var(--icon-size-sm); + width: var(--icon-size-sm); + } + + .menu-drawer__account shop-user-avatar { + --shop-avatar-size: 2.4rem; + + margin-right: 0.55rem; + margin-left: -0.45rem; + } + + .menu-drawer__link-image, + .menu-drawer__featured-product-image, + .menu-drawer__featured-collection-image, + .menu-drawer__featured-collection-link::before { + border-radius: var(--menu-image-border-radius); + } + + @keyframes menu-drawer-nav-open { + 0% { + visibility: hidden; + opacity: 0; + transform: translateX(-0.5rem); + } + + 100% { + visibility: visible; + opacity: 1; + transform: translateX(0); + } + } + + @keyframes menu-drawer-subnav-open { + 0% { + visibility: visible; + opacity: 1; + transform: translateX(0); + } + + 100% { + visibility: hidden; + opacity: 0; + transform: translateX(-1rem); + } + } +{% endstylesheet %} diff --git a/snippets/header-menu.liquid b/snippets/header-menu.liquid new file mode 100644 index 000000000..bc9f9e491 --- /dev/null +++ b/snippets/header-menu.liquid @@ -0,0 +1,90 @@ +{% liquid + assign menu_content_type = block.settings.menu_style | default: 'text' + assign image_border_radius = block.settings.image_border_radius + assign color_scheme_classes = '' + assign color_scheme_setting_id = 'color_scheme_' | append: section.settings.menu_row + assign current_color_scheme = block.settings.color_scheme + assign parent_color_scheme = section.settings[color_scheme_setting_id] + + if parent_color_scheme.id != current_color_scheme.id + assign color_scheme_classes = ' color-' | append: current_color_scheme + endif + + # Check if header and menu colors match. This is used to apply different padding styles in css + if parent_color_scheme.settings.background.rgb == current_color_scheme.settings.background.rgb + assign color_scheme_classes = color_scheme_classes | append: ' color-scheme-matches-parent' + endif + + if block.settings.menu_style == 'featured_collections' + assign ratio = block.settings.featured_collections_aspect_ratio + elsif block.settings.menu_style == 'featured_products' + assign ratio = block.settings.featured_products_aspect_ratio + endif +%} + +{% capture children %} + {% for link in block.settings.menu.links %} + + {% endfor %} + +{% endcapture %} + + diff --git a/snippets/header-row.liquid b/snippets/header-row.liquid new file mode 100644 index 000000000..134390046 --- /dev/null +++ b/snippets/header-row.liquid @@ -0,0 +1,78 @@ +{%- liquid + assign order = order | split: ',' + assign left = '' + assign center = '' + assign right = '' + + if first != blank + assign left = 'first ' + endif + + for item in order + assign column_key = item | append: '_position' + assign row_key = item | append: '_row' + assign item_row = settings[row_key] | default: 'top' + assign item_column = settings[column_key] | default: 'left' + + case item + when 'actions': + assign item_column = 'right' + endcase + + if item_row == row + case item_column + when 'left' + assign left = left | append: item | append: ' ' + when 'center' + assign center = center | append: item | append: ' ' + else + assign right = right | append: item | append: ' ' + endcase + endif + endfor + + assign columns = 'left,center,right' | split: ',' +-%} + +{%- for column in columns -%} + {%- capture items_for_column -%} + {% case column %} + {% when 'left' %} + {{ left }} + {% when 'center' %} + {{ center }} + {% else %} + {{ right }} + {% endcase %} + {%- endcapture -%} + + {%- assign items_array = items_for_column | strip | split: ' ' | compact -%} + + {%- if items_array.size > 0 -%} +
    + {% for key in items_array %} + {% unless key == blank %} + {% case key %} + {% when 'first' %} + {{ first }} + {% when 'logo' %} + {{ logo }} + {% when 'menu' %} + {{ menu }} + {% when 'localization' %} + {{ localization }} + {% when 'search' %} + {{ search }} + {% when 'mobile_search' %} + {{ mobile_search }} + {% when 'actions' %} + {{ actions }} + {% endcase %} + {% endunless %} + {% endfor %} +
    + {%- endif -%} +{%- endfor -%} diff --git a/snippets/icon-or-image.liquid b/snippets/icon-or-image.liquid new file mode 100644 index 000000000..3cd6735fd --- /dev/null +++ b/snippets/icon-or-image.liquid @@ -0,0 +1,40 @@ +{%- doc -%} + Renders either an SVG icon or an uploaded image based on block settings. + + @param {string} icon - The icon name from block.settings.icon + @param {object} image_upload - The uploaded image from block.settings.image_upload + @param {number} width - The width setting from block.settings.width + @param {string} class_name - CSS class name for the rendered element + @param {object} [attributes] - Additional HTML attributes to add to the element +{%- enddoc -%} + +{%- if icon != 'none' and image_upload == blank -%} + +{%- elsif image_upload != blank -%} + {% liquid + assign media_width_desktop = '100vw' + assign media_width_mobile = '100vw' + assign sizes = '(min-width: 1024px) 1024px, ' | append: media_width_desktop | append: ', ' | append: media_width_mobile + assign widths = '300, 375, 450, 525, 600, 675, 750, 768, 850, 900, 1024' + %} + + {% assign image_style = 'width: ' | append: width | append: 'px;' %} + {{ + image_upload + | image_url: width: 1024 + | image_tag: widths: widths, class: class_name, style: image_style, sizes: sizes + }} +{%- endif -%} diff --git a/snippets/icon.liquid b/snippets/icon.liquid new file mode 100644 index 000000000..3ebf7200f --- /dev/null +++ b/snippets/icon.liquid @@ -0,0 +1,399 @@ +{% # To be removed when we can use the icon static block instead %} + +{%- case icon -%} + {%- when 'apple' -%} + + + + {%- when 'banana' -%} + + + {%- when 'bottle' -%} + + + + {%- when 'bluesky' %} + + {%- when 'box' -%} + + {%- when 'caret' -%} + + {%- when 'double-sided-caret' -%} + + + + + + {%- when 'carrot' -%} + + + + + + + {%- when 'chat_bubble' -%} + + + + + {%- when 'check_box' -%} + + + {%- when 'clipboard' -%} + + + + + + {%- when 'dairy' -%} + + + + + + {%- when 'dairy_free' -%} + + + + + + + + + + {%- when 'discord' -%} + + {%- when 'dryer' -%} + + + {%- when 'error' -%} + + + {%- when 'eye' -%} + + + {%- when 'fire' -%} + + + {%- when 'gluten_free' -%} + + + + + + + + + + + + {%- when 'heart' -%} + + {%- when 'iron' -%} + + + + + {%- when 'leaf' -%} + + + + + {%- when 'leather' -%} + + {%- when 'lightning_bolt' -%} + + {%- when 'linkedin' -%} + + {%- when 'lipstick' -%} + + + + {%- when 'lock' -%} + + + + + {%- when 'map_pin' -%} + + + {%- when 'nut_free' -%} + + + + + {%- when 'pants' -%} + + + {%- when 'paw_print' -%} + + + + + + {%- when 'pepper' -%} + + {%- when 'perfume' -%} + + + + + {%- when 'plane' -%} + + {%- when 'plant' -%} + + + + + {%- when 'price_tag' -%} + + + {%- when 'question_mark' -%} + + + {%- when 'recycle' -%} + + + + {%- when 'return' -%} + + + {%- when 'ruler' -%} + + + + + + {%- when 'serving_dish' -%} + + + + + {%- when 'shirt' -%} + + {%- when 'shoe' -%} + + + {%- when 'silhouette' -%} + + + {%- when 'snowflake' -%} + + {%- when 'star' -%} + + {%- when 'stopwatch' -%} + + + + + + + {%- when 'truck' -%} + + + + + {%- when 'washing' -%} + + + {%- when 'arrow' -%} + + + {%- when 'tiktok' -%} + + {%- when 'youtube' -%} + + {%- when 'instagram' -%} + + {%- when 'x' -%} + + {%- when 'twitter' -%} + + {%- when 'facebook' -%} + + {%- when 'pinterest' -%} + + {%- when 'tumblr' -%} + + {%- when 'vimeo' -%} + + {%- when 'snapchat' -%} + + {%- when 'spotify' -%} + + {%- when 'next' -%} + + {%- when 'previous' -%} + + {%- when 'threads' -%} + + {%- when 'whatsapp' -%} + + + {%- when '3d-model' -%} + + {%- when 'mastodon' -%} + + {%- when 'reddit' -%} + + {%- when 'telegram' -%} + + {%- when 'twitch' -%} + +{%- endcase -%} diff --git a/snippets/image.liquid b/snippets/image.liquid new file mode 100644 index 000000000..2f220188f --- /dev/null +++ b/snippets/image.liquid @@ -0,0 +1,32 @@ +{%- doc -%} + Renders the element using provided image object + + @param {object} image - image object + @param {number} [height] - custom image height + @param {string} [class] - additional classes + @param {string} [text_fallback] - text to display if image is blank + @param {boolean} [unset_image_tag] - if true, ignores the image focal point + @param {string} [style] - additional styles + + @example + {% render 'image', image: product.featured_image, height: 300, class: 'product-image' %} +{%- enddoc -%} +{% if image != blank %} + {% assign image_height = height | default: image.height %} + {% assign image_height_2x = height | default: image_height | times: 2 %} + {% assign image_height_3x = height | default: image_height | times: 3 %} + + {% capture image_srcset -%} + {{ image | image_url: height: image_height }} 1x, {{ image | image_url: height: image_height_2x }} 2x, {{ image | image_url: height: image_height_3x }} 3x + {%- endcapture %} + + {% assign style_value = style | default: '' %} + + {% if unset_image_tag %} + {% assign style_value = style_value | append: 'object-position: inherit;' %} + {% endif %} + + {{ image | image_url: height: image_height | image_tag: class: class, srcset: image_srcset, style: style_value }} +{% elsif text_fallback %} + {{ text_fallback }} +{% endif %} diff --git a/snippets/jumbo-text.liquid b/snippets/jumbo-text.liquid new file mode 100644 index 000000000..b24bee9df --- /dev/null +++ b/snippets/jumbo-text.liquid @@ -0,0 +1,186 @@ +{%- doc -%} + Renders text that stretches to fit the full width of its container. + + @param {string} [text] - The text to be rendered. + + @example + {% render 'jumbo-text', text: block.settings.text %} +{%- enddoc -%} + +{% liquid + assign shown_text = text | default: block.settings.text + assign descenders = 'alphabetic' + assign trim = 'trim-both' + + unless block.settings.case == 'uppercase' + if shown_text contains 'g' or shown_text contains 'j' or shown_text contains 'p' or shown_text contains 'q' or shown_text contains 'y' + assign descenders = 'text' + endif + endunless + + assign text_trim = trim | append: ' cap ' | append: descenders + assign shown_text_with_line_breaks = shown_text | newline_to_br + assign text_with_lines = shown_text_with_line_breaks | split: '
    ' + assign nudge = '-0.04em' +%} + +{% capture attributes %} + style=" + --font-family: var(--font-{{ block.settings.font | default: 'accent'}}--family); + --font-weight: var(--font-{{ block.settings.font | default: 'accent'}}--weight); + {% if block.settings.font == 'body' %} + --color: var(--color-foreground); + {% else %} + --color: var(--color-foreground-heading); + {% endif %} + --text-align: {{ block.settings.alignment | default: 'left' }}; + {% if block.settings.alignment == "left" %} + --margin-left-nudge: {{nudge}}; + {% elsif block.settings.alignment == "right" %} + --margin-right-nudge: {{nudge}}; + {% endif %} + --line-height: {{ block.settings.line_height | default: '1' }}; + --letter-spacing: {{ block.settings.letter_spacing | default: '-0.03em' }}; + --text-transform: {{ block.settings.case | default: 'none' }}; + --text-trim: {{text_trim}}; + " + {{ block.shopify_attributes }} +{% endcapture %} + +{% comment %} + If the jumbo text is not wrapped inside its own container, the overflow calculation does not always work correctly + (looks like some weird off-by-one error when comparing sizes). +{% endcomment %} +
    + {% if text != blank %} + {{ text }} + {% else %} + {{ shown_text }} + + {%- assign char_index = 0 -%} + {%- for line in text_with_lines -%} + {%- if forloop.index > 1 -%} +
    + {%- endif -%} + + {%- endfor -%} +
    + {% endif %} +
    + + + +{% stylesheet %} + .jumbo-text__container { + width: 100%; + } + + jumbo-text { + display: block; + font-family: var(--font-family, inherit); + font-style: var(--font-style, normal); + color: var(--color, inherit); + font-weight: var(--font-weight, inherit); + letter-spacing: var(--letter-spacing, -0.02em); + line-height: var(--line-height, 1); + opacity: 0; + text-align: var(--text-align); + text-box: var(--text-trim, trim-end cap text); + text-transform: var(--text-transform, none); + transition: opacity 0.3s ease; + white-space: pre; + width: 100%; + will-change: font-size; + margin-left: var(--margin-left-nudge, 0); + margin-right: var(--margin-right-nudge, 0); + overflow: visible; + } + + jumbo-text.ready { + opacity: 1; + } + + jumbo-text[data-cap-text='true'] { + text-box-edge: cap text; + } + + .jumbo-text-space { + display: inline-flex; + width: 0.5ch; + } + + :is(.jumbo-text-char, .jumbo-text-line) { + display: inline-flex; + } + + @media (prefers-reduced-motion: no-preference) { + /* Blur effect */ + [data-text-effect='blur'] { + filter: blur(20px); + opacity: 0.5; + scale: 1.05; + transition: filter 1.6s var(--animation-timing-fade-in), opacity 1.3s var(--animation-timing-fade-in), + scale 1.6s var(--animation-timing-fade-in); + } + + .jumbo-text-visible[data-text-effect='blur'] { + filter: blur(0); + opacity: 1; + scale: 1; + } + + /* Reveal effect */ + .ready[data-text-effect='reveal'], + .ready[data-text-effect='reveal'] .jumbo-text-line { + overflow: hidden; + } + + .ready[data-text-effect='reveal'] .jumbo-text-char { + transform: translateY(100%); + } + + .jumbo-text-visible[data-text-effect='reveal'] .jumbo-text-char { + transition: transform 0.5s var(--animation-timing-fade-in) calc(var(--line-index) * 0.05s); + transform: translateY(0); + } + + .jumbo-text-visible[data-text-effect='reveal'], + .jumbo-text-visible[data-text-effect='reveal'] .jumbo-text-line { + overflow: visible; + transition: overflow 0s linear 0.75s; + } + } +{% endstylesheet %} diff --git a/snippets/layout-panel-style.liquid b/snippets/layout-panel-style.liquid new file mode 100644 index 000000000..d8311f78e --- /dev/null +++ b/snippets/layout-panel-style.liquid @@ -0,0 +1,33 @@ +{%- liquid + comment + Intended for blocks and sections that provide values for all the referenced settings. + + Accepts: + settings: {block.settings || section.settings} + endcomment + + assign horizontal_alignment = settings.horizontal_alignment + + assign vertical_alignment = settings.vertical_alignment + if settings.align_baseline and vertical_alignment == 'flex-end' + assign vertical_alignment = 'last baseline' + endif + + unless settings.content_direction == 'row' + assign horizontal_alignment = settings.horizontal_alignment_flex_direction_column + assign vertical_alignment = settings.vertical_alignment_flex_direction_column + endunless + + assign vertical_alignment_mobile = vertical_alignment + + if settings.vertical_on_mobile and vertical_alignment == 'last baseline' + assign vertical_alignment_mobile = 'flex-end' + endif +-%} + +--flex-direction: {{ settings.content_direction | default: 'column' }}; --flex-wrap: nowrap; + +{% render 'gap-style', value: settings.gap %} + +--horizontal-alignment: {{ horizontal_alignment }}; --vertical-alignment: {{ vertical_alignment }}; +--vertical-alignment-mobile: {{ vertical_alignment_mobile }}; diff --git a/snippets/link-featured-image.liquid b/snippets/link-featured-image.liquid new file mode 100644 index 000000000..d80935d00 --- /dev/null +++ b/snippets/link-featured-image.liquid @@ -0,0 +1,40 @@ +{%- doc -%} + Renders the featured image for a menu item. + + @param {object} link - The link to render + @param {string} [class] - The class to apply to the image + + @example + {% render 'menu-featured-image', link: link %} +{%- enddoc -%} + +{% liquid + assign image_class = class +%} + +{% if link.type == 'collection_link' %} + {% if link.object.featured_image %} + {{ link.object.featured_image | image_url: width: 1024 | image_tag: loading: 'lazy', class: class, sizes: 'auto' }} + {% elsif link.object.products.size > 0 %} + {% assign product_object = link.object.products | where: 'featured_image' | first %} + {% if product_object.featured_image %} + {{ + product_object.featured_image + | image_url: width: 1024 + | image_tag: loading: 'lazy', class: class, sizes: 'auto' + }} + {% endif %} + {% endif %} +{% elsif link.type == 'collections_link' %} + {% assign collection_object = collections | where: 'featured_image' | first %} + {% if collection_object.featured_image %} + {{ + collection_object.featured_image + | image_url: width: 1024 + | image_tag: loading: 'lazy', class: class, sizes: 'auto' + }} + {% endif %} +{% elsif link.type == 'catalog_link' %} + {% assign product_object = collections.all.products | where: 'featured_image' | first %} + {{ product_object.featured_image | image_url: width: 1024 | image_tag: loading: 'lazy', class: class, sizes: 'auto' }} +{% endif %} diff --git a/snippets/list-filter.liquid b/snippets/list-filter.liquid new file mode 100644 index 000000000..7452dc042 --- /dev/null +++ b/snippets/list-filter.liquid @@ -0,0 +1,783 @@ +{%- doc -%} + Renders a list or swatch filter. + + @param {object} filter - The filter to render + @param {string} filter_style - The filter style ('horizontal' | 'vertical') + @param {number} active_value_count - The number of active values + @param {number} sectionId - The section ID + @param {boolean} [autofocus] - Whether to autofocus the filter + @param {boolean} [should_render_clear] - Whether to render the clear button + @param {boolean} [show_swatch_label] - Whether to show the swatch label + @param {boolean} [in_drawer] - Whether the filter is in a drawer +{%- enddoc -%} + +{% liquid + assign is_swatch = false + assign swatch_index = filter.values | find_index: 'swatch' + + if swatch_index != null + assign is_swatch = true + endif + + assign is_image = false + if filter.presentation == 'image' + assign is_image = true + endif +%} + + +
    + + {{ filter.label }} + +
    + {% if is_swatch %} + + + {%- liquid + if active_value_count > 3 + echo active_value_count + elsif active_value_count > 0 and active_value_count <= 3 + for value in filter.active_values + render 'swatch', swatch: value.swatch, mode: 'filter' + endfor + endif + -%} + + + {% else %} + + 1 %} + class="bubble facets__bubble" + {% endif %} + hide-when-empty + ref="facetStatus" + > + {%- liquid + if active_value_count == 1 + echo filter.active_values[0].label + elsif active_value_count > 1 + echo active_value_count + endif + -%} + + + {% endif %} + + {{- 'icon-caret.svg' | inline_asset_content -}} + +
    +
    + + + {% liquid + assign has_active_values = false + assign inital_visible_values = 10 + if is_swatch + assign inital_visible_values = 22 + endif + if is_image + assign inital_visible_values = 6 + endif + assign max_visible_values = inital_visible_values | plus: 1 + assign render_show_more = false + assign should_render_for_swatch = is_swatch + if is_swatch and show_swatch_label + assign should_render_for_swatch = false + endif + if filter.values.size > max_visible_values and should_render_for_swatch == false + assign render_show_more = true + endif + %} + {% liquid + if render_show_more + if filter_style == 'horizontal' + echo '' + else + echo '' + endif + endif + assign should_use_pills = true + + for value in filter.values + if value.label.size > 3 + assign should_use_pills = false + break + endif + endfor + + if filter.type == 'boolean' + assign should_use_pills = false + endif + %} + +
    + {% liquid + if is_swatch + assign swatch_columns = filter.values.size + + if swatch_columns > 4 + assign swatch_columns = 4 + + # Balance the number of columns based on the number of values, i.e. try to avoid one or two items in + # the last row if the number of values is (almost) divisible by 3. + assign mod4 = filter.values.size | modulo: 4 + assign mod3 = filter.values.size | modulo: 3 + if mod4 != 0 and mod4 != 3 + if mod3 == 0 or mod3 == 2 + assign swatch_columns = 3 + endif + endif + endif + endif + + if is_image + assign image_columns = 3 + if filter.values.size < 3 + assign image_columns = filter.values.size + endif + endif + %} +
      + {%- for value in filter.values -%} + {% liquid + assign input_id = 'Filter-' | append: filter.param_name | escape | append: '-' | append: forloop.index | replace: '.', '-' | append: '-' | append: filter_style | append: '-' | append: in_drawer + assign is_disabled = false + if value.count == 0 and value.active == false + assign is_disabled = true + endif + assign hidden_class = null + if forloop.index > inital_visible_values and render_show_more + assign hidden_class = 'hidden' + if filter_style == 'horizontal' + assign hidden_class = 'mobile:hidden' + endif + endif + %} +
    • + {% if value.active %} + {% assign has_active_values = true %} + {% endif %} + {% if is_image %} +
      +
      + {% if value.image %} + {{ value.image | image_url: width: 300 | image_tag: alt: value.alt }} + {% endif %} + {% if is_disabled %} + + {% endif %} +
      + + +
      + {% elsif is_swatch %} +
      + +
      + {% else %} + {% if should_use_pills %} +
      + + +
      + {% else %} + {% render 'checkbox', + name: value.param_name, + value: value.value, + label: value.label, + checked: value.active, + id: input_id, + disabled: is_disabled, + inputRef: 'facetInputs[]', + events: 'on:pointerenter="/prefetchPage" on:pointerleave="/cancelPrefetchPage"', + autofocus: autofocus + %} + {% endif %} + {% endif %} +
    • + {%- endfor -%} +
    +
    + {% if render_show_more %} + + {% echo '
    ' %} + {% endif %} + + {% if should_render_clear %} + +
    + +
    +
    + {% endif %} +
    +
    +
    +
    + +{% stylesheet %} + .facets input:checked + label { + font-weight: 500; + } + + .facets .checkbox .icon-checkmark { + transition: border-color 0.2s ease, background-color 0.2s ease; + } + + .facets .checkbox:not(:has(.checkbox__input:disabled)):hover .icon-checkmark { + border-color: rgb(var(--color-foreground-rgb) / var(--opacity-40-60)); + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + } + + .facets .checkbox:has(.checkbox__input:checked):not(:has(.checkbox__input:disabled)):hover .icon-checkmark { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-85)); + } + + .facets .checkbox:not(:has(.checkbox__input:disabled)):hover .checkbox__label-text { + color: rgb(var(--color-foreground-rgb) / var(--opacity-90)); + } + + .facets .checkbox .checkbox__label-text { + transition: color 0.2s ease, font-weight 0.2s ease; + } + + /* Pill style */ + .facets__pill-label { + --pill-label-padding-inline: var(--padding-xs); + --pill-label-border-radius: var(--style-border-radius-md); + --pill-label-border-width: var(--variant-picker-button-border-width); + --pill-label-height: var(--button-size-md); + --pill-label-focus-outline-color: var(--color-foreground); + --pill-label-color: var(--color-foreground); + --pill-label-color-rgb: var(--color-foreground-rgb); + --pill-label-background-color: var(--color-background); + --pill-label-background-color-rgb: var(--color-background-rgb); + --pill-label-border-opacity: var(--facets-low-opacity); + + display: inline-flex; + position: relative; + align-items: center; + justify-content: center; + box-shadow: inset 0 0 0 var(--pill-label-border-width) rgb(var(--pill-label-color-rgb) / var(--opacity-10-25)); + border-radius: var(--pill-label-border-radius); + height: var(--pill-label-height); + width: 100%; + padding-inline: var(--pill-label-padding-inline); + color: rgb(var(---pill-label-color-rgb)); + background-color: rgb(var(--pill-label-background-color-rgb)); + cursor: pointer; + transition: color var(--animation-speed) var(--animation-easing), + background-color var(--animation-speed) var(--animation-easing); + outline-color: var(--pill-label-focus-outline-color); + + &:hover { + --pill-label-border-opacity: 100%; + } + } + + .facets__pill-input { + &:checked + .facets__pill-label { + --pill-label-color: var(--color-background); + --pill-label-background-color: var(--color-foreground); + --pill-label-border-opacity: 0; + + font-weight: 500; + } + + &:disabled + .facets__pill-label { + opacity: var(--disabled-opacity); + cursor: not-allowed; + + &:hover { + --pill-label-border-opacity: var(--facets-low-opacity); + } + } + } + + .facets__status-wrapper { + display: flex; + align-items: center; + } + + .facets--drawer .facets__status-wrapper { + @media screen and (max-width: 749px) { + gap: var(--gap-3xs); + } + } + + .facets--vertical .facets__status-wrapper { + gap: var(--gap-xs); + } + + .facets--horizontal .facets__status-wrapper { + gap: 0; + } + + .facets__pill-input:disabled + .facets__pill-label svg { + position: absolute; + top: 0; + left: 0; + border-radius: var(--style-border-radius-md); + } + + .facets__pill-label svg line { + stroke-width: 1.5px; + stroke: rgb(var(--color-foreground-rgb) / var(--facets-low-opacity)); + } + + .facets__pill-wrapper { + position: relative; + } + + .facets__pill-input { + position: absolute; + inset: 0; + margin: 0; + opacity: 0; + cursor: pointer; + } + + /* Swatches */ + .facets__status--swatches { + display: none; + } + + .facets__swatch-wrapper { + display: flex; + } + + .facets__inputs-list--swatches .variant-option__button-label { + --color-variant-text: var(--color-foreground); + } + + .facets__inputs-list--swatches { + --variant-picker-swatch-width: 32px; + --variant-picker-swatch-height: 32px; + + @media screen and (min-width: 750px) { + --variant-picker-swatch-width: 26px; + --variant-picker-swatch-height: 26px; + } + } + + .facets--vertical .facets__inputs-wrapper .facets__inputs-list--swatches-grid { + gap: var(--gap-sm); + } + + .facets--vertical .facets__inputs-list--swatches .facets__inputs-list-item { + display: flex; + } + + .facets__inputs-wrapper .facets__inputs-list--swatches-grid { + --columns: 2; + + display: grid; + grid-template-columns: repeat(var(--columns), 1fr); + } + + .facets__inputs-wrapper .facets__inputs-list--swatches-grid .variant-option--swatches { + cursor: pointer; + overflow: visible; + + &.variant-option--swatches-disabled, + &:has(input:disabled) { + cursor: not-allowed; + } + } + + .facets__inputs-wrapper .facets__inputs-list--swatches-grid label { + cursor: pointer; + word-break: break-word; + white-space: normal; + + .variant-option--swatches-disabled &, + .variant-option--swatches:has(input:disabled) & { + cursor: not-allowed; + } + } + + .facets__inputs-wrapper .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch { + align-items: center; + overflow: visible; + justify-content: flex-start; + display: flex; + width: 100%; + flex-basis: unset; + gap: var(--gap-sm); + } + + .facets__inputs-wrapper .facets__inputs-list--swatches-grid .variant-option__button-label:has(:checked) { + color: rgb(var(--color-foreground-rgb)); + background-color: rgb(var(--color-background-rgb)); + font-weight: 500; + transition: font-weight 0.2s ease; + } + + .facets .variant-option--swatches { + --options-border-radius: var(--variant-picker-swatch-radius); + + width: auto; + } + + .facets--horizontal .facets__status--swatches { + @media screen and (min-width: 750px) { + display: flex; + } + } + + .facets--horizontal .sorting-filter .facets__status { + @media screen and (min-width: 750px) { + display: none; + } + } + + .facets__status--swatches .swatch { + width: calc(var(--variant-picker-swatch-width) / 1.5); + height: calc(var(--variant-picker-swatch-height) / 1.5); + } + + .facets__status--swatches .swatch + .swatch { + margin-left: calc(var(--variant-picker-swatch-width) / -3); + outline: 1px solid rgb(var(--color-background-rgb)); + } + + .variant-option--images { + position: relative; + } + + .variant-option--images { + --image-facet-border-width: var(--variant-picker-button-border-width); + --image-facet-border-opacity: var(--facets-low-opacity); + --image-facet-border-radius: var(--style-border-radius-xs); + + border-radius: var(--image-facet-border-radius); + box-shadow: inset 0 0 0 var(--image-facet-border-width) + rgb(var(--color-foreground-rgb) / var(--image-facet-border-opacity)); + + &:hover:not(:has(input:disabled)), + &:has(input:checked) { + --image-facet-border-opacity: 100%; + } + + &:has(input:checked) { + font-weight: 500; + transition: font-weight 0.2s ease; + } + + &:has(input:checked):hover { + --image-facet-border-width: calc(var(--variant-picker-button-border-width) + 0.5px); + } + + &:has(input:focus-visible) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + &:has(input:disabled), + &:has(input:disabled):hover { + --image-facet-border-opacity: 0; + + opacity: var(--disabled-opacity); + cursor: not-allowed; + + img { + opacity: var(--disabled-opacity); + } + + input, + label, + .facets__image-label { + cursor: not-allowed; + } + + .facets__image-wrapper { + border: var(--style-border-width) solid rgb(var(--color-foreground-rgb) / var(--opacity-30)); + border-radius: var(--image-facet-border-radius); + } + } + } + + .facets__inputs-wrapper .facets__inputs-list--images { + display: grid; + grid-template-columns: repeat(var(--image-columns), 125px); + gap: var(--gap-sm); + } + + .facets--drawer .facets__inputs-wrapper .facets__inputs-list--images { + grid-template-columns: repeat(3, 1fr); + + @media screen and (min-width: 750px) { + grid-template-columns: repeat(4, 1fr); + } + } + + .facets--vertical .facets__inputs-wrapper .facets__inputs-list--images { + grid-template-columns: repeat(2, 1fr); + } + + .facets--drawer .facets__inputs-list--images { + padding-top: var(--padding-xs); + } + + .facets__image-wrapper { + aspect-ratio: 1/1; + width: 100%; + padding: var(--padding-xs); + position: relative; + overflow: hidden; + } + + .facets__image-wrapper img { + height: 100%; + width: 100%; + object-fit: contain; + border-radius: calc(var(--border-radius) / 2); + } + + /* Position disabled-svg */ + .variant-option--images svg { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + width: 100%; + height: 100%; + stroke-width: var(--border-width); + stroke: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + } + + /* Position label text and handle overflow */ + .facets__inputs-list-item, + .variant-option--images { + min-width: 0; + } + + .facets__image-label { + width: 100%; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-block-end: var(--padding-xs); + cursor: pointer; + + .variant-option--images:has(input:disabled) & { + cursor: not-allowed; + } + } + + .facets__inputs-list--swatches .variant-option__button-label:hover:not(:has(input:disabled)) { + font-weight: 500; + } + + .variant-option--images:not(:has(input:disabled)) .facets__image-label:hover { + font-weight: 500; + } +{% endstylesheet %} diff --git a/snippets/localization-form.liquid b/snippets/localization-form.liquid new file mode 100644 index 000000000..234119d73 --- /dev/null +++ b/snippets/localization-form.liquid @@ -0,0 +1,817 @@ +{%- doc -%} + Renders either a country selector, language selector, or both. + + @param {boolean} show_country - Whether to show the country selector + @param {boolean} show_language - Whether to show the language selector + @param {string} block_id - The block ID + @param {string} [form_style] - The style tag string to be applied to the form + @param {string} [localization_style] - The style of the localization form + + @example + {% render 'localization-form', show_country: true, show_language: true, block_id: block.id %} +{%- enddoc -%} + +{%- liquid + comment + From Tyler in July: Noting here that it might make sense for us to just be able to get localization.available_currencies and localization.popular_countries instead of needing this esoteric logic. + endcomment + assign currencies = localization.available_countries | map: 'currency' | map: 'iso_code' | uniq + assign popular_countries = localization.available_countries | where: 'popular?' | sort: 'name' + + assign show_country_filter = false + if localization.available_countries.size > 9 + assign show_country_filter = true + endif + + assign show_popular_countries = false + if localization.available_countries.size > 9 and popular_countries.size > 1 + assign show_popular_countries = true + endif + + assign show_currencies = false + if currencies.size > 1 + assign show_currencies = true + endif + + assign aliases_us = 'us,usa,america,united states of america' + assign aliases_uk = 'uk,gb,great britain' +%} + + {% assign localization_label = 'content.localization_region_and_language' | t %} + + {%- form 'localization', + id: 'LocalizationForm', + class: 'localization-form', + ref: 'form', + aria-label: localization_label + -%} + {% if show_country %} + {% if show_country_filter %} +
    +
    +
    + + {{ 'icon-search.svg' | inline_asset_content }} + +
    + + + +
    +
    + {% endif %} +
    +

    + Country/Region +

    + {% if show_country_filter %} +
    + {% endif %} +
    + {% if show_popular_countries %} + + {% endif %} +
      + + {%- for country in localization.available_countries -%} + {% liquid + assign aliases = '' + case country.iso_code + when 'US' + assign aliases = aliases_us + when 'GB' + assign aliases = aliases_uk + endcase + %} +
    • + + {{- 'icon-checkmark.svg' | inline_asset_content -}} + + {{- country.name }} + +
    • + {%- endfor -%} +
    +
    +
    + +
    + {% endif %} + + {% if show_language %} +
    +

    + {{ 'content.language' | t }} +

    + {% if show_country == true %} + {{ 'content.language' | t }} + {% endif %} + + + {{- 'icon-caret.svg' | inline_asset_content -}} + +
    + {% endif %} + {%- endform -%} +
    + +{% stylesheet %} + /* Localization */ + localization-form-component { + display: flex; + width: var(--width, auto); + + @media screen and (min-width: 750px) { + position: relative; + } + } + + localization-form-component[data-show-filter='false'] .country-selector-form__wrapper { + padding-block-start: var(--padding-xs); + } + + .localization-form { + width: 100%; + } + + localization-form-component .button:is(:not(.country-filter__reset-button)) { + --button-color: var(--color-primary); + --button-background-color: var(--language-button-background-color, var(--color-background)); + --button-border-color: var(--language-button-border-color, var(--color-border)); + + text-decoration-color: transparent; + text-decoration-thickness: 0.075em; + text-underline-offset: 0.125em; + transition: text-decoration-color var(--animation-speed) var(--animation-easing); + } + + localization-form-component .button:is(:not(.country-filter__reset-button)):hover, + .localization-form__list-item:hover, + .localization-form__list-item:focus { + --button-color: var(--color-primary-hover); + + background-color: rgb(var(--color-primary-hover-rgb) / var(--opacity-8)); + } + + .localization-form__list-item[aria-current='true'] { + --button-color: var(--color-primary-active); + + background-color: rgb(var(--color-primary-hover-rgb) / var(--opacity-10)); + } + + .localization-form__list-item-disabled { + pointer-events: none; + } + + .localization-form__list-item:focus-visible { + outline: none; + } + + localization-form-component .localization-selector { + display: flex; + align-items: center; + gap: var(--margin-2xs); + } + + localization-form-component .country-filter__search-icon { + left: 8px; + right: auto; + color: var(--color-foreground-muted); + pointer-events: none; + } + + .country-filter__search-icon .svg-wrapper svg { + width: var(--icon-size-sm); + height: var(--icon-size-sm); + } + + .disclosure { + width: 100%; + } + + .dropdown-localization__button { + display: flex; + position: relative; + align-items: center; + gap: 4px; + font-family: var(--menu-localization-font); + font-size: var(--menu-localization-font-size); + font-weight: var(--menu-top-level-font-weight); + padding-inline: var(--padding-2xs); + margin-inline: calc(-1 * var(--padding-2xs)); + } + + .dropdown-localization__button .icon-caret { + height: var(--icon-size-xs); + width: var(--icon-size-xs); + right: var(--margin-xs); + top: calc(50% - var(--padding-2xs)); + flex-shrink: 0; + transition: transform var(--animation-speed) var(--animation-easing); + } + + .drawer-localization__button .icon-flag, + .dropdown-localization__button .icon-flag { + width: var(--menu-localization-font-size, var(--icon-size-sm)); + height: var(--menu-localization-font-size, var(--icon-size-sm)); + clip-path: circle(50%); /* stylelint-disable-line */ + background-position: center; + background-size: cover; + margin-inline-end: 4px; + position: relative; + } + + .icon-flag::after { + content: ''; + position: absolute; + inset: 0; + box-shadow: inset 0 0 var(--size-shadow) var(--color-shadow); + border-radius: 50%; + } + + .dropdown-localization__button[aria-expanded='true'] .icon-caret svg { + transform: rotate(180deg); + } + + .dropdown-localization__button, + .dropdown-localization__button:hover { + box-shadow: none; + background-color: transparent; + border-color: transparent; + color: var(--color-foreground); + } + + .localization-form__list { + position: relative; + width: 100%; + padding-block: 0 var(--padding-xs); + font-size: var(--font-size-lg); + scroll-padding: var(--padding-xs) 0; + overflow-y: auto; + white-space: nowrap; + + /* Hide scrollbar which would cause extra right padding in Safari */ + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + dropdown-localization-component .localization-form__list { + max-height: 20.5rem; + } + + .localization-wrapper { + position: fixed; + z-index: var(--layer-raised); + border-radius: var(--style-border-radius-popover); + transition-property: display, opacity, translate; + transition-duration: 0.3s; + transition-timing-function: var(--ease-out-quad); + transition-behavior: allow-discrete; + translate: 0 20px; + opacity: 0; + } + + .localization-wrapper:not([hidden]) { + translate: 0 0; + opacity: 1; + } + @starting-style { + .localization-wrapper:not([hidden]) { + translate: 0 20px; + opacity: 0; + } + } + + .localization-form__list-item:not([hidden]) { + margin-block-end: var(--margin-3xs); + display: flex; + gap: var(--margin-sm); + padding: 8px; + border-radius: 8px; + line-height: var(--font-line-height-md); + align-items: center; + text-align: start; + cursor: pointer; + transition: background-color var(--animation-speed) var(--animation-easing); + + .country { + flex: 1; + color: var(--color-foreground); + } + + &:hover { + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-8)); + } + + &[aria-current='true'] { + .country { + font-weight: 500; + } + } + } + + .localization-form__list-item#no-results-message { + grid-template-columns: 1fr; + text-align: center; + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .is-searching .localization-form__list-item .country { + color: rgb(var(--color-foreground-rgb) / var(--opacity-80)); + } + + .localization-form__list-item .country mark { + font-weight: 500; + background: none; + color: var(--color-foreground); + } + + .country-filter { + position: relative; + padding: var(--padding-xs); + border-bottom: var(--style-border-width) solid transparent; + transition: border-color var(--animation-values); + } + + .country-filter.is-scrolled { + border-color: var(--color-border); + } + + .drawer-localization .country-filter { + padding-block: 8px; + } + + dropdown-localization-component .country-filter { + position: relative; + padding: 8px; + } + + .country-selector-form__wrapper { + overflow-y: auto; + max-height: 100%; + flex-grow: 1; + } + + .language-selector { + display: flex; + gap: var(--gap-xs); + padding: var(--padding-md) var(--padding-lg); + position: relative; + align-items: center; + justify-content: space-between; + width: 100%; + } + + .language-selector__label { + flex-shrink: 0; + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .localization-form__select { + border: none; + color: var(--color-foreground); + appearance: none; + background-color: var(--color-input-background); + padding-block: var(--padding-3xs); + padding-inline: var(--padding-xs) calc(var(--icon-size-xs) + var(--padding-xs)); + text-align: right; + cursor: pointer; + max-width: 40vw; + text-overflow: ellipsis; + + &:focus-visible { + outline: var(--focus-outline-width) solid currentcolor; + } + + &:focus { + outline: none; + } + } + + #header-component[transparent] localization-form-component .localization-form .localization-form__select { + background-color: transparent; + } + + .localization-form__select option { + background-color: var(--color-input-background); + color: var(--color-input-text); + } + + dropdown-localization-component .localization-form__select:hover { + background-color: rgb(var(--color-primary-hover-rgb) / var(--opacity-8)); + } + + .language-selector .svg-wrapper.icon-caret { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + } + + .language-selector--collapse-space { + padding-inline-end: var(--padding-2xs); + } + + .language-selector--collapse-space .localization-form__select { + padding-inline-end: var(--icon-size-xs); + } + + .language-selector--collapse-space .svg-wrapper.icon-caret { + right: 0; + } + + .localization-form .icon-checkmark { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .localization-form .svg-wrapper.icon-checkmark { + visibility: hidden; + } + + .localization-form__list-item[aria-current='true'] .svg-wrapper.icon-checkmark { + visibility: visible; + } + + .country-filter__input { + width: 100%; + height: 44px; + font-size: var(--font-size-lg); + padding: var(--padding-md) var(--padding-lg) var(--padding-md) calc(var(--margin-md) + var(--padding-xl)); + border: 1px solid var(--color-foreground); + color: var(--color-input-text); + background-color: var(--color-input-background); + outline-offset: -1px; + + @media screen and (min-width: 750px) { + height: 36px; + } + } + + .country-filter__input::placeholder { + color: inherit; + } + + .country-filter .field { + position: relative; + } + + .country-filter .field__label { + font-size: var(--font-size-lg); + left: var(--margin-2xl); + top: var(--margin-xl); + pointer-events: none; + position: absolute; + } + + .country-filter__input:focus ~ .field__label, + .country-filter__input:not(:placeholder-shown) ~ .field__label, + .country-filter__input:-webkit-autofill ~ .field__label { + font-size: var(--font-size-xs); + top: var(--margin-xs); + } + + .country-filter .field__button:not([hidden]) { + display: flex; + height: fit-content; + position: absolute; + padding: 0; + right: 8px; + top: 50%; + transform: translateY(-50%); + align-items: center; + background-color: transparent; + color: var(--color-input-text); + border: 0; + } + + input[type='search']::-webkit-search-cancel-button { + appearance: none; + } + + .country-selector__close-button { + display: none; + } + + .drawer-localization .drawer-localization__button { + display: flex; + padding: 0; + position: relative; + text-decoration: none; + height: 44px; + + &:hover { + color: var(--color-foreground); + } + } + + .drawer-localization .drawer-localization__button .icon-caret { + width: fit-content; + height: fit-content; + margin: 0; + padding: var(--padding-xl) var(--padding-xl) var(--padding-xl) var(--padding-xs); + } + + dropdown-localization-component { + position: relative; + background-color: transparent; + } + + dropdown-localization-component .country-filter__input { + border: none; + } + + dropdown-localization-component .localization-form__list-item { + margin-inline: 8px; + } + + dropdown-localization-component .localization-wrapper { + box-shadow: var(--shadow-popover); + border: var(--style-border-popover); + background-color: var(--color-background); + max-height: 27.5rem; + position: absolute; + top: calc(100% + 10px); + z-index: calc(var(--layer-header-menu) + 1); + } + + dropdown-localization-component .localization-wrapper.right-bound { + right: 0; + left: unset; + } + + dropdown-localization-component .localization-wrapper.left-bound { + left: -8px; + right: unset; + } + + /* Additional specificity due to dropdown-localization-component getting a low score */ + dropdown-localization-component .language-selector.language-selector { + padding: 10px 8px 10px 16px; + } + + dropdown-localization-component .localization-form__currency { + width: max-content; + opacity: 0; + visibility: hidden; + transition: none; + } + + dropdown-localization-component + :is( + .localization-form__list-item:hover, + .localization-form__list-item[aria-selected='true'], + .localization-form__list-item[aria-current='true'] + ) + .localization-form__currency { + opacity: 1; + color: var(--color-foreground-muted); + transition: opacity var(--animation-speed-slow) var(--animation-easing); + visibility: visible; + } + + .dropdown-localization .language-selector:where(:not(.top-shadow)) { + font-weight: var(--menu-top-level-font-weight); + } + + .dropdown-localization:not(dropdown-localization-component) .language-selector, + .menu-drawer__localization:not(drawer-localization-component) .language-selector { + font-family: var(--menu-localization-font); + font-size: var(--menu-localization-font-size); + } + + .menu-drawer__localization .language-selector.h5 { + padding-inline-start: 0; + } + + .header__column .localization-form__select { + background-color: var(--header-bg-color); + } + + .drawer-localization { + display: contents; + color: var(--color-foreground); + } + + .drawer-localization localization-form-component { + position: relative; + height: 100%; + } + + .drawer-localization .mobile-localization, + .drawer-localization .drawer-localization__button--label { + display: flex; + gap: var(--gap-xs); + margin-block: 0; + align-items: center; + } + + .drawer-localization__button--label.h6 { + font-family: var(--menu-localization-font); + } + + .drawer-localization img { + width: var(--icon-size-sm); + } + + .drawer-localization .localization-button__icon, + .drawer-localization .localization-button__icon svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .drawer-localization summary.is-disabled { + pointer-events: none; + } + + .drawer-localization .localization-wrapper { + width: 100%; + } + + .drawer-localization .localization-form { + display: flex; + flex-direction: column; + position: absolute; + inset: 0; + width: 100%; + height: 100%; + } + + .drawer-localization .localization-form > * { + padding-inline: var(--padding-xl); + } + + .drawer-localization .language-selector .svg-wrapper.icon-caret { + transform: translateY(-50%) rotate(0deg); + } + + .drawer-localization .language-selector .svg-wrapper.icon-caret svg { + transform: none; + } +{% endstylesheet %} diff --git a/snippets/media.liquid b/snippets/media.liquid new file mode 100644 index 000000000..f99f946ef --- /dev/null +++ b/snippets/media.liquid @@ -0,0 +1,116 @@ +{%- doc -%} + Renders media block contents (used in _media and _media-without-appearance blocks) + + @param {string} section_id - The section ID + @param {object} [block] - The block object + @param {boolean} [unset_image_tag] - if true, ignores the image focal point in the image +{%- enddoc -%} + +{% liquid + assign show_image = false + assign show_video = false + + if block.settings.media_type == 'image' + assign show_image = true + endif + + if block.settings.media_type == 'video' + assign show_video = true + endif +%} + +
    + {%- if show_image -%} + {% capture image_tag %} + {% if block.settings.image != blank %} + {% render 'image', + image: block.settings.image, + class: 'media-block__media border-style', + unset_image_tag: unset_image_tag + %} + {% else %} +
    + {{ 'detailed-apparel-1' | placeholder_svg_tag: 'hero__image' }} +
    + {% endif %} + {% endcapture %} + + {% if block.settings.link != blank %} + + {{ image_tag }} + + {% else %} + {{ image_tag }} + {% endif %} + {%- elsif show_video -%} + {% render 'video', + video: block.settings.video, + video_autoplay: block.settings.video_autoplay, + video_loop: block.settings.video_loop, + video_class: 'media-block__media media-block__media--video border-style', + section_id: section_id + %} + {%- else -%} +
    + {{ 'hero-apparel-3' | placeholder_svg_tag }} +
    + {%- endif -%} +
    + +{% stylesheet %} + .media-block { + overflow: hidden; + position: relative; + + @media screen and (min-width: 750px) { + min-height: var(--media-height); + } + } + + .media-block__media { + height: var(--media-height-mobile, auto); + object-fit: var(--image-position, 'cover'); + object-position: center center; + width: 100%; + + @media screen and (min-width: 750px) { + height: 100%; + position: absolute; + } + } + + deferred-media[class].media-block__media + :is(.deferred-media__poster-button img, .deferred-media__poster-button ~ video) { + object-fit: var(--video-position, 'cover'); + } + + /* This is to support corner radius on video and align the video to the center of the block */ + .media-block__media--video { + display: flex; + align-items: center; + justify-content: center; + + @media screen and (max-width: 749px) { + --media-height-mobile: auto; + } + } +{% endstylesheet %} diff --git a/snippets/mega-menu-list.liquid b/snippets/mega-menu-list.liquid new file mode 100644 index 000000000..69174704a --- /dev/null +++ b/snippets/mega-menu-list.liquid @@ -0,0 +1,288 @@ +{%- doc -%} + Renders mega menu list markup and optional featured content. + + @param {object} parent_link - The linklist to render. + @param {string} id - Unique ID to assign to the `
      ` element. + @param {number} [grid_columns_count] - Number of grid columns for the mega menu. + @param {number} [grid_columns_count_tablet] - Number of grid columns for the mega menu on tablets. + @param {number} [grid_columns_count_collection_images] - Number of grid columns when `menu_content_type` is 'collection_images'. + @param {string} [menu_content_type] - Type of content: 'featured_products', 'featured_collections', 'collection_images', or 'text'. + @param {number} [content_aspect_ratio] - Aspect ratio for content images. + @param {number} [image_border_radius] - Border radius for content images. + + @example + {% render 'mega-menu-list', parent_link: link, id: 'MegaMenuList-1', grid_columns_count: 6, menu_content_type: 'featured_products' %} +{%- enddoc -%} + +{% liquid + comment + open_column_span tracks when a vertical column in the mega menu is open. Links will be stacked + in the column until the code closes the column span. + endcomment + assign open_column_span = false + assign column_count = 0 + assign links_before_wrap = 10 + assign max_menu_columns = grid_columns_count | default: 6 + assign max_menu_columns_tablet = grid_columns_count_tablet | default: 4 + + if menu_content_type == 'collection_images' + assign collection_links = parent_link.links | where: 'type', 'collection_link' + assign catalog_links = parent_link.links | where: 'type', 'catalog_link' + assign collection_list_links = parent_link.links | where: 'type', 'collections_link' + if collection_links.size == 0 and catalog_links.size == 0 and collection_list_links.size == 0 + assign menu_content_type = 'text' + endif + endif + + if menu_content_type == 'featured_collections' + if parent_link.type == 'collection_link' + assign collection_handles = parent_link.object.handle | append: ',' + elsif parent_link.type == 'catalog_link' or parent_link.type == 'collections_link' + assign collection_handles = 'all' | append: ',' + endif + assign collection_links = parent_link.links | where: 'type', 'collection_link' + for collection_link in collection_links + assign collection_handles = collection_handles | append: collection_link.object.handle | append: ',' + endfor + endif + + if menu_content_type == 'featured_products' + if parent_link.type == 'collection_link' + assign collection_object = parent_link.object + elsif parent_link.type == 'catalog_link' or parent_link.type == 'collections_link' + assign collection_object = collections.all + else + assign menu_content_type = 'text' + endif + endif +%} +
        + {% for link in parent_link.links %} + {% liquid + # Decide whether to open a column span, and how many columns of the grid to span + if forloop.first or open_column_span == false + assign open_column_span = true + + # Don't allow orphan links in a column + assign break_after_modulo = link.links.size | modulo: links_before_wrap + if break_after_modulo == 1 + assign links_before_wrap = links_before_wrap | minus: 1 + endif + assign break_after_float = links_before_wrap | times: 1.0 + assign column_span = link.links.size | divided_by: break_after_float | ceil | at_least: 1 + assign column_count = column_count | plus: column_span + assign should_break_columns = true + assign span_class = 'mega-menu__column mega-menu__column--span-' | append: column_span + if menu_content_type == 'collection_images' + assign should_break_columns = false + # temporary fix to use 8 column grid (spanning 2) when fewer than 5 collection image links + if parent_link.links.size < 5 + assign span_class = span_class | append: ' mega-menu__column--collection-image' + endif + endif + echo '
      • ' + endif + %} +
        + + {% if menu_content_type == 'collection_images' %} + {% render 'link-featured-image', link: link, class: 'mega-menu__link-image' %} + {% endif %} + + {{- link.title -}} + + + {% if link.links != blank %} +
          + {% for childLink in link.links %} + {% assign break_after_modulo = forloop.index | modulo: links_before_wrap %} +
        • + + {{- childLink.title -}} + +
        • + {% endfor %} +
        + {% endif %} +
        + + {% liquid + # Check conditions for closing the span at the end of each iteration, then close the span if needed + assign next_linklist = parent_link.links[forloop.index] + + if forloop.last + assign open_column_span = false + elsif menu_content_type == 'collection_images' + assign open_column_span = false + elsif next_linklist.links != blank + assign open_column_span = false + elsif link.links != blank and next_linklist.links == blank + assign open_column_span = false + endif + + if open_column_span == false + echo '
      • ' + endif + %} + {% endfor %} +
      + +{% liquid + # decide how many grid columns are needed for the menu list, and how many columns are needed for the featured content + # prioritize a minimum of 1 featured_collection (2 columns), and minimum 2 featured_products (2 columns) + assign min_products = 2 + assign max_products = 3 + assign min_products_tablet = 1 + assign max_products_tablet = 3 + assign min_collections = 1 + + if menu_content_type == 'featured_products' + # desktop breakpoint + assign temp_column_count = column_count | plus: min_products + + if temp_column_count > max_menu_columns + assign max_product_columns = 2 + else + assign max_product_columns = max_menu_columns | minus: column_count | at_most: max_products + endif + + assign max_product_columns = max_product_columns | at_most: collection_object.products.size + + assign max_featured_products = max_product_columns + assign max_menu_columns = max_menu_columns | minus: max_product_columns + + # tablet breakpoint + assign temp_column_count = column_count | plus: min_products_tablet + + if temp_column_count > max_menu_columns_tablet + assign max_product_columns_tablet = 1 + else + assign max_product_columns_tablet = max_menu_columns_tablet | minus: column_count | at_most: max_products_tablet + endif + + assign max_product_columns_tablet = max_product_columns_tablet | at_most: collection_object.products.size + + assign max_featured_products_tablet = max_product_columns_tablet + assign max_menu_columns_tablet = max_menu_columns_tablet | minus: max_product_columns_tablet + endif + + if menu_content_type == 'featured_collections' + # desktop breakpoint + assign min_featured_collection_columns = min_collections | times: 2 + assign temp_column_count = column_count | plus: min_featured_collection_columns + + if temp_column_count > max_menu_columns + assign max_collection_columns = 2 + else + assign max_collection_columns = max_menu_columns | minus: column_count + endif + + assign max_featured_collections = max_collection_columns | divided_by: 2 | floor + assign max_menu_columns = max_menu_columns | minus: max_collection_columns + + # tablet breakpoint + assign max_collection_columns_tablet = 2 + assign max_featured_collections_tablet = 1 + assign max_menu_columns_tablet = max_menu_columns_tablet | minus: max_collection_columns_tablet + endif +%} + +{% style %} + [data-menu-grid-id="{{ id }}"] { + {% if menu_content_type == 'collection_images' and parent_link.links.size < 5 %} + --menu-columns-desktop: {{ grid_columns_count_collection_images }}; + --menu-columns-tablet: {{ grid_columns_count_tablet }}; + {% else %} + --menu-columns-desktop: {{ grid_columns_count }}; + --menu-columns-tablet: {{ grid_columns_count_tablet }}; + {% endif %} + } + + [data-menu-list-id="{{ id }}"] { + {% if menu_content_type == 'collection_images' and parent_link.links.size < 5 %} + --menu-columns-desktop: {{ grid_columns_count_collection_images }}; + --menu-columns-tablet: {{ max_menu_columns_tablet }}; + {% else %} + --menu-columns-desktop: {{ max_menu_columns }}; + --menu-columns-tablet: {{ max_menu_columns_tablet }}; + {% endif %} + } +{% endstyle %} + +{% case menu_content_type %} + {% when 'featured_products' %} + +
        + {% paginate collection_object.products by max_featured_products %} + {% for item in collection_object.products %} + + {% endfor %} + {% endpaginate %} +
      +
      + {% when 'featured_collections' %} + {% assign collection_handles = collection_handles | split: ',' | uniq %} + + {% if collection_handles.size == 1 %} + {% assign max_featured_collections = 1 %} + {% endif %} + + +
        + {% for handle in collection_handles limit: max_featured_collections %} + {% if handle == 'all' %} + {% assign collection_object = collections.all %} + {% else %} + {% assign collection_object = collections[handle] %} + {% endif %} + + {% endfor %} +
      +
      +{% endcase %} diff --git a/snippets/mega-menu.liquid b/snippets/mega-menu.liquid new file mode 100644 index 000000000..3267722cc --- /dev/null +++ b/snippets/mega-menu.liquid @@ -0,0 +1,29 @@ +{%- doc -%} + Renders a mega menu list and optional "more" menu links. + When more menu links are present a duplicate instance of each submenu is also rendered. + + @param {object} [section] - The section object. + @param {linklist} [parent_link] - The linklist to render + @param {string} [id] - Unique ID to assign ul in markup + @param {string} [menu_content_type] - The type of content to render, options: ['featured_products', 'featured_collections', 'collection_images', 'text'] (default: 'text') + @param {number} [content_aspect_ratio] - The aspect ratio to display the content if applicable + @param {number} [image_border_radius] - The border radius used for the content images +{%- enddoc -%} + +
      +
      + {% render 'mega-menu-list', + parent_link: parent_link, + id: id, + grid_columns_count: 6, + grid_columns_count_tablet: 4, + grid_columns_count_collection_images: 8, + menu_content_type: menu_content_type, + content_aspect_ratio: content_aspect_ratio, + image_border_radius: image_border_radius + %} +
      +
      diff --git a/snippets/menu-font-styles.liquid b/snippets/menu-font-styles.liquid new file mode 100644 index 000000000..21015a907 --- /dev/null +++ b/snippets/menu-font-styles.liquid @@ -0,0 +1,23 @@ +{%- comment -%} + Derives CSS variables from the menu typography settings for 1st level/main menu items. + Accepts: + settings {block.settings} + menu_type {string}: 'drawer' or 'mega_menu' +{%- endcomment -%} + +--menu-top-level-font-family: var(--font-{{ settings.type_font_primary_link }}--family); +--menu-top-level-font-size-desktop: {{ settings.type_font_primary_size }}; --menu-top-level-font-style: var(--font- +{{- settings.type_font_primary_link -}} +--style); --menu-top-level-font-weight: var(--font- +{{- settings.type_font_primary_link -}} +--weight); --menu-top-level-font-case: +{%- if settings.type_case_primary_link == 'uppercase' %}uppercase{% else %}none{% endif -%} +; +{% if menu_type == 'drawer' %} + --menu-top-level-font-size: var(--menu-font-2xl--size); --menu-top-level-font-line-height: + var(--menu-font-2xl--line-height); +{% else %} + --menu-top-level-font-size: var(--menu-font-sm--size); --menu-top-level-font-line-height: + var(--menu-font-sm--line-height); +{% endif %} +--menu-top-level-font-color: var(--color-foreground); --menu-top-level-font-color-rgb: var(--color-foreground-rgb); diff --git a/snippets/meta-tags.liquid b/snippets/meta-tags.liquid new file mode 100644 index 000000000..e4bd0f0a2 --- /dev/null +++ b/snippets/meta-tags.liquid @@ -0,0 +1,121 @@ + + + + + + +{%- liquid + assign og_title = page_title | default: shop.name + assign og_url = canonical_url | default: request.origin + assign og_type = 'website' + assign og_description = page_description | default: shop.description | default: shop.name + + if request.page_type == 'product' + assign og_type = 'product' + elsif request.page_type == 'article' + assign og_type = 'article' + elsif request.page_type == 'password' + assign og_url = request.origin + endif +%} + + + + + + + +{%- if page_image -%} + + + + +{%- endif -%} + +{%- if request.page_type == 'product' -%} + + +{%- endif -%} + +{%- if settings.social_twitter_link != blank -%} + +{%- endif -%} + + + + + + {{ page_title }} + {%- if current_tags %} – tagged "{{ current_tags | join: ', ' }}"{% endif -%} + {%- if current_page != 1 %} – Page {{ current_page }}{% endif -%} + {%- unless page_title contains shop.name %} – {{ shop.name }}{% endunless -%} + + + + +{% if page_description %} + +{% endif %} diff --git a/snippets/overflow-list.liquid b/snippets/overflow-list.liquid new file mode 100644 index 000000000..2bb5b6fcc --- /dev/null +++ b/snippets/overflow-list.liquid @@ -0,0 +1,63 @@ +{%- doc -%} + @param {string} children - The children of the overflow list. + @param {string} [class] - The class that is applied on the overflow-list element. + @param {boolean} [defer] - Whether to defer the loading of the overflow list. + @param {number} [minimum-items] - The minimum number of items to show in the overflow list. + @param {string} [more-attributes] - The attributes that are applied on the more button. + @param {string} [ref] - The ref that is set on the overflow-list element. +{%- enddoc -%} + + + + + {{ children }} + diff --git a/snippets/overlay.liquid b/snippets/overlay.liquid new file mode 100644 index 000000000..02d3d49d3 --- /dev/null +++ b/snippets/overlay.liquid @@ -0,0 +1,38 @@ +{%- doc -%} + Renders a full-bleed overlay. + + @param {object} settings - Block or section settings, expecting `overlay_color`, `overlay_style`, and `gradient_direction`. + @param {string} [layer] - The z-index layer for the overlay, defaults to `var(--layer-flat)`. + + @example + {% render 'overlay', settings: section.settings, layer: 'var(--layer-raised)' %} +{%- enddoc -%} + +
      + +{% stylesheet %} + .overlay { + position: absolute; + inset: 0; + z-index: var(--overlay-layer); + pointer-events: none; + border-radius: var(--overlay-border-radius, 0); + } + + .overlay--solid { + background: var(--overlay-color); + } + + .overlay--gradient { + background: linear-gradient(var(--overlay-direction), var(--overlay-color), var(--overlay-color--end)); + } +{% endstylesheet %} diff --git a/snippets/predictive-search-empty-state.liquid b/snippets/predictive-search-empty-state.liquid new file mode 100644 index 000000000..9b0183d13 --- /dev/null +++ b/snippets/predictive-search-empty-state.liquid @@ -0,0 +1,39 @@ +{% doc %} + Renders the predictive search empty state + + @param {object} empty_state_collection - collection used to in empty state + @param {number} shadow_opacity - shadow opacity for the empty state container shadow + @param {string} products_test_id - a playwright test id, used to differentiate empty state from 'real' search results + + @example + {% render 'predictive-search-empty-state', shadow_opacity: 0.1, products_test_id: 'empty-state' %} +{% enddoc %} + +
      +
      + {% liquid + assign products = settings.empty_state_collection.products | default: collections.all.products + assign default_title = 'content.search_results_resource_products' | t + assign title = settings.empty_state_collection.title | default: default_title + %} + {% comment %} Only show products section if there are products to display {% endcomment %} + {% if products.size > 0 %} + {% render 'predictive-search-products-list', + products_test_id: products_test_id, + title: title, + products: products, + limit: 4 + %} + {% else %} +
      +

      {{ 'content.no_products_found' | t }}

      +
      + {% endif %} +
      +
      diff --git a/snippets/predictive-search-products-list.liquid b/snippets/predictive-search-products-list.liquid new file mode 100644 index 000000000..1b5fafe45 --- /dev/null +++ b/snippets/predictive-search-products-list.liquid @@ -0,0 +1,112 @@ +{%- doc -%} + Renders the predictive search products list for empty state and recently viewed products + + @param {string} title - title of the result list + @param {object[]} products - array of products + @param {string[]} [order_ids] - array of product ids + @param {number} [limit] - limit of products to display + @param {string} [products_test_id] - a playwright test id, used to differentiate empty state from 'real' search results +{%- enddoc -%} +{%- liquid + assign recently_viewed_title_text = 'content.recently_viewed_products' | t +-%} +
      + {% if title == recently_viewed_title_text %} +
      +

      + {{ title }} + +

      +
        + {% liquid + assign limit = limit | default: 8 + %} + {% comment %} + If we're searching for recently viewed products by id, we need to reorder the products. + The order here comes from the search terms, and we display the products in the order of the ids. + {% endcomment %} + {% if order_ids != blank %} + {% for _id in order_ids %} + {% assign int_id = _id | times: 1 %} + {% assign product = products | find: 'id', int_id %} +
      • + {% render 'resource-card', + resource_type: 'product', + resource: product, + image_width: 500, + image_hover: true, + image_aspect_ratio: '4 / 5' + %} +
      • + {% endfor %} + {% else %} + {% for product in products limit: limit %} +
      • + {% render 'resource-card', + resource_type: 'product', + resource: product, + image_width: 500, + image_hover: true, + image_aspect_ratio: '4 / 5' + %} +
      • + {% endfor %} + {% endif %} +
      +
      + {% else %} +

      + {{ title }} +

      +
        + {% liquid + assign limit = limit | default: 8 + %} + {% for product in products limit: limit %} +
      • + {% render 'resource-card', + resource_type: 'product', + resource: product, + image_width: 500, + image_hover: true, + image_aspect_ratio: '4 / 5' + %} +
      • + {% endfor %} +
      + {% endif %} +
      diff --git a/snippets/predictive-search-resource-carousel.liquid b/snippets/predictive-search-resource-carousel.liquid new file mode 100644 index 000000000..93701e716 --- /dev/null +++ b/snippets/predictive-search-resource-carousel.liquid @@ -0,0 +1,65 @@ +{%- doc -%} + Renders a carousel of predictive search results cards. + + @param {string} title - The title of the carousel. + @param {object} resources - The resources to display. + @param {string} resource_type - The type of resource to display. +{%- enddoc -%} + +{% liquid + capture slides + for resource in resources + capture children + render 'resource-card', resource_type: resource_type, resource: resource, image_aspect_ratio: '4 / 5', collection_thumbnails: 'multiple' + endcapture + render 'slideshow-slide', index: forloop.index0, children: children, class: 'predictive-search-results__card' + endfor + endcapture +%} + +{% capture header %} +
      +

      + {{ title }} +

      + + {% if resources.size >= 4 %} + {%- render 'slideshow-controls', + show_arrows: true, + icon_style: 'chevron', + shape: 'none' + -%} + {% endif %} +
      +{% endcapture %} + +{% assign slideshow_class = 'predictive-search-results__list predictive-search-results__wrapper list-unstyled slideshow--single-media' %} +{% if resources.size >= 4 %} + {% assign slideshow_class = 'predictive-search-results__list predictive-search-results__wrapper list-unstyled' %} +{% endif %} + +{% render 'slideshow', + class: slideshow_class, + header: header, + infinite: false, + slides: slides, + slide_count: resources.size, + icon_style: 'chevron', + slideshow_gutters: 'start end' +%} + +{% stylesheet %} + .predictive-search-results__wrapper slideshow-slides { + /* Add padding to prevent hover animations from being clipped in slideshow + 15px accommodates: + - Scale effect (9px on each side from 1.03 scale) + - Lift effect (4px upward movement) + - Shadow (15px spread with -5px offset) + Using 16px for better alignment with our spacing scale */ + padding-block: var(--padding-xl); + margin-block: calc(-1 * var(--padding-xl)); + } +{% endstylesheet %} diff --git a/snippets/predictive-search.liquid b/snippets/predictive-search.liquid new file mode 100644 index 000000000..e42058db1 --- /dev/null +++ b/snippets/predictive-search.liquid @@ -0,0 +1,135 @@ +{%- doc -%} + Renders the predictive search input and results. + + @param {string} [class] - Additional classes to add to the component. + @param {string} [search_position] - Lateral position of the search component in the header ('left' or 'right'). + @param {string} [search_test_id] - A Playwright test ID for differentiating search components. + @param {string} [input_id] - The ID for the search input element. + @param {string} [products_test_id] - A Playwright test ID for differentiating products. + + @example + {% render 'predictive-search', search_position: 'left', search_test_id: 'header-search' %} +{%- enddoc -%} + + + + + + + +{% stylesheet %} + predictive-search-component { + &:has([data-search-results]):not(:has(.predictive-search-results__no-results)) { + .predictive-search-form__footer { + display: block; + } + } + } + + .predictive-search-form__footer { + display: none; + } +{% endstylesheet %} diff --git a/snippets/price-filter.liquid b/snippets/price-filter.liquid new file mode 100644 index 000000000..d772538c1 --- /dev/null +++ b/snippets/price-filter.liquid @@ -0,0 +1,239 @@ +{%- doc -%} + Renders a price filter. + + @param {object} filter - The filter object to render. + @param {string} filter_style - The filter style, can be 'horizontal' or 'vertical'. + @param {boolean} [autofocus] - Whether to autofocus the filter. + @param {boolean} [should_render_clear] - Whether to render the clear button. + + @example + {% render 'price-filter', filter: filter, filter_style: 'vertical' %} +{%- enddoc -%} + + +
      + + {{ filter.label }} + + + + + {%- if filter.min_value.value != null or filter.max_value.value != null %} + {%- if filter.min_value.value != null and filter.max_value.value != null %} + {{- filter.min_value.value | money | strip_html -}} + – + {{- filter.max_value.value | money | strip_html -}} + {%- elsif filter.min_value.value != null -%} + {{ filter.min_value.value | money | strip_html }}–{{ filter.range_max | money | strip_html }} + + {%- elsif filter.max_value.value != null -%} + {{- 0 | money | strip_html -}} + – + {{- filter.max_value.value | money | strip_html -}} + {%- endif -%} + {%- endif -%} + + + + {{- 'icon-caret.svg' | inline_asset_content -}} + + + + {% assign min_input_max_value = filter.max_value.value | default: filter.range_max %} + {% assign max_input_min_value = filter.min_value.value | default: 0 %} + + +
      +
      + + +
      + +
      {{ 'fields.separator' | t }}
      + +
      + + +
      +
      + +
      + {%- assign formatted_highest_price = filter.range_max | money -%} + {{ 'content.price_filter_html' | t: price: formatted_highest_price }} +
      + + {% if filter.min_value.value != null or filter.max_value.value != null %} + {% assign has_active_values = true %} + {% endif %} + + {% if should_render_clear %} + +
      + {{- 'actions.clear' | t -}} +
      +
      + {% endif %} +
      +
      +
      +
      + +{% stylesheet %} + /* Price filter */ + .price-facet { + container-type: inline-size; + display: flex; + flex-direction: column; + } + + .facets__inputs-wrapper.price-facet__inputs-wrapper { + flex-wrap: nowrap; + } + + .price-facet__field { + width: 50%; + flex-grow: 0; + } + + @container (max-width: 199px) { + .facets__inputs-wrapper.price-facet__inputs-wrapper { + flex-wrap: wrap; + width: 100%; + } + + .price-facet__inputs-wrapper .price-facet__field { + width: 100%; + } + } + + .facets .facets__inputs-wrapper.price-facet__inputs-wrapper { + padding: var(--style-border-width-inputs); + gap: calc(var(--gap-sm) + (var(--style-border-width-inputs) * 2)); + } + + .facets--horizontal .facets__panel-content:has(.price-facet) { + min-width: 360px; + } + + .facets--horizontal .facets__inputs-wrapper.price-facet__inputs-wrapper { + @media screen and (min-width: 750px) { + padding: calc(var(--padding-md) + var(--style-border-width-inputs)); + } + } + + .price-facet__input { + width: 100%; + text-align: right; + padding-left: calc(2.5 * var(--input-padding-x)); + } + + .price-facet__input::placeholder { + color: var(--facets-input-label-color); + } + + .price-facet__separator { + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-paragraph--size); + } + + .price-facet__highest-price { + padding: var(--padding-xs) 0 var(--padding-sm); + } + + .facets--horizontal .price-facet__highest-price { + padding: 0 var(--padding-md) var(--padding-xs); + } + + .field__label.price-facet__label { + top: 0; + left: 0; + color: var(--facets-input-label-color); + padding: var(--input-padding-y) var(--input-padding-x); + transform: none; + } +{% endstylesheet %} diff --git a/snippets/price.liquid b/snippets/price.liquid new file mode 100644 index 000000000..7369b79ff --- /dev/null +++ b/snippets/price.liquid @@ -0,0 +1,79 @@ +{%- doc -%} + This snippet is used to render a product card. + It is used in the product block,featured product block, and the product card block. + + @param {product} product_resource - The product to render + @param {boolean} [show_unit_price] - Whether to show the unit price + @param {boolean} [show_sale_price_first] - Whether to show the sale price first +{%- enddoc -%} + +{%- liquid + assign show_unit_price = show_unit_price | default: false + assign show_sale_price_first = show_sale_price_first | default: false + assign selected_variant = product_resource.selected_or_first_available_variant + assign price = selected_variant.price + assign compare_at_price = selected_variant.compare_at_price + + assign show_compare_price = false + if compare_at_price > price + assign show_compare_price = true + endif + + if product_resource == blank + assign price = 1999 + endif + + # Checks if product handle matches the closest product's handle (i.e. product page) + # and if the currency code is enabled for product pages + if product.handle == closest.product.handle and settings.currency_code_enabled_product_pages + assign price = price | money_with_currency + assign compare_at_price = compare_at_price | money_with_currency + + # Checks if product handle does not match the closest product's handle (i.e. product card) + # and if the currency code is enabled for product cards + elsif product.handle != closest.product.handle and settings.currency_code_enabled_product_cards + assign price = price | money_with_currency + assign compare_at_price = compare_at_price | money_with_currency + + else + assign price = price | money + assign compare_at_price = compare_at_price | money + endif +-%} + +
      + {% if show_sale_price_first == false and show_compare_price %} + + {{ 'content.price_regular' | t }}  + {{- compare_at_price -}} + + {% endif %} + + {% if show_compare_price %} + + {{ 'content.price_sale' | t }}  + {{ price | default: ' ' }} + + {% else %} + {{ price | default: ' ' }} + {% endif %} + + {% if show_sale_price_first == true and show_compare_price %} + + {{ 'content.price_regular' | t }}  + {{- compare_at_price -}} + + {% endif %} + {%- if selected_variant.unit_price and show_unit_price %} + {%- liquid + if product.handle == closest.product.handle and settings.currency_code_enabled_product_pages + assign unit_price = selected_variant.unit_price | money_with_currency + elsif product.handle != closest.product.handle and settings.currency_code_enabled_product_cards + assign unit_price = selected_variant.unit_price | money_with_currency + else + assign unit_price = selected_variant.unit_price | money + endif + -%} + {% render 'unit-price', price: unit_price, measurement: selected_variant.unit_price_measurement %} + {%- endif -%} +
      diff --git a/snippets/product-card-badges.liquid b/snippets/product-card-badges.liquid new file mode 100644 index 000000000..62b7b1856 --- /dev/null +++ b/snippets/product-card-badges.liquid @@ -0,0 +1,77 @@ +{%- doc -%} + Renders product badges for the product card. + + @param {object} product - The product object. + @param {object} settings - The theme settings object. + + @example + {% render 'product-card-badges', product: product, settings: settings %} +{%- enddoc -%} + +
      + {%- if product.available == false or product.compare_at_price > product.price and product.available -%} +
      + {%- if product.available == false -%} + {{ 'content.product_badge_sold_out' | t }} + {%- elsif product.compare_at_price > product.price -%} + {{ 'content.product_badge_sale' | t }} + {%- endif -%} +
      + {%- endif -%} +
      + +{% stylesheet %} + .product-badges { + --badge-inset: max(var(--padding-xs), calc((var(--border-radius) + var(--padding-xs)) * (1 - cos(45deg)))); + + position: absolute; + z-index: var(--layer-flat); + } + + .product-badges--bottom-left { + bottom: calc(var(--badge-inset) + var(--padding-block-start)); + left: calc(var(--badge-inset) + var(--padding-inline-start)); + } + + .product-badges--top-left { + top: calc(var(--badge-inset) + var(--padding-block-start)); + left: calc(var(--badge-inset) + var(--padding-inline-start)); + } + + .product-badges--top-right { + top: calc(var(--badge-inset) + var(--padding-block-start)); + right: calc(var(--badge-inset) + var(--padding-inline-start)); + } + + .product-badges__badge { + --badge-font-size: var(--font-size--xs); + + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: var(--color-foreground); + background: var(--color-background); + font-size: var(--badge-font-size); + font-family: var(--badge-font-family); + font-weight: var(--badge-font-weight); + text-transform: var(--badge-text-transform); + border-radius: var(--badge-border-radius); + } + + .product-badges__badge--rectangle { + padding-block: var(--badge-rectangle-padding-block); + padding-inline: var(--badge-rectangle-padding-inline); + } +{% endstylesheet %} diff --git a/snippets/product-card.liquid b/snippets/product-card.liquid new file mode 100644 index 000000000..e210f7d53 --- /dev/null +++ b/snippets/product-card.liquid @@ -0,0 +1,231 @@ +{%- doc -%} + This snippet is used to render a product card. + It is used in the product block, featured product block, and the product card block. + The product object is null or when placeholders are rendered. + + @param {object} product - The product object + @param {object} children - The children of the product card + @param {object} [block] - The block object + @param {number} [product_card_gap] - The gap between the product card children (overrides block settings) +{%- enddoc -%} + +{% style %} + {% if request.visual_preview_mode %} + product-card-link { + width: 100%; + min-width: 250px; + } + {% endif %} +{% endstyle %} + +{% liquid + assign has_quick_add = false + if settings.quick_add and product.available + assign has_quick_add = true + endif + + assign has_mobile_quick_add = false + if has_quick_add and settings.mobile_quick_add + assign has_mobile_quick_add = true + endif + + assign product_card_id = 'product-card-link-' | append: block.id | append: '-' | append: product.id + assign product_card_gap_value = product_card_gap | default: block.settings.product_card_gap + + # Logic to determine which variant URL to use (matching swatch selection logic) + assign variant_to_link = product.selected_or_first_available_variant + assign combined_listing_count = product.options_with_values | map: 'values' | map: 'product_url' | compact | size + + unless combined_listing_count > 0 + assign first_image = product.media.first + assign variant_images = product.images | where: 'attached_to_variant?', true + # Get swatchable options (options that have swatch values) + assign swatch_variant_picker = null + for option in product.options_with_values + assign swatch_count = option.values | map: 'swatch' | compact | size + if swatch_count > 0 + assign swatch_variant_picker = option + break + endif + endfor + + if swatch_variant_picker + assign swatch_count = swatch_variant_picker.values | map: 'swatch' | compact | size + assign no_swatch_selected = null + + if swatch_count == 1 + # Single swatch: use that variant + assign variant_to_link = swatch_variant_picker.values.first.variant + elsif swatch_count > 1 + if first_image and variant_images contains first_image + # First image is a variant image - find which variant it belongs to + for option_value in swatch_variant_picker.values + if option_value.variant.featured_media.id == first_image.id + assign variant_to_link = option_value.variant + break + endif + endfor + elsif variant_images.size == 0 + # No variants have images - use first swatch variant + assign variant_to_link = swatch_variant_picker.values.first.variant + else + assign no_swatch_selected = true + endif + # else: First image is NOT a variant image - keep default (selected_or_first_available_variant) + endif + endif + endunless + + if settings.transition_to_main_product + assign featured_image = variant_to_link.featured_image + if featured_image == blank + assign featured_image = product.featured_media.preview_image + endif + + if featured_image != blank + assign featured_media_url = featured_image | image_url: width: 500 + endif + endif + + assign onboarding = false + if product.id == empty + assign onboarding = true + endif +%} + +{%- if settings.transition_to_main_product -%} + +{%- endif -%} + + + + {{ product.title }} + + +
      + {{ children }} +
      +
      +{%- if settings.transition_to_main_product -%} +
      +{%- endif -%} + +{% stylesheet %} + product-card-link, + :not(product-card-link) product-card { + width: 100%; + } + + .product-card__placeholder-image svg { + height: 100%; + } + + @media screen and (max-width: 749px) { + .product-card slideshow-arrows .slideshow-control { + display: none; + } + } + + /* Hide the variant swatches for product cards that show a swatches variant picker */ + :is(.product-card):has(swatches-variant-picker-component) .quick-add .variant-option--swatches { + display: none; + } + + /* Hide "Add" button for single option product cards that show a swatches variant picker */ + :is(.product-card:not([data-no-swatch-selected])):has(.quick-add__product-form-component--single-option):has( + swatches-variant-picker-component + ) + .quick-add__button--choose { + display: none; + } + + /* Hide "Add" button for single option product cards that show a swatches variant picker */ + :is(.product-card[data-no-swatch-selected]):has(.quick-add__product-form-component--single-option):has( + swatches-variant-picker-component + ) + add-to-cart-component { + display: none; + } + + /* Hide "add" button for multi-variant product cards that don't show a swatches variant picker */ + :is(.product-card):has(.quick-add__product-form-component--multi-variant):not(:has(swatches-variant-picker-component)) + .quick-add__button--add { + display: none; + } + + /* Hover effect for single variant product cards and product blocks */ + + /* stylelint-disable selector-max-specificity */ + :is(.product-card):has(.quick-add__product-form-component--single-variant) .card-gallery:hover { + & .quick-add__button--choose { + display: none; + } + + & .quick-add__button--add { + display: grid; + } + } + + .product-card[data-no-swatch-selected] slideshow-component[data-generic-media-size='1'] slideshow-arrows { + display: none; + } + + .product-card[data-no-swatch-selected] + slideshow-component[data-generic-media-size='1'] + slideshow-arrows:has(+ slideshow-slides slideshow-slide[variant-image]:not([hidden])) { + display: flex; + } + + .product-card .variant-option__swatch svg { + display: none; + } + + .product-card [data-available-count='0'] ~ svg { + display: block; + } +{% endstylesheet %} diff --git a/snippets/product-grid.liquid b/snippets/product-grid.liquid new file mode 100644 index 000000000..7b43a11fa --- /dev/null +++ b/snippets/product-grid.liquid @@ -0,0 +1,207 @@ +{%- doc -%} + This snippet is used to render the product grid on collection and search pages. + + @param {object} section - The section object + @param {object} paginate - Pagination object + @param {object} products - Array of product objects + @param {string} [title] - Header of the collection or search results + @param {string} children - List or grid of product cards +{%- enddoc -%} + +{% capture product_card_size %} + {% render 'util-product-grid-card-size' section: section %} +{% endcapture %} +{% assign product_card_size = product_card_size | strip %} + +{% style %} + @media (min-width: 750px) { + {% case section.settings.layout_type %} + {% when 'grid' %} + .product-grid--{{ section.id }}:is(.product-grid--grid) { + --product-grid-columns-desktop: repeat(auto-fill, minmax({{ product_card_size }}, 1fr)); + } + {% when 'organic' %} + {% assign large_span = 2 %} + {% assign row_cycle = 3 %} + {% assign product_cycle = row_cycle | times: 2 %} + {% assign right_large_start_col = 3 %} + .product-grid--{{ section.id }}:not([product-grid-view='zoom-out']):is(.product-grid--organic) .product-grid__item:nth-child({{ product_cycle }}n + 1) { + grid-column: 1 / span {{ large_span }}; + } + + .product-grid--{{ section.id }}:not([product-grid-view='zoom-out']):is(.product-grid--organic) .product-grid__item:nth-child({{ product_cycle }}n + 2), + .product-grid--{{ section.id }}:not([product-grid-view='zoom-out']):is(.product-grid--organic) .product-grid__item:nth-child({{ product_cycle }}n + 5) { + align-self: end; + } + + .product-grid--{{ section.id }}:not([product-grid-view='zoom-out']):is(.product-grid--organic) .product-grid__item:nth-child({{ product_cycle }}n + {{ product_cycle }}) { + grid-column: {{ right_large_start_col }} / span {{ large_span }}; + } + + .product-grid--{{ section.id }}:not([product-grid-view='zoom-out']):is(.product-grid--organic) { + --product-grid-columns-desktop: repeat(4, 1fr); + } + {% endcase %} + + /* This logic helps prevent displaying one column for an large or extra-large product card size on a small screen. We want it to display at least two columns. */ + {% case section.settings.product_card_size %} + {% when 'extra-large' or 'large' %} + @container product-grid (max-width: calc({{ product_card_size }} * 3 + {{ section.settings.columns_gap_horizontal }}px * 2)) { + .product-grid--{{ section.id }}:is(.product-grid--grid) { + --product-grid-columns-desktop: repeat(2, 1fr); + } + } + {% endcase %} + + /* When zoomed out, fit as many 100px-wide columns as possible */ + .product-grid--{{ section.id }}:is([product-grid-view='zoom-out']) { + --product-grid-columns-desktop: repeat(auto-fill, minmax(6.25rem, 1fr)); + } + + .product-grid--{{ section.id }}:is([product-grid-view='zoom-out']) .product-grid-view-zoom-out--details { + display: block; + } + + .product-grid--{{ section.id }}:is([product-grid-view='zoom-out']) .product-grid__card { + padding-inline-start: var(--zoom-out-padding-inline-start, 0); + padding-inline-end: var(--zoom-out-padding-inline-end, 0); + padding-block-start: var(--zoom-out-padding-block-start, 0); + padding-block-end: var(--zoom-out-padding-block-end, 0); + } + } +{% endstyle %} + +
      +
      + {% if products.size == 0 %} +
      +

      + {{ 'content.no_products_found' | t }} +

      +

      + {{ 'content.use_fewer_filters_html' | t: link: collection.url, class: 'main-collection-grid__empty-link' }} +

      +
      + {% else %} + + + {% if title %} +

      {{ title }}

      + {% endif %} +
        + {{ children }} +
      + + {% endif %} +
      +
      + +{% comment %} + This script is used to set the grid view on the product grid stored in sessionStorage. Keeping it here helps us prevent seeing the default state. +{% endcomment %} +{% unless request.design_mode %} + +{% endunless %} + +{% stylesheet %} + .product-grid { + --product-grid-gap: var(--product-grid-gap-mobile); + + isolation: isolate; + + @media screen and (min-width: 750px) { + --product-grid-gap: var(--product-grid-gap-desktop); + } + } + + .product-grid slideshow-arrows .slideshow-control { + display: none; + + @media screen and (min-width: 750px) { + display: grid; + } + } + + .main-collection-grid { + padding: var(--grid--margin--mobile); + + @media screen and (min-width: 750px) { + padding: var(--padding-block-start) var(--padding-inline-end) var(--padding-block-end) var(--padding-inline-start); + } + } + + .main-collection-grid__empty { + padding-block: var(--padding-6xl); + padding-inline: var(--page-margin); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: var(--padding-sm); + } + + .main-collection-grid__empty-title { + margin: 0; + } + + .collection-wrapper--full-width .main-collection-grid__title { + margin-left: var(--page-margin); + } + + .collection-wrapper--full-width-on-mobile .main-collection-grid__title { + @media screen and (max-width: 749px) { + margin-left: var(--page-margin); + } + } +{% endstylesheet %} diff --git a/snippets/product-media.liquid b/snippets/product-media.liquid new file mode 100644 index 000000000..637ae50d4 --- /dev/null +++ b/snippets/product-media.liquid @@ -0,0 +1,208 @@ +{%- doc -%} + Renders a product media component. + + @param {object} media - The product media object. + @param {boolean} [preview_image_only] - Renders only the preview image without controls. + @param {string} [widths] - Image widths for responsive images. + @param {string} [sizes] - Image sizes for responsive images. + @param {string} [loading] - The loading attribute for the image. + @param {object} [block] - The block object. + @param {object} [section] - The section object. + @param {object} [selected_product] - The currently selected product. + @param {boolean} [first_3d_model] - Indicates if this is the first 3D model. + @param {boolean} [is_main_product_media] - Indicates if this is the main product image. + + @example + {% render 'product-media', media: media, preview_image_only: false, loading: 'lazy' %} +{%- enddoc -%} + +{% liquid + assign widths = widths | default: '400, 800, 1200, 1600, 2000' +%} + +
      + {% liquid + assign high_res_url = media.preview_image | image_url: width: 3840 + assign fetch_priority = 'auto' + if is_main_product_media + assign fetch_priority = 'high' + endif + %} + {{ + media.preview_image + | image_url: width: 2000 + | image_tag: + widths: widths, + alt: media.alt, + sizes: sizes, + loading: loading, + class: 'product-media__image', + transitionToProduct: settings.transition_to_main_product, + data_max_resolution: high_res_url, + fetchpriority: fetch_priority + }} + + {% unless preview_image_only %} + {%- case media.media_type -%} + {% when 'model' %} + + + + + + + + {%- if first_3d_model -%} + + {%- endif -%} + {% when 'video', 'external_video' %} + {%- render 'video', + video: media, + video_loop: block.settings.video_loop, + widths: widths, + sizes: sizes, + loading: loading, + disable_controls: true, + section_id: section.id + -%} + {% endcase %} + {% endunless %} +
      + +{% stylesheet %} + .product-media { + aspect-ratio: var(--gallery-aspect-ratio, var(--ratio)); + min-height: 0; + min-width: 0; + } + + /*** Media border-radius feature ****/ + @media screen and (min-width: 750px) { + .media-gallery--carousel slideshow-container, + .media-gallery--grid .product-media > * { + border-radius: var(--media-radius, 0); + overflow: hidden; + } + + /* When the CAROUSEL is on the LEFT side */ + .product-information:not(.product-information--media-right) + .media-gallery--carousel.media-gallery--extend + slideshow-container { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + /* When the CAROUSEL is on the RIGHT side */ + .product-information.product-information--media-right + .media-gallery--carousel.media-gallery--extend + slideshow-container { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + /* When the GRID is on the LEFT side */ + .product-information:not(.product-information--media-right) { + /* One column */ + .media-gallery--grid.media-gallery--extend:not(.media-gallery--two-column) .product-media > *, + /* Two column, small first image */ + .media-gallery--grid.media-gallery--extend.media-gallery--two-column:not(.media-gallery--large-first-image) + .product-media-container:nth-of-type(odd) + .product-media + > *, + /* Two column, large first image */ + .media-gallery--grid.media-gallery--extend.media-gallery--two-column.media-gallery--large-first-image + .product-media-container:is(:first-of-type, :nth-of-type(even)) + .product-media + > * { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + /* When the GRID is on the RIGHT side */ + .product-information.product-information--media-right { + /* One column */ + .media-gallery--grid.media-gallery--extend:not(.media-gallery--two-column) .product-media > *, + /* Two column, small first image */ + .media-gallery--grid.media-gallery--extend.media-gallery--two-column:not(.media-gallery--large-first-image) + .product-media-container:nth-of-type(even) + .product-media + > *, + /* Two column, large first image */ + .media-gallery--grid.media-gallery--extend.media-gallery--two-column.media-gallery--large-first-image + .product-media-container:is(:first-of-type, :nth-of-type(odd)) + .product-media + > * { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + } + } + + ::view-transition-old(gallery-item), + ::view-transition-new(gallery-item) { + animation-duration: 0ms; + } +{% endstylesheet %} diff --git a/snippets/quantity-selector.liquid b/snippets/quantity-selector.liquid new file mode 100644 index 000000000..b42c87a9d --- /dev/null +++ b/snippets/quantity-selector.liquid @@ -0,0 +1,74 @@ +{%- doc -%} + This snippet is used to render the quantity selector for a product. + It is used in the product page and the cart page. + + @param {object} product - the product to render the quantity selector for + @param {number} [in_cart_quantity] - the quantity in the cart to set the input value + @param {number} [line_index] - the index of the forloop representing the line on which the quantity selector is rendered + @param {number} [min] - the minimum quantity the input supports + @param {string} [class] - custom class for the quantity selector, optional + @param {boolean} [can_update_quantity] - whether the quantity can be updated, defaults to true +{%- enddoc -%} + +{% liquid + assign variant = product.selected_or_first_available_variant +%} + + + + + + diff --git a/snippets/quick-add-modal.liquid b/snippets/quick-add-modal.liquid new file mode 100644 index 000000000..cf231d849 --- /dev/null +++ b/snippets/quick-add-modal.liquid @@ -0,0 +1,442 @@ + + + +
      +
      +
      + +{% stylesheet %} + .quick-add-modal { + padding: 0; + border: var(--style-border-popover); + height: fit-content; + overflow: hidden; + min-height: 500px; + box-shadow: 0 5px 30px rgb(0 0 0 / var(--opacity-15)); + + @media screen and (max-width: 750px) { + position: fixed; + display: block; + margin: auto 0 0 0; + min-height: unset; + max-width: 100%; + border-radius: 0; + } + } + + .quick-add-modal[open] { + @media screen and (min-width: 750px) { + display: flex; + } + } + + .quick-add-modal .view-more-details__wrapper { + @media screen and (max-width: 750px) { + display: none; + } + } + + .quick-add-modal[open] { + animation: modalSlideInTop var(--animation-speed) var(--animation-easing) forwards; + } + + .quick-add-modal.dialog-closing { + animation: modalSlideOutTop var(--animation-speed) var(--animation-easing) forwards; + } + + .quick-add-modal__close { + position: absolute; + top: var(--margin-2xs); + right: var(--margin-2xs); + width: var(--minimum-touch-target); + height: var(--minimum-touch-target); + color: var(--color-foreground); + background-color: var(--color-background); + display: flex; + align-items: center; + justify-content: center; + padding: 0; + z-index: 2; + transition: transform 0.15s var(--animation-timing-bounce), opacity 0.15s var(--animation-easing); + } + + .quick-add-modal__close:active { + transform: scale(0.8); + } + + .quick-add-modal__close svg { + width: var(--icon-size-xs); + height: var(--icon-size-xs); + } + + .quick-add-modal__content { + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-template-rows: 100% 1fr; + position: relative; + max-width: var(--wide-content-width); + overflow-y: auto; + max-height: 100vh; + + @media screen and (max-width: 750px) { + grid-template-columns: repeat(4, 1fr); + grid-template-rows: auto; + padding-inline: var(--padding-xl); + padding-block: var(--padding-xl); + gap: var(--gap-lg); + flex: 1; + min-height: 0; + overflow-y: auto; + height: auto; /* Prevent a bug in Safari where height:fit-content is not respected */ + max-height: 100vh; + } + } + + .quick-add-modal__content .media-gallery--grid .media-gallery__grid { + grid-template-columns: 1fr; + } + + .quick-add-modal__content .media-gallery--grid.media-gallery--two-column .product-media-container:first-child { + grid-column: auto; + } + + .quick-add-modal__content { + /* One column */ + .media-gallery--grid:not(.media-gallery--two-column) .product-media > *, + /* Two column, small first image */ + .media-gallery--grid.media-gallery--two-column:not(.media-gallery--large-first-image) + .product-media-container:nth-of-type(odd) + .product-media > *, + /* Two column, large first image */ + .media-gallery--grid.media-gallery--two-column.media-gallery--large-first-image + .product-media-container:is(:first-of-type, :nth-of-type(even)) + .product-media > *, + /* Carousel */ + .media-gallery--carousel slideshow-container { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + .quick-add-modal__content .view-more-details__wrapper { + display: flex; + justify-content: flex-start; + width: 100%; + } + + .view-more-details__wrapper .view-more-details { + display: flex; + align-items: center; + width: fit-content; + } + + .quick-add-modal__content .product-header { + @media screen and (max-width: 750px) { + display: flex; + flex-direction: column; + grid-column: 2 / -1; + grid-row: 1; + padding-right: var(--padding-2xl); + } + } + + .quick-add-modal__content .product-header a:not(product-price *) { + @media screen and (max-width: 749px) { + font-size: var(--font-size--md); + font-weight: 500; + color: inherit; + width: fit-content; + } + } + + .quick-add-modal__content variant-picker, + .quick-add-modal__content product-form-component { + @media screen and (max-width: 750px) { + grid-column: 1 / -1; + } + } + + .quick-add-modal__content .variant-picker__form { + display: block; + } + + .quick-add-modal__content fieldset { + margin-top: var(--padding-lg); + } + + .quick-add-modal__content .product-media-container__zoom-button { + cursor: default; + } + + .quick-add-modal__content .product-details { + grid-column: 4 / -1; + grid-row: 1 / span 2; + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; + + dialog[open] & { + animation: fadeSlideIn 0.3s var(--animation-timing-fade-in) both; + animation-delay: 0.1s; + } + + @media screen and (max-width: 750px) { + grid-column: 2 / span 2; + grid-row: span 1; + overflow-y: auto; + max-height: 100%; + height: 100%; + } + } + + .quick-add-modal__content > * { + min-height: 0; + } + + .quick-add-modal__content .product-details :is(.view-product-title, .buy-buttons-block) { + flex: 0 0 auto; + } + + .quick-add-modal__content .product-details .variant-picker { + --product-swatches-padding-block-end: 0px; + flex: 1 1 auto; + overflow-y: auto; + min-height: 0; + padding-block-end: calc( + var(--product-swatches-padding-block-end) + var(--focus-outline-offset) + var(--focus-outline-width) + ); + } + + .quick-add-modal__content .variant-option--swatches { + padding-inline-start: var(--padding-2xs); + } + + .quick-add-modal__content .variant-option--swatches legend { + margin-inline-start: calc(-1 * var(--padding-2xs)); + } + + .quick-add-modal__content:not(:has(.product-information__media)) .product-details { + grid-column: 1 / -1; + } + + .quick-add-modal__content .view-product-title { + padding: 0; + } + + .quick-add-modal__content .view-product-title a { + color: inherit; + text-decoration: none; + text-align: left; + font-size: var(--font-size--2xl); + font-weight: 600; + line-height: 1.2; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + transition: color 0.2s var(--animation-easing); + } + + .quick-add-modal__content .view-product-title { + display: flex; + } + + .quick-add-modal__content + .product-details + *:not( + .group-block, + .group-block-content, + .buy-buttons-block, + .buy-buttons-block *, + .view-product-title, + .view-product-title *, + variant-picker, + variant-picker *, + product-price, + product-price *, + product-inventory, + product-inventory *, + .view-more-details__wrapper, + .view-more-details__wrapper * + ) { + @media screen and (min-width: 750px) { + display: none !important; + } + } + + .quick-add-modal__content + .group-block:not( + :has( + .buy-buttons-block, + .buy-buttons-block *, + .view-product-title, + .view-product-title *, + variant-picker, + variant-picker *, + product-price, + product-price *, + product-inventory, + product-inventory *, + .view-more-details__wrapper, + .view-more-details__wrapper * + ), + .buy-buttons-block + ) { + display: none; + } + + @media screen and (min-width: 750px) { + .quick-add-modal__content .group-block-content { + gap: min(var(--gap-2xl), var(--gap)); + } + + .quick-add-modal__content .media-gallery__grid { + gap: min(var(--gap-2xs), var(--image-gap)); + border-radius: var(--style-border-radius-popover, 0); + } + + .quick-add-modal__content .media-gallery--grid .product-media img { + border-radius: 0; + } + + .quick-add-modal__content .media-gallery--grid .product-media-container:first-child { + border-top-right-radius: var(--style-border-radius-popover, 0); + } + + .quick-add-modal__content .media-gallery--grid .product-media-container:last-child { + border-bottom-right-radius: var(--style-border-radius-popover, 0); + } + } + + .quick-add-modal__content .product-details > .group-block { + padding: var(--padding-2xl); + max-height: 100%; + } + + .quick-add-modal__content slideshow-slide:not([aria-hidden='false']) { + content-visibility: auto; + } + + .quick-add-modal__content .product-information__media { + width: 100%; + grid-column: 1 / span 1; + grid-row: 1; + position: relative; + top: 0; + animation: fadeIn 0.4s var(--animation-timing-fade-in) both; + + @media screen and (min-width: 750px) { + position: sticky; + grid-column: 1 / 4; + overflow-y: auto; + -ms-overflow-style: none; + scrollbar-width: none; + } + + &::-webkit-scrollbar { + display: none; + } + } + + .quick-add-modal__content .product-information__media media-gallery { + pointer-events: none; + + @media screen and (min-width: 750px) { + position: absolute; + inset: 0; + } + } + + .quick-add-modal media-gallery { + padding: 0; + } + + .quick-add-modal__content .product-information__media slideshow-arrows { + display: none; + } + + .quick-add-modal__content .product-information__media slideshow-container { + display: block; + } + + .quick-add-modal__content .product-information__media slideshow-slides { + display: flex; + flex-direction: column; + gap: var(--gap-2xs); + overflow: visible; + scroll-snap-type: none; + } + + .quick-add-modal__content .product-information__media slideshow-slide { + width: 100%; + flex: none; + scroll-snap-align: unset; + position: relative; + transform: none; + opacity: 1; + visibility: visible; + transition: opacity 0.3s var(--animation-easing); + } + + .quick-add-modal__content .product-information__media slideshow-slide[aria-hidden='true'] { + @media screen and (max-width: 750px) { + display: none; + } + } + + .quick-add-modal__content .product-information__media slideshow-slide:nth-child(1) { + animation: fadeSlideIn 0.3s var(--animation-timing-fade-in) both; + } + + .quick-add-modal__content .product-information__media slideshow-slide:nth-child(2) { + animation: fadeSlideIn 0.3s var(--animation-timing-fade-in) both; + animation-delay: 0.05s; + } + + .quick-add-modal__content .product-information__media slideshow-slide:nth-child(3) { + animation: fadeSlideIn 0.3s var(--animation-timing-fade-in) both; + animation-delay: 0.1s; + } + + .quick-add-modal__content .product-information__media slideshow-controls { + display: none; + } + + .quick-add-modal__content .sticky-content, + .quick-add-modal__content .sticky-content--desktop { + top: 0; + } + + .quick-add-modal__content .text-block.rte:not(product-price), + .quick-add-modal__content .view-more-details__wrapper { + display: none; + } + + @keyframes fadeSlideIn { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } +{% endstylesheet %} diff --git a/snippets/quick-add.liquid b/snippets/quick-add.liquid new file mode 100644 index 000000000..dddff3652 --- /dev/null +++ b/snippets/quick-add.liquid @@ -0,0 +1,324 @@ +{%- doc -%} + Renders a quick add component. + + @param {object} product - The product object + @param {string} section_id - The section ID + @param {object} [block] - The block object +{%- enddoc -%} + +{% liquid + assign product_form_id = 'QuickAdd-ProductForm-' | append: product.id | append: '-' | append: block.id + assign add_to_cart_text = 'actions.add' | t + + # Logic to determine which variant to use (matching swatch selection logic from product-card) + assign variant_to_use = product.selected_or_first_available_variant + assign combined_listing_count = product.options_with_values | map: 'values' | map: 'product_url' | compact | size + + unless combined_listing_count > 0 + assign first_image = product.media.first + assign variant_images = product.images | where: 'attached_to_variant?', true + # Get swatchable options (options that have swatch values) + assign swatch_variant_picker = null + for option in product.options_with_values + assign swatch_count = option.values | map: 'swatch' | compact | size + if swatch_count > 0 + assign swatch_variant_picker = option + break + endif + endfor + + if swatch_variant_picker + assign swatch_count = swatch_variant_picker.values | map: 'swatch' | compact | size + + if swatch_count == 1 + # Single swatch: use that variant + assign variant_to_use = swatch_variant_picker.values.first.variant + elsif swatch_count > 1 + if first_image and variant_images contains first_image + # First image is a variant image - find which variant it belongs to + for option_value in swatch_variant_picker.values + if option_value.variant.featured_media.id == first_image.id + assign variant_to_use = option_value.variant + break + endif + endfor + elsif variant_images.size == 0 + # No variants have images - use first swatch variant + assign variant_to_use = swatch_variant_picker.values.first.variant + endif + # else: First image is NOT a variant image - keep default (selected_or_first_available_variant) + endif + endif + endunless + + if variant_to_use.available + assign can_add_to_cart = true + else + assign can_add_to_cart = false + endif +%} + + + +
      + {%- form 'product', product, id: product_form_id, novalidate: 'novalidate', data-type: 'add-to-cart-form' -%} + + + {% comment %} If there is one variant option but it's swatches or if it's a single variant product, then use add to cart button {% endcomment %} + {%- if product.variants.size == 1 or product.options.size == 1 -%} + {% render 'add-to-cart-button', + add_to_cart_text: add_to_cart_text, + class: 'button quick-add__button quick-add__button--add', + can_add_to_cart: can_add_to_cart, + icon_only_on_mobile: true, + product: product + %} + {%- endif -%} + {%- if product.variants.size > 1 -%} + + {%- endif -%} + {%- endform -%} +
      +
      + +{% stylesheet %} + /* Quick Add */ + .quick-add { + --quick-add-offset: var(--padding-sm); + --quick-add-top: calc(var(--quick-add-offset) + var(--padding-block-start)); + --quick-add-right: calc(var(--quick-add-offset) + var(--padding-inline-end)); + --quick-add-bottom: calc(var(--quick-add-offset) + var(--padding-block-end)); + --quick-add-left: calc(var(--quick-add-offset) + var(--padding-inline-end)); + + position: absolute; + display: var(--quick-add-mobile-display, none); + flex-direction: column; + justify-content: flex-end; + inset: max(var(--quick-add-top), calc((var(--border-radius) + var(--quick-add-top)) * (1 - cos(45deg)))) + max(var(--quick-add-right), calc((var(--border-radius) + var(--quick-add-right)) * (1 - cos(45deg)))) + max(var(--quick-add-bottom), calc((var(--border-radius) + var(--quick-add-bottom)) * (1 - cos(45deg)))) + max(var(--quick-add-left), calc((var(--border-radius) + var(--quick-add-left)) * (1 - cos(45deg)))); + width: auto; + height: auto; + z-index: var(--layer-raised); + cursor: default; + pointer-events: none; + + @media screen and (min-width: 750px) { + --quick-add-offset: var(--padding-md); + + display: var(--quick-add-display, flex); + } + } + + .quick-add .variant-option__button-label input[data-option-available='false'] { + cursor: not-allowed; + } + + .quick-add[class*='color-scheme-'] { + background-color: transparent; + } + + .quick-add__button { + display: grid; + padding: var(--padding-xs); + align-items: center; + background-color: var(--color-background); + color: var(--color-foreground); + border-color: transparent; + box-shadow: var(--shadow-popover); + pointer-events: all; + position: relative; + overflow: hidden; + border-radius: 100px; + + @media screen and (min-width: 750px) { + display: none; + padding: var(--padding-xs) var(--padding-sm); + } + + .quick-add[stay-visible] & { + display: grid; + } + } + + .quick-add__button .add-to-cart-text { + gap: 0; + line-height: 1; + grid-row: 1 / span 1; + grid-column: 1 / span 1; + animation: none; + + @media screen and (min-width: 750px) { + /* offset button padding to show a round button in a collapsed state */ + margin-inline: calc(var(--padding-sm) * -1); + padding-inline: var(--padding-xs); + } + } + + .quick-add__button .add-to-cart-text--added { + position: relative; + grid-row: 1 / span 1; + grid-column: 1 / span 1; + justify-self: end; + line-height: 1; + + @media screen and (min-width: 750px) { + width: 0; + } + } + + .quick-add__button .add-to-cart-text__content { + width: 0; + opacity: 0; + transform: translateX(1em); + transition: width var(--animation-speed) ease-in-out, opacity var(--animation-speed) ease-in-out, + transform var(--animation-speed) ease-in-out; + interpolate-size: allow-keywords; + will-change: width, opacity, transform; + } + + @container (min-width: 99px) { + .quick-add[stay-visible] .add-to-cart-text, + .quick-add__button:is(:focus, :hover) .add-to-cart-text { + gap: var(--gap-2xs); + + @media screen and (min-width: 750px) { + /* offset button padding to show a round button in a collapsed state */ + margin-inline: 0; + padding-inline: 0; + } + } + + .quick-add[stay-visible] .add-to-cart-text__content, + .quick-add__button:is(:focus, :hover) .add-to-cart-text__content { + width: fit-content; + opacity: 1; + transform: translateX(0); + } + } + + .quick-add__button.atc-added .add-to-cart-text { + opacity: 0; + } + + .quick-add__button.atc-added .add-to-cart-text--added { + opacity: 1; + width: auto; + + @supports (width: calc-size(auto, size)) { + width: calc-size(auto, size); + } + } + + .quick-add__button.atc-added .add-to-cart-text { + animation-name: atc-fade-out; + } + + .quick-add__button.atc-added .add-to-cart-text--added { + animation-name: atc-fade-in; + } + + .quick-add__product-form-component { + height: 100%; + } + + .quick-add__product-form-component .shopify-product-form { + display: flex; + justify-content: flex-end; + align-items: flex-end; + container-type: inline-size; + height: 100%; + } + + .quick-add-modal .product-media { + width: 100%; + height: 100%; + } + + .quick-add-modal deferred-media { + display: none; + } + + .quick-add-modal .media-gallery--carousel slideshow-component { + --cursor: default; + } + + @keyframes atc-fade-in { + from { + opacity: 0; + transform: translateX(1em); + position: absolute; + } + + to { + opacity: 1; + transform: translateX(0); + position: inherit; + } + } + + @keyframes atc-fade-out { + from { + opacity: 1; + transform: translateX(0); + position: inherit; + } + + to { + opacity: 0; + transform: translateX(-1em); + position: absolute; + } + } +{% endstylesheet %} diff --git a/snippets/resource-card.liquid b/snippets/resource-card.liquid new file mode 100644 index 000000000..11bb62066 --- /dev/null +++ b/snippets/resource-card.liquid @@ -0,0 +1,273 @@ +{%- doc -%} + Renders a card for displaying various resource types (products, collections, articles, pages). + + @param {object} resource - The product or collection resource to render + @param {string} resource_type - The type of resource to render. + @param {string} [collection_thumbnails] - The style of the collection card. Can be 'single' or 'multiple'. Defaults to 'single' + @param {string} [style] - The style of the card. Can be 'default' or 'overlay' + @param {number} [image_width] - The maximum width of the image, value influences the srcset attribute. Defaults to 1200px. + @param {string} [image_aspect_ratio] - The aspect ratio to display the image. Defaults to image's natural ratio + @param {boolean} [image_hover] - Whether to show a secondary image on hover and focus +{%- enddoc -%} + +{% liquid + if image_aspect_ratio == blank or image_aspect_ratio == 'adapt' + assign ratio = resource.featured_image.aspect_ratio + else + assign ratio = image_aspect_ratio + endif + assign image_width = image_width | default: 1200 + assign widths = '300, 450, 600, 750, 900, 1050, 1200' + assign single_thumbnail_collection = false + if resource_type == 'collection' and collection_thumbnails != 'multiple' + assign single_thumbnail_collection = true + endif + + if resource_type == 'product' and settings.transition_to_main_product + assign featured_media_url = resource.selected_or_first_available_variant.featured_image | image_url: width: image_width + if featured_media_url == blank + assign featured_media_url = resource.featured_media.preview_image | image_url: width: image_width + endif + endif +%} + +{%- if resource_type == 'product' and settings.transition_to_main_product -%} + +{%- endif -%} +
      + + + {{ resource.title }} + + +
      + {%- if resource_type == 'product' or single_thumbnail_collection -%} + {% assign featured_image = resource.featured_image | default: resource.featured_media.preview_image %} + + {%- if featured_image != blank -%} + {{ + featured_image + | image_url: width: image_width + | image_tag: + loading: 'lazy', + class: 'resource-card__image', + widths: widths, + sizes: 'auto', + transitionToProduct: settings.transition_to_main_product, + data-media-id: featured_image.id + }} + {%- if image_hover and resource.media.size > 1 -%} + {{ + resource.media[1] + | image_url: width: image_width + | image_tag: + loading: 'lazy', + class: 'resource-card__image resource-card__image--secondary', + widths: widths, + sizes: 'auto', + transitionToProduct: settings.transition_to_main_product, + data-media-id: resource.media[1].id + }} + {%- endif -%} + {%- else -%} + + {%- endif -%} + {%- elsif resource_type == 'collection' -%} + {%- if resource.products.size > 0 -%} +
      + {% assign resource_products = resource.products | where: 'featured_image' %} + {% for product in resource_products limit: 4 %} + {{ + product.featured_image + | image_url: width: image_width + | image_tag: loading: 'lazy', class: 'resource-card__collection-image', sizes: 'auto', widths: widths + }} + {% endfor %} +
      + {%- endif -%} + {%- endif -%} +
      + +
      +

      + {{- resource.title -}} +

      + + {% if resource_type == 'product' %} + {% render 'price', product_resource: resource, show_unit_price: true %} + {% elsif resource_type == 'collection' and single_thumbnail_collection == false %} +

      + {{- 'content.search_results_resource_products_count' | t: count: resource.all_products_count -}} +

      + {% else %} +

      + {{- resource.excerpt | default: resource.content | strip_html | truncate: 65 -}} +

      + {% endif %} +
      +
      +{%- if resource_type == 'product' and settings.transition_to_main_product -%} +
      +{%- endif -%} + +{% stylesheet %} + .resource-card { + --resource-card-secondary-image-opacity: 0; + --resource-card-primary-image-opacity: calc(1 - var(--resource-card-secondary-image-opacity)); + + display: flex; + flex-direction: column; + row-gap: var(--padding-xs); + position: relative; + text-decoration: none; + height: 100%; + opacity: 0; + animation: fadeIn var(--animation-speed-medium) var(--animation-timing-fade-in) forwards; + } + + .resource-card__link { + position: absolute; + inset: 0; + z-index: 1; + } + + .resource-card__content { + display: flex; + flex-direction: column; + color: var(--color-foreground); + gap: var(--padding-3xs); + + .price { + font-weight: 500; + } + } + + .resource-card[data-resource-type='article'] .resource-card__content, + .resource-card[data-resource-type='page'] .resource-card__content { + gap: var(--padding-xs); + } + + .resource-card__image { + aspect-ratio: var(--resource-card-aspect-ratio, auto); + object-fit: cover; + border-radius: var(--resource-card-corner-radius); + opacity: var(--resource-card-primary-image-opacity); + } + + .resource-card__image--secondary { + position: absolute; + top: 0; + opacity: var(--resource-card-secondary-image-opacity); + border-radius: var(--resource-card-corner-radius); + } + + .resource-card__media:empty { + display: none; + } + + .resource-card__image-placeholder { + padding: var(--padding-sm); + font-size: var(--font-size--lg); + line-height: var(--line-height--display-loose); + word-break: break-word; + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + aspect-ratio: var(--resource-card-aspect-ratio, auto); + border-radius: var(--resource-card-corner-radius); + color: var(--color-foreground); + } + + .resource-card__title { + margin-block: 0; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + line-height: 1.3; + } + + .resource-card__title.paragraph { + line-height: 1.3; + } + + .resource-card--overlay { + height: 100%; + + &::before { + content: ''; + position: absolute; + inset: 50% 0 0; + background: var(--gradient-image-overlay); + border-radius: var(--resource-card-corner-radius); + pointer-events: none; + z-index: var(--layer-flat); + } + } + + .resource-card--overlay .resource-card__image { + height: 100%; + } + + .resource-card--overlay .resource-card__content { + position: absolute; + inset: auto 0 0; + padding: var(--padding-lg) var(--padding-lg) var(--padding-sm); + z-index: var(--layer-raised); + } + + .resource-card--overlay .resource-card__title { + color: var(--color-white); + } + + /* Collection images */ + .resource-card__image-wrapper { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--gap-2xs); + } + + .resource-card__collection-image { + aspect-ratio: 1 / 1; + object-fit: cover; + border-radius: calc(var(--card-corner-radius) - (var(--padding-xs) / 2)); + } + + .resource-card__subtext { + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + margin-block-start: 0; + } + + .resource-card__subtext.paragraph { + font-size: var(--font-size--body-sm); + line-height: var(--line-height--body-tight); + color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + } + + .resource-card:has(.resource-card__image--secondary) { + &:hover, + &:focus { + --resource-card-secondary-image-opacity: 1; + } + } +{% endstylesheet %} diff --git a/snippets/resource-list-carousel.liquid b/snippets/resource-list-carousel.liquid new file mode 100644 index 000000000..547d8efd5 --- /dev/null +++ b/snippets/resource-list-carousel.liquid @@ -0,0 +1,59 @@ +{%- doc -%} + Renders a carousel of predictive search results cards + + @param {string} ref - The ref of the slideshow + @param {object} slides - An array of HTML for the slides to display in the carousel + @param {number} slide_count - The number of slides to display in the carousel + @param {object} settings - The block or sections settings from the parent block/section. + @param {string} [slide_width_max] - The maximum width of the slides in the carousel. + + @example + {% render 'resource-list-carousel', slides: slides, slide_count: slide_count, settings: block.settings %} +{%- enddoc -%} + +{% liquid + assign slideshow_ref = ref | default: 'resourceListCarousel' + if settings.section_width == 'page-width' + assign slideshow_gutters = 'start end' + else + assign slideshow_gutters = null + endif +%} + +{% capture slides %} + {% for item in slides limit: slides.size %} + {% render 'slideshow-slide' + index : forloop.index0, + children : item, + class : 'resource-list__slide' + %} + {% endfor %} +{% endcapture %} + +{% capture slideshow_arrows %} + {% render 'slideshow-arrows', icon_style: settings.icons_style, icon_shape: settings.icons_shape %} +{% endcapture %} + + diff --git a/snippets/scripts.liquid b/snippets/scripts.liquid new file mode 100644 index 000000000..0ee47e4b9 --- /dev/null +++ b/snippets/scripts.liquid @@ -0,0 +1,247 @@ + + +{% if settings.transition_to_main_product %} + {% # theme-check-disable ParserBlockingScript %} + + {% # theme-check-enable %} +{% endif %} + +{{ 'critical.js' | asset_url | preload_tag: as: 'script' }} + + + + + + +{% if template.name == 'collection' or template.name == 'search' %} + + + +{% endif %} + + + + + + +{% if settings.show_add_discount_code %} + +{% endif %} + + + + + + + + + + + + + + + + + + +{% if localization.available_countries.size > 1 or localization.available_languages.size > 1 %} + +{% endif %} + +{% if template == 'product' %} + +{% endif %} + +{% if settings.transition_to_main_product %} + +{% endif %} + + + + diff --git a/snippets/search-modal.liquid b/snippets/search-modal.liquid new file mode 100644 index 000000000..d0b66c884 --- /dev/null +++ b/snippets/search-modal.liquid @@ -0,0 +1,108 @@ + + + + + {% render 'predictive-search', + input_id: 'cmdk-input', + search_test_id: 'search-component--modal', + products_test_id: 'products-list-default--modal' + %} + + + +{% stylesheet %} + /* Search modal style */ + .search-modal { + --search-border-radius: var(--style-border-radius-popover); + --search-border-width: var(--style-border-width); + } + + .search-modal__button { + display: flex; + align-items: center; + justify-content: center; + } + + .search-modal__content { + /* Approx set the top so when the content is at max height, the modal is centered */ + --modal-top-margin: calc(50dvh - var(--modal-max-height) / 2 - 2rem); + --modal-width: 66dvw; + + padding: 0; + + @media screen and (min-width: 750px) { + width: var(--modal-width); + margin-block-start: var(--modal-top-margin); + overflow: hidden; + } + } + + /* Hide the default dialog backdrop on small screens */ + @media screen and (max-width: 749px) { + .search-modal__content::backdrop { + display: none; + } + } + + .dialog-modal[open].search-modal__content { + transform-origin: bottom center; + animation: search-element-slide-in-bottom 300ms var(--ease-out-quad) forwards; + border-radius: var(--search-border-radius); + box-shadow: var(--shadow-popover); + + @media screen and (max-width: 749px) { + border-radius: 0; + } + } + + .dialog-modal.search-modal__content.dialog-closing { + animation: search-element-slide-out-bottom 200ms var(--ease-out-quad) forwards; + } + + .search-modal__content[open] { + display: flex; + } + + .search-modal__content :is(.predictive-search-dropdown, .predictive-search-form__content-wrapper) { + position: relative; + } + + /* Predictive search header tweaks for small screens */ + @media screen and (max-width: 749px) { + .dialog-modal + .predictive-search-form__header:has( + .predictive-search__reset-button:not(.predictive-search__reset-button[hidden]) + )::before { + content: ''; + position: absolute; + right: calc(var(--padding-sm) + var(--minimum-touch-target)); + top: 0; + bottom: 0; + width: var(--border-width-sm); + background-color: var(--color-border); + } + + .dialog-modal + .predictive-search-form__header:has( + .predictive-search__reset-button:not(.predictive-search__reset-button[hidden]) + ) + > .predictive-search__close-modal-button { + &::before { + content: none; + } + } + } +{% endstylesheet %} diff --git a/snippets/search.liquid b/snippets/search.liquid new file mode 100644 index 000000000..271471c15 --- /dev/null +++ b/snippets/search.liquid @@ -0,0 +1,52 @@ +{%- doc -%} + Renders the search action button. + + @param {string} [style] - The style of the search action. + @param {string} [class] - Additional classes for the search action. + + @example + {% render 'search', style: 'default', class: 'custom-class' %} +{%- enddoc -%} + +{% unless style == 'none' %} + + + +{% endunless %} + +{% stylesheet %} + .search-action { + --search-border-radius: var(--style-border-radius-inputs); + --search-border-width: var(--style-border-width-inputs); + + display: flex; + } + + .header__column--center .search-action { + width: auto; + flex-grow: 1; + } + + :is(.header__column--left, .header__column--center) .search-action { + @media screen and (min-width: 750px) { + margin-inline: calc(var(--padding-lg) * -1); + } + } + + .header__column--right .search-action { + @media screen and (min-width: 750px) { + margin-inline: calc(var(--gap-md) * -1) calc(var(--gap-xs) * -1); + } + } +{% endstylesheet %} diff --git a/snippets/section.liquid b/snippets/section.liquid new file mode 100644 index 000000000..2f3e42cce --- /dev/null +++ b/snippets/section.liquid @@ -0,0 +1,96 @@ +{%- doc -%} + Renders a wrapper section + + @param {section} section - The section object + @param {string} children - The children of the section +{%- enddoc -%} + +
      +
      +
      + {% render 'background-media', + background_media: section.settings.background_media, + background_video: section.settings.video, + background_video_position: section.settings.video_position, + background_image: section.settings.background_image, + background_image_position: section.settings.background_image_position + %} +
      + +
      + {% if section.settings.toggle_overlay %} + {% render 'overlay', settings: section.settings, layer: '0' %} + {% endif %} + +
      + {{ children }} +
      +
      +
      + +{% stylesheet %} + .section-wrapper { + --section-height-offset: 0px; + } + + .section[data-shopify-visual-preview] { + min-height: var(--section-preview-height); + padding-top: 0; + } + + .section[data-shopify-visual-preview] .custom-section-background { + display: none; + } + + body:has(> #header-group > .header-section > #header-component[transparent]):not( + :has(> #header-group > .header-section + .shopify-section) + ) + > main + > .section-wrapper:first-child { + --section-height-offset: var(--header-group-height, 0); + } + + .custom-section-background { + grid-column: 1 / -1; + } + + .custom-section-content { + z-index: var(--layer-flat); + } +{% endstylesheet %} diff --git a/snippets/size-style.liquid b/snippets/size-style.liquid new file mode 100644 index 000000000..1b863451a --- /dev/null +++ b/snippets/size-style.liquid @@ -0,0 +1,33 @@ +{%- comment -%} + Intended for blocks and sections that provide values for all the referenced settings. + Accepts: + settings: {block.settings || section.settings} +{%- endcomment -%} + +{%- if settings.width == 'custom' -%} + --size-style-width: + {{- settings.custom_width }}%; +{%- elsif settings.width == 'fill' -%} + --size-style-width: 100%; +{%- else -%} + --size-style-width: {{ settings.width }}; +{%- endif -%} + +{%- if settings.height == 'custom' -%} + --size-style-height: + {{- settings.custom_height }}%; +{%- elsif settings.height == 'fill' -%} + --size-style-height: 100%; +{%- else -%} + --size-style-height: {{ settings.height }}; +{%- endif -%} + +{% if settings.width_mobile == 'custom' %} + --size-style-width-mobile: + {{- settings.custom_width_mobile }}%; --size-style-width-mobile-min: + {{- settings.custom_width_mobile }}%; +{%- elsif settings.width_mobile == 'fill' -%} + --size-style-width-mobile: 100%; --size-style-width-mobile-min: 5rem; +{%- elsif settings.width_mobile == 'fit-content' -%} + --size-style-width-mobile: {{ settings.width_mobile }}; --size-style-width-mobile-min: {{ settings.width_mobile }}; +{%- endif -%} diff --git a/snippets/skip-to-content-link.liquid b/snippets/skip-to-content-link.liquid new file mode 100644 index 000000000..15d8e34e5 --- /dev/null +++ b/snippets/skip-to-content-link.liquid @@ -0,0 +1,16 @@ +{%- doc -%} + Renders a skip to content link, visible on focus only. + Parent element must have position: relative to ensure proper positioning. + + @param {string} href - The URL to skip to, usually an id like "#MainContent". + @param {string} text - The text to display, in the form of a translation key for a locale file. + + @example + {% render 'skip-to-content-link', href: '#MainContent', text: 'Skip to main content' %} +{%- enddoc -%} + + {{ text | t }} + diff --git a/snippets/slideshow-arrow.liquid b/snippets/slideshow-arrow.liquid new file mode 100644 index 000000000..70c511a9e --- /dev/null +++ b/snippets/slideshow-arrow.liquid @@ -0,0 +1,49 @@ +{%- doc -%} + Renders a slideshow arrow control + + @param {string} action - { 'previous' | 'next' } The action to perform when the arrow is clicked. + @param {string} [icon_style] - { 'arrow' | 'chevron' } The style of the icon, defaults to 'arrow'. + @param {string} [icon_shape] - { 'none' | 'circle' | 'square' } The shape of the icon background, defaults to 'none'. + @param {string} [icon_size] - { 'small' | 'medium' | 'large' } The size of the icon, defaults to 'medium'. + + @example + {%- render 'slideshow-arrow', action: 'previous' -%} +{%- enddoc -%} + +{%- liquid + assign icon_name = 'arrow' + assign style = icon_style | default: 'arrow' + assign shape = icon_shape | default: 'none' + + if icon_style contains 'chevron' + assign icon_name = 'caret' + endif + + if icon_style contains 'large' + assign icon_size = 'large' + endif +-%} + + diff --git a/snippets/slideshow-arrows.liquid b/snippets/slideshow-arrows.liquid new file mode 100644 index 000000000..5f32be972 --- /dev/null +++ b/snippets/slideshow-arrows.liquid @@ -0,0 +1,29 @@ +{%- doc -%} + Renders arrow controls for a slideshow component. + Assumes arrows are placed on top of media. + When icon shape is 'none', component uses mixed-blend-mode to ensure visibility. + + @param {string} [class] - The class name to apply to the slideshow-arrows component + @param {string} [icon_style] - The style of the icon, defaults to 'arrow' + @param {string} [icon_shape] - The shape of the icon background (none, circle, square), defaults to 'none' + @param {string} [arrows_position] - { 'left' | 'center' | 'right' } The position of the arrows, defaults to 'center' + + @example + {%- render 'slideshow-arrows' -%} +{%- enddoc -%} + +{%- liquid + if arrows_position == null + assign arrows_position = 'center' + endif +-%} + + + {%- render 'slideshow-arrow', action: 'previous', icon_style: icon_style, icon_shape: icon_shape -%} + {%- render 'slideshow-arrow', action: 'next', icon_style: icon_style, icon_shape: icon_shape -%} + diff --git a/snippets/slideshow-controls.liquid b/snippets/slideshow-controls.liquid new file mode 100644 index 000000000..2e3509acf --- /dev/null +++ b/snippets/slideshow-controls.liquid @@ -0,0 +1,180 @@ +{%- doc -%} + Renders controls for a slider component + + @param {string} [style] - { 'dots' | 'counter' | 'thumbnails' | 'none' } The display style of the controls + @param {boolean} [autoplay] - Whether the controls will display an autoplay option + @param {number} [item_count] - The total number of slides + @param {boolean} [show_arrows] - Whether the controls will display arrows + @param {boolean} [arrows_on_media] - Whether the controls will display as floating icons on the media + @param {boolean} [controls_on_media] - Whether the controls will display as floating controls on the media + @param {media[]} [thumbnails] - Array of media to be displayed as thumbnails, sorted. + @param {string} [pagination_position] - { 'left' | 'center' | 'right' } Sets the pagination position, defaults to 'center' if none passed + @param {string} [icon_style] - The style of the icon, defaults to 'arrow' + @param {string} [shape] - The shape of the control, defaults to 'square' + @param {string} [aspect_ratio] - The aspect ratio of thumbnails, if applicable. defaults to 'adapt' + @param {string} [class] - Additional classes to apply to the controls + @param {boolean} [secondary] - Whether the controls are secondary + + @example + {%- render 'slideshow-controls', style: 'dots', item_count: 10 -%} +{%- enddoc -%} + +{%- liquid + if aspect_ratio == null + assign aspect_ratio = 'adapt' + endif + + if pagination_position == null + assign pagination_position = 'center' + endif + + assign show_arrows_separately = false + if style == 'thumbnails' and arrows_on_media == false + assign show_arrows_separately = true + # Specific case - we want to show the arrows with the thumbnails if everything is off media and centered. + if controls_on_media == false and pagination_position == 'center' + assign show_arrows_separately = false + endif + elsif controls_on_media == true and arrows_on_media == false + assign show_arrows_separately = true + endif + + if pagination_position == 'left' or pagination_position == 'right' + assign scroll_mode = 'vertical' + else + assign scroll_mode = 'horizontal' + endif +-%} + + + {% if show_arrows_separately == false and show_arrows and pagination_position != 'left' %} +
      + {%- render 'slideshow-arrow', action: 'previous', icon_style: icon_style, icon_shape: shape -%} + + {% if pagination_position == 'right' %} + {%- render 'slideshow-arrow', action: 'next', icon_style: icon_style, icon_shape: shape -%} + {% endif %} +
      + {% endif %} + + {% if autoplay %} + + + {% endif %} + + {% case style %} + {% when 'thumbnails' %} + +
      + {% for media in thumbnails %} + + {% endfor %} +
      +
      + {% when 'counter' %} +
      + 1/{{ item_count -}} +
      + {% when 'dots' %} +
        + {% for i in (1..item_count) %} +
      1. + +
      2. + {% endfor %} +
      + {% endcase %} + + {% if show_arrows_separately == false and show_arrows and pagination_position != 'right' %} +
      + {% if pagination_position == 'left' %} + {%- render 'slideshow-arrow', action: 'previous', icon_style: icon_style, icon_shape: shape -%} + {% endif %} + + {%- render 'slideshow-arrow', action: 'next', icon_style: icon_style, icon_shape: shape -%} +
      + {% endif %} +
      + +{% if show_arrows_separately and show_arrows %} +
      + {%- render 'slideshow-arrow', action: 'previous', icon_style: icon_style, icon_shape: shape -%} + {%- render 'slideshow-arrow', action: 'next', icon_style: icon_style, icon_shape: shape -%} +
      +{% endif %} diff --git a/snippets/slideshow-slide.liquid b/snippets/slideshow-slide.liquid new file mode 100644 index 000000000..c6f7f1f7a --- /dev/null +++ b/snippets/slideshow-slide.liquid @@ -0,0 +1,42 @@ +{%- doc -%} + Renders a slideshow slide component. + + @param {number} index - the index of the slide + @param {string} [children] - The content of the slideshow slide + @param {string} [class] - HTML class attribute of the slideshow slide + @param {string} [style] - HTML style attribute of the slideshow slide + @param {string} [attributes] - Additional HTML attributes to add to the slideshow slide + @param {boolean} [hidden] - Hidden slides will not be shown in the slideshow + @param {string} [slide_id] - The unique id assigned to the slide amongst all slides in the slideshow + @param {string} [media_fit] - { 'cover', 'contain' } - CSS property for how the media should be fit in the slide + + @example + {% render 'slideshow-slide', index: 0, children: imageElement, slide_id: 'slide-1', hidden: false, media_fit: 'cover' %} +{%- enddoc -%} + +{%- liquid + assign class = class | strip | strip_newlines + assign style = style | strip | strip_newlines +-%} + + diff --git a/snippets/slideshow.liquid b/snippets/slideshow.liquid new file mode 100644 index 000000000..28aa284e7 --- /dev/null +++ b/snippets/slideshow.liquid @@ -0,0 +1,77 @@ +{%- doc -%} + Renders a slideshow component. + Condiional component and slideshow controls. + + @param {object[]} slides - the slides of the slideshow + @param {string} [ref] - the ref of the slideshow component + @param {string} [class] - HTML class attribute of the slideshow component + @param {string} [controls] - the controls of the slideshow component + @param {string} [style] - HTML style attribute of the slideshow component + @param {boolean} [autoplay] - whether the slideshow will autoplay + @param {number} [autoplay_speed] - the speed of the slideshow autoplay + @param {boolean} [auto_hide_controls] - whether to hide slideshow-controls when the scroller is smaller than the viewport + @param {boolean} [infinite] - whether the slideshow will loop + @param {number} [initial_slide] - the 0-based index of the initial slide, defaults to 0 + @param {string} [slideshow_gutters] - the gutter positions to render. Set width with CSS variables --gutter-slide-width + @param {number} [slide_count] - the total number of slides + @param {string} [slide_size] - the height of the slides + @param {boolean} [show_arrows] - whether the slideshow will render a slideshow-arrows component + @param {string} [slideshow_arrows] - a custom slideshow-arrows component to render instead of the default + @param {string} [icon_style] - The style of the icon, defaults to 'arrow' + @param {string} [arrows_position] - The position of the arrows, defaults to 'bottom' + @param {string} [attributes] - Additional attributes to add to the slideshow component + @param {boolean} [header] - The title of the slideshow + + @example + {% render 'slideshow', slides: slides, slide_count: collection.products.size, ref: 'mobileSlideshow' %} +{%- enddoc -%} + +{% assign class = class | strip %} +{% assign style = style | strip %} + + + {% if header != blank %} + {{ header }} + {% endif %} + + {% if show_arrows and disabled != true %} + {% render 'slideshow-arrows', icon_style: icon_style, arrows_position: arrows_position %} + {% endif %} + {% if slideshow_arrows and disabled != true %} + {{ slideshow_arrows }} + {% endif %} + + {{ slides }} + + + {{ controls }} + diff --git a/snippets/sorting.liquid b/snippets/sorting.liquid new file mode 100644 index 000000000..6f9bb46ce --- /dev/null +++ b/snippets/sorting.liquid @@ -0,0 +1,361 @@ +{%- doc -%} + Renders the sorting component. + + @param {object} results - The results of the search + @param {string} sort_by - The current sort by + @param {string} filter_style - The filter style + @param {string} [suffix] - { 'desktop' | 'mobile' | 'overflow' } Used on `form` attributes to connect inputs to a form[id] + @param {string} [sort_position] - { 'desktop' | 'mobile' } Used in a data-testID selector for automated testing + @param {boolean} should_use_select_on_mobile - Whether to use a select element for the sorting component on mobile + @param {string} section_id - The section ID +{%- enddoc -%} + + + {% liquid + assign default_sort_by = results.default_sort_by + for option in results.sort_options + if option.value == sort_by + assign status = option.name + endif + endfor + %} + + + + +
      + + + {% for option in results.sort_options %} + + {% endfor %} + +
      +
      +
      + +{% stylesheet %} + .sorting-filter__container { + display: flex; + align-items: center; + justify-content: space-between; + padding-inline: var(--drawer-padding) 0; + padding-block: var(--padding-sm); + margin-inline-end: var(--margin-md); + position: relative; + } + + .sorting-filter__container .facets__label { + font-size: var(--font-h4--size); + } + + .sorting-filter__select-wrapper { + display: flex; + position: relative; + border-radius: var(--variant-picker-button-radius); + align-items: center; + overflow: clip; + padding: var(--padding-2xs) var(--padding-xs); + } + + .sorting-filter__select-wrapper:has(:focus-visible) { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + .sorting-filter__select-wrapper:has(:focus-visible) .sorting-filter__select { + outline: none; + } + + .sorting-filter__container .sorting-filter__select { + appearance: none; + border: 0; + margin: 0; + cursor: pointer; + width: 100%; + padding-inline-end: var(--icon-size-2xs); + text-align: right; + + /* Needed for Safari */ + text-align-last: right; + } + + .sorting-filter__select .icon { + position: absolute; + right: var(--padding-md); + top: 50%; + transform: translateY(-50%); + width: var(--icon-size-2xs); + height: var(--icon-size-2xs); + pointer-events: none; + } + + .sorting-filter { + @media screen and (min-width: 750px) { + z-index: var(--facets-upper-z-index); + } + } + + .sorting-filter__options { + display: flex; + right: 0; + flex-direction: column; + gap: var(--margin-3xs); + padding: calc(var(--drawer-padding) / 2); + color: var(--color-foreground); + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .sorting-filter__option { + cursor: pointer; + display: grid; + grid-template-columns: var(--icon-size-sm) 1fr; + gap: var(--margin-2xs); + min-width: 180px; + padding: var(--padding-2xs) calc(var(--drawer-padding) / 2) var(--padding-2xs) var(--padding-2xs); + + &:hover { + border-radius: calc(var(--style-border-radius-popover) / 2); + background-color: rgb(var(--color-foreground-rgb) / var(--opacity-8)); + } + + &:focus { + border-radius: calc(var(--style-border-radius-popover) / 2); + } + } + + .sorting-filter__input { + display: none; + + &:checked + .sorting-filter__checkmark + .sorting-filter__label { + font-weight: 500; + } + } + + .sorting-filter__checkmark { + visibility: hidden; + } + + *:checked ~ .sorting-filter__checkmark { + visibility: visible; + } + + .sorting-filter__label { + cursor: pointer; + pointer-events: none; + } + + .facets-toggle--no-filters .sorting-filter__select-wrapper { + @media screen and (max-width: 749px) { + padding-inline-start: 0; + } + } + + .facets-mobile-wrapper .sorting-filter .facets__panel { + padding-inline: 0; + position: relative; + } + + .facets-mobile-wrapper .sorting-filter .facets__status { + display: none; + } + + .facets-mobile-wrapper:has(> :nth-child(2)) .sorting-filter .sorting-filter__options { + left: 0; + right: unset; + } + + .facets-mobile-wrapper .sorting-filter .facets__label { + margin-inline-end: var(--margin-2xs); + font-size: var(--font-paragraph--size); + color: var(--color-foreground-muted); + } + + .facets-mobile-wrapper .sorting-filter__options { + border-radius: var(--style-border-radius-popover); + position: absolute; + top: 0; + right: 0; + width: max-content; + min-width: var(--facets-panel-min-width); + max-width: var(--facets-panel-width); + max-height: var(--facets-panel-height); + z-index: var(--facets-upper-z-index); + box-shadow: var(--shadow-popover); + border: var(--style-border-popover); + background-color: var(--color-background); + overflow-y: hidden; + padding: var(--padding-sm); + gap: var(--gap-sm); + } + + .facets-toggle .sorting-filter__container { + @media screen and (max-width: 749px) { + padding: 0; + } + } + + .facets-toggle .sorting-filter__container .facets__label { + @media screen and (max-width: 749px) { + display: none; + } + } + + .facets-toggle .sorting-filter::before { + @media screen and (max-width: 749px) { + display: none; + } + } + + .facets--drawer .sorting-filter { + @media screen and (min-width: 750px) { + display: none; + } + } + + .sorting-filter__options { + block-size: 0; + overflow-y: clip; + opacity: 0; + interpolate-size: allow-keywords; + transition: content-visibility var(--animation-speed-slow) allow-discrete, + padding-block var(--animation-speed-slow) var(--animation-easing), + opacity var(--animation-speed-slow) var(--animation-easing), + block-size var(--animation-speed-slow) var(--animation-easing); + } + + details[open] .sorting-filter__options { + opacity: 1; + block-size: auto; + + @starting-style { + block-size: 0; + opacity: 0; + overflow-y: clip; + } + + &:focus-within { + overflow-y: visible; + } + } +{% endstylesheet %} diff --git a/snippets/spacing-padding.liquid b/snippets/spacing-padding.liquid new file mode 100644 index 000000000..5e00f2319 --- /dev/null +++ b/snippets/spacing-padding.liquid @@ -0,0 +1,11 @@ +{%- comment -%} + Intended for blocks and sections that provide values for all the referenced settings. + +
      + + Accepts: + settings: {block.settings || section.settings} +{%- endcomment -%} + +--padding-block-start: {{ settings.padding-block-start | default: 0 }}px; --padding-block-end:{{- settings.padding-block-end | default: 0 -}}px; +--padding-inline-start:{{ settings.padding-inline-start | default: 0 }}px; --padding-inline-end:{{- settings.padding-inline-end | default: 0 -}}px; diff --git a/snippets/spacing-style.liquid b/snippets/spacing-style.liquid new file mode 100644 index 000000000..70d5289af --- /dev/null +++ b/snippets/spacing-style.liquid @@ -0,0 +1,49 @@ +{%- comment -%} + Intended for blocks and sections that provide values for all the referenced settings. + +
      + + Accepts: + settings: {block.settings || section.settings} + suffix: {string} + scale_min {number}: Value above which spacing scaling will be applied. Default: 20 + disable_scaling {boolean}: Disable scaling. Default: false +{%- endcomment -%} +{%- liquid + assign properties = 'padding,margin' | split: ',' + assign directions = 'block,inline' | split: ',' + assign edges = ',start,end' | split: ',' + assign min = scale_min | default: 20 +-%} +{%- capture variables -%} + {%- for property in properties -%} + {%- for direction in directions -%} + {%- for edge in edges -%} + {%-liquid + assign name = property | append: '-' | append: direction + + if edge != blank + assign name = name | append: '-' | append: edge + endif + + assign setting_id = name + + if suffix != blank + assign setting_id = setting_id | append: '-' | append: suffix + endif + + assign value = settings[setting_id] + -%} + + {%- if value != blank -%} + {%- if disable_scaling != true and value > min -%} + --{{ name }}: max({{ min }}px, calc(var(--spacing-scale) * {{ value }}px)); + {%- else -%} + --{{ name }}: {{ value }}px; + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- endfor -%} + {%- endfor -%} +{%- endcapture -%} +{{- variables | strip | strip_newlines -}} diff --git a/snippets/strikethrough-variant.liquid b/snippets/strikethrough-variant.liquid new file mode 100644 index 000000000..f5e85ee2a --- /dev/null +++ b/snippets/strikethrough-variant.liquid @@ -0,0 +1,11 @@ +{% unless product_option.available %} + + {% # 25deg %} + + +{% endunless %} diff --git a/snippets/stylesheets.liquid b/snippets/stylesheets.liquid new file mode 100644 index 000000000..658f3b294 --- /dev/null +++ b/snippets/stylesheets.liquid @@ -0,0 +1,3 @@ +{{ 'base.css' | asset_url | preload_tag: as: 'style' }} +{{ 'overflow-list.css' | asset_url | preload_tag: as: 'style' }} +{{ 'base.css' | asset_url | stylesheet_tag }} diff --git a/snippets/submenu-font-styles.liquid b/snippets/submenu-font-styles.liquid new file mode 100644 index 000000000..411ca3e43 --- /dev/null +++ b/snippets/submenu-font-styles.liquid @@ -0,0 +1,48 @@ +{%- comment -%} + Derives CSS variables from the menu typography settings for 2nd and 3rd level menu items. + Accepts: + settings: {block.settings} +{%- endcomment -%} + +--menu-parent-font-family: var(--font-{{ settings.type_font_tertiary_link }}--family); --menu-parent-font-style: +var(--font- +{{- settings.type_font_tertiary_link -}} +--style); --menu-parent-font-weight: var(--font- +{{- settings.type_font_tertiary_link -}} +--weight); --menu-parent-font-case: +{% if settings.type_case_tertiary_link == 'uppercase' %}uppercase{% else %}none{% endif %}; +{% case settings.menu_font_style %} + {% when 'regular' %} + --menu-parent-font-size: var(--menu-font-md--size); --menu-parent-font-line-height: + var(--menu-font-md--line-height); --menu-parent-font-color: var(--color-foreground); + --menu-parent-active-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + {% when 'inverse' %} + --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height: + var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) / + var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground); + {% when 'inverse_large' %} + --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height: + var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) / + var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground); +{% endcase %} +--menu-child-font-family: var(--font-{{ settings.type_font_secondary_link }}--family); --menu-child-font-style: +var(--font- +{{- settings.type_font_secondary_link -}} +--style); --menu-child-font-weight: var(--font- +{{- settings.type_font_secondary_link -}} +--weight); --menu-child-font-case: +{% if settings.type_case_secondary_link == 'uppercase' %}uppercase{% else %}none{% endif %}; +{% case settings.menu_font_style %} + {% when 'regular' %} + --menu-child-font-size: var(--menu-font-sm--size); --menu-child-font-line-height: var(--menu-font-sm--line-height); + --menu-child-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text)); + --menu-child-active-font-color: var(--color-foreground); + {% when 'inverse' %} + --menu-child-font-size: var(--menu-font-md--size); --menu-child-font-line-height: var(--menu-font-md--line-height); + --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) / + var(--opacity-subdued-text)); + {% when 'inverse_large' %} + --menu-child-font-size: var(--menu-font-xl--size); --menu-child-font-line-height: var(--menu-font-xl--line-height); + --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) / + var(--opacity-subdued-text)); +{% endcase %} diff --git a/snippets/swatch.liquid b/snippets/swatch.liquid new file mode 100644 index 000000000..1bcaffa91 --- /dev/null +++ b/snippets/swatch.liquid @@ -0,0 +1,41 @@ +{%- doc -%} + Renders a swatch + + @param {object} swatch - a swatch object + @param {object} [variant_image] - an alternate image + @param {string} [mode] - one of 'unscaled' or 'filter' + + @example + {% render 'swatch', swatch: swatch, variant_image: variant_image, mode: 'unscaled' %} +{%- enddoc -%} + +{% liquid + assign swatch_value = null + if settings.show_variant_image and variant_image + assign swatch_image_width = settings.variant_swatch_width | times: 2 + assign swatch_image_url = variant_image | image_url: width: swatch_image_width + assign swatch_value = 'url(' | append: swatch_image_url | append: ')' + elsif swatch.image + assign swatch_image_url = swatch.image | image_url: width: 80 + assign swatch_value = 'url(' | append: swatch_image_url | append: ')' + elsif swatch.color + assign swatch_value = 'rgb(' | append: swatch.color.rgb | append: ')' + endif + assign classes = + case mode + when 'unscaled' + assign extra_classes = ' swatch--unscaled' + when 'filter' + assign extra_classes = ' swatch--filter' + when 'pill' + assign extra_classes = ' swatch--pill' + else + assign extra_classes = '' + endcase +%} + + + diff --git a/snippets/tax-info.liquid b/snippets/tax-info.liquid new file mode 100644 index 000000000..3c16eaee0 --- /dev/null +++ b/snippets/tax-info.liquid @@ -0,0 +1,84 @@ +{%- comment -%} + Intended for use in a block similar to the text block. + + Accepts: + has_discounts_enabled: {boolean} - whether discounts are enabled +{%- endcomment -%} + + + {%- if cart.duties_included and cart.taxes_included -%} + {%- if shop.shipping_policy.body == blank -%} + {%- if has_discounts_enabled -%} + {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }} + {%- else -%} + {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy' | t }} + {%- endif -%} + {%- else -%} + {%- if has_discounts_enabled -%} + {{ + 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html' + | t: link: shop.shipping_policy.url + }} + {%- else -%} + {{ + 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} + {%- endif -%} + {%- endif -%} + {%- elsif cart.duties_included == false and cart.taxes_included -%} + {%- if shop.shipping_policy.body == blank -%} + {%- if has_discounts_enabled -%} + {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }} + {%- else -%} + {{ 'content.taxes_included_shipping_at_checkout_without_policy' | t }} + {%- endif -%} + {%- else -%} + {%- if has_discounts_enabled -%} + {{ + 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html' + | t: link: shop.shipping_policy.url + }} + {%- else -%} + {{ 'content.taxes_included_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} + {%- endif -%} + {%- endif -%} + {%- elsif cart.duties_included and cart.taxes_included == false -%} + {%- if shop.shipping_policy.body == blank -%} + {%- if has_discounts_enabled -%} + {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }} + {%- else -%} + {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy' | t }} + {%- endif -%} + {%- else -%} + {%- if has_discounts_enabled -%} + {{ + 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html' + | t: link: shop.shipping_policy.url + }} + {%- else -%} + {{ + 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} + {%- endif -%} + {%- endif -%} + {%- elsif cart.duties_included == false and cart.taxes_included == false -%} + {%- if shop.shipping_policy.body == blank -%} + {%- if has_discounts_enabled -%} + {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }} + {%- else -%} + {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy' | t }} + {%- endif -%} + {%- else -%} + {%- if has_discounts_enabled -%} + {{ + 'content.taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html' + | t: link: shop.shipping_policy.url + }} + {%- else -%} + {{ 'content.taxes_at_checkout_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} + {%- endif -%} + {%- endif -%} + {%- endif -%} + diff --git a/snippets/text.liquid b/snippets/text.liquid new file mode 100644 index 000000000..cfab851ed --- /dev/null +++ b/snippets/text.liquid @@ -0,0 +1,216 @@ +{%- doc -%} + Intended for use in a block similar to the text block. + + @param {string} [class] - custom class to define in addition to text-block classes + @param {string} [fallback_text] - fallback text if settings.text does not exist + @param {string} [width] - width of the text block +{%- enddoc -%} + +{% liquid + assign plain_text = block.settings.text | strip_newlines | strip_html | strip + assign text_width = width | default: block.settings.width + + if block.settings.font_size contains 'heading-lg' or block.settings.font_size contains 'heading-xl' + assign type = 'display' + elsif block.settings.font_size contains 'heading' + assign type = 'heading' + else + assign type = 'body' + endif + if block.settings.type_preset == 'rte' or block.settings.type_preset == 'paragraph' + assign is_rte = true + endif + + capture text_block_classes + if text_width == '100%' + echo 'text-block--align-' | append: block.settings.alignment + if block.settings.max_width == 'none' + echo ' text-block--full-width ' + endif + endif + if block.settings.type_preset == 'custom' + echo ' custom-typography ' + if block.settings.font_size != '' + echo ' custom-font-size ' + endif + if block.settings.color != '' + echo ' custom-color ' + endif + endif + if block.settings.background + echo ' text-block--background ' + endif + if is_rte + echo ' rte ' + endif + endcapture +%} + +{% capture attributes %} + class="{{ class }} spacing-style text-block text-block--{{ block.id }} {{ block.settings.type_preset }} + {{ text_block_classes }} + " + + style=" + {% render 'spacing-padding', settings: block.settings %} + {% render 'typography-style', settings: block.settings %} + --width: {{ text_width }}; + --max-width: var(--max-width--{{ type }}-{{ block.settings.max_width }}); + {% if text_width == "100%" %} + --text-align: {{ block.settings.alignment }}; + {% endif %} + {% if block.settings.background %} + --text-background-color: {{ block.settings.background_color | default: 'rgb(255 255 255 / 1.0)' }}; + --text-corner-radius: {{ block.settings.corner_radius }}px; + --text-padding: max(var(--padding-2xs), calc((var(--text-corner-radius) + var(--padding-xs)) * (1 - cos(45deg)))); + {% endif %} + " + + {{ block.shopify_attributes }} +{% endcapture %} +{% liquid + # {{ attributes }} must be on the immediate HTML parent of the text to preserve + # the click-to-edit connection in the theme editor. Any break between the text, + # including if-statements, will break the connection. + + assign element = 'div' + if is_rte + assign element = 'rte-formatter' + endif +%} + +{% if fallback_text != blank and plain_text == blank %} +
      + {{ fallback_text }} +
      +{% elsif plain_text != blank %} + <{{ element }} {{ attributes }}> + {{ block.settings.text }} + +{% endif %} + +{% stylesheet %} + :root { + --text-align-default: left; + } + + [style*='--horizontal-alignment: center'] .text-block { + --text-align-default: center; + } + + [style*='--horizontal-alignment: flex-end'] .text-block { + --text-align-default: right; + } + + [style*='--horizontal-alignment: flex-start'] > .text-block { + --text-align-default: left; + } + + [style*='--horizontal-alignment: center'] > .text-block { + --text-align-default: center; + } + + [style*='--horizontal-alignment: flex-end'] > .text-block { + --text-align-default: right; + } + + .text-block { + width: var(--width); + max-width: 100%; + display: flex; + flex-direction: column; + align-items: var(--horizontal-alignment); + } + + .text-block > * { + width: var(--width); + max-width: var(--max-width, 100%); + text-align: var(--text-align, var(--text-align-default)); + text-wrap: var(--text-wrap); + } + + .text-block:not(.text-block--full-width).rte, + .text-block:not(.text-block--full-width).paragraph { + /* Safari doesn't support pretty, so fallback to balance */ + text-wrap: balance; + text-wrap: pretty; + } + + .text-block:not(.text-block--full-width):is(.h1, .h2, .h3, .h4, .h5, .h6) { + text-wrap: balance; + } + + /* Hide underline unless text is using paragraph styles. */ + .text-block:is(.h1, .h2, .h3, .h4, .h5, .h6) a { + text-decoration-color: transparent; + } + + .text-block h1, + .text-block.h1 > * { + margin-block: var(--font-h1--spacing); + } + + .text-block h2, + .text-block.h2 > * { + margin-block: var(--font-h2--spacing); + } + + .text-block h3, + .text-block.h3 > * { + margin-block: var(--font-h3--spacing); + } + + .text-block h4, + .text-block.h4 > * { + margin-block: var(--font-h4--spacing); + } + + .text-block h5, + .text-block.h5 > * { + margin-block: var(--font-h5--spacing); + } + + .text-block h6, + .text-block.h6 > * { + margin-block: var(--font-h6--spacing); + } + + .text-block p, + .text-block.p > * { + margin-block: var(--font-paragraph--spacing); + } + + .text-block > *:first-child { + margin-block-start: 0; + } + + .text-block > *:last-child { + margin-block-end: 0; + } + + .text-block--align-center, + .text-block--align-center > * { + margin-inline: auto; + } + + .text-block--align-right, + .text-block--align-right > * { + margin-inline-start: auto; + } + + .text-block--background { + background-color: var(--text-background-color); + border-radius: var(--text-corner-radius); + + /* To avoid text being cropped when using a border radius we add a minimum padding. */ + padding-block-start: max(var(--text-padding), var(--padding-block-start, 0)); + padding-block-end: max(var(--text-padding), var(--padding-block-end, 0)); + padding-inline-start: max(var(--text-padding), var(--padding-inline-start, 0)); + padding-inline-end: max(var(--text-padding), var(--padding-inline-end, 0)); + } + + .custom-color, + .custom-color > :is(h1, h2, h3, h4, h5, h6, p, *) { + color: var(--color); + } +{% endstylesheet %} diff --git a/snippets/theme-editor.liquid b/snippets/theme-editor.liquid new file mode 100644 index 000000000..efa9f5f72 --- /dev/null +++ b/snippets/theme-editor.liquid @@ -0,0 +1,4 @@ + diff --git a/snippets/theme-styles-variables.liquid b/snippets/theme-styles-variables.liquid new file mode 100644 index 000000000..84e74728f --- /dev/null +++ b/snippets/theme-styles-variables.liquid @@ -0,0 +1,556 @@ +{%- liquid + assign primary_font_bold = settings.type_body_font | font_modify: 'weight', 'bold' + assign primary_font_italic = settings.type_body_font | font_modify: 'style', 'italic' + assign primary_font_bold_italic = primary_font_bold | font_modify: 'style', 'italic' + + assign secondary_font_bold = settings.type_subheading_font | font_modify: 'weight', 'bold' + assign secondary_font_italic = settings.type_subheading_font | font_modify: 'style', 'italic' + assign secondary_font_bold_italic = secondary_font_bold | font_modify: 'style', 'italic' + + assign tertiary_font_bold = settings.type_heading_font | font_modify: 'weight', 'bold' + assign tertiary_font_italic = settings.type_heading_font | font_modify: 'style', 'italic' + assign tertiary_font_bold_italic = tertiary_font_bold | font_modify: 'style', 'italic' + + assign accent_font_bold = settings.type_accent_font | font_modify: 'weight', 'bold' + assign accent_font_italic = settings.type_accent_font | font_modify: 'style', 'italic' + assign accent_font_bold_italic = accent_font_bold | font_modify: 'style', 'italic' +%} + +{% style %} + {{ settings.type_body_font | font_face: font_display: 'swap' }} + {{ primary_font_bold | font_face: font_display: 'swap' }} + {{ primary_font_italic | font_face: font_display: 'swap' }} + {{ primary_font_bold_italic | font_face: font_display: 'swap' }} + + {{ settings.type_subheading_font | font_face: font_display: 'swap' }} + {{ secondary_font_bold | font_face: font_display: 'swap' }} + {{ secondary_font_italic | font_face: font_display: 'swap' }} + {{ secondary_font_bold_italic | font_face: font_display: 'swap' }} + + {{ settings.type_heading_font | font_face: font_display: 'swap' }} + {{ tertiary_font_bold | font_face: font_display: 'swap' }} + {{ tertiary_font_italic | font_face: font_display: 'swap' }} + {{ tertiary_font_bold_italic | font_face: font_display: 'swap' }} + + {{ settings.type_accent_font | font_face: font_display: 'swap' }} + {{ accent_font_bold | font_face: font_display: 'swap' }} + {{ accent_font_italic | font_face: font_display: 'swap' }} + {{ accent_font_bold_italic | font_face: font_display: 'swap' }} + + :root { + /* Page Layout */ + --sidebar-width: 25rem; + --narrow-content-width: 36rem; + --normal-content-width: 42rem; + --wide-content-width: 46rem; + --narrow-page-width: 90rem; + --normal-page-width: 120rem; + --wide-page-width: 150rem; + + /* Section Heights */ + --section-height-small: 15rem; + --section-height-medium: 25rem; + --section-height-large: 35rem; + + @media screen and (min-width: 40em) { + --section-height-small: 40svh; + --section-height-medium: 55svh; + --section-height-large: 70svh; + } + + @media screen and (min-width: 60em) { + --section-height-small: 50svh; + --section-height-medium: 65svh; + --section-height-large: 80svh; + } + + /* Letter spacing */ + --letter-spacing-sm: 0.06em; + --letter-spacing-md: 0.13em; + + /* Font families */ + --font-body--family: {{ settings.type_body_font.family }}, {{ settings.type_body_font.fallback_families }}; + --font-body--style: {{ settings.type_body_font.style }}; + --font-body--weight: {{ settings.type_body_font.weight }}; + --font-subheading--family: {{ settings.type_subheading_font.family }}, {{ settings.type_subheading_font.fallback_families }}; + --font-subheading--style: {{ settings.type_subheading_font.style }}; + --font-subheading--weight: {{ settings.type_subheading_font.weight }}; + --font-heading--family: {{ settings.type_heading_font.family }}, {{ settings.type_heading_font.fallback_families }}; + --font-heading--style: {{ settings.type_heading_font.style }}; + --font-heading--weight: {{ settings.type_heading_font.weight }}; + --font-accent--family: {{ settings.type_accent_font.family }}, {{ settings.type_accent_font.fallback_families }}; + --font-accent--style: {{ settings.type_accent_font.style }}; + --font-accent--weight: {{ settings.type_accent_font.weight }}; + + /* Margin sizes */ + --font-h1--spacing: 0.25em; + --font-h2--spacing: 0.25em; + --font-h3--spacing: 0.25em; + --font-h4--spacing: 0.25em; + --font-h5--spacing: 0.25em; + --font-h6--spacing: 0.25em; + --font-paragraph--spacing: 0.5em; + + /* Heading colors */ + --font-h1--color: var(--color-foreground-heading); + --font-h2--color: var(--color-foreground-heading); + --font-h3--color: var(--color-foreground-heading); + --font-h4--color: var(--color-foreground-heading); + --font-h5--color: var(--color-foreground-heading); + --font-h6--color: var(--color-foreground-heading); + + /** Z-Index / Layering */ + --layer-section-background: -2; + --layer-lowest: -1; + --layer-base: 0; + --layer-flat: 1; + --layer-raised: 2; + --layer-heightened: 4; + --layer-sticky: 8; + --layer-window-overlay: 10; + --layer-header-menu: 12; + --layer-overlay: 16; + --layer-menu-drawer: 18; + --layer-temporary: 20; + + /* Max-width / Measure */ + --max-width--body-normal: 50ch; + --max-width--body-narrow: 35ch; + + --max-width--heading-normal: 50ch; + --max-width--heading-narrow: 30ch; + + --max-width--display-normal: 20ch; + --max-width--display-narrow: 15ch; + --max-width--display-tight: 5ch; + + /* Letter-spacing / Tracking */ + --letter-spacing--display-tight: -0.03em; + --letter-spacing--display-normal: 0em; + --letter-spacing--display-loose: 0.03em; + + --letter-spacing--heading-tight: -0.03em; + --letter-spacing--heading-normal: 0em; + --letter-spacing--heading-loose: 0.03em; + + --letter-spacing--body-tight: -0.03em; + --letter-spacing--body-normal: 0em; + --letter-spacing--body-loose: 0.03em; + + /* Line height / Leading */ + --line-height: 1; + + --line-height--display-tight: 1; + --line-height--display-normal: 1.1; + --line-height--display-loose: 1.2; + + --line-height--heading-tight: 1.15; + --line-height--heading-normal: 1.25; + --line-height--heading-loose: 1.35; + + --line-height--body-tight: 1.2; + --line-height--body-normal: 1.4; + --line-height--body-loose: 1.6; + + /* Typography presets */ + {% liquid + assign font_sizes = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", " + assign fluid_size_cutoff = 48 + assign absolute_font_size_min = 10 + + comment + Build an array of font sizes and sort it + endcomment + assign font_size_values = '' + for font_size in font_sizes + assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size + assign size_setting_value = settings[size_setting] | times: 1 + + comment + If the font size is less than 100, pad it with a 0 + This is because we end up with an array of strings, which | sort filter can't order "correctly") + endcomment + if size_setting_value < 100 + assign size_setting_value = '0[size_setting_value]' | replace: '[size_setting_value]', size_setting_value + endif + + assign font_size_values = font_size_values | append: '[size_setting_value],' | replace: '[size_setting_value]', size_setting_value + endfor + + assign font_size_values = font_size_values | split: ',' | uniq | sort_natural + + comment + For each font size S, find the next smaller size S-1, and determine the minimum for S + The calculation depends on the size of S-1 (over or under the cutoff) + endcomment + for font_size in font_sizes + assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size + assign font_size_value = settings[size_setting] | times: 1 + assign font_size_string = '[font_size_value]' | replace: '[font_size_value]', font_size_value + assign index = font_size_values | find_index: font_size_string + + if font_size_value >= fluid_size_cutoff + + comment + Calculate the minimum size for each font size + endcomment + assign fluid_font_size_min = font_size_value + + if index == 0 + assign fluid_font_size_min = absolute_font_size_min + else + assign next_font_size_index = index | minus: 1 + assign next_font_size_value = font_size_values[next_font_size_index] + assign next_font_size_value_number = next_font_size_value | times: 1 + + comment + If the next bigger font size under the fluid cutoff, we use keep a 4px buffer + endcomment + if next_font_size_value_number < fluid_size_cutoff + assign fluid_font_size_min = next_font_size_value_number | plus: 4 + if font_size_value < fluid_font_size_min + assign fluid_font_size_min = font_size_value + endif + else + assign fluid_font_size_min = next_font_size_value | times: 1 + endif + endif + + comment + Calculate the fluid and maximum size for each font size + endcomment + assign fluid_size_min_rem = fluid_font_size_min | divided_by: 16.0 + assign fluid_size = font_size_value | times: 0.1 + assign fluid_size_max_rem = font_size_value | divided_by: 16.0 + + echo '--font-size--[font_size]: clamp([fluid_size_min_rem]rem, [fluid_size]vw, [fluid_size_max_rem]rem);' | replace: '[font_size]', font_size | replace: '[fluid_size_min_rem]', fluid_size_min_rem | replace: '[fluid_size]', fluid_size | replace: '[fluid_size_max_rem]', fluid_size_max_rem + else + assign fluid_size_rem = font_size_value | divided_by: 16.0 + echo '--font-size--[font_size]: [fluid_size_rem]rem;' | replace: '[font_size]', font_size | replace: '[fluid_size_rem]', fluid_size_rem + endif + endfor + + assign type_presets = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", " + + for preset_name in type_presets + assign preset_size = '--font-size--[preset_name]' | replace: '[preset_name]', preset_name + assign preset_line_height = 'type_line_height_[preset_name]' | replace: '[preset_name]', preset_name + + if preset_name == 'paragraph' + assign preset_font = '--font-body--family' + assign preset_style = '--font-body--style' + assign preset_weight = '400' + assign preset_case = '--font-body--case' + assign preset_letter_spacing = 'body-normal' + + echo '--font-[preset_name]--weight: [preset_weight];' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight + echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', preset_letter_spacing + else + assign preset_font_id = 'type_font_[preset_name]' | replace: '[preset_name]', preset_name + assign preset_font = '--font-[preset_font]--family' | replace: '[preset_font]', settings[preset_font_id] + assign preset_style = '--font-[preset_font]--style' | replace: '[preset_font]', settings[preset_font_id] + assign preset_weight = '--font-[preset_font]--weight' | replace: '[preset_font]', settings[preset_font_id] + assign preset_case = 'type_case_[preset_name]' | replace: '[preset_name]', preset_name + assign preset_letter_spacing = 'type_letter_spacing_[preset_name]' | replace: '[preset_name]', preset_name + + echo '--font-[preset_name]--weight: var([preset_weight]);' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight + echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', settings[preset_letter_spacing] + endif + + echo '--font-[preset_name]--size: var([preset_size]);' | replace: '[preset_name]', preset_name | replace: '[preset_size]', preset_size + echo '--font-[preset_name]--family: var([preset_font]);' | replace: '[preset_name]', preset_name | replace: '[preset_font]', preset_font + echo '--font-[preset_name]--style: var([preset_style]);' | replace: '[preset_name]', preset_name | replace: '[preset_style]', preset_style + echo '--font-[preset_name]--case: [preset_case];' | replace: '[preset_name]', preset_name | replace: '[preset_case]', settings[preset_case] + echo '--font-[preset_name]--line-height: var(--line-height--[preset_line_height]);' | replace: '[preset_name]', preset_name | replace: '[preset_line_height]', settings[preset_line_height] + endfor + %} + + /* Hardcoded font sizes */ + --font-size--2xs: 0.625rem; + --font-size--xs: 0.8125rem; + --font-size--sm: 0.875rem; + --font-size--md: 1rem; + --font-size--lg: 1.125rem; + --font-size--xl: 1.25rem; + --font-size--2xl: 1.5rem; + --font-size--3xl: 2rem; + --font-size--4xl: 2.5rem; + --font-size--5xl: 3rem; + --font-size--6xl: 3.5rem; + + /* Menu font sizes */ + --menu-font-sm--size: 0.875rem; + --menu-font-sm--line-height: calc(1.1 + 0.5 * min(16 / 14)); + --menu-font-md--size: 1rem; + --menu-font-md--line-height: calc(1.1 + 0.5 * min(16 / 16)); + --menu-font-lg--size: 1.125rem; + --menu-font-lg--line-height: calc(1.1 + 0.5 * min(16 / 18)); + --menu-font-xl--size: 1.25rem; + --menu-font-xl--line-height: calc(1.1 + 0.5 * min(16 / 20)); + --menu-font-2xl--size: 1.75rem; + --menu-font-2xl--line-height: calc(1.1 + 0.5 * min(16 / 28)); + + /* Colors */ + --color-error: #8B0000; + --color-success: #006400; + --color-white: #FFFFFF; + --color-white-rgb: 255 255 255; + --color-black: #000000; + --color-instock: #3ED660; + --color-lowstock: #EE9441; + --color-outofstock: #C8C8C8; + + /* Opacity */ + --opacity-5: 0.05; + --opacity-8: 0.08; + --opacity-10: 0.1; + --opacity-15: 0.15; + --opacity-20: 0.2; + --opacity-25: 0.25; + --opacity-30: 0.3; + --opacity-40: 0.4; + --opacity-50: 0.5; + --opacity-60: 0.6; + --opacity-70: 0.7; + --opacity-80: 0.8; + --opacity-85: 0.85; + --opacity-90: 0.9; + --opacity-subdued-text: var(--opacity-70); + + --shadow-button: 0 2px 3px rgb(0 0 0 / 20%); + --gradient-image-overlay: linear-gradient(to top, rgb(0 0 0 / 0.5), transparent); + + /* Spacing */ + --margin-3xs: 0.125rem; + --margin-2xs: 0.3rem; + --margin-xs: 0.5rem; + --margin-sm: 0.7rem; + --margin-md: 0.8rem; + --margin-lg: 1rem; + --margin-xl: 1.25rem; + --margin-2xl: 1.5rem; + --margin-3xl: 1.75rem; + --margin-4xl: 2rem; + --margin-5xl: 3rem; + --margin-6xl: 5rem; + + --scroll-margin: 50px; + + --padding-3xs: 0.125rem; + --padding-2xs: 0.25rem; + --padding-xs: 0.5rem; + --padding-sm: 0.7rem; + --padding-md: 0.8rem; + --padding-lg: 1rem; + --padding-xl: 1.25rem; + --padding-2xl: 1.5rem; + --padding-3xl: 1.75rem; + --padding-4xl: 2rem; + --padding-5xl: 3rem; + --padding-6xl: 4rem; + + --gap-3xs: 0.125rem; + --gap-2xs: 0.3rem; + --gap-xs: 0.5rem; + --gap-sm: 0.7rem; + --gap-md: 0.9rem; + --gap-lg: 1rem; + --gap-xl: 1.25rem; + --gap-2xl: 2rem; + --gap-3xl: 3rem; + + --spacing-scale-sm: 0.6; + --spacing-scale-md: 0.7; + --spacing-scale-default: 1.0; + + /* Checkout buttons gap */ + --checkout-button-gap: 8px; + + /* Borders */ + --style-border-width: 1px; + --style-border-radius-xs: 0.2rem; + --style-border-radius-sm: 0.6rem; + --style-border-radius-md: 0.8rem; + --style-border-radius-50: 50%; + --style-border-radius-lg: 1rem; + --style-border-radius-pills: {{ settings.pills_border_radius }}px; + --style-border-radius-inputs: {{ settings.inputs_border_radius }}px; + --style-border-radius-buttons-primary: {{ settings.button_border_radius_primary }}px; + --style-border-radius-buttons-secondary: {{ settings.button_border_radius_secondary }}px; + --style-border-width-primary: {{ settings.primary_button_border_width }}px; + --style-border-width-secondary: {{ settings.secondary_button_border_width }}px; + --style-border-width-inputs: {{ settings.input_border_width }}px; + --style-border-radius-popover: {{ settings.popover_border_radius }}px; + --style-border-popover: {{ settings.popover_border_width }}px {{ settings.popover_border }} rgb(var(--color-border-rgb) / {{ settings.popover_border_opacity }}%); + --style-border-drawer: {{ settings.drawer_border_width }}px {{ settings.drawer_border }} rgb(var(--color-border-rgb) / {{ settings.drawer_border_opacity }}%); + --style-border-swatch-opacity: {{ settings.variant_swatch_border_opacity }}%; + --style-border-swatch-width: {{ settings.variant_swatch_border_width }}px; + --style-border-swatch-style: {{ settings.variant_swatch_border_style }}; + + /* Animation */ + --ease-out-cubic: cubic-bezier(0.33, 1, 0.68, 1); + --ease-out-quad: cubic-bezier(0.32, 0.72, 0, 1); + --animation-speed-fast: 0.0625s; + --animation-speed: 0.125s; + --animation-speed-slow: 0.2s; + --animation-speed-medium: 0.15s; + --animation-easing: ease-in-out; + --animation-slideshow-easing: cubic-bezier(0.4, 0, 0.2, 1); + --drawer-animation-speed: 0.2s; + --animation-values-slow: var(--animation-speed-slow) var(--animation-easing); + --animation-values: var(--animation-speed) var(--animation-easing); + --animation-values-fast: var(--animation-speed-fast) var(--animation-easing); + --animation-values-allow-discrete: var(--animation-speed) var(--animation-easing) allow-discrete; + --animation-timing-hover: cubic-bezier(0.25, 0.46, 0.45, 0.94); + --animation-timing-active: cubic-bezier(0.5, 0, 0.75, 0); + --animation-timing-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); + --animation-timing-default: cubic-bezier(0, 0, 0.2, 1); + --animation-timing-fade-in: cubic-bezier(0.16, 1, 0.3, 1); + --animation-timing-fade-out: cubic-bezier(0.4, 0, 0.2, 1); + + /* View transitions */ + /* View transition old */ + --view-transition-old-main-content: var(--animation-speed) var(--animation-easing) both fadeOut; + + /* View transition new */ + --view-transition-new-main-content: var(--animation-speed) var(--animation-easing) both fadeIn, var(--animation-speed) var(--animation-easing) both slideInTopViewTransition; + + /* Focus */ + --focus-outline-width: 0.09375rem; + --focus-outline-offset: 0.2em; + + /* Badges */ + --badge-blob-padding-block: 1px; + --badge-blob-padding-inline: 12px 8px; + --badge-rectangle-padding-block: 1px; + --badge-rectangle-padding-inline: 6px; + @media screen and (min-width: 750px) { + --badge-blob-padding-block: 4px; + --badge-blob-padding-inline: 16px 12px; + --badge-rectangle-padding-block: 4px; + --badge-rectangle-padding-inline: 10px; + } + + /* Icons */ + --icon-size-2xs: 0.6rem; + --icon-size-xs: 0.85rem; + --icon-size-sm: 1.25rem; + --icon-size-md: 1.375rem; + --icon-size-lg: 1.5rem; + --icon-stroke-width: {% if settings.icon_stroke == 'thin' %}1px{% elsif settings.icon_stroke == 'heavy' %}2px{% else %}1.5px{% endif %}; + + /* Input */ + --input-email-min-width: 200px; + --input-search-max-width: 650px; + --input-padding-y: 0.8rem; + --input-padding-x: 0.8rem; + --input-padding: var(--input-padding-y) var(--input-padding-x); + --input-box-shadow-width: var(--style-border-width-inputs); + --input-box-shadow: 0 0 0 var(--input-box-shadow-width) var(--color-input-border); + --input-box-shadow-focus: 0 0 0 calc(var(--input-box-shadow-width) + 0.5px) var(--color-input-border); + --input-disabled-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10)); + --input-disabled-border-color: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + --input-disabled-text-color: rgb(var(--color-foreground-rgb) / var(--opacity-50)); + --input-textarea-min-height: 55px; + + /* Button size */ + --button-size-sm: 30px; + --button-size-md: 36px; + --button-size: var(--minimum-touch-target); + --button-padding-inline: 24px; + --button-padding-block: 16px; + + /* Button font-family */ + --button-font-family-primary: var(--font-{{ settings.type_font_button_primary }}--family); + --button-font-family-secondary: var(--font-{{ settings.type_font_button_secondary }}--family); + + /* Button font-weight */ + --button-font-weight-primary: {{ settings.button_font_weight_primary }}; + --button-font-weight-secondary: {{ settings.button_font_weight_secondary }}; + + /* Button text case */ + --button-text-case: {{ settings.button_text_case }}; + --button-text-case-primary: {{ settings.button_text_case_primary }}; + --button-text-case-secondary: {{ settings.button_text_case_secondary }}; + + /* Borders */ + --border-color: rgb(var(--color-border-rgb) / var(--opacity-50)); + --border-width-sm: 1px; + --border-width-md: 2px; + --border-width-lg: 5px; + + /* Drawers */ + --drawer-inline-padding: 25px; + --drawer-menu-inline-padding: 2.5rem; + --drawer-header-block-padding: 20px; + --drawer-content-block-padding: 10px; + --drawer-header-desktop-top: 0rem; + --drawer-padding: calc(var(--padding-sm) + 7px); + --drawer-height: 100dvh; + --drawer-width: 95vw; + --drawer-max-width: 500px; + + /* Variant Picker Swatches */ + --variant-picker-swatch-width-unitless: {{ settings.variant_swatch_width }}; + --variant-picker-swatch-height-unitless: {{ settings.variant_swatch_height }}; + --variant-picker-swatch-width: {{ settings.variant_swatch_width | append: 'px' }}; + --variant-picker-swatch-height: {{ settings.variant_swatch_height | append: 'px' }}; + --variant-picker-swatch-radius: {{ settings.variant_swatch_radius | append: 'px' }}; + --variant-picker-border-width: {{ settings.variant_swatch_border_width | append: 'px' }}; + --variant-picker-border-style: {{ settings.variant_swatch_border_style }}; + --variant-picker-border-opacity: {{ settings.variant_swatch_border_opacity | append: '%' }}; + + /* Variant Picker Buttons */ + --variant-picker-button-radius: {{ settings.variant_button_radius | append: 'px' }}; + --variant-picker-button-border-width: {{ settings.variant_button_border_width | append: 'px' }}; + + /* Slideshow */ + --slideshow-controls-size: 3.5rem; + --slideshow-controls-icon: 2rem; + --peek-next-slide-size: 3rem; + + /* Utilities */ + --backdrop-opacity: 0.15; + --backdrop-color-rgb: var(--color-shadow-rgb); + --minimum-touch-target: 44px; + --disabled-opacity: 0.5; + --skeleton-opacity: 0.025; + + /* Shapes */ + --shape--circle: circle(50% at center); + --shape--sunburst: polygon(100% 50%,94.62% 55.87%,98.3% 62.94%,91.57% 67.22%,93.3% 75%,85.7% 77.39%,85.36% 85.36%,77.39% 85.7%,75% 93.3%,67.22% 91.57%,62.94% 98.3%,55.87% 94.62%,50% 100%,44.13% 94.62%,37.06% 98.3%,32.78% 91.57%,25% 93.3%,22.61% 85.7%,14.64% 85.36%,14.3% 77.39%,6.7% 75%,8.43% 67.22%,1.7% 62.94%,5.38% 55.87%,0% 50%,5.38% 44.13%,1.7% 37.06%,8.43% 32.78%,6.7% 25%,14.3% 22.61%,14.64% 14.64%,22.61% 14.3%,25% 6.7%,32.78% 8.43%,37.06% 1.7%,44.13% 5.38%,50% 0%,55.87% 5.38%,62.94% 1.7%,67.22% 8.43%,75% 6.7%,77.39% 14.3%,85.36% 14.64%,85.7% 22.61%,93.3% 25%,91.57% 32.78%,98.3% 37.06%,94.62% 44.13%); + --shape--diamond: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); + --shape--blob: polygon(85.349% 11.712%, 87.382% 13.587%, 89.228% 15.647%, 90.886% 17.862%, 92.359% 20.204%, 93.657% 22.647%, 94.795% 25.169%, 95.786% 27.752%, 96.645% 30.382%, 97.387% 33.048%, 98.025% 35.740%, 98.564% 38.454%, 99.007% 41.186%, 99.358% 43.931%, 99.622% 46.685%, 99.808% 49.446%, 99.926% 52.210%, 99.986% 54.977%, 99.999% 57.744%, 99.975% 60.511%, 99.923% 63.278%, 99.821% 66.043%, 99.671% 68.806%, 99.453% 71.565%, 99.145% 74.314%, 98.724% 77.049%, 98.164% 79.759%, 97.433% 82.427%, 96.495% 85.030%, 95.311% 87.529%, 93.841% 89.872%, 92.062% 91.988%, 89.972% 93.796%, 87.635% 95.273%, 85.135% 96.456%, 82.532% 97.393%, 79.864% 98.127%, 77.156% 98.695%, 74.424% 99.129%, 71.676% 99.452%, 68.918% 99.685%, 66.156% 99.844%, 63.390% 99.942%, 60.624% 99.990%, 57.856% 99.999%, 55.089% 99.978%, 52.323% 99.929%, 49.557% 99.847%, 46.792% 99.723%, 44.031% 99.549%, 41.273% 99.317%, 38.522% 99.017%, 35.781% 98.639%, 33.054% 98.170%, 30.347% 97.599%, 27.667% 96.911%, 25.024% 96.091%, 22.432% 95.123%, 19.907% 93.994%, 17.466% 92.690%, 15.126% 91.216%, 12.902% 89.569%, 10.808% 87.761%, 8.854% 85.803%, 7.053% 83.703%, 5.418% 81.471%, 3.962% 79.119%, 2.702% 76.656%, 1.656% 74.095%, 0.846% 71.450%, 0.294% 68.740%, 0.024% 65.987%, 0.050% 63.221%, 0.343% 60.471%, 0.858% 57.752%, 1.548% 55.073%, 2.370% 52.431%, 3.283% 49.819%, 4.253% 47.227%, 5.249% 44.646%, 6.244% 42.063%, 7.211% 39.471%, 8.124% 36.858%, 8.958% 34.220%, 9.711% 31.558%, 10.409% 28.880%, 11.083% 26.196%, 11.760% 23.513%, 12.474% 20.839%, 13.259% 18.186%, 14.156% 15.569%, 15.214% 13.012%, 16.485% 10.556%, 18.028% 8.261%, 19.883% 6.211%, 22.041% 4.484%, 24.440% 3.110%, 26.998% 2.057%, 29.651% 1.275%, 32.360% 0.714%, 35.101% 0.337%, 37.859% 0.110%, 40.624% 0.009%, 43.391% 0.016%, 46.156% 0.113%, 48.918% 0.289%, 51.674% 0.533%, 54.425% 0.837%, 57.166% 1.215%, 59.898% 1.654%, 62.618% 2.163%, 65.322% 2.750%, 68.006% 3.424%, 70.662% 4.197%, 73.284% 5.081%, 75.860% 6.091%, 78.376% 7.242%, 80.813% 8.551%, 83.148% 10.036%, 85.349% 11.712%); + + /* Buy buttons */ + --height-buy-buttons: calc(var(--padding-lg) * 2 + var(--icon-size-sm)); + + /* Card image height variables */ + --height-small: 10rem; + --height-medium: 11.5rem; + --height-large: 13rem; + --height-full: 100vh; + + @media screen and (min-width: 750px) { + --height-small: 17.5rem; + --height-medium: 21.25rem; + --height-large: 25rem; + } + + /* Modal */ + --modal-max-height: 65dvh; + + /* Card styles for search */ + --card-bg-hover: rgb(var(--color-foreground-rgb) / var(--opacity-5)); + --card-border-hover: rgb(var(--color-foreground-rgb) / var(--opacity-30)); + --card-border-focus: rgb(var(--color-foreground-rgb) / var(--opacity-10)); + + /* Cart */ + --cart-primary-font-family: var(--font-body--family); + --cart-primary-font-style: var(--font-body--style); + --cart-primary-font-weight: var(--font-body--weight); + --cart-secondary-font-family: var(--font-{{ settings.cart_price_font }}--family); + --cart-secondary-font-style: var(--font-{{ settings.cart_price_font }}--style); + --cart-secondary-font-weight: var(--font-{{ settings.cart_price_font }}--weight); + } +{% endstyle %} diff --git a/snippets/timeline-scope.liquid b/snippets/timeline-scope.liquid new file mode 100644 index 000000000..67c1cfe02 --- /dev/null +++ b/snippets/timeline-scope.liquid @@ -0,0 +1,11 @@ +{%- liquid + assign timeline_scope = '' + + for index in (1..count) + assign scope = '--prefix-index, ' | replace: 'prefix', prefix | replace: 'index', index + assign timeline_scope = timeline_scope | append: scope + endfor + + assign timeline_scope = timeline_scope | strip | split: ',' | compact | join: ',' +-%} +{{- timeline_scope -}} diff --git a/snippets/typography-style.liquid b/snippets/typography-style.liquid new file mode 100644 index 000000000..e89876d63 --- /dev/null +++ b/snippets/typography-style.liquid @@ -0,0 +1,75 @@ +{%- comment -%} + Intended for blocks and sections that provide values for all the referenced settings. + +
      + + Accepts: + settings: {settings || section.settings} +{%- endcomment -%} + +{% assign preset = preset | default: settings.type_preset %} + +{%- capture variables -%} + {%- if preset != 'rte' and settings.color != "" -%} + --color: {{ settings.color }}; + {%- endif -%} + {%- if preset == 'custom' -%} + {% liquid + unless type + comment + When choosing to customize the font, picking a specific font size + determines the type of text block. + endcomment + if settings.font_size != '' + assign font_size_value = settings.font_size | split: 'rem' | first | times: 1.0 + + if font_size_value > 4.5 + assign type = 'display' + elsif font_size_value > 3.5 + assign type = 'heading' + else + assign type = 'body' + endif + endif + endunless + %} + {%- if settings.font_size != blank -%} + {%- liquid + assign font_size_rem = settings.font_size | split: 'rem' | first | times: 1.0 + assign fluid_size_cutoff_rem = 3.0 + + if font_size_rem >= fluid_size_cutoff_rem + assign target_viewport = 1400 + assign vw_value = font_size_rem | times: 16 | divided_by: target_viewport | times: 100 + + assign scale_factor = font_size_rem | divided_by: fluid_size_cutoff_rem + assign base_min_rem = 3.0 + assign scaling_bonus_rem = scale_factor | minus: 1 | times: 0.25 + assign dynamic_min_rem = base_min_rem | plus: scaling_bonus_rem + endif + -%} + {%- if font_size_rem >= fluid_size_cutoff_rem -%} + --font-size: clamp({{ dynamic_min_rem }}rem, {{ vw_value }}vw, {{ settings.font_size }}); + {%- else -%} + --font-size: {{ settings.font_size }}; + {%- endif -%} + {%- endif -%} + {%- if settings.weight != blank -%} + --font-weight: {{ settings.weight }}; + {% else %} + --font-weight: {{ settings.font | replace: 'family', 'weight' }}; + {%- endif -%} + --font-family: {{ settings.font }}; + --text-transform: {{ settings.case }}; + --text-wrap: {{ settings.wrap }}; + {% if settings.type_preset == 'custom' and settings.font_size == blank %} + --line-height--display: var(--line-height--display-{{ settings.line_height }}); + --line-height--heading: var(--line-height--heading-{{ settings.line_height }}); + --line-height--body: var(--line-height--body-{{ settings.line_height }}); + {% else %} + --line-height: var(--line-height--{{ type }}-{{ settings.line_height }}); + {% endif %} + --letter-spacing: var(--letter-spacing--{{ type }}-{{ settings.letter_spacing }}); + {%- endif -%} +{%- endcapture -%} +{{- variables | strip | strip_newlines -}} diff --git a/snippets/unit-price.liquid b/snippets/unit-price.liquid new file mode 100644 index 000000000..6d9ba4d59 --- /dev/null +++ b/snippets/unit-price.liquid @@ -0,0 +1,16 @@ +{%- doc -%} + Renders the unit price, including its measurement. + + @param {object} price - The unit price (money or string). + @param {object} measurement - The unit_price_measurement object. + + @example + {% render 'unit-price', price: variant.unit_price, measurement: variant.unit_price_measurement %} + + @example + {% render 'unit-price', price: line_item.unit_price | money_with_currency, measurement: line_item.unit_price_measurement } +{%- enddoc -%} + + {{ 'accessibility.unit_price' | t }} + {{ price | unit_price_with_measurement: measurement }} + diff --git a/snippets/util-autofill-img-size-attr.liquid b/snippets/util-autofill-img-size-attr.liquid new file mode 100644 index 000000000..79dbf1e40 --- /dev/null +++ b/snippets/util-autofill-img-size-attr.liquid @@ -0,0 +1,75 @@ +{%- doc -%} + Echo a sizes attribute for an tag based on a minimum image size. + + @param {number} card_size - The minimum pixel-width of the product card. + @param {number} [card_gap] - The pixel-width of the gap between product cards. + @param {number} [max_breakpoint] - The maximum pixel-width to calculate breakpoints for. + @param {number} [min_breakpoint] - The minimum pixel-width before defaulting to 50vw. + + @example + {% capture size_attribute %} + {% render 'util-autofill-img-size-attr' card_size: 400 %} + {% endcapture %} + {% assign size_attribute = size_attribute | strip %} + {{ image_url | image_tag: sizes: size_attribute }} +{%- enddoc -%} + +{% liquid + # Defense: ensure card_size and card_gap are numbers + assign card_size = card_size | strip | replace: 'px', '' | plus: 0 + + if card_gap + assign card_gap = card_gap | strip | replace: 'px', '' | plus: 0 + else + assign card_gap = 0 + endif + + assign card_size_with_gap = card_size | plus: card_gap + + assign max_breakpoint = max_breakpoint | default: 2000 + + assign min_breakpoint = min_breakpoint | default: 750 + + # Calculate maximum number of columns at max width + assign max_cols = max_breakpoint | divided_by: card_size_with_gap | floor + + assign sizes_attr = '' + + # Calculate breakpoints dynamically based on card size + # Start with max columns and work down + for i in (1..max_cols) + # Current number of columns we're calculating for + assign current_cols = max_cols | minus: i | plus: 1 + + # Skip if we're down to 1 column + if current_cols < 2 + break + endif + + # Calculate the minimum width needed for this many columns + assign min_width_needed = current_cols | times: card_size_with_gap + + if min_width_needed < min_breakpoint + break + endif + + assign percentage = 100 | divided_by: current_cols + + # Build up the sizes attribute + if sizes_attr != '' + assign sizes_attr = sizes_attr | append: ', ' + endif + assign sizes_attr = sizes_attr | append: '(min-width: ' | append: min_width_needed | append: 'px) ' | append: percentage | append: 'vw' + endfor + + # Add tablet size (50vw) and mobile size (100vw) fallbacks + if sizes_attr != '' + assign sizes_attr = sizes_attr | append: ', ' + endif + assign sizes_attr = sizes_attr | append: '(min-width: ' | append: min_breakpoint | append: 'px) 50vw' + + assign sizes_attr = sizes_attr | append: ', 100vw' + + # Echo the sizes attribute + echo sizes_attr +%} diff --git a/snippets/util-product-grid-card-size.liquid b/snippets/util-product-grid-card-size.liquid new file mode 100644 index 000000000..fdbcd0f42 --- /dev/null +++ b/snippets/util-product-grid-card-size.liquid @@ -0,0 +1,45 @@ +{%- doc -%} + Output the minimum product card size for cards in a product grid (main collection and search results). + + @param {object} section - Section object that contains the product card block. + + @example + {% capture product_card_size %} + {% render 'util-product-grid-card-size' section: section %} + {% endcapture %} +{%- enddoc -%} + +{% liquid + if section.settings.layout_type == 'organic' + if section.settings.product_grid_width == 'centered' + assign product_card_size = '250px' + else + assign product_card_size = '260px' + endif + elsif section.settings.product_grid_width == 'centered' + # Hardcoded values for product card size when width set to 'centered' + case section.settings.product_card_size + when 'small' + assign product_card_size = '165px' + when 'medium' + assign product_card_size = '250px' + when 'large' + assign product_card_size = '340px' + when 'extra-large' + assign product_card_size = '480px' + endcase + else + # Hardcoded values for product card size when width set to 'full-width' + case section.settings.product_card_size + when 'small' + assign product_card_size = '180px' + when 'medium' + assign product_card_size = '260px' + when 'large' + assign product_card_size = '365px' + when 'extra-large' + assign product_card_size = '530px' + endcase + endif + echo product_card_size +%} diff --git a/snippets/util-product-media-sizes-attr.liquid b/snippets/util-product-media-sizes-attr.liquid new file mode 100644 index 000000000..50478898d --- /dev/null +++ b/snippets/util-product-media-sizes-attr.liquid @@ -0,0 +1,141 @@ +{%- doc -%} + Calculate the sizes attribute for product media images in the product media gallery. + + @param {object} block - Block object containing media gallery settings + @param {object} section - Section object containing layout settings + @param {object} settings - Theme settings object containing page width configuration + @param {boolean} [is_first_image] - Whether this is the first image (for large_first_image mode) + @param {boolean} [is_single_column] - Whether the layout is single column (carousel or one-column grid) + @param {boolean} [needs_both_sizes] - Whether we need to calculate different sizes for first and other images + + @example + {% capture media_sizes %} + {% render 'util-product-media-sizes-attr', block: block, section: section, settings: settings, is_single_column: is_single_column %} + {% endcapture %} + {% assign media_sizes = media_sizes | strip %} + {{ media | image_url: width: 800 | image_tag: sizes: media_sizes }} +{%- enddoc -%} + +{%- liquid + # Constants + assign page_margin = '40px' + # Section gap divided by 2 (used for single column layouts) + assign gap_half = section.settings.gap | divided_by: 2 | append: 'px' + # Section gap divided by 4 (used for two column layouts where each column gets half of the half gap) + assign gap_quarter = section.settings.gap | divided_by: 4 | append: 'px' + # Image gap divided by 2 (space between images in grid) + assign image_gap_half = block.settings.image_gap | divided_by: 2 | append: 'px' + + assign is_single_column = is_single_column | default: false + assign needs_both_sizes = needs_both_sizes | default: false + + # Determine which size calculation to use + assign calculate_single_column = false + assign calculate_grid_column = false + + if needs_both_sizes + if is_first_image + assign calculate_single_column = true + else + assign calculate_grid_column = true + endif + elsif is_single_column + assign calculate_single_column = true + else + assign calculate_grid_column = true + endif + + # Set up default sizes + if calculate_single_column + # Default for carousel or single column grid (or first image in large_first_image mode) + if section.settings.equal_columns == false + assign default_sizes = '(min-width: 750px) calc(100vw - 25rem - [gap_half]), 100vw' | replace: '[gap_half]', gap_half + else + assign default_sizes = '(min-width: 750px) calc(50vw - [gap_half]), 100vw' | replace: '[gap_half]', gap_half + endif + else + # Default for two column grid - includes image gap and quarter section gap + if section.settings.equal_columns == false + assign default_sizes = '(min-width: 750px) calc((100vw - 25rem) / 2 - [gap_quarter] - [image_gap_half]), 100vw' | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half + else + assign default_sizes = '(min-width: 750px) calc(50vw / 2 - [gap_quarter] - [image_gap_half]), 100vw' | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half + endif + endif + + # Override for center-aligned content + if section.settings.content_width == 'content-center-aligned' + # Define breakpoints and base sizes based on page width + # Breakpoints are the page width setting + margin (where 2 x margin is 80px = 5rem) + case settings.page_width + when 'narrow' + assign breakpoint = '95rem' + assign media_base_size_equal_columns = '45rem' + assign media_base_size_unequal_columns = '65rem' + when 'normal' + assign breakpoint = '125rem' + assign media_base_size_equal_columns = '60rem' + assign media_base_size_unequal_columns = '95rem' + when 'wide' + assign breakpoint = '155rem' + assign media_base_size_equal_columns = '75rem' + assign media_base_size_unequal_columns = '125rem' + endcase + + # Select the appropriate base size + if section.settings.equal_columns + assign media_base_size = media_base_size_equal_columns + else + assign media_base_size = media_base_size_unequal_columns + endif + + # Calculate large screen size base + if block.settings.extend_media + assign large_size_base = '[media_base_size] + (100vw - [breakpoint])' | replace: '[media_base_size]', media_base_size | replace: '[breakpoint]', breakpoint + else + assign large_size_base = media_base_size + endif + + # Calculate medium screen size + if section.settings.equal_columns + assign medium_base = '50vw' + else + assign medium_base = '100vw - 25rem' + endif + + # Build calculation based on column type + if calculate_grid_column + # Grid column calculation - includes image gap + assign medium_base = '([medium_base]) / 2' | replace: '[medium_base]', medium_base + # Build the complete large size expression + assign large_size_expr = '([large_size_base]) / 2 - [image_gap_half]' | replace: '[large_size_base]', large_size_base | replace: '[image_gap_half]', image_gap_half + assign large_size = 'calc([large_size_expr])' | replace: '[large_size_expr]', large_size_expr + + if block.settings.extend_media + assign medium_size = 'calc([medium_base] - [page_margin] - [gap_quarter] - [image_gap_half] + [page_margin])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half + else + assign medium_size = 'calc([medium_base] - [page_margin] - [gap_quarter] - [image_gap_half])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half + endif + assign sizes = '(min-width: [breakpoint]) [large_size], (min-width: 750px) [medium_size], 100vw' | replace: '[breakpoint]', breakpoint | replace: '[large_size]', large_size | replace: '[medium_size]', medium_size + else + # Single column calculation + if block.settings.extend_media + assign large_size = 'calc([large_size_base])' | replace: '[large_size_base]', large_size_base + else + assign large_size = large_size_base + endif + + if block.settings.extend_media + assign medium_size = 'calc([medium_base] - [page_margin] - [gap_half])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_half]', gap_half + else + assign medium_size = 'calc([medium_base] - [page_margin] - [gap_half] - [page_margin])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_half]', gap_half + endif + assign sizes = '(min-width: [breakpoint]) [large_size], (min-width: 750px) [medium_size], 100vw' | replace: '[breakpoint]', breakpoint | replace: '[large_size]', large_size | replace: '[medium_size]', medium_size + endif + else + # Use default sizes + assign sizes = default_sizes + endif + + # Echo the sizes attribute + echo sizes +-%} diff --git a/snippets/variant-main-picker.liquid b/snippets/variant-main-picker.liquid new file mode 100644 index 000000000..2970e04bf --- /dev/null +++ b/snippets/variant-main-picker.liquid @@ -0,0 +1,477 @@ +{%- doc -%} + Renders a default variant picker, used to display the variant picker in the variants block. + + @param {object} product_resource - The product object. +{%- enddoc -%} + +{% unless product_resource.has_only_default_variant %} + {% liquid + assign button_background_brightness = section.settings.color_scheme.settings.foreground | color_brightness + if button_background_brightness < 105 + assign strikethrough_color_mix = '#000' + else + assign strikethrough_color_mix = '#fff' + endif + %} + +
      + {%- for product_option in product_resource.options_with_values -%} + {%- liquid + assign swatch_count = product_option.values | map: 'swatch' | compact | size + assign variant_style = block.settings.variant_style + + if swatch_count > 0 and block.settings.show_swatches + if block.settings.variant_style == 'dropdown' + assign variant_style = 'swatch_dropdown' + else + assign variant_style = 'swatch' + endif + endif + + if variant_style == 'buttons' and settings.variant_button_width == 'equal-width-buttons' + assign fieldset_id = section.id | append: '-' | append: product_resource.id | append: '-' | append: product_option.name | handleize + assign option_id_attribute = 'data-option-id="' | append: fieldset_id | append: '"' + assign longest_value = 0 + endif + -%} + + {%- if variant_style == 'swatch' or block.settings.variant_style == 'buttons' -%} +
      + + {{ product_option.name | escape -}} + {%- if variant_style == 'swatch' -%} + {{ product_option.selected_value }} + {%- endif %} + + {%- for product_option_value in product_option.values -%} + {% if product_option_value.size > longest_value and option_id_attribute %} + {% assign longest_value = product_option_value.size %} + {% endif %} + + {%- endfor -%} + {% if option_id_attribute %} + {% style %} + [data-option-id="{{ fieldset_id }}"] { + --variant-ch: {{ longest_value }}ch; + } + {% endstyle %} + {% endif %} +
      + {%- elsif block.settings.variant_style == 'dropdowns' -%} + {% + # There is an opportunity to build a custom select component that will allow us to style the select element further (animation for dropdown, swatches shown in the dropdown options, etc) + # It's too bad as it mean rebuilding baked in behaviours but I think we've already done that for the locale selectors + # in dawn. So it might mean more time spent in setting it up but worth it for future updates/styling. + %} + {% liquid + assign property_being_updated = false + if settings.variant_swatch_width != settings.variant_swatch_height + assign property_being_updated = true + # (original width / original height) x new height (20px at the moment) = new width + assign new_width = settings.variant_swatch_width | times: 1.0 | divided_by: settings.variant_swatch_height | times: 20 + endif + %} + +
      + +
      + + +
      +
      + {%- endif -%} + {%- endfor -%} + + +
      +
      +{% endunless %} + +{% stylesheet %} + .variant-picker { + width: 100%; + } + + .variant-picker__form { + display: flex; + flex-direction: column; + gap: var(--padding-lg); + width: 100%; + } + + .variant-picker[data-shopify-visual-preview] { + min-width: 300px; + padding-inline-start: max(4px, var(--padding-inline-start)); + } + + .variant-option { + --options-border-radius: var(--variant-picker-button-radius); + --options-border-width: var(--variant-picker-button-border-width); + --variant-option-padding-inline: var(--padding-md); + } + + .variant-option--swatches { + --options-border-radius: var(--variant-picker-swatch-radius); + + width: 100%; + } + + .variant-option--swatches-disabled { + pointer-events: none; + cursor: not-allowed; + } + + .variant-option--swatches > overflow-list { + justify-content: var(--product-swatches-alignment); + + @media (max-width: 749px) { + justify-content: var(--product-swatches-alignment-mobile); + } + } + + .variant-option--buttons { + display: flex; + flex-wrap: wrap; + gap: var(--gap-sm); + margin: 0; + padding: 0; + border: none; + } + + .variant-option--buttons legend { + padding: 0; + margin-block-end: var(--margin-xs); + } + + .variant-option__swatch-value { + padding-inline-start: var(--padding-xs); + color: rgb(var(--color-foreground-rgb) / var(--opacity-70)); + } + + .variant-option__button-label { + --variant-picker-stroke-color: var(--color-variant-border); + + display: flex; + flex: 0 0 calc(3ch + 1.3em); + align-items: center; + position: relative; + padding-block: var(--padding-sm); + padding-inline: var(--padding-lg); + border: var(--style-border-width) solid var(--color-variant-border); + border-radius: var(--options-border-radius); + border-width: var(--options-border-width); + overflow: clip; + justify-content: center; + min-height: calc(3ch + 1.3em); + min-width: fit-content; + white-space: nowrap; + background-color: var(--color-variant-background); + color: var(--color-variant-text); + transition: background-color var(--animation-speed) var(--animation-easing), + border-color var(--animation-speed) var(--animation-easing); + + &:hover { + background-color: var(--color-variant-hover-background); + border-color: var(--color-variant-hover-border); + color: var(--color-variant-hover-text); + } + + @media screen and (min-width: 750px) { + padding: var(--padding-xs) var(--variant-option-padding-inline); + } + } + + .variant-option__button-label__text { + text-align: left; + text-wrap: auto; + } + + .variant-option--equal-width-buttons { + --variant-min-width: clamp(44px, calc(var(--variant-option-padding-inline) * 2 + var(--variant-ch)), 100%); + + display: grid; + grid-template-columns: repeat(auto-fit, minmax(var(--variant-min-width), 1fr)); + + .variant-option__button-label { + min-width: var(--variant-min-width); + } + + .variant-option__button-label__text { + text-align: center; + text-wrap: balance; + } + } + + .variant-option__button-label:has(:focus-visible) { + --variant-picker-stroke-color: var(--color-foreground); + + border-color: var(--color-foreground); + outline: var(--focus-outline-width) solid var(--color-foreground); + outline-offset: var(--focus-outline-offset); + } + + .variant-option__button-label--has-swatch { + padding: 0; + border: none; + display: block; + flex-basis: auto; + min-height: auto; + } + + .variant-option__button-label:has(:checked) { + color: var(--color-selected-variant-text); + background-color: var(--color-selected-variant-background); + border-color: var(--color-selected-variant-border); + transition: background-color var(--animation-speed) var(--animation-easing), + border-color var(--animation-speed) var(--animation-easing); + + &:hover { + background-color: var(--color-selected-variant-hover-background); + border-color: var(--color-selected-variant-hover-border); + color: var(--color-selected-variant-hover-text); + } + } + + .variant-option__button-label:has([data-option-available='false']) { + color: rgb(var(--color-variant-text-rgb) / var(--opacity-60)); + } + + .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover .swatch { + outline: var(--focus-outline-width) solid rgb(var(--color-foreground-rgb) / var(--opacity-35-55)); + outline-offset: var(--focus-outline-offset); + } + + .facets__inputs-list--swatches-grid .variant-option__button-label:has(:focus-visible) .swatch { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + .facets__inputs-list--swatches-grid .variant-option__button-label:has(:focus-visible) { + outline: none; + } + + .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover { + outline: none; + } + + .variant-option__button-label--has-swatch:hover { + outline: var(--focus-outline-width) solid rgb(var(--color-foreground-rgb) / var(--opacity-35-55)); + outline-offset: var(--focus-outline-offset); + } + + .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:has(:checked) { + outline: none; + } + + .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:has(:checked) .swatch { + outline: var(--focus-outline-width) solid var(--color-foreground); + outline-offset: var(--focus-outline-offset); + } + + .variant-option__button-label--has-swatch:has(:checked) { + outline: var(--focus-outline-width) solid var(--color-foreground); + outline-offset: var(--focus-outline-offset); + } + + .variant-option__button-label:has([data-option-available='false']):has(:checked) { + --variant-picker-stroke-color: rgb(var(--color-variant-text-rgb) / var(--opacity-60)); + + background-color: inherit; + color: rgb(var(--color-variant-text-rgb) / var(--opacity-60)); + border-color: var(--color-selected-variant-border); + } + + .variant-option__button-label input, + .variant-option--images input { + /* remove the checkbox from the page flow */ + position: absolute; + + /* set the dimensions to match those of the label */ + inset: 0; + + /* hide it */ + opacity: 0; + margin: 0; + cursor: pointer; + width: 100%; + height: 100%; + } + + .variant-option__button-label svg { + position: absolute; + top: 0; + left: 0; + cursor: pointer; + pointer-events: none; + stroke-width: var(--style-border-width); + stroke: var(--variant-picker-stroke-color); + } + + .variant-option__select-wrapper { + display: flex; + position: relative; + border: var(--style-border-width-inputs) solid var(--color-border); + border-radius: var(--style-border-radius-inputs); + align-items: center; + margin-top: var(--margin-2xs); + overflow: clip; + transition: background-color var(--animation-speed) var(--animation-easing), + border-color var(--animation-speed) var(--animation-easing); + } + + .variant-option__select-wrapper:has(.swatch) { + --variant-picker-swatch-width: 20px; + --variant-picker-swatch-height: 20px; + } + + .variant-option__select-wrapper:hover { + border-color: var(--color-variant-hover-border); + } + + .variant-option__select:focus-visible { + outline: var(--focus-outline-width) solid currentcolor; + outline-offset: var(--focus-outline-offset); + } + + .variant-option__select { + padding-block: var(--padding-md); + padding-inline: var(--padding-lg) calc(var(--padding-lg) + var(--icon-size-2xs)); + appearance: none; + border: 0; + width: 100%; + margin: 0; + cursor: pointer; + } + + .variant-option__select-wrapper .icon { + position: absolute; + right: var(--padding-md); + top: 50%; + transform: translateY(-50%); + width: var(--icon-size-2xs); + height: var(--icon-size-2xs); + pointer-events: none; + } + + .variant-option__select--has-swatch { + padding-inline-start: calc((2 * var(--padding-sm)) + var(--variant-picker-swatch-width)); + } + + .variant-option__select-wrapper .swatch { + position: absolute; + top: 50%; + left: var(--padding-md); + transform: translateY(-50%); + } + + .variant-picker--center, + .variant-picker--center .variant-option { + text-align: center; + align-items: center; + justify-content: center; + width: 100%; + } + + .variant-picker--right, + .variant-picker--right .variant-option { + text-align: right; + justify-content: right; + } +{% endstylesheet %} diff --git a/snippets/variant-quick-add.liquid b/snippets/variant-quick-add.liquid new file mode 100644 index 000000000..1a368b9bd --- /dev/null +++ b/snippets/variant-quick-add.liquid @@ -0,0 +1,101 @@ +{%- doc -%} + Renders a quick-add variant picker, used to display the variant picker in the quick-add modal. + + @param {object} product_resource - The product object. +{%- enddoc -%} + + + {%- for product_option in product_resource.options_with_values -%} + {%- liquid + assign swatch_count = product_option.values | map: 'swatch' | compact | size + assign variant_style = '' + + if swatch_count > 0 + assign variant_style = 'swatch' + else + assign fieldset_id = section.id | append: '-' | append: product_resource.id | append: '-' | append: product_option.name | handleize + assign option_id_attribute = 'data-option-id="' | append: fieldset_id | append: '"' + assign longest_value = 0 + endif + -%} + +
      + + {{ product_option.name | escape -}} + {%- if variant_style == 'swatch' and product_resource.options_with_values.size > 1 -%} + {{ product_option.selected_value }} + {%- endif %} + + {%- for product_option_value in product_option.values -%} + {% if product_option_value.size > longest_value and option_id_attribute %} + {% assign longest_value = product_option_value.size %} + {% endif %} + + {% liquid + assign featured_media = product_option_value.variant.featured_media + + # If the variant has no featured media, and we have a combined listing product, then fall back to using the + # featured media of the child product that is linked to this option value. + if featured_media == blank and product_option_value.product_url + assign featured_media = product_option_value.variant.product.featured_media + endif + %} + + + {%- endfor -%} + {% if option_id_attribute %} + {% style %} + [data-option-id="{{ fieldset_id }}"] { + --variant-ch: {{ longest_value }}ch; + } + {% endstyle %} + {% endif %} +
      + {%- endfor -%} + + +
      diff --git a/snippets/variant-swatches.liquid b/snippets/variant-swatches.liquid new file mode 100644 index 000000000..1ae7ff2f8 --- /dev/null +++ b/snippets/variant-swatches.liquid @@ -0,0 +1,145 @@ +{%- doc -%} + Renders a swatches variant picker, used within the product-swatches block. + + @param {object} product_resource - The product object, which contains variants and options. + @param {boolean} has_option_selected - Whether an option is already selected. + + @example + {% render 'variant-swatches', product_resource: product %} +{%- enddoc -%} + + +
      + {%- for product_option in product_resource.options_with_values -%} + {%- liquid + assign swatch_count = product_option.values | map: 'swatch' | compact | size + -%} + + {% if swatch_count == 0 %} + {% continue %} + {% endif %} + + {%- liquid + assign product_has_combined_listing = closest.product.options_with_values | map: 'values' | map: 'product_url' | compact | size + + # Only apply our custom logic if nothing is selected (initial page load) + if has_option_selected != true and product_has_combined_listing == 0 + # Logic to determine which swatch should be pre-selected + assign first_image = product_resource.media.first + assign variant_images = product_resource.images | where: 'attached_to_variant?', true + assign swatch_to_preselect = null + if swatch_count == 1 + # Single swatch: Always pre-select it + assign swatch_to_preselect = product_option.values.first + elsif swatch_count > 1 + if first_image and variant_images contains first_image + # First image is a variant image - find which variant it belongs to + for option_value in product_option.values + if option_value.variant.featured_media.id == first_image.id + assign swatch_to_preselect = option_value + break + endif + endfor + elsif variant_images.size == 0 + # No variants have images - pre-select first swatch + assign swatch_to_preselect = product_option.values.first + else + assign none_checked = true + endif + # else: First image is NOT a variant image - don't pre-select any swatch + endif + endif + + # Identify which option position this swatch option is + # Use product_option.position which is the actual position among ALL options + assign swatch_option_position = product_option.position + assign swatch_option_key = 'option' | append: swatch_option_position + -%} + +
      + {% capture children %} + {%- for product_option_value in product_option.values -%} + {% liquid + assign featured_media = product_option_value.variant.featured_media + + # If the variant has no featured media, and we have a combined listing product, then fall back to using the + # featured media of the child product that is linked to this option value. + if featured_media == blank and product_option_value.product_url + assign featured_media = product_option_value.variant.product.featured_media + endif + + if has_option_selected != true and product_has_combined_listing == 0 + # Determine if this swatch should be checked + assign is_checked = false + if swatch_to_preselect != nil and swatch_to_preselect.id == product_option_value.id + assign is_checked = true + assign none_checked = false + endif + endif + + # Use Liquid filters to check if any variant with this swatch option value is available + # swatch_option_key was set in the parent loop (e.g., 'option1', 'option2', etc.) + assign available_variants = product_resource.variants | where: swatch_option_key, product_option_value | where: 'available', true + assign first_available_variant = available_variants | first + assign available_count = available_variants | size + %} + +
    • + +
    • + {%- endfor -%} +
    • + +
    • + {% endcapture %} + + {% render 'overflow-list', children: children, ref: 'overflowList', defer: true %} +
      + {%- endfor -%} + +
      +
      diff --git a/snippets/video.liquid b/snippets/video.liquid new file mode 100644 index 000000000..ef87051c1 --- /dev/null +++ b/snippets/video.liquid @@ -0,0 +1,215 @@ +{%- doc -%} + Renders a video element, from a video object (