gatsby-matrix-theme 53.28.14 → 53.28.16

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 (44) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +2 -2
  3. package/src/components/atoms/cards/game-cards/ribbons/index.js +30 -0
  4. package/src/components/atoms/cards/game-cards/ribbons/ribbons.module.scss +14 -0
  5. package/src/components/atoms/cards/game-cards/template-five/index.js +6 -0
  6. package/src/components/atoms/cards/game-cards/template-five/template-five.stories.js +15 -0
  7. package/src/components/atoms/cards/game-cards/template-four/index.js +6 -0
  8. package/src/components/atoms/cards/game-cards/template-four/template-four.stories.js +15 -0
  9. package/src/components/atoms/cards/game-cards/template-one/index.js +6 -0
  10. package/src/components/atoms/cards/game-cards/template-one/template-one.stories.js +15 -0
  11. package/src/components/atoms/cards/game-cards/template-one/template-one.test.js +42 -6
  12. package/src/components/atoms/cards/game-cards/template-six/index.js +6 -0
  13. package/src/components/atoms/cards/game-cards/template-six/template-six.stories.js +15 -2
  14. package/src/components/atoms/cards/game-cards/template-three/index.js +6 -0
  15. package/src/components/atoms/cards/game-cards/template-three/template-three.stories.js +15 -0
  16. package/src/components/atoms/cards/game-cards/template-two/index.js +6 -0
  17. package/src/components/atoms/cards/game-cards/template-two/template-two.stories.js +15 -0
  18. package/src/components/molecules/operator-details/index.js +8 -2
  19. package/src/components/molecules/operator-details/operator-details.module.scss +6 -0
  20. package/src/components/molecules/operator-details/operator-details.stories.js +10 -0
  21. package/src/components/molecules/operator-details/operator-details.test.js +15 -0
  22. package/src/components/molecules/toplist/row/variant-one.js +3 -0
  23. package/src/components/molecules/toplist/row/variant-one.stories.js +11 -1
  24. package/src/components/molecules/wagering-calculator/README.md +188 -0
  25. package/src/components/organisms/cards/index.js +24 -3
  26. package/src/components/organisms/cards/template-one/index.js +8 -0
  27. package/src/components/organisms/cards/template-two/index.js +16 -2
  28. package/src/components/organisms/cards/template-two/item/index.js +15 -1
  29. package/src/gatsby-core-theme/components/organisms/toplist/index.js +3 -0
  30. package/src/gatsby-core-theme/components/organisms/toplist/list/index.js +4 -2
  31. package/src/gatsby-core-theme/components/organisms/toplist/toplist.stories.js +10 -0
  32. package/storybook/public/127.99c9e6d4.iframe.bundle.js +1 -0
  33. package/storybook/public/{251.2a8ee5d6.iframe.bundle.js → 251.31f7a99d.iframe.bundle.js} +3 -3
  34. package/storybook/public/{251.2a8ee5d6.iframe.bundle.js.map → 251.31f7a99d.iframe.bundle.js.map} +1 -1
  35. package/storybook/public/{591.6dbd470c.iframe.bundle.js → 591.5653aa66.iframe.bundle.js} +1 -1
  36. package/storybook/public/693.b5f0a394.iframe.bundle.js +1 -0
  37. package/storybook/public/iframe.html +1 -1
  38. package/storybook/public/main.31e21238.iframe.bundle.js +1 -0
  39. package/storybook/public/project.json +1 -1
  40. package/storybook/public/{runtime~main.1bd78bca.iframe.bundle.js → runtime~main.3b29e117.iframe.bundle.js} +1 -1
  41. package/storybook/public/127.0af394fa.iframe.bundle.js +0 -1
  42. package/storybook/public/693.203bbdc7.iframe.bundle.js +0 -1
  43. package/storybook/public/main.f2521572.iframe.bundle.js +0 -1
  44. /package/storybook/public/{251.2a8ee5d6.iframe.bundle.js.LICENSE.txt → 251.31f7a99d.iframe.bundle.js.LICENSE.txt} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [53.28.16](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.28.15...v53.28.16) (2026-10-13)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * enable multiple ribbons for toplist and for slot cards ([5043e77](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/5043e773fb3e42237b82c5ff597a81b6b593164c))
