@wayke-se/components-react 3.5.3 → 3.6.0

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.
Files changed (40) hide show
  1. package/dist-node/index.js +622 -127
  2. package/dist-node/index.js.map +1 -1
  3. package/dist-src/components/AccessoryCard/index.js +14 -0
  4. package/dist-src/components/AccessoryCard/wrapper.js +90 -0
  5. package/dist-src/components/DocumentList/wrapper.js +1 -1
  6. package/dist-src/components/Gallery/index.js +7 -4
  7. package/dist-src/components/Gallery/wrapper.js +1 -38
  8. package/dist-src/components/Icon/index.js +2 -0
  9. package/dist-src/components/Image/index.js +5 -0
  10. package/dist-src/components/Link/index.js +28 -0
  11. package/dist-src/components/NavButton/index.js +42 -0
  12. package/dist-src/components/OverflowGrid/index.js +56 -66
  13. package/dist-src/components/OverflowGrid/wrapper.js +144 -0
  14. package/dist-src/components/PriceBox/index.js +6 -0
  15. package/dist-src/components/PriceBox/wrapper.js +34 -0
  16. package/dist-src/layout/theme.js +8 -0
  17. package/dist-src/layouts/searchItem/Accessories/AccessoryModal.js +51 -0
  18. package/dist-src/layouts/searchItem/Accessories/index.js +32 -0
  19. package/dist-src/layouts/searchItem/Related.js +23 -25
  20. package/dist-src/layouts/searchItem/index.js +3 -1
  21. package/dist-src/queries/SEARCH_ITEM_BRANCH_QUERY.js +18 -0
  22. package/dist-src/queries/SEARCH_ITEM_QUERY.js +18 -0
  23. package/dist-types/@types/codegen/types.d.ts +17 -0
  24. package/dist-types/components/AccessoryCard/index.d.ts +16 -0
  25. package/dist-types/components/AccessoryCard/wrapper.d.ts +18 -0
  26. package/dist-types/components/Gallery/wrapper.d.ts +2 -6
  27. package/dist-types/components/Icon/index.d.ts +1 -0
  28. package/dist-types/components/Image/index.d.ts +1 -0
  29. package/dist-types/components/Link/index.d.ts +7 -0
  30. package/dist-types/components/NavButton/index.d.ts +3 -0
  31. package/dist-types/components/OverflowGrid/index.d.ts +12 -3
  32. package/dist-types/components/OverflowGrid/wrapper.d.ts +18 -0
  33. package/dist-types/components/PriceBox/index.d.ts +11 -0
  34. package/dist-types/components/PriceBox/wrapper.d.ts +10 -0
  35. package/dist-types/layout/theme.d.ts +8 -0
  36. package/dist-types/layouts/searchItem/Accessories/AccessoryModal.d.ts +8 -0
  37. package/dist-types/layouts/searchItem/Accessories/index.d.ts +7 -0
  38. package/dist-web/index.js +535 -122
  39. package/dist-web/index.js.map +1 -1
  40. package/package.json +1 -1
package/dist-web/index.js CHANGED
@@ -66,6 +66,14 @@ const theme = {
66
66
  Lg: '@media (min-width: 1200px)',
67
67
  LtLg: '@media (max-width: 1199px)',
68
68
  },
