Skip to content

Commit 813fc9b

Browse files
committed
feat: added recommended thrive articles
Changes related to topcoder-platform#3565
1 parent babc36b commit 813fc9b

File tree

8 files changed

+294
-10
lines changed

8 files changed

+294
-10
lines changed

src/assets/images/calendar.svg

Lines changed: 36 additions & 0 deletions
Loading

src/shared/components/challenge-detail/Header/index.jsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable jsx-a11y/click-events-have-key-events */
12
/**
23
* Challenge header component.
34
* This component renders all other child components part of the header.
@@ -47,6 +48,7 @@ export default function ChallengeHeader(props) {
4748
selectedView,
4849
showDeadlineDetail,
4950
hasFirstPlacement,
51+
hasThriveArticles,
5052
isMenuOpened,
5153
} = props;
5254

@@ -246,15 +248,29 @@ export default function ChallengeHeader(props) {
246248
<h1 styleName="challenge-header">
247249
{name}
248250
</h1>
249-
<ChallengeTags
250-
subTrack={subTrack}
251-
track={trackLower}
252-
challengesUrl={challengesUrl}
253-
challengeSubtracksMap={challengeSubtracksMap}
254-
events={eventNames}
255-
technPlatforms={miscTags}
256-
setChallengeListingFilter={setChallengeListingFilter}
257-
/>
251+
<div styleName="tag-container">
252+
<ChallengeTags
253+
subTrack={subTrack}
254+
track={trackLower}
255+
challengesUrl={challengesUrl}
256+
challengeSubtracksMap={challengeSubtracksMap}
257+
events={eventNames}
258+
technPlatforms={miscTags}
259+
setChallengeListingFilter={setChallengeListingFilter}
260+
/>
261+
{hasThriveArticles && (
262+
<div
263+
styleName="recommend-tag"
264+
role="button"
265+
tabIndex={0}
266+
onClick={
267+
() => {
268+
window.document.body.scrollIntoView(false);
269+
}}
270+
>Recommended THRIVE Articles
271+
</div>
272+
)}
273+
</div>
258274
</div>
259275
</div>
260276
<div styleName="prizes-ops-container">
@@ -450,6 +466,7 @@ ChallengeHeader.propTypes = {
450466
}).isRequired,
451467
challengesUrl: PT.string.isRequired,
452468
hasRegistered: PT.bool.isRequired,
469+
hasThriveArticles: PT.bool.isRequired,
453470
numWinners: PT.number.isRequired,
454471
onSelectorClicked: PT.func.isRequired,
455472
onToggleDeadlines: PT.func.isRequired,

src/shared/components/challenge-detail/Header/style.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,21 @@
124124
}
125125
}
126126

127+
.tag-container {
128+
display: flex;
129+
align-items: center;
130+
cursor: pointer;
131+
}
132+
133+
.recommend-tag {
134+
@include roboto-regular;
135+
136+
width: 199px;
137+
margin-left: 12px;
138+
font-size: 14px;
139+
color: $tc-dark-blue-110;
140+
}
141+
127142
@include design-accent-bg;
128143
@include develop-accent-bg;
129144
@include datasci-accent-bg;

src/shared/components/challenge-detail/Specification/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export default function ChallengeDetailsView(props) {
101101

102102
/* TODO: This render markup is monstrous - should be refactored. */
103103
return (
104-
<div>
104+
<div styleName="container">
105105
{
106106
isSaving ? (
107107
<SaveConfirmationModal

src/shared/components/challenge-detail/Specification/styles.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
@import "~styles/mixins";
22
$tc-link-visited: #0c4e98;
33

4+
.container {
5+
border-radius: 0 0 (3 * $corner-radius) (3 * $corner-radius);
6+
}
7+
48
@mixin noteStyle {
59
@include roboto-regular;
610

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import PT from 'prop-types';
3+
import { map } from 'lodash';
4+
import { config } from 'topcoder-react-utils';
5+
import moment from 'moment';
6+
import CalendarIcon from '../../../../assets/images/calendar.svg';
7+
8+
import './style.scss';
9+
10+
export default function ThriveArticles({ articles }) {
11+
const formatTitle = (title) => {
12+
if (title.length <= 28) {
13+
return title;
14+
}
15+
if (title[28] === '') {
16+
return `${title.substr(0, 29)}..`;
17+
}
18+
return `${title.substr(0, 28)}..`;
19+
};
20+
21+
const getPageUrl = article => (article.externalArticle && article.contentUrl
22+
? article.contentUrl
23+
: `${config.TC_EDU_BASE_PATH}${config.TC_EDU_ARTICLES_PATH}/${article.title}`);
24+
25+
const items = map(articles, (a, idx) => (
26+
<div styleName="article" key={idx}>
27+
<div styleName="article-left">
28+
<div styleName="article-read-time">{a.fields.readTime}</div>
29+
<div styleName="article-title"><a href={getPageUrl(a.fields)} target="_blank" rel="noopener noreferrer" title={a.fields.title}>{formatTitle(a.fields.title)}</a></div>
30+
<div styleName="article-create-time"><CalendarIcon />{moment(a.creationDate).format('MMM DD, YYYY')}</div>
31+
</div>
32+
<div
33+
styleName="article-right"
34+
style={{
35+
backgroundImage: `url(${a.fields.featuredImage.file.url})`,
36+
}}
37+
/>
38+
</div>
39+
));
40+
return (
41+
<div styleName="container">
42+
<div styleName="header-container">
43+
<div styleName="header">
44+
Recommended THRIVE Articles
45+
</div>
46+
<div styleName="right-url">
47+
<a href="http://topcoder.com/thrive" rel="noopener noreferrer" target="_blank">Explore THRIVE</a>
48+
</div>
49+
</div>
50+
<div styleName="articles">
51+
{items}
52+
</div>
53+
</div>
54+
);
55+
}
56+
57+
ThriveArticles.defaultProps = {
58+
articles: [],
59+
};
60+
61+
ThriveArticles.propTypes = {
62+
articles: PT.arrayOf(PT.object),
63+
};
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
@import "~styles/mixins";
2+
3+
.container {
4+
@include roboto-regular;
5+
6+
max-width: 1240px;
7+
width: 100%;
8+
display: flex;
9+
background-color: $tc-white;
10+
flex-direction: column;
11+
border-radius: (3 * $corner-radius);
12+
padding: 22px 11px 28px;
13+
margin: 50px auto 0;
14+
}
15+
16+
.header-container {
17+
display: flex;
18+
align-items: center;
19+
justify-content: space-between;
20+
margin-bottom: 20px;
21+
}
22+
23+
.header {
24+
@include roboto-bold;
25+
26+
margin-left: 33px;
27+
font-size: 20px;
28+
color: $tc-black;
29+
}
30+
31+
.right-url {
32+
margin-right: 13px;
33+
font-size: 15px;
34+
color: $tc-dark-blue-110;
35+
}
36+
37+
.articles {
38+
display: flex;
39+
}
40+
41+
.article {
42+
display: flex;
43+
position: relative;
44+
overflow: hidden;
45+
flex: 1;
46+
margin: 0 13px;
47+
border-radius: (5 * $corner-radius);
48+
background-color: #f4f4f4;
49+
}
50+
51+
.article-left {
52+
display: flex;
53+
flex: 1;
54+
padding: 0 20px;
55+
flex-direction: column;
56+
}
57+
58+
.article-read-time {
59+
@include roboto-regular;
60+
61+
margin-top: 13px;
62+
font-size: 12px;
63+
font-weight: 500;
64+
letter-spacing: -0.33px;
65+
color: $tc-gray-70;
66+
}
67+
68+
.article-title {
69+
@include barlow-semi-bold;
70+
71+
margin-top: 1px;
72+
font-size: 20px;
73+
line-height: 1.1;
74+
color: $tc-gray-70;
75+
}
76+
77+
.article-create-time {
78+
@include roboto-regular;
79+
80+
display: flex;
81+
align-items: center;
82+
margin-top: 11px;
83+
font-size: 12px;
84+
font-weight: 500;
85+
letter-spacing: -0.33px;
86+
color: $tc-gray-70;
87+
88+
svg {
89+
margin-right: 5px;
90+
}
91+
}
92+
93+
.article-right {
94+
background-size: cover;
95+
background-repeat: no-repeat;
96+
background-position: center center;
97+
width: 155px;
98+
min-width: 155px;
99+
min-height: 138px;
100+
101+
&::before {
102+
content: "";
103+
width: 20px;
104+
height: calc(100% + 4px);
105+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='62' height='243' viewBox='0 0 62 243'%3E%3Ctitle%3EPath%3C/title%3E%3Cpath d='M54.308.5H.5v242h53.117c-1.051-11.042-3.275-19.687-8.803-37.002-.973-3.046-1.01-3.164-1.372-4.305-7.67-24.217-9.843-38.31-6.548-56.672 2.333-13.003 5.435-23.77 10.32-37.324.387-1.073 5.032-13.655 6.285-17.256 4.653-13.375 6.985-23.76 7.563-36.17.69-14.83-1.373-31.891-6.754-53.271z' stroke='%23D4D4D4' stroke-width='0' fill='%23F4F4F4' fill-rule='evenodd'/%3E%3C/svg%3E");
106+
background-repeat: no-repeat;
107+
background-size: cover;
108+
background-position: right -2px;
109+
position: absolute;
110+
margin-left: -1px;
111+
}
112+
}

0 commit comments

Comments
 (0)