Skip to content

Commit e658110

Browse files
Merge branch 'develop' into general-referrals
2 parents 85a95a0 + 950950e commit e658110

File tree

11 files changed

+751
-118
lines changed

11 files changed

+751
-118
lines changed

.circleci/config.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ workflows:
343343
branches:
344344
only:
345345
- develop
346+
- fix-challenge-end-date
346347
# This is alternate dev env for parallel testing
347348
- "build-test":
348349
context : org-global
@@ -356,7 +357,7 @@ workflows:
356357
filters:
357358
branches:
358359
only:
359-
- general-referrals
360+
- free
360361
# This is beta env for production soft releases
361362
- "build-prod-beta":
362363
context : org-global
@@ -371,7 +372,7 @@ workflows:
371372
branches:
372373
only:
373374
- develop
374-
- tc-api-issue
375+
- fix-challenge-end-date
375376
# Production builds are exectuted
376377
# when PR is merged to the master
377378
# Don't change anything in this configuration

src/shared/components/Contentful/Article/Article.jsx

Lines changed: 111 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-len */
12
/* eslint-disable react/no-unused-state */
23
/**
34
* The core article rendering.
@@ -13,6 +14,7 @@ import markdown from 'utils/markdown';
1314
import ContentfulLoader from 'containers/ContentfulLoader';
1415
import LoadingIndicator from 'components/LoadingIndicator';
1516
import YouTubeVideo from 'components/YouTubeVideo';
17+
import Viewport from 'components/Contentful/Viewport';
1618
import moment from 'moment';
1719
import localStorage from 'localStorage';
1820
import { Helmet } from 'react-helmet';
@@ -33,6 +35,11 @@ const htmlToText = require('html-to-text');
3335
const CONTENT_PREVIEW_LENGTH = 110;
3436
// Votes local storage key
3537
const LOCAL_STORAGE_KEY = 'VENBcnRpY2xlVm90ZXM=';
38+
// def banner image
39+
const DEFAULT_BANNER_IMAGE = 'https://images.ctfassets.net/piwi0eufbb2g/7v2hlDsVep7FWufHw0lXpQ/2505e61a880e68fab4e80cd0e8ec1814/0C37CB5E-B253-4804-8935-78E64E67589E.png';
40+
// random ads banner - left sidebar
41+
const RANDOM_BANNERS = ['6G8mjiTC1mzeSQ2YoUG1gB', '1DnDD02xX1liHfSTf5Vsn8', 'HQZ3mN0rR92CbNTkKTHJ5', '1OLoX8ZsvjAnn4TdGbZESD', '77jn01UGoQe2gqA7x0coQD'];
42+
const RANDOM_BANNER = RANDOM_BANNERS[_.random(0, 4)];
3643

3744
export default class Article extends React.Component {
3845
componentDidMount() {
@@ -131,33 +138,45 @@ export default class Article extends React.Component {
131138
<meta name="description" property="og:description" content={description} />
132139
<meta name="description" property="description" content={description} />
133140
<meta name="twitter:description" content={description} />
134-
<meta name="image" property="og:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : null} />
135-
<meta name="twitter:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : null} />
141+
<meta name="image" property="og:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
142+
<meta name="twitter:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
136143
</Helmet>
137-
{/* Banner */}
138-
{
139-
fields.featuredImage ? (
140-
<div className={theme.bannerContainer}>
141-
<svg viewBox="0 25 1050 600" version="1.1" preserveAspectRatio="none" className={theme['site-header-background']}>
142-
<defs>
143-
<clipPath id="user-space" clipPathUnits="userSpaceOnUse">
144-
<path id="jagged-top" d="M955.643,455.426c113.929-152.899,130.923-281.812-19.966-387.73 C883.769,31.258,814.91-10.997,685,3c-87.558,9.434-218,32-332,9c-48.207-9.726-146.137-5.765-167.796,6.768 C45.296,99.719-82.626,352.551,69.262,473.459c151.887,120.908,379.734,0.979,533.623,75.92 C756.773,624.319,841.715,608.326,955.643,455.426" />
145-
</clipPath>
146-
</defs>
147-
<image width="100%" height="100%" preserveAspectRatio="none" href={subData.assets.items[fields.featuredImage.sys.id].fields.file.url} clipPath="url(#user-space)" />
148-
</svg>
144+
<div className={theme.wrapper}>
145+
{/* Banner */}
146+
<div className={fields.featuredImage ? theme.bannerContainer : theme.bannerContainerDefaultImage}>
147+
<div className={theme.bannerInner}>
148+
<div className={theme.bannerInnerLeft}>
149+
<h4 className={theme.articleDate}>{moment(fields.creationDate).format('MMMM D, YYYY')}</h4>
150+
<h1 className={theme.articleTitle}>{fields.title}</h1>
151+
</div>
152+
<div className={theme.bannerInnerRight}>
153+
{
154+
fields.featuredImage ? (
155+
<div className={theme['site-header-background']}>
156+
<svg className={theme.bannerSvg}>
157+
<clipPath id="thrive-banner-clip-path" clipPathUnits="objectBoundingBox">
158+
<path d="M0.477,1 C0.72,0.999,1,0.804,1,0.56 C1,0.316,0.766,-0.067,0.528,0.021 C0.343,0.089,0.145,-0.088,0.076,0.063 C0.016,0.193,-0.071,0.456,0.101,0.618 C0.274,0.782,0.234,1,0.477,1" />
159+
</clipPath>
160+
</svg>
161+
<div className={theme.bannerClippedImageHolder} style={{ backgroundImage: `url(${subData.assets.items[fields.featuredImage.sys.id].fields.file.url})` }} />
162+
</div>
163+
) : (
164+
<img src={DEFAULT_BANNER_IMAGE} alt="Thrive - default banner" className={theme['site-header-background']} />
165+
)
166+
}
167+
</div>
149168
</div>
150-
) : null
151-
}
152-
<div
153-
className={fields.featuredImage
154-
? theme.contentContainerWithBanner : theme.contentContainer}
155-
style={fixStyle(fields.extraStylesForContainer)}
156-
>
157-
<div className={theme.contentLeftBar}>
158-
{/* Authors */}
159-
<div className={theme.authorContainer}>
160-
{
169+
<img src="https://images.ctfassets.net/piwi0eufbb2g/3StLyQh5ne1Lk9H7C1oVxv/52f17a02122212052e44585d3e79fcf7/29320408-E820-48E1-B0FD-539EAC296910.svg" alt="Thrive banner shape" className={theme.bannerBottShape} />
170+
</div>
171+
<div
172+
className={fields.featuredImage
173+
? theme.contentContainerWithBanner : theme.contentContainer}
174+
style={fixStyle(fields.extraStylesForContainer)}
175+
>
176+
<div className={theme.contentLeftBar}>
177+
{/* Authors */}
178+
<div className={theme.authorContainer}>
179+
{
161180
_.map(fields.contentAuthor, author => (
162181
<div key={author.sys.id} className={theme.authorWrapper}>
163182
{
@@ -189,72 +208,89 @@ export default class Article extends React.Component {
189208
</div>
190209
))
191210
}
192-
</div>
193-
<div className={theme.separator} />
194-
<h3 className={theme.label}>DURATION</h3>
195-
<span className={theme.duration}>{fields.readTime}</span>
196-
<div className={theme.separator} />
197-
<h3 className={theme.label}>categories & Tags</h3>
198-
{/* Tags */}
199-
<div className={theme.tagContainer}>
200-
{
211+
</div>
212+
<div className={theme.separator} />
213+
<h3 className={theme.label}>DURATION</h3>
214+
<span className={theme.duration}>{fields.readTime}</span>
215+
<div className={theme.separator} />
216+
<h3 className={theme.label}>categories</h3>
217+
{/* Cats */}
218+
<div className={theme.tagContainer}>
219+
{
220+
_.map(fields.contentCategory, cat => (
221+
<div className={theme.tagItem} key={cat.sys.id} title={`Search for articles in ${cat.fields.trackParent}:${cat.fields.name} category`}>
222+
<Link to={`${config.TC_EDU_BASE_PATH}${config.TC_EDU_TRACKS_PATH}?${qs.stringify({ track: cat.fields.trackParent, tax: cat.fields.name })}`} key={`${cat.sys.id}`} className={theme.catLink}>{cat.fields.name}</Link>
223+
</div>
224+
))
225+
}
226+
</div>
227+
<div className={theme.separator} />
228+
<h3 className={theme.label}>Tags</h3>
229+
{/* Tags */}
230+
<div className={theme.tagContainer}>
231+
{
201232
_.map(fields.tags, tag => (
202233
<div className={theme.tagItem} key={tag} title={`Search for articles labelled as ${tag}`}>
203234
<Link to={`${config.TC_EDU_BASE_PATH}${config.TC_EDU_SEARCH_PATH}?${qs.stringify({ tags: tag })}`} key={`${tag}`}>{tag}</Link>
204235
</div>
205236
))
206237
}
238+
</div>
239+
<div className={theme.separator} />
240+
<h3 className={theme.label}>share</h3>
241+
<div className={theme.shareButtons}>
242+
<a href={`https://www.linkedin.com/sharing/share-offsite/?url=${shareUrl}`} target="_blank" rel="noopener noreferrer">
243+
<IconLinkedIn />
244+
</a>
245+
<a href={`https://www.facebook.com/sharer/sharer.php?u=${shareUrl}&src=share_button`} target="_blank" rel="noopener noreferrer">
246+
<IconFacebook />
247+
</a>
248+
<a href={`https://twitter.com/intent/tweet?url=${shareUrl}`} target="_blank" rel="noopener noreferrer">
249+
<IconTwitter />
250+
</a>
251+
</div>
252+
<div className={theme.mobileSeparator} />
253+
<div className={theme.leftSidebarContent}>
254+
<Viewport
255+
id={fields.leftSidebarContent
256+
? fields.leftSidebarContent.sys.id : RANDOM_BANNER}
257+
preview={preview}
258+
spaceName={spaceName}
259+
environment={environment}
260+
/>
261+
</div>
207262
</div>
208-
<div className={theme.separator} />
209-
<h3 className={theme.label}>share</h3>
210-
<div className={theme.shareButtons}>
211-
<a href={`https://www.linkedin.com/sharing/share-offsite/?url=${shareUrl}`} target="_blank" rel="noopener noreferrer">
212-
<IconLinkedIn />
213-
</a>
214-
<a href={`https://www.facebook.com/sharer/sharer.php?u=${shareUrl}&src=share_button`} target="_blank" rel="noopener noreferrer">
215-
<IconFacebook />
216-
</a>
217-
<a href={`https://twitter.com/intent/tweet?url=${shareUrl}`} target="_blank" rel="noopener noreferrer">
218-
<IconTwitter />
219-
</a>
220-
</div>
221-
<div className={theme.mobileSeparator} />
222-
</div>
223-
{/* Content */}
224-
<div className={theme.articleContent}>
225-
<div className={theme.articleContentTop}>
226-
<h4 className={theme.articleDate}>{moment(fields.creationDate).format('MMMM D, YYYY')}</h4>
227-
<h1 className={theme.articleTitle}>{fields.title}</h1>
228-
</div>
229-
<MarkdownRenderer markdown={fields.content} {...contentfulConfig} />
230-
{
263+
{/* Content */}
264+
<div className={theme.articleContent}>
265+
<MarkdownRenderer markdown={fields.content} {...contentfulConfig} />
266+
{
231267
fields.type === 'Video' && fields.contentUrl ? (
232268
<YouTubeVideo src={fields.contentUrl} />
233269
) : null
234270
}
235-
{/* Voting */}
236-
<div className={theme.actionContainer}>
237-
<div className={theme.action}>
238-
<div tabIndex={0} role="button" className={theme.circleGreenIcon} onClick={() => this.updateVote('up')} onKeyPress={() => this.updateVote('up')}>
239-
<GestureIcon />
240-
</div>
241-
<span>
242-
{
271+
{/* Voting */}
272+
<div className={theme.actionContainer}>
273+
<div className={theme.action}>
274+
<div tabIndex={0} role="button" className={theme.circleGreenIcon} onClick={() => this.updateVote('up')} onKeyPress={() => this.updateVote('up')}>
275+
<GestureIcon />
276+
</div>
277+
<span>
278+
{
243279
upvotes
244280
}
245-
</span>
246-
</div>
247-
<div className={theme.action}>
248-
<div tabIndex={0} role="button" className={theme.circleRedIcon} onClick={() => this.updateVote('down')} onKeyPress={() => this.updateVote('down')}>
249-
<GestureIcon />
281+
</span>
282+
</div>
283+
<div className={theme.action}>
284+
<div tabIndex={0} role="button" className={theme.circleRedIcon} onClick={() => this.updateVote('down')} onKeyPress={() => this.updateVote('down')}>
285+
<GestureIcon />
286+
</div>
287+
<span>{downvotes}</span>
250288
</div>
251-
<span>{downvotes}</span>
252289
</div>
253290
</div>
254291
</div>
255-
</div>
256-
{/* Recommended */}
257-
{
292+
{/* Recommended */}
293+
{
258294
fields.recommended ? (
259295
<div className={theme.recommendedContainer}>
260296
<div className={theme.recommendedTopShape} />
@@ -331,6 +367,7 @@ export default class Article extends React.Component {
331367
</div>
332368
) : null
333369
}
370+
</div>
334371
</React.Fragment>
335372
);
336373
}

0 commit comments

Comments
 (0)