69
+ mask: {
70
+ gradient: {
71
+ toTop: 'linear-gradient(to top, #000, transparent)',
72
+ toBottom: 'linear-gradient(to bottom, #000, transparent)',
73
+ toLeft: 'linear-gradient(to left, #000, transparent)',
74
+ toRight: 'linear-gradient(to right, #000, transparent)',
75
+ },
76
+ },
69
77
  distances: {
70
78
  baseUnit: '8px',
71
79
  inputHeight: '48px',
@@ -650,6 +658,8 @@ const IconExclamationCircle = ({ block }) => (createElement(Icon$1, { viewBox: "
650
658
  createElement("path", { d: "M14.482 21.893c0-0.857 0.694-1.551 1.551-1.551s1.551 0.694 1.551 1.551c0 0.857-0.694 1.551-1.551 1.551s-1.551-0.694-1.551-1.551zM16.033 2.838c-7.271 0-13.187 5.916-13.187 13.187s5.916 13.187 13.187 13.187 13.187-5.916 13.187-13.187c0-7.271-5.916-13.187-13.187-13.187zM16.033 27.203c-6.163 0-11.178-5.015-11.178-11.178s5.015-11.178 11.178-11.178c6.164 0 11.178 5.015 11.178 11.178s-5.014 11.178-11.178 11.178zM16.033 8.308c-0.555 0-1.004 0.45-1.004 1.004v8.227c0 0.555 0.45 1.004 1.004 1.004s1.004-0.45 1.004-1.004v-8.227c0-0.555-0.45-1.004-1.004-1.004z" })));
651
659
  const IconExclamationTriangle = ({ block }) => (createElement(Icon$1, { viewBox: "0 0 32 32", block: block },
652
660
  createElement("path", { d: "M15.951 19.663c-0.457 0-0.828-0.37-0.828-0.828v-4.357c0-0.457 0.37-0.828 0.828-0.828s0.828 0.37 0.828 0.828v4.357c0 0.457-0.371 0.828-0.828 0.828zM15.952 22.906c-0.305 0-0.606-0.126-0.821-0.341s-0.338-0.514-0.338-0.818 0.122-0.606 0.338-0.821c0.431-0.43 1.209-0.43 1.639 0 0.215 0.215 0.341 0.516 0.341 0.821s-0.126 0.603-0.341 0.818c-0.215 0.215-0.513 0.341-0.818 0.341zM27.049 27.070h-22.196c-0.352 0-0.677-0.186-0.855-0.489s-0.184-0.677-0.014-0.985l11.098-20.105c0.175-0.317 0.508-0.513 0.87-0.513s0.695 0.197 0.87 0.513l11.098 20.105c0.17 0.308 0.165 0.683-0.014 0.985s-0.504 0.489-0.856 0.489zM6.536 25.083h18.83l-9.415-17.056-9.415 17.056z" })));
661
+ const IconImage = ({ block }) => (createElement(Icon$1, { viewBox: "0 0 16 16", block: block },
662
+ createElement("path", { d: "M14.4 1.6H1.6C.7 1.6 0 2.3 0 3.2v9.6c0 .9.7 1.6 1.6 1.6h12.8c.9 0 1.6-.7 1.6-1.6V3.2c0-.9-.7-1.6-1.6-1.6zm0 11.2H1.6V3.2h12.8v9.6zM3.2 6c0-.7.5-1.2 1.2-1.2s1.2.5 1.2 1.2-.5 1.2-1.2 1.2S3.2 6.7 3.2 6zm.2 4.5l6.2-4.4c.4-.3.9-.2 1.1.2v.1l2.4 4.2c.1.2 0 .4-.1.5-.1 0-.1.1-.2.1H3.7c-.2 0-.4-.2-.4-.4 0-.1 0-.3.1-.3z", fillRule: "evenodd", clipRule: "evenodd" })));
653
663
 
654
664
  const SortSelect = ({ value, options, onChange, unit }) => (React__default.createElement(Wrapper$4, null,
655
665
  React__default.createElement(Select, { value: value, onChange: onChange, title: "Sortering", "aria-label": "Sortering" }, options.map((option) => (React__default.createElement(Option, { key: option.value, value: option.value },
@@ -2871,47 +2881,10 @@ const ImageFull = styled.img `
2871
2881
  object-fit: cover;
2872
2882
  `;
2873
2883
  // Arrow Nav
2874
- const Arrow = styled(ButtonReset) `
2884
+ const Arrow = styled.div `
2875
2885
  position: absolute;
2876
2886
  top: 50%;
2877
2887
  transform: translateY(-50%);
2878
- display: flex;
2879
- align-items: center;
2880
- justify-content: center;
2881
- width: ${size(4)};
2882
- height: ${size(4)};
2883
- border-radius: 50%;
2884
- font-size: 1rem;
2885
- line-height: 1;
2886
- background-color: rgba(255, 255, 255, 0.4);
2887
- backdrop-filter: blur(5px);
2888
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
2889
- color: ${(props) => props.theme.color.textDark};
2890
- transform-origin: 50% 50%;
2891
- transition: transform 200ms ease;
2892
-
2893
- :before {
2894
- content: '';
2895
- position: absolute;
2896
- top: 0;
2897
- bottom: 0;
2898
- left: 0;
2899
- right: 0;
2900
- border-radius: 50%;
2901
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
2902
- opacity: 0;
2903
- transition: opacity 200ms ease;
2904
- }
2905
-
2906
- :hover {
2907
- :before {
2908
- opacity: 1;
2909
- }
2910
- }
2911
-
2912
- :active {
2913
- transform: translateY(-50%) scale(0.95);
2914
- }
2915
2888
 
2916
2889
  ${(props) => props.theme.breakpoint.LtSm} {
2917
2890
  display: none;
@@ -3014,6 +2987,46 @@ const EnableNavigationButton = styled.div `
3014
2987
  z-index: 1;
3015
2988
  `;
3016
2989
 
2990
+ const NavButton = styled(ButtonReset) `
2991
+ position: relative;
2992
+ display: flex;
2993
+ align-items: center;
2994
+ justify-content: center;
2995
+ width: ${size(4)};
2996
+ height: ${size(4)};
2997
+ border-radius: 50%;
2998
+ background-color: ${(props) => props.theme.color.bg};
2999
+ color: ${(props) => props.theme.color.textDark};
3000
+ font-size: 0.75rem;
3001
+ box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
3002
+ transition: transform 200ms ease;
3003
+
3004
+ &::before {
3005
+ content: '';
3006
+ position: absolute;
3007
+ top: 0;
3008
+ bottom: 0;
3009
+ left: 0;
3010
+ right: 0;
3011
+ border-radius: 50%;
3012
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
3013
+ opacity: 0;
3014
+ transition: opacity 200ms ease;
3015
+ }
3016
+
3017
+ &:enabled {
3018
+ &:hover {
3019
+ &::before {
3020
+ opacity: 1;
3021
+ }
3022
+ }
3023
+ }
3024
+
3025
+ &:active {
3026
+ transform: scale(0.95);
3027
+ }
3028
+ `;
3029
+
3017
3030
  const Wrapper$h = styled.div `
3018
3031
  position: fixed;
3019
3032
  top: 0;
@@ -4020,10 +4033,12 @@ const Gallery = ({ media, placeholderImage }) => {
4020
4033
  React__default.createElement(ButtonSecondary, { onClick: onEnableNavigation, title: "St\u00E4ng" },
4021
4034
  React__default.createElement(ButtonContent, null, "St\u00E4ng"))))),
4022
4035
  !navigationDisabled && mediaLength > 1 && (React__default.createElement(React__default.Fragment, null,
4023
- React__default.createElement(ArrowLeft, { onClick: prevImage, title: "F\u00F6reg\u00E5ende bild" },
4024
- React__default.createElement(IconChevronLeft, { block: true })),
4025
- React__default.createElement(ArrowRight, { onClick: nextImage, title: "N\u00E4sta bild" },
4026
- React__default.createElement(IconChevronRight, { block: true }))))),
4036
+ React__default.createElement(ArrowLeft, null,
4037
+ React__default.createElement(NavButton, { onClick: prevImage, title: "F\u00F6reg\u00E5ende bild" },
4038
+ React__default.createElement(IconChevronLeft, { block: true }))),
4039
+ React__default.createElement(ArrowRight, null,
4040
+ React__default.createElement(NavButton, { onClick: nextImage, title: "N\u00E4sta bild" },
4041
+ React__default.createElement(IconChevronRight, { block: true })))))),
4027
4042
  React__default.createElement(Alt, null,
4028
4043
  React__default.createElement(QuickNav, { ref: quickNavRef }, !!media?.length ? (media.map((m, i) => {
4029
4044
  const src = m.files[0].formats.filter(notEmpty).find((x) => x.format === '225x150')?.url ||
@@ -4149,6 +4164,24 @@ const SEARCH_ITEM_QUERY = gql `
4149
4164
  phonenumber
4150
4165
  avatar
4151
4166
  }
4167
+ accessories {
4168
+ articleNumber
4169
+ description
4170
+ excerpt
4171
+ id
4172
+ images
4173
+ logotype
4174
+ manufacturer
4175
+ model
4176
+ name
4177
+ price
4178
+ assemblyPrice
4179
+ productPage {
4180
+ title
4181
+ url
4182
+ }
4183
+ salePrice
4184
+ }
4152
4185
  manufacturer {
4153
4186
  description
4154
4187
  logotype
@@ -5826,69 +5859,200 @@ const SectionHeader = ({ children, onClick, actionTitle }) => (React__default.cr
5826
5859
  React__default.createElement(ButtonClear, { as: "a", href: "#", onClick: onClick },
5827
5860
  React__default.createElement(ButtonContent, null, actionTitle))))));
5828
5861
 
5829
- const OverflowGrid = styled.div `
5830
- ${(props) => props.theme.breakpoint.LtMd} {
5831
- ${Wrapper} & {
5832
- margin-left: ${size(-3)};
5833
- margin-right: ${size(-2)};
5834
- }
5862
+ const Wrapper$v = styled.div `
5863
+ --container-gutter: ${size(2)};
5864
+ --bg: ${(props) => props.theme.color.bg};
5865
+
5866
+ ${(props) => props.theme.breakpoint.Sm} {
5867
+ --container-gutter: ${size(3)};
5835
5868
  }
5836
5869
 
5870
+ position: relative;
5871
+
5872
+ ${({ $accentBg }) => $accentBg &&
5873
+ css `
5874
+ --bg: ${(props) => props.theme.color.accent};
5875
+ `}
5876
+ `;
5877
+ const Item$b = styled.li `
5878
+ flex: 1 0 auto;
5879
+ width: 100%;
5880
+ max-width: 100%;
5881
+ scroll-snap-align: start;
5882
+
5837
5883
  ${(props) => props.theme.breakpoint.LtSm} {
5838
- ${Wrapper} & {
5839
- margin-left: ${size(-2)};
5840
- margin-right: ${size(-1)};
5884
+ &:is(:only-child, #important) {
5885
+ width: 100%;
5886
+ max-width: 100%;
5841
5887
  }
5842
5888
  }
5843
5889
  `;
5844
- const OverflowGridList = styled.ul `
5890
+ const List$9 = styled.ul `
5845
5891
  display: flex;
5846
- align-items: flex-start;
5892
+ align-items: stretch;
5847
5893
  list-style: none;
5848
- padding: 0;
5849
- margin: ${size(-1)};
5894
+ padding: 0 var(--container-gutter);
5895
+ margin: 0;
5896
+ overflow: auto;
5897
+ scroll-snap-type: x mandatory;
5898
+ scroll-padding-left: var(--container-gutter);
5899
+ scrollbar-width: none;
5900
+ -ms-overflow-style: none;
5850
5901
 
5851
- ${(props) => props.theme.breakpoint.LtMd} {
5852
- ${Wrapper} & {
5853
- overflow: auto;
5854
- -webkit-overflow-scrolling: touch;
5855
- padding: 0 ${size(3)};
5902
+ &::-webkit-scrollbar {
5903
+ display: none;
5904
+ }
5856
5905
 
5857
- :after {
5858
- content: '';
5859
- flex: 0 0 auto;
5860
- height: 1px;
5861
- width: ${size(2)};
5906
+ ${({ $columns }) => $columns &&
5907
+ css `
5908
+ ${Item$b} {
5909
+ width: ${100 / $columns}%;
5910
+ max-width: ${100 / $columns}%;
5862
5911
  }
5863
- }
5864
- }
5912
+ `}
5865
5913
 
5866
- ${(props) => props.theme.breakpoint.LtSm} {
5867
- ${Wrapper} & {
5868
- padding: 0 ${size(2)};
5914
+ ${({ $columnsSm }) => $columnsSm &&
5915
+ css `
5916
+ ${(props) => props.theme.breakpoint.Sm} {
5917
+ ${Item$b} {
5918
+ width: ${100 / $columnsSm}%;
5919
+ max-width: ${100 / $columnsSm}%;
5920
+ }
5921
+ }
5922
+ `}
5869
5923
 
5870
- :after {
5871
- width: ${size(1)};
5924
+ ${({ $columnsMd }) => $columnsMd &&
5925
+ css `
5926
+ ${(props) => props.theme.breakpoint.Md} {
5927
+ ${Item$b} {
5928
+ width: ${100 / $columnsMd}%;
5929
+ max-width: ${100 / $columnsMd}%;
5930
+ }
5872
5931
  }
5873
- }
5874
- }
5932
+ `}
5875
5933
  `;
5876
- const OverflowGridItem = styled.li `
5877
- flex: 1 0 auto;
5878
- width: calc(100% - ${size(2)});
5879
- max-width: calc(100% - ${size(2)});
5880
- padding: ${size(1)};
5934
+ const ListWrapper = styled.div `
5935
+ position: relative;
5936
+ overflow: hidden;
5937
+ margin: 0 calc(var(--container-gutter) * -1);
5881
5938
 
5882
- ${(props) => props.theme.breakpoint.Sm} {
5883
- width: calc(50% - ${size(3)});
5884
- max-width: calc(50% - ${size(3)});
5939
+ ${(props) => props.theme.breakpoint.Md} {
5940
+ &::before,
5941
+ &::after {
5942
+ content: '';
5943
+ position: absolute;
5944
+ top: 0;
5945
+ bottom: 0;
5946
+ width: var(--container-gutter);
5947
+ background-color: var(--bg);
5948
+ z-index: 1;
5949
+ }
5950
+
5951
+ &::before {
5952
+ left: 0;
5953
+
5954
+ ${({ $spacing }) => $spacing
5955
+ ? css `
5956
+ mask-image: linear-gradient(to right, #000 ${size($spacing)}, transparent);
5957
+ `
5958
+ : css `
5959
+ mask-image: ${(props) => props.theme.mask.gradient.toRight};
5960
+ `}
5961
+ }
5962
+
5963
+ &::after {
5964
+ right: 0;
5965
+
5966
+ ${({ $spacing }) => $spacing
5967
+ ? css `
5968
+ mask-image: linear-gradient(to left, #000 ${size($spacing)}, transparent);
5969
+ `
5970
+ : css `
5971
+ mask-image: ${(props) => props.theme.mask.gradient.toLeft};
5972
+ `}
5973
+ }
5885
5974
  }
5886
5975
 
5887
- ${(props) => props.theme.breakpoint.Md} {
5888
- width: 33.333%;
5889
- max-width: 33.333%;
5976
+ ${({ $spacing }) => $spacing &&
5977
+ css `
5978
+ ${List$9} {
5979
+ margin: 0 -${size($spacing / 2)};
5980
+ }
5981
+
5982
+ ${Item$b} {
5983
+ padding: 0 ${size($spacing / 2)};
5984
+ }
5985
+ `}
5986
+ `;
5987
+ const NavBtn = styled.div `
5988
+ position: absolute;
5989
+ top: 50%;
5990
+ z-index: 2;
5991
+
5992
+ ${(props) => props.theme.breakpoint.LtSm} {
5993
+ display: none;
5890
5994
  }
5891
5995
  `;
5996
+ const PrevBtn = styled(NavBtn) `
5997
+ left: 0;
5998
+ transform: translate(-50%, -50%);
5999
+ `;
6000
+ const NextBtn = styled(NavBtn) `
6001
+ right: 0;
6002
+ transform: translate(50%, -50%);
6003
+ `;
6004
+
6005
+ const OverflowGrid = ({ items, itemKeyBase, spacing, columns, columnsSm, columnsMd, accentBg, }) => {
6006
+ const overflowElement = useRef(null);
6007
+ const onPrev = useCallback(() => {
6008
+ const itemWidth = overflowElement.current?.children[0].clientWidth || 0;
6009
+ const scrollLeft = overflowElement.current?.scrollLeft || 0;
6010
+ if (scrollLeft > 0) {
6011
+ overflowElement.current?.scroll({
6012
+ left: scrollLeft - itemWidth,
6013
+ behavior: 'smooth',
6014
+ });
6015
+ }
6016
+ }, []);
6017
+ const onNext = useCallback(() => {
6018
+ const itemWidth = overflowElement.current?.children[0].clientWidth || 0;
6019
+ const scrollWidth = overflowElement.current?.scrollWidth || 0;
6020
+ const scrollLeft = overflowElement.current?.scrollLeft || 0;
6021
+ const overflowElementWidth = overflowElement.current?.offsetWidth || 0;
6022
+ const overflowElementScrollWidth = scrollWidth - overflowElementWidth;
6023
+ if (overflowElementScrollWidth !== scrollLeft) {
6024
+ overflowElement.current?.scroll({
6025
+ left: scrollLeft + itemWidth,
6026
+ behavior: 'smooth',
6027
+ });
6028
+ }
6029
+ }, []);
6030
+ // Hide navigation buttons depending on scroll position
6031
+ const [hidePrevNav, setHidePrevNav] = useState(true);
6032
+ const [hideNextNav, setHideNextNav] = useState(true);
6033
+ const onScroll = () => {
6034
+ const scrollLeft = overflowElement.current?.scrollLeft || 0;
6035
+ const scrollWidth = overflowElement.current?.scrollWidth || 0;
6036
+ const overflowElementWidth = overflowElement.current?.offsetWidth || 0;
6037
+ const overflowElementScrollWidth = scrollWidth - overflowElementWidth;
6038
+ setHidePrevNav(scrollLeft == 0 ? true : false);
6039
+ setHideNextNav(overflowElementScrollWidth == scrollLeft ? true : false);
6040
+ };
6041
+ useEffect(() => {
6042
+ onScroll();
6043
+ overflowElement.current?.addEventListener('scroll', onScroll);
6044
+ return () => overflowElement.current?.removeEventListener('scroll', onScroll);
6045
+ }, []);
6046
+ return (React__default.createElement(Wrapper$v, { "$accentBg": accentBg },
6047
+ React__default.createElement(ListWrapper, { "$spacing": spacing },
6048
+ React__default.createElement(List$9, { ref: overflowElement, "$columns": columns, "$columnsSm": columnsSm, "$columnsMd": columnsMd }, items.map((item, i) => (React__default.createElement(Item$b, { key: itemKeyBase ? `${itemKeyBase}-${i}` : `overflow-grid-item-${i}` }, item))))),
6049
+ !hidePrevNav && (React__default.createElement(PrevBtn, null,
6050
+ React__default.createElement(NavButton, { onClick: onPrev, title: "Previous" },
6051
+ React__default.createElement(IconChevronLeft, null)))),
6052
+ !hideNextNav && (React__default.createElement(NextBtn, null,
6053
+ React__default.createElement(NavButton, { onClick: onNext, title: "Next" },
6054
+ React__default.createElement(IconChevronRight, null))))));
6055
+ };
5892
6056
 
5893
6057
  const RelatedSearchContext = createContext({
5894
6058
  moreLikeThisUrl: false,
@@ -5946,8 +6110,7 @@ const Related = ({ id, hashRoute, pathRoute, authorizedReseller, displayBranchNa
5946
6110
  React__default.createElement(SectionHeader, { onClick: () => { }, actionTitle: "Visa alla" },
5947
6111
  React__default.createElement(H2, { noMargin: true }, "Senast inkomna")))),
5948
6112
  React__default.createElement(Repeat, null,
5949
- React__default.createElement(OverflowGrid, null,
5950
- React__default.createElement(OverflowGridList, null, response?.documentList.documents.map((document) => {
6113
+ React__default.createElement(OverflowGrid, { accentBg: true, columns: 1.05, columnsSm: 2.1, columnsMd: 3, spacing: 2, items: response?.documentList.documents.map((document) => {
5951
6114
  const prefix = pathRoute ? `/${pathRoute}` : '/';
5952
6115
  const r = regexPathGuid();
5953
6116
  const pathRouteUrl = window.location.pathname === '/'
@@ -5955,28 +6118,27 @@ const Related = ({ id, hashRoute, pathRoute, authorizedReseller, displayBranchNa
5955
6118
  : r.test(`${pathRoute}${id}`)
5956
6119
  ? window.location.pathname.replace(r, document._id)
5957
6120
  : `${window.location.pathname}${prefix}${document._id}`;
5958
- return (React__default.createElement(OverflowGridItem, { key: document._id },
5959
- React__default.createElement(ProductCard, { id: document._id, onClick: onItemClicked, title: document.title, href: pathRoute ? pathRouteUrl : hashRoute ? `#${document._id}` : undefined, image: document.featuredImage?.files?.[0]?.url, description: document.shortDescription, branchName: displayBranchName ? document.branches?.[0]?.name : undefined, uspList: [
5960
- {
5961
- title: document.modelYear,
5962
- },
5963
- {
5964
- title: `${numberSeparator(document.mileage)} mil`,
5965
- },
5966
- {
5967
- title: document.gearboxType,
5968
- },
5969
- {
5970
- title: document.fuelType,
5971
- },
5972
- ], price: `${numberSeparator(document.price)} kr`, oldPrice: document.oldPrice !== undefined && document.price < document.oldPrice
5973
- ? `${numberSeparator(document.oldPrice)} kr`
5974
- : undefined, leasingPrice: document.leasingPrice !== undefined
5975
- ? `${numberSeparator(document.leasingPrice)} kr/mån`
5976
- : undefined, businessLeasingPrice: document.businessLeasingPrice !== undefined
5977
- ? `${numberSeparator(document.businessLeasingPrice)} kr/mån`
5978
- : undefined, pathRoute: pathRoute })));
5979
- })))))));
6121
+ return (React__default.createElement(ProductCard, { key: document._id, id: document._id, onClick: onItemClicked, title: document.title, href: pathRoute ? pathRouteUrl : hashRoute ? `#${document._id}` : undefined, image: document.featuredImage?.files?.[0]?.url, description: document.shortDescription, branchName: displayBranchName ? document.branches?.[0]?.name : undefined, uspList: [
6122
+ {
6123
+ title: document.modelYear,
6124
+ },
6125
+ {
6126
+ title: `${numberSeparator(document.mileage)} mil`,
6127
+ },
6128
+ {
6129
+ title: document.gearboxType,
6130
+ },
6131
+ {
6132
+ title: document.fuelType,
6133
+ },
6134
+ ], price: `${numberSeparator(document.price)} kr`, oldPrice: document.oldPrice !== undefined && document.price < document.oldPrice
6135
+ ? `${numberSeparator(document.oldPrice)} kr`
6136
+ : undefined, leasingPrice: document.leasingPrice !== undefined
6137
+ ? `${numberSeparator(document.leasingPrice)} kr/mån`
6138
+ : undefined, businessLeasingPrice: document.businessLeasingPrice !== undefined
6139
+ ? `${numberSeparator(document.businessLeasingPrice)} kr/mån`
6140
+ : undefined, pathRoute: pathRoute }));
6141
+ }) })))));
5980
6142
  };
