gatsby-core-theme 44.13.4 → 44.14.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ # [44.14.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.13.5...v44.14.0) (2026-02-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * maxchar prop ([0973336](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/09733366c2e2b8f74ed4a9a4e3deafefa719b268))
7
+ * template six ([915270f](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/915270fae542a59dee6732406eeaaa729cef5e68))
8
+ * test ([5d02286](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/5d02286b077906048633287e4630f8d88c75bf55))
9
+ * tests ([4eae4ad](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/4eae4ad3b6e80ee011d3cd98763c0c3f9b911dce))
10
+
11
+
12
+ * Merge branch 'EN-327/spotlight-six' into 'master' ([066cbed](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/066cbed8aa9d8a6288d45294f985a25de88d3b6f))
13
+
14
+
15
+ ### Features
16
+
17
+ * spotlights template six ([0d062e6](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/0d062e68350879bf68fd658d8da8c935becf0ce5))
18
+
19
+ ## [44.13.5](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.13.4...v44.13.5) (2026-02-09)
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * add load more button to cards ([1e157a3](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/1e157a363d185d1016c1024e02bf898207923267))
25
+
26
+
27
+ * Merge branch 'en-54-add-load-more-button-to-cards' into 'master' ([9e81ffc](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/9e81ffc1392c99be916960d4680e5247b4261599))
28
+
1
29
  ## [44.13.4](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.13.3...v44.13.4) (2026-02-06)
2
30
 
3
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-core-theme",
3
- "version": "44.13.4",
3
+ "version": "44.14.0",
4
4
  "description": "Gatsby Theme NPM Package",
5
5
  "author": "",
6
6
  "license": "ISC",
@@ -83,6 +83,11 @@ const Modules = ({ module, page, pageContext, modulePosition }) => {
83
83
  return lazy(() =>
84
84
  import("~molecules/spotlights_v2/image-text/template-five")
85
85
  );
86
+ }
87
+ if (module?.style === "template_six") {
88
+ return lazy(() =>
89
+ import("~molecules/spotlights_v2/image-text/template-six")
90
+ );
86
91
  }
