@financial-times/dotcom-ui-shell 7.3.1 → 7.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. package/package.json +6 -2
  2. package/src/__test__/components/Content.test.tsx +23 -0
  3. package/src/__test__/components/DocumentHead.test.tsx +38 -0
  4. package/src/__test__/components/GTMBody.test.tsx +36 -0
  5. package/src/__test__/components/GTMHead.test.tsx +27 -0
  6. package/src/__test__/components/LinkedData.test.tsx +31 -0
  7. package/src/__test__/components/OpenGraph.test.tsx +25 -0
  8. package/src/__test__/components/ResourceHints.test.tsx +18 -0
  9. package/src/__test__/components/Shell.test.tsx +29 -0
  10. package/src/__test__/components/Stylesheets.test.tsx +22 -0
  11. package/src/__test__/components/__snapshots__/Content.test.tsx.snap +22 -0
  12. package/src/__test__/components/__snapshots__/DocumentHead.test.tsx.snap +87 -0
  13. package/src/__test__/components/__snapshots__/GTMBody.test.tsx.snap +21 -0
  14. package/src/__test__/components/__snapshots__/GTMHead.test.tsx.snap +17 -0
  15. package/src/__test__/components/__snapshots__/LinkedData.test.tsx.snap +41 -0
  16. package/src/__test__/components/__snapshots__/OpenGraph.test.tsx.snap +42 -0
  17. package/src/__test__/components/__snapshots__/ResourceHints.test.tsx.snap +54 -0
  18. package/src/__test__/components/__snapshots__/Shell.test.tsx.snap +317 -0
  19. package/src/__test__/components/__snapshots__/Stylesheets.test.tsx.snap +50 -0
  20. package/src/__test__/lib/flattenOpenGraphData.spec.ts +37 -0
  21. package/src/__test__/lib/formatAttributeNames.spec.ts +38 -0
  22. package/src/__test__/lib/getResourceType.spec.ts +28 -0
  23. package/src/components/Content.tsx +25 -0
  24. package/src/components/DocumentHead.tsx +103 -0
  25. package/src/components/GTMBody.tsx +29 -0
  26. package/src/components/GTMHead.tsx +23 -0
  27. package/src/components/LinkedData.tsx +38 -0
  28. package/src/components/OpenGraph.tsx +20 -0
  29. package/src/components/ResourceHints.tsx +63 -0
  30. package/src/components/Shell.tsx +97 -0
  31. package/src/components/StyleSheets.tsx +35 -0
  32. package/src/index.ts +1 -0
  33. package/src/lib/flattenOpenGraphData.ts +24 -0
  34. package/src/lib/formatAttributeNames.ts +36 -0
  35. package/src/lib/getResourceType.ts +34 -0
  36. package/src/lib/imageServiceIconURL.ts +24 -0
  37. package/src/lib/loadAsyncStylesheets.ts +27 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/dotcom-ui-shell",
3
- "version": "7.3.1",
3
+ "version": "7.3.2",
4
4
  "description": "",
5
5
  "main": "component.js",
6
6
  "browser": "browser.js",
@@ -35,7 +35,11 @@
35
35
  "npm": "7.x || 8.x"
36
36
  },
37
37
  "files": [
38
- "dist/"
38
+ "dist/",
39
+ "src/",
40
+ "browser.js",
41
+ "component.js",
42
+ "styles.scss"
39
43
  ],