5981
6143
 
5982
6144
  const PackageOptions = ({ packageOptions }) => {
@@ -6019,7 +6181,7 @@ const getBg = (severity) => {
6019
6181
  }
6020
6182
  return bg;
6021
6183
  };
6022
- const Wrapper$v = styled.div.attrs(() => ({
6184
+ const Wrapper$w = styled.div.attrs(() => ({
6023
6185
  className: 'wayke__theme wayke__font--bold',
6024
6186
  })) `
6025
6187
  display: inline-block;
@@ -6031,7 +6193,7 @@ const Wrapper$v = styled.div.attrs(() => ({
6031
6193
  line-height: 1.2;
6032
6194
  `;
6033
6195
 
6034
- const Badge = ({ label, severity }) => React__default.createElement(Wrapper$v, { severity: severity }, label);
6196
+ const Badge = ({ label, severity }) => React__default.createElement(Wrapper$w, { severity: severity }, label);
6035
6197
 
6036
6198
  const KeyOrder = [
6037
6199
  'monday',
@@ -6139,7 +6301,7 @@ const SettingsContext = createContext({});
6139
6301
 
6140
6302
  const useSettings = () => useContext(SettingsContext);
6141
6303
 
6142
- const Wrapper$w = styled.a `
6304
+ const Wrapper$x = styled.a `
6143
6305
  display: block;
6144
6306
  `;
6145
6307
  const Image$3 = styled.img `
@@ -6178,7 +6340,7 @@ const StaticMap = ({ position }) => {
6178
6340
  }
6179
6341
  const { latitude, longitude } = position;
6180
6342
  if (visible && googleMapsApiKey) {
6181
- return (React__default.createElement(Wrapper$w, { href: `http://maps.google.com/maps?q=${latitude},${longitude}`, title: "Visa p\u00E5 Google Maps", target: "_blank", rel: "nofollow noopener noreferrer" },
6343
+ return (React__default.createElement(Wrapper$x, { href: `http://maps.google.com/maps?q=${latitude},${longitude}`, title: "Visa p\u00E5 Google Maps", target: "_blank", rel: "nofollow noopener noreferrer" },
6182
6344
  React__default.createElement(Image$3, { src: `https://maps.googleapis.com/maps/api/staticmap?center=${latitude},${longitude}&zoom=10&size=640x280&maptype=roadmap&markers=${googleMapsMarker ? `icon:${encodeURIComponent(googleMapsMarker)}` : ''}%7C${latitude},${longitude}&key=${googleMapsApiKey}`, alt: "Karta" })));
6183
6345
  }
6184
6346
  return (React__default.createElement(Placeholder, { href: `http://maps.google.com/maps?q=${latitude},${longitude}`, target: "_blank", rel: "noopener noreferrer nofollow", onClick: onShowMap },
@@ -6245,6 +6407,24 @@ const SEARCH_ITEM_BRANCH_QUERY = gql `
6245
6407
  phonenumber
6246
6408
  avatar
6247
6409
  }
6410
+ accessories {
6411
+ articleNumber
6412
+ description
6413
+ excerpt
6414
+ id
6415
+ images
6416
+ logotype
6417
+ manufacturer
6418
+ model
6419
+ name
6420
+ price
6421
+ assemblyPrice
6422
+ productPage {
6423
+ title
6424
+ url
6425
+ }
6426
+ salePrice
6427
+ }
6248
6428
  branch {
6249
6429
  connections {
6250
6430
  id
@@ -7015,7 +7195,7 @@ const MetadataItem = ({ name, hint, value, unit }) => {
7015
7195
  React__default.createElement(Content$2, { dangerouslySetInnerHTML: { __html: hint } })))));
7016
7196
  };
7017
7197
 
7018
- const Wrapper$x = styled.div `
7198
+ const Wrapper$y = styled.div `
7019
7199
  overflow: hidden;
7020
7200
  margin-top: ${size(-1)};
7021
7201
  margin-left: ${size(-1)};
@@ -7026,7 +7206,7 @@ const Wrapper$x = styled.div `
7026
7206
  margin-right: ${size(-2)};
7027
7207
  }
7028
7208
  `;
7029
- const List$9 = styled.ul `
7209
+ const List$a = styled.ul `
7030
7210
  list-style: none;
7031
7211
  padding: 0;
7032
7212
  margin: 0;
@@ -7040,7 +7220,7 @@ const List$9 = styled.ul `
7040
7220
  padding-right: ${size(1)};
7041
7221
  }
7042
7222
  `;
7043
- const Item$b = styled.li `
7223
+ const Item$c = styled.li `
7044
7224
  display: inline-block;
7045
7225
  vertical-align: bottom;
7046
7226
  font-size: 1rem;
@@ -7081,8 +7261,8 @@ const Action$8 = styled(ButtonReset).attrs(() => ({
7081
7261
  `}
7082
7262
  `;
7083
7263
 
7084
- const Tabs = ({ tabs, active, onClick }) => (createElement(Wrapper$x, null,
7085
- createElement(List$9, null, tabs.map((tab) => (createElement(Item$b, { key: tab.name },
7264
+ const Tabs = ({ tabs, active, onClick }) => (createElement(Wrapper$y, null,
7265
+ createElement(List$a, null, tabs.map((tab) => (createElement(Item$c, { key: tab.name },
7086
7266
  createElement(Action$8, { title: tab.displayName, onClick: onClick ? () => onClick(tab.name) : undefined, active: tab.name === active ? 'true' : undefined }, tab.displayName)))))));
7087
7267
 
7088
7268
  const MetadataSubCategory = ({ name, properties }) => (React__default.createElement(Repeat, null,
@@ -7139,7 +7319,7 @@ const PdfListItem = styled.li.attrs(() => ({
7139
7319
  flex: 0 0 100%;
7140
7320
  }
7141
7321
  `;
7142
- const List$a = styled.ul `
7322
+ const List$b = styled.ul `
7143
7323
  list-style: none;
7144
7324
  padding: 0;
7145
7325
  display: flex;
@@ -7167,7 +7347,7 @@ const PdfSubtitle = styled.div `
7167
7347
  color: ${(props) => props.theme.color.textDarkLighten};
7168
7348
  `;
7169
7349
  const PdfColumn = styled.div `
7170
- flex 0 0 auto;
7350
+ flex: 0 0 auto;
7171
7351
  &:first-child {
7172
7352
  flex: 1 1 auto;
7173
7353
  }
@@ -7202,7 +7382,7 @@ const PdfDownloadItem = ({ document }) => {
7202
7382
  React__default.createElement(PdfColumn, null,
7203
7383
  React__default.createElement(PdfLink, { href: document.url, rel: "noopener noreferrer nofollow", target: "_blank" }, "\u00D6ppna")))));
7204
7384
  };
7205
- const DocumentList = ({ documents }) => (React__default.createElement(List$a, null, documents.map((document, i) => (React__default.createElement(PdfDownloadItem, { key: `${document.url}-${i}`, document: document })))));
7385
+ const DocumentList = ({ documents }) => (React__default.createElement(List$b, null, documents.map((document, i) => (React__default.createElement(PdfDownloadItem, { key: `${document.url}-${i}`, document: document })))));
7206
7386
 
7207
7387
  const Translation = {
7208
7388
  'tyre-label': 'Energideklaration för däck',
@@ -7243,6 +7423,238 @@ const Documents = ({ documents }) => {
7243
7423
  React__default.createElement(DocumentList, { documents: group.documents }))))));
7244
7424
  };
7245
7425
 
7426
+ const Wrapper$z = styled.div `
7427
+ display: flex;
7428
+ flex-direction: column;
7429
+ gap: ${size(2)};
7430
+ height: 100%;
7431
+ `;
7432
+ const imageBaseStyling = css `
7433
+ flex-shrink: 0;
7434
+ aspect-ratio: 16 / 9;
7435
+ border-radius: 3px;
7436
+ `;
7437
+ const Image$4 = styled.img `
7438
+ ${imageBaseStyling};
7439
+ display: block;
7440
+ width: 100%;
7441
+ object-fit: cover;
7442
+ `;
7443
+ const ImageaPlaceholder = styled.div `
7444
+ ${imageBaseStyling};
7445
+ display: flex;
7446
+ align-items: center;
7447
+ justify-content: center;
7448
+ color: ${(props) => props.theme.color.textDarkLighten};
7449
+ font-size: 2rem;
7450
+ background-color: ${(props) => props.theme.color.accent};
7451
+ `;
7452
+ const Body$5 = styled.div `
7453
+ flex: 1 1 auto;
7454
+ display: flex;
7455
+ align-items: flex-start;
7456
+ flex-direction: column;
7457
+ gap: ${size(1)};
7458
+ `;
7459
+ const Heading$7 = styled.div `
7460
+ display: flex;
7461
+ align-items: center;
7462
+ justify-content: space-between;
7463
+ gap: ${size(2)};
7464
+ `;
7465
+ const Title$2 = styled.div.attrs(() => ({
7466
+ className: 'wayke__theme wayke__font--bold',
7467
+ })) `
7468
+ font-size: 1.125rem;
7469
+ `;
7470
+ const Branding = styled.img `
7471
+ display: block;
7472
+ `;
7473
+ const Price$2 = styled.div.attrs(() => ({
7474
+ className: 'wayke__theme wayke__font--bold',
7475
+ })) ``;
7476
+ const Preamble = styled.div `
7477
+ --preamble-max-height: ${size(6)};
7478
+ --preamble-gradient-height: calc(var(--preamble-max-height) / 2);
7479
+
7480
+ position: relative;
7481
+ max-height: var(--preamble-max-height);
7482
+ overflow: hidden;
7483
+ display: -webkit-box;
7484
+ -webkit-box-orient: vertical;
7485
+ -webkit-line-clamp: 2;
7486
+ white-space: pre-wrap;
7487
+
7488
+ &::before {
7489
+ content: '';
7490
+ position: absolute;
7491
+ top: var(--preamble-max-height);
7492
+ left: 0;
7493
+ width: 100%;
7494
+ height: var(--preamble-gradient-height);
7495
+ transform: translateY(-100%); // Only visible if Preamble reaches max height
7496
+ color: ${(props) => props.theme.color.bg};
7497
+ mask-image: ${(props) => props.theme.mask.gradient.toTop};
7498
+ pointer-events: none;
7499
+ }
7500
+ `;
7501
+ const ReadMoreBtn = styled(ButtonReset).attrs(() => ({
7502
+ className: 'wayke__theme wayke__font--bold wayke__color--primary-text',
7503
+ })) `
7504
+ margin-top: auto;
7505
+ display: block;
7506
+ color: ${(props) => props.theme.color.link};
7507
+ font-size: 0.875rem;
7508
+
7509
+ &:hover {
7510
+ text-decoration: underline;
7511
+ }
7512
+ `;
7513
+
7514
+ const AccessoryCard = ({ title, image, branding, price, preamble, readMoreCta, }) => (React__default.createElement(Wrapper$z, null,
7515
+ image ? (React__default.createElement(Image$4, { src: image.src, srcSet: image.srcSet, alt: image.alt })) : (React__default.createElement(ImageaPlaceholder, null,
7516
+ React__default.createElement(IconImage, null))),
7517
+ React__default.createElement(Body$5, null,
7518
+ React__default.createElement(Heading$7, null,
7519
+ React__default.createElement(Title$2, null, title),
7520
+ branding && React__default.createElement(Branding, { src: branding.src, srcSet: branding.srcSet, alt: branding.alt })),
7521
+ price && React__default.createElement(Price$2, null, price),
7522
+ preamble && React__default.createElement(Preamble, null, preamble),
7523
+ readMoreCta && React__default.createElement(ReadMoreBtn, { onClick: readMoreCta }, "L\u00E4s mer"))));
7524
+
7525
+ const Image$5 = styled.img `
7526
+ display: block;
7527
+ width: 100%;
7528
+ `;
7529
+
7530
+ const Link$1 = styled.a.attrs(() => ({
7531
+ className: 'wayke__theme wayke__color--primary-text',
7532
+ })) `
7533
+ text-decoration: none;
7534
+ cursor: pointer;
7535
+ text-decoration: underline;
7536
+
7537
+ :not(:hover) {
7538
+ color: ${(props) => props.theme.color.textDark};
7539
+ }
7540
+
7541
+ &:hover {
7542
+ text-decoration: underline;
7543
+ }
7544
+
7545
+ ${({ $hoverGhost }) => $hoverGhost &&
7546
+ css `
7547
+ &:before {
7548
+ content: '';
7549
+ position: absolute;
7550
+ top: 0;
7551
+ left: 0;
7552
+ width: 100%;
7553
+ height: 100%;
7554
+ }
7555
+ `}
7556
+ `;
7557
+
7558
+ const Wrapper$A = styled.ul `
7559
+ --price-box-gutter: ${size(2)};
7560
+
7561
+ list-style: none;
7562
+ padding: var(--price-box-gutter);
7563
+ margin: 0;
7564
+ border: 1px solid ${(props) => props.theme.color.border};
7565
+ `;
7566
+ const Row = styled.li `
7567
+ display: flex;
7568
+ align-items: center;
7569
+ justify-content: space-between;
7570
+ gap: var(--price-box-gutter);
7571
+
7572
+ & + & {
7573
+ margin-top: calc(var(--price-box-gutter) / 4);
7574
+ }
7575
+
7576
+ ${({ $oldPrice }) => $oldPrice &&
7577
+ css `
7578
+ --price-text-decoration: line-through;
7579
+
7580
+ color: ${(props) => props.theme.color.textDarkLighten};
7581
+ font-size: 0.875rem;
7582
+ `}
7583
+ `;
7584
+ const Label$a = styled.div ``;
7585
+ const Price$3 = styled.div.attrs(() => ({
7586
+ className: 'wayke__theme wayke__font--bold',
7587
+ })) `
7588
+ text-decoration: var(--price-text-decoration);
7589
+ `;
7590
+
7591
+ const PriceBox = ({ prices }) => (React__default.createElement(Wrapper$A, null, prices?.map((item, i) => (React__default.createElement(Row, { key: `${item.label}-${i}`, "$oldPrice": item.oldPrice },
7592
+ React__default.createElement(Label$a, null, item.label),
7593
+ React__default.createElement(Price$3, null, item.price))))));
7594
+
7595
+ const AccesoryModal = ({ accessory, onClose }) => {
7596
+ const priceList = [
7597
+ {
7598
+ label: 'Kontantpris',
7599
+ price: `${numberSeparator(accessory.price)} kr`,
7600
+ oldPrice: false,
7601
+ },
7602
+ ];
7603
+ if (accessory.salePrice) {
7604
+ priceList.push({
7605
+ label: 'Tidigare pris',
7606
+ price: `${numberSeparator(accessory.salePrice)} kr`,
7607
+ oldPrice: true,
7608
+ });
7609
+ }
7610
+ if (accessory.assemblyPrice) {
7611
+ priceList.push({
7612
+ label: 'Monteringskostnad',
7613
+ price: `${numberSeparator(accessory.assemblyPrice)} kr`,
7614
+ oldPrice: false,
7615
+ });
7616
+ }
7617
+ return (React__default.createElement(Modal, { title: accessory.name, onClose: onClose },
7618
+ accessory.images?.[0] && (React__default.createElement(Repeat, null,
7619
+ React__default.createElement(Image$5, { src: `${accessory.images[0]}?w=632`, alt: `${accessory.name}` }))),
7620
+ accessory.logotype && (React__default.createElement(Repeat, null,
7621
+ React__default.createElement(LogoBox, { logo: `${accessory.logotype}?w=160`, logo2x: `${accessory.logotype}?w=320`, alt: accessory.manufacturer || 'Logotyp', wide: true }))),
7622
+ React__default.createElement(Repeat, null,
7623
+ React__default.createElement(PriceBox, { prices: priceList })),
7624
+ React__default.createElement(Repeat, null,
7625
+ React__default.createElement(Content$2, { dangerouslySetInnerHTML: { __html: marked(accessory.description) } })),
7626
+ accessory.articleNumber && (React__default.createElement(Repeat, null,
7627
+ React__default.createElement(UtilityTextBold, { as: "div" }, "Art. nr."),
7628
+ React__default.createElement("div", null, accessory.articleNumber))),
7629
+ accessory.productPage && accessory.productPage.url && (React__default.createElement(Repeat, null,
7630
+ React__default.createElement(Link$1, { href: accessory.productPage.url, title: `Mer information om ${accessory.name}`, target: "_blank", rel: "noopener noreferrer nofollow" },
7631
+ accessory.productPage.title || 'Läs mer',
7632
+ " (\u00F6ppnas i ny flik)")))));
7633
+ };
7634
+
7635
+ const AccessoriesSection = ({ accessories }) => {
7636
+ const [modal, setModal] = useState();
7637
+ const onOpenModal = (accessory) => setModal(accessory);
7638
+ const onCloseModal = () => setModal(undefined);
7639
+ if (!accessories?.length)
7640
+ return null;
7641
+ return (React__default.createElement(React__default.Fragment, null,
7642
+ modal && React__default.createElement(AccesoryModal, { accessory: modal, onClose: onCloseModal }),
7643
+ React__default.createElement(ProductPageMainSection, null,
7644
+ React__default.createElement(Repeat, null,
7645
+ React__default.createElement(H2, { noMargin: true }, "Tillbeh\u00F6r")),
7646
+ React__default.createElement(Repeat, null,
7647
+ React__default.createElement(Content$2, null,
7648
+ React__default.createElement("p", null, "Tillbeh\u00F6r som passar till detta fordon."))),
7649
+ React__default.createElement(Repeat, null,
7650
+ React__default.createElement(OverflowGrid, { columns: 1.05, columnsSm: 2.1, columnsMd: 2, spacing: 2, items: accessories.map((accessory) => (React__default.createElement(AccessoryCard, { key: accessory.id, title: accessory.name, image: accessory.images?.[0]
7651
+ ? {
7652
+ src: `${accessory.images?.[0]}?w=539&h=303`,
7653
+ alt: accessory.name,
7654
+ }
7655
+ : undefined, price: `${numberSeparator(accessory.price)} kr`, preamble: accessory.excerpt, readMoreCta: () => onOpenModal(accessory) }))) })))));
7656
+ };
7657
+
7246
7658
  const WaykeSearchItem = ({ id, hashRoute, pathRoute, disableResetScrollOnInit, placeholderImage, modifyDocumentTitleItem, displayBranchName, onClickSearchItem, }) => {
7247
7659
  const { ecomSettings } = useSettings();
7248
7660
  const ecomContext = useRef();
@@ -7296,7 +7708,7 @@ const WaykeSearchItem = ({ id, hashRoute, pathRoute, disableResetScrollOnInit, p
7296
7708
  const { vehicle } = result;
7297
7709
  const contact = centralStorageVehicle?.contact;
7298
7710
  const branch = centralStorageVehicle?.branch;
7299
- const { title, shortDescription, media, description, price, discount, financialOptions, manufacturer, ecommerce, packageOptions, publishedAt, documents, availableFrom, flags, } = vehicle;
7711
+ const { title, accessories, shortDescription, media, description, price, discount, financialOptions, manufacturer, ecommerce, packageOptions, publishedAt, documents, availableFrom, flags, } = vehicle;
7300
7712
  const insuranceOptions = centralStorageVehicle?.insuranceOptions
7301
7713
  ? centralStorageVehicle.insuranceOptions
7302
7714
  : vehicle.insuranceOptions;
@@ -7379,6 +7791,7 @@ const WaykeSearchItem = ({ id, hashRoute, pathRoute, disableResetScrollOnInit, p
7379
7791
  React__default.createElement(Branch, { branch: branch, displayBranchName: displayBranchName, loading: loadingCentralStorageVehicle }),
7380
7792
  ecommerce && ecommerce.enabled && (React__default.createElement(Repeat, null,
7381
7793
  React__default.createElement(ButtonPrimary, { disabled: !!ecommerce.reserved, title: "K\u00F6p bilen online", onClick: () => ecomContext.current?.start() }, "K\u00F6p bilen online")))),
7794
+ React__default.createElement(AccessoriesSection, { accessories: accessories }),
7382
7795
  React__default.createElement(PackageOptions, { packageOptions: packageOptions }),
7383
7796
  React__default.createElement(ManufacturerPackageOption, { packageOption: manufacturer?.packageOption }))))),
7384
7797
  React__default.createElement(Related, { id: id, hashRoute: hashRoute, pathRoute: pathRoute, authorizedReseller: !!branch?.flags?.authorizedReseller, displayBranchName: displayBranchName, onClickSearchItem: onClickSearchItem })),