-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #102 from galaxyproject/fran/66-carousel
feat: add carousel to home page (#66)
- Loading branch information
Showing
26 changed files
with
699 additions
and
164 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
...nts/Home/components/Section/components/SectionHero/components/Carousel/cards/constants.ts
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,11 @@ | ||
import { CardProps } from "@databiosphere/findable-ui/lib/components/common/Card/card"; | ||
import * as MDX from "../content"; | ||
|
||
export const CAROUSEL_CARDS: Pick<CardProps, "text">[] = [ | ||
{ | ||
text: MDX.ShareUsageAndJoinAdvisoryPanel({}), | ||
}, | ||
{ | ||
text: MDX.LearnToAnalyzeData({}), | ||
}, | ||
]; |
57 changes: 57 additions & 0 deletions
57
...nts/Home/components/Section/components/SectionHero/components/Carousel/carousel.styles.ts
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,57 @@ | ||
import { | ||
mediaDesktopSmallUp, | ||
mediaTabletUp, | ||
} from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; | ||
import styled from "@emotion/styled"; | ||
import { Bullets } from "../../../../../../../common/Bullets/bullets"; | ||
import { | ||
CAROUSEL_HEIGHT, | ||
CAROUSEL_HEIGHT_SM, | ||
MAX_CARD_WIDTH, | ||
} from "./common/constants"; | ||
|
||
export const CarouselView = styled.div` | ||
grid-column: 1 / -1; | ||
max-width: ${MAX_CARD_WIDTH}px; | ||
width: 100%; | ||
${mediaDesktopSmallUp} { | ||
grid-column: 7 / -1; | ||
grid-row: 1 / 3; | ||
justify-self: flex-end; | ||
} | ||
`; | ||
|
||
export const Carousel = styled.div` | ||
cursor: grab; | ||
height: ${CAROUSEL_HEIGHT_SM}px; | ||
position: relative; /* Positions CardPositioner. */ | ||
user-select: none; | ||
&:active { | ||
cursor: grabbing; | ||
} | ||
${mediaTabletUp} { | ||
height: ${CAROUSEL_HEIGHT}px; | ||
} | ||
.MuiIconButton-root { | ||
opacity: 0; | ||
transition: opacity 150ms ease-in-out; | ||
} | ||
&:hover { | ||
> .MuiIconButton-root { | ||
opacity: 1; | ||
} | ||
} | ||
`; | ||
|
||
export const StyledBullets = styled(Bullets)` | ||
bottom: 14px; | ||
left: 50%; | ||
position: absolute; | ||
transform: translateX(-50%); | ||
z-index: 100; | ||
`; |
40 changes: 40 additions & 0 deletions
40
...omponents/Home/components/Section/components/SectionHero/components/Carousel/carousel.tsx
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,40 @@ | ||
import { SWIPE_ACTION } from "../../../../../../../../hooks/useSwipeInteraction/common/entities"; | ||
import { | ||
Carousel as CarouselCards, | ||
CarouselView, | ||
StyledBullets, | ||
} from "./carousel.styles"; | ||
import { Arrow } from "./components/Arrow/arrow"; | ||
import { Cards } from "./components/Cards/cards"; | ||
import { useInteractiveCarousel } from "./hooks/useInteractiveCarousel"; | ||
|
||
export const Carousel = (): JSX.Element => { | ||
const { | ||
activeIndex, | ||
interactiveAction, | ||
interactiveCards, | ||
interactiveIndexes, | ||
onSetActiveIndex, | ||
onSetSwipeAction, | ||
} = useInteractiveCarousel(); | ||
return ( | ||
<CarouselView> | ||
<CarouselCards {...interactiveAction}> | ||
<Arrow | ||
onClick={(): void => onSetSwipeAction(SWIPE_ACTION.SWIPE_BACKWARD)} | ||
swipeAction={SWIPE_ACTION.SWIPE_BACKWARD} | ||
/> | ||
<Cards activeIndex={activeIndex} cards={interactiveCards} /> | ||
<Arrow | ||
onClick={(): void => onSetSwipeAction(SWIPE_ACTION.SWIPE_FORWARD)} | ||
swipeAction={SWIPE_ACTION.SWIPE_FORWARD} | ||
/> | ||
<StyledBullets | ||
activeBullet={activeIndex} | ||
bullets={interactiveIndexes} | ||
onBullet={onSetActiveIndex} | ||
/> | ||
</CarouselCards> | ||
</CarouselView> | ||
); | ||
}; |
12 changes: 12 additions & 0 deletions
12
...ts/Home/components/Section/components/SectionHero/components/Carousel/common/constants.ts
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,12 @@ | ||
export const CARD_OFFSET_Y = 8; | ||
export const CARD_SCALE_X = 40; | ||
export const MAX_CARD_HEIGHT = 216; | ||
export const MAX_CARD_HEIGHT_SM = 280; | ||
export const MAX_DECK_SIZE = 1; // Currently, deck size is only 1 additional card. | ||
export const MAX_CARD_WIDTH = 504; | ||
export const CAROUSEL_HEIGHT = MAX_CARD_HEIGHT + MAX_DECK_SIZE * CARD_OFFSET_Y; | ||
export const CAROUSEL_HEIGHT_SM = | ||
MAX_CARD_HEIGHT_SM + MAX_DECK_SIZE * CARD_OFFSET_Y; | ||
export const TRANSITION_DELAY = 100; | ||
export const TRANSITION_DURATION = 100; | ||
export const ARROW_OFFSET_Y = (CARD_OFFSET_Y * MAX_DECK_SIZE) / 2; |
90 changes: 90 additions & 0 deletions
90
...onents/Home/components/Section/components/SectionHero/components/Carousel/common/utils.ts
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,90 @@ | ||
import { SWIPE_ACTION } from "../../../../../../../../../hooks/useSwipeInteraction/common/entities"; | ||
import { | ||
ARROW_OFFSET_Y, | ||
CARD_OFFSET_Y, | ||
CARD_SCALE_X, | ||
MAX_CARD_WIDTH, | ||
MAX_DECK_SIZE, | ||
TRANSITION_DELAY, | ||
TRANSITION_DURATION, | ||
} from "./constants"; | ||
|
||
/** | ||
* Returns the arrow's transform scaleX and translateY. | ||
* @param swipeAction - Swipe action. | ||
* @returns arrow's transform. | ||
*/ | ||
export function getArrowTransform(swipeAction: SWIPE_ACTION): string { | ||
return swipeAction === SWIPE_ACTION.SWIPE_FORWARD | ||
? `translate(24px, calc(${ARROW_OFFSET_Y}px - 50%)) scaleX(-1)` | ||
: `translate(-24px, calc(${ARROW_OFFSET_Y}px - 50%))`; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's position in the deck. | ||
* @param index - Card index. | ||
* @param activeIndex - Active index. | ||
* @param lastIndex - Last index. | ||
* @returns card position (position zero to deck size). | ||
*/ | ||
export function getCardPosition( | ||
index: number, | ||
activeIndex: number, | ||
lastIndex: number | ||
): number { | ||
const order = index - activeIndex; | ||
if (order >= 0) return order; | ||
// If the order is negative, stack the card to the end of the deck. | ||
// Grab the last (positive) position in the deck and add the card position (index + 1). | ||
return lastIndex - activeIndex + index + 1; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's x-axis scale. | ||
* @param cardPosition - Card position. | ||
* @returns card x-axis scale. | ||
*/ | ||
export function getCardScaleX(cardPosition: number): string { | ||
if (cardPosition === 0) return "scaleX(1)"; // The active card is scaled to 1. | ||
return `scaleX(${ | ||
(MAX_CARD_WIDTH - cardPosition * CARD_SCALE_X) / MAX_CARD_WIDTH | ||
})`; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's transform scaleX and translateY. | ||
* @param cardPosition - Card position. | ||
* @returns card transform. | ||
*/ | ||
export function getCardTransform(cardPosition: number): string { | ||
return `${getCardScaleX(cardPosition)} ${getCardTranslateY(cardPosition)}`; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's transition. | ||
* @param cardPosition - Card position. | ||
* @returns card transition. | ||
*/ | ||
export function getCardTransition(cardPosition: number): string { | ||
return `all ${TRANSITION_DURATION}ms ease-in-out ${ | ||
cardPosition * TRANSITION_DELAY | ||
}ms, z-index 0ms ${TRANSITION_DELAY}ms`; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's y-axis offset. | ||
* @param cardPosition - Card position. | ||
* @returns y-axis offset. | ||
*/ | ||
export function getCardTranslateY(cardPosition: number): string { | ||
return `translateY(${(MAX_DECK_SIZE - cardPosition) * CARD_OFFSET_Y}px)`; | ||
} | ||
|
||
/** | ||
* Returns the carousel card's z-index. | ||
* @param cardPosition - Card position. | ||
* @returns card z-index. | ||
*/ | ||
export function getCardZIndex(cardPosition: number): number { | ||
return MAX_DECK_SIZE - cardPosition; | ||
} |
60 changes: 60 additions & 0 deletions
60
...nents/Section/components/SectionHero/components/Carousel/components/Arrow/arrow.styles.ts
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,60 @@ | ||
import { mediaTabletDown } from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; | ||
import { | ||
inkMain, | ||
smokeDark, | ||
smokeLightest, | ||
white, | ||
} from "@databiosphere/findable-ui/lib/styles/common/mixins/colors"; | ||
import { black08 } from "@databiosphere/findable-ui/lib/theme/common/palette"; | ||
import { css } from "@emotion/react"; | ||
import styled from "@emotion/styled"; | ||
import { IconButton as MIconButton } from "@mui/material"; | ||
import { | ||
SwipeAction, | ||
SWIPE_ACTION, | ||
} from "../../../../../../../../../../hooks/useSwipeInteraction/common/entities"; | ||
import { MAX_DECK_SIZE } from "../../common/constants"; | ||
import { getArrowTransform } from "../../common/utils"; | ||
|
||
interface Props { | ||
swipeAction: SwipeAction; | ||
} | ||
|
||
export const IconButton = styled(MIconButton, { | ||
shouldForwardProp: (props) => props !== "swipeAction", | ||
})<Props>` | ||
& { | ||
background-color: ${white}; | ||
border-radius: 50%; | ||
box-shadow: inset 0 0 0 1px ${smokeDark}, 0 1px 0 0 ${black08}; | ||
color: ${inkMain}; | ||
position: absolute; | ||
top: 50%; | ||
transform: ${({ swipeAction }) => getArrowTransform(swipeAction)}; | ||
z-index: ${MAX_DECK_SIZE + 1}; | ||
&:hover { | ||
background-color: ${smokeLightest}; | ||
} | ||
&:active { | ||
box-shadow: inset 0 0 0 1px ${smokeDark}; | ||
} | ||
${mediaTabletDown} { | ||
display: none; | ||
} | ||
} | ||
${({ swipeAction }) => | ||
swipeAction === SWIPE_ACTION.SWIPE_BACKWARD && | ||
css` | ||
left: 0; | ||
`} | ||
${({ swipeAction }) => | ||
swipeAction === SWIPE_ACTION.SWIPE_FORWARD && | ||
css` | ||
right: 0; | ||
`} | ||
`; |
21 changes: 21 additions & 0 deletions
21
.../components/Section/components/SectionHero/components/Carousel/components/Arrow/arrow.tsx
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,21 @@ | ||
import { SouthIcon } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/components/SouthIcon/southIcon"; | ||
import { SwipeAction } from "../../../../../../../../../../hooks/useSwipeInteraction/common/entities"; | ||
import { IconButton } from "./arrow.styles"; | ||
|
||
interface ArrowProps { | ||
onClick: () => void; | ||
swipeAction: SwipeAction; | ||
} | ||
|
||
export const Arrow = ({ onClick, swipeAction }: ArrowProps): JSX.Element => { | ||
return ( | ||
<IconButton | ||
color="secondary" | ||
onClick={onClick} | ||
size="large" | ||
swipeAction={swipeAction} | ||
> | ||
<SouthIcon fontSize="small" /> | ||
</IconButton> | ||
); | ||
}; |
95 changes: 95 additions & 0 deletions
95
...nents/Section/components/SectionHero/components/Carousel/components/Cards/cards.styles.ts
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,95 @@ | ||
import { | ||
mediaTabletDown, | ||
mediaTabletUp, | ||
} from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; | ||
import { | ||
inkLight, | ||
smokeMain, | ||
} from "@databiosphere/findable-ui/lib/styles/common/mixins/colors"; | ||
import { | ||
textBody500, | ||
textBodyLarge500, | ||
textBodySmall4002Lines, | ||
} from "@databiosphere/findable-ui/lib/styles/common/mixins/fonts"; | ||
import { elevation01 } from "@databiosphere/findable-ui/lib/theme/common/shadows"; | ||
import styled from "@emotion/styled"; | ||
import { Card as MCard } from "@mui/material"; | ||
import { | ||
MAX_CARD_HEIGHT, | ||
MAX_CARD_HEIGHT_SM, | ||
MAX_CARD_WIDTH, | ||
} from "../../common/constants"; | ||
import { | ||
getCardTransform, | ||
getCardTransition, | ||
getCardZIndex, | ||
} from "../../common/utils"; | ||
|
||
interface Props { | ||
cardPosition: number; | ||
} | ||
|
||
export const CardPositioner = styled("div")<Props>` | ||
display: grid; | ||
height: 100%; | ||
max-height: ${MAX_CARD_HEIGHT_SM}px; | ||
max-width: ${MAX_CARD_WIDTH}px; | ||
position: absolute; | ||
transform: ${({ cardPosition }) => getCardTransform(cardPosition)}; | ||
transition: ${({ cardPosition }) => getCardTransition(cardPosition)}; | ||
width: 100%; | ||
z-index: ${({ cardPosition }) => getCardZIndex(cardPosition)}; | ||
${mediaTabletUp} { | ||
max-height: ${MAX_CARD_HEIGHT}px; | ||
} | ||
`; | ||
|
||
export const Card = styled(MCard)` | ||
border: none; | ||
box-shadow: ${elevation01}, inset 0 0 0 1px ${smokeMain}; | ||
display: flex; | ||
height: 100%; | ||
width: 100%; | ||
` as typeof MCard; | ||
|
||
export const CardSection = styled.div` | ||
display: flex; | ||
flex: 1; | ||
flex-direction: column; | ||
padding: 24px; | ||
`; | ||
|
||
export const CardContent = styled.div` | ||
h1, | ||
h2, | ||
h3 { | ||
${textBodyLarge500}; | ||
margin: 0; | ||
} | ||
p { | ||
${textBodySmall4002Lines}; | ||
color: ${inkLight}; | ||
margin: 8px 0; | ||
&:last-of-type { | ||
margin-bottom: 0; | ||
} | ||
} | ||
${mediaTabletDown} { | ||
-webkit-box-orient: vertical; | ||
display: -webkit-box; | ||
-webkit-line-clamp: 10; | ||
overflow: hidden; | ||
} | ||
`; | ||
|
||
export const CardActions = styled.div` | ||
${textBody500}; | ||
align-items: center; | ||
display: flex; | ||
gap: 16px; | ||
margin-top: 16px; | ||
`; |
Oops, something went wrong.