gatsby-core-theme 44.0.41 → 44.1.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,26 @@
1
+ # [44.1.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.0.42...v44.1.0) (2025-05-21)
2
+
3
+
4
+ * Merge branch 'tm-5470-custom-logo-alt' into 'master' ([51d98bb](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/51d98bb106549c47f61540780a5efd592202b67e))
5
+
6
+
7
+ ### Features
8
+
9
+ * custom logo alt ([ddf1164](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/ddf1164ea20a2143dff63a97fff5083293b9bcb8))
10
+
11
+ ## [44.0.42](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.0.41...v44.0.42) (2025-05-21)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * fix test ([033c59d](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/033c59d02855f46fe2b484b1927e9d94c81c28d2))
17
+ * make changes ([0155c8c](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/0155c8c074b0b51b2926d0a1963ffa26db3401c8))
18
+ * remove static logic for IRL ([d51dd66](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/d51dd66f4ef558432b5095940f21a01381e4daa9))
19
+ * remove when content is null ([7ed4f5d](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/7ed4f5daacbe07658ada459dce15abb6394e5e34))
20
+
21
+
22
+ * Merge branch 'tm-5213-head-update' into 'master' ([28abae7](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/28abae7bdf0a46f1e8ac05c06dc6a6914ae4f665))
23
+
1
24
  ## [44.0.41](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.0.40...v44.0.41) (2025-05-20)
2
25
 
3
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-core-theme",
3
- "version": "44.0.41",
3
+ "version": "44.1.0",
4
4
  "description": "Gatsby Theme NPM Package",
5
5
  "author": "",
6
6
  "license": "ISC",
@@ -7,9 +7,9 @@ import { getUrl, getLanguage } from "~helpers/getters";
7
7
  import { getMetaTags, getCanonicalUrl } from "~helpers/head";
8
8
  import customData from "./customData";
9
9
 
10
- const HeadData = ({ page = {}, siteInfo }) => {
10
+ const HeadData = ({ page = {} }) => {
11
11
  const isTracker = page.template === "tracker";
12
- const metaTags = getMetaTags(page, siteInfo, isTracker);
12
+ const metaTags = getMetaTags(page, isTracker);
13
13
  let defaultHref = null;
14
14
 
15
15
  return (
@@ -26,6 +26,7 @@ const Navigation = ({
26
26
  stopScrollOnOpen = true,
27
27
  canOpenAllSubMenus = true,
28
28
  logo = "/images/logo.svg",
29
+ logoAlt = `${process.env.GATSBY_SITE_NAME} logo`,
29
30
  logoWidth = 200,
30
31
  logoHeight = 31,
31
32
  searchIcon = null,
@@ -39,7 +40,6 @@ const Navigation = ({
39
40
  megaMenu = false,
40
41
  menu,
41
42
  }) => {
42
-
43
43
  const navRef = useRef(React.createRef());
44
44
  const { admin } = useContext(Context) || {};
45
45
  const showMenu =
@@ -54,12 +54,7 @@ const Navigation = ({
54
54
  pageTypes[template]?.showLogoWithLink ?? pageTypes.default.showLogoWithLink;
55
55
 
56
56
  const logoImg = (
57
- <img
58
- alt={`${process.env.GATSBY_SITE_NAME} logo`}
59
- src={logo}
60
- width={logoWidth}
61
- height={logoHeight}
62
- />
57
+ <img alt={logoAlt} src={logo} width={logoWidth} height={logoHeight} />
63
58
  );
64
59
 
65
60
  if (stopScrollOnOpen) toggleScroll("", true);
@@ -135,7 +130,9 @@ const Navigation = ({
135
130
  />
136
131
 
137
132
  <div className={styles.navIconContainer}>
138
- {activeMarket && !disableMarketDropdown && <MarketDropdown pageContext={pageContext} />}
133
+ {activeMarket && !disableMarketDropdown && (
134
+ <MarketDropdown pageContext={pageContext} />
135
+ )}
139
136
  {showNotifications && <Notifications section={section} />}
140
137
  {hasCustomComponent && (
141
138
  <CustomComponent
@@ -205,6 +202,7 @@ Navigation.propTypes = {
205
202
  megaMenu: PropTypes.bool,
206
203
  menu: PropTypes.string,
207
204
  logo: PropTypes.string,
205
+ logoAlt: PropTypes.string,
208
206
  logoWidth: PropTypes.number,
209
207
  logoHeight: PropTypes.number,
210
208
  };
@@ -1,43 +1,86 @@
1
- import React from 'react';
2
- import { render, cleanup, waitFor } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
1
+ import React from "react";
2
+ import { render, cleanup, waitFor } from "@testing-library/react";
3
+ import "@testing-library/jest-dom/extend-expect";
4
4
 
5
- import { getNavigationMenus } from '~tests/factories/sections/navigation.factory';
6
- import getPageData from '../../../../tests/factories/pages/default.factory';
7
- import Navigation from '.';
5
+ import { getNavigationMenus } from "~tests/factories/sections/navigation.factory";
6
+ import getPageData from "../../../../tests/factories/pages/default.factory";
7
+ import Navigation from ".";
8
8
 
9
9
  const menuSection = getNavigationMenus(1, 2, true);
10
- const pageContext = {page: getPageData()}
11
- describe('Navigation Component', () => {
12
- test('render navigation', async () => {
13
- const { container } = render(<Navigation pageContext={pageContext} section={menuSection} />);
10
+ const pageContext = { page: getPageData() };
11
+ describe("Navigation Component", () => {
12
+ test("render navigation", async () => {
13
+ const { container } = render(
14
+ <Navigation pageContext={pageContext} section={menuSection} />
15
+ );
14
16
 
15
17
  await waitFor(() => {
16
- expect(container.querySelectorAll('.nav')).toHaveLength(1);
17
- expect(container.querySelectorAll('.logo')).toHaveLength(1);
18
- expect(container.querySelectorAll('.menuContainer')).toHaveLength(1);
19
- expect(container.querySelectorAll('.search')).toHaveLength(1);
18
+ expect(container.querySelectorAll(".nav")).toHaveLength(1);
19
+ expect(container.querySelectorAll(".logo")).toHaveLength(1);
20
+ expect(container.querySelectorAll(".menuContainer")).toHaveLength(1);
21
+ expect(container.querySelectorAll(".search")).toHaveLength(1);
20
22
  });
21
23
  });
22
- test('render navigation when template is ppc', async () => {
23
- const { container } = render(<Navigation pageContext={pageContext} section={menuSection} template="ppc" />);
24
+ test("render navigation when template is ppc", async () => {
25
+ const { container } = render(
26
+ <Navigation
27
+ pageContext={pageContext}
28
+ section={menuSection}
29
+ template="ppc"
30
+ />
31
+ );
24
32
 
25
33
  await waitFor(() => {
26
- expect(container.querySelectorAll('.nav')).toHaveLength(1);
27
- expect(container.querySelectorAll('.logo')).toHaveLength(1);
28
- expect(container.querySelectorAll('.menuContainer')).toHaveLength(0);
29
- expect(container.querySelectorAll('.search')).toHaveLength(0);
34
+ expect(container.querySelectorAll(".nav")).toHaveLength(1);
35
+ expect(container.querySelectorAll(".logo")).toHaveLength(1);
36
+ expect(container.querySelectorAll(".menuContainer")).toHaveLength(0);
37
+ expect(container.querySelectorAll(".search")).toHaveLength(0);
30
38
  });
31
39
  });
32
- test('render navigation without search', async () => {
33
- const { container } = render(<Navigation pageContext={pageContext} section={menuSection} hasSearch={false} />);
40
+ test("render navigation without search", async () => {
41
+ const { container } = render(
42
+ <Navigation
43
+ pageContext={pageContext}
44
+ section={menuSection}
45
+ hasSearch={false}
46
+ />
47
+ );
34
48
 
35
49
  await waitFor(() => {
36
- expect(container.querySelectorAll('.nav')).toHaveLength(1);
37
- expect(container.querySelectorAll('.menuContainer')).toHaveLength(1);
38
- expect(container.querySelectorAll('.search')).toHaveLength(0);
50
+ expect(container.querySelectorAll(".nav")).toHaveLength(1);
51
+ expect(container.querySelectorAll(".menuContainer")).toHaveLength(1);
52
+ expect(container.querySelectorAll(".search")).toHaveLength(0);
39
53
  });
40
54
  });
55
+ test("render navigation with custom logo alt", async () => {
56
+ const { container } = render(
57
+ <Navigation
58
+ pageContext={pageContext}
59
+ section={menuSection}
60
+ hasSearch={false}
61
+ logoAlt="custom logo alt"
62
+ />
63
+ );
64
+
65
+ expect(container.querySelectorAll("img")[0]).toHaveProperty(
66
+ "alt",
67
+ "custom logo alt"
68
+ );
69
+ });
70
+ test("render navigation with default logo alt", async () => {
71
+ const { container } = render(
72
+ <Navigation
73
+ pageContext={pageContext}
74
+ section={menuSection}
75
+ hasSearch={false}
76
+ />
77
+ );
78
+
79
+ expect(container.querySelectorAll("img")[0]).toHaveProperty(
80
+ "alt",
81
+ `${process.env.GATSBY_SITE_NAME} logo`
82
+ );
83
+ });
41
84
  });
42
85
  afterEach(() => {
43
86
  cleanup();
@@ -1,15 +1,71 @@
1
- import { getLanguage,setName } from '~helpers/getters';
2
- import { getRobotOptions, getCanonicalUrl } from '~helpers/head';
3
-
4
-
5
- export default (page, siteInfo, pageImage, isTracker) => [
6
- { type: "meta", name: "description", content: page.meta_description },
7
- { type: "meta", name: "robots", content: getRobotOptions(page.robot_options) },
8
- { type: "meta", property: "og:title", content: page.meta_title },
9
- { type: "meta", property: "og:site_name", content: siteInfo?.site_name ? setName(siteInfo.site_name) : "" },
10
- { type: "meta", property: "og:description", content: page.meta_description },
11
- { type: "meta", property: "og:type", content: page.path === '/' ? 'website' : 'article' },
12
- { type: "meta", property: "og:image", content: pageImage },
13
- { type: "meta", property: "og:url", content: getCanonicalUrl(page, isTracker) },
14
- { type: "meta", property: "og:locale", content: getLanguage(page.language) === 'en' ? 'en_GB' : getLanguage(page.language) },
15
- ];
1
+ /* eslint-disable camelcase */
2
+ import parse from 'html-react-parser';
3
+ import { getLanguage, setName, getPageImage, imagePrettyUrl } from "~helpers/getters";
4
+ import { getRobotOptions, getCanonicalUrl, transformMetaTitle, getTwitterUsername } from "~helpers/head";
5
+
6
+
7
+
8
+ export default (page, isTracker) => {
9
+ const { relation, meta_title, meta_description, relation_type, siteInfo } = page;
10
+ const pageImage = getPageImage(page) || imagePrettyUrl(siteInfo?.site_logo);
11
+ const parsedMetaDescr = meta_description ? parse(meta_description) : '';
12
+ const metaTitle = transformMetaTitle(relation, meta_title, relation_type);
13
+ const twitterUsername = getTwitterUsername(page.siteSchema?.twitter);
14
+
15
+
16
+ return [
17
+ { type: "meta", name: "description", content: page.meta_description },
18
+ {
19
+ type: "meta",
20
+ name: "robots",
21
+ content: getRobotOptions(page.robot_options),
22
+ },
23
+ { type: "meta", property: "og:title", content: metaTitle},
24
+ {
25
+ type: "meta",
26
+ property: "og:site_name",
27
+ content: siteInfo?.site_name ? setName(siteInfo.site_name) : "",
28
+ },
29
+ { type: "meta", property: "og:description", content: parsedMetaDescr },
30
+ {
31
+ type: "meta",
32
+ property: "og:type",
33
+ content: page.path === "/" ? "website" : "article",
34
+ },
35
+ { type: "meta", property: "og:image", content: pageImage },
36
+ {
37
+ type: "meta",
38
+ property: "og:url",
39
+ content: getCanonicalUrl(page, isTracker),
40
+ },
41
+ {
42
+ type: "meta",
43
+ property: "og:locale",
44
+ content:
45
+ getLanguage(page.language) === "en"
46
+ ? "en_GB"
47
+ : getLanguage(page.language),
48
+ },
49
+ { type: "meta", content: process.env.PLACENAME },
50
+ { type: "region", content: process.env.COUNTRY },
51
+ {
52
+ type: "meta",
53
+ name: "facebook-domain-verification",
54
+ content: process.env.FBVERIFACTION,
55
+ },
56
+ {
57
+ type: "meta",
58
+ name: "robots",
59
+ content:
60
+ process.env.GATSBY_ACTIVE_ENV !== "development"
61
+ ? page?.meta_robots?.join(",")
62
+ : null,
63
+ },
64
+ { type: "meta", name: "twitter:title", content: twitterUsername && metaTitle },
65
+ { type: "meta", name: "twitter:description", content: twitterUsername && parsedMetaDescr },
66
+ { type: "meta", name: "twitter:site", content: twitterUsername && `@${twitterUsername}` },
67
+ { type: "meta", name: "twitter:creator", content: twitterUsername && `@${twitterUsername}` },
68
+ { type: "meta", name: "twitter:card", content: twitterUsername && 'summary' },
69
+ { type: "meta", name: "twitter:image", content: twitterUsername && pageImage.replace('/filters:format(webp)', '') },
70
+ ]
71
+ };
@@ -1,17 +1,23 @@
1
1
  import React from "react";
2
- import { getPageImage, imagePrettyUrl } from "~helpers/getters";
2
+ import { getPageImage, imagePrettyUrl, getBonus } from "~helpers/getters";
3
+ import { generatePlaceholderString } from "~helpers/generators";
3
4
  import keygen from "~helpers/keygen";
4
5
  import metaTags from "~constants/metaTags";
5
6
 
6
7
  export const getMetaTags = (page, siteInfo, isTracker) => {
7
8
  const pageImage = getPageImage(page) || imagePrettyUrl(siteInfo?.site_logo);
8
- return metaTags(page, siteInfo, pageImage, isTracker).map((meta) => (
9
- <meta
10
- key={keygen()}
11
- {...(meta.name ? { name: meta.name } : { property: meta.property })}
12
- content={meta.content}
13
- />
14
- ));
9
+ // eslint-disable-next-line array-callback-return
10
+ return metaTags(page, siteInfo, pageImage, isTracker).map((meta) => {
11
+ if (meta?.content) {
12
+ return (
13
+ <meta
14
+ key={keygen()}
15
+ {...(meta.name ? { name: meta.name } : { property: meta.property })}
16
+ content={meta.content}
17
+ />
18
+ );
19
+ }
20
+ });
15
21
  };
16
22
 
17
23
  export function getCanonicalUrl(page, isTracker) {
@@ -49,3 +55,37 @@ export function getRobotOptions(options) {
49
55
  array.push("noindex,follow");
50
56
  return array.join();
51
57
  }
58
+
59
+ export function getLocale(language) {
60
+ if (language) {
61
+ const locale = language.split("_").reverse();
62
+ locale[1] = locale[1].toUpperCase();
63
+ return locale.join("_");
64
+ }
65
+ return null;
66
+ }
67
+
68
+ export function getTwitterUsername(url) {
69
+ // eslint-disable-next-line no-useless-escape
70
+ const regex = /https?:\/\/(www\.)?twitter\.com\/(#!\/)?@?([^\/]*)/;
71
+ const m = regex.exec(url);
72
+
73
+ if (m !== null && m.length >= 3) {
74
+ return m[3];
75
+ }
76
+
77
+ return null;
78
+ }
79
+
80
+ export function transformMetaTitle(relation, metaTitle, type) {
81
+ if (type !== "operator") return metaTitle;
82
+
83
+ switch (metaTitle) {
84
+ case "[OPERATOR_REVIEW_META_TITLE]":
85
+ return `${relation.name} ${generatePlaceholderString("[YEAR]")} ${
86
+ getBonus("main", relation).one_liner
87
+ }`;
88
+ default:
89
+ return metaTitle;
90
+ }
91
+ }
@@ -1,4 +1,4 @@
1
- import {getMetaTags, getCanonicalUrl} from './head';
1
+ import {getMetaTags, getCanonicalUrl, getTwitterUsername, getLocale} from './head';
2
2
 
3
3
  describe('head.js functions', () => {
4
4
  describe('getMetaTags', () => {
@@ -47,4 +47,29 @@ describe('head.js functions', () => {
47
47
  expect(getCanonicalUrl(page, false)).toBe('https://example.com/about');
48
48
  });
49
49
  });
50
+
51
+ describe('getLocale', () => {
52
+ it('returns null when no language is provided', () => {
53
+ expect(getLocale(null)).toBeNull();
54
+ expect(getLocale(undefined)).toBeNull();
55
+ expect(getLocale('')).toBeNull();
56
+ });
57
+
58
+ it('transforms language code correctly', () => {
59
+ expect(getLocale('en_us')).toBe('us_EN');
60
+ });
61
+ });
62
+
63
+ describe('getTwitterUsername', () => {
64
+ it('returns null for invalid Twitter URLs', () => {
65
+ expect(getTwitterUsername('')).toBeNull();
66
+ expect(getTwitterUsername('https://example.com')).toBeNull();
67
+ expect(getTwitterUsername('https://twitter.com')).toBeNull();
68
+ });
69
+
70
+ it('extracts username from various Twitter URL formats', () => {
71
+ expect(getTwitterUsername('https://twitter.com/username')).toBe('username');
72
+ expect(getTwitterUsername('https://www.twitter.com/username')).toBe('username');
73
+ });
74
+ });
50
75
  });