Skip to content

Commit

Permalink
feat(videodetail): add collapsible text
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut committed Jun 3, 2021
1 parent f38300b commit 405ec1f
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 22 deletions.
36 changes: 36 additions & 0 deletions src/components/CollapsibleText/CollapsibleText.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@use '../../styles/variables';
@use '../../styles/theme';

.collapsibleText {
position: relative;
padding-bottom: 20px;
}
.dummyDiv {
position: absolute;
visibility: hidden;
}
.textContainer {
overflow: hidden;
&.collapsed {
mask-image: linear-gradient(-180deg, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 100%);
-webkit-mask-image: linear-gradient(-180deg, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 100%);
}
}
.chevron {
position: absolute;
width: 24px;
height: 24px;
bottom: 25px;
left: calc(50% - 24px / 2);
z-index: 1;
cursor: pointer;

> svg {
transform: rotate(90deg);
}
&.expanded {
> svg {
transform: rotate(270deg);
}
}
}
12 changes: 12 additions & 0 deletions src/components/CollapsibleText/CollapsibleText.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { render } from '@testing-library/react';

import CollapsibleText from './CollapsibleText';

describe('<CollapsibleText>', () => {
test('renders and matches snapshot', () => {
const { container } = render(<CollapsibleText text="Test..." />);

expect(container).toMatchSnapshot();
});
});
50 changes: 50 additions & 0 deletions src/components/CollapsibleText/CollapsibleText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react';

import IconButton from '../IconButton/IconButton';
import ChevronRight from '../../icons/ChevronRight';

import styles from './CollapsibleText.module.scss';

type Props = {
text: string;
className?: string;
maxHeight?: 'none' | number;
};

const CollapsibleText: React.FC<Props> = ({ text, className, maxHeight = 'none' }: Props) => {
const dummyDiv = useRef<HTMLDivElement>() as React.MutableRefObject<HTMLDivElement>;
const [doesFlowOver, setDoesFlowOver] = useState(false);
const [collapsed, setCollapsed] = useState(true);

const ariaLabel = collapsed ? 'Expand' : 'Collapse';

useEffect(() => {
dummyDiv.current && setDoesFlowOver(dummyDiv.current.scrollHeight > dummyDiv.current?.offsetHeight);
}, [maxHeight]);

return (
<div className={classNames(styles.collapsibleText)}>
<div ref={dummyDiv} className={styles.dummyDiv} style={{ maxHeight }}>
{text}
</div>
<div
className={classNames(styles.textContainer, className, { [styles.collapsed]: collapsed && doesFlowOver })}
style={{ maxHeight: collapsed ? maxHeight : 'none' }}
>
{text}
</div>
{doesFlowOver && (
<IconButton
aria-label={ariaLabel}
className={classNames(styles.chevron, { [styles.expanded]: !collapsed })}
onClick={() => setCollapsed(!collapsed)}
>
<ChevronRight />
</IconButton>
)}
</div>
);
};

