gatsby-theme-q3 3.1.5 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. package/CHANGELOG.md +75 -36
  2. package/gatsby-browser.js +29 -0
  3. package/gatsby-config.js +7 -47
  4. package/gatsby-node.js +0 -1
  5. package/lib/components/FormBoxContent.js +2 -1
  6. package/lib/components/PageWrapper.js +2 -11
  7. package/lib/components/PublicTemplate.js +130 -6
  8. package/lib/components/SearchEngine.js +67 -20
  9. package/lib/components/Wrapper.js +3 -25
  10. package/lib/components/__tests__/SearchEngine.test.js +41 -0
  11. package/lib/components/useSiteMetaData.js +13 -12
  12. package/lib/components/withPublicTemplate.js +17 -0
  13. package/lib/components/withSuccessOp.js +1 -1
  14. package/lib/pages/login.js +7 -4
  15. package/lib/pages/password-change.js +4 -3
  16. package/lib/pages/password-reset.js +4 -3
  17. package/lib/pages/reverify.js +5 -2
  18. package/lib/pages/verify.js +5 -3
  19. package/package.json +6 -6
  20. package/src/components/FormBoxContent.jsx +1 -1
  21. package/src/components/PageWrapper.jsx +1 -13
  22. package/src/components/PublicTemplate.jsx +134 -5
  23. package/src/components/SearchEngine.jsx +82 -23
  24. package/src/components/Wrapper.jsx +3 -27
  25. package/src/components/__tests__/SearchEngine.test.jsx +58 -0
  26. package/src/components/useSiteMetaData.js +17 -16
  27. package/src/components/withPublicTemplate.jsx +11 -0
  28. package/src/components/withSuccessOp.jsx +1 -1
  29. package/src/pages/login.jsx +55 -43
  30. package/src/pages/password-change.jsx +5 -3
  31. package/src/pages/password-reset.jsx +5 -3
  32. package/src/pages/reverify.jsx +4 -2
  33. package/src/pages/verify.jsx +9 -12
  34. package/__tests__/config.int.test.js +0 -73
  35. package/helpers/__tests__/loadContent.unit.test.js +0 -13
  36. package/helpers/__tests__/pagination.unit.test.js +0 -139
  37. package/helpers/__tests__/slug.unit.test.js +0 -21
  38. package/helpers/archive.js +0 -42
  39. package/helpers/index.js +0 -19
  40. package/helpers/loadContent.js +0 -45
  41. package/helpers/loadTheme.js +0 -10
  42. package/helpers/pagination.js +0 -109
  43. package/helpers/setup.js +0 -60
  44. package/helpers/slug.js +0 -31
  45. package/helpers/slugType.js +0 -24
  46. package/lib/components/LocaleBundles.js +0 -42
  47. package/lib/components/useLocale.js +0 -31
  48. package/src/components/LocaleBundles.jsx +0 -37
  49. package/src/components/useLocale.js +0 -20
@@ -9,19 +9,20 @@ var _lodash = require("lodash");
9
9
 
10
10
  var _gatsby = require("gatsby");
11
11
 
12
- var _default = () => (0, _lodash.get)((0, _gatsby.useStaticQuery)((0, _gatsby.graphql)`
13
- query {
14
- site {
15
- siteMetadata {
16
- appDirectory
17
- brand
18
- description
19
- favicon
20
- logo
21
- title
12
+ var _useRunTime = _interopRequireDefault(require("gatsby-theme-q3-mui/src/components/useRunTime"));
13
+
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+
16
+ var _default = () => (0, _lodash.merge)((0, _lodash.get)((0, _gatsby.useStaticQuery)((0, _gatsby.graphql)`
17
+ query {
18
+ site {
19
+ siteMetadata {
20
+ appDirectory
21
+ description
22
+ title
23
+ }
22
24
  }
23
25
  }
24
- }
25
- `), 'site.siteMetadata', {});
26
+ `), 'site.siteMetadata', {}), (0, _useRunTime.default)());
26
27
 
27
28
  exports.default = _default;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = _interopRequireDefault(require("react"));
