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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. package/dist/node/components/Content.d.ts +6 -0
  2. package/dist/node/components/DocumentHead.d.ts +36 -0
  3. package/dist/node/components/GTMBody.d.ts +11 -0
  4. package/dist/node/components/GTMHead.d.ts +11 -0
  5. package/dist/node/components/LinkedData.d.ts +13 -0
  6. package/dist/node/components/OpenGraph.d.ts +12 -0
  7. package/dist/node/components/ResourceHints.d.ts +11 -0
  8. package/dist/node/components/Shell.d.ts +29 -0
  9. package/dist/node/components/StyleSheets.d.ts +14 -0
  10. package/dist/node/index.d.ts +1 -0
  11. package/dist/node/lib/flattenOpenGraphData.d.ts +4 -0
  12. package/dist/node/lib/formatAttributeNames.d.ts +4 -0
  13. package/dist/node/lib/getResourceType.d.ts +2 -0
  14. package/dist/node/lib/imageServiceIconURL.d.ts +2 -0
  15. package/dist/node/lib/loadAsyncStylesheets.d.ts +2 -0
  16. package/dist/tsconfig.tsbuildinfo +2370 -0
  17. package/package.json +11 -9
  18. package/src/components/Content.tsx +0 -25
  19. package/src/components/DocumentHead.tsx +0 -103
  20. package/src/components/GTMBody.tsx +0 -29
  21. package/src/components/GTMHead.tsx +0 -23
  22. package/src/components/LinkedData.tsx +0 -38
  23. package/src/components/OpenGraph.tsx +0 -20
  24. package/src/components/ResourceHints.tsx +0 -63
  25. package/src/components/Shell.tsx +0 -97
  26. package/src/components/StyleSheets.tsx +0 -35
  27. package/src/index.ts +0 -1
  28. package/src/lib/flattenOpenGraphData.ts +0 -24
  29. package/src/lib/formatAttributeNames.ts +0 -36
  30. package/src/lib/getResourceType.ts +0 -34
  31. package/src/lib/imageServiceIconURL.ts +0 -24
  32. package/src/lib/loadAsyncStylesheets.ts +0 -27
