diff --git a/src/shared/components/Contentful/ContentSlider/ContentSlider.jsx b/src/shared/components/Contentful/ContentSlider/ContentSlider.jsx
index fd84bf3b46..b0fc1796d5 100644
--- a/src/shared/components/Contentful/ContentSlider/ContentSlider.jsx
+++ b/src/shared/components/Contentful/ContentSlider/ContentSlider.jsx
@@ -36,8 +36,66 @@ class ContentSlider extends Component {
const {
children, theme, autoStart, duration, id, containerStyle,
slidesToShow, framePadding, withoutControls, vertical, cellSpacing,
- cellAlign, wrapAround, heightMode, arrowTheme,
+ cellAlign, wrapAround, heightMode, arrowTheme, hideSliderDots, themeName,
+ arrowLeftImage, arrowRightImage,
} = this.props;
+ const renderControls = {
+ renderCenterLeftControls: ({ previousSlide }) => (
+
+ ),
+ };
+ if (hideSliderDots) {
+ renderControls.renderBottomCenterControls = () => null;
+ }
+ if (themeName === 'Controls Bottom Right') {
+ renderControls.renderCenterLeftControls = () => null;
+ renderControls.renderCenterRightControls = () => null;
+ renderControls.renderBottomRightControls = ({ previousSlide, nextSlide }) => (
+
(
-
- {arrowTheme === 'Gray' ? : }
-
- )}
- renderCenterRightControls={({ nextSlide }) => (
-
- {arrowTheme === 'Gray' ? : }
-
- )}
+ {...renderControls}
>
{children}
@@ -103,6 +140,10 @@ ContentSlider.defaultProps = {
wrapAround: true,
heightMode: 'max',
arrowTheme: 'Gray',
+ hideSliderDots: false,
+ themeName: 'Default',
+ arrowLeftImage: null,
+ arrowRightImage: null,
};
ContentSlider.propTypes = {
@@ -110,14 +151,7 @@ ContentSlider.propTypes = {
children: PT.node.isRequired,
autoStart: PT.bool,
duration: PT.number,
- theme: PT.shape({
- container: PT.string,
- content: PT.string,
- controlLeft: PT.string,
- controlRight: PT.string,
- multiContent: PT.any,
- singleContent: PT.any,
- }),
+ theme: PT.shape(),
containerStyle: PT.shape(),
slidesToShow: PT.number,
framePadding: PT.string,
@@ -128,6 +162,10 @@ ContentSlider.propTypes = {
wrapAround: PT.bool,
heightMode: PT.string,
arrowTheme: PT.string,
+ hideSliderDots: PT.bool,
+ themeName: PT.string,
+ arrowLeftImage: PT.shape(),
+ arrowRightImage: PT.shape(),
};
export default themr('Contentful-Slider', defaultTheme)(ContentSlider);
diff --git a/src/shared/components/Contentful/ContentSlider/index.jsx b/src/shared/components/Contentful/ContentSlider/index.jsx
index 0eabebf054..f90e740c44 100644
--- a/src/shared/components/Contentful/ContentSlider/index.jsx
+++ b/src/shared/components/Contentful/ContentSlider/index.jsx
@@ -36,6 +36,9 @@ function ContentSliderItemsLoader(props) {
environment,
heightMode,
arrowTheme,
+ hideSliderDots,
+ arrowLeftImage,
+ arrowRightImage,
} = props;
return (
@@ -58,6 +61,10 @@ function ContentSliderItemsLoader(props) {
wrapAround={wrapAround}
heightMode={heightMode}
arrowTheme={arrowTheme}
+ hideSliderDots={hideSliderDots}
+ themeName={theme}
+ arrowLeftImage={arrowLeftImage}
+ arrowRightImage={arrowRightImage}
>
{
ids.map(itemId => (
@@ -94,6 +101,9 @@ ContentSliderItemsLoader.defaultProps = {
environment: null,
heightMode: 'current',
arrowTheme: 'Gray',
+ hideSliderDots: false,
+ arrowLeftImage: null,
+ arrowRightImage: null,
};
ContentSliderItemsLoader.propTypes = {
@@ -115,6 +125,9 @@ ContentSliderItemsLoader.propTypes = {
wrapAround: PT.bool,
heightMode: PT.string,
arrowTheme: PT.string,
+ hideSliderDots: PT.bool,
+ arrowLeftImage: PT.shape(),
+ arrowRightImage: PT.shape(),
};
export default function ContentfulSlider(props) {
@@ -152,6 +165,9 @@ export default function ContentfulSlider(props) {
wrapAround={fields.wrapAround}
heightMode={fields.heightMode}
arrowTheme={fields.arrowTheme}
+ hideSliderDots={fields.hideSliderDots}
+ arrowLeftImage={fields.arrowLeftImage}
+ arrowRightImage={fields.arrowRightImage}
/>
);
}}
diff --git a/src/shared/components/Contentful/ContentSlider/themes/default.scss b/src/shared/components/Contentful/ContentSlider/themes/default.scss
index 59f0d8d5c4..e1d07d595b 100644
--- a/src/shared/components/Contentful/ContentSlider/themes/default.scss
+++ b/src/shared/components/Contentful/ContentSlider/themes/default.scss
@@ -46,3 +46,19 @@
margin-right: 15px;
}
}
+
+.bottomRightControls {
+ display: flex;
+ position: absolute;
+ right: 0;
+ bottom: -50px;
+
+ a.controlLeft {
+ margin: 0;
+ margin-right: 20px;
+ }
+
+ a.controlRight {
+ margin: 0;
+ }
+}
diff --git a/src/shared/components/Contentful/Viewport/index.jsx b/src/shared/components/Contentful/Viewport/index.jsx
index 52a79427c2..30d3a78e28 100644
--- a/src/shared/components/Contentful/Viewport/index.jsx
+++ b/src/shared/components/Contentful/Viewport/index.jsx
@@ -17,7 +17,7 @@ import BlogFeed from 'containers/Contentful/BlogFeed';
import { errors } from 'topcoder-react-lib';
import LoadingIndicator from 'components/LoadingIndicator';
import PT from 'prop-types';
-import React from 'react';
+import React, { useState } from 'react';
import Countdown from 'components/Contentful/Countdown';
import Tabs from 'components/Contentful/Tabs';
import AppComponentLoader from 'components/Contentful/AppComponent';
@@ -30,11 +30,13 @@ import Article from 'components/Contentful/Article';
import { isomorphy } from 'topcoder-react-utils';
import MemberTalkCloud from 'components/Contentful/MemberTalkCloud';
import Masonry from 'react-masonry-css';
+import { PrimaryButton } from 'topcoder-react-ui-kit';
// AOS
import AOS from 'aos';
import 'aos/dist/aos.css';
+import tc from 'components/buttons/themed/tc.scss';
import Viewport from './Viewport';
import columnTheme from './themes/column.scss';
@@ -78,6 +80,10 @@ const THEMES = {
Masonry: masonryTheme,
};
+const buttonThemes = {
+ tc,
+};
+
/* Loads viewport content assets. */
function ViewportContentLoader(props) {
const {
@@ -91,12 +97,19 @@ function ViewportContentLoader(props) {
viewportId,
animationOnScroll,
masonryConfig,
+ itemsPerPage,
+ loadMoreButtonText,
+ loadMoreButtonTheme,
+ loadMoreButtonContainerStyles,
} = props;
let {
extraStylesForContainer,
} = props;
+ const [page, setPage] = useState(1);
- const getInner = data => contentIds.map((id) => {
+ const getInner = data => contentIds.slice(
+ 0, (itemsPerPage ? itemsPerPage * page : contentIds.length),
+ ).map((id) => {
const type = data.entries.items[id].sys.contentType.sys.id;
const Component = COMPONENTS[type];
if (Component) {
@@ -146,7 +159,44 @@ function ViewportContentLoader(props) {
AOS.init();
}
}
- return (
+ return itemsPerPage ? (
+
+
+ {
+ themeName === 'Masonry' && masonryConfig ? (
+
+ {getInner(data)}
+
+ ) : getInner(data)
+ }
+
+ {
+ page * itemsPerPage < contentIds.length && (
+
+
{
+ setPage(page + 1);
+ }}
+ theme={{
+ button: buttonThemes.tc[loadMoreButtonTheme],
+ disabled: buttonThemes.tc.themedButtonDisabled,
+ }}
+ >
+ {loadMoreButtonText}
+
+
+ )
+ }
+
+ ) : (
);
})}
diff --git a/src/shared/components/Contentful/Viewport/themes/column.scss b/src/shared/components/Contentful/Viewport/themes/column.scss
index 2c30bf0518..56f62c8cac 100644
--- a/src/shared/components/Contentful/Viewport/themes/column.scss
+++ b/src/shared/components/Contentful/Viewport/themes/column.scss
@@ -2,3 +2,14 @@
flex-direction: column;
width: 100%;
}
+
+.loadMoreWrapper {
+ display: flex;
+ flex-direction: column;
+
+ .loadMoreButtonContainer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+}
diff --git a/src/shared/components/Contentful/Viewport/themes/grid.scss b/src/shared/components/Contentful/Viewport/themes/grid.scss
index 4a9d33cc93..6e2ad2ab95 100644
--- a/src/shared/components/Contentful/Viewport/themes/grid.scss
+++ b/src/shared/components/Contentful/Viewport/themes/grid.scss
@@ -24,3 +24,14 @@
}
}
}
+
+.loadMoreWrapper {
+ display: flex;
+ flex-direction: column;
+
+ .loadMoreButtonContainer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+}
diff --git a/src/shared/components/Contentful/Viewport/themes/masonry.scss b/src/shared/components/Contentful/Viewport/themes/masonry.scss
index 6f3dd73412..a03628ce60 100644
--- a/src/shared/components/Contentful/Viewport/themes/masonry.scss
+++ b/src/shared/components/Contentful/Viewport/themes/masonry.scss
@@ -21,3 +21,14 @@ $gutterSize: 20px;
}
}
}
+
+.loadMoreWrapper {
+ display: flex;
+ flex-direction: column;
+
+ .loadMoreButtonContainer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+}