Skip to content

Commit 516c2c5

Browse files
Merge pull request #5983 from topcoder-platform/jan-fixes-2
Jan fixes 2
2 parents 25d8362 + 1613220 commit 516c2c5

File tree

9 files changed

+204
-38
lines changed

9 files changed

+204
-38
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ workflows:
363363
filters:
364364
branches:
365365
only:
366-
- jan-updates-1
366+
- jan-fixes-2
367367
# This is stage env for production QA releases
368368
- "build-prod-staging":
369369
context : org-global

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const CONTENT_PREVIEW_LENGTH = 110;
3939
// Votes local storage key
4040
const LOCAL_STORAGE_KEY = 'VENBcnRpY2xlVm90ZXM=';
4141
// def banner image
42-
const DEFAULT_BANNER_IMAGE = 'https://images.ctfassets.net/piwi0eufbb2g/7v2hlDsVep7FWufHw0lXpQ/2505e61a880e68fab4e80cd0e8ec1814/0C37CB5E-B253-4804-8935-78E64E67589E.png';
42+
const DEFAULT_BANNER_IMAGE = 'https://images.ctfassets.net/piwi0eufbb2g/7v2hlDsVep7FWufHw0lXpQ/2505e61a880e68fab4e80cd0e8ec1814/0C37CB5E-B253-4804-8935-78E64E67589E.png?w=1200&h=630';
4343
// random ads banner - left sidebar
4444
const RANDOM_BANNERS = ['6G8mjiTC1mzeSQ2YoUG1gB', '1DnDD02xX1liHfSTf5Vsn8', 'HQZ3mN0rR92CbNTkKTHJ5', '1OLoX8ZsvjAnn4TdGbZESD', '77jn01UGoQe2gqA7x0coQD'];
4545
const RANDOM_BANNER = RANDOM_BANNERS[_.random(0, 4)];
@@ -167,9 +167,10 @@ class Article extends React.Component {
167167
<meta name="title" property="og:title" content={fields.title} />
168168
<meta name="description" property="og:description" content={description} />
169169
<meta name="description" property="description" content={description} />
170+
<meta name="twitter:title" content={fields.title} />
170171
<meta name="twitter:description" content={description} />
171-
<meta name="image" property="og:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
172-
<meta name="twitter:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
172+
<meta name="image" property="og:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}?w=1200&h=630` : DEFAULT_BANNER_IMAGE} />
173+
<meta name="twitter:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}?w=1200&h=630` : DEFAULT_BANNER_IMAGE} />
173174
<link rel="alternate" type="application/rss+xml" title="Topcoder Thrive - RSS feed" href="https://topcoder.com/api/feeds/thrive" />
174175
</Helmet>
175176
<div className={theme.wrapper}>

src/shared/components/Contentful/ContentSlider/ContentSlider.jsx

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,66 @@ class ContentSlider extends Component {
3636
const {
3737
children, theme, autoStart, duration, id, containerStyle,
3838
slidesToShow, framePadding, withoutControls, vertical, cellSpacing,
39-
cellAlign, wrapAround, heightMode, arrowTheme,
39+
cellAlign, wrapAround, heightMode, arrowTheme, hideSliderDots, themeName,
40+
arrowLeftImage, arrowRightImage,
4041
} = this.props;
42+
const renderControls = {
43+
renderCenterLeftControls: ({ previousSlide }) => (
44+
<a
45+
onClick={previousSlide}
46+
onKeyPress={previousSlide}
47+
role="button"
48+
tabIndex={0}
49+
className={theme.controlLeft}
50+
>
51+
{arrowRightImage && <img src={arrowRightImage.fields.file.url} alt="Slider left arrow" />}
52+
{!arrowRightImage && (arrowTheme === 'Gray' ? <GrayArrowNext /> : <WhiteArrowNext />)}
53+
</a>
54+
),
55+
renderCenterRightControls: ({ nextSlide }) => (
56+
<a
57+
onClick={nextSlide}
58+
onKeyPress={nextSlide}
59+
role="button"
60+
tabIndex={0}
61+
className={theme.controlRight}
62+
>
63+
{arrowLeftImage && <img src={arrowLeftImage.fields.file.url} alt="Slider right arrow" />}
64+
{!arrowLeftImage && (arrowTheme === 'Gray' ? <GrayArrowPrev /> : <WhiteArrowPrev />)}
65+
</a>
66+
),
67+
};
68+
if (hideSliderDots) {
69+
renderControls.renderBottomCenterControls = () => null;
70+
}
71+
if (themeName === 'Controls Bottom Right') {
72+
renderControls.renderCenterLeftControls = () => null;
73+
renderControls.renderCenterRightControls = () => null;
74+
renderControls.renderBottomRightControls = ({ previousSlide, nextSlide }) => (
75+
<div className={theme.bottomRightControls}>
76+
<a
77+
onClick={previousSlide}
78+
onKeyPress={previousSlide}
79+
role="button"
80+
tabIndex={0}
81+
className={theme.controlLeft}
82+
>
83+
{arrowLeftImage && <img src={arrowLeftImage.fields.file.url} alt="Slider left arrow" />}
84+
{!arrowLeftImage && (arrowTheme === 'Gray' ? <GrayArrowPrev /> : <WhiteArrowPrev />)}
85+
</a>
86+
<a
87+
onClick={nextSlide}
88+
onKeyPress={nextSlide}
89+
role="button"
90+
tabIndex={0}
91+
className={theme.controlRight}
92+
>
93+
{arrowRightImage && <img src={arrowRightImage.fields.file.url} alt="Slider right arrow" />}
94+
{!arrowRightImage && (arrowTheme === 'Gray' ? <GrayArrowNext /> : <WhiteArrowNext />)}
95+
</a>
96+
</div>
97+
);
98+
}
4199

42100
return (
43101
<div
@@ -59,28 +117,7 @@ class ContentSlider extends Component {
59117
vertical={vertical}
60118
cellSpacing={cellSpacing}
61119
wrapAround={wrapAround}
62-
renderCenterLeftControls={({ previousSlide }) => (
63-
<a
64-
onClick={previousSlide}
65-
onKeyPress={previousSlide}
66-
role="button"
67-
tabIndex={0}
68-
className={theme.controlLeft}
69-
>
70-
{arrowTheme === 'Gray' ? <GrayArrowPrev /> : <WhiteArrowPrev />}
71-
</a>
72-
)}
73-
renderCenterRightControls={({ nextSlide }) => (
74-
<a
75-
onClick={nextSlide}
76-
onKeyPress={nextSlide}
77-
role="button"
78-
tabIndex={0}
79-
className={theme.controlRight}
80-
>
81-
{arrowTheme === 'Gray' ? <GrayArrowNext /> : <WhiteArrowNext />}
82-
</a>
83-
)}
120+
{...renderControls}
84121
>
85122
{children}
86123
</CarouselInject>
@@ -103,21 +140,18 @@ ContentSlider.defaultProps = {
103140
wrapAround: true,
104141
heightMode: 'max',
105142
arrowTheme: 'Gray',
143+
hideSliderDots: false,
144+
themeName: 'Default',
145+
arrowLeftImage: null,
146+
arrowRightImage: null,
106147
};
107148

108149
ContentSlider.propTypes = {
109150
id: PT.string.isRequired,
110151
children: PT.node.isRequired,
111152
autoStart: PT.bool,
112153
duration: PT.number,
113-
theme: PT.shape({
114-
container: PT.string,
115-
content: PT.string,
116-
controlLeft: PT.string,
117-
controlRight: PT.string,
118-
multiContent: PT.any,
119-
singleContent: PT.any,
120-
}),
154+
theme: PT.shape(),
121155
containerStyle: PT.shape(),
122156
slidesToShow: PT.number,
123157
framePadding: PT.string,
@@ -128,6 +162,10 @@ ContentSlider.propTypes = {
128162
wrapAround: PT.bool,
129163
heightMode: PT.string,
130164
arrowTheme: PT.string,
165+
hideSliderDots: PT.bool,
166+
themeName: PT.string,
167+
arrowLeftImage: PT.shape(),
168+
arrowRightImage: PT.shape(),
131169
};
132170

133171
export default themr('Contentful-Slider', defaultTheme)(ContentSlider);

src/shared/components/Contentful/ContentSlider/index.jsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ function ContentSliderItemsLoader(props) {
3636
environment,
3737
heightMode,
3838
arrowTheme,
39+
hideSliderDots,
40+
arrowLeftImage,
41+
arrowRightImage,
3942
} = props;
4043

4144
return (
@@ -58,6 +61,10 @@ function ContentSliderItemsLoader(props) {
5861
wrapAround={wrapAround}
5962
heightMode={heightMode}
6063
arrowTheme={arrowTheme}
64+
hideSliderDots={hideSliderDots}
65+
themeName={theme}
66+
arrowLeftImage={arrowLeftImage}
67+
arrowRightImage={arrowRightImage}
6168
>
6269
{
6370
ids.map(itemId => (
@@ -94,6 +101,9 @@ ContentSliderItemsLoader.defaultProps = {
94101
environment: null,
95102
heightMode: 'current',
96103
arrowTheme: 'Gray',
104+
hideSliderDots: false,
105+
arrowLeftImage: null,
106+
arrowRightImage: null,
97107
};
98108

99109
ContentSliderItemsLoader.propTypes = {
@@ -115,6 +125,9 @@ ContentSliderItemsLoader.propTypes = {
115125
wrapAround: PT.bool,
116126
heightMode: PT.string,
117127
arrowTheme: PT.string,
128+
hideSliderDots: PT.bool,
129+
arrowLeftImage: PT.shape(),
130+
arrowRightImage: PT.shape(),
118131
};
119132

120133
export default function ContentfulSlider(props) {
@@ -152,6 +165,9 @@ export default function ContentfulSlider(props) {
152165
wrapAround={fields.wrapAround}
153166
heightMode={fields.heightMode}
154167
arrowTheme={fields.arrowTheme}
168+
hideSliderDots={fields.hideSliderDots}
169+
arrowLeftImage={fields.arrowLeftImage}
170+
arrowRightImage={fields.arrowRightImage}
155171
/>
156172
);
157173
}}

src/shared/components/Contentful/ContentSlider/themes/default.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,19 @@
4646
margin-right: 15px;
4747
}
4848
}
49+
50+
.bottomRightControls {
51+
display: flex;
52+
position: absolute;
53+
right: 0;
54+
bottom: -50px;
55+
56+
a.controlLeft {
57+
margin: 0;
58+
margin-right: 20px;
59+
}
60+
61+
a.controlRight {
62+
margin: 0;
63+
}
64+
}

src/shared/components/Contentful/Viewport/index.jsx

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import BlogFeed from 'containers/Contentful/BlogFeed';
1717
import { errors } from 'topcoder-react-lib';
1818
import LoadingIndicator from 'components/LoadingIndicator';
1919
import PT from 'prop-types';
20-
import React from 'react';
20+
import React, { useState } from 'react';
2121
import Countdown from 'components/Contentful/Countdown';
2222
import Tabs from 'components/Contentful/Tabs';
2323
import AppComponentLoader from 'components/Contentful/AppComponent';
@@ -30,11 +30,13 @@ import Article from 'components/Contentful/Article';
3030
import { isomorphy } from 'topcoder-react-utils';
3131
import MemberTalkCloud from 'components/Contentful/MemberTalkCloud';
3232
import Masonry from 'react-masonry-css';
33+
import { PrimaryButton } from 'topcoder-react-ui-kit';
3334

3435
// AOS
3536
import AOS from 'aos';
3637
import 'aos/dist/aos.css';
3738

39+
import tc from 'components/buttons/themed/tc.scss';
3840
import Viewport from './Viewport';
3941

4042
import columnTheme from './themes/column.scss';
@@ -78,6 +80,10 @@ const THEMES = {
7880
Masonry: masonryTheme,
7981
};
8082

83+
const buttonThemes = {
84+
tc,
85+
};
86+
8187
/* Loads viewport content assets. */
8288
function ViewportContentLoader(props) {
8389
const {
@@ -91,12 +97,19 @@ function ViewportContentLoader(props) {
9197
viewportId,
9298
animationOnScroll,
9399
masonryConfig,
100+
itemsPerPage,
101+
loadMoreButtonText,
102+
loadMoreButtonTheme,
103+
loadMoreButtonContainerStyles,
94104
} = props;
95105
let {
96106
extraStylesForContainer,
97107
} = props;
108+
const [page, setPage] = useState(1);
98109

99-
const getInner = data => contentIds.map((id) => {
110+
const getInner = data => contentIds.slice(
111+
0, (itemsPerPage ? itemsPerPage * page : contentIds.length),
112+
).map((id) => {
100113
const type = data.entries.items[id].sys.contentType.sys.id;
101114
const Component = COMPONENTS[type];
102115
if (Component) {
@@ -146,7 +159,44 @@ function ViewportContentLoader(props) {
146159
AOS.init();
147160
}
148161
}
149-
return (
162+
return itemsPerPage ? (
163+
<div className={theme.loadMoreWrapper}>
164+
<Viewport
165+
viewportId={viewportId}
166+
extraStylesForContainer={fixStyle(extraStylesForContainer)}
167+
theme={theme}
168+
animation={animation}
169+
>
170+
{
171+
themeName === 'Masonry' && masonryConfig ? (
172+
<Masonry breakpointCols={masonryConfig} className="viewport-masonry-grid" columnClassName="viewport-masonry-grid_column">
173+
{getInner(data)}
174+
</Masonry>
175+
) : getInner(data)
176+
}
177+
</Viewport>
178+
{
179+
page * itemsPerPage < contentIds.length && (
180+
<div
181+
className={theme.loadMoreButtonContainer}
182+
style={fixStyle(loadMoreButtonContainerStyles)}
183+
>
184+
<PrimaryButton
185+
onClick={() => {
186+
setPage(page + 1);
187+
}}
188+
theme={{
189+
button: buttonThemes.tc[loadMoreButtonTheme],
190+
disabled: buttonThemes.tc.themedButtonDisabled,
191+
}}
192+
>
193+
{loadMoreButtonText}
194+
</PrimaryButton>
195+
</div>
196+
)
197+
}
198+
</div>
199+
) : (
150200
<Viewport
151201
viewportId={viewportId}
152202
extraStylesForContainer={fixStyle(extraStylesForContainer)}
@@ -180,6 +230,10 @@ ViewportContentLoader.defaultProps = {
180230
}),
181231
animationOnScroll: null,
182232
masonryConfig: null,
233+
itemsPerPage: null,
234+
loadMoreButtonText: null,
235+
loadMoreButtonTheme: null,
236+
loadMoreButtonContainerStyles: null,
183237
};
184238

185239
ViewportContentLoader.propTypes = {
@@ -194,6 +248,10 @@ ViewportContentLoader.propTypes = {
194248
baseUrl: PT.string.isRequired,
195249
animationOnScroll: PT.shape(),
196250
masonryConfig: PT.shape(),
251+
itemsPerPage: PT.string,
252+
loadMoreButtonText: PT.string,
253+
loadMoreButtonTheme: PT.string,
254+
loadMoreButtonContainerStyles: PT.shape(),
197255
};
198256

199257
/* Loads the main viewport entry. */
@@ -247,6 +305,10 @@ export function ViewportLoader(props) {
247305
baseUrl={baseUrl}
248306
animationOnScroll={viewport.fields.animationOnScroll}
249307
masonryConfig={viewport.fields.masonryConfig}
308+
itemsPerPage={viewport.fields.itemsPerPage}
309+
loadMoreButtonText={viewport.fields.loadMoreButtonText}
310+
loadMoreButtonTheme={viewport.fields.loadMoreButtonTheme}
311+
loadMoreButtonContainerStyles={viewport.fields.loadMoreButtonContainerStyles}
250312
/>
251313
);
252314
})}

src/shared/components/Contentful/Viewport/themes/column.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,14 @@
22
flex-direction: column;
33
width: 100%;
44
}
5+
6+
.loadMoreWrapper {
7+
display: flex;
8+
flex-direction: column;
9+
10+
.loadMoreButtonContainer {
11+
display: flex;
12+
justify-content: center;
13+
align-items: center;
14+
}
15+
}

0 commit comments

Comments
 (0)