sfc-utils 1.3.25 → 1.3.26
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/accountswap.js +3 -2
- package/css/nav2.less +1 -1
- package/example/.prettierrc +5 -0
- package/example/README.md +8 -0
- package/example/gatsby-config.js +131 -0
- package/example/gatsby-node.js +45 -0
- package/example/package-lock.json +13418 -0
- package/example/package.json +71 -0
- package/example/project-config.json +42 -0
- package/example/src/components/layout.js +236 -0
- package/example/src/components/sfc/ad.js +47 -0
- package/example/src/components/sfc/ai2html/ai2html_template.ai +1369 -4
- package/example/src/components/sfc/button.js +40 -0
- package/example/src/components/sfc/byline.js +42 -0
- package/example/src/components/sfc/component-helpers/customhooks.js +17 -0
- package/example/src/components/sfc/component-helpers/datehelpers.js +55 -0
- package/example/src/components/sfc/component-helpers/newsletterhelpers.js +89 -0
- package/example/src/components/sfc/component-helpers/requesthelpers.js +7 -0
- package/example/src/components/sfc/component-helpers/scrolldownhelpers.js +11 -0
- package/example/src/components/sfc/component-helpers/utilfunctions.js +68 -0
- package/example/src/components/sfc/creditline.js +35 -0
- package/example/src/components/sfc/credits.js +17 -0
- package/example/src/components/sfc/creditssection.js +47 -0
- package/example/src/components/sfc/dropcap.js +15 -0
- package/example/src/components/sfc/footer.js +36 -0
- package/example/src/components/sfc/geocoder.js +148 -0
- package/example/src/components/sfc/misccredit.js +17 -0
- package/example/src/components/sfc/navtop.js +121 -0
- package/example/src/components/sfc/newsletter.js +157 -0
- package/example/src/components/sfc/relatedlink.js +23 -0
- package/example/src/components/sfc/relatedrow.js +23 -0
- package/example/src/components/sfc/relatedsection.js +27 -0
- package/example/src/components/sfc/safelink.js +86 -0
- package/example/src/components/sfc/scrolldown.js +22 -0
- package/example/src/components/sfc/sharebuttons.js +93 -0
- package/example/src/components/sfc/topper.js +88 -0
- package/example/src/components/sfc/video.js +74 -0
- package/example/src/components/sfc/wcmimage.js +131 -0
- package/example/src/data/sfc/images/react.gif +0 -0
- package/example/src/data/sfc/related_links.json +17 -0
- package/example/src/html.js +41 -0
- package/example/src/pages/index.js +143 -0
- package/example/src/styles/defaults.less +99 -0
- package/example/src/styles/footer.less +345 -0
- package/example/src/styles/modules/ad.module.less +21 -0
- package/example/src/styles/modules/ai2html.module.less +19 -0
- package/example/src/styles/modules/button.module.less +94 -0
- package/example/src/styles/modules/byline.module.less +11 -0
- package/example/src/styles/modules/creditline.module.less +12 -0
- package/example/src/styles/modules/credits.module.less +7 -0
- package/example/src/styles/modules/creditssection.module.less +17 -0
- package/example/src/styles/modules/dropcap.module.less +18 -0
- package/example/src/styles/modules/geocoder.module.less +79 -0
- package/example/src/styles/modules/newsletter.module.less +147 -0
- package/example/src/styles/modules/relatedlink.module.less +28 -0
- package/example/src/styles/modules/relatedrow.module.less +8 -0
- package/example/src/styles/modules/relatedsection.module.less +19 -0
- package/example/src/styles/modules/scrolldown.module.less +31 -0
- package/example/src/styles/modules/share.module.less +22 -0
- package/example/src/styles/modules/topper.module.less +63 -0
- package/example/src/styles/modules/video.module.less +27 -0
- package/example/src/styles/modules/wcmimage.module.less +20 -0
- package/example/src/styles/nav.less +187 -0
- package/example/src/styles/project.less +1 -0
- package/example/src/styles/reset.css +95 -0
- package/example/src/styles/seed.less +5 -0
- package/example/src/styles/typography.css +168 -0
- package/example/src/styles/values.less +74 -0
- package/example/static/manifest.webmanifest +1 -0
- package/example/tasks/create-c2p-sheet.js +6 -0
- package/example/tasks/deploy-addon.py +14 -0
- package/example/tasks/google-docs.js +16 -0
- package/example/tasks/google-sheets.js +17 -0
- package/example/tasks/node-helpers.js +81 -0
- package/example/tasks/post-build.sh +7 -0
- package/example/tasks/pre-build.sh +18 -0
- package/example/tempsettings.js +28 -0
- package/package.json +1 -1
- package/settings.js +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "utilstest",
|
|
3
|
+
"description": "A Hearst interactive project",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "ewagstaff",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"axios": "0.27.2",
|
|
8
|
+
"css.gg": "2.0.0",
|
|
9
|
+
"gatsby": "4.13.0",
|
|
10
|
+
"gatsby-plugin-htaccess": "1.4.0",
|
|
11
|
+
"gatsby-plugin-html-attributes": "1.0.5",
|
|
12
|
+
"gatsby-plugin-less": "6.13.0",
|
|
13
|
+
"gatsby-plugin-preact": "6.13.0",
|
|
14
|
+
"gatsby-plugin-react-helmet": "5.13.0",
|
|
15
|
+
"gatsby-source-filesystem": "4.13.0",
|
|
16
|
+
"gatsby-transformer-json": "4.13.0",
|
|
17
|
+
"jump.js": "1.0.2",
|
|
18
|
+
"less": "4.1.1",
|
|
19
|
+
"preact": "10.5.13",
|
|
20
|
+
"preact-render-to-string": "5.2.0",
|
|
21
|
+
"prop-types": "15.7.2",
|
|
22
|
+
"react": "16.14.0",
|
|
23
|
+
"react-dom": "16.14.0",
|
|
24
|
+
"react-headroom": "3.1.1",
|
|
25
|
+
"react-helmet": "6.1.0",
|
|
26
|
+
"react-lazyload": "3.2.0",
|
|
27
|
+
"require-directory": "2.1.1",
|
|
28
|
+
"swr": "^0.5.6"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"gatsby"
|
|
32
|
+
],
|
|
33
|
+
"browserslist": [
|
|
34
|
+
"Chrome >= 61",
|
|
35
|
+
"ChromeAndroid >= 80",
|
|
36
|
+
"Safari >= 11",
|
|
37
|
+
"iOS >= 11",
|
|
38
|
+
"Firefox >= 60",
|
|
39
|
+
"FirefoxAndroid >= 68",
|
|
40
|
+
"Edge >= 16",
|
|
41
|
+
"Opera >= 48",
|
|
42
|
+
"Android >= 80",
|
|
43
|
+
"Samsung >= 8.2"
|
|
44
|
+
],
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"deploy:git": "func() { npm run clean && export GATSBY_DEPLOY_ENV=\"$1\" && export GATSBY_DEPLOY_ORIGIN=\"$2\" && tasks/pre-build.sh && gatsby build --prefix-paths && tasks/post-build.sh; }; func",
|
|
48
|
+
"auth": "tasks/googleauth.js",
|
|
49
|
+
"sheets": "tasks/google-sheets.js",
|
|
50
|
+
"docs": "tasks/google-docs.js",
|
|
51
|
+
"dev": "export GATSBY_DEPLOY_ENV=development && gatsby develop -H 0.0.0.0",
|
|
52
|
+
"makec2p": "tasks/create-c2p-sheet.js",
|
|
53
|
+
"clean": "rm -rf .cache && rm -rf public_export && rm -rf public",
|
|
54
|
+
"format": "prettier --write \"src/**/*.js\"",
|
|
55
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
56
|
+
"analyze": "export ANALYZE_BUNDLE_SIZE=true && gatsby build"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"babel-eslint": "10.1.0",
|
|
60
|
+
"eslint": "7.7.0",
|
|
61
|
+
"gatsby-plugin-webpack-bundle-analyser-v2": "^1.1.27",
|
|
62
|
+
"luxon": "1.24.1",
|
|
63
|
+
"prettier": "2.0",
|
|
64
|
+
"probe-image-size": "^7.0.1",
|
|
65
|
+
"request": "^2.88.2"
|
|
66
|
+
},
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "The possible paywall values are 'meter' (hit the paywall after a certain number of free stories), 'paywall' (paywall immediately), 'free' (no wall), or 'meter-no-paywall' (count this against the reader's meter, but never show the paywall on this page)",
|
|
3
|
+
"PAYWALL_SETTING": "meter",
|
|
4
|
+
"EMBEDDED": false,
|
|
5
|
+
"GOOGLE_SHEETS": [],
|
|
6
|
+
"GOOGLE_DOCS": [],
|
|
7
|
+
|
|
8
|
+
"_domain_explainer": "NOTE: MAIN_DOMAIN will get swapped out based on the MARKEY_KEY when deployed on the server. If you are building it locally for a repo push, you need to set the domain manually here.",
|
|
9
|
+
"MAIN_DOMAIN": "https://projects.sfchronicle.com",
|
|
10
|
+
|
|
11
|
+
"PROJECT": {
|
|
12
|
+
"_key_explainer": "NOTE: Change MARKET_KEY to deploy to other markets using their domain and settings. Accepted markets include: SFC, Houston, SanAntonio, Albany, CT",
|
|
13
|
+
"MARKET_KEY": "SFC",
|
|
14
|
+
|
|
15
|
+
"_comment": "IMPORTANT: SUBFOLDER and SLUG for used for file pathing and the deploy script! Take care with your edits to them! NOTE: Stage deploys will automatically go to 'projects/test-proj'",
|
|
16
|
+
"SUBFOLDER": "{%= subfolder_path %}",
|
|
17
|
+
"SLUG": "{%= app_slug %}",
|
|
18
|
+
|
|
19
|
+
"TITLE": "",
|
|
20
|
+
"DISPLAY_TITLE": "",
|
|
21
|
+
"SOCIAL_TITLE": "",
|
|
22
|
+
"IMAGE": "",
|
|
23
|
+
"DESCRIPTION": "",
|
|
24
|
+
"DECK": "",
|
|
25
|
+
"TWITTER_TEXT": "Some social text",
|
|
26
|
+
"_options_for_HEARST_CATEGORY": "Bay Area,Politics,Climate,Weather,California Wildfires,Food,Sports,Tech,Travel,US & World,Chronicle Vault,Opinion",
|
|
27
|
+
"HEARST_CATEGORY": "Bay Area",
|
|
28
|
+
"KEY_SUBJECTS": "Data",
|
|
29
|
+
"DATE": "January 1, 1970 6:00 PM",
|
|
30
|
+
|
|
31
|
+
"NEWSLETTER_ID": "SFC_NL_TopStories",
|
|
32
|
+
"NEWSLETTER_PROMO": "Get the Bay Area's best journalism delivered to my inbox daily",
|
|
33
|
+
"NEWSLETTER_LEGAL": "By subscribing, you agree to our <a href=\"https://www.sfchronicle.com/terms_of_use/\">Terms of Use</a> and acknowledge that your information will be used as described in our <a href=\"https://www.sfchronicle.com/privacy_policy/\"> Privacy Notice</a>.",
|
|
34
|
+
|
|
35
|
+
"AUTHORS": [
|
|
36
|
+
{
|
|
37
|
+
"AUTHOR_NAME": "Chronicle Digital Team",
|
|
38
|
+
"AUTHOR_PAGE": "https://projects.sfchronicle.com/"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/* Layout wraps all pages so updates here effect everything */
|
|
2
|
+
|
|
3
|
+
import React, { Fragment, useEffect } from 'react'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import { Helmet } from 'react-helmet'
|
|
6
|
+
|
|
7
|
+
// Bring in footer
|
|
8
|
+
import Footer from './sfc/footer'
|
|
9
|
+
|
|
10
|
+
// Add SFC utils
|
|
11
|
+
import { blendHDN, appCheck, getBrands, getBlueconic } from '../../../index'
|
|
12
|
+
|
|
13
|
+
// Import global styles needed in document
|
|
14
|
+
require('../styles/seed.less')
|
|
15
|
+
|
|
16
|
+
const Layout = ({
|
|
17
|
+
meta,
|
|
18
|
+
url_add = '',
|
|
19
|
+
description = false,
|
|
20
|
+
image = false,
|
|
21
|
+
social_title = false,
|
|
22
|
+
title = false,
|
|
23
|
+
children,
|
|
24
|
+
}) => {
|
|
25
|
+
// Determine if we need registration code
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
EMBEDDED,
|
|
29
|
+
MAIN_DOMAIN,
|
|
30
|
+
PROJECT: {
|
|
31
|
+
AUTHORS,
|
|
32
|
+
DESCRIPTION,
|
|
33
|
+
IMAGE,
|
|
34
|
+
ISO_MODDATE,
|
|
35
|
+
ISO_PUBDATE,
|
|
36
|
+
OPT_SLASH,
|
|
37
|
+
SLUG,
|
|
38
|
+
SOCIAL_TITLE,
|
|
39
|
+
SUBFOLDER,
|
|
40
|
+
TITLE,
|
|
41
|
+
MARKET_KEY,
|
|
42
|
+
CANONICAL_URL
|
|
43
|
+
},
|
|
44
|
+
} = meta
|
|
45
|
+
|
|
46
|
+
// Override these if they exist (but just use the default otherwise)
|
|
47
|
+
DESCRIPTION = description || DESCRIPTION
|
|
48
|
+
IMAGE = image || IMAGE
|
|
49
|
+
SOCIAL_TITLE = social_title || SOCIAL_TITLE
|
|
50
|
+
TITLE = title || TITLE
|
|
51
|
+
|
|
52
|
+
// Make sure url_add ends with a slash
|
|
53
|
+
if (url_add && url_add.slice(-1) !== "/"){
|
|
54
|
+
url_add += "/"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Set fonts by MARKET_KEY
|
|
58
|
+
switch(MARKET_KEY){
|
|
59
|
+
case "SFC": require('../../../fonts/sfc.less'); break;
|
|
60
|
+
case "Houston": require('../../../fonts/houston.less'); break;
|
|
61
|
+
case "Albany": require('../../../fonts/albany.less'); break;
|
|
62
|
+
// TK many more
|
|
63
|
+
default: require('../../../fonts/default.less'); break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine if app ver
|
|
67
|
+
// Either from the build settings or from the query string
|
|
68
|
+
const isApp = appCheck()
|
|
69
|
+
|
|
70
|
+
// Combine our settings with what Hearst puts on page
|
|
71
|
+
let stringHDN = ''
|
|
72
|
+
if (!EMBEDDED) {
|
|
73
|
+
// Put url_add into a new meta object to pass in
|
|
74
|
+
const metaHDN = Object.assign({}, meta)
|
|
75
|
+
metaHDN.URL_ADD = url_add
|
|
76
|
+
// Make sure this is free on app
|
|
77
|
+
if (isApp){
|
|
78
|
+
metaHDN.PAYWALL_SETTING = "free";
|
|
79
|
+
}
|
|
80
|
+
let blended = blendHDN(metaHDN)
|
|
81
|
+
stringHDN = blended.stringHDN
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get brand vars
|
|
85
|
+
const thisBrand = getBrands(MARKET_KEY);
|
|
86
|
+
|
|
87
|
+
// Handle author data
|
|
88
|
+
let authorObj = []
|
|
89
|
+
let newAuthor = {}
|
|
90
|
+
try {
|
|
91
|
+
AUTHORS.forEach(author => {
|
|
92
|
+
newAuthor = {
|
|
93
|
+
'@type': 'Person',
|
|
94
|
+
name: author.AUTHOR_NAME,
|
|
95
|
+
url: author.AUTHOR_PAGE,
|
|
96
|
+
}
|
|
97
|
+
authorObj.push(newAuthor)
|
|
98
|
+
})
|
|
99
|
+
} catch (err) {
|
|
100
|
+
// If it errored, just set to neutral default
|
|
101
|
+
authorObj = {
|
|
102
|
+
'@type': 'Person',
|
|
103
|
+
name: thisBrand.attributes.siteName,
|
|
104
|
+
url: MAIN_DOMAIN,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
// React Helmet is actually terrible and runs these scripts twice, so we are including them async ourselves
|
|
110
|
+
// Run analytics and resizing scripts right away so we take care of that
|
|
111
|
+
if (!EMBEDDED){
|
|
112
|
+
let script = document.createElement('script');
|
|
113
|
+
script.type = 'text/javascript';
|
|
114
|
+
script.src = 'https://nexus.ensighten.com/hearst/news/Bootstrap.js';
|
|
115
|
+
document.body.appendChild(script);
|
|
116
|
+
} else {
|
|
117
|
+
let script = document.createElement('script');
|
|
118
|
+
script.type = 'text/javascript';
|
|
119
|
+
script.src = 'https://projects.sfchronicle.com/shared/js/responsive-child.js';
|
|
120
|
+
document.body.appendChild(script);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!EMBEDDED && !isApp){
|
|
124
|
+
let script = document.createElement('script');
|
|
125
|
+
script.type = 'text/javascript';
|
|
126
|
+
script.id = 'adPositionManagerScriptTag';
|
|
127
|
+
script.src = 'https://aps.hearstnp.com/Scripts/loadAds.js';
|
|
128
|
+
document.body.appendChild(script);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Wait a beat, then add to body so it doesn't mess with the head (which Helmet seems to want to manage)
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
if (!EMBEDDED && !isApp){
|
|
134
|
+
let blueconicURL = getBlueconic(window.location.origin)
|
|
135
|
+
let script = document.createElement('script');
|
|
136
|
+
script.type = 'text/javascript';
|
|
137
|
+
script.defer = true;
|
|
138
|
+
script.src = blueconicURL;
|
|
139
|
+
document.body.appendChild(script);
|
|
140
|
+
}
|
|
141
|
+
}, 5000)
|
|
142
|
+
}, [])
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<Fragment>
|
|
146
|
+
{/* Forcing HDN vars in so we can feed them to ensighten */}
|
|
147
|
+
<Helmet
|
|
148
|
+
script={[
|
|
149
|
+
{
|
|
150
|
+
type: 'text/javascript',
|
|
151
|
+
innerHTML: stringHDN,
|
|
152
|
+
},
|
|
153
|
+
]}
|
|
154
|
+
/>
|
|
155
|
+
<Helmet>
|
|
156
|
+
<title>{TITLE}</title>
|
|
157
|
+
<meta name="description" content={DESCRIPTION} />
|
|
158
|
+
<link
|
|
159
|
+
rel="shortcut icon"
|
|
160
|
+
href="/favicon.ico"
|
|
161
|
+
type="image/x-icon"
|
|
162
|
+
/>
|
|
163
|
+
<link rel="canonical" href={ CANONICAL_URL } />
|
|
164
|
+
|
|
165
|
+
{(isApp || EMBEDDED) ? (
|
|
166
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
167
|
+
) : (
|
|
168
|
+
<meta name="robots" content="max-image-preview:large" />
|
|
169
|
+
)}
|
|
170
|
+
|
|
171
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
172
|
+
<meta name="twitter:title" content={SOCIAL_TITLE} />
|
|
173
|
+
<meta name="twitter:site" content={"@"+thisBrand.attributes.twitter} />
|
|
174
|
+
<meta
|
|
175
|
+
name="twitter:url"
|
|
176
|
+
content={`${MAIN_DOMAIN}/${SUBFOLDER}${OPT_SLASH}${SLUG}/${url_add}`}
|
|
177
|
+
/>
|
|
178
|
+
<meta name="twitter:image" content={IMAGE} />
|
|
179
|
+
<meta name="twitter:description" content={DESCRIPTION} />
|
|
180
|
+
|
|
181
|
+
<meta property="og:type" content="article" />
|
|
182
|
+
<meta property="og:title" content={SOCIAL_TITLE} />
|
|
183
|
+
<meta property="og:site_name" content={thisBrand.attributes.siteName} />
|
|
184
|
+
<meta property="og:url" content={`${MAIN_DOMAIN}/${SUBFOLDER}${OPT_SLASH}${SLUG}/${url_add}`}/>
|
|
185
|
+
<meta property="og:image" content={IMAGE} />
|
|
186
|
+
<meta property="og:description" content={DESCRIPTION} />
|
|
187
|
+
|
|
188
|
+
<script data-schema="NewsArticle" type="application/ld+json">{`{
|
|
189
|
+
"@context": "http://schema.org",
|
|
190
|
+
"@type": "NewsArticle",
|
|
191
|
+
"mainEntityOfPage": {
|
|
192
|
+
"@type": "WebPage",
|
|
193
|
+
"@id": "${MAIN_DOMAIN}/${SUBFOLDER}${OPT_SLASH}${SLUG}/${url_add}"
|
|
194
|
+
},
|
|
195
|
+
"headline": "${TITLE}",
|
|
196
|
+
"image": {
|
|
197
|
+
"@type": "ImageObject",
|
|
198
|
+
"url": "${IMAGE}"
|
|
199
|
+
},
|
|
200
|
+
"datePublished": "${ISO_PUBDATE}",
|
|
201
|
+
"dateModified": "${ISO_MODDATE}",
|
|
202
|
+
"author": ${JSON.stringify(authorObj)},
|
|
203
|
+
"publisher": {
|
|
204
|
+
"@type": "Organization",
|
|
205
|
+
"name": "${thisBrand.attributes.siteName}",
|
|
206
|
+
"logo": {
|
|
207
|
+
"@type": "ImageObject",
|
|
208
|
+
"url": "/apple-touch-icon.png",
|
|
209
|
+
"width": "180",
|
|
210
|
+
"height": "180"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"description": "${DESCRIPTION}"
|
|
214
|
+
}`}</script>
|
|
215
|
+
</Helmet>
|
|
216
|
+
|
|
217
|
+
{/* Full project included here: */}
|
|
218
|
+
{children}
|
|
219
|
+
|
|
220
|
+
{/* Include footer unless it's embedded or the app version: */}
|
|
221
|
+
{!EMBEDDED && !isApp && <Footer meta={meta} />}
|
|
222
|
+
</Fragment>
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
Layout.propTypes = {
|
|
227
|
+
meta: PropTypes.object.isRequired,
|
|
228
|
+
url_add: PropTypes.string,
|
|
229
|
+
children: PropTypes.node.isRequired,
|
|
230
|
+
image: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
231
|
+
description: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
232
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
233
|
+
social_title: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default Layout
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import * as adStyles from '../../styles/modules/ad.module.less'
|
|
4
|
+
|
|
5
|
+
// Hearst ad -- make sure Juice is fully loaded before running the script logic
|
|
6
|
+
const Ad = ({ adLetter }) => {
|
|
7
|
+
const [loaded, setLoaded] = useState(false)
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
let attemptLoad = () => {
|
|
11
|
+
if (typeof hearstPlaceAd === "undefined"){
|
|
12
|
+
// The function isn't ready yet, so wait
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
attemptLoad()
|
|
15
|
+
}, 1000)
|
|
16
|
+
} else {
|
|
17
|
+
// We have the function, so set loaded
|
|
18
|
+
setLoaded(true)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Kick off loop
|
|
23
|
+
attemptLoad()
|
|
24
|
+
}, [])
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className={adStyles.ad}>
|
|
28
|
+
<p className={adStyles.adhed}>Advertisement</p>
|
|
29
|
+
<div id={`${adLetter}Pflex`}>
|
|
30
|
+
{loaded &&
|
|
31
|
+
<script
|
|
32
|
+
type="text/javascript"
|
|
33
|
+
dangerouslySetInnerHTML={{
|
|
34
|
+
__html: `/*<![CDATA[*/hearstPlaceAd("${adLetter}Pflex");/*]]>*/`,
|
|
35
|
+
}}
|
|
36
|
+
></script>
|
|
37
|
+
}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Ad.propTypes = {
|
|
44
|
+
adLetter: PropTypes.string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default Ad
|