sfc-utils 1.3.54 → 1.3.56
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/brands2.js +1 -1
- package/components/authors.mjs +41 -0
- package/components/byline.mjs +79 -0
- package/components/captioncredit.mjs +31 -0
- package/components/heading.mjs +33 -0
- package/components/helpers/datehelpers.mjs +54 -0
- package/components/helpers/utilfunctions.mjs +12 -0
- package/components/sharebuttons.mjs +93 -0
- package/components/topper2.mjs +202 -0
- package/components/wcmimage2.mjs +111 -0
- package/copy/c2p_sheet.js +1 -1
- package/css/nav2.less +1 -0
- package/example/gatsby-config.js +2 -2
- package/example/gatsby-node.js +7 -1
- package/example/project-config.json +3 -3
- package/example/src/components/layout.js +9 -9
- package/example/src/pages/index.js +36 -6
- package/example/src/styles/credittooltip.less +55 -0
- package/example/src/styles/footer.less +48 -38
- package/example/src/styles/{defaults.less → old css/defaults.less} +0 -0
- package/example/src/styles/old css/footer.less +345 -0
- package/example/src/styles/old css/nav.less +187 -0
- package/example/src/styles/old css/project.less +1 -0
- package/example/src/styles/old css/reset.css +95 -0
- package/example/src/styles/old css/seed.less +7 -0
- package/example/src/styles/{typography.css → old css/typography.css} +0 -0
- package/example/src/styles/old css/values.less +74 -0
- package/example/src/styles/project.less +1 -1
- package/example/src/styles/reset.css +4 -2
- package/example/src/styles/seed.less +4 -3
- package/example/src/styles/values.less +129 -0
- package/example/src/styles/variables.less +142 -0
- package/package.json +2 -1
- package/settings.js +10 -1
- package/styles/brandStylesCommon.less +164 -0
- package/styles/modules/share.module.less +25 -0
- package/styles/modules/topper2.module.less +143 -0
- package/styles/modules/wcmimage2.module.less +32 -0
- package/styles/values.less +128 -0
- package/styles/variables.less +143 -0
package/brands2.js
CHANGED
|
@@ -47,7 +47,7 @@ let getBrands2 = function(market){
|
|
|
47
47
|
styles: {
|
|
48
48
|
"@brand": "#FF7500",
|
|
49
49
|
"@brand-secondary": "#1874CB",
|
|
50
|
-
"@hed": '"
|
|
50
|
+
"@hed": '"Publico Headline", Georgia, serif',
|
|
51
51
|
"@hed-alt": '"Marr Sans Condensed", Georgia, serif',
|
|
52
52
|
"@serif": '"Publico", Georgia, serif',
|
|
53
53
|
"@sans": '"Marr Sans", Helvetica, sans-serif',
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { Fragment } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
const Authors = ({ url, name, index, isLast }) => {
|
|
5
|
+
let prefix = ' '
|
|
6
|
+
// Add necessary spacing and grammar
|
|
7
|
+
if (index > 0) {
|
|
8
|
+
prefix = ', '
|
|
9
|
+
|
|
10
|
+
if (isLast) {
|
|
11
|
+
prefix = ' and '
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Fragment>
|
|
17
|
+
{url ? (
|
|
18
|
+
<Fragment>
|
|
19
|
+
{prefix}
|
|
20
|
+
<a target="_blank" rel="author noopener noreferrer" href={url}>
|
|
21
|
+
<span className="byline-name">{name}</span>
|
|
22
|
+
</a>
|
|
23
|
+
</Fragment>
|
|
24
|
+
) : (
|
|
25
|
+
<span>
|
|
26
|
+
{prefix}
|
|
27
|
+
<span className="byline-name">{name}</span>
|
|
28
|
+
</span>
|
|
29
|
+
)}
|
|
30
|
+
</Fragment>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Authors.propTypes = {
|
|
35
|
+
url: PropTypes.string.isRequired,
|
|
36
|
+
name: PropTypes.string.isRequired,
|
|
37
|
+
index: PropTypes.number,
|
|
38
|
+
isLast: PropTypes.bool,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default Authors
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { Fragment } from 'react'
|
|
2
|
+
import Authors from './authors.mjs'
|
|
3
|
+
import ShareButtons from './sharebuttons.mjs'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
pubdateString,
|
|
7
|
+
moddateString,
|
|
8
|
+
} from './helpers/datehelpers.mjs'
|
|
9
|
+
|
|
10
|
+
const Byline = ({ meta }) => {
|
|
11
|
+
const {
|
|
12
|
+
PROJECT: { AUTHORS, ISO_MODDATE, ISO_PUBDATE },
|
|
13
|
+
} = meta
|
|
14
|
+
const has_authors = AUTHORS[0].AUTHOR_NAME !== ""
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
<div className="byline-wrapper">
|
|
19
|
+
<div className="byline">
|
|
20
|
+
{has_authors &&
|
|
21
|
+
<>
|
|
22
|
+
<span>By</span>
|
|
23
|
+
{AUTHORS.map((author, index) => {
|
|
24
|
+
// Pass special flag if this is the last item
|
|
25
|
+
let isLast = false
|
|
26
|
+
if (index === AUTHORS.length - 1) {
|
|
27
|
+
isLast = true
|
|
28
|
+
}
|
|
29
|
+
// Add the bylines
|
|
30
|
+
return (
|
|
31
|
+
<Authors
|
|
32
|
+
key={author.AUTHOR_NAME}
|
|
33
|
+
url={author.AUTHOR_PAGE}
|
|
34
|
+
name={author.AUTHOR_NAME}
|
|
35
|
+
index={index}
|
|
36
|
+
isLast={isLast}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
})}
|
|
40
|
+
</>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
{ has_authors && <span> | </span> }
|
|
44
|
+
|
|
45
|
+
{ !moddateString &&
|
|
46
|
+
<>
|
|
47
|
+
|
|
48
|
+
<time
|
|
49
|
+
className="topper-dateline"
|
|
50
|
+
dateTime={ISO_PUBDATE}
|
|
51
|
+
itemProp="datePublished"
|
|
52
|
+
>
|
|
53
|
+
{!has_authors && <span>Published </span>} {pubdateString}
|
|
54
|
+
</time>
|
|
55
|
+
</>
|
|
56
|
+
}
|
|
57
|
+
{moddateString && (
|
|
58
|
+
<Fragment>
|
|
59
|
+
<time
|
|
60
|
+
className="topper-dateline updated-date"
|
|
61
|
+
dateTime={ISO_MODDATE}
|
|
62
|
+
itemProp="dateModified"
|
|
63
|
+
>
|
|
64
|
+
Updated {moddateString}
|
|
65
|
+
</time>
|
|
66
|
+
</Fragment>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
<div className="articleHeader--shareTools">
|
|
70
|
+
<div className="share-list" id="sharebutton-wrapper">
|
|
71
|
+
<ShareButtons meta={meta} />
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default Byline
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
// import * as capcredStyles from "../styles/modules/captioncredit.module.less"
|
|
3
|
+
|
|
4
|
+
const CaptionCredit = (props) => {
|
|
5
|
+
let {caption, credit, extraStyles} = props
|
|
6
|
+
|
|
7
|
+
let captionCss = ["topper-image", "caption"]; //capcredStyles.cFigCap,
|
|
8
|
+
if (extraStyles) captionCss = captionCss.concat(extraStyles);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
{caption && credit && (
|
|
13
|
+
<figcaption className={captionCss.join(' ')}>
|
|
14
|
+
{caption} <span className="credit">{credit}</span>
|
|
15
|
+
</figcaption>
|
|
16
|
+
)}
|
|
17
|
+
{!caption && credit && (
|
|
18
|
+
<figcaption className={captionCss.join(' ')}>
|
|
19
|
+
<span className="credit">{credit}</span>
|
|
20
|
+
</figcaption>
|
|
21
|
+
)}
|
|
22
|
+
{caption && !credit && (
|
|
23
|
+
<figcaption className={captionCss.join(' ')}>
|
|
24
|
+
{caption}
|
|
25
|
+
</figcaption>
|
|
26
|
+
)}
|
|
27
|
+
</>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default CaptionCredit
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
const Heading =(props) => {
|
|
4
|
+
let {level, className, text} = props
|
|
5
|
+
if (!level) {
|
|
6
|
+
level = 3
|
|
7
|
+
}
|
|
8
|
+
if (!className) {
|
|
9
|
+
className = ""
|
|
10
|
+
}
|
|
11
|
+
const object = {...props}
|
|
12
|
+
delete object["text"]
|
|
13
|
+
delete object["level"]
|
|
14
|
+
|
|
15
|
+
level = level.toString()
|
|
16
|
+
|
|
17
|
+
switch (level) {
|
|
18
|
+
case '1':
|
|
19
|
+
return <h1 {...object} className={`hed ${className}`} dangerouslySetInnerHTML={{__html:text}}></h1>
|
|
20
|
+
case '2':
|
|
21
|
+
return <h2 {...object} className={`${className}`} dangerouslySetInnerHTML={{__html:text}}></h2>
|
|
22
|
+
case '3':
|
|
23
|
+
return <h3 {...object} className={`subhead ${className}`} dangerouslySetInnerHTML={{__html:text}}></h3>
|
|
24
|
+
case '4':
|
|
25
|
+
return <h4 {...object} className={`subhead-sans ${className}`} dangerouslySetInnerHTML={{__html:text}}></h4>
|
|
26
|
+
case '5':
|
|
27
|
+
return <h5 {...object} className={`lead-in ${className}`} dangerouslySetInnerHTML={{__html:text}}></h5>
|
|
28
|
+
case '6':
|
|
29
|
+
return <h6 {...object} className={`label ${className}`} dangerouslySetInnerHTML={{__html:text}}></h6>
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default Heading
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Add SFC utils
|
|
2
|
+
import { getSettings } from '../../settings'
|
|
3
|
+
const settings = getSettings()
|
|
4
|
+
|
|
5
|
+
// declare date function variables
|
|
6
|
+
// Convert date to readable time
|
|
7
|
+
const readablePubDate = convertDatesToAP(settings.PROJECT.DATE)
|
|
8
|
+
// Check safely for MOD_DATE
|
|
9
|
+
let readableModDate
|
|
10
|
+
// Convert date string to AP style abbreviations
|
|
11
|
+
let pubdateString = readablePubDate
|
|
12
|
+
let moddateString = ''
|
|
13
|
+
|
|
14
|
+
function convertDatesToAP(dateString) {
|
|
15
|
+
// Convert date string to AP style abbreviations
|
|
16
|
+
let newDateString = dateString
|
|
17
|
+
newDateString = newDateString
|
|
18
|
+
.replace('January', 'Jan.')
|
|
19
|
+
.replace('February', 'Feb.')
|
|
20
|
+
.replace('August', 'Aug.')
|
|
21
|
+
.replace('September', 'Sept.')
|
|
22
|
+
.replace('October', 'Oct.')
|
|
23
|
+
.replace('November', 'Nov.')
|
|
24
|
+
.replace('December', 'Dec.')
|
|
25
|
+
.replace('AM', 'a.m.')
|
|
26
|
+
.replace('PM', 'p.m.')
|
|
27
|
+
// Return the result
|
|
28
|
+
return newDateString
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
;(function prepDates() {
|
|
32
|
+
if (typeof settings.PROJECT.MOD_DATE !== 'undefined') {
|
|
33
|
+
readableModDate = convertDatesToAP(settings.PROJECT.MOD_DATE)
|
|
34
|
+
} else {
|
|
35
|
+
// If MOD_DATE does not exist, set false so it doesn't render
|
|
36
|
+
readableModDate = false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Only check moddate if we have a value
|
|
40
|
+
if (readableModDate) {
|
|
41
|
+
moddateString = readableModDate
|
|
42
|
+
|
|
43
|
+
// Chop time off pubdate if possible
|
|
44
|
+
try {
|
|
45
|
+
// eslint-disable-next-line prefer-destructuring
|
|
46
|
+
pubdateString = readablePubDate.match(/.*\d{4}/gm)[0]
|
|
47
|
+
} catch (err) {
|
|
48
|
+
// That's fine
|
|
49
|
+
console.log(err)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})()
|
|
53
|
+
|
|
54
|
+
export { pubdateString, moddateString }
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import * as shareStyles from '../styles/modules/share.module.less'
|
|
3
|
+
|
|
4
|
+
const ShareButtons = ({ meta, urlAdd }) => {
|
|
5
|
+
// Extension to URL if passed in
|
|
6
|
+
if (!urlAdd) {
|
|
7
|
+
urlAdd = ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let facebookClick = (e) => {
|
|
11
|
+
const link = e.currentTarget.getAttribute('href')
|
|
12
|
+
e.preventDefault()
|
|
13
|
+
if (link) {
|
|
14
|
+
window.open(link, 'facebook-share-dialog', 'width=626,height=436')
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let subfolder = ''
|
|
19
|
+
if (meta.PROJECT.SUBFOLDER) {
|
|
20
|
+
subfolder = meta.PROJECT.SUBFOLDER + '/'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className={shareStyles.wrapper} id="sharebutton-box">
|
|
25
|
+
{/* Twitter */}
|
|
26
|
+
<a
|
|
27
|
+
href={`https://twitter.com/intent/tweet?url=${meta.MAIN_DOMAIN}%2F${subfolder}${meta.PROJECT.SLUG}%2F${urlAdd}&text=${meta.PROJECT.TWITTER_TEXT}`}
|
|
28
|
+
className={shareStyles.link}
|
|
29
|
+
>
|
|
30
|
+
<svg
|
|
31
|
+
className={shareStyles.svg}
|
|
32
|
+
data-icon="twitter"
|
|
33
|
+
role="img"
|
|
34
|
+
aria-hidden="true"
|
|
35
|
+
focusable="false"
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
viewBox="0 0 248 204"
|
|
38
|
+
>
|
|
39
|
+
<path
|
|
40
|
+
data-name="Twitter Logo"
|
|
41
|
+
fill="currentColor"
|
|
42
|
+
d="M222 51.29c.15 2.16.15 4.34.15 6.52 0 66.74-50.8 143.69-143.69 143.69A142.91 142.91 0 0 1 1 178.82a102.72 102.72 0 0 0 12 .72 101.29 101.29 0 0 0 62.72-21.66 50.53 50.53 0 0 1-47.18-35.07 50.35 50.35 0 0 0 22.8-.86 50.53 50.53 0 0 1-40.52-49.5v-.64a50.25 50.25 0 0 0 22.92 6.32 50.55 50.55 0 0 1-15.6-67.42 143.38 143.38 0 0 0 104.08 52.77 50.55 50.55 0 0 1 86.06-46.06 101.19 101.19 0 0 0 32.06-12.26 50.66 50.66 0 0 1-22.2 27.93 100.89 100.89 0 0 0 29-7.94A102.84 102.84 0 0 1 222 51.29z"
|
|
43
|
+
/>
|
|
44
|
+
</svg>
|
|
45
|
+
</a>
|
|
46
|
+
{/* Facebook */}
|
|
47
|
+
<a
|
|
48
|
+
href={`https://www.facebook.com/sharer/sharer.php?u=${meta.MAIN_DOMAIN}%2F${subfolder}${meta.PROJECT.SLUG}%2F${urlAdd}`}
|
|
49
|
+
className={shareStyles.link}
|
|
50
|
+
onClick={facebookClick}
|
|
51
|
+
>
|
|
52
|
+
<svg
|
|
53
|
+
className={shareStyles.svg}
|
|
54
|
+
aria-hidden="true"
|
|
55
|
+
focusable="false"
|
|
56
|
+
data-prefix="fab"
|
|
57
|
+
data-icon="facebook"
|
|
58
|
+
role="img"
|
|
59
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
60
|
+
viewBox="0 0 320 512"
|
|
61
|
+
>
|
|
62
|
+
<path
|
|
63
|
+
fill="currentColor"
|
|
64
|
+
d="M279.14 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06h40.42V6.26S260.43 0 225.36 0c-73.22 0-121.08 44.38-121.08 124.72v70.62H22.89V288h81.39v224h100.17V288z"
|
|
65
|
+
></path>
|
|
66
|
+
</svg>
|
|
67
|
+
</a>
|
|
68
|
+
{/* Email */}
|
|
69
|
+
<a
|
|
70
|
+
href={`mailto:?subject=${meta.PROJECT.TITLE}&body=${meta.PROJECT.DESCRIPTION}%0A%0A${meta.MAIN_DOMAIN}%2F${subfolder}${meta.PROJECT.SLUG}%2F${urlAdd}`}
|
|
71
|
+
className={shareStyles.link}
|
|
72
|
+
>
|
|
73
|
+
<svg
|
|
74
|
+
className={shareStyles.svg}
|
|
75
|
+
aria-hidden="true"
|
|
76
|
+
focusable="false"
|
|
77
|
+
data-prefix="fas"
|
|
78
|
+
data-icon="envelope"
|
|
79
|
+
role="img"
|
|
80
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
81
|
+
viewBox="0 0 512 512"
|
|
82
|
+
>
|
|
83
|
+
<path
|
|
84
|
+
fill="currentColor"
|
|
85
|
+
d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"
|
|
86
|
+
></path>
|
|
87
|
+
</svg>
|
|
88
|
+
</a>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default ShareButtons
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import Heading from "./heading.mjs"
|
|
3
|
+
import WCMImage2 from "./wcmimage2.mjs"
|
|
4
|
+
import CaptionCredit from "./captioncredit.mjs"
|
|
5
|
+
import * as topperStyles from "../styles/modules/topper2.module.less"
|
|
6
|
+
|
|
7
|
+
const Topper2 = ({ settings, wcmData, lazyloader }) => {
|
|
8
|
+
const {
|
|
9
|
+
Topper_Style, Title, Title_Style, Deck, Image, Image_Alt, Image_Caption, Image_Credits,
|
|
10
|
+
HeaderDek_Vertical_Position, HeaderDek_Vertical_Offset, HeaderDek_Horizontal_Offset, HeaderDek_Horizontal_Position, Inverted_Colors
|
|
11
|
+
} = settings
|
|
12
|
+
|
|
13
|
+
const headerDekStyleList = () => {
|
|
14
|
+
switch(Topper_Style) {
|
|
15
|
+
case "stacked":
|
|
16
|
+
case "no-visual":
|
|
17
|
+
return [topperStyles.headerDekStacked, " mw-lg mt-lg mb-md"];
|
|
18
|
+
case "full-screen":
|
|
19
|
+
// apply margin offsets from spreadsheet
|
|
20
|
+
calculatefullScreenOffsets();
|
|
21
|
+
return [
|
|
22
|
+
topperStyles.headerDekFullScreen, fullScreenHorizontalCss(),
|
|
23
|
+
... (HeaderDek_Vertical_Position === "top") ? [topperStyles.headerDekTop] : [topperStyles.headerDekBottom],
|
|
24
|
+
... (Inverted_Colors === "black-text-white-bg") ? [topperStyles.blackTextWhiteBg] : [topperStyles.whiteTextBlackBg]
|
|
25
|
+
];
|
|
26
|
+
case "side-by-side":
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** get horizontal positioning css for full screen header-deck container **/
|
|
32
|
+
const fullScreenHorizontalCss = () => {
|
|
33
|
+
switch (HeaderDek_Horizontal_Position) {
|
|
34
|
+
case "left": return topperStyles.headerDekLeft;
|
|
35
|
+
case "right": return topperStyles.headerDekRight;
|
|
36
|
+
case "center": return topperStyles.headerDekCenter;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const headerStyleList = () => {
|
|
41
|
+
let defaultStyles;
|
|
42
|
+
switch(Topper_Style) {
|
|
43
|
+
case "stacked":
|
|
44
|
+
defaultStyles = [];
|
|
45
|
+
break;
|
|
46
|
+
case "no-visual":
|
|
47
|
+
defaultStyles = ["left"];
|
|
48
|
+
break;
|
|
49
|
+
case "full-screen":
|
|
50
|
+
defaultStyles = [topperStyles.hedFullScreen, fullScreenTextAlignCss()];
|
|
51
|
+
break;
|
|
52
|
+
case "side-by-side":
|
|
53
|
+
defaultStyles = [];
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (Title_Style !== "") {
|
|
58
|
+
let extraStyles = Title_Style.split(", ");
|
|
59
|
+
defaultStyles = defaultStyles.concat(extraStyles);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return defaultStyles;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const deckStyleList = () => {
|
|
66
|
+
switch(Topper_Style) {
|
|
67
|
+
case "stacked":
|
|
68
|
+
return ["deck"];
|
|
69
|
+
case "no-visual":
|
|
70
|
+
return ["deck left"];
|
|
71
|
+
case "full-screen":
|
|
72
|
+
return ["deck", topperStyles.deckFullScreen, fullScreenTextAlignCss()];
|
|
73
|
+
case "side-by-side":
|
|
74
|
+
return ["deck"];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** get text alignment based on header-deck position **/
|
|
79
|
+
const fullScreenTextAlignCss = () => {
|
|
80
|
+
switch (HeaderDek_Horizontal_Position) {
|
|
81
|
+
case "left": return topperStyles.textAlignLeft;
|
|
82
|
+
case "right": return topperStyles.textAlignLeft;
|
|
83
|
+
case "center": return topperStyles.textAlignCenter;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const ImageHTML = () => <WCMImage2 wcm={Image} alt={Image_Alt} isNotLazyloaded={false} wcmData={wcmData} lazyloader={lazyloader} isFullScreenTopper={false}/>
|
|
88
|
+
const FullScreenImageHTML = () => <WCMImage2 wcm={Image} alt={Image_Alt} isNotLazyloaded={false} ratio={calculateFullScreenImageRatio()} wcmData={wcmData} lazyloader={lazyloader} isFullScreenTopper={true}/>
|
|
89
|
+
|
|
90
|
+
const TopperHtml = () => {
|
|
91
|
+
switch (Topper_Style) {
|
|
92
|
+
case "full-screen":
|
|
93
|
+
return (
|
|
94
|
+
<>
|
|
95
|
+
<div className={topperStyles.topperContainerFullScreen}>
|
|
96
|
+
<figure className={`topper-image ${topperStyles.imageFullScreen}` } aria-labelledby="topperCaptionText">
|
|
97
|
+
<FullScreenImageHTML/>
|
|
98
|
+
<CaptionCredit caption={Image_Caption} credit={Image_Credits} extraStyles={topperStyles.hideWhenDesktop}/>
|
|
99
|
+
</figure>
|
|
100
|
+
<div className={headerDekStyleList().join(' ')}>
|
|
101
|
+
<Heading level={1} text={Title}
|
|
102
|
+
className={headerStyleList().join(' ')}
|
|
103
|
+
/>
|
|
104
|
+
<Heading
|
|
105
|
+
level={2}
|
|
106
|
+
text={Deck}
|
|
107
|
+
className={deckStyleList().join(' ')}
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="topperCaptionText">
|
|
112
|
+
<CaptionCredit caption={Image_Caption} credit={Image_Credits} extraStyles={[topperStyles.hideWhenMobile, topperStyles.smallPaddingLeft]}/>
|
|
113
|
+
</div>
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
case "stacked":
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<div>
|
|
121
|
+
<div className={headerDekStyleList().join('')}>
|
|
122
|
+
<Heading
|
|
123
|
+
level={1}
|
|
124
|
+
text={Title}
|
|
125
|
+
className={headerStyleList().join(' ')}
|
|
126
|
+
/>
|
|
127
|
+
<Heading
|
|
128
|
+
level={2}
|
|
129
|
+
text={Deck}
|
|
130
|
+
className={deckStyleList().join(' ')}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
<figure className={`mw-xl ml-auto mr-auto ${topperStyles.imageStacked}`}>
|
|
134
|
+
<ImageHTML/>
|
|
135
|
+
<CaptionCredit caption={Image_Caption} credit={Image_Credits} />
|
|
136
|
+
</figure>
|
|
137
|
+
</div>
|
|
138
|
+
</>
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
case "no-visual":
|
|
142
|
+
return (
|
|
143
|
+
<>
|
|
144
|
+
<div>
|
|
145
|
+
<div className={headerDekStyleList().join('')}>
|
|
146
|
+
<Heading
|
|
147
|
+
level={1}
|
|
148
|
+
text={Title}
|
|
149
|
+
className={headerStyleList().join(' ')}
|
|
150
|
+
/>
|
|
151
|
+
<Heading
|
|
152
|
+
level={2}
|
|
153
|
+
text={Deck}
|
|
154
|
+
className={deckStyleList().join(' ')}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const calculatefullScreenOffsets = () => {
|
|
164
|
+
var r = document.querySelector(':root');
|
|
165
|
+
|
|
166
|
+
let verticalOffset = convertStringToNumber(HeaderDek_Vertical_Offset, (HeaderDek_Vertical_Position === "bottom"));
|
|
167
|
+
let horizontalOffset = convertStringToNumber(HeaderDek_Horizontal_Offset, (HeaderDek_Horizontal_Position === "right"));
|
|
168
|
+
|
|
169
|
+
r.style.setProperty('--headerDek-vertical-offset', verticalOffset + "px" );
|
|
170
|
+
r.style.setProperty('--headerDek-horizontal-offset', horizontalOffset + "px");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const convertStringToNumber = (maybeStr, isFlipped) => {
|
|
174
|
+
var num = 0;
|
|
175
|
+
if (typeof(maybeStr) === "string") {
|
|
176
|
+
// remove all non-number characters and "-" from string
|
|
177
|
+
num = Number(maybeStr.replace(/(?!^)-|[^0-9-]/g,''))
|
|
178
|
+
} else {
|
|
179
|
+
num = maybeStr
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (isNaN(num)) num = 0;
|
|
183
|
+
if (isFlipped) num *= -1;
|
|
184
|
+
|
|
185
|
+
return num;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const calculateFullScreenImageRatio = () => {
|
|
189
|
+
// ratio needs to account for height of nav bar which is 37px
|
|
190
|
+
const windowRatio = ((window.innerHeight-37) / window.innerWidth)*100;
|
|
191
|
+
let fullScreenRatio = "56.25%"; // defaults to 16/9;
|
|
192
|
+
|
|
193
|
+
if (windowRatio < 56.25) fullScreenRatio = (windowRatio + "%")
|
|
194
|
+
return fullScreenRatio
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<TopperHtml/>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export default Topper2
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React, {useRef, useEffect, useState} from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import * as wcmimageStyles from "../styles/modules/wcmimage2.module.less"
|
|
4
|
+
import { debounce } from './helpers/utilfunctions.mjs'
|
|
5
|
+
|
|
6
|
+
const currentEnv = process.env.GATSBY_DEPLOY_ENV
|
|
7
|
+
|
|
8
|
+
const ImageHTML = ({fullPath, imageRez, alt, isFullScreenTopper}) => {
|
|
9
|
+
let imageCss = [wcmimageStyles.cImg];
|
|
10
|
+
if (isFullScreenTopper) imageCss.push(wcmimageStyles.cImgFullscreen);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<img
|
|
14
|
+
className={imageCss.join(' ')}
|
|
15
|
+
src={`${fullPath}${imageRez}x0.jpg`}
|
|
16
|
+
alt={alt}/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const WCMImage = ({ wcm, alt, ratio, wcmData, lazyloader, isFullScreenTopper }) => {
|
|
21
|
+
// When the wrapping div is rendered, we're going to figure out the best size for this image to be
|
|
22
|
+
let picRef = useRef(null)
|
|
23
|
+
let [imageRez, setImageRez] = useState(0)
|
|
24
|
+
|
|
25
|
+
let setImageWidth = () => {
|
|
26
|
+
let pixelWidth = 900 // Default width if we need a fallback
|
|
27
|
+
let pixelRatio = window.devicePixelRatio || 1
|
|
28
|
+
if (picRef.current && picRef.current.offsetWidth){
|
|
29
|
+
pixelWidth = Math.round(picRef.current.offsetWidth * pixelRatio)
|
|
30
|
+
}
|
|
31
|
+
if (imageRez < pixelWidth){ // No need to resize if we're just scaling down
|
|
32
|
+
setImageRez(pixelWidth)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const debouncedHandleResize = debounce(function handleResize() {
|
|
38
|
+
setImageWidth()
|
|
39
|
+
}, 500)
|
|
40
|
+
window.addEventListener('resize', debouncedHandleResize)
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
window.removeEventListener('resize', debouncedHandleResize)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
setImageWidth()
|
|
49
|
+
}, [])
|
|
50
|
+
|
|
51
|
+
// If this is actually undefined, return null
|
|
52
|
+
// No error, nothing is rendered
|
|
53
|
+
if (!wcm){
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// This calculation is not used for the topper impl, but keeping it here just in case
|
|
58
|
+
// it is needed for the general WCMImage utils migration
|
|
59
|
+
let r = document.querySelector(':root');
|
|
60
|
+
let photoRatio = "56.25%"; // Default to 16/9
|
|
61
|
+
let fullPath = `https://s.hdnux.com/photos/0/0/0/${wcm}/0/`;
|
|
62
|
+
if (!ratio){
|
|
63
|
+
let matchedPhoto = wcmData.nodes.find((item) => {
|
|
64
|
+
return (item.photo.wcmid).toString() === (wcm).toString()
|
|
65
|
+
})
|
|
66
|
+
if (!matchedPhoto && currentEnv !== "development"){
|
|
67
|
+
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.`
|
|
68
|
+
}
|
|
69
|
+
if (matchedPhoto){
|
|
70
|
+
// Set ratio of the actual photo like a legit hacker
|
|
71
|
+
photoRatio = (matchedPhoto.photo.ratio*100)+"%";
|
|
72
|
+
r.style.setProperty('--img-bottom-padding-ratio', photoRatio);
|
|
73
|
+
|
|
74
|
+
fullPath = matchedPhoto.photo.full_path;
|
|
75
|
+
} else {
|
|
76
|
+
// Alert that things will go wrong on deploy
|
|
77
|
+
console.error(`No matching ID for ${wcm} found in gatsby-node.js! This is fine for development, but it will error on deploy!`);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
// If an override is being passed in, use that
|
|
81
|
+
photoRatio = ratio
|
|
82
|
+
r.style.setProperty('--img-bottom-padding-ratio', photoRatio);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Get serious about alt tags
|
|
86
|
+
if (typeof alt !== "string"){
|
|
87
|
+
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.`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Pull lazyloader HTML from index.js
|
|
91
|
+
const LazyLoaderHTML = lazyloader;
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div ref={picRef}>
|
|
95
|
+
|
|
96
|
+
<LazyLoaderHTML>
|
|
97
|
+
<ImageHTML fullPath={fullPath} imageRez={imageRez} alt={alt} isFullScreenTopper={isFullScreenTopper}/>
|
|
98
|
+
</LazyLoaderHTML>
|
|
99
|
+
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
WCMImage.propTypes = {
|
|
105
|
+
wcm: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
106
|
+
alt: PropTypes.string.isRequired,
|
|
107
|
+
ratio: PropTypes.string,
|
|
108
|
+
lazyloader: PropTypes.element
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default WCMImage
|
package/copy/c2p_sheet.js
CHANGED
|
@@ -63,7 +63,7 @@ let createSheet = (auth, fallback, configData) => {
|
|
|
63
63
|
|
|
64
64
|
const drive = google.drive({ version: "v3", auth });
|
|
65
65
|
const body = { title: "New C2P sheet" };
|
|
66
|
-
const templateId = "
|
|
66
|
+
const templateId = "1DUvYnFdxtBv1AXcDI9X00s_opUSu4uHJmd5LNemCN9E";
|
|
67
67
|
drive.files.copy(
|
|
68
68
|
{
|
|
69
69
|
fileId: templateId, // Base template
|
package/css/nav2.less
CHANGED