Skip to content

Commit

Permalink
GIVCAMP-307 | Stacked story hero variant (#251)
Browse files Browse the repository at this point in the history
* Stacked story hero variant

* hero headline sizes

* Hero variant styles

* Stretch image to full width

* Optimize images; clean up

* Add fallback hero bg color before a proper value is entered
  • Loading branch information
yvonnetangsu authored Mar 19, 2024
1 parent a831dc9 commit cec029a
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 101 deletions.
81 changes: 38 additions & 43 deletions components/BlurryPoster/BlurryPoster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,42 +93,44 @@ export const BlurryPoster = ({

return (
<Container {...props} bgColor={bgColor} width="full" className={styles.root}>
<picture>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '1000x600' : '2000x1200', bgImageFocus)}
media="(min-width: 1200px)"
// Exact height and width don't matter as long as aspect ratio is the same as the image
width={2000}
height={1200}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '600x600' : '1200x1200', bgImageFocus)}
media="(min-width: 768px)"
width={1200}
height={1200}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '450x300' : '900x600', bgImageFocus)}
media="(min-width: 461px)"
width={900}
height={600}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '200x300' : '600x900', bgImageFocus)}
media="(max-width: 460px)"
width={600}
height={900}
/>
<img
src={getProcessedImage(bgImageSrc, addBgBlur ? '1000x600' : '2000x1200', bgImageFocus)}
alt={bgImageAlt || ''}
width={2000}
height={1200}
aria-describedby={hasCaption && !!bgImageAlt ? 'story-hero-caption' : undefined}
className={styles.bgImage}
fetchPriority={type === 'hero' ? 'high' : 'auto'}
/>
</picture>
{bgImageSrc && (
<picture>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '1000x600' : '2000x1200', bgImageFocus)}
media="(min-width: 1200px)"
// Exact height and width don't matter as long as aspect ratio is the same as the image
width={2000}
height={1200}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '600x600' : '1200x1200', bgImageFocus)}
media="(min-width: 768px)"
width={1200}
height={1200}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '450x300' : '900x600', bgImageFocus)}
media="(min-width: 461px)"
width={900}
height={600}
/>
<source
srcSet={getProcessedImage(bgImageSrc, addBgBlur ? '200x300' : '600x900', bgImageFocus)}
media="(max-width: 460px)"
width={600}
height={900}
/>
<img
src={getProcessedImage(bgImageSrc, addBgBlur ? '1000x600' : '2000x1200', bgImageFocus)}
alt={bgImageAlt || ''}
width={2000}
height={1200}
aria-describedby={hasCaption && !!bgImageAlt ? 'story-hero-caption' : undefined}
className={styles.bgImage}
fetchPriority={type === 'hero' ? 'high' : 'auto'}
/>
</picture>
)}
<div className={cnb(styles.blurWrapper(
addBgBlur,
!!darkOverlay && darkOverlay !== 'none', type, bgColor,
Expand Down Expand Up @@ -202,13 +204,6 @@ export const BlurryPoster = ({
{body}
</Paragraph>
)}
{/* No authors and published dates for MVP */}
{/* {byline && (
<Text>{byline}</Text>
)}
{date && (
<time dateTime={publishedDate}>{formattedDate}</time>
)} */}
{cta && (
<div className={styles.cta}>
{cta}
Expand Down
27 changes: 0 additions & 27 deletions components/Hero/StoryHeroMvp.styles.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,3 @@
import { cnb } from 'cnbuilder';

export const root = 'relative';

export const imageCrops = {
'1x1': '1200x1200',
'2x1': '2000x1000',
'3x2': '2100x1400',
'5x8': '1000x1600',
'16x9': '2000x1125',
'free': '2000x0',
};
export type ImageCropType = keyof typeof imageCrops;

export const mobileImageCrops = {
'1x1': '1000x1000',
'2x1': '1000x500',
'3x2': '1200x800',
'5x8': '1000x1600',
'16x9': '1600x900',
'free': '1000x0',
};

export const image = (renderTwoImages: boolean) => cnb(
'size-full',
renderTwoImages ? 'hidden lg:block' : '',
);
export const mobileImage = 'size-full lg:hidden';
export const captionWrapper = 'mt-06em';
export const caption = 'caption *:leading-display mt-08em max-w-prose-wide';
81 changes: 50 additions & 31 deletions components/Hero/StoryHeroMvp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { Container } from '@/components/Container';
import { BlurryPoster } from '@/components/BlurryPoster';
import { CreateBloks } from '@/components/CreateBloks';
import { RichText } from '@/components/RichText';
import { type SbImageType, type SbTypographyProps } from '@/components/Storyblok/Storyblok.types';
import { StoryHeroStacked } from '@/components/Hero/StoryHeroStacked';
import { type SbImageType, type SbTypographyProps, type SbColorPickerType } from '@/components/Storyblok/Storyblok.types';
import { type SbBlokData } from '@storyblok/react/rsc';
import { paletteAccentColors, type PaletteAccentHexColorType } from '@/utilities/colorPalettePlugin';
import { getNumBloks } from '@/utilities/getNumBloks';
import { hasRichText } from '@/utilities/hasRichText';
import{ type HeroOverlayType } from '@/utilities/datasource';
import { type HeroOverlayType } from '@/utilities/datasource';
import * as styles from './StoryHeroMvp.styles';

export type StoryHeroMvpProps = {
Expand All @@ -20,6 +21,8 @@ export type StoryHeroMvpProps = {
byline?: string;
publishedDate?: string;
dek?: string;
heroVariant?: 'default' | 'stacked';
heroBgColor?: SbColorPickerType;
heroImage?: SbImageType;
bgImage?: SbImageType;
bgImageAlt?: string;
Expand All @@ -46,6 +49,8 @@ export const StoryHeroMvp = ({
byline,
dek,
publishedDate,
heroVariant,
heroBgColor: { color: bgHexColor } = {},
heroImage: { filename, focus } = {},
bgImage: { filename: bgImageSrc, focus: bgImageFocus } = {},
bgImageAlt,
Expand All @@ -67,42 +72,56 @@ export const StoryHeroMvp = ({
day: 'numeric',
year: 'numeric',
});

const Caption = hasRichText(caption)
? <RichText textColor="black-70" wysiwyg={caption} className={styles.caption} />
: undefined;
const hasCaption = hasRichText(caption);
const Caption = hasCaption ? <RichText textColor="black-70" wysiwyg={caption} className={styles.caption} /> : undefined;

return (
<Container
as="header"
width="full"
className={styles.root}
>
<BlurryPoster
type="hero"
isTwoCol={useTwoColLayout}
heading={title}
superhead={superhead}
customHeading={customHeading}
headingLevel="h1"
headingFont={headingFont === 'druk' ? 'druk' : 'serif'}
isSmallHeading={isSmallHeading}
byline={byline}
publishedDate={formattedDate}
body={dek}
imageSrc={filename}
imageFocus={focus}
alt={alt}
bgImageSrc={bgImageSrc}
bgImageFocus={bgImageFocus}
bgImageAlt={bgImageAlt}
bgColor={isLightHero ? 'white' : 'black'}
addBgBlur={addBgBlur}
darkOverlay={darkOverlay}
imageOnLeft={isLeftImage}
tabColor={paletteAccentColors[tabColorValue]}
hasCaption={hasRichText(caption)}
/>
{heroVariant === 'stacked' ? (
<StoryHeroStacked
title={title}
superhead={superhead}
headingFont={headingFont}
isSmallHeading={isSmallHeading}
dek={dek}
heroBgColor={bgHexColor}
imageSrc={filename}
imageFocus={focus}
alt={alt}
isLightHero={isLightHero}
hasCaption={hasCaption}
/>
) : (
<BlurryPoster
type="hero"
isTwoCol={useTwoColLayout}
heading={title}
superhead={superhead}
customHeading={customHeading}
headingLevel="h1"
headingFont={headingFont === 'druk' ? 'druk' : 'serif'}
isSmallHeading={isSmallHeading}
byline={byline}
publishedDate={formattedDate}
body={dek}
imageSrc={filename}
imageFocus={focus}
alt={alt}
bgImageSrc={bgImageSrc}
bgImageFocus={bgImageFocus}
bgImageAlt={bgImageAlt}
bgColor={isLightHero ? 'white' : 'black'}
addBgBlur={addBgBlur}
darkOverlay={darkOverlay}
imageOnLeft={isLeftImage}
tabColor={paletteAccentColors[tabColorValue]}
hasCaption={hasCaption}
/>
)}
{!!getNumBloks(heroTexturedBar) && (
<CreateBloks blokSection={heroTexturedBar} />
)}
Expand Down
21 changes: 21 additions & 0 deletions components/Hero/StoryHeroStacked.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { cnb } from 'cnbuilder';

export const root = 'relative';

export const contentWrapper = 'mt-40 md:-mt-60 xl:mt-0';
export const superhead = (isLightHero: boolean) => cnb('cc mb-04em w-full', !isLightHero && 'text-shadow-sm');
export const heading = (
isSmallHeading?: boolean,
headingFont?: 'druk' | 'serif',
) => cnb('mb-0 text-balance mx-auto whitespace-pre-line', {
'fluid-type-7 max-w-1400': headingFont === 'druk',
'md:fluid-type-8': isSmallHeading && headingFont === 'druk',
'md:fluid-type-9': !isSmallHeading && headingFont === 'druk',
'fluid-type-5 md:fluid-type-7 max-w-1200': headingFont === 'serif',
'xl:fluid-type-8 ': headingFont === 'serif' && !isSmallHeading,
});
export const dek = 'max-w-900 text-balance mx-auto rs-mt-3';
export const image = 'rs-mt-4 w-full';
export const mobileImage = 'size-full lg:hidden';
export const captionWrapper = 'mt-06em';
export const caption = 'caption *:leading-display mt-08em max-w-prose-wide';
130 changes: 130 additions & 0 deletions components/Hero/StoryHeroStacked.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { AnimateInView } from '@/components/Animate';
import { Container } from '@/components/Container';
import {
Heading, Paragraph, Text, SrOnlyText,
} from '@/components/Typography';
import { getProcessedImage } from '@/utilities/getProcessedImage';
import { getSbImageSize } from '@/utilities/getSbImageSize';
import * as styles from './StoryHeroStacked.styles';

export type StoryHeroStackedProps = {
title: string;
superhead?: string;
headingFont?: 'serif' | 'druk';
isSmallHeading?: boolean;
dek?: string;
heroBgColor?: string; // Hex color value from Storyblok native color picker
imageSrc?: string;
imageFocus?: string;
alt?: string;
hasCaption?: boolean;
isLightHero?: boolean;
};

export const StoryHeroStacked = ({
title,
superhead,
headingFont,
isSmallHeading,
dek,
heroBgColor,
imageSrc,
imageFocus,
alt,
hasCaption,
isLightHero = false,
}: StoryHeroStackedProps) => {
// We keep the original image aspect ratio
const imageSize = getSbImageSize(imageSrc) || { width: 0, height: 0 };
const { width: imageWidth, height: imageHeight } = imageSize;

return (
<Container
width="full"
className={styles.root}
pt={10}
style={{ backgroundColor: heroBgColor || '#888' }}
>
<Container className={styles.contentWrapper}>
{superhead && (
<AnimateInView animation="slideUp">
<Text
size={1}
align="center"
color={isLightHero ? 'black' : 'white'}
// If there is a heading, superhead will be rendered as screen reader text as part of the heading
aria-hidden
className={styles.superhead(isLightHero)}
>
{superhead}
</Text>
</AnimateInView>
)}
{title && (
<AnimateInView animation="slideUp" delay={0.1}>
<Heading
as="h1"
align="center"
color={isLightHero ? 'black' : 'white'}
font={headingFont}
leading={headingFont === 'druk' ? 'druk' : 'tight'}
className={styles.heading(isSmallHeading, headingFont)}
>
{superhead && <SrOnlyText>{`${superhead}:`}</SrOnlyText>}{title}
</Heading>
</AnimateInView>
)}
{dek && (
<AnimateInView animation="slideUp" delay={0.2}>
<Paragraph
variant="overview"
weight="normal"
leading="display"
align="center"
className={styles.dek}
color={isLightHero ? 'black' : 'white'}
noMargin
>
{dek}
</Paragraph>
</AnimateInView>
)}
</Container>
{imageSrc && (
<AnimateInView animation="zoomSharpen" duration={1}>
<picture>
<source
srcSet={getProcessedImage(imageSrc, '2000x0', imageFocus)}
media="(min-width: 1500px)"
/>
<source
srcSet={getProcessedImage(imageSrc, '1500x0', imageFocus)}
media="(min-width: 1200px)"
/>
<source
srcSet={getProcessedImage(imageSrc, '1200x0', imageFocus)}
media="(min-width: 768px)"
/>
<source
srcSet={getProcessedImage(imageSrc, '800x0', imageFocus)}
media="(min-width: 576px)"
/>
<source
srcSet={getProcessedImage(imageSrc, '600x0', imageFocus)}
media="(max-width: 575px)"
/>
<img
src={getProcessedImage(imageSrc, '2000x0', imageFocus)}
alt={alt || ''}
aria-describedby={hasCaption ? 'story-hero-caption' : undefined}
fetchPriority="high"
width={imageWidth}
height={imageHeight}
className={styles.image}
/>
</picture>
</AnimateInView>
)}
</Container>
);
};
Loading

0 comments on commit cec029a

Please sign in to comment.