87
92
  return lazy(() =>
88
93
  import("~molecules/spotlights_v2/image-text/template-one")
@@ -94,7 +94,8 @@ describe('Search Component', () => {
94
94
 
95
95
  const button2 = container.querySelector('.customSelectContainer ol li:nth-child(2) button');
96
96
  fireEvent.click(button2);
97
-
97
+ const loadMoreButton = getByText("Load More");
98
+ fireEvent.click(loadMoreButton);
98
99
  // Default Pages
99
100
  expect(getByText('Best Arabic Online Casinos 2024')).toBeInTheDocument();
100
101
  expect(getByText('Best Online Casino Payment Methods For Arab Players In 2024')).toBeInTheDocument();
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import TemplateThree from "../template-three/index"
4
+
5
+ export default function TemplateOne({
6
+ module,
7
+ characterMaxReadMore=300
8
+ }) {
9
+ return (
10
+ <TemplateThree
11
+ readMore={false}
12
+ module={module}
13
+ characterMaxReadMore={characterMaxReadMore}
14
+ />
15
+ );
16
+ }
17
+
18
+ TemplateOne.propTypes = {
19
+ module: PropTypes.shape({
20
+ items: PropTypes.arrayOf(PropTypes.shape({})),
21
+ name: PropTypes.string,
22
+ }).isRequired,
23
+ characterMaxReadMore: PropTypes.number,
24
+ };
@@ -0,0 +1,94 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import React from 'react';
3
+ import {
4
+ Title,
5
+ Description,
6
+ Primary,
7
+ PRIMARY_STORY,
8
+ ArgsTable,
9
+ } from '@storybook/addon-docs/blocks';
10
+ import TemplateOne from '.';
11
+
12
+ export default {
13
+ title: 'Theme/Modules/Spotlight/Image Text/Template Six',
14
+ component: TemplateOne,
15
+ argTypes: {
16
+ buttonType: {
17
+ name: 'buttonType',
18
+ defaultValue: 'secondary',
19
+ options: ['primary', 'secondary', 'tertiary'],
20
+ control: { type: 'radio' },
21
+ },
22
+ buttonSize: {
23
+ name: 'buttonType',
24
+ defaultValue: 'm',
25
+ options: ['xs', 's', 'm', 'l', 'xl', 'noSize'],
26
+ control: { type: 'radio' },
27
+ },
28
+ },
29
+ parameters: {
30
+ docs: {
31
+ description: {
32
+ component: 'A component that shows a list of pros and cons and corresponding icons.',
33
+ },
34
+ page: () => (
35
+ <>
36
+ <Title />
37
+ <Description />
38
+ <Primary />
39
+ <ArgsTable story={PRIMARY_STORY} />
40
+ </>
41
+ ),
42
+ },
43
+ },
44
+ };
45
+
46
+ const Template = (args) => <TemplateOne {...args} />;
47
+
48
+ export const Default = Template.bind({});
49
+ Default.args = {
50
+ module: {
51
+ mode: 'image_text',
52
+ read_more_text: '',
53
+ show_read_more: '1',
54
+ items: [
55
+ {
56
+ image: `1702045256/xl.png`,
57
+ label: `Javier A. Pernia`,
58
+ link: {
59
+ title: null,
60
+ type: 'internal',
61
+ value: `/rizk`,
62
+ },
63
+ link_text: 'Read Review',
64
+ subtitle: 'Senior Content Writer',
65
+ text: `<p>Lorem ipsum dolor sit amet consectetur. Diam justo eu tellus morbi amet suspendisse purus tincidunt. Fermentum with risus felis feugiat scelerisque in convallis id cras. Varius lacus id lacus hendrerit commodo orci loredio dignissim massa mauris massa pellentesque et magna lectus duis. Rhoncus eros enim egestas integer eu duis ullamcorper. Magna dictum suspendisse habitasse massa. Odio viverra sit nisl duis nisl sit. Quam ut tincidunt dui lorem pretium commodo aliquam accumsan. Sagittis ultrices est vitae habitant eget morbi. Eu non ipsum pretium enim eleifend quam ut. At tortor in ut sed ultrices suspendisse bibendum nunc. In odio volutpat scelerisque gravida egestas ut turpis. Ut facilisi massa elit maecenas amet volutpat quis eu.</p>`,
66
+ },
67
+ {
68
+ image: `1702045256/xl.png`,
69
+ label: `Javier A. Pernia`,
70
+ subtitle: 'Senior Content Writer',
71
+ link: {
72
+ title: null,
73
+ type: 'internal',
74
+ value: `/rizk`,
75
+ },
76
+ link_text: 'Read Review',
77
+ text: `<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ullamcorper orci a, nec lacus, viverra. Fusce pellentesque eget vitae, ac nibh sem in neque sagittis. Dapibus ornare egestas sagittis massa arcu est arcu fermentum.</p>`,
78
+ },
79
+ {
80
+ image: `1702045256/xl.png`,
81
+ subtitle: 'Senior Content Writer',
82
+ label: `Javier A. Pernia`,
83
+ link: {
84
+ title: null,
85
+ type: 'internal',
86
+ value: `/rizk`,
87
+ },
88
+ link_text: 'Read Review',
89
+ text: `<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ullamcorper orci a, nec lacus, viverra. Fusce pellentesque eget vitae, ac nibh sem in neque sagittis. Dapibus ornare egestas sagittis massa arcu est arcu fermentum.</p>`,
90
+ },
91
+ ],
92
+ },
93
+ scrollableContent: false,
94
+ };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+
5
+ import TemplateOne from '.';
6
+ import TemplateThree from '../template-three';
7
+ import { getSpotlightItems } from '~tests/factories/modules/spotlights.factory';
8
+
9
+ jest.mock('../template-three', () => jest.fn(() => null));
10
+
11
+ describe('TemplateOne Component', () => {
12
+ test('renders TemplateThree with correct props', () => {
13
+ const moduleMock = getSpotlightItems(3, 'image');
14
+
15
+ render(<TemplateOne module={moduleMock} />);
16
+
17
+ expect(TemplateThree).toHaveBeenCalledTimes(1);
18
+
19
+ expect(TemplateThree).toHaveBeenCalledWith(
20
+ expect.objectContaining({
21
+ readMore: false,
22
+ module: moduleMock,
23
+ characterMaxReadMore:300
24
+ }),
25
+ {}
26
+ );
27
+ });
28
+ });
@@ -18,7 +18,7 @@ export default function TemplateOne({
18
18
  }) {
19
19
  const { items } = module;
20
20
  return (
21
- <div className={styles?.spotlightsImage || ''}>
21
+ <div className={`${styles?.spotlightsImage} ${!readMore ? styles.carouselTemplate : ``}`}>
22
22
  {
23
23
  // eslint-disable-next-line react/prop-types
24
24
  items?.map((res) => {
@@ -1,7 +1,50 @@
1
1
  .spotlightsImage {
2
2
  max-width: var(--main-container-max);
3
3
  margin: 0 auto;
4
+
4
5
  @include flex-direction(column);
5
6
  @include flex-align(center, center);
7
+
6
8
  gap: 1.6rem;
9
+ }
10
+
11
+ .carouselTemplate {
12
+ max-width: var(--main-container-max);
13
+ margin: 0 auto;
14
+ display: flex;
15
+ flex-direction: row;
16
+ overflow-x: scroll;
17
+ gap: 1.6rem;
18
+ justify-content: flex-start;
19
+ padding-bottom: 1.6rem;
20
+
21
+ @include min(tablet) {
22
+ flex-direction: column;
23
+ overflow-x: hidden;
24
+ }
25
+
26
+ &::-webkit-scrollbar {
27
+ height: 6px;
28
+ border-radius: 30px;
29
+ }
30
+
31
+ &::-webkit-scrollbar-track {
32
+ background: #e0e0e2;
33
+ border-radius: 30px;
34
+ }
35
+
36
+ &::-webkit-scrollbar-thumb {
37
+ background-color: #64646D;
38
+ border-radius: 30px;
39
+ }
40
+
41
+ div:first-child {
42
+ div {
43
+ width: 30rem;
44
+
45
+ @include min(tablet) {
46
+ width: 100%;
47
+ }
48
+ }
49
+ }
7
50
  }
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable react-hooks/rules-of-hooks */
2
2
  /* eslint-disable no-nested-ternary */
3
- import React, { useState, useEffect } from 'react';
3
+ import React from "react";
4
4
  import PropTypes from 'prop-types';
5
5
 
6
6
  import Pagination from '~molecules/pagination';
@@ -9,31 +9,26 @@ import Button from '~atoms/button/button';
9
9
 
10
10
  import useTranslate from '~hooks/useTranslate/useTranslate';
11
11
  import styles from './archive.module.scss';
12
+ import useLoadMore from "~hooks/useLoadMore";
12
13
 
13
14
  const Archive = ({ module, page, loadMore, gtmClass = '', anchorLabel, modulePosition, buttonType = 'tertiary', buttonSize = 'm' }) => {
14
- const [moduleItems, setModuleItems] = useState([...module.items]);
15
- const updatedModule = { ...module };
16
- const hasLoadMore = module.pagination_type === 'load_more';
15
+ const hasLoadMore = module.pagination_type === "load_more";
17
16
 
18
- useEffect(() => {
19
- if (module.pagination_type === 'load_more') {
20
- const items = module.items.filter(
21
- (item, index) => index < parseInt(loadMore ? loadMore.limit : 9)
22
- );
23
- setModuleItems(items);
24
- }
25
- }, [module, module.items, loadMore]);
17
+ const {
18
+ items: moduleItems,
19
+ loadMore: loadMoreHandler,
20
+ hasMore,
21
+ } = useLoadMore({
22
+ items: module.items,
23
+ enabled: hasLoadMore,
24
+ initialLimit: loadMore?.limit ?? 9,
25
+ increment: loadMore?.increment ?? 9,
26
+ });
26
27
 
27
- const loadMoreHandler = () => {
28
- let items = [...module.items];
29
- if (items.length > moduleItems.length) {
30
- items = items.filter(
31
- (item, index) => index < moduleItems.length + parseInt(loadMore ? loadMore.increment : 9)
32
- );
33
- setModuleItems(items);
34
- }
28
+ const updatedModule = {
29
+ ...module,
30
+ items: moduleItems,
35
31
  };
36
-
37
32
  const loadMoreText = useTranslate(`load_more_${module?.model_type}`) || useTranslate('load_more', 'Load More');
38
33
 
39
34
  updatedModule.items = moduleItems;
@@ -41,6 +36,7 @@ const Archive = ({ module, page, loadMore, gtmClass = '', anchorLabel, modulePos
41
36
  <>
42
37
  <Items module={updatedModule} page={page} gtmClass={gtmClass} modulePosition={modulePosition}/>
43
38
  {hasLoadMore ? (
39
+ hasMore &&
44
40
  module.items.length > updatedModule.items.length && (
45
41
  <div className={styles.loadMoreWrapper || ''}>
46
42
  <Button
@@ -0,0 +1,33 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ const useLoadMore = ({
4
+ items = [],
5
+ enabled = true,
6
+ initialLimit = 9,
7
+ increment = initialLimit,
8
+ }) => {
9
+ const [visibleItems, setVisibleItems] = useState([]);
10
+
11
+ useEffect(() => {
12
+ if (!enabled) {
13
+ setVisibleItems(items)
14
+ return;
15
+ }
16
+
17
+ setVisibleItems(items.slice(0, initialLimit));
18
+ }, [items, enabled, initialLimit])
19
+
20
+ const loadMore = () => {
21
+ setVisibleItems((prev) => items.slice(0, Math.min(prev.length + increment, items.length)))
22
+ }
23
+
24
+ const hasMore = visibleItems.length < items.length;
25
+
26
+ return {
27
+ items: visibleItems,
28
+ loadMore,
29
+ hasMore
30
+ }
31
+ };
32
+
33
+ export default useLoadMore
@@ -0,0 +1,84 @@
1
+ import { renderHook, act } from "@testing-library/react";
2
+ import useLoadMore from "./index";
3
+
4
+ describe("useLoadMore hook", () => {
5
+ const items = [1, 2, 3, 4, 5, 6];
6
+
7
+ test("returns initial limited items when enabled", () => {
8
+ const { result } = renderHook(() =>
9
+ useLoadMore({
10
+ items,
11
+ enabled: true,
12
+ initialLimit: 3,
13
+ increment: 2,
14
+ })
15
+ );
16
+
17
+ expect(result.current.items).toEqual([1, 2, 3]);
18
+ expect(result.current.hasMore).toBe(true);
19
+ });
20
+
21
+ test("returns all items when disabled", () => {
22
+ const { result } = renderHook(() =>
23
+ useLoadMore({
24
+ items,
25
+ enabled: false,
26
+ initialLimit: 3,
27
+ })
28
+ );
29
+
30
+ expect(result.current.items).toEqual(items);
31
+ expect(result.current.hasMore).toBe(false);
32
+ });
33
+
34
+ test("loadMore increases visible items by increment", () => {
35
+ const { result } = renderHook(() =>
36
+ useLoadMore({
37
+ items,
38
+ initialLimit: 2,
39
+ increment: 2,
40
+ })
41
+ );
42
+
43
+ act(() => {
44
+ result.current.loadMore();
45
+ });
46
+
47
+ expect(result.current.items).toEqual([1, 2, 3, 4]);
48
+ expect(result.current.hasMore).toBe(true);
49
+ });
50
+
51
+ test("loadMore does not exceed total items length", () => {
52
+ const { result } = renderHook(() =>
53
+ useLoadMore({
54
+ items,
55
+ initialLimit: 4,
56
+ increment: 5,
57
+ })
58
+ );
59
+
60
+ act(() => {
61
+ result.current.loadMore();
62
+ });
63
+
64
+ expect(result.current.items).toEqual(items);
65
+ expect(result.current.hasMore).toBe(false);
66
+ });
67
+
68
+ test("hasMore becomes false when all items are visible", () => {
69
+ const { result } = renderHook(() =>
70
+ useLoadMore({
71
+ items,
72
+ initialLimit: 3,
73
+ increment: 3,
74
+ })
75
+ );
76
+
77
+ act(() => {
78
+ result.current.loadMore();
79
+ });
80
+
81
+ expect(result.current.items).toEqual(items);
82
+ expect(result.current.hasMore).toBe(false);
83
+ });
84
+ });