Skip to content

Commit

Permalink
feat(home): add shelf loading state
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristiaanScheermeijer committed May 7, 2021
1 parent 034da76 commit 3bcb426
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function Card({

return (
<div className={cardClassName} onClick={onClick} onMouseEnter={onHover} role="button" aria-label={`Play ${title}`}>
<div className={posterClassNames} style={{ backgroundImage: `url(${posterSource})` }}>
<div className={posterClassNames} style={{ backgroundImage: posterSource ? `url(${posterSource})` : '' }}>
<div className={styles.meta}>
<div className={styles.title}>{featured ? title : ''}</div>
{metaData()}
Expand Down
36 changes: 25 additions & 11 deletions src/components/Shelf/Shelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,27 @@ export type ShelfProps = {
onCardClick: (playlistItem: PlaylistItem) => void;
onCardHover: (playlistItem: PlaylistItem) => void;
featured?: boolean;
loading?: boolean;
};

const Shelf: React.FC<ShelfProps> = ({ playlist, onCardClick, onCardHover, featured = false }: ShelfProps) => {
const placeholderItems = new Array(15).fill({});

const Shelf: React.FC<ShelfProps> = ({ playlist, onCardClick, onCardHover, featured = false, loading = false }: ShelfProps) => {
const breakpoint: Breakpoint = useBreakpoint();
const tilesToShow: number = featured ? featuredTileBreakpoints[breakpoint] : tileBreakpoints[breakpoint];

if (!playlist) return null;

return (
<div className={styles['Shelf']}>
{!featured && <h2 className={styles['title']}>{playlist.title}</h2>}
<TileDock
items={playlist.playlist}
{!featured && (
<h2 className={styles['title']}>{loading ? '...' : playlist.title}</h2>
)}
<TileDock<PlaylistItem | number>
items={loading ? placeholderItems : playlist.playlist}
tilesToShow={tilesToShow}
cycleMode={'restart'}
transitionTime="0.3s"
transitionTime={loading ? '0s' : '0.3s'}
spacing={12}
renderLeftControl={(handleClick) => (
<button className={classNames(styles['arrowButton'], styles['arrowLeft'])} onClick={handleClick}>
Expand All @@ -57,14 +62,23 @@ const Shelf: React.FC<ShelfProps> = ({ playlist, onCardClick, onCardHover, featu
</button>
)}
renderTile={(item) => {
const playlistItem = item as PlaylistItem;
if (loading || typeof item === 'number') {
return (
<Card
title={'...'}
duration={0}
featured={featured}
/>
);
}

return (
<Card
title={playlistItem.title}
duration={playlistItem.duration}
posterSource={playlistItem.image}
onClick={() => onCardClick(playlistItem)}
onHover={() => onCardHover(playlistItem)}
title={item.title}
duration={item.duration}
posterSource={item.image}
onClick={() => onCardClick(item)}
onHover={() => onCardHover(item)}
featured={featured}
/>
);
Expand Down
36 changes: 18 additions & 18 deletions src/components/TileDock/TileDock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export type CycleMode = 'stop' | 'restart' | 'endless';
type Direction = 'left' | 'right';
type Position = { x: number; y: number };

export type TileDockProps = {
items: unknown[];
export type TileDockProps<T> = {
items: T[];
cycleMode?: CycleMode;
tilesToShow?: number;
spacing?: number;
Expand All @@ -15,17 +15,17 @@ export type TileDockProps = {
showControls?: boolean;
animated?: boolean;
transitionTime?: string;
renderTile: (item: unknown) => JSX.Element;
renderTile: (item: T) => JSX.Element;
renderLeftControl?: (handleClick: () => void) => JSX.Element;
renderRightControl?: (handleClick: () => void) => JSX.Element;
};

type Tile = {
item: unknown;
type Tile<T> = {
item: T;
key: string;
};

const makeTiles = (originalList: unknown[], slicedItems: unknown[]): Tile[] => {
const makeTiles = <T,>(originalList: T[], slicedItems: T[]): Tile<T>[] => {
const itemIndices: string[] = [];

return slicedItems.map((item) => {
Expand All @@ -38,27 +38,27 @@ const makeTiles = (originalList: unknown[], slicedItems: unknown[]): Tile[] => {
});
};

const sliceItems = (
items: unknown[],
const sliceItems = <T,>(
items: T[],
isMultiPage: boolean,
index: number,
tilesToShow: number,
cycleMode: CycleMode,
): Tile[] => {
): Tile<T>[] => {
if (!isMultiPage) return makeTiles(items, items);

const sliceFrom: number = index;
const sliceTo: number = index + tilesToShow * 3;
const cycleModeEndlessCompensation: number = cycleMode === 'endless' ? tilesToShow : 1;
const listStartClone: unknown[] = items.slice(0, tilesToShow + cycleModeEndlessCompensation);
const listEndClone: unknown[] = items.slice(0 - tilesToShow + 1);
const itemsWithClones: unknown[] = [...listEndClone, ...items, ...listStartClone];
const itemsSlice: unknown[] = itemsWithClones.slice(sliceFrom, sliceTo);
const listStartClone: T[] = items.slice(0, tilesToShow + cycleModeEndlessCompensation);
const listEndClone: T[] = items.slice(0 - tilesToShow + 1);
const itemsWithClones: T[] = [...listEndClone, ...items, ...listStartClone];
const itemsSlice: T[] = itemsWithClones.slice(sliceFrom, sliceTo);

return makeTiles(items, itemsSlice);
};

const TileDock = ({
const TileDock = <T extends unknown>({
items,
tilesToShow = 6,
cycleMode = 'endless',
Expand All @@ -70,7 +70,7 @@ const TileDock = ({
renderTile,
renderLeftControl,
renderRightControl,
}: TileDockProps) => {
}: TileDockProps<T>) => {
const [index, setIndex] = useState<number>(0);
const [slideToIndex, setSlideToIndex] = useState<number>(0);
const [transform, setTransform] = useState<number>(-100);
Expand All @@ -84,8 +84,8 @@ const TileDock = ({
const isMultiPage: boolean = items.length > tilesToShow;
const transformWithOffset: number = isMultiPage ? 100 - tileWidth * (tilesToShow - 1) + transform : 0;

const tileList: Tile[] = useMemo(() => {
return sliceItems(items, isMultiPage, index, tilesToShow, cycleMode);
const tileList: Tile<T>[] = useMemo(() => {
return sliceItems<T>(items, isMultiPage, index, tilesToShow, cycleMode);
}, [items, isMultiPage, index, tilesToShow, cycleMode]);

const transitionBasis: string = `transform ${animated ? transitionTime : '0s'} ease`;
Expand Down Expand Up @@ -187,7 +187,7 @@ const TileDock = ({
onTouchEnd={handleTouchEnd}
onTransitionEnd={handleTransitionEnd}
>
{tileList.map((tile: Tile, listIndex) => {
{tileList.map((tile: Tile<T>, listIndex) => {
// Todo:
// const isTabable = isAnimating || !isMultiPage || (listIndex > tilesToShow - 1 && listIndex < tilesToShow * 2);
const isVisible = true; // Todo: hide all but visible?
Expand Down
14 changes: 11 additions & 3 deletions src/container/Shelf/Shelf.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import type { PlaylistItem } from 'types/playlist';

import usePlaylist, { UsePlaylistResult } from '../../hooks/usePlaylist';
import ShelfComponent from '../../components/Shelf/Shelf';
import type { PlaylistItem } from 'types/playlist';

type ShelfProps = {
playlistId: string;
Expand All @@ -13,10 +14,17 @@ type ShelfProps = {
const Shelf = ({ playlistId, onCardClick, onCardHover, featured = false }: ShelfProps): JSX.Element => {
const { isLoading, error, data: playlist }: UsePlaylistResult = usePlaylist(playlistId);

if (isLoading) return <p>Spinner here (todo)</p>;
if (error) return <p>Error here {error}</p>;

return <ShelfComponent playlist={playlist} onCardClick={onCardClick} onCardHover={onCardHover} featured={featured} />;
return (
<ShelfComponent
loading={isLoading}
playlist={playlist}
onCardClick={onCardClick}
onCardHover={onCardHover}
featured={featured}
/>
);
};

export default Shelf;

0 comments on commit 3bcb426

Please sign in to comment.