Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add animated image slider #1417

Merged
merged 21 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1b0951c
wip: basic image with arrows
roadlittledawn Jun 21, 2021
0a0d020
refactor: add prop validation. remove extra img component. only show …
roadlittledawn Jun 21, 2021
b43b7b5
feat: add left arrow to navigate to previous image
roadlittledawn Jun 21, 2021
6890786
chore: remove console.log
roadlittledawn Jun 21, 2021
a956633
refactor: use image placeholder if no images passed to slider
roadlittledawn Jun 21, 2021
bb88a9e
refactor: use Button from theme
roadlittledawn Jun 21, 2021
3abb4fb
fix: fix lint error
roadlittledawn Jun 21, 2021
5978e1c
feat: add fade animation for each slide
roadlittledawn Jun 21, 2021
f07fc88
fix: remove unneeded no image placeholder for now
roadlittledawn Jun 21, 2021
c871c2a
feat: add slide dots. add liz's sliding transformation config
roadlittledawn Jun 22, 2021
c5cb659
fix: fix lint errors
roadlittledawn Jun 22, 2021
96de16d
refactor: change nav control colors to be more visible on light/dark …
roadlittledawn Jun 22, 2021
cfea220
chore: go back to using real screenshots
roadlittledawn Jun 22, 2021
f7ad1b2
refactor: improve nav button styling to be visible on light/dark scre…
roadlittledawn Jun 22, 2021
f280a1a
refactor: add meaninful img alt value
roadlittledawn Jun 22, 2021
62a0538
fix: fix lint error on alt attribute
roadlittledawn Jun 22, 2021
d4b77f5
refactor: make props required for now. remove img width when not on l…
roadlittledawn Jun 22, 2021
7fcc603
refactor: move ImageSlider to components dir. show entire scaled down…
roadlittledawn Jun 22, 2021
f7ff4e8
refactor: tweaks to sizing and layouts for images
roadlittledawn Jun 22, 2021
c918ce3
refactor: cleanup superfluous css
roadlittledawn Jun 22, 2021
a8f18ba
fix: prevent image from overflowing top/bottom of slide
roadlittledawn Jun 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/@newrelic/gatsby-theme-newrelic/icons/feather.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ export default {
/>
</>
),
'chevron-left': (
<>
<polyline points="15 18 9 12 15 6" />
</>
),
'chevron-right': (
<>
<polyline points="9 18 15 12 9 6" />
</>
),
circle: (
<>
<circle cx="12" cy="12" r="10" />
</>
),
clock: (
<>
<circle cx="12" cy="12" r="10" />
Expand Down
203 changes: 203 additions & 0 deletions src/components/ImageSlider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import { css } from '@emotion/react';
import { Button, Icon } from '@newrelic/gatsby-theme-newrelic';
import { Transition, animated } from 'react-spring';

const ImageSlider = ({ images, height }) => {
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
const [forward, setForward] = useState(true);

const handleClickNext = () => {
const nextImageIndex = selectedImageIndex + 1;
setSelectedImageIndex(nextImageIndex % images.length);
setForward(true);
};

const handleClickPrev = () => {
const prevImageIndex = selectedImageIndex - 1;
if (prevImageIndex < 0) {
setSelectedImageIndex(images.length - 1);
} else {
setSelectedImageIndex(prevImageIndex % images.length);
}
setForward(false);
};

const handleClickSpecificSlide = (indexValue) => {
setSelectedImageIndex(indexValue);
};

return (
<div
css={css`
position: relative;
display: flex;
align-items: center;
height: ${height}px;
margin-bottom: 2rem;
overflow: hidden;
`}
>
{images.length > 1 && (
<div
css={css`
z-index: 200;
width: 100%;
height: 20%;
display: flex;
justify-content: space-between;
@media screen and (max-width: 400px) {
height: 12%;
}
`}
>
<Button
onClick={handleClickPrev}
variant={Button.VARIANT.PLAIN}
css={css`
background: var(--color-neutrals-300);
opacity: 0.2;
border: none;
cursor: pointer;
width: 10%;
min-width: 3rem;
height: 100%;
&:hover {
opacity: 0.5;
background: var(--color-neutrals-300);
}
`}
>
<Icon
css={css`
color: var(--color-black);
`}
name="chevron-left"
size="100%"
/>
</Button>
<Button
onClick={handleClickNext}
variant={Button.VARIANT.PLAIN}
css={css`
background: var(--color-neutrals-300);
opacity: 0.2;
border: none;
cursor: pointer;
width: 10%;
min-width: 3rem;
height: 100%;
&:hover {
opacity: 0.5;
background: var(--color-neutrals-300);
}
`}
>
<Icon
name="chevron-right"
size="100%"
css={css`
color: var(--color-black);
`}
/>
</Button>
</div>
)}
{
<Transition
items={images[selectedImageIndex]}
from={{
opacity: 0.5,
transform: `translate3d(${forward ? '100%' : '-100%'}, 0px, 0px)`,
}}
enter={{ opacity: 1, transform: 'translate3d(-0%, 0px, 0px)' }}
leave={{
transform: `translate3d(${forward ? '-100%' : '100%'}, 0px, 0px)`,
}}
delay={200}
config={{ mass: 1, tension: 100, friction: 20 }}
>
{(styles, item) => (
<animated.div
css={css`
display: flex;
height: 100%;
align-items: center;
`}
style={{ ...styles, position: 'absolute' }}
>
<a href={item} target="_blank" rel="noreferrer">
<img
src={item}
alt={`${item.split('/').slice(-1)}`}
css={css`
width: 100%;
max-height: ${height}px;
box-sizing: border-box;
box-shadow: inset 0px 0px 0px 4px var(--divider-color);
border-radius: 4px;
padding: 0.25rem;
`}
/>
</a>
</animated.div>
)}
</Transition>
}
<div
css={css`
z-index: 200;
position: absolute;
bottom: 2%;
width: 100%;
`}
>
<div
css={css`
display: flex;
justify-content: center;
flex-wrap: wrap;
`}
>
{images.map((_, index) => (
<Button
onClick={() => handleClickSpecificSlide(index)}
key={`goToSlide${index}`}
variant={Button.VARIANT.PLAIN}
css={css`
border: none;
cursor: pointer;
color: var(--color-neutrals-300);
&:hover {
background: none;
border: none;
color: var(--color-neutrals-300);
}
`}
>
<Icon
name="circle"
css={css`
fill: ${selectedImageIndex === index
? `var(--color-neutrals-300)`
: 'none'};
&:hover {
fill: var(--color-neutrals-300);
}
`}
/>
</Button>
))}
</div>
</div>
</div>
);
};

ImageSlider.propTypes = {
images: PropTypes.array.isRequired,
height: PropTypes.number.isRequired,
};

export default ImageSlider;
6 changes: 2 additions & 4 deletions src/templates/ObservabilityPackDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import ImageGallery from '../components/ImageGallery';
import Intro from '../components/Intro';
import InstallButton from '../components/InstallButton';
import ImageSlider from '../components/ImageSlider';

const ObservabilityPackDetails = ({ data, location }) => {
const pack = data.observabilityPacks;
Expand Down Expand Up @@ -134,7 +135,7 @@ const ObservabilityPackDetails = ({ data, location }) => {
{pack.dashboards?.map((dashboard) => (
<>
<h3>{dashboard.name}</h3>
<ImageGallery images={dashboard.screenshots} />
<ImageSlider height={400} images={dashboard.screenshots} />
{dashboard.description && (
<>
<h4>Description</h4>
Expand Down Expand Up @@ -267,11 +268,8 @@ export const pageQuery = graphql`
query($id: String!) {
observabilityPacks(id: { eq: $id }) {
name
websiteUrl
logoUrl
level
id
iconUrl
description
dashboards {
description
Expand Down