gatsby-theme-q3 3.1.5 → 3.2.3

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 (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
  );