Feat/BOOK-257 videoplayer with card
* feat(BOOK-257): Added VideoPlayer with card component * feat(BOOK-257): Added queries and component for VideoCard block to Content and Collection pages * fix(BOOK-257): Only setting object-fit: cover on the video if it is not fullscreen * feat(BOOK-257): Added queries and component for VideoCard block to Startpage * feat(BOOK-257): Added queries and component for Video block to content/collection/start page Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
@@ -5,7 +5,7 @@ import { VideoPlayer } from '.'
|
||||
import { config as videoPlayerConfig } from './variants'
|
||||
|
||||
const meta: Meta<typeof VideoPlayer> = {
|
||||
title: 'Core Components/🚧 VideoPlayer 🚧',
|
||||
title: 'Core Components//🚧 Video 🚧/VideoPlayer',
|
||||
component: VideoPlayer,
|
||||
|
||||
parameters: {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { VariantProps } from 'class-variance-authority'
|
||||
import { Typography } from '../../Typography'
|
||||
import { variants } from './variants'
|
||||
|
||||
import { VideoPlayer, VideoPlayerProps } from '..'
|
||||
import styles from './videoWithCard.module.css'
|
||||
|
||||
interface TextCardProps {
|
||||
variant: 'text'
|
||||
heading: string
|
||||
text?: string
|
||||
}
|
||||
interface QuoteCardProps {
|
||||
variant: 'quote'
|
||||
quote: string
|
||||
author: string
|
||||
authorDescription?: string
|
||||
}
|
||||
|
||||
type VideoWithCardProps = VariantProps<typeof variants> &
|
||||
(TextCardProps | QuoteCardProps) & {
|
||||
video: Pick<VideoPlayerProps, 'src' | 'captions' | 'focalPoint'>
|
||||
}
|
||||
|
||||
export function VideoWithCard(props: VideoWithCardProps) {
|
||||
const { variant, style, video } = props
|
||||
const classNames = variants({
|
||||
variant,
|
||||
style,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.videoWithCardWrapper}>
|
||||
<div className={styles.videoWithCard}>
|
||||
<VideoPlayer variant="inline" {...video} />
|
||||
<article className={classNames}>
|
||||
<CardContent {...props} />
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContent(props: VideoWithCardProps) {
|
||||
if (props.variant === 'quote') {
|
||||
const { quote, author, authorDescription } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="Title/smLowCase">
|
||||
<blockquote className={styles.blockquote}>{quote}</blockquote>
|
||||
</Typography>
|
||||
|
||||
<cite className={styles.cite}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<span>{author}</span>
|
||||
</Typography>
|
||||
{authorDescription ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{authorDescription}</span>
|
||||
</Typography>
|
||||
) : null}
|
||||
</cite>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const { heading, text } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="Title/smLowCase">
|
||||
<h3 className={styles.heading}>{heading}</h3>
|
||||
</Typography>
|
||||
{text ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{text}</p>
|
||||
</Typography>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
||||
|
||||
import { VideoWithCard } from '.'
|
||||
import { config } from './variants'
|
||||
|
||||
const meta: Meta<typeof VideoWithCard> = {
|
||||
title: 'Core Components//🚧 Video 🚧//VideoWithCard',
|
||||
component: VideoWithCard,
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'A component to display a VideoPlayer and content inside a card connected to the video. The size and gaps are determined by the parent container.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: 'select',
|
||||
options: Object.keys(config.variants.variant),
|
||||
table: {
|
||||
defaultValue: {
|
||||
summary: config.defaultVariants.variant,
|
||||
},
|
||||
type: {
|
||||
summary: Object.keys(config.variants.variant).join(' | '),
|
||||
},
|
||||
},
|
||||
description:
|
||||
'The variant of the card, which determines its style of the text and what content is shown.',
|
||||
},
|
||||
style: {
|
||||
control: 'select',
|
||||
options: Object.keys(config.variants.style),
|
||||
table: {
|
||||
defaultValue: {
|
||||
summary: config.defaultVariants.style,
|
||||
},
|
||||
type: {
|
||||
summary: Object.keys(config.variants.style).join(' | '),
|
||||
},
|
||||
},
|
||||
description:
|
||||
'This decides the background color and text color of the card.',
|
||||
},
|
||||
heading: {
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
description: 'The heading text. Only applicable for the text variant.',
|
||||
},
|
||||
text: {
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
description: 'The body text. Only applicable for the text variant.',
|
||||
},
|
||||
quote: {
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
description: 'The quote text. Only applicable for the quote variant.',
|
||||
},
|
||||
author: {
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
description:
|
||||
'The author of the quote. Only applicable for the quote variant.',
|
||||
},
|
||||
authorDescription: {
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
description:
|
||||
'The description of the author. Only applicable for the quote variant.',
|
||||
},
|
||||
video: {
|
||||
control: false,
|
||||
table: {
|
||||
type: {
|
||||
summary:
|
||||
'{ src: string; captions?: Caption[]; focalPoint?: FocalPoint}',
|
||||
},
|
||||
},
|
||||
description:
|
||||
'The video props including source URL, captions and focal point. Please note that not all props from the VideoPlayer component are supported in this wrapper component.',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof VideoWithCard>
|
||||
|
||||
const videoProps = {
|
||||
src: 'https://eu-assets.contentstack.com/v3/assets/bltfd73aa2de3a5c4e3/bltad0fe3c2ce340947/68eced6c14e5a8150ebba18c/Scandic_EB_Master.mp4',
|
||||
}
|
||||
|
||||
const quoteCardProps = {
|
||||
variant: 'quote' as const,
|
||||
quote: 'Download our membership App for smoother & richer experience',
|
||||
author: 'Hans Christian Andersen',
|
||||
authorDescription: 'The famed Danish storyteller.',
|
||||
video: videoProps,
|
||||
}
|
||||
|
||||
const textCardProps = {
|
||||
variant: 'text' as const,
|
||||
heading: 'Download our membership App now',
|
||||
text: 'Hans Christian Andersen, the famed Danish storyteller, spent many years of his life in Nyhavn, drawing inspiration from its lively atmosphere and picturesque setting.',
|
||||
video: videoProps,
|
||||
}
|
||||
|
||||
const smallDecorator = (Story: React.FC) => (
|
||||
<div
|
||||
style={{
|
||||
width: '792px',
|
||||
paddingRight: '2rem',
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
|
||||
const largeDecorator = (Story: React.FC) => (
|
||||
<div
|
||||
style={{
|
||||
width: '1200px',
|
||||
paddingRight: '2rem',
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
|
||||
export const QuotePrimary1Small: Story = {
|
||||
args: {
|
||||
...quoteCardProps,
|
||||
style: 'primary-1',
|
||||
},
|
||||
decorators: [smallDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const QuotePrimary2Small: Story = {
|
||||
args: {
|
||||
...quoteCardProps,
|
||||
style: 'primary-2',
|
||||
},
|
||||
decorators: [smallDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const TextPrimary1Small: Story = {
|
||||
args: {
|
||||
...textCardProps,
|
||||
style: 'primary-1',
|
||||
},
|
||||
decorators: [smallDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const TextPrimary2Small: Story = {
|
||||
args: {
|
||||
...textCardProps,
|
||||
style: 'primary-2',
|
||||
},
|
||||
decorators: [smallDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const QuotePrimary1Large: Story = {
|
||||
args: {
|
||||
...quoteCardProps,
|
||||
style: 'primary-1',
|
||||
},
|
||||
decorators: [largeDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const QuotePrimary2Large: Story = {
|
||||
args: {
|
||||
...quoteCardProps,
|
||||
style: 'primary-2',
|
||||
},
|
||||
decorators: [largeDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const TextPrimary1Large: Story = {
|
||||
args: {
|
||||
...textCardProps,
|
||||
style: 'primary-1',
|
||||
},
|
||||
decorators: [largeDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
|
||||
export const TextPrimary2Large: Story = {
|
||||
args: {
|
||||
...textCardProps,
|
||||
style: 'primary-2',
|
||||
},
|
||||
decorators: [largeDecorator],
|
||||
render: (args) => <VideoWithCard {...args} />,
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { VariantProps } from 'class-variance-authority'
|
||||
import { Typography } from '../../Typography'
|
||||
import { variants } from './variants'
|
||||
|
||||
import { VideoPlayer, VideoPlayerProps } from '..'
|
||||
import styles from './videoWithCard.module.css'
|
||||
interface TextCardProps {
|
||||
variant: 'text'
|
||||
heading: string
|
||||
text?: string
|
||||
}
|
||||
interface QuoteCardProps {
|
||||
variant: 'quote'
|
||||
quote: string
|
||||
author: string
|
||||
authorDescription?: string
|
||||
}
|
||||
|
||||
type VideoWithCardProps = VariantProps<typeof variants> &
|
||||
(TextCardProps | QuoteCardProps) & {
|
||||
video: Pick<VideoPlayerProps, 'src' | 'captions' | 'focalPoint'>
|
||||
}
|
||||
|
||||
export function VideoWithCard(props: VideoWithCardProps) {
|
||||
const { variant, style, video } = props
|
||||
const classNames = variants({
|
||||
variant,
|
||||
style,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.videoWithCardWrapper}>
|
||||
<div className={styles.videoWithCard}>
|
||||
<VideoPlayer variant="inline" {...video} />
|
||||
<article className={classNames}>
|
||||
<CardContent {...props} />
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContent(props: VideoWithCardProps) {
|
||||
if (props.variant === 'quote') {
|
||||
const { quote, author, authorDescription } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="Title/smLowCase">
|
||||
<blockquote className={styles.blockquote}>{quote}</blockquote>
|
||||
</Typography>
|
||||
|
||||
<cite className={styles.cite}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<span>{author}</span>
|
||||
</Typography>
|
||||
{authorDescription ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{authorDescription}</span>
|
||||
</Typography>
|
||||
) : null}
|
||||
</cite>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const { heading, text } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="Title/smLowCase">
|
||||
<h3 className={styles.heading}>{heading}</h3>
|
||||
</Typography>
|
||||
{text ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{text}</p>
|
||||
</Typography>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { cva } from 'class-variance-authority'
|
||||
|
||||
import styles from './videoWithCard.module.css'
|
||||
|
||||
export const config = {
|
||||
variants: {
|
||||
variant: {
|
||||
text: styles['variant-text'],
|
||||
quote: styles['variant-quote'],
|
||||
},
|
||||
style: {
|
||||
'primary-1': styles['style-primary-1'],
|
||||
'primary-2': styles['style-primary-2'],
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
style: 'primary-1',
|
||||
variant: 'text',
|
||||
},
|
||||
} as const
|
||||
|
||||
export const variants = cva(styles.card, config)
|
||||
@@ -0,0 +1,84 @@
|
||||
.videoWithCardWrapper {
|
||||
width: 100%;
|
||||
container-type: inline-size;
|
||||
container-name: videoWithCardWrapper;
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.videoWithCard {
|
||||
grid-template-columns: 1fr auto;
|
||||
min-height: 261px;
|
||||
gap: var(--Space-x1);
|
||||
|
||||
.card {
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@container videoWithCardWrapper (min-width: 793px) {
|
||||
.videoWithCard {
|
||||
min-height: 445px;
|
||||
gap: var(--Space-x2);
|
||||
|
||||
.card {
|
||||
width: 391px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.videoWithCard {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
gap: var(--Space-x025);
|
||||
}
|
||||
|
||||
.card {
|
||||
display: grid;
|
||||
min-height: 200px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: var(--Space-x3) var(--Space-x4);
|
||||
align-content: center;
|
||||
border-radius: var(--Corner-radius-lg);
|
||||
|
||||
&.style-primary-1 {
|
||||
background: var(--Surface-Brand-Primary-1-Default);
|
||||
color: var(--Text-Brand-OnPrimary-1-Heading);
|
||||
}
|
||||
|
||||
&.style-primary-2 {
|
||||
background: var(--Surface-Brand-Primary-2-Default);
|
||||
color: var(--Text-Brand-OnPrimary-2-Default);
|
||||
|
||||
.heading {
|
||||
color: var(--Text-Brand-OnPrimary-2-Heading);
|
||||
}
|
||||
}
|
||||
|
||||
&.variant-quote {
|
||||
gap: var(--Space-x3);
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
gap: var(--Space-x4);
|
||||
}
|
||||
}
|
||||
|
||||
&.variant-text {
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
}
|
||||
|
||||
.blockquote {
|
||||
&::before {
|
||||
content: '“';
|
||||
}
|
||||
&::after {
|
||||
content: '”';
|
||||
}
|
||||
}
|
||||
|
||||
.cite {
|
||||
font-style: normal;
|
||||
display: grid;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ interface Caption {
|
||||
isDefault: boolean
|
||||
}
|
||||
|
||||
interface VideoPlayerProps extends VariantProps<typeof variants> {
|
||||
export interface VideoPlayerProps extends VariantProps<typeof variants> {
|
||||
src: string
|
||||
className?: string
|
||||
captions?: Caption[]
|
||||
|
||||
@@ -40,7 +40,10 @@
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
|
||||
&:not(:fullscreen) {
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.playButton {
|
||||
|
||||
Reference in New Issue
Block a user