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.
Files changed (79) hide show
  1. package/accountswap.js +3 -2
  2. package/css/nav2.less +1 -1
  3. package/example/.prettierrc +5 -0
  4. package/example/README.md +8 -0
  5. package/example/gatsby-config.js +131 -0
  6. package/example/gatsby-node.js +45 -0
  7. package/example/package-lock.json +13418 -0
  8. package/example/package.json +71 -0
  9. package/example/project-config.json +42 -0
  10. package/example/src/components/layout.js +236 -0
  11. package/example/src/components/sfc/ad.js +47 -0
  12. package/example/src/components/sfc/ai2html/ai2html_template.ai +1369 -4
  13. package/example/src/components/sfc/button.js +40 -0
  14. package/example/src/components/sfc/byline.js +42 -0
  15. package/example/src/components/sfc/component-helpers/customhooks.js +17 -0
  16. package/example/src/components/sfc/component-helpers/datehelpers.js +55 -0
  17. package/example/src/components/sfc/component-helpers/newsletterhelpers.js +89 -0
  18. package/example/src/components/sfc/component-helpers/requesthelpers.js +7 -0
  19. package/example/src/components/sfc/component-helpers/scrolldownhelpers.js +11 -0
  20. package/example/src/components/sfc/component-helpers/utilfunctions.js +68 -0
  21. package/example/src/components/sfc/creditline.js +35 -0
  22. package/example/src/components/sfc/credits.js +17 -0
  23. package/example/src/components/sfc/creditssection.js +47 -0
  24. package/example/src/components/sfc/dropcap.js +15 -0
  25. package/example/src/components/sfc/footer.js +36 -0
  26. package/example/src/components/sfc/geocoder.js +148 -0
  27. package/example/src/components/sfc/misccredit.js +17 -0
  28. package/example/src/components/sfc/navtop.js +121 -0
  29. package/example/src/components/sfc/newsletter.js +157 -0
  30. package/example/src/components/sfc/relatedlink.js +23 -0
  31. package/example/src/components/sfc/relatedrow.js +23 -0
  32. package/example/src/components/sfc/relatedsection.js +27 -0
  33. package/example/src/components/sfc/safelink.js +86 -0
  34. package/example/src/components/sfc/scrolldown.js +22 -0
  35. package/example/src/components/sfc/sharebuttons.js +93 -0
  36. package/example/src/components/sfc/topper.js +88 -0
  37. package/example/src/components/sfc/video.js +74 -0
  38. package/example/src/components/sfc/wcmimage.js +131 -0
  39. package/example/src/data/sfc/images/react.gif +0 -0
  40. package/example/src/data/sfc/related_links.json +17 -0
  41. package/example/src/html.js +41 -0
  42. package/example/src/pages/index.js +143 -0
  43. package/example/src/styles/defaults.less +99 -0
  44. package/example/src/styles/footer.less +345 -0
  45. package/example/src/styles/modules/ad.module.less +21 -0
  46. package/example/src/styles/modules/ai2html.module.less +19 -0
  47. package/example/src/styles/modules/button.module.less +94 -0
  48. package/example/src/styles/modules/byline.module.less +11 -0
  49. package/example/src/styles/modules/creditline.module.less +12 -0
  50. package/example/src/styles/modules/credits.module.less +7 -0
  51. package/example/src/styles/modules/creditssection.module.less +17 -0
  52. package/example/src/styles/modules/dropcap.module.less +18 -0
  53. package/example/src/styles/modules/geocoder.module.less +79 -0
  54. package/example/src/styles/modules/newsletter.module.less +147 -0
  55. package/example/src/styles/modules/relatedlink.module.less +28 -0
  56. package/example/src/styles/modules/relatedrow.module.less +8 -0
  57. package/example/src/styles/modules/relatedsection.module.less +19 -0
  58. package/example/src/styles/modules/scrolldown.module.less +31 -0
  59. package/example/src/styles/modules/share.module.less +22 -0
  60. package/example/src/styles/modules/topper.module.less +63 -0
  61. package/example/src/styles/modules/video.module.less +27 -0
  62. package/example/src/styles/modules/wcmimage.module.less +20 -0
  63. package/example/src/styles/nav.less +187 -0
  64. package/example/src/styles/project.less +1 -0
  65. package/example/src/styles/reset.css +95 -0
  66. package/example/src/styles/seed.less +5 -0
  67. package/example/src/styles/typography.css +168 -0
  68. package/example/src/styles/values.less +74 -0
  69. package/example/static/manifest.webmanifest +1 -0
  70. package/example/tasks/create-c2p-sheet.js +6 -0
  71. package/example/tasks/deploy-addon.py +14 -0
  72. package/example/tasks/google-docs.js +16 -0
  73. package/example/tasks/google-sheets.js +17 -0
  74. package/example/tasks/node-helpers.js +81 -0
  75. package/example/tasks/post-build.sh +7 -0
  76. package/example/tasks/pre-build.sh +18 -0
  77. package/example/tempsettings.js +28 -0
  78. package/package.json +1 -1
  79. 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