9
+
10
+ var _PublicTemplate = _interopRequireDefault(require("./PublicTemplate"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const withPublicTemplate = Component => props => /*#__PURE__*/_react.default.createElement(_PublicTemplate.default, props, /*#__PURE__*/_react.default.createElement(Component, props));
15
+
16
+ var _default = withPublicTemplate;
17
+ exports.default = _default;
@@ -41,7 +41,7 @@ const withSuccessOp = (Component, msg) => {
41
41
  component: _gatsby.Link,
42
42
  to: "/login",
43
43
  variant: "contained",
44
- color: "primary"
44
+ color: "secondary"
45
45
  }, t('labels:login'))) : /*#__PURE__*/_react.default.createElement(Component, _extends({}, props, {
46
46
  onSuccess: (0, _utils.toOp)(pathname)
47
47
  }));
@@ -27,9 +27,11 @@ var _FormBox = _interopRequireDefault(require("../components/FormBox"));
27
27
 
28
28
  var _withAuthenticate = _interopRequireDefault(require("../components/withAuthenticate"));
29
29
 
30
+ var _withPublicTemplate = _interopRequireDefault(require("../components/withPublicTemplate"));
31
+
30
32
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
33
 
32
- var _default = (0, _withAuthenticate.default)(({
34
+ const Login = (0, _withPublicTemplate.default)((0, _withAuthenticate.default)(({
33
35
  authenticate
34
36
  }) => {
35
37
  const {
@@ -64,10 +66,11 @@ var _default = (0, _withAuthenticate.default)(({
64
66
  to: "/reverify"
65
67
  }, t('labels:reverifyLink')))),
66
68
  renderTop: /*#__PURE__*/_react.default.createElement(_Typography.default, {
67
- variant: "h1",
69
+ component: "h1",
70
+ variant: "h2",
68
71
  gutterBottom: true
69
72
  }, t('titles:login'))
70
73
  });
71
- });
72
-
74
+ }));
75
+ var _default = Login;
73
76
  exports.default = _default;
@@ -25,6 +25,8 @@ var _FormBox = _interopRequireDefault(require("../components/FormBox"));
25
25
 
26
26
  var _withSuccessOp = _interopRequireDefault(require("../components/withSuccessOp"));
27
27
 
28
+ var _withPublicTemplate = _interopRequireDefault(require("../components/withPublicTemplate"));
29
+
28
30
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
31
 
30
32
  const PasswordChange = ({
@@ -65,7 +67,6 @@ PasswordChange.propTypes = {
65
67
  search: _propTypes.default.string
66
68
  }).isRequired
67
69
  };
68
-
69
- var _default = (0, _withSuccessOp.default)(PasswordChange, 'passwordChangeNotice');
70
-
70
+ const PasswordChangeWithTemplate = (0, _withPublicTemplate.default)((0, _withSuccessOp.default)(PasswordChange, 'passwordChangeNotice'));
71
+ var _default = PasswordChangeWithTemplate;
71
72
  exports.default = _default;
