Skip to content

Commit

Permalink
feat: add carousel to home page (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fran McDade authored and Fran McDade committed Sep 25, 2024
1 parent 465901f commit 0123448
Show file tree
Hide file tree
Showing 18 changed files with 440 additions and 109 deletions.
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({}),
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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;
}
`;

export const StyledBullets = styled(Bullets)`
bottom: 14px;
left: 50%;
position: absolute;
transform: translateX(-50%);
z-index: 100;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
Carousel as CarouselCards,
CarouselView,
StyledBullets,
} from "./carousel.styles";
import { Cards } from "./components/Cards/cards";
import { useInteractiveCarousel } from "./hooks/useInteractiveCarousel";

export const Carousel = (): JSX.Element => {
const {
activeIndex,
interactiveAction,
interactiveCards,
interactiveIndexes,
onSetActiveIndex,
} = useInteractiveCarousel();
return (
<CarouselView>
<CarouselCards {...interactiveAction}>
<Cards activeIndex={activeIndex} cards={interactiveCards} />
<StyledBullets
activeBullet={activeIndex}
bullets={interactiveIndexes}
onBullet={onSetActiveIndex}
/>
</CarouselCards>
</CarouselView>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const CARD_OFFSET_Y = 8;
export const CARD_SCALE_X = 40;
export const MAX_CARD_HEIGHT = 216;
export const MAX_CARD_HEIGHT_SM = 216;
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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
CARD_OFFSET_Y,
CARD_SCALE_X,
MAX_CARD_WIDTH,
MAX_DECK_SIZE,
TRANSITION_DELAY,
TRANSITION_DURATION,
} from "./constants";

/**
* 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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { 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 { ButtonBase as MButtonBase, 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;
}
}
`;

export const CardCallToAction = styled(MButtonBase)`
&.MuiButtonBase-root {
${textBody500};
color: #28285b;
margin-top: 16px;
text-decoration: underline;
text-decoration-skip-ink: none;
text-underline-position: from-font;
&:hover {
text-decoration: none;
}
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CardProps } from "@databiosphere/findable-ui/lib/components/common/Card/card";
import { RoundedPaper } from "@databiosphere/findable-ui/lib/components/common/Paper/paper.styles";
import { Fragment } from "react";
import { getCardPosition } from "../../common/utils";
import { Card, CardContent, CardPositioner, CardSection } from "./cards.styles";

export interface CardsProps {
activeIndex: number;
cards: CardProps[];
}

export const Cards = ({ activeIndex, cards }: CardsProps): JSX.Element => {
const lastIndex = cards.length - 1;
return (
<Fragment>
{cards.map(({ text }, c) => {
return (
<CardPositioner
key={c}
cardPosition={getCardPosition(c, activeIndex, lastIndex)}
>
<Card component={RoundedPaper}>
<CardSection>
<CardContent>{text}</CardContent>
</CardSection>
</Card>
</CardPositioner>
);
})}
</Fragment>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as LearnToAnalyzeData } from "./learnToAnalyzeData.mdx";
export { default as ShareUsageAndJoinAdvisoryPanel } from "./shareUsageAndJoinAdvisoryPanel.mdx";
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Learn how to analyze your data!

The new BRC-analytics platform will make heavy use of the Galaxy platform for analysis of data. To learn how to use this system or to improve your already existing skills enroll into [Galaxy Academy 2024](https://training.galaxyproject.org/training-material/events/galaxy-academy-2024.html). The Academy is a global online training event that will take place October 7 - 11, 2024. For more information please see [the event page](https://training.galaxyproject.org/training-material/events/galaxy-academy-2024.html). Note that free registration is required.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Share your usage and join our advisory panel.

BRC Analytics is actively evolving to provide comprehensive data access and analytical tools for all 785 eukaryotic pathogens, host taxa, and vectors previously supported by VEuPathDB.We need your help to improve—share your usage patterns and join our design advisory panel to help shape the future of the platform.

<CardCTA
href="https://docs.google.com/forms/d/e/1FAIpQLSdSj9QtrY1zdUF45V7zGDKY1qKlo8BbSgF0BPfKfSzRTlgsVg/viewform?usp=sf_link"
rel="noopener noreferrer"
target="_blank"
>
Get Involved
</CardCTA>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CardProps } from "@databiosphere/findable-ui/lib/components/common/Card/card";
import { useMemo } from "react";
import {
UseSwipeInteraction,
useSwipeInteraction,
} from "../../../../../../../../../hooks/useSwipeInteraction/useSwipeInteraction";
import { CAROUSEL_CARDS } from "../cards/constants";

export interface UseInteractiveCarousel {
activeIndex: UseSwipeInteraction["activeIndex"];
interactiveAction?: UseSwipeInteraction["interactiveAction"];
interactiveCards: CardProps[];
interactiveIndexes: number[];
onSetActiveIndex: UseSwipeInteraction["onSetActiveIndex"];
onSetSwipeAction: UseSwipeInteraction["onSetSwipeAction"];
}

/**
* Facilitates interaction capabilities for the carousel.
* @returns carousel cards, interactive indexes, and interactive actions.
*/
export function useInteractiveCarousel(): UseInteractiveCarousel {
// Raw carousel cards.
const carouselCards = CAROUSEL_CARDS;
// Get the interactive indexes.
const interactiveIndexes = useMemo(
() => buildInteractiveIndexes(carouselCards),
[carouselCards]
);
// Get the active index and interactive actions.
const swipeInteraction = useSwipeInteraction(
interactiveIndexes.length,
true,
8000
);
return {
interactiveCards: carouselCards,
interactiveIndexes,
...swipeInteraction,
};
}

/**
* Returns array of interactive indexes.
* @param cards - Cards.
* @returns a list of indexes that are interactive.
*/
function buildInteractiveIndexes(cards: CardProps[]): number[] {
return [...Array(cards.length).keys()];
}
Loading

0 comments on commit 0123448

Please sign in to comment.