@magento/venia-pwa-live-search 1.0.0-alpha6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -0
- package/postcss.config.js +3 -0
- package/src/api/fragments.js +193 -0
- package/src/api/graphql.js +26 -0
- package/src/api/mutations.js +94 -0
- package/src/api/queries.js +225 -0
- package/src/api/search.js +222 -0
- package/src/components/AddToCartButton/AddToCartButton.jsx +32 -0
- package/src/components/AddToCartButton/AddToCartButton.stories.mdx +14 -0
- package/src/components/AddToCartButton/index.js +10 -0
- package/src/components/Alert/Alert.jsx +155 -0
- package/src/components/Alert/index.js +11 -0
- package/src/components/Breadcrumbs/Breadcrumbs.jsx +34 -0
- package/src/components/Breadcrumbs/MockPages.js +14 -0
- package/src/components/Breadcrumbs/index.js +11 -0
- package/src/components/ButtonShimmer/ButtonShimmer.css +32 -0
- package/src/components/ButtonShimmer/ButtonShimmer.jsx +23 -0
- package/src/components/ButtonShimmer/index.js +11 -0
- package/src/components/CategoryFilters/CategoryFilters.jsx +59 -0
- package/src/components/CategoryFilters/index.js +10 -0
- package/src/components/Facets/Facets.jsx +50 -0
- package/src/components/Facets/Range/RangeFacet.js +20 -0
- package/src/components/Facets/Scalar/ScalarFacet.js +29 -0
- package/src/components/Facets/SelectedFilters.js +80 -0
- package/src/components/Facets/format.js +52 -0
- package/src/components/Facets/index.js +14 -0
- package/src/components/Facets/mocks.js +119 -0
- package/src/components/FacetsShimmer/FacetsShimmer.css +49 -0
- package/src/components/FacetsShimmer/FacetsShimmer.jsx +25 -0
- package/src/components/FacetsShimmer/index.js +11 -0
- package/src/components/FilterButton/FilterButton.jsx +40 -0
- package/src/components/FilterButton/index.js +11 -0
- package/src/components/ImageCarousel/Image.jsx +34 -0
- package/src/components/ImageCarousel/ImageCarousel.jsx +103 -0
- package/src/components/ImageCarousel/index.js +11 -0
- package/src/components/InputButtonGroup/InputButtonGroup.jsx +120 -0
- package/src/components/InputButtonGroup/index.js +11 -0
- package/src/components/LabelledInput/LabelledInput.jsx +51 -0
- package/src/components/LabelledInput/index.js +11 -0
- package/src/components/Loading/Loading.jsx +32 -0
- package/src/components/Loading/index.js +11 -0
- package/src/components/NoResults/NoResults.jsx +55 -0
- package/src/components/NoResults/index.js +11 -0
- package/src/components/Pagination/Pagination.jsx +105 -0
- package/src/components/Pagination/index.js +10 -0
- package/src/components/PerPagePicker/PerPagePicker.jsx +114 -0
- package/src/components/PerPagePicker/index.js +11 -0
- package/src/components/Pill/Pill.jsx +34 -0
- package/src/components/Pill/index.js +11 -0
- package/src/components/Pill/mock.js +23 -0
- package/src/components/ProductCardShimmer/ProductCardShimmer.css +72 -0
- package/src/components/ProductCardShimmer/ProductCardShimmer.jsx +28 -0
- package/src/components/ProductCardShimmer/index.js +11 -0
- package/src/components/ProductItem/MockData.js +508 -0
- package/src/components/ProductItem/ProductItem.css +84 -0
- package/src/components/ProductItem/ProductItem.jsx +347 -0
- package/src/components/ProductItem/ProductPrice.jsx +181 -0
- package/src/components/ProductItem/index.js +11 -0
- package/src/components/ProductList/MockData.js +190 -0
- package/src/components/ProductList/ProductList.jsx +127 -0
- package/src/components/ProductList/index.js +11 -0
- package/src/components/ProductList/product-list.css +18 -0
- package/src/components/SearchBar/SearchBar.jsx +33 -0
- package/src/components/SearchBar/index.js +11 -0
- package/src/components/Shimmer/Shimmer.css +82 -0
- package/src/components/Shimmer/Shimmer.jsx +66 -0
- package/src/components/Shimmer/index.js +11 -0
- package/src/components/Slider/Slider.css +61 -0
- package/src/components/Slider/Slider.jsx +103 -0
- package/src/components/Slider/index.jsx +11 -0
- package/src/components/SliderDoubleControl/SliderDoubleControl.css +83 -0
- package/src/components/SliderDoubleControl/SliderDoubleControl.jsx +220 -0
- package/src/components/SliderDoubleControl/index.js +11 -0
- package/src/components/SortDropdown/SortDropdown.jsx +126 -0
- package/src/components/SortDropdown/index.js +11 -0
- package/src/components/SwatchButton/SwatchButton.jsx +72 -0
- package/src/components/SwatchButton/index.js +11 -0
- package/src/components/SwatchButtonGroup/SwatchButtonGroup.jsx +86 -0
- package/src/components/SwatchButtonGroup/index.js +11 -0
- package/src/components/ViewSwitcher/ViewSwitcher.jsx +46 -0
- package/src/components/ViewSwitcher/index.js +11 -0
- package/src/components/WishlistButton/WishlistButton.jsx +67 -0
- package/src/components/WishlistButton/index.js +11 -0
- package/src/containers/App.jsx +145 -0
- package/src/containers/LiveSearchPLPLoader.jsx +24 -0
- package/src/containers/LiveSearchPopoverLoader.jsx +190 -0
- package/src/containers/LiveSearchSRLPLoader.jsx +24 -0
- package/src/containers/ProductListingPage.jsx +66 -0
- package/src/containers/ProductsContainer.jsx +145 -0
- package/src/containers/ProductsHeader.jsx +123 -0
- package/src/context/attributeMetadata.js +63 -0
- package/src/context/cart.js +97 -0
- package/src/context/displayChange.js +90 -0
- package/src/context/events.js +160 -0
- package/src/context/index.js +19 -0
- package/src/context/products.jsx +336 -0
- package/src/context/resultsModifierContext.js +35 -0
- package/src/context/search.jsx +127 -0
- package/src/context/store.jsx +93 -0
- package/src/context/translation.jsx +125 -0
- package/src/context/widgetConfig.jsx +120 -0
- package/src/context/wishlist.jsx +97 -0
- package/src/hooks/eventing/useEventListener.js +13 -0
- package/src/hooks/eventing/useLocation.js +21 -0
- package/src/hooks/eventing/useMagentoExtensionContext.js +28 -0
- package/src/hooks/eventing/usePageView.js +36 -0
- package/src/hooks/eventing/useShopperContext.js +33 -0
- package/src/hooks/eventing/useStorefrontInstanceContext.js +46 -0
- package/src/hooks/eventing/useViewedOffsets.js +74 -0
- package/src/hooks/useAccessibleDropdown.js +148 -0
- package/src/hooks/useLiveSearchPLPConfig.js +112 -0
- package/src/hooks/useLiveSearchPopoverConfig.js +83 -0
- package/src/hooks/useLiveSearchSRLPConfig.js +97 -0
- package/src/hooks/usePagination.js +83 -0
- package/src/hooks/useRangeFacet.js +62 -0
- package/src/hooks/useScalarFacet.js +61 -0
- package/src/hooks/useSliderFacet.js +43 -0
- package/src/i18n/Sorani.js +60 -0
- package/src/i18n/ar_AE.js +60 -0
- package/src/i18n/bg_BG.js +60 -0
- package/src/i18n/bn_IN.js +60 -0
- package/src/i18n/ca_ES.js +60 -0
- package/src/i18n/cs_CZ.js +60 -0
- package/src/i18n/da_DK.js +60 -0
- package/src/i18n/de_DE.js +60 -0
- package/src/i18n/el_GR.js +60 -0
- package/src/i18n/en_GA.js +60 -0
- package/src/i18n/en_GB.js +60 -0
- package/src/i18n/en_US.js +70 -0
- package/src/i18n/es_ES.js +60 -0
- package/src/i18n/et_EE.js +60 -0
- package/src/i18n/eu_ES.js +60 -0
- package/src/i18n/fa_IR.js +60 -0
- package/src/i18n/fi_FI.js +60 -0
- package/src/i18n/fr_FR.js +60 -0
- package/src/i18n/gl_ES.js +60 -0
- package/src/i18n/hi_IN.js +60 -0
- package/src/i18n/hu_HU.js +60 -0
- package/src/i18n/hy_AM.js +60 -0
- package/src/i18n/id_ID.js +60 -0
- package/src/i18n/index.js +89 -0
- package/src/i18n/it_IT.js +60 -0
- package/src/i18n/ja_JP.js +60 -0
- package/src/i18n/ko_KR.js +60 -0
- package/src/i18n/lt_LT.js +60 -0
- package/src/i18n/lv_LV.js +60 -0
- package/src/i18n/nb_NO.js +60 -0
- package/src/i18n/nl_NL.js +60 -0
- package/src/i18n/pt_BR.js +60 -0
- package/src/i18n/pt_PT.js +60 -0
- package/src/i18n/ro_RO.js +60 -0
- package/src/i18n/ru_RU.js +60 -0
- package/src/i18n/sv_SE.js +60 -0
- package/src/i18n/th_TH.js +60 -0
- package/src/i18n/tr_TR.js +60 -0
- package/src/i18n/zh_Hans_CN.js +60 -0
- package/src/i18n/zh_Hant_TW.js +60 -0
- package/src/icons/NoImage.svg +1 -0
- package/src/icons/adjustments.svg +3 -0
- package/src/icons/cart.svg +3 -0
- package/src/icons/checkmark.svg +3 -0
- package/src/icons/chevron.svg +3 -0
- package/src/icons/emptyHeart.svg +3 -0
- package/src/icons/error.svg +3 -0
- package/src/icons/filledHeart.svg +3 -0
- package/src/icons/filter.svg +29 -0
- package/src/icons/gridView.svg +11 -0
- package/src/icons/info.svg +3 -0
- package/src/icons/listView.svg +5 -0
- package/src/icons/loading.svg +6 -0
- package/src/icons/plus.svg +4 -0
- package/src/icons/sort.svg +18 -0
- package/src/icons/warning.svg +3 -0
- package/src/icons/x.svg +3 -0
- package/src/index.jsx +65 -0
- package/src/queries/customerGroupCode.gql.js +10 -0
- package/src/queries/eventing/getMagentoExtensionContext.gql.js +13 -0
- package/src/queries/eventing/getPageType.gql.js +14 -0
- package/src/queries/eventing/getStorefrontContext.gql.js +27 -0
- package/src/queries/index.js +3 -0
- package/src/queries/liveSearchPlpConfigs.gql.js +30 -0
- package/src/queries/liveSearchPopoverConfigs.gql.js +28 -0
- package/src/styles/autocomplete.module.css +56 -0
- package/src/styles/index.css +1638 -0
- package/src/styles/searchBar.module.css +119 -0
- package/src/styles/tokens.css +99 -0
- package/src/targets/intercept.js +21 -0
- package/src/utils/constants.js +26 -0
- package/src/utils/decodeHtmlString.js +13 -0
- package/src/utils/dom.js +14 -0
- package/src/utils/eventing/getCookie.js +9 -0
- package/src/utils/eventing/usePageTypeFromUrl.js +26 -0
- package/src/utils/getProductImage.js +94 -0
- package/src/utils/getProductPrice.js +83 -0
- package/src/utils/getUserViewHistory.js +27 -0
- package/src/utils/handleUrlFilters.js +164 -0
- package/src/utils/htmlStringDecode.js +13 -0
- package/src/utils/modifyResults.js +164 -0
- package/src/utils/sort.js +95 -0
- package/src/utils/useIntersectionObserver.js +27 -0
- package/src/utils/validateStoreDetails.js +39 -0
- package/src/wrappers/wrapUseApp.js +28 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React from 'react';
|
|
11
|
+
|
|
12
|
+
import { useStore } from '../../context';
|
|
13
|
+
import RangeFacet from './Range/RangeFacet';
|
|
14
|
+
import ScalarFacet from './Scalar/ScalarFacet';
|
|
15
|
+
import SliderDoubleControl from '../SliderDoubleControl';
|
|
16
|
+
|
|
17
|
+
export const Facets = ({ searchFacets }) => {
|
|
18
|
+
const {
|
|
19
|
+
config: { priceSlider },
|
|
20
|
+
} = useStore();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="ds-plp-facets flex flex-col">
|
|
24
|
+
<form className="ds-plp-facets__list border-t border-gray-200">
|
|
25
|
+
{searchFacets?.map((facet) => {
|
|
26
|
+
const bucketType = facet?.buckets[0]?.__typename;
|
|
27
|
+
switch (bucketType) {
|
|
28
|
+
case 'ScalarBucket':
|
|
29
|
+
return <ScalarFacet key={facet.attribute} filterData={facet} />;
|
|
30
|
+
case 'RangeBucket':
|
|
31
|
+
return priceSlider ? (
|
|
32
|
+
<SliderDoubleControl filterData={facet} />
|
|
33
|
+
) : (
|
|
34
|
+
<RangeFacet
|
|
35
|
+
key={facet.attribute}
|
|
36
|
+
filterData={facet}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
case 'CategoryView':
|
|
40
|
+
return <ScalarFacet key={facet.attribute} filterData={facet} />;
|
|
41
|
+
default:
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
})}
|
|
45
|
+
</form>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default Facets;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import useRangeFacet from '../../../hooks/useRangeFacet';
|
|
3
|
+
import { InputButtonGroup } from '../../InputButtonGroup';
|
|
4
|
+
|
|
5
|
+
const RangeFacet = ({ filterData }) => {
|
|
6
|
+
const { isSelected, onChange } = useRangeFacet(filterData);
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<InputButtonGroup
|
|
10
|
+
title={filterData.title}
|
|
11
|
+
attribute={filterData.attribute}
|
|
12
|
+
buckets={filterData.buckets}
|
|
13
|
+
type="radio"
|
|
14
|
+
isSelected={isSelected}
|
|
15
|
+
onChange={e => onChange(e.value)}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default RangeFacet;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { InputButtonGroup } from '../../InputButtonGroup';
|
|
12
|
+
import useScalarFacet from '../../../hooks/useScalarFacet';
|
|
13
|
+
|
|
14
|
+
const ScalarFacet = ({ filterData }) => {
|
|
15
|
+
const { isSelected, onChange } = useScalarFacet(filterData);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<InputButtonGroup
|
|
19
|
+
title={filterData.title}
|
|
20
|
+
attribute={filterData.attribute}
|
|
21
|
+
buckets={filterData.buckets}
|
|
22
|
+
type="checkbox"
|
|
23
|
+
isSelected={isSelected}
|
|
24
|
+
onChange={args => onChange(args.value, args.selected)}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default ScalarFacet;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { useSearch, useProducts, useTranslation } from '../../context';
|
|
11
|
+
import Pill from '../Pill';
|
|
12
|
+
import { formatBinaryLabel, formatRangeLabel } from './format';
|
|
13
|
+
|
|
14
|
+
const SelectedFilters = () => {
|
|
15
|
+
const searchCtx = useSearch();
|
|
16
|
+
const productsCtx = useProducts();
|
|
17
|
+
const translation = useTranslation();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="w-full h-full">
|
|
21
|
+
{searchCtx.filters?.length > 0 && (
|
|
22
|
+
<div className="ds-plp-facets__pills pb-6 sm:pb-6 flex flex-wrap mt-8 justify-start">
|
|
23
|
+
{searchCtx.filters.map(filter => (
|
|
24
|
+
<div key={filter.attribute}>
|
|
25
|
+
{filter.in?.map(option => (
|
|
26
|
+
<Pill
|
|
27
|
+
key={formatBinaryLabel(
|
|
28
|
+
filter,
|
|
29
|
+
option,
|
|
30
|
+
searchCtx.categoryNames,
|
|
31
|
+
productsCtx.categoryPath
|
|
32
|
+
)}
|
|
33
|
+
label={formatBinaryLabel(
|
|
34
|
+
filter,
|
|
35
|
+
option,
|
|
36
|
+
searchCtx.categoryNames,
|
|
37
|
+
productsCtx.categoryPath
|
|
38
|
+
)}
|
|
39
|
+
type="transparent"
|
|
40
|
+
onClick={() =>
|
|
41
|
+
searchCtx.updateFilterOptions(
|
|
42
|
+
filter,
|
|
43
|
+
option
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
))}
|
|
48
|
+
{filter.range && (
|
|
49
|
+
<Pill
|
|
50
|
+
label={formatRangeLabel(
|
|
51
|
+
filter,
|
|
52
|
+
productsCtx.currencyRate,
|
|
53
|
+
productsCtx.currencySymbol
|
|
54
|
+
)}
|
|
55
|
+
type="transparent"
|
|
56
|
+
onClick={() => {
|
|
57
|
+
searchCtx.removeFilter(
|
|
58
|
+
filter.attribute
|
|
59
|
+
);
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
))}
|
|
65
|
+
<div className="py-1">
|
|
66
|
+
<button
|
|
67
|
+
className="ds-plp-facets__header__clear-all border-none bg-transparent hover:border-none hover:bg-transparent
|
|
68
|
+
focus:border-none focus:bg-transparent active:border-none active:bg-transparent active:shadow-none text-sm px-4"
|
|
69
|
+
onClick={() => searchCtx.clearFilters()}
|
|
70
|
+
>
|
|
71
|
+
{translation.Filter.clearAll}
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default SelectedFilters;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const formatRangeLabel = (filter, currencyRate = '1', currencySymbol = '$') => {
|
|
11
|
+
const range = filter.range;
|
|
12
|
+
|
|
13
|
+
const rate = currencyRate;
|
|
14
|
+
const symbol = currencySymbol;
|
|
15
|
+
const label = `${symbol}${
|
|
16
|
+
range?.from && parseFloat(rate) * parseInt(range.from.toFixed(0), 10)
|
|
17
|
+
? (
|
|
18
|
+
parseFloat(rate) * parseInt(range.from?.toFixed(0), 10)
|
|
19
|
+
)?.toFixed(2)
|
|
20
|
+
: 0
|
|
21
|
+
}${
|
|
22
|
+
range?.to && parseFloat(rate) * parseInt(range.to.toFixed(0), 10)
|
|
23
|
+
? ` - ${symbol}${(
|
|
24
|
+
parseFloat(rate) * parseInt(range.to.toFixed(0), 10)
|
|
25
|
+
).toFixed(2)}`
|
|
26
|
+
: ' and above'
|
|
27
|
+
}`;
|
|
28
|
+
return label;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const formatBinaryLabel = (filter, option, categoryNames, categoryPath) => {
|
|
32
|
+
if (categoryPath && categoryNames) {
|
|
33
|
+
const category = categoryNames.find(
|
|
34
|
+
facet =>
|
|
35
|
+
facet.attribute === filter.attribute && facet.value === option
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (category?.name) {
|
|
39
|
+
return category.name;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const title = filter.attribute?.split('_');
|
|
44
|
+
if (option === 'yes') {
|
|
45
|
+
return title.join(' ');
|
|
46
|
+
} else if (option === 'no') {
|
|
47
|
+
return `not ${title.join(' ')}`;
|
|
48
|
+
}
|
|
49
|
+
return option;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { formatBinaryLabel, formatRangeLabel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './Facets';
|
|
11
|
+
export { default as SelectedFilters } from './SelectedFilters';
|
|
12
|
+
export * from './Range/RangeFacet';
|
|
13
|
+
export * from './Scalar/ScalarFacet';
|
|
14
|
+
export { Facets as default } from './Facets';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const colorBuckets = [
|
|
11
|
+
{
|
|
12
|
+
count: 5,
|
|
13
|
+
title: 'Green',
|
|
14
|
+
__typename: 'ScalarBucket'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
count: 4,
|
|
18
|
+
title: 'Black',
|
|
19
|
+
__typename: 'ScalarBucket'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
count: 3,
|
|
23
|
+
title: 'Blue',
|
|
24
|
+
__typename: 'ScalarBucket'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
count: 2,
|
|
28
|
+
title: 'Gray',
|
|
29
|
+
__typename: 'ScalarBucket'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
count: 1,
|
|
33
|
+
title: 'Pink',
|
|
34
|
+
__typename: 'ScalarBucket'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
count: 0,
|
|
38
|
+
title: 'Yellow',
|
|
39
|
+
__typename: 'ScalarBucket'
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const sizeBuckets = [
|
|
44
|
+
{
|
|
45
|
+
count: 2,
|
|
46
|
+
title: '32',
|
|
47
|
+
__typename: 'ScalarBucket'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
count: 2,
|
|
51
|
+
title: '33',
|
|
52
|
+
__typename: 'ScalarBucket'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
count: 1,
|
|
56
|
+
title: 'L',
|
|
57
|
+
__typename: 'ScalarBucket'
|
|
58
|
+
}
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const priceBuckets = [
|
|
62
|
+
{
|
|
63
|
+
title: '0.0-25.0',
|
|
64
|
+
__typename: 'RangeBucket',
|
|
65
|
+
from: 0,
|
|
66
|
+
to: 25,
|
|
67
|
+
count: 45
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
title: '25.0-50.0',
|
|
71
|
+
__typename: 'RangeBucket',
|
|
72
|
+
from: 25,
|
|
73
|
+
to: 50,
|
|
74
|
+
count: 105
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: '75.0-100.0',
|
|
78
|
+
__typename: 'RangeBucket',
|
|
79
|
+
from: 75,
|
|
80
|
+
to: 100,
|
|
81
|
+
count: 6
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
title: '200.0-225.0',
|
|
85
|
+
__typename: 'RangeBucket',
|
|
86
|
+
from: 200,
|
|
87
|
+
to: 225,
|
|
88
|
+
count: 2
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
export const mockFilters = [
|
|
93
|
+
{
|
|
94
|
+
title: 'Color',
|
|
95
|
+
attribute: 'color',
|
|
96
|
+
buckets: colorBuckets,
|
|
97
|
+
__typename: 'ScalarBucket'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
title: 'Size',
|
|
101
|
+
attribute: 'size',
|
|
102
|
+
buckets: sizeBuckets,
|
|
103
|
+
__typename: 'ScalarBucket'
|
|
104
|
+
}
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
export const mockColorFilter = {
|
|
108
|
+
title: 'Color',
|
|
109
|
+
attribute: 'color',
|
|
110
|
+
buckets: colorBuckets,
|
|
111
|
+
__typename: 'ScalarBucket'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const mockPriceFilter = {
|
|
115
|
+
title: 'Price',
|
|
116
|
+
attribute: 'price',
|
|
117
|
+
buckets: priceBuckets,
|
|
118
|
+
__typename: 'RangeBucket'
|
|
119
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
@keyframes placeholderShimmer {
|
|
2
|
+
0% {
|
|
3
|
+
background-position: calc(-100vw + 40px); /* 40px offset */
|
|
4
|
+
}
|
|
5
|
+
100% {
|
|
6
|
+
background-position: calc(100vw - 40px); /* 40px offset */
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.shimmer-animation-facet {
|
|
11
|
+
background-color: #f6f7f8;
|
|
12
|
+
background-image: linear-gradient(
|
|
13
|
+
to right,
|
|
14
|
+
#f6f7f8 0%,
|
|
15
|
+
#edeef1 20%,
|
|
16
|
+
#f6f7f8 40%,
|
|
17
|
+
#f6f7f8 100%
|
|
18
|
+
);
|
|
19
|
+
background-repeat: no-repeat;
|
|
20
|
+
background-size: 100vw 4rem;
|
|
21
|
+
animation-duration: 1s;
|
|
22
|
+
animation-fill-mode: forwards;
|
|
23
|
+
animation-iteration-count: infinite;
|
|
24
|
+
animation-name: placeholderShimmer;
|
|
25
|
+
animation-timing-function: linear;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ds-sdk-input__header {
|
|
29
|
+
display: flex;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
margin-bottom: 1rem;
|
|
32
|
+
margin-top: 0.75rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ds-sdk-input__title {
|
|
36
|
+
height: 2.5rem;
|
|
37
|
+
flex: 0 0 auto;
|
|
38
|
+
width: 50%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.ds-sdk-input__item {
|
|
42
|
+
height: 2rem;
|
|
43
|
+
width: 80%;
|
|
44
|
+
margin-bottom: 0.3125rem;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ds-sdk-input__item:last-child {
|
|
48
|
+
margin-bottom: 0;
|
|
49
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './FacetsShimmer.css';
|
|
3
|
+
|
|
4
|
+
export const FacetsShimmer = () => {
|
|
5
|
+
return (
|
|
6
|
+
<>
|
|
7
|
+
<div className="ds-sdk-input ds-sdk-input--loading">
|
|
8
|
+
<div className="ds-sdk-input__content">
|
|
9
|
+
<div className="ds-sdk-input__header">
|
|
10
|
+
<div className="ds-sdk-input__title shimmer-animation-facet" />
|
|
11
|
+
</div>
|
|
12
|
+
<div className="ds-sdk-input__list">
|
|
13
|
+
<div className="ds-sdk-input__item shimmer-animation-facet" />
|
|
14
|
+
<div className="ds-sdk-input__item shimmer-animation-facet" />
|
|
15
|
+
<div className="ds-sdk-input__item shimmer-animation-facet" />
|
|
16
|
+
<div className="ds-sdk-input__item shimmer-animation-facet" />
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div className="ds-sdk-input__border border-t mt-md border-gray-200" />
|
|
21
|
+
</>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//export default FacetsShimmer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './FacetsShimmer';
|
|
11
|
+
export { FacetsShimmer as default } from './FacetsShimmer';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { useTranslation } from '../../context/translation';
|
|
12
|
+
import AdjustmentsIcon from '../../icons/adjustments.svg';
|
|
13
|
+
|
|
14
|
+
export const FilterButton = ({ displayFilter, type, title }) => {
|
|
15
|
+
const translation = useTranslation();
|
|
16
|
+
|
|
17
|
+
return type === 'mobile' ? (
|
|
18
|
+
<div className="ds-sdk-filter-button">
|
|
19
|
+
<button
|
|
20
|
+
className="flex items-center bg-gray-100 ring-black ring-opacity-5 rounded-md p-sm outline outline-gray-200 hover:outline-gray-800 h-[32px]"
|
|
21
|
+
onClick={displayFilter}
|
|
22
|
+
>
|
|
23
|
+
{/* <AdjustmentsIcon className="w-md" /> */}
|
|
24
|
+
<img src={AdjustmentsIcon} className={`w-md`} />
|
|
25
|
+
{translation.Filter.title}
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
) : (
|
|
29
|
+
<div className="ds-sdk-filter-button-desktop">
|
|
30
|
+
<button
|
|
31
|
+
className="flex items-center bg-gray-100 ring-black ring-opacity-5 rounded-md p-sm text-sm h-[32px]"
|
|
32
|
+
onClick={displayFilter}
|
|
33
|
+
>
|
|
34
|
+
{title}
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default FilterButton;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './FilterButton';
|
|
11
|
+
export { default as FilterButton } from './FilterButton';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useIntersectionObserver } from '../../utils/useIntersectionObserver';
|
|
3
|
+
|
|
4
|
+
export const Image = ({
|
|
5
|
+
image,
|
|
6
|
+
alt,
|
|
7
|
+
carouselIndex,
|
|
8
|
+
index,
|
|
9
|
+
}) => {
|
|
10
|
+
const imageRef = useRef(null);
|
|
11
|
+
const [imageUrl, setImageUrl] = useState('');
|
|
12
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
13
|
+
const entry = useIntersectionObserver(imageRef, { rootMargin: '200px' });
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!entry) return;
|
|
17
|
+
|
|
18
|
+
if (entry?.isIntersecting && index === carouselIndex) {
|
|
19
|
+
setIsVisible(true);
|
|
20
|
+
setImageUrl(entry?.target?.dataset.src || '');
|
|
21
|
+
}
|
|
22
|
+
}, [entry, carouselIndex, index, image]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<img
|
|
26
|
+
className={`aspect-auto w-100 h-auto ${isVisible ? 'visible' : 'invisible'}`}
|
|
27
|
+
ref={imageRef}
|
|
28
|
+
src={imageUrl}
|
|
29
|
+
data-src={typeof image === 'object' ? image.src : image}
|
|
30
|
+
srcSet={typeof image === 'object' ? image.srcset : null}
|
|
31
|
+
alt={alt}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Image } from './Image';
|
|
3
|
+
|
|
4
|
+
export const ImageCarousel = ({
|
|
5
|
+
images,
|
|
6
|
+
productName,
|
|
7
|
+
carouselIndex,
|
|
8
|
+
setCarouselIndex,
|
|
9
|
+
}) => {
|
|
10
|
+
const [swipeIndex, setSwipeIndex] = useState(0);
|
|
11
|
+
|
|
12
|
+
const cirHandler = (index) => {
|
|
13
|
+
setCarouselIndex(index);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const prevHandler = () => {
|
|
17
|
+
if (carouselIndex === 0) {
|
|
18
|
+
setCarouselIndex(0);
|
|
19
|
+
} else {
|
|
20
|
+
setCarouselIndex((prev) => prev - 1);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const nextHandler = () => {
|
|
25
|
+
if (carouselIndex === images.length - 1) {
|
|
26
|
+
setCarouselIndex(0);
|
|
27
|
+
} else {
|
|
28
|
+
setCarouselIndex((prev) => prev + 1);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div className="ds-sdk-product-image-carousel max-h-[250px] max-w-2xl m-auto">
|
|
34
|
+
<div
|
|
35
|
+
className="flex flex-nowrap overflow-hidden relative rounded-lg w-full h-full"
|
|
36
|
+
onTouchStart={(e) => setSwipeIndex(e.touches[0].clientX)}
|
|
37
|
+
onTouchEnd={(e) => {
|
|
38
|
+
const endIndex = e.changedTouches[0].clientX;
|
|
39
|
+
if (swipeIndex > endIndex) {
|
|
40
|
+
nextHandler();
|
|
41
|
+
} else if (swipeIndex < endIndex) {
|
|
42
|
+
prevHandler();
|
|
43
|
+
}
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<div className="overflow-hidden relative max-w-[200px]">
|
|
47
|
+
<div
|
|
48
|
+
className={`flex transition ease-out duration-40`}
|
|
49
|
+
style={{
|
|
50
|
+
transform: `translateX(-${carouselIndex * 100}%)`,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
{images.map((item, index) => {
|
|
54
|
+
return (
|
|
55
|
+
<Image
|
|
56
|
+
image={item}
|
|
57
|
+
carouselIndex={carouselIndex}
|
|
58
|
+
index={index}
|
|
59
|
+
key={index}
|
|
60
|
+
alt={productName}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
})}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
{images.length > 1 && (
|
|
68
|
+
<div className="absolute z-1 flex space-x-3 -translate-x-1/2 bottom-0 left-1/2 pb-2 ">
|
|
69
|
+
{images.map((_item, index) => {
|
|
70
|
+
return (
|
|
71
|
+
<span
|
|
72
|
+
key={index}
|
|
73
|
+
style={
|
|
74
|
+
carouselIndex === index
|
|
75
|
+
? {
|
|
76
|
+
width: `12px`,
|
|
77
|
+
height: `12px`,
|
|
78
|
+
borderRadius: `50%`,
|
|
79
|
+
border: `1px solid black`,
|
|
80
|
+
cursor: `pointer`,
|
|
81
|
+
backgroundColor: `#252525`,
|
|
82
|
+
}
|
|
83
|
+
: {
|
|
84
|
+
width: `12px`,
|
|
85
|
+
height: `12px`,
|
|
86
|
+
borderRadius: `50%`,
|
|
87
|
+
border: `1px solid silver`,
|
|
88
|
+
cursor: `pointer`,
|
|
89
|
+
backgroundColor: `silver`,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
onClick={(e) => {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
cirHandler(index);
|
|
95
|
+
}}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
})}
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
6
|
+
accordance with the terms of the Adobe license agreement accompanying
|
|
7
|
+
it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './ImageCarousel';
|
|
11
|
+
export { ImageCarousel as default } from './ImageCarousel';
|