Skip to content

Commit

Permalink
feat: ENG-3464 - Richtext Carousel (#670)
Browse files Browse the repository at this point in the history
* feat: Richtext Carousel

* Style putzing

* Sizing tweaks

* Sorting out text renders

* Mo tweaks

* Config tweak

* Dist experimenting

* Add dist components

* Add dist index

* Add dist theme

* Add dist utils

* Ignore dist styleguide

* Export stuff

* Tidyup

* Commit updates in build

* Render properly

* Render node copy properly

* Provide default heights

* Dynamically handle new bg colour prop

* Handle more colour logic

* Actually commit the built stuff

* More options

* Tweakz

* Spacing tweak

* Another tweak

* Update build

* Remove dist folder again

* Reignore dist

* Update test with correct data

* Tidyup

* Housekeeping

* Oh no more tidyup

* Whoops
  • Loading branch information
AndyEPhipps authored Sep 2, 2024
1 parent adba9ea commit fb8e985
Show file tree
Hide file tree
Showing 7 changed files with 663 additions and 2 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

# production
/build
/dist
/styleguide

/dist
# Kinda crummy, but in order to use your PR branch in another context (for prototyping etc.),
# you can *temporarily* un-ignore the dist folder (all apart from the styleguide folder; don't need that):
#/dist/styleguide

# misc
.DS_Store
.env.local
Expand Down
160 changes: 160 additions & 0 deletions src/components/Organisms/RichtextCarousel/RichtextCarousel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, {
useEffect, useState, useCallback
} from 'react';
import PropTypes from 'prop-types';
import {
CarouselProvider, Slider, Slide, ButtonBack, ButtonNext
} from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
import {
CarouselWrapper, SlideCopyWrapper, HeadingCopyWrapper
} from './RichtextCarousel.style';
import { breakpointValues } from '../../../theme/shared/allBreakpoints';

const RichtextCarousel = ({
data: {
contentful_id: thisID,
autoPlay,
nodes,
headingCopy,
// Set some defaults for good measure:
mobileHeight = 300,
tabletHeight = 350,
desktopHeight = 350,
carouselBackgroundColour = 'white',
nodeBackgroundColour = 'white',
nodeOutlineColour = 'grey'
}
}) => {
// Defaults to mobile config:
const [isMobile, setIsMobile] = useState(true);
const [visibleSlides, setVisibleSlides] = useState(1);
const [totalSlides, setTotalSlides] = useState(null);
const [theseItems, setTheseItems] = useState();

// Custom function to let us update the carousel config dynamically
const screenResize = useCallback(() => {
const screenSize = typeof window !== 'undefined' ? window.innerWidth : null;
const isCurrentlyMobile = window.innerWidth < breakpointValues.M;

if (screenSize !== null && (isMobile !== isCurrentlyMobile)) {
setIsMobile(isCurrentlyMobile);
setVisibleSlides(isCurrentlyMobile ? 1 : 3);
setTotalSlides(isCurrentlyMobile ? theseItems.length : theseItems.length + 2);
}
}, [isMobile, theseItems]);

// Cache our data source, using as a flag for render logic:
useEffect(() => {
setTheseItems(nodes);
}, [setTheseItems, nodes]);

useEffect(() => {
if (window !== 'undefined' && window.innerWidth >= breakpointValues.M) {
// On inital render, update carousel plugin config
// to suit the non-mobile layout and functionality:
setIsMobile(false);
setVisibleSlides(3);
}

// Hook into browser's own onresize event to call our custom wrapper function:
if (typeof window !== 'undefined') window.onresize = screenResize;
}, [screenResize]);

if (theseItems && totalSlides === null) {
// Reflects our two dummy/bookend slides for non-mobile/tablet views:
setTotalSlides(isMobile ? theseItems.length : theseItems.length + 2);
}

return (
<CarouselWrapper
className="CarouselWrapper"
id={thisID}
mobileHeight={mobileHeight}
tabletHeight={tabletHeight}
desktopHeight={desktopHeight}
carouselBackgroundColour={carouselBackgroundColour}
>

<HeadingCopyWrapper>
{headingCopy}
</HeadingCopyWrapper>

{theseItems && (
<CarouselProvider
naturalSlideWidth={50}
naturalSlideHeight={200}
totalSlides={totalSlides}
isPlaying={autoPlay}
interval={5000}
visibleSlides={visibleSlides}
infinite
>
<Slider classNameAnimation="richtext-carousel">

{/* Dummy slide for our desired non-mobile layout and functionality */}
{isMobile === false && (
<Slide index={0} key={0} />
)}

{Object.keys(theseItems).map((key, index) => {
// Reflect that initial dummy/bookend slide shown on non-mobile/tablet views:
const thisOffsetIndex = index + (isMobile ? 0 : 1);

return (
// Calculate the index offset accordingly to reflect the number of slides,
// but use the REAL index when determining if its the last REAL slide
<Slide
index={thisOffsetIndex}
className={index === (theseItems.length - 1) && 'last-slide'}
key={thisOffsetIndex}
>

<SlideCopyWrapper
className="slide-copy-wrapper"
mobileHeight={mobileHeight}
tabletHeight={tabletHeight}
desktopHeight={desktopHeight}
nodeBackgroundColour={nodeBackgroundColour}
nodeOutlineColour={nodeOutlineColour}
>
{theseItems[index].copy}
</SlideCopyWrapper>

</Slide>
);
})}

{/* Dummy slide for our desired non-mobile layout and functionality */}
{isMobile === false && (
<Slide index={theseItems.length + 1} key="bookend-last" />
)}

</Slider>
<ButtonBack>Back</ButtonBack>
<ButtonNext>Next</ButtonNext>
</CarouselProvider>
)}

</CarouselWrapper>
);
};

RichtextCarousel.propTypes = {
data: PropTypes.shape({
headingCopy: PropTypes.string.isRequired,
nodes: PropTypes.arrayOf(PropTypes.shape({
copy: PropTypes.string.isRequired
})).isRequired,
autoPlay: PropTypes.bool.isRequired,
contentful_id: PropTypes.string.isRequired,
mobileHeight: PropTypes.number,
tabletHeight: PropTypes.number,
desktopHeight: PropTypes.number,
carouselBackgroundColour: PropTypes.string,
nodeBackgroundColour: PropTypes.string,
nodeOutlineColour: PropTypes.string
}).isRequired
};

export default RichtextCarousel;
14 changes: 14 additions & 0 deletions src/components/Organisms/RichtextCarousel/RichtextCarousel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Richtext Carousel

```js
const { RichtextCarouselItems } = require('../../../styleguide/data/data');

<div>
<h2 style={{textAlign: 'center'}}>
Richtext Carousel #1
</h2>
<RichtextCarousel
data={RichtextCarouselItems}/>
</div>

```
Loading

0 comments on commit fb8e985

Please sign in to comment.