7
+
8
+
9
+ * Merge branch 'EN-720-Ribbons' into 'master' ([4bb4fab](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/4bb4fabc572566d9fabbbeb43c656120fb5f6e69))
10
+
11
+ ## [53.28.15](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.28.14...v53.28.15) (2026-10-08)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * update core version ([cb875dc](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/cb875dc6e127f4554da85e101338d779c71eca64))
17
+
1
18
  ## [53.28.14](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.28.13...v53.28.14) (2026-09-24)
2
19
 
3
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-matrix-theme",
3
- "version": "53.28.14",
3
+ "version": "53.28.16",
4
4
  "main": "index.js",
5
5
  "description": "Matrix Theme NPM Package",
6
6
  "author": "",
@@ -26,7 +26,7 @@
26
26
  "@gigmedia/enigma-utils": "^1.20.0",
27
27
  "@react-icons/all-files": "^4.1.0",
28
28
  "gatsby": "^5.11.0",
29
- "gatsby-core-theme": "44.35.12",
29
+ "gatsby-core-theme": "44.35.13",
30
30
  "gatsby-plugin-sharp": "^5.11.0",
31
31
  "gatsby-plugin-sitemap": "^6.13.1",
32
32
  "gatsby-transformer-sharp": "^5.11.0",
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Ribbons from '~atoms/ribbons';
4
+ import styles from './ribbons.module.scss';
5
+
6
+ export default function GameCardRibbons({ item, showRibbon = false, multipleRibbons = false }) {
7
+ if (!showRibbon) return null;
8
+
9
+ const ribbons = item?.relation?.ribbons || item?.ribbons || [];
10
+ if (!Array.isArray(ribbons) || ribbons.length === 0) return null;
11
+
12
+ const visibleRibbons = multipleRibbons ? ribbons : ribbons.slice(0, 1);
13
+
14
+ return (
15
+ <div className={styles.ribbon || ''}>
16
+ <Ribbons item={visibleRibbons} />
17
+ </div>
18
+ );
19
+ }
20
+
21
+ GameCardRibbons.propTypes = {
22
+ item: PropTypes.shape({
23
+ ribbons: PropTypes.arrayOf(PropTypes.string),
24
+ relation: PropTypes.shape({
25
+ ribbons: PropTypes.arrayOf(PropTypes.string),
26
+ }),
27
+ }),
28
+ showRibbon: PropTypes.bool,
29
+ multipleRibbons: PropTypes.bool,
30
+ };
@@ -0,0 +1,14 @@
1
+ .ribbon {
2
+ position: absolute;
3
+ top: 2.4rem;
4
+ left: 2.4rem;
5
+ z-index: 2;
6
+ max-width: calc(100% - 4.8rem);
7
+ pointer-events: none;
8
+
9
+ > div {
10
+ position: static;
11
+ flex-wrap: wrap;
12
+ max-width: 100%;
13
+ }
14
+ }
@@ -12,6 +12,7 @@ import LazyImage from '~hooks/lazy-image';
12
12
  import { getAltText } from '~helpers/image';
13
13
  import useTranslate from '~hooks/useTranslate/useTranslate';
14
14
  import { TrackingKeys } from '~constants/tracking-api';
15
+ import GameCardRibbons from '../ribbons';
15
16
 
16
17
  import styles from './template-five.module.scss';
17
18
 
@@ -29,6 +30,8 @@ const TemplateFive = ({
29
30
  showRoundedRating = false,
30
31
  modulePosition,
31
32
  itemPosition,
33
+ showRibbon = false,
34
+ multipleRibbons = false,
32
35
  }) => {
33
36
  const { relation, path, banner } = item;
34
37
  const { name } = relation || {};
@@ -141,6 +144,7 @@ const TemplateFive = ({
141
144
  )}
142
145
  </div>
143
146
  </div>
147
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
144
148
  </div>
145
149
  );
146
150
  };
@@ -190,6 +194,8 @@ TemplateFive.propTypes = {
190
194
  showRoundedRating: PropTypes.bool,
191
195
  modulePosition: PropTypes.number,
192
196
  itemPosition: PropTypes.number,
197
+ showRibbon: PropTypes.bool,
198
+ multipleRibbons: PropTypes.bool,
193
199
  };
194
200
 
195
201
  export default TemplateFive;
@@ -23,6 +23,20 @@ export default {
23
23
  },
24
24
  description: 'The translations object',
25
25
  },
