Skip to content

Commit

Permalink
Merge pull request #889: Make showcase expandable
Browse files Browse the repository at this point in the history
  • Loading branch information
victorlin authored Jun 5, 2024
2 parents 6b9079d + 0dc2c00 commit 2e4844e
Showing 1 changed file with 85 additions and 18 deletions.
103 changes: 85 additions & 18 deletions static-site/src/components/ListResources/Showcase.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable react/prop-types */
import React, { useCallback, useEffect, useState } from 'react';
import { FaChevronDown, FaChevronUp } from 'react-icons/fa';
import styled from 'styled-components';
import {CardInner, CardImg, CardTitle} from "../Cards/styles";
import { theme } from "../../layouts/theme";
Expand All @@ -9,26 +10,56 @@ import { LIST_ANCHOR } from "./index";
import { Card, FilterOption, Group } from './types';

const cardWidthHeight = 160; // pixels
const expandPreviewHeight = 50 //pixels
const transitionDuration = "0.3s"
const transitionTimingFunction = "ease"

interface ShowcaseProps {
cards: Card[]
setSelectedFilterOptions: React.Dispatch<React.SetStateAction<readonly FilterOption[]>>
}

export const Showcase = ({cards, setSelectedFilterOptions}: ShowcaseProps) => {
if (!cards.length) return null;

const [cardsContainerHeight, setCardsContainerHeight] = useState<number>(0);
const [isExpanded, setIsExpanded] = useState<boolean>(false);

const toggleExpand = () => {
setIsExpanded(!isExpanded);
};

/**
* Function that runs on changes to the container.
* Used to determine the height upon resize.
*/
function cardsContainerRef(cardsContainer: HTMLDivElement) {
if (!cardsContainer) return;

if(cardsContainerHeight != cardsContainer.clientHeight) {
setCardsContainerHeight(cardsContainer.clientHeight)
}
}

const isExpandable = cardsContainerHeight > cardWidthHeight;

return (
<div>
<Byline>
Showcase resources: click to filter the resources to a pathogen
</Byline>
<SingleRow>
<ShowcaseContainer>
<ShowcaseContainer className={!isExpandable ? "" : isExpanded ? "expanded" : "collapsed"} $expandedHeight={cardsContainerHeight}>
<CardsContainer ref={cardsContainerRef}>
{cards.map((el) => (
<ShowcaseTile card={el} key={el.name} setSelectedFilterOptions={setSelectedFilterOptions}/>
))}
</ShowcaseContainer>
</SingleRow>
</CardsContainer>
<PreviewOverlay onClick={toggleExpand} className={!isExpandable || isExpanded ? "hidden" : "visible"} />
</ShowcaseContainer>
{isExpandable && <>
<ArrowButton onClick={toggleExpand}>
{isExpanded ? <FaChevronUp/> : <FaChevronDown/>}
</ArrowButton>
</>}
<Spacer/>
</div>
)
Expand Down Expand Up @@ -66,23 +97,59 @@ const ShowcaseTile = ({card, setSelectedFilterOptions}: ShowcaseTileProps) => {
}


/* SingleRow only shows a single row of tiles. By using this to wrap a flexbox
element we can leverage the intelligent wrapping of the flexbox to decide how
many tiles to show in a single row. The downside is that showcase tiles are
still in the DOM, and the images are still fetched etc */
const SingleRow = styled.div`
max-height: ${cardWidthHeight}px;
overflow-y: clip;
const ShowcaseContainer = styled.div<{$expandedHeight: number}>`
position: relative;
overflow-y: hidden;
&.collapsed {
max-height: ${cardWidthHeight + expandPreviewHeight}px;
}
&.expanded {
max-height: ${(props) => `${props.$expandedHeight}px`};
}
transition: max-height ${transitionDuration} ${transitionTimingFunction};
`

const ArrowButton = styled.div`
text-align: center;
width: 100%;
height: 1em;
cursor: pointer;
`

const ShowcaseContainer = styled.div`
const PreviewOverlay = styled.div`
position: absolute;
z-index: 1;
bottom: 0;
left: 0;
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0) -100%,
rgba(255, 255, 255, 1) 100%);
width: 100%;
height: ${expandPreviewHeight}px;
cursor: pointer;
&.visible {
opacity: 1;
}
&.hidden {
opacity: 0;
}
transition: opacity ${transitionDuration} ${transitionTimingFunction};
`;

const CardsContainer = styled.div`
/* background-color: #ffeab0; */
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: hidden;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(${cardWidthHeight}px, max-content));
grid-gap: 1%;
overflow: hidden;
justify-content: space-between;
justify-content: center;
`;

const Spacer = styled.div`
Expand Down

0 comments on commit 2e4844e

Please sign in to comment.