40
44
  "repository": {
41
45
  "type": "git",
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/Content'
4
+
5
+ describe('dotcom-ui-shell/src/components/Content', () => {
6
+ describe('with stringified contents', () => {
7
+ it('renders the given HTML string without escaping', () => {
8
+ const contents = '<p>Hello, World!</p>'
9
+ const tree = renderer.create(<Subject contents={contents} />).toJSON()
10
+
11
+ expect(tree).toMatchSnapshot()
12
+ })
13
+ })
14
+
15
+ describe('with component contents', () => {
16
+ it('renders the components', () => {
17
+ const contents = <p>Hello, World!</p>
18
+ const tree = renderer.create(<Subject contents={contents} />).toJSON()
19
+
20
+ expect(tree).toMatchSnapshot()
21
+ })
22
+ })
23
+ })
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/DocumentHead'
4
+
5
+ describe('dotcom-ui-shell/src/components/DocumentHead', () => {
6
+ it('renders the document head', () => {
7
+ const props = {
8
+ description: 'Website description.',
9
+ facebookPage: 'facebook-page-id',
10
+ pageTitle: 'Page title',
11
+ siteTitle: 'Website title',
12
+ twitterSite: '@twitter_page',
13
+ canonicalURL: 'https://my.site',
14
+ metaTags: [{ rel: 'alternate', type: 'application/rss+xml', href: 'path/to/rss' }]
15
+ }
16
+
17
+ const tree = renderer.create(<Subject {...props} />).toJSON()
18
+ expect(tree).toMatchSnapshot()
19
+ })
20
+
21
+ it('should not render smart banner meta tag when showSmartBanner false', () => {
22
+ const props = {
23
+ description: 'Website description.',
24
+ facebookPage: 'facebook-page-id',
25
+ pageTitle: 'Page title',
26
+ siteTitle: 'Website title',
27
+ twitterSite: '@twitter_page',
28
+ canonicalURL: 'https://my.site',
29
+ metaTags: [{ rel: 'alternate', type: 'application/rss+xml', href: 'path/to/rss' }],
30
+ showSmartBanner: false
31
+ }
32
+
33
+ const tree = renderer.create(<Subject {...props} />).root
34
+ expect(() => {
35
+ tree.findByProps({name: 'apple-itunes-app'})
36
+ }).toThrow()
37
+ })
38
+ })
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import GTMBody from '../../components/GTMBody'
4
+
5
+ describe('dotcom-ui-shell/src/components/GTMBody', () => {
6
+ it('renders the gtm body script when the enableGTM flag is on', () => {
7
+ const props = {
8
+ flags: {
9
+ enableGTM: true
10
+ }
11
+ }
12
+
13
+ const tree = renderer.create(<GTMBody {...props} />).toJSON()
14
+ expect(tree).toMatchSnapshot()
15
+ })
16
+
17
+ it('renders null when the enableGTM flag is off', () => {
18
+ const props = {
19
+ flags: {
20
+ enableGTM: false
21
+ }
22
+ }
23
+
24
+ const tree = renderer.create(<GTMBody {...props} />).toJSON()
25
+ expect(tree).toMatchSnapshot()
26
+ })
27
+
28
+ it('renders null when there is no enableGTM', () => {
29
+ const props = {
30
+ flags: {}
31
+ }
32
+
33
+ const tree = renderer.create(<GTMBody {...props} />).toJSON()
34
+ expect(tree).toMatchSnapshot()
35
+ })
36
+ })
@@ -0,0 +1,27 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import GTMHead from '../../components/GTMHead'
4
+
5
+ describe('dotcom-ui-shell/src/components/GTMHead', () => {
6
+ it('renders the gtm head script when the enableGTM flag is on', () => {
7
+ const props = {
8
+ flags: {
9
+ enableGTM: true
10
+ }
11
+ }
12
+
13
+ const tree = renderer.create(<GTMHead {...props} />).toJSON()
14
+ expect(tree).toMatchSnapshot()
15
+ })
16
+
17
+ it('renders null when the enableGTM flag is off', () => {
18
+ const props = {
19
+ flags: {
20
+ enableGTM: false
21
+ }
22
+ }
23
+
24
+ const tree = renderer.create(<GTMHead {...props} />).toJSON()
25
+ expect(tree).toMatchSnapshot()
26
+ })
27
+ })
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/LinkedData'
4
+
5
+ describe('dotcom-ui-shell/src/components/LinkedData', () => {
6
+ it('renders the base site schema', () => {
7
+ const tree = renderer.create(<Subject />).toJSON()
8
+ expect(tree).toMatchSnapshot()
9
+ })
10
+
11
+ it('renders the given additional schemas', () => {
12
+ const fixture = [
13
+ {
14
+ '@context': 'http://schema.org',
15
+ '@type': 'Person',
16
+ name: 'John Doe',
17
+ email: 'john.doe@example.com',
18
+ netWorth: '1 trillion'
19
+ },
20
+ {
21
+ '@context': 'http://schema.org',
22
+ '@type': 'Organization',
23
+ url: 'https://www.ft.com',
24
+ address: 'Bracken House, EC4M 9JA'
25
+ }
26
+ ]
27
+
28
+ const tree = renderer.create(<Subject jsonLd={fixture} />).toJSON()
29
+ expect(tree).toMatchSnapshot()
30
+ })
31
+ })
@@ -0,0 +1,25 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/OpenGraph'
4
+
5
+ describe('dotcom-ui-shell/src/components/OpenGraph', () => {
6
+ it('renders the given Open Graph data to meta tags', () => {
7
+ const fixture = {
8
+ og: {
9
+ title: 'Open Graph title',
10
+ video: 'https://my.site/video.mp4',
11
+ 'video:type': 'video/mp4',
12
+ 'video:width': 640,
13
+ 'video:height': 360
14
+ },
15
+ article: {
16
+ published_time: '2019-02-27T06:59:35.000Z',
17
+ modified_time: '2019-02-27T16:01:21.000Z',
18
+ author: ['Joe Bloggs', 'Jane Doe']
19
+ }
20
+ }
21
+
22
+ const tree = renderer.create(<Subject openGraph={fixture} />).toJSON()
23
+ expect(tree).toMatchSnapshot()
24
+ })
25
+ })
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/ResourceHints'
4
+
5
+ describe('dotcom-ui-shell/src/components/ResourceHints', () => {
6
+ it('renders the given paths and URLs as resource hints', () => {
7
+ const fixture = [
8
+ 'www.example.com/assets/style.css',
9
+ 'www.example.com/images/graphic.svg#icon',
10
+ 'http://polyfill.io/v3/bundle.min.js?features=es5,es6',
11
+ '/assets/public/style.as83hd99.css',
12
+ '/__origami/service/build/v3/font?font_format=woff2&font_name=FinancierDisplayWeb-Bold&system_code=origami&version=1.12'
13
+ ]
14
+
15
+ const tree = renderer.create(<Subject resourceHints={fixture} />).toJSON()
16
+ expect(tree).toMatchSnapshot()
17
+ })
18
+ })
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import ShallowRenderer from 'react-test-renderer/shallow'
4
+ import { Shell } from '../../components/Shell'
5
+
6
+ describe('dotcom-ui-shell/src/components/Shell', () => {
7
+ it('should define all props as optional except the `pageTitle` prop', () => {
8
+ new ShallowRenderer().render(<Shell pageTitle="Foo" />)
9
+ })
10
+
11
+ it('renders boolean boolean html data attributes correctly', () => {
12
+ const htmlAttributes = { dataIsProduction: '', dataIsDevelopment: false }
13
+ const htmlTag = renderer.create(<Shell pageTitle="Foo" htmlAttributes={htmlAttributes} />).toJSON()
14
+
15
+ // where react is concerned, a `true` boolean data attribute
16
+ // is one where the attribute value is an empty string (because
17
+ // it is not possible to render the attribute without a value),
18
+ // and a `false` boolean data attribute is one where the attribute
19
+ // has not been specified altogether
20
+ expect(htmlTag.props).toHaveProperty('data-is-production', '')
21
+ expect(htmlTag.props).not.toHaveProperty('data-is-development')
22
+ })
23
+
24
+ it('renders the GTM script when the enableGTM flag is on', () => {
25
+ const tree = renderer.create(<Shell pageTitle="Foo" flags={{ enableGTM: true }} />).toJSON()
26
+
27
+ expect(tree).toMatchSnapshot()
28
+ })
29
+ })
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Subject from '../../components/StyleSheets'
4
+
5
+ describe('dotcom-ui-shell/src/components/StyleSheets', () => {
6
+ it('renders the given stylesheets and critical styles', () => {
7
+ const props = {
8
+ stylesheets: ['path/to/styles.css'],
9
+ criticalStyles: 'html { margin: 0 } body { font-family: "Comic Sans" }'
10
+ }
11
+ const tree = renderer.create(<Subject {...props} />).toJSON()
12
+ expect(tree).toMatchSnapshot()
13
+ })
14
+
15
+ it('renders JavaScript for adding asyncronous stylesheets if appropriate', () => {
16
+ const props = {
17
+ asyncStylesheets: ['path/to/async-styles.css']
18
+ }
19
+ const tree = renderer.create(<Subject {...props} />).toJSON()
20
+ expect(tree).toMatchSnapshot()
21
+ })
22
+ })
@@ -0,0 +1,22 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/Content with component contents renders the components 1`] = `
4
+ <p>
5
+ Hello, World!
6
+ </p>
7
+ `;
8
+
9
+ exports[`dotcom-ui-shell/src/components/Content with stringified contents renders the given HTML string without escaping 1`] = `
10
+ <div
11
+ dangerouslySetInnerHTML={
12
+ Object {
13
+ "__html": "<p>Hello, World!</p>",
14
+ }
15
+ }
16
+ style={
17
+ Object {
18
+ "display": "contents",
19
+ }
20
+ }
21
+ />
22
+ `;
@@ -0,0 +1,87 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/DocumentHead renders the document head 1`] = `
4
+ Array [
5
+ <meta
6
+ charSet="utf-8"
7
+ />,
8
+ <meta
9
+ content="IE=edge"
10
+ httpEquiv="X-UA-Compatible"
11
+ />,
12
+ <meta
13
+ content="width=device-width, initial-scale=1"
14
+ name="viewport"
15
+ />,
16
+ <title>
17
+ Page title | Website title
18
+ </title>,
19
+ <meta
20
+ content="Website description."
21
+ name="description"
22
+ />,
23
+ <link
24
+ href="https://my.site"
25
+ rel="canonical"
26
+ />,
27
+ <meta
28
+ content="index,follow,max-snippet:200,max-image-preview:large"
29
+ name="robots"
30
+ />,
31
+ <meta
32
+ content="4-t8sFaPvpO5FH_Gnw1dkM28CQepjzo8UjjAkdDflTw"
33
+ name="google-site-verification"
34
+ />,
35
+ <meta
36
+ href="path/to/rss"
37
+ rel="alternate"
38
+ type="application/rss+xml"
39
+ />,
40
+ <script
41
+ dangerouslySetInnerHTML={
42
+ Object {
43
+ "__html": "{\\"@context\\":\\"http://schema.org\\",\\"@type\\":\\"WebSite\\",\\"name\\":\\"Financial Times\\",\\"alternateName\\":\\"FT.com\\",\\"url\\":\\"http://www.ft.com\\"}",
44
+ }
45
+ }
46
+ type="application/ld+json"
47
+ />,
48
+ <meta
49
+ content="facebook-page-id"
50
+ property="fb:pages"
51
+ />,
52
+ <meta
53
+ content="@twitter_page"
54
+ property="twitter:site"
55
+ />,
56
+ <meta
57
+ content="app-id=1200842933, app-argument=https://my.site"
58
+ name="apple-itunes-app"
59
+ />,
60
+ <link
61
+ href="https://www.ft.com/__origami/service/image/v2/images/raw/ftlogo-v1%3Abrand-ft-logo-square-coloured?source=update-logos&format=svg"
62
+ rel="icon"
63
+ type="image/svg+xml"
64
+ />,
65
+ <link
66
+ href="https://www.ft.com/__origami/service/image/v2/images/raw/ftlogo-v1%3Abrand-ft-logo-square-coloured?source=update-logos&format=png&width=32&height=32"
67
+ rel="alternate icon"
68
+ sizes="32x32"
69
+ type="image/png"
70
+ />,
71
+ <link
72
+ href="https://www.ft.com/__origami/service/image/v2/images/raw/ftlogo-v1%3Abrand-ft-logo-square-coloured?source=update-logos&format=png&width=194&height=194"
73
+ rel="alternate icon"
74
+ sizes="194x194"
75
+ type="image/png"
76
+ />,
77
+ <link
78
+ href="https://www.ft.com/__origami/service/image/v2/images/raw/ftlogo-v1%3Abrand-ft-logo-square-coloured?source=update-logos&format=png&width=180&height=180"
79
+ rel="apple-touch-icon"
80
+ sizes="180x180"
81
+ />,
82
+ <link
83
+ href="https://www.ft.com/__assets/creatives/manifest/manifest-v6.json"
84
+ rel="manifest"
85
+ />,
86
+ ]
87
+ `;
@@ -0,0 +1,21 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/GTMBody renders null when the enableGTM flag is off 1`] = `null`;
4
+
5
+ exports[`dotcom-ui-shell/src/components/GTMBody renders null when there is no enableGTM 1`] = `null`;
6
+
7
+ exports[`dotcom-ui-shell/src/components/GTMBody renders the gtm body script when the enableGTM flag is on 1`] = `
8
+ <noscript>
9
+ <iframe
10
+ height="0"
11
+ src="https://www.googletagmanager.com/ns.html?id=GTM-NWQJW68"
12
+ style={
13
+ Object {
14
+ "display": "none",
15
+ "visibility": "hidden",
16
+ }
17
+ }
18
+ width="0"
19
+ />
20
+ </noscript>
21
+ `;
@@ -0,0 +1,17 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/GTMHead renders null when the enableGTM flag is off 1`] = `null`;
4
+
5
+ exports[`dotcom-ui-shell/src/components/GTMHead renders the gtm head script when the enableGTM flag is on 1`] = `
6
+ <script
7
+ dangerouslySetInnerHTML={
8
+ Object {
9
+ "__html": "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
10
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
11
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
12
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
13
+ })(window,document,'script','dataLayer','GTM-NWQJW68');",
14
+ }
15
+ }
16
+ />
17
+ `;
@@ -0,0 +1,41 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/LinkedData renders the base site schema 1`] = `
4
+ <script
5
+ dangerouslySetInnerHTML={
6
+ Object {
7
+ "__html": "{\\"@context\\":\\"http://schema.org\\",\\"@type\\":\\"WebSite\\",\\"name\\":\\"Financial Times\\",\\"alternateName\\":\\"FT.com\\",\\"url\\":\\"http://www.ft.com\\"}",
8
+ }
9
+ }
10
+ type="application/ld+json"
11
+ />
12
+ `;
13
+
14
+ exports[`dotcom-ui-shell/src/components/LinkedData renders the given additional schemas 1`] = `
15
+ Array [
16
+ <script
17
+ dangerouslySetInnerHTML={
18
+ Object {
19
+ "__html": "{\\"@context\\":\\"http://schema.org\\",\\"@type\\":\\"Person\\",\\"name\\":\\"John Doe\\",\\"email\\":\\"john.doe@example.com\\",\\"netWorth\\":\\"1 trillion\\"}",
20
+ }
21
+ }
22
+ type="application/ld+json"
23
+ />,
24
+ <script
25
+ dangerouslySetInnerHTML={
26
+ Object {
27
+ "__html": "{\\"@context\\":\\"http://schema.org\\",\\"@type\\":\\"Organization\\",\\"url\\":\\"https://www.ft.com\\",\\"address\\":\\"Bracken House, EC4M 9JA\\"}",
28
+ }
29
+ }
30
+ type="application/ld+json"
31
+ />,
32
+ <script
33
+ dangerouslySetInnerHTML={
34
+ Object {
35
+ "__html": "{\\"@context\\":\\"http://schema.org\\",\\"@type\\":\\"WebSite\\",\\"name\\":\\"Financial Times\\",\\"alternateName\\":\\"FT.com\\",\\"url\\":\\"http://www.ft.com\\"}",
36
+ }
37
+ }
38
+ type="application/ld+json"
39
+ />,
40
+ ]
41
+ `;
@@ -0,0 +1,42 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/OpenGraph renders the given Open Graph data to meta tags 1`] = `
4
+ Array [
5
+ <meta
6
+ content="Open Graph title"
7
+ property="og:title"
8
+ />,
9
+ <meta
10
+ content="https://my.site/video.mp4"
11
+ property="og:video"
12
+ />,
13
+ <meta
14
+ content="video/mp4"
15
+ property="og:video:type"
16
+ />,
17
+ <meta
18
+ content={640}
19
+ property="og:video:width"
20
+ />,
21
+ <meta
22
+ content={360}
23
+ property="og:video:height"
24
+ />,
25
+ <meta
26
+ content="2019-02-27T06:59:35.000Z"
27
+ property="article:published_time"
28
+ />,
29
+ <meta
30
+ content="2019-02-27T16:01:21.000Z"
31
+ property="article:modified_time"
32
+ />,
33
+ <meta
34
+ content="Joe Bloggs"
35
+ property="article:author"
36
+ />,
37
+ <meta
38
+ content="Jane Doe"
39
+ property="article:author"
40
+ />,
41
+ ]
42
+ `;
@@ -0,0 +1,54 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`dotcom-ui-shell/src/components/ResourceHints renders the given paths and URLs as resource hints 1`] = `
4
+ Array [
5
+ <link
6
+ href="https://spoor-api.ft.com"
7
+ rel="preconnect"
8
+ />,
9
+ <link
10
+ crossOrigin="use-credentials"
11
+ href="https://session-next.ft.com"
12
+ rel="preconnect"
13
+ />,
14
+ <link
15
+ href="https://ads-api.ft.com"
16
+ rel="preconnect"
17
+ />,
18
+ <link
19
+ href="https://securepubads.g.doubleclick.net"
20
+ rel="preconnect"
21
+ />,
22
+ <link
23
+ as="style"
24
+ href="www.example.com/assets/style.css"
25
+ rel="preload"
26
+ type="text/css"
27
+ />,
28
+ <link
29
+ as="image"
30
+ href="www.example.com/images/graphic.svg#icon"
31
+ rel="preload"
32
+ type={null}
33
+ />,
34
+ <link
35
+ as="script"
36
+ href="http://polyfill.io/v3/bundle.min.js?features=es5,es6"
37
+ rel="preload"
38
+ type={null}
39
+ />,
40
+ <link
41
+ as="style"
42
+ href="/assets/public/style.as83hd99.css"
43
+ rel="preload"
44
+ type="text/css"
45
+ />,
46
+ <link
47
+ as="font"
48
+ crossOrigin="anonymous"
49
+ href="/__origami/service/build/v3/font?font_format=woff2&font_name=FinancierDisplayWeb-Bold&system_code=origami&version=1.12"
50
+ rel="preload"
51
+ type="font/woff2"
52
+ />,
53
+ ]
54
+ `;