26
+ argTypes: {
27
+ showRibbon: {
28
+ name: 'showRibbon',
29
+ type: { name: 'boolean', required: false },
30
+ defaultValue: false,
31
+ description: 'Show ribbons. Off by default.',
32
+ },
33
+ multipleRibbons: {
34
+ name: 'multipleRibbons',
35
+ type: { name: 'boolean', required: false },
36
+ defaultValue: false,
37
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
38
+ },
39
+ },
26
40
  };
27
41
 
28
42
  const Template = (args) => <TemplateFive {...args} />;
@@ -50,6 +64,7 @@ Default.args = {
50
64
  name: 'Wildz',
51
65
  path: 'wildz-casino',
52
66
  },
67
+ ribbons: ['New', 'Exclusive'],
53
68
  },
54
69
  },
55
70
  translations: {
@@ -12,6 +12,7 @@ import Link from '~hooks/link';
12
12
  import LazyImage from '~hooks/lazy-image';
13
13
  import useTranslate from '~hooks/useTranslate/useTranslate';
14
14
  import { TrackingKeys } from '~constants/tracking-api';
15
+ import GameCardRibbons from '../ribbons';
15
16
  import styles from './template-four.module.scss';
16
17
 
17
18
  const TemplateFour = ({
@@ -27,6 +28,8 @@ const TemplateFour = ({
27
28
  showRoundedRating = false,
28
29
  modulePosition,
29
30
  itemPosition,
31
+ showRibbon = false,
32
+ multipleRibbons = false,
30
33
  }) => {
31
34
  const { relation, path, banner } = item;
32
35
  const { name } = relation || {};
@@ -127,6 +130,7 @@ const TemplateFour = ({
127
130
  )}
128
131
  </div>
129
132
  </div>
133
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
130
134
  </div>
131
135
  );
132
136
  };
@@ -170,6 +174,8 @@ TemplateFour.propTypes = {
170
174
  showRoundedRating: PropTypes.bool,
171
175
  modulePosition: PropTypes.number,
172
176
  itemPosition: PropTypes.number,
177
+ showRibbon: PropTypes.bool,
178
+ multipleRibbons: PropTypes.bool,
173
179
  };
174
180
 
175
181
  export default TemplateFour;
@@ -22,6 +22,20 @@ export default {
22
22
  },
23
23
  description: 'The translations object',
24
24
  },
25
+ argTypes: {
26
+ showRibbon: {
27
+ name: 'showRibbon',
28
+ type: { name: 'boolean', required: false },
29
+ defaultValue: false,
30
+ description: 'Show ribbons. Off by default.',
31
+ },
32
+ multipleRibbons: {
33
+ name: 'multipleRibbons',
34
+ type: { name: 'boolean', required: false },
35
+ defaultValue: false,
36
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
37
+ },
38
+ },
25
39
  };
26
40
 
27
41
  const Template = (args) => <TemplateFour {...args} />;
@@ -38,6 +52,7 @@ Default.args = {
38
52
  name: 'NetEnt',
39
53
  path: 'netent-casinos',
40
54
  },
55
+ ribbons: ['New', 'Exclusive'],
41
56
  },
42
57
  },
43
58
  translations: {
@@ -11,6 +11,7 @@ import Link from '~hooks/link';
11
11
  import LazyImage from '~hooks/lazy-image';
12
12
  import useTranslate from '~hooks/useTranslate/useTranslate';
13
13
  import { TrackingKeys } from '~constants/tracking-api';
14
+ import GameCardRibbons from '../ribbons';
14
15
  import styles from './template-one.module.scss';
15
16
 
16
17
  const TemplateOne = ({
@@ -26,6 +27,8 @@ const TemplateOne = ({
26
27
  itemPosition,
27
28
  moduleStyle,
28
29
  showImageAsLink = true,
30
+ showRibbon = false,
31
+ multipleRibbons = false,
29
32
  }) => {
30
33
  const { relation, path, banner } = item;
31
34
  const { name } = relation || {};
@@ -143,6 +146,7 @@ const TemplateOne = ({
143
146
  />
144
147
  )}
145
148
  </div>
149
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
146
150
  </div>
147
151
  );
148
152
  };
@@ -187,6 +191,8 @@ TemplateOne.propTypes = {
187
191
  itemPosition: PropTypes.number,
188
192
  moduleStyle: PropTypes.string,
189
193
  showImageAsLink: PropTypes.bool,
194
+ showRibbon: PropTypes.bool,
195
+ multipleRibbons: PropTypes.bool,
190
196
  };
191
197
 
192
198
  export default TemplateOne;
@@ -22,6 +22,20 @@ export default {
22
22
  },
23
23
  description: 'The translations object',
24
24
  },
25
+ argTypes: {
26
+ showRibbon: {
27
+ name: 'showRibbon',
28
+ type: { name: 'boolean', required: false },
29
+ defaultValue: false,
30
+ description: 'Show ribbons. Off by default.',
31
+ },
32
+ multipleRibbons: {
33
+ name: 'multipleRibbons',
34
+ type: { name: 'boolean', required: false },
35
+ defaultValue: false,
36
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
37
+ },
38
+ },
25
39
  };
26
40
 
27
41
  const Template = (args) => <TemplateOne {...args} />;
@@ -38,6 +52,7 @@ Default.args = {
38
52
  name: 'NetEnt',
39
53
  path: 'netent-casinos',
40
54
  },
55
+ ribbons: ['New', 'Exclusive'],
41
56
  },
42
57
  },
43
58
  translations: {
@@ -17,9 +17,9 @@ describe('Game Cards', () => {
17
17
  };
18
18
 
19
19
  const { container, getByText } = render(<TemplateOne item={card} />);
20
- expect(getByText('Wildz Casino')).toBeTruthy();
21
- expect(getByText('Test Game Provider')).toBeTruthy();
22
- expect(getByText('Play now')).toBeTruthy();
20
+ expect(getByText('Wildz Casino')).toBeInTheDocument();
21
+ expect(getByText('Test Game Provider')).toBeInTheDocument();
22
+ expect(getByText('Play now')).toBeInTheDocument();
23
23
  expect(container.querySelectorAll('a')).toHaveLength(4);
24
24
  });
25
25
  test('Template One Operator', () => {
@@ -33,11 +33,47 @@ describe('Game Cards', () => {
33
33
  };
34
34
 
35
35
  const { container, getByText } = render(<TemplateOne useOneStarRating={false} item={card} />);
36
- expect(getByText('Wildz Casino')).toBeTruthy();
37
- expect(getByText('Test Game Operator')).toBeTruthy();
38
- expect(getByText('Play now')).toBeTruthy();
36
+ expect(getByText('Wildz Casino')).toBeInTheDocument();
37
+ expect(getByText('Test Game Operator')).toBeInTheDocument();
38
+ expect(getByText('Play now')).toBeInTheDocument();
39
39
  expect(container.querySelectorAll('a')).toHaveLength(4);
40
40
  });
41
+
42
+ test('hides ribbons unless showRibbon is set', () => {
43
+ const card = getSampleOperatorCards().items[0];
44
+ card.relation = {
45
+ ...card.relation,
46
+ ribbons: ['New', 'Exclusive'],
47
+ };
48
+
49
+ const { queryByText } = render(<TemplateOne item={card} />);
50
+ expect(queryByText('New')).not.toBeInTheDocument();
51
+ expect(queryByText('Exclusive')).not.toBeInTheDocument();
52
+ });
53
+
54
+ test('shows only the first ribbon when showRibbon is true', () => {
55
+ const card = getSampleOperatorCards().items[0];
56
+ card.relation = {
57
+ ...card.relation,
58
+ ribbons: ['New', 'Exclusive'],
59
+ };
60
+
61
+ const { getByText, queryByText } = render(<TemplateOne item={card} showRibbon />);
62
+ expect(getByText('New')).toBeInTheDocument();
63
+ expect(queryByText('Exclusive')).not.toBeInTheDocument();
64
+ });
65
+
66
+ test('shows every ribbon when multipleRibbons is true', () => {
67
+ const card = getSampleOperatorCards().items[0];
68
+ card.relation = {
69
+ ...card.relation,
70
+ ribbons: ['New', 'Exclusive'],
71
+ };
72
+
73
+ const { getByText } = render(<TemplateOne item={card} showRibbon multipleRibbons />);
74
+ expect(getByText('New')).toBeInTheDocument();
75
+ expect(getByText('Exclusive')).toBeInTheDocument();
76
+ });
41
77
  });
42
78
 
