diff --git a/.github/workflow-examples/automatic_deployment_production.yml b/.github/workflow-examples/automatic_deployment_production.yml
index 3565324e91..5f3c18e73d 100644
--- a/.github/workflow-examples/automatic_deployment_production.yml
+++ b/.github/workflow-examples/automatic_deployment_production.yml
@@ -39,6 +39,8 @@ jobs:
#
# You must configure store credentials as secrets on your GitHub repo for automatic deployment via GitHub Actions
+# This defaults to pushing the theme to channel ID 1, which is the default storefront. If you wish to push to an
+# Alternate storefront, use a different channel ID
#
- name: Connect to store
@@ -48,4 +50,4 @@ jobs:
run: stencil init -u $URL -t $TOKEN -p 3000
- name: Push theme live, automatically deleting oldest theme if necessary
- run: stencil push -a -d
+ run: stencil push -a -d -c 1
diff --git a/.github/workflow-examples/poll_for_changed_configuration.yml b/.github/workflow-examples/poll_for_changed_configuration.yml
index 3bba3e3fe6..714d9d69cc 100644
--- a/.github/workflow-examples/poll_for_changed_configuration.yml
+++ b/.github/workflow-examples/poll_for_changed_configuration.yml
@@ -49,8 +49,8 @@ jobs:
TOKEN: ${{ secrets.STENCIL_ACCESS_TOKEN_PRODUCTION }}
run: stencil init -u $URL -t $TOKEN -p 3000
- - name: Check for an updated configuration on the live store
- run: stencil pull
+ - name: Check for an updated configuration on the live default storefront (channel ID 1)
+ run: stencil pull -c 1
- name: Create Pull Request
id: cpr
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 32425b7443..0714295018 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,21 @@
# Changelog
## Draft
+- Fixed displaying swatch name for multiple swatch options on page. [#2040](https://github.com/bigcommerce/cornerstone/pull/2040)
+- Added settings for payment banners. [#2021](https://github.com/bigcommerce/cornerstone/pull/2021)
+- Use https:// for schema markup. [#2039](https://github.com/bigcommerce/cornerstone/pull/2039)
+- Update focus tooltip styles contrast to achieve accessibility AA Complaince. [#2047](https://github.com/bigcommerce/cornerstone/pull/2047)
+- Apple pay button displaying needs to be fixed. [#2043](https://github.com/bigcommerce/cornerstone/pull/2043)
+
+## 5.4.0 (04-26-2021)
+- Incorrect focus order for product carousels. [#2034](https://github.com/bigcommerce/cornerstone/pull/2034)
+- Removed duplicates of main tag.[#2032](https://github.com/bigcommerce/cornerstone/pull/2032)
+- Hamburger Menu Icon missing on Google AMP Pages. [#2022](https://github.com/bigcommerce/cornerstone/pull/2022)
+- Wish List drop down is truncated on product page. [#2001](https://github.com/bigcommerce/cornerstone/pull/2001)
+- Improve performance of analyzing homepage carousel images. [#2027](https://github.com/bigcommerce/cornerstone/pull/2027)
+- Added keyboard support on radio buttons. [#2028](https://github.com/bigcommerce/cornerstone/pull/2028)
+- Replace SSL settings in Page builder with global region for SSL certificate. [#2026](https://github.com/bigcommerce/cornerstone/pull/2026)
+- fixed email address validation in forms. [#2029](https://github.com/bigcommerce/cornerstone/pull/2029)
- Fixed unnecessary horizontal scroll on swatch options on PDP. [#2023](https://github.com/bigcommerce/cornerstone/pull/2023)
- Always showing product counts for Category facet in the faceted search results page. [#2035](https://github.com/bigcommerce/cornerstone/pull/2035)
diff --git a/assets/js/theme/cart.js b/assets/js/theme/cart.js
index 01268687e9..c13b165cae 100644
--- a/assets/js/theme/cart.js
+++ b/assets/js/theme/cart.js
@@ -10,6 +10,7 @@ import CartItemDetails from './common/cart-item-details';
export default class Cart extends PageManager {
onReady() {
this.$modal = null;
+ this.$cartPageContent = $('[data-cart]');
this.$cartContent = $('[data-cart-content]');
this.$cartMessages = $('[data-cart-status]');
this.$cartTotals = $('[data-cart-totals]');
@@ -18,9 +19,16 @@ export default class Cart extends PageManager {
this.$activeCartItemId = null;
this.$activeCartItemBtnAction = null;
+ this.setApplePaySupport();
this.bindEvents();
}
+ setApplePaySupport() {
+ if (window.ApplePaySession) {
+ this.$cartPageContent.addClass('apple-pay-supported');
+ }
+ }
+
cartUpdate($target) {
const itemId = $target.data('cartItemid');
this.$activeCartItemId = itemId;
diff --git a/assets/js/theme/common/aria/radioOptions.js b/assets/js/theme/common/aria/radioOptions.js
index f65eb29827..5a32129994 100644
--- a/assets/js/theme/common/aria/radioOptions.js
+++ b/assets/js/theme/common/aria/radioOptions.js
@@ -9,6 +9,7 @@ const setCheckedRadioItem = (itemCollection, itemIdx) => {
}
$item.attr('aria-checked', true).prop('checked', true).focus();
+ $item.trigger('change');
});
};
@@ -31,21 +32,18 @@ const handleItemKeyDown = itemCollection => e => {
}
switch (keyCode) {
- case ariaKeyCodes.RETURN:
- case ariaKeyCodes.SPACE: {
- setCheckedRadioItem(itemCollection, itemIdx);
- break;
- }
case ariaKeyCodes.LEFT:
case ariaKeyCodes.UP: {
const prevItemIdx = calculateTargetItemPosition(lastCollectionItemIdx, itemIdx - 1);
itemCollection.get(prevItemIdx).focus();
+ setCheckedRadioItem(itemCollection, itemIdx - 1);
break;
}
case ariaKeyCodes.RIGHT:
case ariaKeyCodes.DOWN: {
const nextItemIdx = calculateTargetItemPosition(lastCollectionItemIdx, itemIdx + 1);
itemCollection.get(nextItemIdx).focus();
+ setCheckedRadioItem(itemCollection, itemIdx + 1);
break;
}
diff --git a/assets/js/theme/common/carousel/constants.js b/assets/js/theme/common/carousel/constants.js
new file mode 100644
index 0000000000..9db53bebe6
--- /dev/null
+++ b/assets/js/theme/common/carousel/constants.js
@@ -0,0 +1 @@
+export const FOCUSABLE_ELEMENTS_SELECTOR = '[href], button, input, textarea, select, details, [contenteditable="true"], [tabindex]';
diff --git a/assets/js/theme/common/carousel/index.js b/assets/js/theme/common/carousel/index.js
index 1cdc858699..a687f11035 100644
--- a/assets/js/theme/common/carousel/index.js
+++ b/assets/js/theme/common/carousel/index.js
@@ -2,62 +2,61 @@ import 'slick-carousel';
import {
activatePlayPauseButton,
+ analizeSlides,
arrowAriaLabling,
dotsSetup,
getActiveSlideIdxAndSlidesQuantity,
handleImageAspectRatio,
handleImageLoad,
- setTabindexes,
- tooltipSetup,
+ refreshFocus,
updateTextWithLiveData,
} from './utils';
-/**
- * returns activeSlideIdx and slidesQuantity
- * based on provided carousel settings
- * @param {Object} $slickSettings
- * @returns {Object}
- */
-const extractSlidesDetails = ({
- slideCount, $slides, options: { slidesToShow, slidesToScroll },
-}) => getActiveSlideIdxAndSlidesQuantity(
- slideCount,
- slidesToShow,
- slidesToScroll,
- $slides,
-);
+export const setCarouselState = ({ delegateTarget }, carouselObj) => {
+ const carouselObjCurrent = carouselObj || delegateTarget.slick;
+ const { $slider } = carouselObjCurrent;
+
+ $slider.data('state', getActiveSlideIdxAndSlidesQuantity(carouselObjCurrent));
+};
export const onUserCarouselChange = ({ data }, context, $slider) => {
const $activeSlider = $slider || data;
- const $parentContainer = $activeSlider.hasClass('productView-thumbnails') ? $('.productView-images') : $activeSlider;
- const { activeSlideIdx, slidesQuantity } = extractSlidesDetails($activeSlider[0].slick);
+ const $parentContainer = $activeSlider.hasClass('productView-thumbnails') ? $activeSlider.parent('.productView-images') : $activeSlider;
+ const { activeSlideIdx, slidesQuantity } = $activeSlider.data('state');
const $carouselContentElement = $('[data-carousel-content-change-message]', $parentContainer);
const carouselContentAnnounceMessage = updateTextWithLiveData(context.carouselContentAnnounceMessage, (activeSlideIdx + 1), slidesQuantity);
$carouselContentElement.text(carouselContentAnnounceMessage);
};
-export const onSlickCarouselChange = (e, carousel, context) => {
+export const onSlickCarouselChange = (e, carouselObj, context) => {
const {
$dots,
$slider,
$prevArrow,
$nextArrow,
- } = carousel;
+ options: { infinite },
+ } = carouselObj;
- const { activeSlideIdx, slidesQuantity } = extractSlidesDetails(carousel);
+ const { activeSlideIdx, slidesQuantity } = $slider.data('state') || getActiveSlideIdxAndSlidesQuantity(carouselObj);
dotsSetup($dots, activeSlideIdx, slidesQuantity, context);
- arrowAriaLabling($prevArrow, $nextArrow, activeSlideIdx, slidesQuantity, context.carouselArrowAndDotAriaLabel);
- setTabindexes($slider.find('.slick-slide'));
- tooltipSetup($prevArrow, $nextArrow, $dots);
- activatePlayPauseButton(carousel, slidesQuantity, context);
+ arrowAriaLabling($prevArrow, $nextArrow, activeSlideIdx, slidesQuantity, infinite, context.carouselArrowAndDotAriaLabel);
+ analizeSlides($slider.find('.slick-slide'));
+ refreshFocus($prevArrow, $nextArrow, $dots, $slider, activeSlideIdx, slidesQuantity, infinite);
+
+ $slider.data('state', null);
};
export default function (context) {
$('[data-slick]').each((idx, carousel) => {
// getting element using find to pass jest test
const $carousel = $(document).find(carousel);
+
+ $carousel.on('init breakpoint swipe', setCarouselState);
+ $carousel.on('click', '.slick-arrow, .slick-dots', setCarouselState);
+
+ $carousel.on('init breakpoint', (e, carouselObj) => activatePlayPauseButton(e, carouselObj, context));
$carousel.on('init afterChange', (e, carouselObj) => onSlickCarouselChange(e, carouselObj, context));
$carousel.on('click', '.slick-arrow, .slick-dots', $carousel, e => onUserCarouselChange(e, context));
$carousel.on('swipe', (e, carouselObj) => onUserCarouselChange(e, context, carouselObj.$slider));
@@ -65,7 +64,7 @@ export default function (context) {
if ($carousel.hasClass('heroCarousel')) {
$carousel.on('init afterChange', handleImageLoad);
$carousel.on('swipe', handleImageAspectRatio);
- $carousel.on('click', '.slick-arrow, .slick-dots', $carousel, handleImageAspectRatio);
+ $carousel.on('click', '.slick-arrow, .slick-dots', handleImageAspectRatio);
// Alternative image styling for IE, which doesn't support objectfit
if (typeof document.documentElement.style.objectFit === 'undefined') {
diff --git a/assets/js/theme/common/carousel/utils/activatePlayPauseButton.js b/assets/js/theme/common/carousel/utils/activatePlayPauseButton.js
index 7405369771..71f4d8be5e 100644
--- a/assets/js/theme/common/carousel/utils/activatePlayPauseButton.js
+++ b/assets/js/theme/common/carousel/utils/activatePlayPauseButton.js
@@ -2,18 +2,7 @@ import { throttle } from 'lodash';
const PLAY_ACTION = 'slickPlay';
const PAUSE_ACTION = 'slickPause';
-const IS_ACTIVATED_DATA_ATTR = 'is-activated';
-
-export default (carousel, slidesQuantity, context) => {
- const { $slider, $dots, speed } = carousel;
- const $playPauseButton = $slider.find('[data-play-pause-button]');
-
- if ($playPauseButton.length === 0) return;
-
- $playPauseButton.css('display', slidesQuantity < 2 ? 'none' : 'block');
-
- if ($playPauseButton.data(IS_ACTIVATED_DATA_ATTR)) return;
-
+const updateButtonLabels = (context) => {
const {
carouselPlayPauseButtonPlay,
carouselPlayPauseButtonPause,
@@ -21,30 +10,43 @@ export default (carousel, slidesQuantity, context) => {
carouselPlayPauseButtonAriaPause,
} = context;
- const updateLabels = action => {
- $playPauseButton
+ return ($button, action) => {
+ $button
.text(action === PLAY_ACTION
? carouselPlayPauseButtonPause : carouselPlayPauseButtonPlay)
.attr('aria-label', action === PLAY_ACTION
? carouselPlayPauseButtonAriaPause : carouselPlayPauseButtonAriaPlay);
};
+};
+let updateButtonLabelsWithContext;
- const onPlayPauseClick = () => {
- const action = carousel.paused ? PLAY_ACTION : PAUSE_ACTION;
+export default (e, carouselObj, context) => {
+ const { $slider, $dots, options: { speed } } = carouselObj;
+ const $playPauseButton = $slider.find('[data-play-pause-button]');
- $slider.slick(action);
- updateLabels(action);
- };
+ if ($playPauseButton.length === 0) return;
// for correct carousel controls focus order
if ($dots) {
$playPauseButton.insertBefore($dots);
} else $slider.append($playPauseButton);
- $playPauseButton.on('click', throttle(onPlayPauseClick, speed, { trailing: false }));
- $playPauseButton.data(IS_ACTIVATED_DATA_ATTR, true);
+ const { slidesQuantity } = $slider.data('state');
+ $playPauseButton.css('display', slidesQuantity > 1 ? 'block' : 'none');
- if (carousel.breakpoints.length) {
- $slider.on('breakpoint', () => updateLabels(PLAY_ACTION));
+ if (e.type === 'init') updateButtonLabelsWithContext = updateButtonLabels(context);
+
+ if (e.type === 'breakpoint') {
+ updateButtonLabelsWithContext($playPauseButton, PLAY_ACTION);
+ return;
}
+
+ const onPlayPauseClick = () => {
+ const action = carouselObj.paused ? PLAY_ACTION : PAUSE_ACTION;
+
+ $slider.slick(action);
+ updateButtonLabelsWithContext($playPauseButton, action);
+ };
+
+ $playPauseButton.on('click', throttle(onPlayPauseClick, speed, { trailing: false }));
};
diff --git a/assets/js/theme/common/carousel/utils/setTabindexes.js b/assets/js/theme/common/carousel/utils/analizeSlides.js
similarity index 76%
rename from assets/js/theme/common/carousel/utils/setTabindexes.js
rename to assets/js/theme/common/carousel/utils/analizeSlides.js
index 892b2ca0c4..7b1d38c57d 100644
--- a/assets/js/theme/common/carousel/utils/setTabindexes.js
+++ b/assets/js/theme/common/carousel/utils/analizeSlides.js
@@ -1,4 +1,4 @@
-const FOCUSABLE_ELEMENTS_SELECTOR = '[href], button, input, textarea, select, details, [contenteditable="true"], [tabindex]';
+import { FOCUSABLE_ELEMENTS_SELECTOR } from '../constants';
export default ($slides) => {
$slides.each((idx, slide) => {
diff --git a/assets/js/theme/common/carousel/utils/arrowAriaLabling.js b/assets/js/theme/common/carousel/utils/arrowAriaLabling.js
index 1751262d1d..dc96c2b77a 100644
--- a/assets/js/theme/common/carousel/utils/arrowAriaLabling.js
+++ b/assets/js/theme/common/carousel/utils/arrowAriaLabling.js
@@ -1,6 +1,7 @@
import updateTextWithLiveData from './updateTextWithLiveData';
+import tooltipSetup from './tooltipSetup';
-export default ($prevArrow, $nextArrow, activeSlideIdx, slidesQuantity, ariaLabel) => {
+export default ($prevArrow, $nextArrow, activeSlideIdx, slidesQuantity, isInfinite, ariaLabel) => {
if (slidesQuantity < 2 || !$prevArrow || !$nextArrow) return;
const activeSlideNumber = activeSlideIdx + 1;
@@ -8,10 +9,18 @@ export default ($prevArrow, $nextArrow, activeSlideIdx, slidesQuantity, ariaLabe
const prevSlideNumber = activeSlideIdx === 0 ? slidesQuantity : activeSlideNumber - 1;
const arrowLeftText = updateTextWithLiveData(ariaLabel, prevSlideNumber, slidesQuantity);
- $prevArrow.attr('aria-label', arrowLeftText);
+ $prevArrow.attr({
+ 'aria-label': arrowLeftText,
+ tabindex: !isInfinite && activeSlideIdx === 0 ? -1 : 0,
+ });
+ tooltipSetup($prevArrow);
const nextSlideNumber = activeSlideIdx === slidesQuantity - 1 ? 1 : activeSlideNumber + 1;
const arrowRightText = updateTextWithLiveData(ariaLabel, nextSlideNumber, slidesQuantity);
- $nextArrow.attr('aria-label', arrowRightText);
+ $nextArrow.attr({
+ 'aria-label': arrowRightText,
+ tabindex: !isInfinite && activeSlideIdx === slidesQuantity - 1 ? -1 : 0,
+ });
+ tooltipSetup($nextArrow);
};
diff --git a/assets/js/theme/common/carousel/utils/dotsSetup.js b/assets/js/theme/common/carousel/utils/dotsSetup.js
index 9db5927d7d..109f1847e5 100644
--- a/assets/js/theme/common/carousel/utils/dotsSetup.js
+++ b/assets/js/theme/common/carousel/utils/dotsSetup.js
@@ -1,4 +1,5 @@
import updateTextWithLiveData from './updateTextWithLiveData';
+import tooltipSetup from './tooltipSetup';
export default ($dots, activeSlideIdx, slidesQuantity, { carouselArrowAndDotAriaLabel, carouselActiveDotAriaLabel }) => {
if (!$dots) return;
@@ -14,7 +15,8 @@ export default ($dots, activeSlideIdx, slidesQuantity, { carouselArrowAndDotAria
const dotLabelText = updateTextWithLiveData(carouselArrowAndDotAriaLabel, idx + 1, slidesQuantity);
const dotSlideStatusText = idx === activeSlideIdx ? `, ${carouselActiveDotAriaLabel}` : '';
const dotAriaLabel = `${dotLabelText}${dotSlideStatusText}`;
+ const $dotButton = $(dot).find('[data-carousel-dot]');
- $(dot).find('[data-carousel-dot]').attr('aria-label', dotAriaLabel);
+ tooltipSetup($dotButton.attr('aria-label', dotAriaLabel));
});
};
diff --git a/assets/js/theme/common/carousel/utils/getActiveSlideIdxAndSlidesQuantity.js b/assets/js/theme/common/carousel/utils/getActiveSlideIdxAndSlidesQuantity.js
index 352a82dc80..83f1cccef2 100644
--- a/assets/js/theme/common/carousel/utils/getActiveSlideIdxAndSlidesQuantity.js
+++ b/assets/js/theme/common/carousel/utils/getActiveSlideIdxAndSlidesQuantity.js
@@ -1,4 +1,4 @@
-export default (slideCount, slidesToShow, slidesToScroll, $slides) => {
+export default ({ slideCount, $slides, options: { slidesToShow, slidesToScroll } }) => {
const lastVisibleIdx = $slides.get().reduce((acc, curr, idx) => {
if ($(curr).hasClass('slick-active')) return idx;
return acc;
diff --git a/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js b/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js
index c5b67c770e..3cdf46b7df 100644
--- a/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js
+++ b/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js
@@ -5,16 +5,12 @@ export default ({ $slider }, isAnalyzedDataAttr) => {
if (isAnalyzedSlide) return { isAnalyzedSlide };
const $activeSlideImg = $activeSlide.find('.heroCarousel-image');
-
- const attrsObj = {
- src: $activeSlideImg.attr('src'),
- srcset: $activeSlideImg.attr('srcset'),
- sizes: $activeSlideImg.attr('sizes'),
- };
+ const activeSlideImgNode = $activeSlideImg[0];
return {
- attrsObj,
$slider,
$activeSlide,
+ $activeSlideImg,
+ activeSlideImgNode,
};
};
diff --git a/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js b/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js
index ef163e433e..f10ab2cdd6 100644
--- a/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js
+++ b/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js
@@ -6,7 +6,7 @@ const IMAGE_CLASSES = {
};
const IS_ANALYZED_DATA_ATTR = 'image-ratio-analyzed';
-const defineClass = (imageAspectRatio) => {
+const defineAspectRatioClass = (imageAspectRatio) => {
switch (true) {
case imageAspectRatio > 0.8 && imageAspectRatio <= 1.2:
return IMAGE_CLASSES.square;
@@ -17,13 +17,21 @@ const defineClass = (imageAspectRatio) => {
}
};
-export default ({ delegateTarget }, carousel) => {
+const setAspectRatioClass = (imageNode, $slides) => {
+ if (imageNode.naturalHeight <= 1) return;
+
+ const imageAspectRatio = imageNode.naturalHeight / imageNode.naturalWidth;
+ $slides.each((idx, slide) => $(slide).addClass(defineAspectRatioClass(imageAspectRatio)));
+};
+
+export default ({ delegateTarget }, carouselObj) => {
const {
isAnalyzedSlide,
- attrsObj,
$slider,
$activeSlide,
- } = getActiveSlideInfo(carousel || delegateTarget.slick, IS_ANALYZED_DATA_ATTR);
+ $activeSlideImg,
+ activeSlideImgNode,
+ } = getActiveSlideInfo(carouselObj || delegateTarget.slick, IS_ANALYZED_DATA_ATTR);
if (isAnalyzedSlide) return;
@@ -32,15 +40,12 @@ export default ({ delegateTarget }, carousel) => {
if ($activeSlide.find('.heroCarousel-content').length) return;
- $('')
- .on('load', function getImageSizes() {
- const imageHeight = this.height;
- const imageWidth = this.width;
-
- if (imageHeight < 2 || imageWidth < 2) return;
-
- const imageAspectRatio = imageHeight / imageWidth;
- $activeSlideAndClones.each((idx, slide) => $(slide).addClass(defineClass(imageAspectRatio)));
- })
- .attr(attrsObj);
+ if (activeSlideImgNode.complete) {
+ if (activeSlideImgNode.naturalHeight === 1) {
+ // only base64 image from srcset was loaded
+ $activeSlideImg.on('load', () => setAspectRatioClass(activeSlideImgNode, $activeSlideAndClones));
+ } else if (activeSlideImgNode.naturalHeight > 1) {
+ setAspectRatioClass(activeSlideImgNode, $activeSlideAndClones);
+ }
+ } else $activeSlideImg.on('load', () => setAspectRatioClass(activeSlideImgNode, $activeSlideAndClones));
};
diff --git a/assets/js/theme/common/carousel/utils/handleImageLoad.js b/assets/js/theme/common/carousel/utils/handleImageLoad.js
index 66572db108..9a9f5383a8 100644
--- a/assets/js/theme/common/carousel/utils/handleImageLoad.js
+++ b/assets/js/theme/common/carousel/utils/handleImageLoad.js
@@ -1,20 +1,47 @@
+import { isBrowserIE } from '../../utils/ie-helpers';
import getActiveSlideInfo from './getActiveSlideInfo';
const IMAGE_ERROR_CLASS = 'is-image-error';
const IS_ANALYZED_DATA_ATTR = 'image-load-analyzed';
-export default (e, carousel) => {
+const generateImage = ($slide, $image) => {
+ $('')
+ .on('error', () => $slide.addClass(IMAGE_ERROR_CLASS))
+ .attr('src', $image.attr('src'));
+};
+
+export default (e, carouselObj) => {
const {
isAnalyzedSlide,
- attrsObj,
$activeSlide,
- } = getActiveSlideInfo(carousel, IS_ANALYZED_DATA_ATTR);
+ $activeSlideImg,
+ activeSlideImgNode,
+ } = getActiveSlideInfo(carouselObj, IS_ANALYZED_DATA_ATTR);
if (isAnalyzedSlide) return;
$activeSlide.data(IS_ANALYZED_DATA_ATTR, true);
- $('')
- .on('error', () => $activeSlide.addClass(IMAGE_ERROR_CLASS))
- .attr(attrsObj);
+ if (activeSlideImgNode.complete) {
+ if (activeSlideImgNode.naturalHeight === 0) {
+ $activeSlide.addClass(IMAGE_ERROR_CLASS);
+ } else if (activeSlideImgNode.naturalHeight === 1) {
+ // only base64 image from srcset was loaded
+ $activeSlideImg.on('error', () => $activeSlide.addClass(IMAGE_ERROR_CLASS));
+ }
+
+ return;
+ }
+
+ if (!$activeSlideImg.attr('src')) {
+ $activeSlide.addClass(IMAGE_ERROR_CLASS);
+ return;
+ }
+
+ if (isBrowserIE) {
+ generateImage($activeSlide, $activeSlideImg);
+ return;
+ }
+
+ $activeSlideImg.on('error', () => $activeSlide.addClass(IMAGE_ERROR_CLASS));
};
diff --git a/assets/js/theme/common/carousel/utils/index.js b/assets/js/theme/common/carousel/utils/index.js
index 3e7e2dd0a0..f6ad26c659 100644
--- a/assets/js/theme/common/carousel/utils/index.js
+++ b/assets/js/theme/common/carousel/utils/index.js
@@ -1,9 +1,9 @@
export { default as activatePlayPauseButton } from './activatePlayPauseButton';
+export { default as analizeSlides } from './analizeSlides';
export { default as arrowAriaLabling } from './arrowAriaLabling';
export { default as dotsSetup } from './dotsSetup';
export { default as getActiveSlideIdxAndSlidesQuantity } from './getActiveSlideIdxAndSlidesQuantity';
export { default as handleImageAspectRatio } from './handleImageAspectRatio';
export { default as handleImageLoad } from './handleImageLoad';
-export { default as setTabindexes } from './setTabindexes';
-export { default as tooltipSetup } from './tooltipSetup';
+export { default as refreshFocus } from './refreshFocus';
export { default as updateTextWithLiveData } from './updateTextWithLiveData';
diff --git a/assets/js/theme/common/carousel/utils/refreshFocus.js b/assets/js/theme/common/carousel/utils/refreshFocus.js
new file mode 100644
index 0000000000..dad85f3d56
--- /dev/null
+++ b/assets/js/theme/common/carousel/utils/refreshFocus.js
@@ -0,0 +1,20 @@
+import { FOCUSABLE_ELEMENTS_SELECTOR } from '../constants';
+
+export default ($prevArrow, $nextArrow, $dots, $slider, activeSlideIdx, slidesQuantity, isInfinite) => {
+ if (isInfinite || !$prevArrow || !$nextArrow) return;
+
+ if (activeSlideIdx === 0 && $prevArrow.is(':focus')) {
+ $nextArrow.focus();
+ } else if (activeSlideIdx === slidesQuantity - 1 && $nextArrow.is(':focus')) {
+ if ($dots) {
+ $dots.children().first().find('[data-carousel-dot]').focus();
+ return;
+ }
+
+ const $firstActiveSlide = $slider.find('.slick-active').first();
+
+ if ($firstActiveSlide.is(FOCUSABLE_ELEMENTS_SELECTOR)) {
+ $firstActiveSlide.focus();
+ } else $firstActiveSlide.find(FOCUSABLE_ELEMENTS_SELECTOR).first().focus();
+ }
+};
diff --git a/assets/js/theme/common/carousel/utils/tooltipSetup.js b/assets/js/theme/common/carousel/utils/tooltipSetup.js
index da4af37856..c2a6003ba0 100644
--- a/assets/js/theme/common/carousel/utils/tooltipSetup.js
+++ b/assets/js/theme/common/carousel/utils/tooltipSetup.js
@@ -2,7 +2,7 @@ const TOOLTIP_DATA_SELECTOR = 'data-carousel-tooltip';
const TOOLTIP_CLASS = 'carousel-tooltip';
const TOOLTIP_NODE = ``;
-const setupTooltipAriaLabel = ($node) => {
+export default ($node) => {
const $existedTooltip = $node.find(`[${TOOLTIP_DATA_SELECTOR}]`);
if ($existedTooltip.length) {
$existedTooltip.attr('aria-label', $node.attr('aria-label'));
@@ -11,21 +11,3 @@ const setupTooltipAriaLabel = ($node) => {
$node.append($tooltip);
}
};
-
-const setupArrowTooltips = (...arrowNodes) => {
- arrowNodes.forEach($arrow => setupTooltipAriaLabel($arrow));
-};
-
-const setupDotTooltips = ($dots) => {
- $dots.children().each((idx, dot) => setupTooltipAriaLabel($('[data-carousel-dot]', dot)));
-};
-
-export default ($prevArrow, $nextArrow, $dots) => {
- if ($prevArrow && $nextArrow) {
- setupArrowTooltips($prevArrow, $nextArrow);
- }
-
- if ($dots) {
- setupDotTooltips($dots);
- }
-};
diff --git a/assets/js/theme/common/models/forms.js b/assets/js/theme/common/models/forms.js
index c4870e68dd..ddb7dfc846 100644
--- a/assets/js/theme/common/models/forms.js
+++ b/assets/js/theme/common/models/forms.js
@@ -1,6 +1,6 @@
const forms = {
email(value) {
- const re = /^.+@.+\..+/;
+ const re = /^\S+@\S+\.\S+/;
return re.test(value);
},
diff --git a/assets/js/theme/common/product-details.js b/assets/js/theme/common/product-details.js
index b698f15d77..326767d4e8 100644
--- a/assets/js/theme/common/product-details.js
+++ b/assets/js/theme/common/product-details.js
@@ -18,7 +18,9 @@ export default class ProductDetails extends ProductDetailsBase {
this.imageGallery.init();
this.listenQuantityChange();
this.$swatchOptionMessage = $('.swatch-option-message');
- this.swatchOptionMessageInitText = this.$swatchOptionMessage.text();
+ this.swatchInitMessageStorage = {};
+ this.swatchGroupIdList = $('[id^="swatchGroup"]').map((_, group) => $(group).attr('id'));
+ this.storeInitMessagesForSwatches();
const $form = $('form[data-cart-item-add]', $scope);
const $productOptionsElement = $('[data-product-option-change]', $form);
@@ -43,10 +45,17 @@ export default class ProductDetails extends ProductDetailsBase {
if (context.showSwatchNames) {
this.$swatchOptionMessage.removeClass('u-hidden');
- $productSwatchGroup.on('change', ({ target }) => this.showSwatchNameOnOption($(target)));
+
+ $productSwatchGroup.on('change', ({ target }) => {
+ const swatchGroupElement = target.parentNode.parentNode;
+
+ this.showSwatchNameOnOption($(target), $(swatchGroupElement));
+ });
$.each($productSwatchGroup, (_, element) => {
- if ($(element).is(':checked')) this.showSwatchNameOnOption($(element));
+ const swatchGroupElement = element.parentNode.parentNode;
+
+ if ($(element).is(':checked')) this.showSwatchNameOnOption($(element), $(swatchGroupElement));
});
}
@@ -76,6 +85,16 @@ export default class ProductDetails extends ProductDetailsBase {
this.previewModal = modalFactory('#previewModal')[0];
}
+ storeInitMessagesForSwatches() {
+ if (this.swatchGroupIdList.length && isEmpty(this.swatchInitMessageStorage)) {
+ this.swatchGroupIdList.each((_, swatchGroupId) => {
+ if (!this.swatchInitMessageStorage[swatchGroupId]) {
+ this.swatchInitMessageStorage[swatchGroupId] = $(`#${swatchGroupId} ~ .swatch-option-message`).text().trim();
+ }
+ });
+ }
+ }
+
setProductVariant() {
const unsatisfiedRequiredFields = [];
const options = [];
@@ -218,12 +237,14 @@ export default class ProductDetails extends ProductDetailsBase {
* if this setting is enabled in Page Builder
* show name for swatch option
*/
- showSwatchNameOnOption($swatch) {
+ showSwatchNameOnOption($swatch, $swatchGroup) {
const swatchName = $swatch.attr('aria-label');
+ const activeSwatchGroupId = $swatchGroup.attr('aria-labelledby');
+ const $swatchOptionMessage = $(`#${activeSwatchGroupId} ~ .swatch-option-message`);
- $('[data-product-attribute="swatch"] [data-option-value]').text(swatchName);
- this.$swatchOptionMessage.text(`${this.swatchOptionMessageInitText} ${swatchName}`);
- this.setLiveRegionAttributes(this.$swatchOptionMessage, 'status', 'assertive');
+ $('[data-option-value]', $swatchGroup).text(swatchName);
+ $swatchOptionMessage.text(`${this.swatchInitMessageStorage[activeSwatchGroupId]} ${swatchName}`);
+ this.setLiveRegionAttributes($swatchOptionMessage, 'status', 'assertive');
}
setLiveRegionAttributes($element, roleType, ariaLiveStatus) {
@@ -376,6 +397,10 @@ export default class ProductDetails extends ProductDetailsBase {
if (this.previewModal) {
this.previewModal.open();
+ if (window.ApplePaySession) {
+ this.previewModal.$modal.addClass('apple-pay-supported');
+ }
+
if ($addToCartBtn.parents('.quickView').length === 0) this.previewModal.$preModalFocusedEl = $addToCartBtn;
this.updateCartContent(this.previewModal, response.data.cart_item.id, () => this.previewModal.setupFocusTrap());
} else {
diff --git a/assets/js/theme/common/utils/ie-helpers.js b/assets/js/theme/common/utils/ie-helpers.js
index c65b0c1275..cde421dc48 100644
--- a/assets/js/theme/common/utils/ie-helpers.js
+++ b/assets/js/theme/common/utils/ie-helpers.js
@@ -1,3 +1,3 @@
-export const isBrowserIE = navigator.userAgent.includes('Trident');
+export const isBrowserIE = !!document.documentMode;
export const convertIntoArray = collection => Array.prototype.slice.call(collection);
diff --git a/assets/js/theme/global/cart-preview.js b/assets/js/theme/global/cart-preview.js
index 0fc5138c7d..b5c79f086f 100644
--- a/assets/js/theme/global/cart-preview.js
+++ b/assets/js/theme/global/cart-preview.js
@@ -15,6 +15,10 @@ export default function (secureBaseUrl, cartId) {
const $body = $('body');
+ if (window.ApplePaySession) {
+ $cartDropdown.addClass('apple-pay-supported');
+ }
+
$body.on('cart-quantity-update', (event, quantity) => {
$cart.attr('aria-label', (_, prevValue) => prevValue.replace(/\d+/, quantity));
diff --git a/assets/js/theme/global/quick-view.js b/assets/js/theme/global/quick-view.js
index 85b13bcdd7..907282f1c8 100644
--- a/assets/js/theme/global/quick-view.js
+++ b/assets/js/theme/global/quick-view.js
@@ -4,7 +4,7 @@ import utils from '@bigcommerce/stencil-utils';
import ProductDetails from '../common/product-details';
import { defaultModal } from './modal';
import 'slick-carousel';
-import { onSlickCarouselChange, onUserCarouselChange } from '../common/carousel';
+import { setCarouselState, onSlickCarouselChange, onUserCarouselChange } from '../common/carousel';
export default function (context) {
const modal = defaultModal();
@@ -24,7 +24,10 @@ export default function (context) {
const $carousel = modal.$content.find('[data-slick]');
if ($carousel.length) {
- $carousel.on('init afterChange', (e, carousel) => onSlickCarouselChange(e, carousel, context));
+ $carousel.on('init breakpoint swipe', setCarouselState);
+ $carousel.on('click', '.slick-arrow, .slick-dots', setCarouselState);
+
+ $carousel.on('init afterChange', (e, carouselObj) => onSlickCarouselChange(e, carouselObj, context));
$carousel.on('click', '.slick-arrow, .slick-dots', $carousel, e => onUserCarouselChange(e, context));
$carousel.on('swipe', (e, carouselObj) => onUserCarouselChange(e, context, carouselObj.$slider));
diff --git a/assets/js/theme/search.js b/assets/js/theme/search.js
index f022231cdb..8467de01e5 100644
--- a/assets/js/theme/search.js
+++ b/assets/js/theme/search.js
@@ -204,9 +204,15 @@ export default class Search extends CatalogPage {
}
});
- setTimeout(() => {
- $('[data-search-aria-message]').removeClass('u-hidden');
- }, 100);
+ const $searchResultsMessage = $(`
${this.context.searchResultsCount}
`)
+ .prependTo('body');
+
+ setTimeout(() => $searchResultsMessage.focus(), 100);
}
loadTreeNodes(node, cb) {
diff --git a/assets/scss/common/_focus-tooltip.scss b/assets/scss/common/_focus-tooltip.scss
index 9d1bd3ccbf..7a7fed7052 100644
--- a/assets/scss/common/_focus-tooltip.scss
+++ b/assets/scss/common/_focus-tooltip.scss
@@ -6,14 +6,14 @@
top: 50%;
border-width: remCalc(10px);
border-style: solid;
- border-color: transparent transparent $adminBar-tooltip-bg-backgroundColor transparent;
+ border-color: transparent transparent $focusTooltip-backgroundColor transparent;
}
&:after {
content: attr($attr);
padding: remCalc(4px) remCalc(6px);
- background-color: $adminBar-tooltip-bg-backgroundColor;
- color: white;
+ background-color: $focusTooltip-backgroundColor;
+ color: $focusTooltip-textColor;
position: absolute;
font-size: 1rem;
white-space: nowrap;
diff --git a/assets/scss/components/stencil/applePay/_applePay.scss b/assets/scss/components/stencil/applePay/_applePay.scss
index dbaf8a4a8c..c931dd0d63 100644
--- a/assets/scss/components/stencil/applePay/_applePay.scss
+++ b/assets/scss/components/stencil/applePay/_applePay.scss
@@ -25,23 +25,14 @@
}
}
-.cart-additionalCheckoutButtons {
- .apple-pay-checkout-button {
- margin-top: spacing("half");
- }
-}
-
.apple-pay-supported {
.apple-pay-checkout-button {
display: block;
float: right;
}
-}
-.previewCartCheckout {
- .apple-pay-checkout-button {
+ & .previewCartCheckout .apple-pay-checkout-button {
display: inline-block;
float: none;
- margin-top: spacing("half");
}
}
diff --git a/assets/scss/components/stencil/cart/_cart.scss b/assets/scss/components/stencil/cart/_cart.scss
index a119cf829b..7bdfebd6ea 100644
--- a/assets/scss/components/stencil/cart/_cart.scss
+++ b/assets/scss/components/stencil/cart/_cart.scss
@@ -43,18 +43,6 @@ $card-preview-zoom-bottom-offset: 6rem;
float: right;
}
}
-
- .CheckoutButton {
- margin-bottom: spacing("base");
-
- &:first-child {
- margin-top: spacing("single");
- }
-
- &:last-child {
- margin-bottom: spacing("single");
- }
- }
}
// Cart layout
@@ -557,7 +545,8 @@ $card-preview-zoom-bottom-offset: 6rem;
.previewCart-additionalCheckoutButtons {
@extend %additionalCheckoutButtons;
- padding-right: 1.5rem;
+ padding-right: spacing('single');
+ padding-bottom: spacing('single');
}
// Cart Preview
@@ -608,7 +597,7 @@ $card-preview-zoom-bottom-offset: 6rem;
}
@include lazy-loaded-padding('productthumb_size');
-
+
&:after {
@include breakpoint("xxsmall") {
padding-bottom: 75%;
diff --git a/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss b/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss
index c109d870eb..10cff12547 100644
--- a/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss
+++ b/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss
@@ -33,6 +33,15 @@
}
}
+ // for IE
+ @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
+ opacity: 0;
+
+ &.slick-initialized {
+ opacity: 1;
+ }
+ }
+
&:not(.slick-initialized) :not(.heroCarousel-slide--first).heroCarousel-slide {
display: none;
}
diff --git a/assets/scss/components/stencil/previewCart/_previewCart.scss b/assets/scss/components/stencil/previewCart/_previewCart.scss
index e8967df692..52bb04ca2d 100644
--- a/assets/scss/components/stencil/previewCart/_previewCart.scss
+++ b/assets/scss/components/stencil/previewCart/_previewCart.scss
@@ -56,10 +56,13 @@
width: 100%;
// scss-lint:disable NestingDepth
- + .button,
+ p {
margin-top: spacing("half");
}
+
+ &:not(:last-child) {
+ margin-bottom: spacing("half");
+ }
}
}
diff --git a/assets/scss/components/stencil/productView/_productView.scss b/assets/scss/components/stencil/productView/_productView.scss
index ac5ffe9293..1d51469e38 100644
--- a/assets/scss/components/stencil/productView/_productView.scss
+++ b/assets/scss/components/stencil/productView/_productView.scss
@@ -119,17 +119,9 @@
// Details
// -----------------------------------------------------------------------------
-//
-// 1. for Androind Chrome and IE with zoom horizontal scroll fix
-//
-// -----------------------------------------------------------------------------
.productView-details {
padding-bottom: spacing("single") + spacing("third");
-
- &.product-options {
- overflow: hidden; // 1
- }
}
diff --git a/assets/scss/settings/global/color/_color.scss b/assets/scss/settings/global/color/_color.scss
index ae4dfaed6e..0269c3a4d9 100644
--- a/assets/scss/settings/global/color/_color.scss
+++ b/assets/scss/settings/global/color/_color.scss
@@ -67,3 +67,9 @@ $color-textSecondary-active: stencilColor("color-textSecondary--active");
$color-textLink: stencilColor("color-textLink");
$color-textLink-hover: stencilColor("color-textLink--hover");
$color-textLink-active: stencilColor("color-textLink--active");
+
+
+// Tooltips
+// -----------------------------------------------------------------------------
+$focusTooltip-textColor: stencilColor("focusTooltip-textColor");
+$focusTooltip-backgroundColor: stencilColor("focusTooltip-backgroundColor");
\ No newline at end of file
diff --git a/config.json b/config.json
index b7771ee1b9..91114bc4eb 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,6 @@
{
"name": "Cornerstone",
- "version": "5.3.0",
+ "version": "5.4.0",
"template_engine": "handlebars_v4",
"meta": {
"price": 0,
@@ -309,12 +309,12 @@
"color_badge_product_sold_out_badges": "#007dc6",
"color_text_product_sold_out_badges": "#ffffff",
"color_hover_product_sold_out_badges": "#000000",
+ "focusTooltip-textColor": "#ffffff",
+ "focusTooltip-backgroundColor": "#313440",
"restrict_to_login": false,
"swatch_option_size": "22x22",
"social_icon_placement_top": false,
"social_icon_placement_bottom": "bottom_none",
- "geotrust_ssl_common_name": "",
- "geotrust_ssl_seal_size": "M",
"navigation_design": "simple",
"price_ranges": true,
"pdp-price-label": "",
@@ -331,6 +331,13 @@
"paymentbuttons-paypal-label": "checkout",
"paymentbuttons-paypal-tagline": false,
"paymentbuttons-paypal-fundingicons": false,
+ "paymentbanners-homepage-color": "white",
+ "paymentbanners-homepage-ratio": "8x1",
+ "paymentbanners-cartpage-text-color": "black",
+ "paymentbanners-cartpage-logo-position": "left",
+ "paymentbanners-cartpage-logo-type": "primary",
+ "paymentbanners-proddetailspage-color": "white",
+ "paymentbanners-proddetailspage-ratio": "8x1",
"supported_card_type_icons": [
"american_express",
"diners",
@@ -595,7 +602,9 @@
"color_hover_product_sale_badges": "#000000",
"color_badge_product_sold_out_badges": "#007dc6",
"color_text_product_sold_out_badges": "#ffffff",
- "color_hover_product_sold_out_badges": "#000000"
+ "color_hover_product_sold_out_badges": "#000000",
+ "focusTooltip-textColor": "#666666",
+ "focusTooltip-backgroundColor": "#ffffff"
}
},
{
@@ -803,7 +812,9 @@
"color_hover_product_sale_badges": "#000000",
"color_badge_product_sold_out_badges": "#007dc6",
"color_text_product_sold_out_badges": "#ffffff",
- "color_hover_product_sold_out_badges": "#000000"
+ "color_hover_product_sold_out_badges": "#000000",
+ "focusTooltip-textColor": "#ffffff",
+ "focusTooltip-backgroundColor": "#313440"
}
}
]
diff --git a/package-lock.json b/package-lock.json
index 065e83913b..a6346d3754 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "bigcommerce-cornerstone",
- "version": "5.2.0",
+ "version": "5.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index be74cbe6a5..9a98ed8724 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "bigcommerce-cornerstone",
"description": "The BigCommerce reference theme for the Stencil platform",
- "version": "5.3.0",
+ "version": "5.4.0",
"private": true,
"author": "BigCommerce",
"license": "MIT",
diff --git a/schema.json b/schema.json
index 60005a5e44..018499e13c 100644
--- a/schema.json
+++ b/schema.json
@@ -938,36 +938,6 @@
"label": "i18n.ShowKlarna",
"force_reload": true,
"id": "show_accept_klarna"
- },
- {
- "type": "heading",
- "content": "i18n.GeoTrustSSL"
- },
- {
- "type": "paragraph",
- "content": "i18n.IfYouvePurchasedAGeoTrust"
- },
- {
- "type": "text",
- "label": "i18n.SSLCommonName",
- "force_reload": true,
- "id": "geotrust_ssl_common_name"
- },
- {
- "type": "select",
- "label": "i18n.SealSize",
- "id": "geotrust_ssl_seal_size",
- "options": [
- {
- "value": "M",
- "label": "i18n.Medium"
- },
- {
- "value": "S",
- "label": "i18n.Small"
- }
- ],
- "force_reload": true
}
]
},
@@ -3062,5 +3032,199 @@
]
}
]
+ },
+ {
+ "name": "i18n.PaymentBanners",
+ "enable": "paymentBanners",
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "i18n.BannersMessaging"
+ },
+ {
+ "type": "heading",
+ "content": "i18n.ProductPageBanner"
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleColor",
+ "id": "paymentbanners-proddetailspage-color",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "blue",
+ "label": "i18n.Blue"
+ },
+ {
+ "value": "black",
+ "label": "i18n.Black"
+ },
+ {
+ "value": "white",
+ "label": "i18n.White"
+ },
+ {
+ "value": "white-no-border",
+ "label": "i18n.White-no-border"
+ },
+ {
+ "value": "gray",
+ "label": "i18n.gray"
+ },
+ {
+ "value": "monochrome",
+ "label": "i18n.monochrome"
+ },
+ {
+ "value": "grayscale",
+ "label": "i18n.grayscale"
+ }
+ ]
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleRatio",
+ "id": "paymentbanners-proddetailspage-ratio",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "8x1",
+ "label": "i18n.8x1"
+ },
+ {
+ "value": "20x1",
+ "label": "i18n.20x1"
+ }
+ ]
+ },
+ {
+ "type": "heading",
+ "content": "i18n.HomePageBanner"
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleColor",
+ "id": "paymentbanners-homepage-color",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "blue",
+ "label": "i18n.Blue"
+ },
+ {
+ "value": "black",
+ "label": "i18n.Black"
+ },
+ {
+ "value": "white",
+ "label": "i18n.White"
+ },
+ {
+ "value": "white-no-border",
+ "label": "i18n.White-no-border"
+ },
+ {
+ "value": "gray",
+ "label": "i18n.gray"
+ },
+ {
+ "value": "monochrome",
+ "label": "i18n.monochrome"
+ },
+ {
+ "value": "grayscale",
+ "label": "i18n.grayscale"
+ }
+ ]
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleRatio",
+ "id": "paymentbanners-homepage-ratio",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "8x1",
+ "label": "i18n.8x1"
+ },
+ {
+ "value": "20x1",
+ "label": "i18n.20x1"
+ }
+ ]
+ },
+ {
+ "type": "heading",
+ "content": "i18n.CartPageBanner"
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerTextStyleColor",
+ "id": "paymentbanners-cartpage-text-color",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "black",
+ "label": "i18n.Black"
+ },
+ {
+ "value": "white",
+ "label": "i18n.White"
+ },
+ {
+ "value": "monochrome",
+ "label": "i18n.monochrome"
+ },
+ {
+ "value": "grayscale",
+ "label": "i18n.grayscale"
+ }
+ ]
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleLogoPosition",
+ "id": "paymentbanners-cartpage-logo-position",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "left",
+ "label": "i18n.left"
+ },
+ {
+ "value": "right",
+ "label": "i18n.right"
+ },
+ {
+ "value": "top",
+ "label": "i18n.top"
+ }
+ ]
+ },
+ {
+ "type": "select",
+ "label": "i18n.BannerStyleLogoType",
+ "id": "paymentbanners-cartpage-logo-type",
+ "force_reload": true,
+ "options": [
+ {
+ "value": "inline",
+ "label": "i18n.inline"
+ },
+ {
+ "value": "primary",
+ "label": "i18n.primary"
+ },
+ {
+ "value": "alternative",
+ "label": "i18n.alternative"
+ },
+ {
+ "value": "none",
+ "label": "i18n.none"
+ }
+ ]
+ }
+ ]
}
]
diff --git a/schemaTranslations.json b/schemaTranslations.json
index 66364f0ba1..fc98a816f1 100644
--- a/schemaTranslations.json
+++ b/schemaTranslations.json
@@ -866,34 +866,6 @@
"uk": "Показати Klarna",
"zh": "显示 Klarna"
},
- "i18n.GeoTrustSSL": {
- "default": "GeoTrust SSL",
- "fr": "SSL GeoTrust",
- "it": "GeoTrust SSL",
- "uk": "GeoTrust SSL",
- "zh": "Geo信任SSL"
- },
- "i18n.IfYouvePurchasedAGeoTrust": {
- "default": "If you've purchased a GeoTrust SSL from BigCommerce, check your BigCommerce Account Dashboard for the correct Common Name to use here.",
- "fr": "Si vous avez acheté un SSL GeoTrust auprès de BigCommerce, consultez le tableau de bord de votre compte BigCommerce pour le nom commun correct à utiliser ici.",
- "it": "Sei hai acquistato un SSL GeoTrust da BigCommerce, verifica sulla Dashboard del tuo Account BigCommerce il corretto Nome Comune da utilizzare qui.",
- "uk": "Якщо ви придбали GeoTrust SSL у BigCommerce, перевірте на панелі керування облікового запису BigCommerce правильну загальну назву, яку тут можна використовувати.",
- "zh": "如果您有在Bigcommerce中购买Geo信任SSL,检查您的Bigcommerce账户的控制面板,获得在这里使用的正确的公共名称。"
- },
- "i18n.SSLCommonName": {
- "default": "SSL Common Name",
- "fr": "Nom commun du SSL",
- "it": "Nome Comune SSL",
- "uk": "Загальна назва SSL",
- "zh": "SSL公共名称"
- },
- "i18n.SealSize": {
- "default": "Seal size",
- "fr": "Taille du sceau",
- "it": "Dimensioni sigillo",
- "uk": "Розмір печатки",
- "zh": "标志尺寸"
- },
"i18n.Medium": {
"default": "Medium",
"fr": "Moyen",
@@ -2047,5 +2019,74 @@
},
"i18n.CheckoutPayPalButton": {
"default": "Checkout PayPal Button"
+ },
+ "i18n.ProductPageBanner": {
+ "default": "Product page banner"
+ },
+ "i18n.BannerStyleColor": {
+ "default": "Banner style color"
+ },
+ "i18n.White-no-border": {
+ "default": "White no border"
+ },
+ "i18n.gray": {
+ "default": "Gray"
+ },
+ "i18n.monochrome": {
+ "default": "Monochrome"
+ },
+ "i18n.grayscale": {
+ "default": "Grayscale"
+ },
+ "i18n.BannerStyleRatio": {
+ "default": "Banner style ratio"
+ },
+ "i18n.8x1": {
+ "default": "8x1"
+ },
+ "i18n.20x1": {
+ "default": "20x1"
+ },
+ "i18n.HomePageBanner": {
+ "default": "Home page banner"
+ },
+ "i18n.BannerTextStyleColor": {
+ "default": "Banner text style color"
+ },
+ "i18n.BannerStyleLogoPosition": {
+ "default": "Banner style logo position"
+ },
+ "i18n.left": {
+ "default": "Left"
+ },
+ "i18n.right": {
+ "default": "Right"
+ },
+ "i18n.top": {
+ "default": "Top"
+ },
+ "i18n.BannerStyleLogoType": {
+ "default": "Banner style logo type"
+ },
+ "i18n.inline": {
+ "default": "Inline"
+ },
+ "i18n.alternative": {
+ "default": "Alternative"
+ },
+ "i18n.none": {
+ "default": "None"
+ },
+ "i18n.PaymentBanners": {
+ "default": "Payment Banners"
+ },
+ "i18n.CartPageBanner": {
+ "default": "Cart page banner"
+ },
+ "i18n.primary": {
+ "default": "Primary"
+ },
+ "i18n.BannersMessaging": {
+ "default": "Please note that in order for the changes to apply, you need navigate to the PayPal Settings in BC Control Panel, disable an appropriate messaging banner(s), click \"Save\" button, enable the banner again and click \"Save\" button again"
}
}
diff --git a/templates/components/amp/css/header.html b/templates/components/amp/css/header.html
index b68c06ad5e..804a448426 100644
--- a/templates/components/amp/css/header.html
+++ b/templates/components/amp/css/header.html
@@ -1,6 +1,6 @@
.amp-menu-button {
background-color: transparent;
- background-image: url('data:image/svg+xml;utf8,');
+ background-image: url('data:image/svg+xml;utf8,');
background-repeat: no-repeat;
background-size: 2rem 1.8rem;
background-position: center center;
diff --git a/templates/components/amp/products/product-view-details.html b/templates/components/amp/products/product-view-details.html
index 1a9cf6956e..3330cbb7e6 100644
--- a/templates/components/amp/products/product-view-details.html
+++ b/templates/components/amp/products/product-view-details.html
@@ -2,7 +2,7 @@
{{product.title}}
{{#if product.brand }}
-
+
{{/if}}
diff --git a/templates/components/amp/products/reviews.html b/templates/components/amp/products/reviews.html
index 253e534592..a170886893 100644
--- a/templates/components/amp/products/reviews.html
+++ b/templates/components/amp/products/reviews.html
@@ -7,9 +7,9 @@
{{#each reviews.list}}
-
-
+
-
+
{{> components/amp/products/ratings rating=rating}}
{{ rating }}
diff --git a/templates/components/common/body.html b/templates/components/common/body.html
index 37249490b2..a292afad97 100644
--- a/templates/components/common/body.html
+++ b/templates/components/common/body.html
@@ -1,4 +1,4 @@
-
+
{{#block "hero"}} {{/block}}
+ {{{region name="ssl_site_seal--global"}}}
diff --git a/templates/components/products/options/swatch.html b/templates/components/products/options/swatch.html
index d3a5fb0a4e..8470a42f97 100644
--- a/templates/components/products/options/swatch.html
+++ b/templates/components/products/options/swatch.html
@@ -1,5 +1,5 @@
-