export default CollapsibleText;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<CollapsibleText> renders and matches snapshot 1`] = `
<div>
<div
class="collapsibleText"
>
<div
class="dummyDiv"
style="max-height: none;"
>
Test...
</div>
<div
class="textContainer"
style="max-height: none;"
>
Test...
</div>
</div>
</div>
`;
12 changes: 10 additions & 2 deletions src/components/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import classNames from 'classnames';
import React from 'react';

import styles from './IconButton.module.scss';
Expand All @@ -7,12 +8,19 @@ type Props = {
children: JSX.Element;
'aria-label': string;
tabIndex?: number;
className?: string;
};

const IconButton: React.FC<Props> = ({ children, onClick, 'aria-label': ariaLabel, tabIndex = 0 }: Props) => {
const IconButton: React.FC<Props> = ({
children,
onClick,
'aria-label': ariaLabel,
tabIndex = 0,
className,
}: Props) => {
return (
<div
className={styles.iconButton}
className={classNames(styles.iconButton, className)}
onClick={onClick}
aria-label={ariaLabel}
role="button"
Expand Down
2 changes: 1 addition & 1 deletion src/components/TileDock/TileDock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const TileDock = <T extends unknown>({
const ulStyle = {
transform: `translate3d(${transformWithOffset}%, 0, 0)`,
// prettier-ignore
webkitTransform: `translate3d(${transformWithOffset}%, 0, 0)`,
WebkitTransform: `translate3d(${transformWithOffset}%, 0, 0)`,
transition: transitionBasis,
marginLeft: -spacing / 2,
marginRight: -spacing / 2,
Expand Down
11 changes: 6 additions & 5 deletions src/components/Video/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import type { PlaylistItem } from 'types/playlist';
import classNames from 'classnames';

import CollapsibleText from '../CollapsibleText/CollapsibleText';
import Cinema from '../../containers/Cinema/Cinema';
import useBreakpoint, { Breakpoint } from '../../hooks/useBreakpoint';
import Favorite from '../../icons/Favorite';
Expand All @@ -24,9 +25,11 @@ type Props = {
};

const Video: React.FC<Props> = ({ item, play, startPlay, goBack, posterFading, relatedShelf }: Props) => {
const posterImage = item.image.replace('720', '1280'); // Todo: 1280 should be sent from API
const breakpoint = useBreakpoint();
const breakpoint: Breakpoint = useBreakpoint();
const isLargeScreen = breakpoint >= Breakpoint.md;
const isMobile = breakpoint === Breakpoint.xs;
const imageSourceWidth = 640 * (window.devicePixelRatio > 1 || isLargeScreen ? 2 : 1);
const posterImage = item.image.replace('720', imageSourceWidth.toString()); // Todo: should be taken from images (1280 should be sent from API)

const metaData = [];
if (item.pubdate) metaData.push(new Date(item.pubdate).getFullYear());
Expand All @@ -35,17 +38,15 @@ const Video: React.FC<Props> = ({ item, play, startPlay, goBack, posterFading, r
if (item.rating) metaData.push(item.rating);
const metaString = metaData.join(' • ');

//todo: image based on screen res, etc (like Home)
//todo: breakpoints not same as css (so info padding-top acts too soon)
//todo: description enlarger

return (
<div className={styles.video}>
<div className={styles.main}>
<div className={styles.info}>
<h2 className={styles.title}>{item.title}</h2>
<div className={styles.meta}>{metaString}</div>
{!isMobile && <div className={styles.description}>{item.description}</div>}
<CollapsibleText text={item.description} className={styles.description} maxHeight={isMobile ? 50 : 'none'} />
<div className={styles.playButton}>
<Button
color="secondary"
Expand Down
15 changes: 13 additions & 2 deletions src/components/Video/__snapshots__/Video.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,20 @@ exports[`<Video> renders and matches snapshot 1`] = `
1970 • 5h 54m • Tester • CC_CC
</div>
<div
class="description"
class="collapsibleText"
>
Test item description
<div
class="dummyDiv"
style="max-height: none;"
>
Test item description
</div>
<div
class="textContainer description"
style="max-height: none;"
>
Test item description
</div>
</div>
<div
class="playButton"
Expand Down
1 change: 1 addition & 0 deletions src/containers/Shelf/Shelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ShelfProps = {
const Shelf = ({ playlistId, onCardClick, onCardHover, relatedMediaId, featured = false }: ShelfProps): JSX.Element => {
const { isLoading, error, data: playlist }: UsePlaylistResult = usePlaylist(playlistId, relatedMediaId);

if (!playlistId) return <p>No playlist</p>;
if (error) return <p>Error here {error}</p>;

return (
Expand Down
21 changes: 11 additions & 10 deletions src/containers/Video/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,25 @@ const Video = ({ playlistId, videoType, episodeId, mediaId }: VideoProps): JSX.E
const getSeriesItem = () => playlist?.playlist[0];
const item = videoType === 'movie' ? getMovieItem() : getSeriesItem();

const startPlay = () => (item ? history.push(videoUrl(item, playlistId, true)) : null);
const goBack = () => (item ? history.push(videoUrl(item, playlistId, false)) : null);
const startPlay = () => item && history.push(videoUrl(item, playlistId, true));
const goBack = () => item && history.push(videoUrl(item, playlistId, false));

const onCardClick = (playlistItem: PlaylistItem) =>
history.push(cardUrl(playlistItem, config.recommendationsPlaylist));
const onCardHover = (playlistItem: PlaylistItem) => updateBlurImage(playlistItem.image);
const onCardClick = (item: PlaylistItem) => history.push(cardUrl(item));
const onCardHover = (item: PlaylistItem) => updateBlurImage(item.image);

useEffect(() => {
if (item) updateBlurImage(item.image);
}, [item, updateBlurImage]);
useEffect(() => item && updateBlurImage(item.image), [item, updateBlurImage]);

//todo: series andere playlist
//todo: currently playing in recommended

//temp:
console.info({ episodeId });

if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading list</p>;
if (!playlist) return <p>List not found</p>;
if (!item) return <p>Can not find medium</p>;

console.info({ episodeId });

return (
<VideoComponent
item={item}
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/usePlaylist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const getPlaylistById = (playlistId: string, relatedMediaId?: string) => {
export type UsePlaylistResult<TData = Playlist, TError = unknown> = UseBaseQueryResult<TData, TError>;

export default function usePlaylist(playlistId: string, relatedMediaId?: string): UsePlaylistResult {
return useQuery(['playlist', playlistId], () => getPlaylistById(playlistId, relatedMediaId), {
return useQuery(['playlist', playlistId, relatedMediaId], () => getPlaylistById(playlistId, relatedMediaId), {
enabled: !!playlistId,
});
}
2 changes: 1 addition & 1 deletion src/utils/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const slugify = (text: string, whitespaceChar: string = '-') =>
.replace(/-/g, whitespaceChar);

const movieURL = (item: PlaylistItem, playlistId: string = '') =>
`/m/${item.mediaid}/${slugify(item.title)}?list=${playlistId}`;
`/m/${item.mediaid}/${slugify(item.title)}${playlistId ? `?list=${playlistId}` : ''}`;

const seriesURL = (item: PlaylistItem, playlistId: string = '') => `/s/${playlistId}/${slugify(item.title)}`;

Expand Down

0 comments on commit 405ec1f

Please sign in to comment.