43
79
  afterEach(() => {
@@ -8,6 +8,7 @@ import LazyImage from 'gatsby-core-theme/src/hooks/lazy-image';
8
8
  import { formatDate } from '~helpers/date-time';
9
9
 
10
10
  import useTranslate from '~hooks/useTranslate/useTranslate';
11
+ import GameCardRibbons from '../ribbons';
11
12
  import styles from './template-six.module.scss';
12
13
 
13
14
  const TemplateSix = ({
@@ -19,6 +20,8 @@ const TemplateSix = ({
19
20
  verifyIcon = '',
20
21
  showImageAsLink = false,
21
22
  showByLabel = false,
23
+ showRibbon = false,
24
+ multipleRibbons = false,
22
25
  }) => {
23
26
  const { title, path, relation, author } = item;
24
27
  const date = item?.updated_at || item?.created_at;
@@ -93,6 +96,7 @@ const TemplateSix = ({
93
96
  </div>
94
97
  )}
95
98
  </>
99
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
96
100
  </div>
97
101
  );
98
102
  };
@@ -124,6 +128,8 @@ TemplateSix.propTypes = {
124
128
  verifyIcon: PropTypes.string,
125
129
  showImageAsLink: PropTypes.bool,
126
130
  showByLabel: PropTypes.bool,
131
+ showRibbon: PropTypes.bool,
132
+ multipleRibbons: PropTypes.bool,
127
133
  };
128
134
 
129
135
  export default TemplateSix;
@@ -47,8 +47,20 @@ export default {
47
47
  play_now_slots: 'Play Slots LANG',
48
48
  },
49
49
  description: 'The translations object',
50
- }
51
- }
50
+ },
51
+ showRibbon: {
52
+ name: 'showRibbon',
53
+ type: { name: 'boolean', required: false },
54
+ defaultValue: false,
55
+ description: 'Show ribbons. Off by default.',
56
+ },
57
+ multipleRibbons: {
58
+ name: 'multipleRibbons',
59
+ type: { name: 'boolean', required: false },
60
+ defaultValue: false,
61
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
62
+ },
63
+ },
52
64
  };
53
65
 
54
66
  const Template = (args) => (
@@ -79,6 +91,7 @@ Default.args = {
79
91
  name: 'NetEnt',
80
92
  path: 'netent-casinos',
81
93
  },
94
+ ribbons: ['New', 'Exclusive'],
82
95
  },
83
96
  },
84
97
  translations: {
@@ -12,6 +12,7 @@ import Link from '~hooks/link';
12
12
  import LazyImage from '~hooks/lazy-image';
13
13
  import useTranslate from '~hooks/useTranslate/useTranslate';
14
14
  import { TrackingKeys } from '~constants/tracking-api';
15
+ import GameCardRibbons from '../ribbons';
15
16
  import styles from './template-three.module.scss';
16
17
 
17
18
  const TemplateThree = ({
@@ -27,6 +28,8 @@ const TemplateThree = ({
27
28
  showRoundedRating = false,
28
29
  modulePosition,
29
30
  itemPosition,
31
+ showRibbon = false,
32
+ multipleRibbons = false,
30
33
  }) => {
31
34
  const { relation, path, banner } = item;
32
35
  const { name } = relation || {};
@@ -126,6 +129,7 @@ const TemplateThree = ({
126
129
  )}
127
130
  </div>
128
131
  </div>
132
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
129
133
  </div>
130
134
  );
131
135
  };
@@ -173,6 +177,8 @@ TemplateThree.propTypes = {
173
177
  showRoundedRating: PropTypes.bool,
174
178
  modulePosition: PropTypes.number,
175
179
  itemPosition: PropTypes.number,
180
+ showRibbon: PropTypes.bool,
181
+ multipleRibbons: PropTypes.bool,
176
182
  };
177
183
 
178
184
  export default TemplateThree;
@@ -22,6 +22,20 @@ export default {
22
22
  },
23
23
  description: 'The translations object',
24
24
  },
25
+ argTypes: {
26
+ showRibbon: {
27
+ name: 'showRibbon',
28
+ type: { name: 'boolean', required: false },
29
+ defaultValue: false,
30
+ description: 'Show ribbons. Off by default.',
31
+ },
32
+ multipleRibbons: {
33
+ name: 'multipleRibbons',
34
+ type: { name: 'boolean', required: false },
35
+ defaultValue: false,
36
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
37
+ },
38
+ },
25
39
  };
26
40
 
27
41
  const Template = (args) => <TemplateThree {...args} />;
@@ -38,6 +52,7 @@ Default.args = {
38
52
  name: 'NetEnt',
39
53
  path: 'netent-casinos',
40
54
  },
