forked from US-GHG-Center/veda-config-ghg
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
freitagb
committed
Nov 12, 2024
1 parent
794e410
commit 1e22710
Showing
7 changed files
with
251 additions
and
6 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import React from '$veda-ui/react'; | ||
import styled from '$veda-ui/styled-components'; | ||
import { Button, Icon } from '$veda-ui/@trussworks/react-uswds'; | ||
|
||
import { | ||
Card, | ||
CardBody, | ||
CardFooter, | ||
} from '$veda-ui/@trussworks/react-uswds'; | ||
|
||
|
||
const progressColor = '#1565EF'; | ||
|
||
const ProgressIndicator = styled.div` | ||
background-color: ${progressColor}; | ||
width: ${props => props.progressWidth}%; | ||
transition: ${props => props.noTransition? null: 'width 200ms ease-out'}; | ||
`; | ||
|
||
function ProgressBar({ selected, shouldProgress, progressDone, progressPercentage }) { | ||
// If progress is done, 100% - false if something is manually selected | ||
// If it is in progress, progress Percentage - false if something is manually selected | ||
// If it is manually selected, 100% | ||
const progressWidth = progressDone? 100: shouldProgress? progressPercentage: selected? 100: 0; | ||
const noTransition = (!shouldProgress && !progressDone && progressPercentage === 0)? true : false; | ||
|
||
return <> | ||
<div className="height-05 bg-base-lighter"> | ||
<ProgressIndicator className="height-full" progressWidth={progressWidth} noTransition={noTransition} /> | ||
</div> | ||
</> | ||
} | ||
|
||
export function ItemPanel({ item, linkComponent: LinkComponent }) { | ||
return (<> | ||
|
||
<div className="tablet:margin-top-0 margin-top-2 flex-align-self-stretch"> | ||
<p className="margin-top-2 margin-bottom-2 flex-align-self-stretch">{item.description}</p> | ||
<LinkComponent className="display-flex flex-align-center veda-color--link" to={item.link}> | ||
<Icon.ArrowForward stroke={progressColor} fill={progressColor} /> | ||
<span className="padding-left-1">Read more</span> | ||
</LinkComponent> | ||
</div> | ||
</>) | ||
} | ||
|
||
export default function CarouselItem({ item, itemIdx, onTitleClick, shouldProgress, progressDone, progressPercentage, selected, linkComponent: LinkComponent }) { | ||
return <Card | ||
gridLayout={{ tablet: { col: 4 } }} | ||
containerProps={{className:`hover:bg-base-lightest padding-x-1 radius-0 border-0 animation--transition ${(selected || shouldProgress)? 'opacity-100':'opacity-50'}`}}> | ||
<ProgressBar shouldProgress={shouldProgress} progressDone={progressDone} progressPercentage={progressPercentage}selected={selected} /> | ||
<CardBody className="padding-left-0 position-relative"> | ||
<h3 className="tablet:margin-top-1 carousel--title text-bold veda-color--base"> | ||
{item.title} | ||
</h3> | ||
<p className="margin-top-2 flex-align-self-stretch">{item.description}</p> | ||
<Button | ||
unstyled={true} | ||
className="position-absolute top-0 left-0 width-full height-full blocklink" | ||
onClick={() => { onTitleClick(item); } } | ||
type="button" | ||
role="tab" | ||
aria-label={`Slide ${itemIdx+1}`} | ||
aria-selected={selected.toString()} | ||
aria-controls={`carousel-item-${itemIdx+1}`} | ||
children={undefined} /> | ||
</CardBody> | ||
<CardFooter className="padding-left-0 padding-top-1"> | ||
<LinkComponent className="display-flex flex-align-center veda-color--link" to={item.link}> | ||
<Icon.ArrowForward stroke={progressColor} fill={progressColor} /> | ||
<span className="padding-left-1">Read more</span> | ||
</LinkComponent> | ||
</CardFooter> | ||
</Card> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* The classes for css transition group */ | ||
.imagetransition { | ||
&-enter { | ||
opacity: 0.5; | ||
} | ||
&-enter-active { | ||
opacity: 1; | ||
transition: opacity 400ms ease-in; | ||
} | ||
&-exit { | ||
opacity: 1; | ||
} | ||
/* ending EXIT animation */ | ||
&-exit-active { | ||
opacity: 0; | ||
transition: opacity 400ms ease-out; | ||
} | ||
} | ||
|
||
.veda-color--link { | ||
color: var(--veda-color-link); | ||
} | ||
.veda-color--base { | ||
color: var(--veda-color-base); | ||
} | ||
|
||
.animation--transition { | ||
transition: opacity 200ms ease-out; | ||
} | ||
|
||
.carousel { | ||
&--height { | ||
height: 500px; | ||
} | ||
|
||
&--content-image { | ||
width: 100%; | ||
height: 100%; | ||
object-fit: cover; | ||
} | ||
&--title { | ||
font-size: 1.25rem; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import React, { useState, useEffect, useCallback } from '$veda-ui/react'; | ||
|
||
import { CSSTransition, TransitionGroup } from "react-transition-group"; | ||
import { useMediaQuery } from "$veda-ui-scripts/utils/use-media-query"; | ||
import { GridContainer, Grid } from '$veda-ui/@trussworks/react-uswds'; | ||
import LazyLoad from '$veda-ui/react-lazyload'; | ||
import { CardGroup } from '$veda-ui/@trussworks/react-uswds'; | ||
|
||
import CarouselItems from './items'; | ||
import CarouselItem, { ItemPanel } from './carousel-item'; | ||
|
||
|
||
import SmartLink from '$veda-ui-scripts/components/common/smart-link'; | ||
|
||
import '/common/styles.scss'; | ||
import './index.scss'; | ||
|
||
const interval = 100; | ||
const slide_length = 50; | ||
const item_n = CarouselItems.length; | ||
|
||
export function DesktopCarousel () { | ||
const [timer, setTimer] = useState(0); | ||
const [selectedItem, setSelectedItem] = useState(null); | ||
const [timerAnimationId, setTimerAnimationId] = useState(null); | ||
|
||
// Animation starts on landing, once it is stopped, it is not going to be played again. | ||
useEffect(() => { | ||
const intervalId = setInterval(() => { | ||
setTimer(prev => { | ||
return prev + 1; | ||
}); | ||
}, interval); | ||
setTimerAnimationId(intervalId); | ||
return () => { | ||
clearInterval(intervalId); | ||
}; | ||
}, []); | ||
|
||
const animationTimer = timer % slide_length; | ||
// animationTimer/slide_length will never be 1, compensating the value here | ||
const progressPercentage = Math.floor((animationTimer/slide_length) * (100*(slide_length/(slide_length-1)))); | ||
const currentProgressItemIdx = Math.floor((timer / slide_length)%item_n); | ||
const itemInProgress = selectedItem?? CarouselItems[currentProgressItemIdx]; | ||
|
||
const onTitleClick = useCallback((clickedItem) => { | ||
clearInterval(timerAnimationId); | ||
setTimerAnimationId(null); | ||
setSelectedItem(clickedItem); | ||
},[timerAnimationId]); | ||
|
||
|
||
return ( | ||
<GridContainer aria-roledescription="carousel" aria-label="Highlighted VEDA Dashboard projects"> | ||
<Grid row className="position-relative carousel--height" aria-live="off"> | ||
<TransitionGroup> | ||
<CSSTransition | ||
key={itemInProgress.title} | ||
timeout={2000} | ||
classNames="imagetransition" | ||
> | ||
<div className="carousel--height width-full position-absolute left-0 top-0 shadow-1"> | ||
<img className="carousel--content-image" src={itemInProgress.image} alt={itemInProgress.imageAlt} /> | ||
</div> | ||
</CSSTransition> | ||
</TransitionGroup> | ||
</Grid> | ||
<CardGroup className="tablet:margin-top-4 margin-top-2" role="tablist" aria-label="Slides"> | ||
{CarouselItems.map((item, itemIdx) => { | ||
return <CarouselItem | ||
key={item.title} | ||
item={item} | ||
itemIdx={itemIdx} | ||
onTitleClick={onTitleClick} | ||
progressDone= {selectedItem? false: itemIdx < currentProgressItemIdx} | ||
shouldProgress = {selectedItem? false: currentProgressItemIdx == itemIdx} | ||
selected={!timerAnimationId && selectedItem?.title === item.title} | ||
progressPercentage = {progressPercentage} | ||
linkComponent={SmartLink} | ||
/> | ||
})} | ||
</CardGroup> | ||
</GridContainer>) | ||
} | ||
|
||
function TabletCarousel() { | ||
return <GridContainer> | ||
<Grid row className="margin-top-2"> | ||
{CarouselItems.map((item) => { | ||
return <Grid col={12} key={item.title} className="margin-bottom-4"> | ||
<div> | ||
<img className="carousel--content-image" src={item.image} /> | ||
</div> | ||
<h3 className="margin-top-1">{item.title}</h3> | ||
<ItemPanel item={item} linkComponent={SmartLink} /> | ||
</Grid> | ||
})} | ||
</Grid> | ||
</GridContainer> | ||
} | ||
|
||
|
||
export default function Carousel-stories() { | ||
const { isMediumUp } = useMediaQuery(); | ||
return isMediumUp? | ||
<LazyLoad | ||
className="hug-reset-container" | ||
offset={100} | ||
once | ||
> | ||
<DesktopCarousel /> | ||
</LazyLoad>: | ||
<div className="hug-reset-container"><TabletCarousel /></div> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export default [ | ||
{ | ||
link: 'https://earth.gov/sealevel', | ||
title: 'Global Sea Level Rise', | ||
description: 'The Global Sea Level Rise Portal offers essential information on current and project sea level rise to inform coastal communities across the globe.', | ||
image: new URL('../media/global_slr.png', import.meta.url).href, | ||
imageAlt: 'Coastline with crashing waves' | ||
}, | ||
{ | ||
link: 'https://earth.gov/sealevel/us', | ||
title: 'U.S. Sea Level Rise', | ||
description: ' The U.S. Sea Level Rise portal is a federally supported data visualizations coupled with explanations and science education to help communities prepare for challenges that will affect our coastal environments.', | ||
image: new URL('../media/us_slr.png', import.meta.url).href, | ||
imageAlt: 'Coastline with crashing waves' | ||
}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters