gatsby-core-theme 44.23.0 → 44.23.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [44.23.2](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.23.1...v44.23.2) (2026-05-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add strong text ([9db12c2](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/9db12c262cf88510608ecf3d26f78a083631fd67))
7
+
8
+ ## [44.23.1](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.23.0...v44.23.1) (2026-05-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * improve style ([747562d](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/747562de00430c2c623b499540648c3c35818e02))
14
+ * separate context for cookie ([b99dcd1](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/b99dcd1dd37bca8cad937cdb67ecbbb37ce5c4cc))
15
+
1
16
  # [44.23.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.22.4...v44.23.0) (2026-04-29)
2
17
 
3
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-core-theme",
3
- "version": "44.23.0",
3
+ "version": "44.23.2",
4
4
  "description": "Gatsby Theme NPM Package",
5
5
  "author": "",
6
6
  "license": "ISC",
@@ -3,7 +3,6 @@
3
3
  import React, { useContext } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
 
6
- import keygen from '~helpers/keygen';
7
6
  import { imagePrettyUrl } from '~helpers/getters';
8
7
  import { getAltText } from '~helpers/image';
9
8
  import Link from '~hooks/link';
@@ -34,19 +33,22 @@ const LinkList = ({
34
33
  function renderLinkContent(item, index) {
35
34
  const icon = listIcon[index];
36
35
 
37
- const LinkImage = () => (
38
- <LazyImage
39
- src={imagePrettyUrl(
40
- item.image || item.logo?.url?.split('.com/')[1],
41
- width || item?.image_object?.width || item.logo?.width,
42
- height || item?.image_object?.height || item.logo?.height
43
- )}
44
- alt={getAltText(item?.image_object || item.logo, item.title)}
45
- width={width || item?.image_object?.width || item.logo?.width}
46
- height={height || item?.image_object?.height || item.logo?.height}
47
- loading={disableLazyLoad ? 'eager' : 'lazy'}
48
- />
49
- );
36
+ const imgWidth = width || item?.image_object?.width || item.logo?.width;
37
+ const imgHeight = height || item?.image_object?.height || item.logo?.height;
38
+ const imgEl =
39
+ (item.image || item.logo) ? (
40
+ <LazyImage
41
+ src={imagePrettyUrl(
42
+ item.image || item.logo?.url?.split('.com/')[1],
43
+ imgWidth,
44
+ imgHeight
45
+ )}
46
+ alt={getAltText(item?.image_object || item.logo, item.title)}
47
+ width={imgWidth}
48
+ height={imgHeight}
49
+ loading={disableLazyLoad ? 'eager' : 'lazy'}
50
+ />
51
+ ) : null;
50
52
 
51
53
  return (
52
54
  <>
@@ -54,10 +56,10 @@ const LinkList = ({
54
56
  <>
55
57
  {multiIcon ? icon : listIcon}
56
58
  <span>{item.title}</span>
57
- {(item.image || item.logo) && <LinkImage />}
59
+ {imgEl}
58
60
  </>
59
61
  )}
60
- {(item.image || item.logo) && imageOnly && <LinkImage />}
62
+ {imageOnly && imgEl}
61
63
  </>
62
64
  );
63
65
  }
@@ -111,8 +113,12 @@ const LinkList = ({
111
113
  );
112
114
  }
113
115
 
116
+ function getItemKey(item, index) {
117
+ return item?.value || item?.url || item?.title || item?.name || index;
118
+ }
119
+
114
120
  function renderItems(item, index) {
115
- return <li key={keygen()}>{renderLinkWrapper(item, index)}</li>;
121
+ return <li key={getItemKey(item, index)}>{renderLinkWrapper(item, index)}</li>;
116
122
  }
117
123
 
118
124
  const renderSingleList = () => {
@@ -126,13 +132,13 @@ const LinkList = ({
126
132
  };
127
133
 
128
134
  const renderLinklists = () => {
129
- return lists.children.map((list) => {
135
+ return lists.children.map((list, listIndex) => {
130
136
  return (
131
- <ul className={classes || ''} key={keygen()}>
132
- {showListTitle && <li key={keygen()}>{list.title}</li>}
137
+ <ul className={classes || ''} key={list?.title || list?.value || listIndex}>
138
+ {showListTitle && <li key={`title-${list?.title || listIndex}`}>{list.title}</li>}
133
139
  {list.children &&
134
- list.children.map((child) => {
135
- return renderItems(child);
140
+ list.children.map((child, childIndex) => {
141
+ return renderItems(child, childIndex);
136
142
  })}
137
143
  </ul>
138
144
  );
@@ -90,7 +90,7 @@ export default function TemplateOne({
90
90
  <span>
91
91
  {item?.odds_text}
92
92
  {item?.odds_text && item?.odds_value ? ": " : ""}
93
- {item?.odds_value}
93
+ <strong>{item?.odds_value}</strong>
94
94
  </span>
95
95
  </div>
96
96
  )}
@@ -1,5 +1,7 @@
1
- import React, { useRef } from "react";
1
+ import React, { useRef, useState, useEffect } from "react";
2
2
  import PropTypes from "prop-types";
3
+ import { IoIosArrowBack } from "@react-icons/all-files/io/IoIosArrowBack";
4
+ import { IoIosArrowForward } from "@react-icons/all-files/io/IoIosArrowForward";
3
5
  import keygen from "~helpers/keygen";
4
6
  import LazyImage from "~hooks/lazy-image";
5
7
  import Button from "../../../../atoms/button/operator-cta";
@@ -26,104 +28,167 @@ const DEFAULT_CTA_TRANSLATE = {
26
28
  blacklisted: { translationKey: 'blacklisted', defaultValue: 'Blacklisted' }
27
29
  };
28
30
 
31
+ const BUTTON_SCROLL = 300;
32
+
29
33
  export default function TemplateTwo({
30
34
  module,
31
35
  showOperatorHeader = false,
32
36
  ctaTranslate = DEFAULT_CTA_TRANSLATE,
33
37
  }) {
34
38
  const container = useRef(null);
39
+ const [scrollX, setScrollX] = useState(0);
40
+ const [scrollEnd, setScrollEnd] = useState(false);
41
+ const [showButtons, setShowButtons] = useState(false);
42
+
35
43
  const items = module?.items;
36
44
  const ctaText = module?.link_text;
37
45
  const date = useTranslate('date', 'Date:');
38
46
  const funbetLabel = useTranslate('funbet', 'Funbet');
39
47
 
40
- return (
41
- <ScrollX refTag={container} scroll>
42
- <div
43
- ref={container}
44
- className={styles.sportOdds}
45
- // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
46
- tabIndex={0}
47
- >
48
- {(items || []).map((item) => {
49
- const operatorName = item?.relation?.name;
50
- const operatorLogo = item?.relation?.logo;
51
-
52
- return (
53
- <div key={keygen()} className={styles.card}>
54
- <div className={styles.header}>
55
- {
56
- showOperatorHeader ?
57
- <>
58
- {operatorLogo?.url ? (
59
- <LazyImage
60
- src={operatorLogo.url}
61
- width={20}
62
- height={20}
63
- alt={operatorLogo.alt || operatorName}
64
- />
65
- ) : (
66
- <span className={styles.operatorIcon} aria-hidden="true" />
67
- )}
68
- {operatorName && <span>{operatorName}</span>}
69
- </> : <>
70
- <FunIcon />
71
- <span>{funbetLabel}</span>
72
- </>
73
- }
74
- </div>
48
+ const updateButtons = (shift) => {
49
+ setScrollEnd(
50
+ Math.floor(container.current.scrollWidth - (container.current.scrollLeft + shift)) <=
51
+ container.current.offsetWidth
52
+ );
53
+ };
75
54
 
76
- <div className={styles.body}>
77
- <div className={styles.main}>
78
- <div className={styles.info}>
79
- {item?.main_title && (
80
- <p className={styles.title}>{item.main_title}</p>
81
- )}
82
- {item?.secondary_title && (
83
- <p className={styles.time}>{date}<span>{item.secondary_title}</span></p>
84
- )}
85
- </div>
55
+ const scroll = (shift) => {
56
+ container.current.scrollTo({
57
+ left: container.current.scrollLeft + shift,
58
+ behavior: 'smooth',
59
+ });
60
+ updateButtons(shift);
61
+ setScrollX(scrollX + shift);
62
+ };
63
+
64
+ const onStopScrolling = () => {
65
+ setScrollX(container.current.scrollLeft);
66
+ updateButtons(0);
67
+ };
68
+
69
+ const onScroll = (scrollLeft) => {
70
+ updateButtons(0);
71
+ setScrollX(scrollLeft);
72
+ };
73
+
74
+ useEffect(() => {
75
+ const timer = setTimeout(() => {
76
+ if (container.current) {
77
+ setShowButtons(container.current.scrollWidth > container.current.offsetWidth);
78
+ }
79
+ }, 500);
80
+ return () => clearTimeout(timer);
81
+ }, []);
82
+
83
+ return (
84
+ <div className={styles.wrapper}>
85
+ <ScrollX refTag={container} scroll stopScrolling={onStopScrolling} onScroll={onScroll}>
86
+ <div
87
+ ref={container}
88
+ className={styles.sportOdds}
89
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
90
+ tabIndex={0}
91
+ >
92
+ {(items || []).map((item) => {
93
+ const operatorName = item?.relation?.name;
94
+ const operatorLogo = item?.relation?.logo;
86
95
 
87
- <div className={styles.action}>
88
- {(item?.odds_text || item?.odds_value) && (
89
- <div className={styles.odds}>
90
- {operatorLogo?.url && (
96
+ return (
97
+ <div key={keygen()} className={styles.card}>
98
+ <div className={styles.header}>
99
+ {
100
+ showOperatorHeader ?
101
+ <>
102
+ {operatorLogo?.url ? (
91
103
  <LazyImage
92
104
  src={operatorLogo.url}
93
- width={48}
94
- height={48}
105
+ width={20}
106
+ height={20}
95
107
  alt={operatorLogo.alt || operatorName}
96
108
  />
109
+ ) : (
110
+ <span className={styles.operatorIcon} aria-hidden="true" />
97
111
  )}
98
- <span>
99
- {item?.odds_text}
100
- {item?.odds_text && item?.odds_value ? ": " : ""}
101
- {item?.odds_value}
102
- </span>
103
- </div>
104
- )}
105
-
106
- <Button
107
- operator={item?.relation}
108
- buttonType="primary"
109
- buttonSize="m"
110
- btnText={ctaText}
111
- isInternalLink={false}
112
- targetBlank
113
- moduleName={module?.name}
114
- tracker={module?.bonus?.tracking_link_name || 'main'}
115
- translationsObj={ctaTranslate}
116
- />
117
- </div>
112
+ {operatorName && <span>{operatorName}</span>}
113
+ </> : <>
114
+ <FunIcon />
115
+ <span>{funbetLabel}</span>
116
+ </>
117
+ }
118
118
  </div>
119
119
 
120
- <Tnc operator={item?.relation} tracker={item?.bonus?.tracking_link_name} />
120
+ <div className={styles.body}>
121
+ <div className={styles.main}>
122
+ <div className={styles.info}>
123
+ {item?.main_title && (
124
+ <p className={styles.title}>{item.main_title}</p>
125
+ )}
126
+ {item?.secondary_title && (
127
+ <p className={styles.time}>{date}<span>{item.secondary_title}</span></p>
128
+ )}
129
+ </div>
130
+
131
+ <div className={styles.action}>
132
+ {(item?.odds_text || item?.odds_value) && (
133
+ <div className={styles.odds}>
134
+ {operatorLogo?.url && (
135
+ <LazyImage
136
+ src={operatorLogo.url}
137
+ width={48}
138
+ height={48}
139
+ alt={operatorLogo.alt || operatorName}
140
+ />
141
+ )}
142
+ <span>
143
+ {item?.odds_text}
144
+ {item?.odds_text && item?.odds_value ? ": " : ""}
145
+ <strong>{item?.odds_value}</strong>
146
+ </span>
147
+ </div>
148
+ )}
149
+
150
+ <Button
151
+ operator={item?.relation}
152
+ buttonType="primary"
153
+ buttonSize="m"
154
+ btnText={ctaText}
155
+ isInternalLink={false}
156
+ targetBlank
157
+ moduleName={module?.name}
158
+ tracker={module?.bonus?.tracking_link_name || 'main'}
159
+ translationsObj={ctaTranslate}
160
+ />
161
+ </div>
162
+ </div>
163
+
164
+ <Tnc operator={item?.relation} tracker={item?.bonus?.tracking_link_name} />
165
+ </div>
121
166
  </div>
122
- </div>
123
- );
124
- })}
125
- </div>
126
- </ScrollX>
167
+ );
168
+ })}
169
+ </div>
170
+ </ScrollX>
171
+ {showButtons && (
172
+ <div className={styles.navigation}>
173
+ <button
174
+ className={`${styles.navButton} ${scrollX <= 0 ? styles.disabled : ''}`}
175
+ onClick={() => scroll(-BUTTON_SCROLL)}
176
+ type="button"
177
+ aria-label="Previous"
178
+ >
179
+ <IoIosArrowBack />
180
+ </button>
181
+ <button
182
+ className={`${styles.navButton} ${scrollEnd ? styles.disabled : ''}`}
183
+ onClick={() => scroll(BUTTON_SCROLL)}
184
+ type="button"
185
+ aria-label="Next"
186
+ >
187
+ <IoIosArrowForward />
188
+ </button>
189
+ </div>
190
+ )}
191
+ </div>
127
192
  );
128
193
  }
129
194
 
@@ -1,19 +1,80 @@
1
- .sportOdds {
1
+ .wrapper {
2
2
  max-width: var(--main-container-max);
3
3
  margin: 0 auto;
4
4
 
5
+ @include flex-direction(column);
6
+
7
+ gap: 1.6rem;
8
+ }
9
+
10
+ .sportOdds {
5
11
  @include flex-direction(row);
6
12
  @include flex-align(stretch, start);
7
13
 
8
14
  gap: 1.6rem;
9
15
  overflow-x: auto;
10
16
  scroll-snap-type: x mandatory;
11
-
17
+ padding-bottom: 2rem;
18
+
12
19
  &::-webkit-scrollbar {
20
+ height: 0.6rem;
21
+ border-radius: 0.6rem;
22
+
23
+ @include max(mobile) {
24
+ display: none;
25
+ }
26
+ }
27
+
28
+ &::-webkit-scrollbar-track {
29
+ background: var(--spotlight-sport-odds-scrollbar-track, #E4E4E7);
30
+ border-radius: 0.6rem;
31
+ }
32
+
33
+ &::-webkit-scrollbar-thumb {
34
+ background-color: var(--spotlight-sport-odds-scrollbar-thumb, #3F3F46);
35
+ border-radius: 0.6rem;
36
+ }
37
+
38
+ }
39
+
40
+ .navigation {
41
+ @include flex-direction(row);
42
+ @include flex-align(center, flex-start);
43
+
44
+ gap: 0.8rem;
45
+
46
+ @include max(mobile) {
13
47
  display: none;
14
48
  }
15
49
  }
16
50
 
51
+ .navButton {
52
+ @include flex-direction(row);
53
+ @include flex-align(center, center);
54
+
55
+ width: 4rem;
56
+ height: 4rem;
57
+ border-radius: 0.6rem;
58
+ background: var(--spotlight-sport-odds-nav-bg, #E4E4E7);
59
+ border: 0;
60
+ color: var(--spotlight-sport-odds-nav-text, #52525B);
61
+ cursor: pointer;
62
+ padding: 0;
63
+ font-size: 1.6rem;
64
+
65
+ &:hover {
66
+ background: var(--spotlight-sport-odds-nav-hover-bg, #E4E4E7);
67
+ color: var(--spotlight-sport-odds-nav-hover-text, #18181B);
68
+ }
69
+ }
70
+
71
+ .disabled {
72
+ opacity: 0.4;
73
+ cursor: not-allowed;
74
+ pointer-events: none;
75
+ background: var(--spotlight-sport-odds-nav-deactive-bg, #F4F4F5);
76
+ }
77
+
17
78
  .card {
18
79
  flex: 0 0 auto;
19
80
  width: 28rem;
@@ -7,12 +7,14 @@ import PropTypes from "prop-types";
7
7
 
8
8
  import useTranslate from "~hooks/useTranslate/useTranslate";
9
9
  import { setCookie, getCookie } from "~helpers/cookies";
10
- import { Context } from "~context/MainProvider";
10
+ import { Context, CookieVisibilityContext } from "~context/MainProvider";
11
11
  import styles from "./cookie-consent.module.scss";
12
12
 
13
13
  import cookiesContent from '../../../constants/cookies';
14
14
  import { parseCookieTextWithLinks } from '../../../helpers/generators.mjs'
15
15
 
16
+ const CookieModal = lazy(() => import("../../molecules/cookie-modal"));
17
+
16
18
  const CookieConsent = ({
17
19
  settingsCookie,
18
20
  children,
@@ -22,16 +24,13 @@ const CookieConsent = ({
22
24
  showRejectButton = false,
23
25
  }) => {
24
26
  const {
25
- showCookieBanner = false,
26
- showCookieModal = false,
27
27
  openCookieBanner = () => {},
28
28
  openCookieSettings = () => {},
29
29
  closeCookieModal = () => {},
30
30
  closeCookieConsent = () => {},
31
31
  } = useContext(Context)?.cookieConsentContext || {};
32
-
33
- const CookieModal = lazy(() => import("../../molecules/cookie-modal"));
34
-
32
+ const { showCookieBanner = false, showCookieModal = false } =
33
+ useContext(CookieVisibilityContext) || {};
35
34
 
36
35
  const shouldShowRejectButton =
37
36
  typeof cookiesContent.showRejectButton === "boolean"
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable react/prop-types */
2
- import React, { createContext, useState } from "react";
2
+ import React, { createContext, useState, useCallback, useMemo } from "react";
3
3
 
4
4
  const setBodyScrollLock = (locked) => {
5
5
  if (typeof document === "undefined") return;
@@ -7,6 +7,10 @@ const setBodyScrollLock = (locked) => {
7
7
  };
8
8
 
9
9
  export const Context = createContext();
10
+ export const CookieVisibilityContext = createContext({
11
+ showCookieBanner: false,
12
+ showCookieModal: false,
13
+ });
10
14
 
11
15
  export default (props) => {
12
16
  const { value, children } = props;
@@ -14,49 +18,77 @@ export default (props) => {
14
18
  const [showTranslationKeys, setShowTranslationKeys] = useState(false);
15
19
  const [showFilter, setShowFilter] = useState(false);
16
20
  const [topListFilters, setTopListFilters] = useState();
17
- const topListContext = {
18
- showFilter,
19
- setShowFilter,
20
- topListFilters,
21
- setTopListFilters,
22
- };
21
+
22
+ const topListContext = useMemo(
23
+ () => ({
24
+ showFilter,
25
+ setShowFilter,
26
+ topListFilters,
27
+ setTopListFilters,
28
+ }),
29
+ [showFilter, topListFilters]
30
+ );
23
31
 
24
32
  const [showCookieBanner, setShowCookieBanner] = useState(false);
25
33
  const [showCookieModal, setShowCookieModal] = useState(false);
26
34
 
27
- const cookieConsentContext = {
28
- showCookieBanner,
29
- showCookieModal,
30
- openCookieBanner: () => setShowCookieBanner(true),
31
- openCookieSettings: () => {
32
- setShowCookieModal(true);
33
- setBodyScrollLock(true);
34
- },
35
- closeCookieModal: () => {
36
- setShowCookieModal(false);
37
- setBodyScrollLock(false);
38
- },
39
- closeCookieConsent: () => {
40
- setShowCookieBanner(false);
41
- setShowCookieModal(false);
42
- setBodyScrollLock(false);
43
- },
44
- };
35
+ const openCookieBanner = useCallback(() => setShowCookieBanner(true), []);
36
+ const openCookieSettings = useCallback(() => {
37
+ setShowCookieModal(true);
38
+ setBodyScrollLock(true);
39
+ }, []);
40
+ const closeCookieModal = useCallback(() => {
41
+ setShowCookieModal(false);
42
+ setBodyScrollLock(false);
43
+ }, []);
44
+ const closeCookieConsent = useCallback(() => {
45
+ setShowCookieBanner(false);
46
+ setShowCookieModal(false);
47
+ setBodyScrollLock(false);
48
+ }, []);
49
+
50
+ const cookieConsentContext = useMemo(
51
+ () => ({
52
+ openCookieBanner,
53
+ openCookieSettings,
54
+ closeCookieModal,
55
+ closeCookieConsent,
56
+ }),
57
+ [openCookieBanner, openCookieSettings, closeCookieModal, closeCookieConsent]
58
+ );
59
+
60
+ const cookieVisibility = useMemo(
61
+ () => ({ showCookieBanner, showCookieModal }),
62
+ [showCookieBanner, showCookieModal]
63
+ );
64
+
65
+ const contextValue = useMemo(
66
+ () => ({
67
+ translations: value.translations,
68
+ preview: value.isPreview,
69
+ language: value.language,
70
+ admin: value.admin,
71
+ setShowTranslationKeys,
72
+ showTranslationKeys,
73
+ topListContext,
74
+ cookieConsentContext,
75
+ }),
76
+ [
77
+ value.translations,
78
+ value.isPreview,
79
+ value.language,
80
+ value.admin,
81
+ showTranslationKeys,
82
+ topListContext,
83
+ cookieConsentContext,
84
+ ]
85
+ );
45
86
 
46
87
  return (
47
- <Context.Provider
48
- value={{
49
- translations: value.translations,
50
- preview: value.isPreview,
51
- language: value.language,
52
- admin: value.admin,
53
- setShowTranslationKeys,
54
- showTranslationKeys,
55
- topListContext,
56
- cookieConsentContext,
57
- }}
58
- >
59
- {children}
88
+ <Context.Provider value={contextValue}>
89
+ <CookieVisibilityContext.Provider value={cookieVisibility}>
90
+ {children}
91
+ </CookieVisibilityContext.Provider>
60
92
  </Context.Provider>
61
93
  );
62
94
  };