55
+ ribbons: ['New', 'Exclusive'],
41
56
  },
42
57
  },
43
58
  translations: {
@@ -12,6 +12,7 @@ import Link from '~hooks/link';
12
12
  import LazyImage from '~hooks/lazy-image';
13
13
  import useTranslate from '~hooks/useTranslate/useTranslate';
14
14
  import { TrackingKeys } from '~constants/tracking-api';
15
+ import GameCardRibbons from '../ribbons';
15
16
  import styles from './template-two.module.scss';
16
17
 
17
18
  const TemplateTwo = ({
@@ -27,6 +28,8 @@ const TemplateTwo = ({
27
28
  showRoundedRating = false,
28
29
  modulePosition,
29
30
  itemPosition,
31
+ showRibbon = false,
32
+ multipleRibbons = false,
30
33
  }) => {
31
34
  const { relation, path, banner } = item;
32
35
  const { name } = relation || {};
@@ -131,6 +134,7 @@ const TemplateTwo = ({
131
134
  )}
132
135
  </div>
133
136
  </div>
137
+ <GameCardRibbons item={item} showRibbon={showRibbon} multipleRibbons={multipleRibbons} />
134
138
  </div>
135
139
  );
136
140
  };
@@ -178,6 +182,8 @@ TemplateTwo.propTypes = {
178
182
  showRoundedRating: PropTypes.bool,
179
183
  modulePosition: PropTypes.number,
180
184
  itemPosition: PropTypes.number,
185
+ showRibbon: PropTypes.bool,
186
+ multipleRibbons: PropTypes.bool,
181
187
  };
182
188
 
183
189
  export default TemplateTwo;
@@ -22,6 +22,20 @@ export default {
22
22
  },
23
23
  description: 'The translations object',
24
24
  },
25
+ argTypes: {
26
+ showRibbon: {
27
+ name: 'showRibbon',
28
+ type: { name: 'boolean', required: false },
29
+ defaultValue: false,
30
+ description: 'Show ribbons. Off by default.',
31
+ },
32
+ multipleRibbons: {
33
+ name: 'multipleRibbons',
34
+ type: { name: 'boolean', required: false },
35
+ defaultValue: false,
36
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
37
+ },
38
+ },
25
39
  };
26
40
 
27
41
  const Template = (args) => <TemplateTwo {...args} />;
@@ -38,6 +52,7 @@ Default.args = {
38
52
  name: 'NetEnt',
39
53
  path: 'netent-casinos',
40
54
  },
55
+ ribbons: ['New', 'Exclusive'],
41
56
  },
42
57
  },
