sfc-utils 1.3.25 → 1.3.28

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 (81) hide show
  1. package/README.md +4 -2
  2. package/accountswap.js +3 -2
  3. package/copy/c2p_sheet.js +7 -7
  4. package/css/nav2.less +1 -1
  5. package/example/.prettierrc +5 -0
  6. package/example/README.md +8 -0
  7. package/example/gatsby-config.js +131 -0
  8. package/example/gatsby-node.js +45 -0
  9. package/example/package-lock.json +13418 -0
  10. package/example/package.json +71 -0
  11. package/example/project-config.json +42 -0
  12. package/example/src/components/layout.js +236 -0
  13. package/example/src/components/sfc/ad.js +47 -0
  14. package/example/src/components/sfc/ai2html/ai2html_template.ai +1369 -4
  15. package/example/src/components/sfc/button.js +40 -0
  16. package/example/src/components/sfc/byline.js +42 -0
  17. package/example/src/components/sfc/component-helpers/customhooks.js +17 -0
  18. package/example/src/components/sfc/component-helpers/datehelpers.js +55 -0
  19. package/example/src/components/sfc/component-helpers/newsletterhelpers.js +89 -0
  20. package/example/src/components/sfc/component-helpers/requesthelpers.js +7 -0
  21. package/example/src/components/sfc/component-helpers/scrolldownhelpers.js +11 -0
  22. package/example/src/components/sfc/component-helpers/utilfunctions.js +68 -0
  23. package/example/src/components/sfc/creditline.js +35 -0
  24. package/example/src/components/sfc/credits.js +17 -0
  25. package/example/src/components/sfc/creditssection.js +47 -0
  26. package/example/src/components/sfc/dropcap.js +15 -0
  27. package/example/src/components/sfc/footer.js +36 -0
  28. package/example/src/components/sfc/geocoder.js +148 -0
  29. package/example/src/components/sfc/misccredit.js +17 -0
  30. package/example/src/components/sfc/navtop.js +121 -0
  31. package/example/src/components/sfc/newsletter.js +157 -0
  32. package/example/src/components/sfc/relatedlink.js +23 -0
  33. package/example/src/components/sfc/relatedrow.js +23 -0
  34. package/example/src/components/sfc/relatedsection.js +27 -0
  35. package/example/src/components/sfc/safelink.js +86 -0
  36. package/example/src/components/sfc/scrolldown.js +22 -0
  37. package/example/src/components/sfc/sharebuttons.js +93 -0
  38. package/example/src/components/sfc/topper.js +88 -0
  39. package/example/src/components/sfc/video.js +74 -0
  40. package/example/src/components/sfc/wcmimage.js +131 -0
  41. package/example/src/data/sfc/images/react.gif +0 -0
  42. package/example/src/data/sfc/related_links.json +17 -0
  43. package/example/src/html.js +41 -0
  44. package/example/src/pages/index.js +143 -0
  45. package/example/src/styles/defaults.less +99 -0
  46. package/example/src/styles/footer.less +345 -0
  47. package/example/src/styles/modules/ad.module.less +21 -0
  48. package/example/src/styles/modules/ai2html.module.less +19 -0
  49. package/example/src/styles/modules/button.module.less +94 -0
  50. package/example/src/styles/modules/byline.module.less +11 -0
  51. package/example/src/styles/modules/creditline.module.less +12 -0
  52. package/example/src/styles/modules/credits.module.less +7 -0
  53. package/example/src/styles/modules/creditssection.module.less +17 -0
  54. package/example/src/styles/modules/dropcap.module.less +18 -0
  55. package/example/src/styles/modules/geocoder.module.less +79 -0
  56. package/example/src/styles/modules/newsletter.module.less +147 -0
  57. package/example/src/styles/modules/relatedlink.module.less +28 -0
  58. package/example/src/styles/modules/relatedrow.module.less +8 -0
  59. package/example/src/styles/modules/relatedsection.module.less +19 -0
  60. package/example/src/styles/modules/scrolldown.module.less +31 -0
  61. package/example/src/styles/modules/share.module.less +22 -0
  62. package/example/src/styles/modules/topper.module.less +63 -0
  63. package/example/src/styles/modules/video.module.less +27 -0
  64. package/example/src/styles/modules/wcmimage.module.less +20 -0
  65. package/example/src/styles/nav.less +187 -0
  66. package/example/src/styles/project.less +1 -0
  67. package/example/src/styles/reset.css +95 -0
  68. package/example/src/styles/seed.less +5 -0
  69. package/example/src/styles/typography.css +168 -0
  70. package/example/src/styles/values.less +74 -0
  71. package/example/static/manifest.webmanifest +1 -0
  72. package/example/tasks/create-c2p-sheet.js +6 -0
  73. package/example/tasks/deploy-addon.py +14 -0
  74. package/example/tasks/google-docs.js +16 -0
  75. package/example/tasks/google-sheets.js +17 -0
  76. package/example/tasks/node-helpers.js +81 -0
  77. package/example/tasks/post-build.sh +7 -0
  78. package/example/tasks/pre-build.sh +18 -0
  79. package/example/tempsettings.js +28 -0
  80. package/package.json +1 -1
  81. package/settings.js +1 -1