package/package.json CHANGED
@@ -1,18 +1,17 @@
1
1
  {
2
2
  "name": "@financial-times/dotcom-ui-shell",
3
- "version": "7.2.7",
3
+ "version": "7.3.1",
4
4
  "description": "",
5
5
  "main": "component.js",
6
6
  "browser": "browser.js",
7
7
  "types": "src/index.ts",
8
8
  "scripts": {
9
9
  "test": "echo \"Error: no test specified\" && exit 1",
10
- "tsc": "../../node_modules/.bin/tsc --incremental",
11
10
  "clean": "npm run clean:dist && npm run clean:node_modules",
12
11
  "clean:dist": "rm -rf dist",
13
12
  "clean:node_modules": "rm -rf node_modules",
14
13
  "clean:install": "npm run clean && npm i",
15
- "build:node": "npm run tsc -- --module commonjs --outDir ./dist/node",
14
+ "build:node": "tsc",
16
15
  "build": "npm run build:node",
17
16
  "dev": "npm run build:node -- --watch",
18
17
  "preinstall": "[ \"$INIT_CWD\" != \"$PWD\" ] || npm_config_yes=true npx check-engine"
@@ -21,11 +20,11 @@
21
20
  "author": "",
22
21
  "license": "MIT",
23
22
  "dependencies": {
24
- "@financial-times/dotcom-ui-app-context": "^7.2.7",
25
- "@financial-times/dotcom-ui-base-styles": "^7.2.7",
26
- "@financial-times/dotcom-ui-bootstrap": "^7.2.7",
27
- "@financial-times/dotcom-ui-flags": "^7.2.7",
28
- "@financial-times/dotcom-ui-polyfill-service": "^7.2.7",
23
+ "@financial-times/dotcom-ui-app-context": "file:../dotcom-ui-app-context",
24
+ "@financial-times/dotcom-ui-base-styles": "file:../dotcom-ui-base-styles",
25
+ "@financial-times/dotcom-ui-bootstrap": "file:../dotcom-ui-bootstrap",
26
+ "@financial-times/dotcom-ui-flags": "file:../dotcom-ui-flags",
27
+ "@financial-times/dotcom-ui-polyfill-service": "file:../dotcom-ui-polyfill-service",
29
28
  "mime-types": "^2.1.26"
30
29
  },
31
30
  "peerDependencies": {
@@ -35,6 +34,9 @@
35
34
  "node": ">= 14.0.0",
36
35
  "npm": "7.x || 8.x"
37
36
  },
37
+ "files": [
38
+ "dist/"
39
+ ],
38
40
  "repository": {
39
41
  "type": "git",
40
42
  "repository": "https://github.com/Financial-Times/dotcom-page-kit.git",
@@ -48,4 +50,4 @@
48
50
  "check-engine": "^1.10.1",
49
51
  "react": "^16.8.6"
50
52
  }
51
- }
53
+ }
@@ -1,25 +0,0 @@
1
- import React from 'react'
2
-
3
- export type TContentProps = {
4
- contents?: string | React.ReactNode
5
- }
6
-
7
- const styles = {
8
- display: 'contents'
9
- }
10
-
11
- function Content({ contents }: TContentProps) {
12
- if (typeof contents === 'string') {
13
- return <div style={styles} dangerouslySetInnerHTML={{ __html: contents }} />
14
- }
15
-
16
- // We could try and validate this but there are so many possibilities
17
- // of node types and potentially nested arrays etc.
18
- if (contents) {
19
- return <React.Fragment>{contents}</React.Fragment>
20
- }
21
-
22
- return null
23
- }
24
-
25
- export default Content
@@ -1,103 +0,0 @@
1
- import React from 'react'
2
- import imageServiceIconURL from '../lib/imageServiceIconURL'
3
- import OpenGraph, { TOpenGraphProps } from './OpenGraph'
4
- import LinkedData, { TLinkedDataProps } from './LinkedData'
5
-
6
- export type TDocumentHeadProps = TOpenGraphProps &
7
- TLinkedDataProps & {
8
- description?: string
9
- facebookPage?: string
10
- googleSiteVerification?: string
11
- metaTags?: Array<{ [key: string]: any }>
12
- pageTitle: string
13
- robots?: string
14
- siteTitle?: string
15
- twitterSite?: string
16
- canonicalURL?: string
17
- manifestFile?: string
18
- additionalMetadata?: React.ReactNode,
19
- showSmartBanner?: boolean
20
- }
21
-
22
- const DocumentHead = (props: TDocumentHeadProps) => (
23
- <React.Fragment>
24
- <meta charSet="utf-8" />
25
- <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
26
- <meta name="viewport" content="width=device-width, initial-scale=1" />
27
-
28
- <title>{props.pageTitle ? `${props.pageTitle} | ${props.siteTitle}` : props.siteTitle}</title>
29
-
30
- {props.description && <meta name="description" content={props.description} />}
31
-
32
- {props.canonicalURL && <link rel="canonical" href={props.canonicalURL} />}
33
-
34
- {/* SEO */}
35
- <meta name="robots" content={props.robots} />
36
- <meta name="google-site-verification" content={props.googleSiteVerification} />
37
- {props.metaTags.map((attributes, i) => (
38
- <meta key={`meta-${i}`} {...attributes} />
39
- ))}
40
- <LinkedData jsonLd={props.jsonLd} />
41
-
42
- {/* social media */}
43
- <meta property="fb:pages" content={props.facebookPage} />
44
- <meta property="twitter:site" content={props.twitterSite} />
45
- <OpenGraph openGraph={props.openGraph} />
46
-
47
- {/* native apps */}
48
- {props.showSmartBanner &&
49
- (
50
- <meta
51
- name="apple-itunes-app"
52
- content={props.canonicalURL ? `app-id=1200842933, app-argument=${props.canonicalURL}` : 'app-id=1200842933'}
53
- />
54
- )
55
- }
56
-
57
- {/* packaging */}
58
- <link
59
- rel="icon"
60
- type="image/svg+xml"
61
- href={imageServiceIconURL('ftlogo-v1:brand-ft-logo-square-coloured', 0, 'svg')}
62
- />
63
- <link
64
- rel="alternate icon"
65
- type="image/png"
66
- href={imageServiceIconURL('ftlogo-v1:brand-ft-logo-square-coloured', 32)}
67
- sizes="32x32"
68
- />
69
- <link
70
- rel="alternate icon"
71
- type="image/png"
72
- href={imageServiceIconURL('ftlogo-v1:brand-ft-logo-square-coloured', 194)}
73
- sizes="194x194"
74
- />
75
- <link
76
- rel="apple-touch-icon"
77
- href={imageServiceIconURL('ftlogo-v1:brand-ft-logo-square-coloured', 180)}
78
- sizes="180x180"
79
- />
80
-
81
- {props.manifestFile ? <link rel="manifest" href={props.manifestFile} /> : null}
82
-
83
- {/* We can't add an option for every single metadata option so allow custom elements to be inserted*/}
84
- {props.additionalMetadata}
85
- </React.Fragment>
86
- )
87
-
88
- DocumentHead.defaultProps = {
89
- description:
90
- 'News, analysis and comment from the Financial Times, the worldʼs leading global business publication',
91
- facebookPage: '8860325749',
92
- googleSiteVerification: '4-t8sFaPvpO5FH_Gnw1dkM28CQepjzo8UjjAkdDflTw',
93
- metaTags: [],
94
- jsonLd: [],
95
- robots: 'index,follow,max-snippet:200,max-image-preview:large',
96
- siteTitle: 'Financial Times',
97
- twitterSite: '@FinancialTimes',
98
- manifestFile: 'https://www.ft.com/__assets/creatives/manifest/manifest-v6.json',
99
- additionalMetadata: null,
100
- showSmartBanner: true
101
- }
102
-
103
- export default DocumentHead
@@ -1,29 +0,0 @@
1
- import React from 'react'
2
- import { TFlagsData } from '@financial-times/dotcom-ui-flags/src/types'
3
-
4
- // This component is maintained by the ads team
5
- const GTMBody = ({ flags }: { flags: TFlagsData }) => {
6
- if (!flags.enableGTM) {
7
- return null
8
- }
9
-
10
- return (
11
- <noscript>
12
- <iframe
13
- src="https://www.googletagmanager.com/ns.html?id=GTM-NWQJW68"
14
- height="0"
15
- width="0"
16
- style={{
17
- display: 'none',
18
- visibility: 'hidden'
19
- }}
20
- />
21
- </noscript>
22
- )
23
- }
24
-
25
- GTMBody.defaultProps = {
26
- flags: {}
27
- }
28
-
29
- export default GTMBody
@@ -1,23 +0,0 @@
1
- import React from 'react'
2
- import { TFlagsData } from '@financial-times/dotcom-ui-flags/src/types'
3
-
4
- // This component is maintained by the ads team
5
- const GTMHead = ({ flags }: { flags: TFlagsData }) => {
6
- if (!flags.enableGTM) {
7
- return null
8
- }
9
-
10
- const tagManager = `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
11
- new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
12
- j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
13
- 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
14
- })(window,document,'script','dataLayer','GTM-NWQJW68');`
15
-
16
- return <script dangerouslySetInnerHTML={{ __html: tagManager }} />
17
- }
18
-
19
- GTMHead.defaultProps = {
20
- flags: {}
21
- }
22
-
23
- export default GTMHead
@@ -1,38 +0,0 @@
1
- import React from 'react'
2
-
3
- export type TLinkedDataProps = {
4
- jsonLd?: { [key: string]: any }
5
- }
6
-
7
- const LinkedData = ({ jsonLd }: TLinkedDataProps) => (
8
- <React.Fragment>
9
- {Array.isArray(jsonLd) &&
10
- jsonLd.map((data, i) => (
11
- <script
12
- key={`jsonld-${i}`}
13
- type="application/ld+json"
14
- dangerouslySetInnerHTML={{
15
- __html: JSON.stringify(data)
16
- }}
17
- />
18
- ))}
19
- <script
20
- type="application/ld+json"
21
- dangerouslySetInnerHTML={{
22
- __html: JSON.stringify({
23
- '@context': 'http://schema.org',
24
- '@type': 'WebSite',
25
- name: 'Financial Times',
26
- alternateName: 'FT.com',
27
- url: 'http://www.ft.com'
28
- })
29
- }}
30
- />
31
- </React.Fragment>
32
- )
33
-
34
- LinkedData.defaultProps = {
35
- jsonLd: []
36
- }
37
-
38
- export default LinkedData
@@ -1,20 +0,0 @@
1
- import React from 'react'
2
- import flattenOpenGraphData, { TOpenGraphData } from '../lib/flattenOpenGraphData'
3
-
4
- export type TOpenGraphProps = {
5
- openGraph?: TOpenGraphData
6
- }
7
-
8
- const OpenGraph = ({ openGraph }: TOpenGraphProps) => (
9
- <React.Fragment>
10
- {flattenOpenGraphData(openGraph).map(([property, content], i) => (
11
- <meta key={`og-${i}`} property={property} content={content} />
12
- ))}
13
- </React.Fragment>
14
- )
15
-
16
- OpenGraph.defaultProps = {
17
- openGraph: {}
18
- }
19
-
20
- export default OpenGraph
@@ -1,63 +0,0 @@
1
- import React from 'react'
2
- import mimeTypes from 'mime-types'
3
- import getResourceType from '../lib/getResourceType'
4
-
5
- export type TResourceHintsProps = {
6
- resourceHints?: string[]
7
- }
8
-
9
- const ResourceHints = (props: TResourceHintsProps) => {
10
- return (
11
- <React.Fragment>
12
- {/*
13
- Spoor is the API which receives the tracking events sent by the o-tracking library
14
- <https://github.com/Financial-Times/o-tracking>
15
- */}
16
- <link rel="preconnect" href="https://spoor-api.ft.com" />
17
- {/*
18
- The session API is used to validate users and retrieve information about them
19
- <https://github.com/Financial-Times/next-session>
20
- */}
21
- <link rel="preconnect" href="https://session-next.ft.com" crossOrigin="use-credentials" />
22
- {/*
23
- The ads API is used to fetch ad targeting information for the current page
24
- <https://github.com/Financial-Times/next-ads-api>
25
- */}
26
- <link rel="preconnect" href="https://ads-api.ft.com" />
27
- {/*
28
- The Google Publisher Tag library (GPT) is hosted here which is used to deliver ads
29
- <https://github.com/Financial-Times/o-ads/blob/HEAD/src/js/ad-servers/gpt.js>
30
- */}
31
- <link rel="preconnect" href="https://securepubads.g.doubleclick.net" />
32
-
33
- {props.resourceHints.map((resource, i) => {
34
- const contentType = getResourceType(resource)
35
- const mimeType =
36
- mimeTypes.lookup(resource) ||
37
- mimeTypes.lookup(resource.match(/(?<=font_format=)([a-z0-9]+)/)?.[0]) ||
38
- null
39
-
40
- const attributes: React.LinkHTMLAttributes<HTMLLinkElement> = {
41
- as: contentType,
42
- href: resource,
43
- type: mimeType
44
- }
45
-
46
- // Fonts are expected to be fetched anonymously by the browser, and the preload request is
47
- // only made anonymous by using the crossorigin attribute.
48
- // <https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content>
49
- if (contentType === 'font') {
50
- attributes.crossOrigin = 'anonymous'
51
- }
52
-
53
- return <link key={`hint-${i}`} rel="preload" {...attributes} />
54
- })}
55
- </React.Fragment>
56
- )
57
- }
58
-
59
- ResourceHints.defaultProps = {
60
- resourceHints: []
61
- }
62
-
63
- export default ResourceHints
@@ -1,97 +0,0 @@
1
- import React from 'react'
2
- import Content, { TContentProps } from './Content'
3
- import DocumentHead, { TDocumentHeadProps } from './DocumentHead'
4
- import StyleSheets, { TStylesheetProps } from './StyleSheets'
5
- import ResourceHints, { TResourceHintsProps } from './ResourceHints'
6
- import { AppContextEmbed, TAppContextProps } from '@financial-times/dotcom-ui-app-context'
7
- import {
8
- fontFaceURLs,
9
- documentStyles,
10
- LoadFontsEmbed,
11
- loadCustomFontsClassNames
12
- } from '@financial-times/dotcom-ui-base-styles'
13
- import { FlagsEmbed, TFlagsEmbedProps } from '@financial-times/dotcom-ui-flags'
14
- import { Bootstrap, TBootstrapProps } from '@financial-times/dotcom-ui-bootstrap'
15
- import * as polyfillService from '@financial-times/dotcom-ui-polyfill-service'
16
- import formatAttributeNames, { TAttributeData } from '../lib/formatAttributeNames'
17
- import GTMHead from './GTMHead'
18
- import GTMBody from './GTMBody'
19
-
20
- type TShellProps = TDocumentHeadProps &
21
- TAppContextProps &
22
- TStylesheetProps &
23
- TResourceHintsProps &
24
- TContentProps &
25
- TFlagsEmbedProps & {
26
- scripts?: string[]
27
- children?: any
28
- initialProps?: any
29
- bodyAttributes?: TAttributeData
30
- htmlAttributes?: TAttributeData
31
- }
32
-
33
- function Shell(props: TShellProps) {
34
- const bootstrapProps: TBootstrapProps = {
35
- coreScripts: [polyfillService.core()],
36
- enhancedScripts: [polyfillService.enhanced(), ...props.scripts]
37
- }
38
-
39
- const resourceHints = [
40
- polyfillService.enhanced(),
41
- // There is no need to include stylesheets here as any <link rel="stylesheet" /> tags
42
- // should be found by the browser's speculative parser.
43
- ...props.scripts,
44
- ...props.resourceHints,
45
- ...fontFaceURLs
46
- ]
47
-
48
- return (
49
- <html
50
- {...formatAttributeNames(props.htmlAttributes)}
51
- lang="en-GB"
52
- className={`no-js core ${loadCustomFontsClassNames}`}
53
- data-o-component="o-typography"
54
- style={documentStyles}
55
- >
56
- <head>
57
- <DocumentHead {...props} />
58
- <ResourceHints resourceHints={resourceHints} />
59
- {/* TODO: refactor initial props, flags data, and context data to the bottom of body */}
60
- <script
61
- id="initial-props"
62
- type="application/json"
63
- dangerouslySetInnerHTML={{ __html: JSON.stringify(props.initialProps) }}
64
- />
65
- <StyleSheets
66
- criticalStyles={props.criticalStyles}
67
- stylesheets={props.stylesheets}
68
- asyncStylesheets={props.asyncStylesheets}
69
- />
70
- <Bootstrap {...bootstrapProps} />
71
- <GTMHead flags={props.flags} />
72
- <LoadFontsEmbed />
73
- </head>
74
- <body {...formatAttributeNames(props.bodyAttributes)}>
75
- <GTMBody flags={props.flags} />
76
- <Content contents={props.contents || props.children} />
77
- <AppContextEmbed appContext={props.appContext} />
78
- <FlagsEmbed flags={props.flags} />
79
- </body>
80
- </html>
81
- )
82
- }
83
-
84
- Shell.defaultProps = {
85
- scripts: [],
86
- stylesheets: [],
87
- asyncStylesheets: [],
88
- resourceHints: [],
89
- htmlAttributes: {},
90
- bodyAttributes: {}
91
- }
92
-
93
- export { Shell }
94
- export type { TShellProps }
95
-
96
- // Export sub-components to more-easily enable custom integrations
97
- export { DocumentHead, ResourceHints, Content }
@@ -1,35 +0,0 @@
1
- import React from 'react'
2
- import loadAsyncStylesheetsString from '../lib/loadAsyncStylesheets'
3
-
4
- export type TStylesheetProps = {
5
- criticalStyles?: string
6
- stylesheets?: string[]
7
- asyncStylesheets?: string[]
8
- }
9
-
10
- const Stylesheets = ({ criticalStyles, stylesheets, asyncStylesheets }: TStylesheetProps) => (
11
- <React.Fragment>
12
- {criticalStyles && <style dangerouslySetInnerHTML={{ __html: criticalStyles }} />}
13
- {Array.isArray(stylesheets) &&
14
- stylesheets.map((stylesheet, i) => <link rel="stylesheet" key={`stylesheet-${i}`} href={stylesheet} />)}
15
- {Array.isArray(asyncStylesheets) && !!asyncStylesheets.length && (
16
- <React.Fragment>
17
- <noscript>
18
- {asyncStylesheets.map((stylesheet, i) => (
19
- <link rel="stylesheet" href={stylesheet} key={`async-stylesheet-${i}`} />
20
- ))}
21
- </noscript>
22
- <script
23
- data-stylesheets={asyncStylesheets.join()}
24
- dangerouslySetInnerHTML={{ __html: loadAsyncStylesheetsString }}></script>
25
- </React.Fragment>
26
- )}
27
- </React.Fragment>
28
- )
29
-
30
- Stylesheets.defaultProps = {
31
- stylesheets: [],
32
- asyncStylesheets: []
33
- }
34
-
35
- export default Stylesheets
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './components/Shell'
@@ -1,24 +0,0 @@
1
- // Flattens a nested object into an array of key/value pairs
2
- // { foo: { bar: { baz: 123 } } } => [['foo:bar:baz', 123]]
3
-
4
- export type TOpenGraphData = {
5
- [key: string]: any | any[] | TOpenGraphData
6
- }
7
-
8
- export default function flattenData(data: TOpenGraphData, prefix?: string): Array<string[]> {
9
- const output = []
10
-
11
- for (const [key, value] of Object.entries(data)) {
12
- const property = prefix ? `${prefix}:${key}` : key
13
-
14
- if (value && value.constructor === Object) {
15
- output.push(...flattenData(value, property))
16
- } else if (Array.isArray(value)) {
17
- output.push(...value.map((value) => [property, value]))
18
- } else {
19
- output.push([property, value])
20
- }
21
- }
22
-
23
- return output
24
- }
@@ -1,36 +0,0 @@
1
- export type TAttributeData = {
2
- [key: string]: string | number | boolean
3
- }
4
-
5
- export default function formatAttributeNames(data: TAttributeData = {}) {
6
- const output = {}
7
-
8
- for (const [key, value] of Object.entries(data)) {
9
- const hyphenatedKey = hyphenateString(key)
10
-
11
- // Let's render boolean data attributes properly
12
- // as per https://github.com/Financial-Times/dotcom-page-kit/issues/370
13
- if (hyphenatedKey.startsWith('data-') && typeof value === 'boolean') {
14
- // Where react is concerned, a `true` boolean data attribute
15
- // is one where the attribute value is an empty string (because
16
- // it is not possible to render an attribute without a value),
17
- // and a `false` boolean data attribute is one where the attribute
18
- // has not been specified altogether
19
- if (value) {
20
- output[hyphenatedKey] = ''
21
- }
22
- } else {
23
- output[hyphenatedKey] = value
24
- }
25
- }
26
-
27
- return output
28
- }
29
-
30
- function hyphenateChar(char) {
31
- return '-' + char.toLowerCase()
32
- }
33
-
34
- function hyphenateString(prop) {
35
- return prop.replace(/([A-Z])/g, hyphenateChar)
36
- }
@@ -1,34 +0,0 @@
1
- import path from 'path'
2
- import url from 'url'
3
-
4
- const StyleFiles = new Set(['.css'])
5
-
6
- const ScriptFiles = new Set(['.js', '.mjs'])
7
-
8
- const ImageFiles = new Set(['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp'])
9
-
10
- export default (file: string): string => {
11
- // Always parse the file so that we can ignore any domain names, query strings etc.
12
- // Node's old URL API is able to parse anything inc. filenames, paths, and URLs.
13
- const { pathname } = url.parse(file)
14
-
15
- const extension = path.extname(pathname)
16
-
17
- if (StyleFiles.has(extension)) {
18
- return 'style'
19
- }
20
-
21
- if (ScriptFiles.has(extension)) {
22
- return 'script'
23
- }
24
-
25
- if (ImageFiles.has(extension)) {
26
- return 'image'
27
- }
28
-
29
- if (file.includes('font_format=woff')) {
30
- return 'font'
31
- }
32
-
33
- throw Error(`Unknown filename extension "${extension}`)
34
- }
@@ -1,24 +0,0 @@
1
- import querystring from 'querystring'
2
-
3
- function imageServiceIconURL(image: string, size: number, format = 'png'): string {
4
- const serviceURL = 'https://www.ft.com/__origami/service/image/v2/images/raw/'
5
-
6
- const serviceParameters = {
7
- source: 'update-logos',
8
- format: format,
9
- width: size,
10
- height: size
11
- }
12
-
13
- // Do not add width and height if format is svg because svg files scale automatically
14
- if (format === 'svg') {
15
- delete serviceParameters.width
16
- delete serviceParameters.height
17
- }
18
-
19
- const queryString = querystring.stringify(serviceParameters)
20
-
21
- return `${serviceURL}${encodeURIComponent(image)}?${queryString}`
22
- }
23
-
24
- export default imageServiceIconURL
@@ -1,27 +0,0 @@
1
- /*
2
- Load stylesheets asyncronously. See:
3
- • https://www.filamentgroup.com/lab/load-css-simpler/
4
- • https://w3c.github.io/preload/#example-5
5
-
6
- @NOTE: This is in ES5 syntax, because it's not compiled, because it's server-side code.
7
- (You don't need to compile server-side code because you get to set whichever version of node you want.)
8
- Its stringified and given to the client via "dangerouslySetInnerHTML" in a <script> tag.
9
- Because it runs in the client, it needs to be ES5 so it's compatible with older browsers.
10
- */
11
- function loadAsyncStylesheets() {
12
- var currentScript = document.scripts[document.scripts.length - 1]
13
- var stylesheets = currentScript.getAttribute('data-stylesheets').split(',')
14
-
15
- for (var i = 0, len = stylesheets.length; i < len; i++) {
16
- var link = document.createElement('link')
17
- link.href = stylesheets[i]
18
- link.rel = 'stylesheet'
19
- link.media = 'print' // <-- 'print' is intentional; on load, it changes to 'all'.
20
- link.onload = function (event) {
21
- var target = event.target as HTMLLinkElement
22
- target.media = 'all'
23
- }
24
- currentScript.parentNode.insertBefore(link, currentScript)
25
- }
26
- }
27
- export default '(' + loadAsyncStylesheets.toString() + ')()'