43
58
  translations: {
@@ -28,6 +28,7 @@ const OperatorDetails = ({
28
28
  showReviewLink = true,
29
29
  showAuthorAsLink = true,
30
30
  showRibbon = false,
31
+ multipleRibbons = false,
31
32
  contentRibbon = false,
32
33
  useOneStarRating = true,
33
34
  showRatingLabel = false,
@@ -58,6 +59,10 @@ const OperatorDetails = ({
58
59
  const itemName = item?.name || item?.relation?.name;
59
60
  const status = item?.status || item?.relation?.status;
60
61
  const hasRibbons = typeof ribbons !== 'undefined' && ribbons.length > 0;
62
+ let visibleRibbons = [];
63
+ if (hasRibbons) {
64
+ visibleRibbons = multipleRibbons ? ribbons : [ribbons[0]];
65
+ }
61
66
  const trackerType = tracker.toLowerCase().replace(' ', '_');
62
67
 
63
68
  const image = item?.logo;
@@ -101,7 +106,7 @@ const OperatorDetails = ({
101
106
  (status === 'active'
102
107
  ? hasRibbons && (
103
108
  <Ribbons
104
- item={[ribbons[0]]}
109
+ item={visibleRibbons}
105
110
  customStyle={`${styles.ribbon} ${contentRibbon && styles.contentRibbon}`}
106
111
  />
107
112
  )
@@ -130,7 +135,7 @@ const OperatorDetails = ({
130
135
  (status === 'active'
131
136
  ? hasRibbons && (
132
137
  <Ribbons
133
- item={[ribbons[0]]}
138
+ item={visibleRibbons}
134
139
  customStyle={`${styles.ribbon} ${contentRibbon && styles.contentRibbon}`}
135
140
  />
136
141
  )
@@ -244,6 +249,7 @@ OperatorDetails.propTypes = {
244
249
  showAuthorAsLink: PropTypes.bool,
245
250
  authorTemplateTwo: PropTypes.bool,
246
251
  showRibbon: PropTypes.bool,
252
+ multipleRibbons: PropTypes.bool,
247
253
  template: PropTypes.string,
248
254
  imageWidth: PropTypes.number,
249
255
  imageHeight: PropTypes.number,
@@ -28,6 +28,12 @@
28
28
  position: static;
29
29
  }
30
30
 
31
+ .ribbon {
32
+ flex-wrap: wrap;
33
+ row-gap: 0.4rem;
34
+ max-width: 28rem;
35
+ }
36
+
31
37
  .operatorName {
32
38
  font-size: 1.8rem;
33
39
  font-weight: 700;
@@ -29,6 +29,16 @@ export default {
29
29
  ribbons: {
30
30
  defaultValue: ['Test'],
31
31
  },
32
+ showRibbon: {
33
+ control: 'boolean',
34
+ defaultValue: false,
35
+ description: 'Show ribbons',
36
+ },
37
+ multipleRibbons: {
38
+ control: 'boolean',
39
+ defaultValue: false,
40
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
41
+ },
32
42
  link: {
33
43
  control: 'text',
34
44
  defaultValue: 'https://example.com',
@@ -58,6 +58,21 @@ describe('OperatorDetails', () => {
58
58
  // });
59
59
  // });
60
60
 
61
+ it('shows only the first ribbon unless multipleRibbons is set', () => {
62
+ const item = { ...mockItem, status: 'active' };
63
+ const { getByText, queryByText, rerender } = render(
64
+ <OperatorDetails item={item} ribbons={['New', 'Exclusive']} showRibbon />
65
+ );
66
+
67
+ expect(getByText('New')).toBeInTheDocument();
68
+ expect(queryByText('Exclusive')).not.toBeInTheDocument();
69
+
70
+ rerender(<OperatorDetails item={item} ribbons={['New', 'Exclusive']} showRibbon multipleRibbons />);
71
+
72
+ expect(getByText('New')).toBeInTheDocument();
73
+ expect(getByText('Exclusive')).toBeInTheDocument();
74
+ });
75
+
61
76
  it('does not display author information when showAuthor is false', async () => {
62
77
  const { queryByText } = render(
63
78
  <OperatorDetails item={mockItem} itemName={mockItemName} showAuthor={false} />
@@ -33,6 +33,7 @@ export default function Row({
33
33
  height = 96,
34
34
  modulePosition,
35
35
  itemPosition,
36
+ multipleRibbons = false,
36
37
  }) {
37
38
  const sellingPoints = item.selling_points;
38
39
  const { ribbons } = item;
@@ -60,6 +61,7 @@ export default function Row({
60
61
  authorTemplateTwo={!!((layout === 'grid' && firstRowItems) || authorTemplateTwo)}
61
62
  ribbons={ribbons}
62
63
  showRibbon
64
+ multipleRibbons={multipleRibbons}
63
65
  icon={verifyIcon}
64
66
  isPPC={isPPC}
65
67
  moduleName={moduleName}
@@ -150,4 +152,5 @@ Row.propTypes = {
150
152
  isPPC: PropTypes.bool,
151
153
  width: PropTypes.number,
152
154
  height: PropTypes.number,
155
+ multipleRibbons: PropTypes.bool,
153
156
  };
@@ -19,7 +19,7 @@ export default {
19
19
  item: {
20
20
  name: 'item',
21
21
  type: { name: 'object', required: true },
22
- defaultValue: getToplistItem(),
22
+ defaultValue: { ...getToplistItem(), ribbons: ['Exclusive Bonus', 'New'] },
23
23
  description: 'toplist item',
24
24
  },
25
25
  tracker: {
@@ -104,6 +104,16 @@ export default {
104
104
  defaultValue: <VerifiedAuthor />,
105
105
  description: 'Show the correct author',
106
106
  },
107
+ multipleRibbons: {
108
+ name: 'multipleRibbons',
109
+ type: { name: 'boolean', required: false },
110
+ defaultValue: false,
111
+ description: 'Show every ribbon. Off by default, so only the first ribbon is shown.',
112
+ table: {
113
+ type: { summary: 'boolean' },
114
+ defaultValue: { summary: false },
115
+ },
116
+ },
107
117
  },
108
118
  parameters: {
109
119
  docs: {