diff --git a/www/src/components/rotator.js b/www/src/components/rotator.js new file mode 100644 index 0000000000000..27ff993a69316 --- /dev/null +++ b/www/src/components/rotator.js @@ -0,0 +1,195 @@ +import React, { Component } from "react" +import Slider from "./slider" +import { options } from "../utils/typography" +import { scale, colors, space, radii } from "../utils/presets" +import Link from "gatsby-link" +import MdNavigateBefore from "react-icons/lib/md/navigate-before" +import MdNavigateNext from "react-icons/lib/md/navigate-next" +import { srOnly } from "../utils/styles" + +const controlButtonStyles = { + WebkitAppearance: `none`, + color: colors.gray.calm, + fontWeight: 700, + border: 0, + background: `transparent`, + position: `absolute`, + top: 0, + bottom: 0, + left: 0, + padding: 0, + fontSize: scale[5], + width: space[8], + textAlign: `center`, + "&:hover": { + cursor: `pointer`, + color: colors.gatsby, + background: colors.ui.whisper, + }, + "&:active": { background: colors.ui.light }, +} + +class Rotator extends Component { + state = { + item: 0, + size: {}, + } + sliderContainer = React.createRef() + intervalId = null + + _clearInterval() { + if (this.intervalId) { + clearInterval(this.intervalId) + this.intervalId = null + } + } + + decrementItem = () => { + this._clearInterval() + this.setState({ + item: + (this.state.item + this.props.items.length - 1) % + this.props.items.length, + }) + } + + incrementItemAndClearInterval = () => { + this._clearInterval() + this.incrementItem() + } + + incrementItem = () => { + this.setState(state => { + return { + item: (state.item + 1) % this.props.items.length, + } + }) + } + + componentDidMount() { + if (this.shouldAnimate()) { + requestAnimationFrame(() => { + this.intervalId = setInterval(this.incrementItem, 5000) + this.setState({ size: this.getDimensions() }) + }) + } + } + + componentWillUnmount() { + clearInterval(this.intervalId) + } + + componentDidUpdate(prevProps, prevState) { + if (this.shouldAnimate() && prevState.item !== this.state.item) { + requestAnimationFrame(() => { + this.setState({ size: this.getDimensions() }) + }) + } + } + + getDimensions() { + if (this.sliderContainer.current === null) { + return { + width: `auto`, + height: `auto`, + } + } + + return this.sliderContainer.current.getBoundingClientRect() + } + + shouldAnimate() { + const mediaQuery = window.matchMedia(`(prefers-reduced-motion)`) + return !mediaQuery || !mediaQuery.matches + } + + render() { + const { text, pluginName } = this.props.items[this.state.item] + const enableSlider = this.shouldAnimate() && this.intervalId + + return ( +
+ Need
+
+
+ {!enableSlider ? (
+ <>{text}>
+ ) : (
+
+ There’s{` `} + {pluginName ? ( + a plugin + ) : ( + `a plugin` + )} + {` `} + for that. +
+ + +diff --git a/www/src/utils/styles.js b/www/src/utils/styles.js index fd1511b95ae6d..4a61d52b029bd 100644 --- a/www/src/utils/styles.js +++ b/www/src/utils/styles.js @@ -17,6 +17,17 @@ const stripeAnimation = keyframes({ "100%": { backgroundPosition: `${space[7]} ${space[11]}` }, }) +export const srOnly = { + position: `absolute`, + width: 1, + height: 1, + padding: 0, + overflow: `hidden`, + clip: `rect(0,0,0,0)`, + whiteSpace: `nowrap`, + border: 0, +} + export const scrollbarStyles = { WebkitOverflowScrolling: `touch`, "&::-webkit-scrollbar": {