@@ -0,0 +1,74 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import videoStyles from '../../styles/modules/video.module.less'
4
+
5
+ export default function Video({
6
+ id,
7
+ containerClass,
8
+ innerContainerClass,
9
+ videoClass,
10
+ autoPlay = true,
11
+ loop = true,
12
+ muted = true,
13
+ alt,
14
+ cap,
15
+ cred,
16
+ }) {
17
+ return (
18
+ <figure className={containerClass ? containerClass : videoStyles.container}>
19
+ <div
20
+ className={
21
+ innerContainerClass
22
+ ? innerContainerClass
23
+ : innerContainerClass === null
24
+ ? ''
25
+ : videoStyles.responsiveContainer
26
+ }
27
+ >
28
+ <video
29
+ className={videoClass ? videoClass : videoStyles.default}
30
+ autoPlay={autoPlay}
31
+ loop={loop}
32
+ muted={muted}
33
+ preload="auto"
34
+ alt={alt}
35
+ poster={`https://files.sfchronicle.com/static-assets/compression-bot/${id}.jpg`}
36
+ >
37
+ <source
38
+ src={`https://files.sfchronicle.com/static-assets/compression-bot/${id}.mp4`}
39
+ type="video/mp4"
40
+ />
41
+ <source
42
+ src={`https://files.sfchronicle.com/static-assets/compression-bot/${id}.m3u8`}
43
+ type="application/x-mpegURL"
44
+ />
45
+ </video>
46
+ </div>
47
+ {cap && cred && (
48
+ <figcaption className={videoStyles.cFigCap}>
49
+ {cap} <span className={videoStyles.cFigCred}>{cred}</span>
50
+ </figcaption>
51
+ )}
52
+ {!cap && cred && (
53
+ <figcaption className={videoStyles.cFigCap}>
54
+ <span className={videoStyles.cFigCred}>{cred}</span>
55
+ </figcaption>
56
+ )}
57
+ {cap && !cred && (
58
+ <figcaption className={videoStyles.cFigCap}>{cap}</figcaption>
59
+ )}
60
+ </figure>
61
+ )
62
+ }
63
+
64
+ Video.propTypes = {
65
+ id: PropTypes.string.isRequired,
66
+ videoClass: PropTypes.string,
67
+ containerClass: PropTypes.string,
68
+ autoPlay: PropTypes.bool,
69
+ loop: PropTypes.bool,
70
+ muted: PropTypes.bool,
71
+ alt: PropTypes.string.isRequired,
72
+ cred: PropTypes.string,
73
+ cap: PropTypes.string,
74
+ }
@@ -0,0 +1,131 @@
1
+ import React, {useRef, useEffect, useLayoutEffect, useState} from 'react'
2
+ import LazyLoad from 'react-lazyload'
3
+ import PropTypes from 'prop-types'
4
+ import * as wcmimageStyles from '../../styles/modules/wcmimage.module.less'
5
+ import { useStaticQuery, graphql } from "gatsby"
6
+ import { debounce } from '../sfc/component-helpers/utilfunctions'
7
+
8
+ const currentEnv = process.env.GATSBY_DEPLOY_ENV
9
+
10
+ const WCMImage = ({ wcm, alt, cap, cred, lz, className, ratio }) => {
11
+ // When the wrapping div is rendered, we're going to figure out the best size for this image to be
12
+ let picRef = useRef(null)
13
+ let [imageRez, setImageRez] = useState(0)
14
+
15
+ let setImageWidth = () => {
16
+ let pixelWidth = 900 // Default width if we need a fallback
17
+ let pixelRatio = window.devicePixelRatio || 1
18
+ if (picRef.current && picRef.current.offsetWidth){
19
+ pixelWidth = Math.round(picRef.current.offsetWidth * pixelRatio)
20
+ }
21
+ if (imageRez < pixelWidth){ // No need to resize if we're just scaling down
22
+ setImageRez(pixelWidth)
23
+ }
24
+ }
25
+
26
+ useEffect(() => {
27
+ const debouncedHandleResize = debounce(function handleResize() {
28
+ setImageWidth()
29
+ }, 500)
30
+ window.addEventListener('resize', debouncedHandleResize)
31
+
32
+ return () => {
33
+ window.removeEventListener('resize', debouncedHandleResize)
34
+ }
35
+ })
36
+
37
+ useEffect(() => {
38
+ setImageWidth()
39
+ }, [])
40
+
41
+ // Use GraphQL to grab the data for the WCM photo we want
42
+ const data = useStaticQuery(graphql`
43
+ query PhotoQuery {
44
+ allWcmPhotos {
45
+ nodes {
46
+ photo {
47
+ ratio
48
+ wcmid
49
+ full_path
50
+ }
51
+ }
52
+ }
53
+ }
54
+ `)
55
+
56
+ let photoRatio = "56.25%"; // Default to 16/9
57
+ let fullPath = `https://s.hdnux.com/photos/0/0/0/${wcm}/0/`;
58
+ if (!ratio){
59
+ let matchedPhoto = data.allWcmPhotos.nodes.find((item) => {
60
+ return item.photo.wcmid.toString() === wcm.toString()
61
+ })
62
+ if (!matchedPhoto && currentEnv !== "development"){
63
+ throw `WCMImage error: No matching ID for ${wcm} present in the array at the top of gatsby-node.js! If it's already there, you might need to reboot dev.`
64
+ }
65
+ if (matchedPhoto){
66
+ // Set ratio of the actual photo like a legit hacker
67
+ photoRatio = (matchedPhoto.photo.ratio*100)+"%";
68
+ fullPath = matchedPhoto.photo.full_path;
69
+ } else {
70
+ // Alert that things will go wrong on deploy
71
+ console.error(`No matching ID for ${wcm} found in gatsby-node.js! This is fine for development, but it will error on deploy!`);
72
+ }
73
+ } else {
74
+ // If an override is being passed in, use that
75
+ photoRatio = ratio
76
+ }
77
+
78
+ // Get serious about alt tags
79
+ if (typeof alt !== "string"){
80
+ throw `WCMImage error: Image for ${wcm} needs an alt tag! Please add a good, descriptive alt tag. Suggestion from Mozilla: When choosing alt strings for your images, imagine what you would say when reading the page to someone over the phone without mentioning that there's an image on the page.`
81
+ }
82
+
83
+ // Conditionally lazyload if we want to and have the capability
84
+ const ConditionalWrapper = ({ condition, wrapper, children }) =>
85
+ condition ? wrapper(children) : children;
86
+
87
+ return (
88
+ <figure className={className ? className : ""}>
89
+ <div ref={picRef} style={{paddingBottom: photoRatio, overflow: "hidden", position: "relative"}}>
90
+ <ConditionalWrapper
91
+ condition={!lz}
92
+ wrapper={children => <LazyLoad offset={300} resize once>{children}</LazyLoad>}
93
+ >
94
+ {imageRez > 0 &&
95
+ <img style={{position: "absolute"}}
96
+ className={wcmimageStyles.cImg}
97
+ // "lazy" won't work on older browsers, which is why we use LazyLoad conditionally
98
+ loading="lazy"
99
+ src={`${fullPath}${imageRez}x0.jpg`}
100
+ // PLEASE INCLUDE ALTS
101
+ alt={alt}
102
+ />
103
+ }
104
+ </ConditionalWrapper>
105
+ </div>
106
+ {cap && cred && (
107
+ <figcaption className={wcmimageStyles.cFigCap}>
108
+ {cap} <span className={wcmimageStyles.cFigCred}>{cred}</span>
109
+ </figcaption>
110
+ )}
111
+ {!cap && cred && (
112
+ <figcaption className={wcmimageStyles.cFigCap}>
113
+ <span className={wcmimageStyles.cFigCred}>{cred}</span>
114
+ </figcaption>
115
+ )}
116
+ {cap && !cred && (
117
+ <figcaption className={wcmimageStyles.cFigCap}>{cap}</figcaption>
118
+ )}
119
+ </figure>
120
+ )
121
+ }
122
+
123
+ WCMImage.propTypes = {
124
+ wcm: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
125
+ // alt: PropTypes.string.isRequired,
126
+ cap: PropTypes.string,
127
+ cred: PropTypes.string,
128
+ className: PropTypes.string,
129
+ }
130
+
131
+ export default WCMImage
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "title": "TK TITLE1",
4
+ "url": "https://www.sfchronicle.com",
5
+ "wcmid": 20374215
6
+ },
7
+ {
8
+ "title": "TK TITLE2",
9
+ "url": "https://www.sfchronicle.com",
10
+ "wcmid": 20374215
11
+ },
12
+ {
13
+ "title": "TK TITLE3",
14
+ "url": "https://www.sfchronicle.com",
15
+ "wcmid": 20374215
16
+ }
17
+ ]
@@ -0,0 +1,41 @@
1
+ import React from "react"
2
+ import PropTypes from "prop-types"
3
+
4
+ export default function HTML(props) {
5
+ return (
6
+ <html {...props.htmlAttributes}>
7
+ <head>
8
+ <meta charSet="utf-8" />
9
+ <meta httpEquiv="x-ua-compatible" content="ie=edge" />
10
+ <meta
11
+ name="viewport"
12
+ content="width=device-width, initial-scale=1, shrink-to-fit=no"
13
+ />
14
+ <script src="https://projects.sfchronicle.com/shared/js/jquery.min.js"></script>
15
+ <script src="https://treg.hearstnp.com/treg.js"></script>
16
+ {props.headComponents}
17
+ </head>
18
+ <body {...props.bodyAttributes} is="responsive-body">
19
+ {props.preBodyComponents}
20
+ <noscript key="noscript" id="gatsby-noscript">
21
+ This app works best with JavaScript enabled.
22
+ </noscript>
23
+ <div
24
+ key={`body`}
25
+ id="___gatsby"
26
+ dangerouslySetInnerHTML={{ __html: props.body }}
27
+ />
28
+ {props.postBodyComponents}
29
+ </body>
30
+ </html>
31
+ )
32
+ }
33
+
34
+ HTML.propTypes = {
35
+ htmlAttributes: PropTypes.object,
36
+ headComponents: PropTypes.array,
37
+ bodyAttributes: PropTypes.object,
38
+ preBodyComponents: PropTypes.array,
39
+ body: PropTypes.string,
40
+ postBodyComponents: PropTypes.array,
41
+ }
@@ -0,0 +1,143 @@
1
+ import React from 'react'
2
+ import { graphql } from 'gatsby'
3
+ import PropTypes from 'prop-types'
4
+ // import useSWR from 'swr'
5
+ // import { getData } from '../components/sfc/component-helpers/requesthelpers'
6
+ import Layout from '../components/layout'
7
+ import WCMImage from '../components/sfc/wcmimage'
8
+ import DropCap from '../components/sfc/dropcap'
9
+ import { useCanNativeLazyLoad } from '../components/sfc/component-helpers/customhooks'
10
+ import Topper from '../components/sfc/topper'
11
+ import RelatedSection from '../components/sfc/relatedsection'
12
+ import CreditsSection from '../components/sfc/creditssection'
13
+ import Ad from '../components/sfc/ad'
14
+ import Newsletter from '../components/sfc/newsletter'
15
+ let rawCredits;
16
+ try {
17
+ rawCredits = require('../data/credits.sheet.json')
18
+ } catch (err){
19
+ // It's fine
20
+ rawCredits = null;
21
+ }
22
+ let related_links;
23
+ try{
24
+ related_links = require('../data/related_links.sheet.json')
25
+ } catch(err){
26
+ related_links = require('../data/sfc/related_links.json')
27
+ }
28
+
29
+ const IndexPage = ({ data }) => {
30
+ // easy hooks based request library
31
+ // const { data: responseData, error } = useSWR('https://api.kanye.rest', getData, {
32
+ // onSuccess: (data) => console.log(data),
33
+ // onError: (err) => console.log(err),
34
+ // })
35
+
36
+ // custom hook checks for nativelazyload
37
+ const lazy = useCanNativeLazyLoad()
38
+
39
+ const {
40
+ site: { siteMetadata },
41
+ allRelatedLinksJson: { nodes: relatedLinks },
42
+ } = data
43
+
44
+ return (
45
+ <Layout meta={siteMetadata}>
46
+ <Topper meta={siteMetadata} />
47
+ <main>
48
+ <article>
49
+ <p>
50
+ <DropCap>T</DropCap>
51
+ he Savage nodded, frowning. "You got rid of them. Yes, that's just
52
+ like you. Getting rid of everything unpleasant instead of learning
53
+ to put up with it. Whether 'tis better in the mind to suffer the
54
+ slings and arrows or outrageous fortune, or to take arms against a
55
+ sea of troubles and by opposing end them... But you don't do either.
56
+ Neither suffer nor oppose. You just abolish the slings and arrows.
57
+ It's too easy."
58
+ </p>
59
+
60
+ <p>
61
+ The Savage nodded, frowning. "You got rid of them. Yes, that's just
62
+ like you. Getting rid of everything unpleasant instead of learning
63
+ to put up with it. Whether 'tis better in the mind to suffer the
64
+ slings and arrows or outrageous fortune, or to take arms against a
65
+ sea of troubles and by opposing end them... But you don't do either.
66
+ Neither suffer nor oppose. You just abolish the slings and arrows.
67
+ It's too easy."
68
+ </p>
69
+
70
+ {/* Wrapping div supports "embed-" + center/left/right/full classes */}
71
+ <div className="embed-center">
72
+ <WCMImage wcm={20374215} alt="TKTKTK" lz={lazy} cap={"TKTKTK caption"} />
73
+ </div>
74
+
75
+ <p>
76
+ The Savage nodded, frowning. "You got rid of them. Yes, that's just
77
+ like you. Getting rid of everything unpleasant instead of learning
78
+ to put up with it. Whether 'tis better in the mind to suffer the
79
+ slings and arrows or outrageous fortune, or to take arms against a
80
+ sea of troubles and by opposing end them... But you don't do either.
81
+ Neither suffer nor oppose. You just abolish the slings and arrows.
82
+ It's too easy."
83
+ </p>
84
+
85
+ <Ad adLetter="A" />
86
+
87
+ <Newsletter />
88
+ </article>
89
+ </main>
90
+
91
+ <RelatedSection links={related_links} />
92
+ {rawCredits && <CreditsSection creditsData={rawCredits}/>}
93
+ </Layout>
94
+ )
95
+ }
96
+
97
+ export const query = graphql`
98
+ {
99
+ site {
100
+ siteMetadata {
101
+ EMBEDDED
102
+ MAIN_DOMAIN
103
+ PAYWALL_SETTING
104
+ PROJECT {
105
+ AUTHORS {
106
+ AUTHOR_NAME
107
+ AUTHOR_PAGE
108
+ }
109
+ DATE
110
+ DESCRIPTION
111
+ HEARST_CATEGORY
112
+ KEY_SUBJECTS
113
+ DECK
114
+ DISPLAY_TITLE
115
+ IMAGE
116
+ ISO_MODDATE
117
+ ISO_PUBDATE
118
+ OPT_SLASH
119
+ SLUG
120
+ SOCIAL_TITLE
121
+ SUBFOLDER
122
+ TITLE
123
+ TWITTER_TEXT
124
+ ANALYTICS_CREDIT
125
+ MARKET_KEY
126
+ CANONICAL_URL
127
+ }
128
+ }
129
+ }
130
+ allRelatedLinksJson {
131
+ nodes {
132
+ wcmid
133
+ title
134
+ url
135
+ }
136
+ }
137
+ }
138
+ `
139
+ IndexPage.propTypes = {
140
+ data: PropTypes.object.isRequired,
141
+ }
142
+
143
+ export default IndexPage
@@ -0,0 +1,99 @@
1
+ // A home for our CSS that we think should be on all projects
2
+ //elements
3
+ body {
4
+ color: @text;
5
+ font-family: @serif-book;
6
+ width: 100%;
7
+ height: 100%;
8
+ min-width: 100%;
9
+ min-height: 100%;
10
+ }
11
+
12
+ hr {
13
+ color: @light-gray;
14
+ max-width: 33%;
15
+ margin-left: auto;
16
+ margin-right: auto;
17
+ }
18
+
19
+ article {
20
+ margin-top: @step-3;
21
+ }
22
+
23
+ h1,
24
+ h2,
25
+ h3,
26
+ h4 {
27
+ line-height: 1.2;
28
+ font-weight: normal;
29
+ font-variant-numeric: lining-nums;
30
+ font-kerning: normal;
31
+ font-variant-ligatures: normal;
32
+ text-rendering: optimizeLegibility;
33
+ max-width: 720px;
34
+ margin-left: auto;
35
+ margin-right: auto;
36
+ }
37
+
38
+ p {
39
+ font-size: @base-font-size;
40
+ max-width: 720px;
41
+ margin-left: auto;
42
+ margin-right: auto;
43
+ padding: 0 @step--1;
44
+ }
45
+
46
+ a {
47
+ color: @text;
48
+ text-decoration: underline;
49
+ text-decoration-color: @brand;
50
+ text-decoration-skip-ink: auto;
51
+ outline: 0 !important;
52
+
53
+ &:hover {
54
+ color: @brand;
55
+ }
56
+
57
+ &:visited {
58
+ color: @gray;
59
+ }
60
+ }
61
+
62
+ .grecaptcha-badge { // Captcha text handled in widget
63
+ display: none;
64
+ }
65
+
66
+ iframe {
67
+ border: none !important;
68
+ }
69
+
70
+ .gg-chevron-down {
71
+ --ggs: 2;
72
+ }
73
+
74
+ // Handle basic embed classes
75
+ .embed-center, .embed-left, .embed-right, .embed-full {
76
+ max-width: 800px;
77
+ margin: @step-3 auto;
78
+ width: 100%;
79
+ padding: 0 @step--1;
80
+ }
81
+
82
+ .embed-left {
83
+ float: left;
84
+ max-width: 600px;
85
+ }
86
+
87
+ .embed-right {
88
+ float: right;
89
+ max-width: 600px;
90
+ }
91
+
92
+ .embed-full {
93
+ max-width: 100%;
94
+ padding: 0;
95
+
96
+ figcaption {
97
+ padding: 0 10px;
98
+ }
99
+ }