diff --git a/components/BasicCard/BasicCard.tsx b/components/BasicCard/BasicCard.tsx index 012deeb6f..611493ecb 100644 --- a/components/BasicCard/BasicCard.tsx +++ b/components/BasicCard/BasicCard.tsx @@ -77,7 +77,6 @@ export const BasicCard = ({ body, ctaLink, filename, - alt, focus, aspectRatio = '1x1', visibleHorizontal, @@ -128,7 +127,6 @@ export const BasicCard = ({ {...props} bgColor={a11yBgColor} filename={filename} - alt={alt} focus={focus} visibleHorizontal={visibleHorizontal} visibleVertical={visibleVertical} diff --git a/components/CampaignCard/CampaignCard.tsx b/components/CampaignCard/CampaignCard.tsx index 5857662b0..652f56e9d 100644 --- a/components/CampaignCard/CampaignCard.tsx +++ b/components/CampaignCard/CampaignCard.tsx @@ -37,6 +37,7 @@ export const CampaignCard = ({ filename={filename} alt={alt} focus={focus} + imageSize="card" visibleHorizontal={visibleHorizontal} visibleVertical={visibleVertical} className={styles.image} diff --git a/components/EmbedVideo/EmbedVideo.styles.ts b/components/EmbedVideo/EmbedVideo.styles.ts index ca9c48b9c..3f4d1350e 100644 --- a/components/EmbedVideo/EmbedVideo.styles.ts +++ b/components/EmbedVideo/EmbedVideo.styles.ts @@ -1,5 +1,6 @@ export const videoAspectRatios = { '16x9': 'aspect-[16/9]', + '9x16': 'aspect-[9/16]', '4x3': 'aspect-[4/3]', '1x1': 'aspect-1', }; diff --git a/components/EmbedVideo/EmbedVideo.tsx b/components/EmbedVideo/EmbedVideo.tsx index ab796c1d9..9d11b84f8 100644 --- a/components/EmbedVideo/EmbedVideo.tsx +++ b/components/EmbedVideo/EmbedVideo.tsx @@ -39,21 +39,22 @@ export const EmbedVideo = ({ captionAlign={captionAlign} pt={pt} pb={pb} - childrenWrapperClass={styles.videoAspectRatios[aspectRatio]} {...props} > - {isClient && ( - - )} +
+ {isClient && ( + + )} +
); }; diff --git a/components/GallerySlideshow/Slide.tsx b/components/GallerySlideshow/Slide.tsx index c959c436b..f8fa1e928 100644 --- a/components/GallerySlideshow/Slide.tsx +++ b/components/GallerySlideshow/Slide.tsx @@ -33,6 +33,10 @@ export const Slide = ({
+ {alt diff --git a/components/Image/AspectRatioImage.tsx b/components/Image/AspectRatioImage.tsx index eebbeef76..1d7bf22be 100644 --- a/components/Image/AspectRatioImage.tsx +++ b/components/Image/AspectRatioImage.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; +import { getAspectRatioNumber } from '@/utilities/getAspectRatioNumber'; import { getProcessedImage } from '@/utilities/getProcessedImage'; import { getSbImageSize } from '@/utilities/getSbImageSize'; -import { getAspectRatioNumber } from '@/utilities/getAspectRatioNumber'; import { visiblePositionToFocus } from '@/utilities/visiblePositionToFocus'; import { type SbImageType } from '@/components/Storyblok/Storyblok.types'; import * as styles from './Image.styles'; @@ -12,17 +12,19 @@ export type AspectRatioImageProps = SbImageType & React.HTMLAttributes { @@ -36,35 +38,63 @@ export const AspectRatioImage = ({ return visiblePositionToFocus(originalWidth, originalHeight, visibleHorizontal, visibleVertical); }, [focus, originalWidth, originalHeight, visibleHorizontal, visibleVertical]); - const { cropHeight, cropWidth } = useMemo(() => { - const targetCropWidth = styles.aspectImageSizes[imageSize]; - - // E.g. '3x2' => 1.5 - const aspectRatioDecimal = getAspectRatioNumber(aspectRatio); - - const cropWidth = originalWidth > targetCropWidth ? targetCropWidth : originalWidth; - const cropHeight = Math.round(cropWidth / aspectRatioDecimal); - - return { cropWidth, cropHeight }; - }, [aspectRatio, imageSize, originalWidth]); - if (!filename) { return null; } - const processedImg = getProcessedImage(filename, `${cropWidth}x${cropHeight}`, imageFocus); + const aspectRatioNumber = getAspectRatioNumber(aspectRatio); + const desktopCropSize = styles.imageCropsDesktop[aspectRatio]; + const desktopCropWidth = parseInt(desktopCropSize.split('x')[0], 10); + + const largestWidth = imageSize ? styles.aspectImageSizes[imageSize] : desktopCropWidth; + const largestHeight = Math.round(largestWidth / aspectRatioNumber); + const largestCropString = `${largestWidth}x${largestHeight}`; return ( -
- {alt -
+ <> + {!imageSize ? ( + + {originalWidth >= desktopCropWidth && ( + + )} + + + + {alt + + ) : ( + {alt + )} + ); }; diff --git a/components/Image/FullWidthImage.tsx b/components/Image/FullWidthImage.tsx index 6ff3198c2..8e3a8886e 100644 --- a/components/Image/FullWidthImage.tsx +++ b/components/Image/FullWidthImage.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { cnb } from 'cnbuilder'; -import { getSbImageSize } from '@/utilities/getSbImageSize'; import { getImageSources } from '@/utilities/getImageSources'; +import { getSbImageSize } from '@/utilities/getSbImageSize'; import { type SbImageType } from '@/components/Storyblok/Storyblok.types'; import * as styles from './Image.styles'; @@ -9,6 +9,7 @@ export type FullWidthImageProps = SbImageType & React.HTMLAttributes { const { width: originalWidth, height: originalHeight } = getSbImageSize(filename); - // Get corresponding image sources for responsive images const imageSources = useMemo(() => { - return getImageSources(filename, originalWidth); - }, [originalWidth, filename]); + return getImageSources(filename); + }, [filename]); return (
- {imageSources.map(({ srcSet, media }, index) => ( + {imageSources.map(({ srcSet, media }) => ( ))} {alt ({ /** * StoryImage styles */ - -export const imageAspectRatios = { - '1x1': 'aspect-1', - '3x2': 'aspect-[3/2]', - '16x9': 'aspect-[16/9]', -}; -export type ImageAspectRatioType = keyof typeof imageAspectRatios; +export type ImageAspectRatioType = '1x1' | '1x2' | '2x1' | '2x3' | '3x2' | '3x4' | '4x3' | '5x8' | '8x5' | '9x16' | '10x3' | '16x9'; // 2XL and up >= 1500px export const imageCropsDesktop = { - '1x1': '2000x2000', + '1x1': '1400x1400', // We rarely have square or portrait images edge to edge so they can be smaller than the viewport size + '1x2': '1000x2000', + '2x1': '2000x1000', + '2x3': '1200x1800', '3x2': '2100x1400', + '3x4': '1500x2000', + '4x3': '2000x1500', + '5x8': '1000x1600', + '8x5': '2000x1250', + '9x16': '900x1600', + '10x3': '2000x600', '16x9': '2000x1125', - 'free': '2000x0', }; export type ImageCropType = keyof typeof imageCropsDesktop; // LG-XL - 992px - 1499px export const imageCropsSmallDesktop = { '1x1': '1000x1000', + '1x2': '1000x2000', + '2x1': '1500x750', + '2x3': '1200x1800', '3x2': '1500x1000', + '3x4': '1200x1600', + '4x3': '1600x1200', + '5x8': '1000x1600', + '8x5': '1600x1000', + '9x16': '900x1600', + '10x3': '1500x450', '16x9': '1600x900', - 'free': '1500x0', }; // SM-MD - 576px - 991px export const imageCropsTablet = { '1x1': '1000x1000', + '1x2': '1000x2000', + '2x1': '1000x500', + '2x3': '1000x1500', '3x2': '1000x667', + '3x4': '1000x1333', + '4x3': '1000x750', + '5x8': '1000x1600', + '8x5': '1000x625', + '9x16': '900x1600', + '10x3': '1000x300', '16x9': '1000x563', - 'free': '1000x0', }; // XS - up to 575px export const imageCropsMobile = { '1x1': '600x600', + '1x2': '600x1200', + '2x1': '600x300', + '2x3': '600x900', '3x2': '600x400', + '3x4': '600x800', + '4x3': '600x450', + '5x8': '600x960', + '8x5': '640x400', + '9x16': '630x1120', + '10x3': '600x180', '16x9': '640x360', - 'free': '600x0', }; export const image = 'size-full object-cover'; diff --git a/components/Image/StoryImage.tsx b/components/Image/StoryImage.tsx index 7faf334a1..03e133337 100644 --- a/components/Image/StoryImage.tsx +++ b/components/Image/StoryImage.tsx @@ -1,14 +1,15 @@ import { cnb } from 'cnbuilder'; -import { useMemo } from 'react'; +import { AspectRatioImage } from './AspectRatioImage'; +import { FullWidthImage } from './FullWidthImage'; import { MediaWrapper, type MediaWrapperProps } from '@/components/Media'; import { type LightPageBgColorType } from '@/utilities/datasource'; -import { getImageSources } from '@/utilities/getImageSources'; -import { getSbImageSize } from '@/utilities/getSbImageSize'; import * as styles from './Image.styles'; export type StoryImageProps = MediaWrapperProps & { imageSrc: string; + imageFocus?: string; alt?: string; + aspectRatio?: styles.ImageAspectRatioType | 'free'; visibleVertical?: styles.VisibleVerticalType; backgroundColor?: LightPageBgColorType; isCard?: boolean; @@ -16,7 +17,9 @@ export type StoryImageProps = MediaWrapperProps & { export const StoryImage = ({ imageSrc, + imageFocus, mediaWidth, + aspectRatio = 'free', alt, caption, captionAlign, @@ -27,12 +30,7 @@ export const StoryImage = ({ pb, ...props }: StoryImageProps) => { - const { width: originalWidth, height: originalHeight } = getSbImageSize(imageSrc); - - // Get corresponding image sources for responsive images - const imageSources = useMemo(() => { - return getImageSources(imageSrc, originalWidth); - }, [originalWidth, imageSrc]); + const hasAspectRatio = !!aspectRatio && aspectRatio !== 'free'; return ( {!!imageSrc && ( - - {imageSources.map(({ srcSet, media }, index ) => ( - + {hasAspectRatio ? ( + + ) : ( + - ))} - {alt - + )} + )} ); diff --git a/components/Media/MediaWrapper.styles.ts b/components/Media/MediaWrapper.styles.ts index 7abed5b4b..512b3165f 100644 --- a/components/Media/MediaWrapper.styles.ts +++ b/components/Media/MediaWrapper.styles.ts @@ -6,8 +6,8 @@ import { lightPageBgColors, type LightPageBgColorType } from '@/utilities/dataso export const storyImageWidths = { 'su-w-full': '', // This is labeled as the edge-to-edge option 'centered-container': '', - 'su-w-story': 'lg:basis-8/12', - 'su-w-inset': 'sm:basis-10/12 md:basis-8/12 lg:basis-7/12 xl:basis-6/12 2xl:basis-5/12', + 'su-w-story': 'lg:w-8/12', + 'su-w-inset': 'sm:w-10/12 md:w-8/12 lg:w-7/12 xl:w-6/12 2xl:w-5/12', 'fit-container': '', }; export type StoryImageWidthType = keyof typeof storyImageWidths; @@ -15,8 +15,8 @@ export type StoryImageWidthType = keyof typeof storyImageWidths; // Video Widths (from Storyblok) export const videoWidths = { site: 'w-full', - inset: 'sm:basis-10/12 md:basis-8/12 lg:basis-7/12 xl:basis-6/12', - story: 'lg:basis-8/12', + inset: 'sm:w-10/12 md:w-8/12 lg:w-7/12 xl:w-6/12', + story: 'lg:w-8/12', 'fit-parent': 'w-full', }; export type VideoWidthType = keyof typeof videoWidths; @@ -27,7 +27,7 @@ export const mediaWidths = { }; export type MediaWidthType = StoryImageWidthType | VideoWidthType; -export const root = 'relative flex'; +export const root = 'relative'; export const wrapper = 'mx-auto w-full'; // Caption component styles @@ -39,7 +39,7 @@ export const caption = ( captionAlign: TextAlignType, ) => cnb( '*:*:leading-display *:*:xl:leading-snug first:*:*:mt-0', - isCard ? 'rs-px-0 pt-08em rs-pb-2' : 'pt-06em', + isCard ? 'rs-px-0 pt-08em rs-pb-0' : 'pt-06em', lightPageBgColors[captionBgColor], { 'text-center mx-auto': captionAlign === 'center' || mediaWidth === 'su-w-full', diff --git a/components/Media/MediaWrapper.tsx b/components/Media/MediaWrapper.tsx index 0fd3dd5cb..f8082a6f7 100644 --- a/components/Media/MediaWrapper.tsx +++ b/components/Media/MediaWrapper.tsx @@ -40,9 +40,7 @@ export const MediaWrapper = ({ {...props} >
-
- {children} -
+ {children} {caption && ( hasLink && 'group-hocus-within:scale-105 will-change transition-transform *:w-full'; +export const image = (hasLink: boolean) => hasLink && 'group-hocus-within:scale-105 will-change-transform transition-transform w-full'; diff --git a/components/QuoteCard/QuoteCard.tsx b/components/QuoteCard/QuoteCard.tsx index 3995c2e13..33128cbac 100644 --- a/components/QuoteCard/QuoteCard.tsx +++ b/components/QuoteCard/QuoteCard.tsx @@ -56,7 +56,6 @@ export const QuoteCard = ({ quoteSource, filename, focus, - alt, visibleHorizontal = 'center', visibleVertical = 'top', borderColor, @@ -74,7 +73,6 @@ export const QuoteCard = ({ {...props} bgColor={bgColor} filename={filename} - alt={alt} focus={focus} visibleHorizontal={visibleHorizontal} visibleVertical={visibleVertical} diff --git a/components/Storyblok/PageHeader/HeaderFullWidthImage.tsx b/components/Storyblok/PageHeader/HeaderFullWidthImage.tsx index b22be6d29..850779b95 100644 --- a/components/Storyblok/PageHeader/HeaderFullWidthImage.tsx +++ b/components/Storyblok/PageHeader/HeaderFullWidthImage.tsx @@ -4,6 +4,7 @@ import { Heading } from '@/components/Typography'; import { FullWidthImage } from '@/components/Image/FullWidthImage'; import { RichText } from '@/components/RichText'; import { hasRichText } from '@/utilities/hasRichText'; +import { getProcessedImage } from '@/utilities/getProcessedImage'; import { type HeaderProps } from './Header.types'; type HeaderFullWidthImageProps = Partial; @@ -40,8 +41,8 @@ export const HeaderFullWidthImage = ({ {fullWidthImage} {logoFilename && ( {logoAlt} )} diff --git a/components/Storyblok/PageHeader/HeaderSmallImage.tsx b/components/Storyblok/PageHeader/HeaderSmallImage.tsx index 4011f5deb..6e3f9b67c 100644 --- a/components/Storyblok/PageHeader/HeaderSmallImage.tsx +++ b/components/Storyblok/PageHeader/HeaderSmallImage.tsx @@ -41,14 +41,16 @@ export const HeaderSmallImage = ({ )} aria-hidden="true" /> - +
+ +
)} diff --git a/components/Storyblok/SbBasicCard.tsx b/components/Storyblok/SbBasicCard.tsx index 6a8276c4c..e87390514 100644 --- a/components/Storyblok/SbBasicCard.tsx +++ b/components/Storyblok/SbBasicCard.tsx @@ -39,7 +39,7 @@ export const SbBasicCard = ({ blok }: SbBasicCardProps) => { headline, content, ctaLink, - image: { filename, alt, focus} = {}, + image: { filename, focus } = {}, showImage, imageAspectRatio = '1x1', visibleHorizontal = 'center', @@ -72,7 +72,6 @@ export const SbBasicCard = ({ blok }: SbBasicCardProps) => { body={RichTextContent} ctaLink={CtaLink} filename={showImage ? filename : ''} - alt={showImage ? alt : ''} focus={showImage ? focus : ''} aspectRatio={showImage ? imageAspectRatio : undefined} visibleHorizontal={showImage ? visibleHorizontal : undefined} diff --git a/components/Storyblok/SbCampaignPage/CampaignHero.tsx b/components/Storyblok/SbCampaignPage/CampaignHero.tsx index 594e3e13a..c2a165286 100644 --- a/components/Storyblok/SbCampaignPage/CampaignHero.tsx +++ b/components/Storyblok/SbCampaignPage/CampaignHero.tsx @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import { type SbBlokData } from '@storyblok/react/rsc'; import { CreateBloks } from '@/components/CreateBloks'; import { Heading, Paragraph } from '@/components/Typography'; @@ -7,10 +6,11 @@ import { FullWidthImage, type VisibleHorizontalType } from '@/components/Image'; import { getSbImageSize } from '@/utilities/getSbImageSize'; import { modTypeSizes, type ModTypeSizeTypes, type AllCardBgColorType } from '@/utilities/datasource'; import { type SbImageType } from '@/components/Storyblok/Storyblok.types'; -import { getImageSources } from '@/utilities/getImageSources'; +import { getProcessedImage } from '@/utilities/getProcessedImage'; import { getNumBloks } from '@/utilities/getNumBloks'; import * as styles from './SbCampaignPage.styles'; + type CampaignHeroProps = { title?: string; intro?: string; @@ -53,11 +53,11 @@ export const CampaignHero = ({ const isFullWidthImage = heroStyle !== 'left-image'; const isDarkContent = heroBgColor === 'white' || heroBgColor === 'fog-light'; - const { width: originalWidth, height: originalHeight } = getSbImageSize(logoFilename); - // Get corresponding image sources for responsive images - const logoImageSources = useMemo(() => { - return getImageSources(logoFilename, originalWidth); - }, [originalWidth, logoFilename]); + const { width: originalWidth, height: originalHeight } = logoFilename + ? getSbImageSize(logoFilename) + : { width: 0, height: 0 }; + // If the logo is wider than 430px, resize it to 430px otherwise keep original dimensions + const processedLogo = logoFilename ? getProcessedImage(logoFilename, originalWidth > 430 ? '430x0' : '') : ''; const full_width_image = !!filename ? ( @@ -80,23 +80,14 @@ export const CampaignHero = ({
{!!logoFilename && ( - - {logoImageSources.map(({ srcSet, media }, index) => ( - - ))} - {logoAlt - + {logoAlt )} { // Use all white text and links in the header if no color is chosen or if white is chosen const isWhiteHeader = headerColor !== 'su-text-black'; + const { width: logoWidth, height: logoHeight } = filename + ? getSbImageSize(filename) + : { width: 0, height: 0 }; return ( { {filename && ( 400 ? 400 : logoWidth}x0`)} alt={alt || 'Campaign logo'} + width={logoWidth} + height={logoHeight} className={styles.logoImage} /> diff --git a/components/Storyblok/SbInteriorPage.tsx b/components/Storyblok/SbInteriorPage.tsx index a8e13a996..3742a9fd1 100644 --- a/components/Storyblok/SbInteriorPage.tsx +++ b/components/Storyblok/SbInteriorPage.tsx @@ -75,6 +75,7 @@ export const SbInteriorPage = ({ blok, slug }: SbInteriorPageProps) => { const hasHeroImage = headerStyle === 'has-image' || headerStyle === 'full-width-image'; const hasContentMenu = !!getNumBloks(contentMenu); const showMobileContentMenu = hasContentMenu && layout === 'left-sidebar'; + const hasContactInfo = !!getNumBloks(contactInfo); return ( { {layout === 'left-sidebar' && ( )} {/* Main body content */} -
+
diff --git a/components/Storyblok/SbMegaMenu/SbMegaMenu.styles.ts b/components/Storyblok/SbMegaMenu/SbMegaMenu.styles.ts index 6fda39601..c522e3528 100644 --- a/components/Storyblok/SbMegaMenu/SbMegaMenu.styles.ts +++ b/components/Storyblok/SbMegaMenu/SbMegaMenu.styles.ts @@ -60,6 +60,6 @@ export const cardRoot = (backgroundColor: DarkBgColorType = 'digital-red') => cn export const cardImageWrapper = 'hidden lg:block overflow-hidden'; export const cardImage = 'group-hocus-within:scale-105 transition-transform'; export const cardContent = 'rs-px-2 rs-pt-2 rs-pb-3 group-hover:bg-black-true/40 group-focus-within:bg-black-true/40 transition-colors'; -export const cardHeading = 'rs-mb-1 type-3 lg:type-2'; -export const headingLink = 'stretched-link no-underline text-white hocus:text-white hocus:underline'; -export const cardCtaTextIcon = 'group-hocus-within:translate-x-02em'; +export const cardHeading = 'group-hocus-within:underline rs-mb-1 type-3 lg:type-2'; + +export const cta = 'rs-mt-1 stretched-link hocus:no-underline'; diff --git a/components/Storyblok/SbMegaMenu/SbMegaMenuCard.tsx b/components/Storyblok/SbMegaMenu/SbMegaMenuCard.tsx index b0e6beb55..2a69bf891 100644 --- a/components/Storyblok/SbMegaMenu/SbMegaMenuCard.tsx +++ b/components/Storyblok/SbMegaMenu/SbMegaMenuCard.tsx @@ -1,7 +1,7 @@ import { type SbBlokData, storyblokEditable } from '@storyblok/react/rsc'; import { AspectRatioImage } from '@/components/Image'; -import { SbLink } from '@/components/Storyblok/partials/SbLink'; -import { Heading, Paragraph } from '@/components/Typography'; +import { CtaLink } from '@/components/Cta'; +import { Heading } from '@/components/Typography'; import { type SbImageType, type SbLinkType } from '@/components/Storyblok/Storyblok.types'; import { type DarkBgColorType } from '@/utilities/datasource'; import * as styles from './SbMegaMenu.styles'; @@ -31,7 +31,6 @@ export const SbMegaMenuCard = ({ blok }: SbMegaMenuCardProps) => {
{ )}
{headline && ( - - - {headline} - + + {headline} )} {ctaText && ( - {ctaText} - + )}
diff --git a/components/Storyblok/SbQuoteCard.tsx b/components/Storyblok/SbQuoteCard.tsx index ca2e1f4db..ba4df52b3 100644 --- a/components/Storyblok/SbQuoteCard.tsx +++ b/components/Storyblok/SbQuoteCard.tsx @@ -29,7 +29,7 @@ export const SbQuoteCard = ({ blok }: SbQuoteCardProps) => { const { quoteText, quoteSource, - image: { filename, alt, focus} = {}, + image: { filename, focus } = {}, showImage, visibleHorizontal = 'center', visibleVertical = 'top', @@ -69,7 +69,6 @@ export const SbQuoteCard = ({ blok }: SbQuoteCardProps) => { quoteText={QuoteText} quoteSource={QuoteSource} filename={displayImage ? filename : ''} - alt={displayImage ? alt : ''} focus={displayImage ? focus : ''} visibleHorizontal={displayImage ? visibleHorizontal : undefined} visibleVertical={displayImage ? visibleVertical : undefined} diff --git a/components/Storyblok/SbStoryImage.tsx b/components/Storyblok/SbStoryImage.tsx index a19d19047..dac083f73 100644 --- a/components/Storyblok/SbStoryImage.tsx +++ b/components/Storyblok/SbStoryImage.tsx @@ -1,6 +1,6 @@ import { storyblokEditable, type SbBlokData } from '@storyblok/react/rsc'; import { type StoryblokRichtext } from 'storyblok-rich-text-react-renderer'; -import { StoryImage, type VisibleVerticalType } from '@/components/Image'; +import { StoryImage, type VisibleVerticalType, ImageAspectRatioType } from '@/components/Image'; import { StoryImageWidthType } from '@/components/Media'; import { RichText } from '@/components/RichText'; import { type TextAlignType } from '@/components/Typography'; @@ -12,6 +12,7 @@ type SbStoryImageProps = { blok: SbBlokData & { image: SbImageType; alt?: string; + aspectRatio?: ImageAspectRatioType | 'free'; imageWidth?: StoryImageWidthType; visibleVertical?: VisibleVerticalType; caption?: StoryblokRichtext; @@ -25,7 +26,8 @@ type SbStoryImageProps = { export const SbStoryImage = ({ blok: { - image: { filename, alt } = {}, + image: { filename, alt, focus } = {}, + aspectRatio, caption, captionAlign, isCard, @@ -37,6 +39,12 @@ export const SbStoryImage = ({ }, blok, }: SbStoryImageProps) => { + /** + * If user chooses the "Edge to edge" option (su-w-full), use the 10x3 aspect ratio for cropping + * Previously we didn't crop the image, but use a container height of 30vw to simulate the 10x3 ratio + * Cropping the image is better because the user can now set an image focus and it reduces the image size + */ + const effectiveAspectRatio = imageWidth === 'su-w-full' ? '10x3' : aspectRatio || 'free'; const Caption = hasRichText(caption) ? { superheadline, headline, link, - image: { filename, alt, focus } = {}, + image: { filename, focus } = {}, showImage, visibleHorizontal = 'center', visibleVertical = 'center', @@ -41,7 +41,6 @@ export const SbTileCard = ({ blok }: SbTileCardProps) => { headline={headline} link={link} filename={showImage ? filename : ''} - alt={showImage ? alt : ''} focus={showImage ? focus : ''} visibleHorizontal={showImage ? visibleHorizontal : undefined} visibleVertical={showImage ? visibleVertical : undefined} diff --git a/components/Storyblok/partials/PageLayout.tsx b/components/Storyblok/partials/PageLayout.tsx index 2aa621c61..bea6265b5 100644 --- a/components/Storyblok/partials/PageLayout.tsx +++ b/components/Storyblok/partials/PageLayout.tsx @@ -47,7 +47,7 @@ export const PageLayout = ({ oodCampaignHeader={oodCampaignHeader} slug={slug} /> -
+
{children} diff --git a/components/TileCard/TileCard.styles.ts b/components/TileCard/TileCard.styles.ts index de8692664..09e518009 100644 --- a/components/TileCard/TileCard.styles.ts +++ b/components/TileCard/TileCard.styles.ts @@ -2,12 +2,10 @@ import { cnb } from 'cnbuilder'; export const superhead = 'text-09em mb-16 md:max-lg:text-[.8em]'; -export const heading = 'fluid-type-2 md:max-lg:text-25'; - -export const link = 'group stretched-link font-semibold'; +export const link = 'group stretched-link font-semibold no-underline'; export const linkText = (hasDarkText: boolean) => cnb( - 'lg:leading-tight group-hocus:underline', + 'lg:leading-tight group-hocus:underline fluid-type-2 md:max-lg:text-25', hasDarkText ? 'group-hocus:text-digital-red' : 'group-hocus:text-white', ); diff --git a/components/TileCard/TileCard.tsx b/components/TileCard/TileCard.tsx index 6ebbadfc1..82ec228b8 100644 --- a/components/TileCard/TileCard.tsx +++ b/components/TileCard/TileCard.tsx @@ -22,46 +22,42 @@ const TileCardContent = ({ superheadline, headline, link, - headingLevel = 'h3', + headingLevel, }: TileCardContentProps) => { const isExternalLink = link?.linktype !== 'story'; return ( <> {superheadline && ( - {superheadline} - + )} - - - - {headline} - - - + + + {headline} + + ); }; @@ -73,7 +69,6 @@ export const TileCard = ({ headline, link, filename, - alt, focus, visibleHorizontal, visibleVertical, @@ -96,7 +91,6 @@ export const TileCard = ({ hasLink bgColor={a11yBgColor} filename={filename} - alt={alt} focus={focus} visibleHorizontal={visibleHorizontal} visibleVertical={visibleVertical} diff --git a/styles/tables.css b/styles/tables.css index c2c5e9e9f..92e9b910c 100644 --- a/styles/tables.css +++ b/styles/tables.css @@ -1,6 +1,6 @@ /* Table styles for Giving */ table:not(.life-income-gifts) tr { - @apply even:bg-fog-light; + @apply even:bg-fog-light odd:bg-white; } /* Wrapper styles that adds the horizontal scroll if the table is wider than the viewport */ diff --git a/utilities/getImageSources.ts b/utilities/getImageSources.ts index 792a4c50d..f2ea13b5c 100644 --- a/utilities/getImageSources.ts +++ b/utilities/getImageSources.ts @@ -1,4 +1,5 @@ import { getProcessedImage } from './getProcessedImage'; +import { getSbImageSize } from './getSbImageSize'; type ResponsiveBreakpointType = { cropWidth: number; @@ -11,34 +12,26 @@ type ImageSourceType = { }; // Default breakpoints for generating responsive images -const defaultResponsiveBreakpoints: ResponsiveBreakpointType[] = [ +const srcsetBreakpoints: ResponsiveBreakpointType[] = [ { cropWidth: 2000, minWidth: 1500 }, { cropWidth: 1500, minWidth: 1200 }, { cropWidth: 1200, minWidth: 992 }, - { cropWidth: 1000, minWidth: 768 }, - { cropWidth: 800, minWidth: 461 }, - { cropWidth: 460, minWidth: 0 }, // Mobile/smallest size + { cropWidth: 1000, minWidth: 576 }, + { cropWidth: 600, minWidth: 0 }, // Mobile/smallest size ]; /** * Generates responsive image sources for use with picture element * * @param filename - The image filename from Storyblok - * @param originalWidth - Original width of the image - * @param originalHeight - Original height of the image - * @param customBreakpoints - Optional custom breakpoints to override defaults * @returns Array of image sources with srcSet and media queries */ -export const getImageSources = ( - filename: string, - originalWidth: number, - customBreakpoints?: ResponsiveBreakpointType[], -): ImageSourceType[] => { +export const getImageSources = ( filename: string ): ImageSourceType[] => { const sources: ImageSourceType[] = []; - const breakpoints = customBreakpoints || defaultResponsiveBreakpoints; + const { width: originalWidth } = getSbImageSize(filename); // If the original image width is < 2000px, find out what breakpoint range it falls into - const largestBp = breakpoints.find(bp => originalWidth >= bp.minWidth && originalWidth < bp.cropWidth); + const largestBp = srcsetBreakpoints.find(bp => originalWidth >= bp.minWidth && originalWidth < bp.cropWidth); // If we found an appropriate breakpoint, insert the original image at that breakpoint // For example, if the original image is 1100px, it will be used for the min-width: 992px breakpoint @@ -50,9 +43,9 @@ export const getImageSources = ( } // Add all smaller sizes that are relevant - breakpoints + srcsetBreakpoints // First pass: always include the mobile size, and keep all the breakpoints with minWidth < the original image width - .filter(bp => bp.cropWidth < originalWidth || bp.cropWidth === 460) + .filter(bp => bp.cropWidth < originalWidth || bp.cropWidth === 600) // If the original image is wider than 2000px (no largestBp assigned), keep all the breakpoints from the first pass // Otherwise, keep only the breakpoints that are smaller than the largestBp .filter(bp => !largestBp || bp.minWidth < largestBp.minWidth)