@@ -19,6 +19,8 @@ var _FormBoxContent = _interopRequireDefault(require("../components/FormBoxConte
19
19
 
20
20
  var _withSuccessOp = _interopRequireDefault(require("../components/withSuccessOp"));
21
21
 
22
+ var _withPublicTemplate = _interopRequireDefault(require("../components/withPublicTemplate"));
23
+
22
24
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
25
 
24
26
  const PasswordReset = ({
@@ -43,7 +45,6 @@ const PasswordReset = ({
43
45
  PasswordReset.propTypes = {
44
46
  onSuccess: _propTypes.default.func.isRequired
45
47
  };
46
-
47
- var _default = (0, _withSuccessOp.default)(PasswordReset, 'passwordResetNotice');
48
-
48
+ const PasswordResetWithTemplate = (0, _withPublicTemplate.default)((0, _withSuccessOp.default)(PasswordReset, 'passwordResetNotice'));
49
+ var _default = PasswordResetWithTemplate;
49
50
  exports.default = _default;
@@ -27,6 +27,8 @@ var _FormBoxNotice = _interopRequireDefault(require("../components/FormBoxNotice
27
27
 
28
28
  var _utils = require("../components/utils");
29
29
 
30
+ var _withPublicTemplate = _interopRequireDefault(require("../components/withPublicTemplate"));
31
+
30
32
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
33
 
32
34
  const Reverify = ({
@@ -45,7 +47,7 @@ const Reverify = ({
45
47
  component: _gatsby.Link,
46
48
  to: "/reverify",
47
49
  variant: "contained",
48
- color: "primary"
50
+ color: "secondary"
49
51
  }, t('labels:tryAgain')));
50
52
  return /*#__PURE__*/_react.default.createElement(_FormBox.default, {
51
53
  renderBottom: /*#__PURE__*/_react.default.createElement(_builders.Form, {
@@ -71,5 +73,6 @@ Reverify.propTypes = {
71
73
  pathname: _propTypes.default.string
72
74
  }).isRequired
73
75
  };
74
- var _default = Reverify;
76
+ const ReverifyWithTemplate = (0, _withPublicTemplate.default)(Reverify);
77
+ var _default = ReverifyWithTemplate;
75
78
  exports.default = _default;
@@ -25,9 +25,11 @@ var _FormBox = _interopRequireDefault(require("../components/FormBox"));
25
25
 
26
26
  var _withAuthenticate = _interopRequireDefault(require("../components/withAuthenticate"));
27
27
 
28
+ var _withPublicTemplate = _interopRequireDefault(require("../components/withPublicTemplate"));
29
+
28
30
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
31
 
30
- var _default = (0, _withAuthenticate.default)(({
32
+ const Verify = (0, _withPublicTemplate.default)((0, _withAuthenticate.default)(({
31
33
  authenticate,
32
34
  ...props
33
35
  }) => {
@@ -70,6 +72,6 @@ var _default = (0, _withAuthenticate.default)(({
70
72
  description: "verify"
71
73
  })
72
74
  });
73
- });
74
-
75
+ }));
76
+ var _default = Verify;
75
77
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-theme-q3",
3
- "version": "3.1.5",
3
+ "version": "3.2.3",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {
@@ -23,24 +23,24 @@
23
23
  "gatsby-image": "^3.11.0",
24
24
  "gatsby-plugin-canonical-urls": "^4.2.0",
25
25
  "gatsby-plugin-force-trailing-slashes": "^1.0.5",
26
- "gatsby-plugin-manifest": "^4.2.0",
27
26
  "gatsby-plugin-material-ui": "^3.0.1",
28
27
  "gatsby-plugin-netlify": "^3.14.0",
29
28
  "gatsby-plugin-robots-txt": "^1.6.14",
30
29
  "gatsby-plugin-sharp": "^4.2.0",
31
30
  "gatsby-plugin-sitemap": "^5.2.0",
32
- "gatsby-source-contentful": "^7.0.0",
33
- "gatsby-theme-q3-mui": "^3.1.5",
31
+ "gatsby-theme-q3-mui": "^3.2.3",
34
32
  "gatsby-transformer-sharp": "^4.2.0",
35
33
  "lodash": "^4.17.20",
36
34
  "process": "^0.11.10",
37
35
  "prop-types": "^15.7.2",
38
- "q3-ui-locale": "^3.1.5",
36
+ "q3-ui-helpers": "^3.2.0",
37
+ "q3-ui-locale": "^3.2.1",
39
38
  "query-string": "^7.0.1",
39
+ "react-helmet": "^6.1.0",
40
40
  "react-share": "^4.3.1",
41
41
  "slugify": "^1.6.3",
42
42
  "transform-loader": "^0.2.4",
43
43
  "yarn": "^1.22.17"
44
44
  },
45
- "gitHead": "abefd5cfba5c173f7d1df2393657ba25ebbb415f"
45
+ "gitHead": "d430a77040909c76b680e920a3f2cc7fd3264215"
46
46
  }
@@ -8,7 +8,7 @@ const FormBoxContent = ({ title, description }) => {
8
8
 
9
9
  return (
10
10
  <>
11
- <Typography variant="h1" gutterBottom>
11
+ <Typography component="h1" variant="h2" gutterBottom>
12
12
  {t(`titles:${title}`)}
13
13
  </Typography>
14
14
  <Typography gutterBottom>
@@ -2,23 +2,11 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { Loader } from 'q3-admin/lib/components';
4
4
  import SearchEngine from './SearchEngine';
5
- import useLocale from './useLocale';
6
5
 
7
- // cannot conditionally call hooks otherwise
8
- const Locale = () => {
9
- useLocale();
10
- return null;
11
- };
12
-
13
- const PageWrapper = ({
14
- children,
15
- includeLoader,
16
- includeLocale,
17
- }) => (
6
+ const PageWrapper = ({ children, includeLoader }) => (
18
7
  <>
19
8
  <SearchEngine />
20
9
  {includeLoader && <Loader />}
21
- {includeLocale && <Locale />}
22
10
  {children}
23
11
  </>
24
12
  );
@@ -1,17 +1,146 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Public } from 'q3-admin/lib/components';
3
+ import {
4
+ Box,
5
+ Paper,
6
+ Link,
7
+ Grid,
8
+ Hidden,
9
+ makeStyles,
10
+ } from '@material-ui/core';
11
+ import { Link as ReachLink } from 'gatsby';
12
+ import { useTranslation } from 'q3-ui-locale';
13
+ import { isString } from 'lodash';
4
14
  import AdminPublicGateway from './AdminPublicGateway';
5
15
  import useSiteMetaData from './useSiteMetaData';
6
16
 
17
+ const useStyle = makeStyles((theme) => ({
18
+ logo: {
19
+ height: 95,
20
+ width: 180,
21
+ display: 'block',
22
+
23
+ '& img': {
24
+ objectFit: 'contain',
25
+ height: '100%',
26
+ width: '100%',
27
+ },
28
+ },
29
+ container: {
30
+ maxWidth: '85vw',
31
+ width: 850,
32
+
33
+ [theme.breakpoints.down('md')]: {
34
+ width: '100%',
35
+ },
36
+
37
+ [theme.breakpoints.down('sm')]: {
38
+ width: 'auto',
39
+ },
40
+ },
41
+ photo: ({ photo }) => ({
42
+ backgroundColor: theme.palette.secondary.light,
43
+ backgroundImage: isString(photo)
44
+ ? `url("${String(photo).replace(/\s/gi, '%20')}")`
45
+ : undefined,
46
+ backgroundSize: 'contain',
47
+ backgroundPosition: 'center',
48
+ backgroundRepeat: 'no-repeat',
49
+ width: '100%',
50
+ height: '100%',
51
+ backgroundBlendMode: 'multiply',
52
+ minHeight: '55vh',
53
+ }),
54
+ }));
55
+
56
+ const Copyright = () => {
57
+ const { brand } = useSiteMetaData();
58
+
59
+ return brand ? (
60
+ <Box display="inline-block" mx={1}>
61
+ ©{new Date().getFullYear()} {brand}
62
+ </Box>
63
+ ) : null;
64
+ };
65
+
66
+ // eslint-disable-next-line
67
+ const TextLink = ({ href, text }) => {
68
+ const { t } = useTranslation('labels');
69
+
70
+ return href ? (
71
+ <Box display="inline-block" mx={1}>
72
+ <Link href={href} target="_blank">
73
+ {t(text)}
74
+ </Link>
75
+ </Box>
76
+ ) : null;
77
+ };
78
+
7
79
  const PublicTemplate = ({ children, ...rest }) => {
8
- const { brand, logo } = useSiteMetaData();
80
+ const {
81
+ brand,
82
+ cancellation,
83
+ logo,
84
+ terms,
85
+ privacy,
86
+ photo,
87
+ } = useSiteMetaData();
88
+ const cls = useStyle({
89
+ photo,
90
+ });
9
91
 
10
92
  return (
11
93
  <AdminPublicGateway {...rest}>
12
- <Public companyName={brand} logo={logo}>
13
- {children}
14
- </Public>
94
+ <Box
95
+ alignItems="center"
96
+ component="article"
97
+ display="flex"
98
+ flexDirection="column"
99
+ justifyContent="center"
100
+ width="100%"
101
+ >
102
+ <Box
103
+ component="header"
104
+ mt="2vh"
105
+ mb={2}
106
+ textAlign="center"
107
+ >
108
+ <ReachLink to="/" className={cls.logo}>
109
+ <img alt={brand} src={logo} />
110
+ </ReachLink>
111
+ </Box>
112
+ <Paper className={cls.container}>
113
+ <Grid alignItems="center" container spacing={1}>
114
+ <Hidden smDown>
115
+ <Grid item xs={6}>
116
+ <Box className={cls.photo} />
117
+ </Grid>
118
+ </Hidden>
119
+ <Grid item md={6} xs={12}>
120
+ <Box p={2}>{children}</Box>
121
+ </Grid>
122
+ </Grid>
123
+ </Paper>
124
+ <Box
125
+ maxWidth="75vw"
126
+ component="footer"
127
+ mt={3}
128
+ textAlign="center"
129
+ >
130
+ <small>
131
+ <Copyright />
132
+ <TextLink
133
+ href={terms}
134
+ text="termsAndConditions"
135
+ />
136
+ <TextLink href={privacy} text="privacyPolicy" />
137
+ <TextLink
138
+ href={cancellation}
139
+ text="cancellationPolicy"
140
+ />
141
+ </small>
142
+ </Box>
143
+ </Box>
15
144
  </AdminPublicGateway>
16
145
  );
17
146
  };
@@ -1,32 +1,89 @@
1
1
  import React from 'react';
2
+ import { get, isFunction, isObject } from 'lodash';
2
3
  import PropTypes from 'prop-types';
3
4
  import { Helmet } from 'react-helmet';
5
+ import { browser } from 'q3-ui-helpers';
4
6
  import useSiteMetaData from './useSiteMetaData';
5
7
 
8
+ const withContent = (output) => (content) =>
9
+ content && isFunction(output) ? output(content) : [];
10
+
11
+ export const getStartUrl = () =>
12
+ browser.isBrowserReady()
13
+ ? get(window, 'location.host')
14
+ : '';
15
+
16
+ export const generateMetaDescriptionOptions = withContent(
17
+ (content) => [
18
+ {
19
+ name: 'description',
20
+ content,
21
+ },
22
+ {
23
+ property: 'og:description',
24
+ content,
25
+ },
26
+ {
27
+ name: 'twitter:description',
28
+ content,
29
+ },
30
+ ],
31
+ );
32
+
33
+ export const generateMetaTitleOptions = withContent(
34
+ (content) => [
35
+ {
36
+ property: 'og:title',
37
+ content,
38
+ },
39
+ {
40
+ name: 'twitter:title',
41
+ content,
42
+ },
43
+ ],
44
+ );
45
+
46
+ export const generateBrand = (xs) =>
47
+ xs ? `%s | ${xs}` : undefined;
48
+
49
+ export const generateIcons = (site = {}) =>
50
+ site?.favicon
51
+ ? [
52
+ {
53
+ src: site.favicon,
54
+ sizes: '512x512',
55
+ type: 'image/png',
56
+ },
57
+ ]
58
+ : [];
59
+
60
+ export const generateManifest = (site = {}) => ({
61
+ background_color: site.color,
62
+ description: site.description,
63
+ display: 'fullscreen',
64
+ icons: generateIcons(site),
65
+ name: site.title,
66
+ start_url: getStartUrl(),
67
+ short_name: site.brand,
68
+ theme_color: site.color,
69
+ });
70
+
6
71
  const SEO = ({ description, lang, meta, title }) => {
7
72
  const site = useSiteMetaData();
8
73
  const metaDescription = description || site.description;
74
+ const metaTitle = title || site.title;
75
+ const manifestData = generateManifest(site);
9
76
 
10
77
  return (
11
78
  <Helmet
12
79
  htmlAttributes={{
13
80
  lang,
14
81
  }}
15
- title={title || site.title}
16
- titleTemplate={`%s | ${site.brand}`}
82
+ title={metaTitle}
83
+ titleTemplate={generateBrand(site.brand)}
17
84
  meta={[
18
- {
19
- name: 'description',
20
- content: metaDescription,
21
- },
22
- {
23
- property: 'og:title',
24
- content: title,
25
- },
26
- {
27
- property: 'og:description',
28
- content: metaDescription,
29
- },
85
+ ...generateMetaTitleOptions(metaTitle),
86
+ ...generateMetaDescriptionOptions(metaDescription),
30
87
  {
31
88
  property: 'og:type',
32
89
  content: 'website',
@@ -35,16 +92,18 @@ const SEO = ({ description, lang, meta, title }) => {
35
92
  name: 'twitter:card',
36
93
  content: 'summary',
37
94
  },
38
- {
39
- name: 'twitter:title',
40
- content: title,
41
- },
42
- {
43
- name: 'twitter:description',
44
- content: metaDescription,
45
- },
46
95
  ].concat(meta)}
47
- />
96
+ >
97
+ {isObject(manifestData) ? (
98
+ <link
99
+ rel="manifest"
100
+ href={`data:application/manifest+json,${encodeURIComponent(
101
+ JSON.stringify(manifestData),
102
+ )}`}
103
+ />
104
+ ) : null}
105
+ <link rel="icon" href={site.favicon} />
106
+ </Helmet>
48
107
  );
49
108
  };
50
109
 
@@ -1,38 +1,14 @@
1
1
  /* eslint-disable import/no-extraneous-dependencies */
2
2
  import React from 'react';
3
- import axios from 'axios';
4
3
  import PropTypes from 'prop-types';
5
4
  import AuthProvider from 'q3-ui-permissions';
6
- import LocaleBundles from './LocaleBundles';
7
5
 
8
- const setBaseUrlForRest = (
9
- baseURL = process.env.GATSBY_APP_BASE_URL ||
10
- 'http://localhost:9000',
11
- ) => {
12
- axios.defaults.baseURL = baseURL;
13
- return axios.defaults;
14
- };
15
-
16
- const Wrapper = ({ baseURL, children, locale }) => {
17
- setBaseUrlForRest(baseURL);
18
-
19
- return (
20
- <LocaleBundles locale={locale}>
21
- <AuthProvider>{children}</AuthProvider>
22
- </LocaleBundles>
23
- );
24
- };
25
-
26
- Wrapper.defaultProps = {
27
- baseURL: undefined,
28
- };
6
+ const Wrapper = ({ children }) => (
7
+ <AuthProvider>{children}</AuthProvider>
8
+ );
29
9
 
30
10
  Wrapper.propTypes = {
31
- baseURL: PropTypes.string,
32
11
  children: PropTypes.node.isRequired,
33
-
34
- // eslint-disable-next-line
35
- locale: PropTypes.object.isRequired,
36
12
  };
37
13
 
38
14
  export default Wrapper;
@@ -0,0 +1,58 @@
1
+ import {
2
+ generateMetaDescriptionOptions,
3
+ getStartUrl,
4
+ generateIcons,
5
+ generateBrand,
6
+ } from '../SearchEngine';
7
+
8
+ jest.mock('q3-ui-locale', () => ({
9
+ browser: {
10
+ isBrowserReady: jest.fn(),
11
+ },
12
+ }));
13
+
14
+ const host = 'https://google.ca';
15
+
16
+ beforeEach(() => {
17
+ Object.defineProperty(window, 'location', {
18
+ value: {
19
+ host,
20
+ },
21
+ });
22
+ });
23
+
24
+ describe('SearchEngine', () => {
25
+ it('should not render descriptions without content', () => {
26
+ expect(generateMetaDescriptionOptions().length).toBe(0);
27
+ });
28
+
29
+ it('should render descriptions with content', () => {
30
+ expect(
31
+ generateMetaDescriptionOptions('foo').length,
32
+ ).toBeGreaterThanOrEqual(1);
33
+ });
34
+
35
+ it('should return host', () => {
36
+ expect(getStartUrl()).toMatch(host);
37
+ });
38
+
39
+ it('should render favicon', () => {
40
+ expect(
41
+ generateIcons({
42
+ favicon: host,
43
+ }),
44
+ ).toHaveLength(1);
45
+ });
46
+
47
+ it('should not render favicon', () => {
48
+ expect(
49
+ generateIcons({
50
+ favicon: undefined,
51
+ }),
52
+ ).toHaveLength(0);
53
+ });
54
+
55
+ it('should include template literals', () => {
56
+ expect(generateBrand('3merge')).toMatch('%s | 3merge');
57
+ });
58
+ });
@@ -1,22 +1,23 @@
1
- import { get } from 'lodash';
1
+ import { get, merge } from 'lodash';
2
2
  import { useStaticQuery, graphql } from 'gatsby';
3
+ import useRunTime from 'gatsby-theme-q3-mui/src/components/useRunTime';
3
4
 
4
5
  export default () =>
5
- get(
6
- useStaticQuery(graphql`
7
- query {
8
- site {
9
- siteMetadata {
10
- appDirectory
11
- brand
12
- description
13
- favicon
14
- logo
15
- title
6
+ merge(
7
+ get(
8
+ useStaticQuery(graphql`
9
+ query {
10
+ site {
11
+ siteMetadata {
12
+ appDirectory
13
+ description
14
+ title
15
+ }
16
16
  }
17
17
  }
18
- }
19
- `),
20
- 'site.siteMetadata',
21
- {},
18
+ `),
19
+ 'site.siteMetadata',
20
+ {},
21
+ ),
22
+ useRunTime(),
22
23
  );