From 167d59206b88cdd4f2985096d4c4b4c7e0f07735 Mon Sep 17 00:00:00 2001 From: Charlotte Emms <43961396+cemms1@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:46:22 +0100 Subject: [PATCH 1/8] Scaffold the small scrollable container (#12504) Co-authored-by: James Mockett Co-authored-by: Georges Lebreton Co-authored-by: Anna Beddow --- .../ScrollableSmallContainer.importable.tsx | 258 ++++++++++++++++++ .../ScrollableSmallContainer.stories.tsx | 35 +++ 2 files changed, 293 insertions(+) create mode 100644 dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx create mode 100644 dotcom-rendering/src/components/ScrollableSmallContainer.stories.tsx diff --git a/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx new file mode 100644 index 00000000000..9a8c462fee1 --- /dev/null +++ b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx @@ -0,0 +1,258 @@ +import { css } from '@emotion/react'; +import { from, space, until } from '@guardian/source/foundations'; +import { + Button, + Hide, + SvgChevronLeftSingle, + SvgChevronRightSingle, +} from '@guardian/source/react-components'; +import { useEffect, useRef /* useState */ } from 'react'; +import { palette } from '../palette'; +import type { + DCRContainerPalette, + DCRContainerType, + DCRFrontCard, +} from '../types/front'; +import { FrontCard } from './FrontCard'; + +type Props = { + trails: DCRFrontCard[]; + containerPalette?: DCRContainerPalette; + showAge?: boolean; + absoluteServerTimes?: boolean; + imageLoading: 'lazy' | 'eager'; + containerType: DCRContainerType; +}; + +const carouselStyles = css` + display: grid; + grid-auto-columns: 1fr; + grid-auto-flow: column; + overflow-x: auto; + overflow-y: hidden; + scroll-snap-type: x mandatory; + scroll-behavior: smooth; + overscroll-behavior-x: contain; + overscroll-behavior-y: auto; + scroll-padding-left: 10px; + /** + * Hide scrollbars + * See: https://stackoverflow.com/a/38994837 + */ + ::-webkit-scrollbar { + display: none; /* Safari and Chrome */ + } + scrollbar-width: none; /* Firefox */ + position: relative; +`; + +const itemStyles = css` + scroll-snap-align: start; + grid-area: span 1; + position: relative; + margin: ${space[3]}px 10px; + :first-child { + ${from.tablet} { + margin-left: 0px; + } + } +`; + +const verticalLineStyles = css` + :not(:last-child)::after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + right: -10px; + width: 1px; + background-color: ${palette('--card-border-top')}; + transform: translateX(-50%); + } +`; + +/** + * Generates CSS styles for a grid layout used in a carousel. + * + * @param {number} totalCards - The total number of cards in the carousel. + * @returns {string} - The CSS styles for the grid layout. + */ +const generateCarouselColumnStyles = (totalCards: number) => { + const peepingCardWidth = space[8]; + + return css` + ${until.tablet} { + grid-template-columns: repeat( + ${totalCards}, + calc((100% - ${peepingCardWidth}px)) + ); + } + + ${from.tablet} { + grid-template-columns: repeat(${totalCards}, 50%); + } + `; +}; + +/** + * This is an island - todo + * + */ +export const ScrollableSmallContainer = ({ + trails, + containerPalette, + containerType, + absoluteServerTimes, + imageLoading, + showAge, +}: Props) => { + const carouselRef = useRef(null); + const carouselLength = trails.length; + + // const [previousButtonState, setShowPreviousButton] = useState(false); + // const [nextButtonState, setShowNextButton] = useState(true); + + const scrollTo = (direction: 'left' | 'right') => { + if (!carouselRef.current) return; + + const cardWidth = + carouselRef.current.querySelector('li')?.offsetWidth ?? 0; + const offset = direction === 'left' ? -cardWidth : cardWidth; + carouselRef.current.scrollBy({ + left: offset, + behavior: 'smooth', + }); + }; + + /** + * TODO - should update the style of the navigation buttons based on the carousel's scroll position. + * + * This function checks the current scroll position of the carousel and sets the styles + * of the previous and next buttons accordingly. The previous button is disabled if the carousel + * is at the start, and the next button is disabled if the carousel is at the end. + */ + const updateButtonVisibilityOnScroll = () => { + const carouselElement = carouselRef.current; + if (!carouselElement) return; + + // const scrollLeft = carouselElement.scrollLeft; + // const maxScrollLeft = + // carouselElement.scrollWidth - carouselElement.clientWidth; + + // setShowPreviousButton(scrollLeft > 0); + // setShowNextButton(scrollLeft < maxScrollLeft); + }; + + useEffect(() => { + const carouselElement = carouselRef.current; + if (!carouselElement) return; + + carouselElement.addEventListener( + 'scroll', + updateButtonVisibilityOnScroll, + ); + + return () => { + carouselElement.removeEventListener( + 'scroll', + updateButtonVisibilityOnScroll, + ); + }; + }, []); + + return ( +
+
    + {trails.map((trail) => { + return ( +
  1. + +
  2. + ); + })} +
+ + {/** TODO - put these buttons on the top right of the container */} + + {carouselLength > 2 && ( + <> +
+
+ +
+
+ + )} +
+
+ ); +}; diff --git a/dotcom-rendering/src/components/ScrollableSmallContainer.stories.tsx b/dotcom-rendering/src/components/ScrollableSmallContainer.stories.tsx new file mode 100644 index 00000000000..b3e9b831130 --- /dev/null +++ b/dotcom-rendering/src/components/ScrollableSmallContainer.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { discussionApiUrl } from '../../fixtures/manual/discussionApiUrl'; +import { trails } from '../../fixtures/manual/highlights-trails'; +import { FrontSection } from './FrontSection'; +import { ScrollableSmallContainer } from './ScrollableSmallContainer.importable'; + +export default { + title: 'ScrollableSmallContainer', + component: ScrollableSmallContainer, + args: { + trails, + containerPalette: undefined, + showAge: true, + absoluteServerTimes: true, + imageLoading: 'eager', + containerType: 'scrollable/small', + }, +} as Meta; + +type Story = StoryObj; + +export const Default = {}; + +export const WithFrontSection = { + render: (args) => ( + + + + ), +} satisfies Story; From 7861eb595383666e027a55fc5350f8b31cc7386d Mon Sep 17 00:00:00 2001 From: Tom Forbes Date: Tue, 8 Oct 2024 11:23:08 +0100 Subject: [PATCH 2/8] Update to ticker with size prop (#12481) * Update to ticker with size prop * lock file --- dotcom-rendering/package.json | 2 +- .../designableBanner/DesignableBanner.tsx | 5 ++++- .../marketing/epics/ContributionsEpic.tsx | 5 ++++- pnpm-lock.yaml | 20 +++++++++---------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/dotcom-rendering/package.json b/dotcom-rendering/package.json index 66b07752f7d..c640608fabb 100644 --- a/dotcom-rendering/package.json +++ b/dotcom-rendering/package.json @@ -51,7 +51,7 @@ "@guardian/ophan-tracker-js": "2.2.5", "@guardian/shimport": "1.0.2", "@guardian/source": "8.0.0", - "@guardian/source-development-kitchen": "9.0.0", + "@guardian/source-development-kitchen": "11.0.0", "@guardian/support-dotcom-components": "2.9.1", "@guardian/tsconfig": "0.2.0", "@playwright/test": "1.45.3", diff --git a/dotcom-rendering/src/components/marketing/banners/designableBanner/DesignableBanner.tsx b/dotcom-rendering/src/components/marketing/banners/designableBanner/DesignableBanner.tsx index b39400d8e8e..469b98d9927 100644 --- a/dotcom-rendering/src/components/marketing/banners/designableBanner/DesignableBanner.tsx +++ b/dotcom-rendering/src/components/marketing/banners/designableBanner/DesignableBanner.tsx @@ -345,11 +345,14 @@ const DesignableBanner: ReactComponent = ({ templateSettings.tickerStylingSettings && ( )} diff --git a/dotcom-rendering/src/components/marketing/epics/ContributionsEpic.tsx b/dotcom-rendering/src/components/marketing/epics/ContributionsEpic.tsx index 7b9d25a3085..457a115267d 100644 --- a/dotcom-rendering/src/components/marketing/epics/ContributionsEpic.tsx +++ b/dotcom-rendering/src/components/marketing/epics/ContributionsEpic.tsx @@ -404,9 +404,12 @@ const ContributionsEpic: ReactComponent = ({ {tickerSettings?.tickerData && ( )} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3bacce86d5c..6b44528276e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -371,8 +371,8 @@ importers: specifier: 8.0.0 version: 8.0.0(@emotion/react@11.11.3)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@guardian/source-development-kitchen': - specifier: 9.0.0 - version: 9.0.0(@emotion/react@11.11.3)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) + specifier: 11.0.0 + version: 11.0.0(@emotion/react@11.11.3)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@guardian/support-dotcom-components': specifier: 2.9.1 version: 2.9.1(@guardian/libs@18.0.0)(zod@3.22.4) @@ -4574,13 +4574,13 @@ packages: tslib: 2.6.2 dev: false - /@guardian/source-development-kitchen@8.0.0(@emotion/react@11.11.3)(@guardian/libs@16.1.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): - resolution: {integrity: sha512-97Qcm9laquXen7GMOkQ2syvKlvY6VaAN3zalXnxEDHZiSgUhthWrVFJp2G5CsqP9c5lpl4RkUcF2PkYek8J2Jw==} + /@guardian/source-development-kitchen@11.0.0(@emotion/react@11.11.3)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): + resolution: {integrity: sha512-aMfC08bAEFnCsobX3D618WSFZ7J8SkgHWgEgyOwiZJD9Yq0HSd0hbOmBK5HnkcDBXuc51l0z2Q0svztOKO2TZg==} peerDependencies: '@emotion/react': ^11.11.3 - '@guardian/libs': ^18.0.0 + '@guardian/libs': ^19.0.0 '@guardian/source': ^8.0.0 - '@types/react': ^18.2.11 + '@types/react': ^18.2.79 react: ^18.2.0 tslib: ^2.6.2 typescript: ~5.5.2 @@ -4595,7 +4595,7 @@ packages: optional: true dependencies: '@emotion/react': 11.11.3(@types/react@18.3.1)(react@18.3.1) - '@guardian/libs': 16.1.0(tslib@2.6.2)(typescript@5.5.3) + '@guardian/libs': 18.0.0(tslib@2.6.2)(typescript@5.5.3) '@guardian/source': 8.0.0(@emotion/react@11.11.3)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@types/react': 18.3.1 react: 18.3.1 @@ -4603,8 +4603,8 @@ packages: typescript: 5.5.3 dev: false - /@guardian/source-development-kitchen@9.0.0(@emotion/react@11.11.3)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): - resolution: {integrity: sha512-7384llH2Q8eyWBd48ITY6TTis5YhhaOeEW6y7ziPNwlRmI1wP99hlxidXv9FxReiPcdTkQ2U+c0l5k2qdiRg1g==} + /@guardian/source-development-kitchen@8.0.0(@emotion/react@11.11.3)(@guardian/libs@16.1.0)(@guardian/source@8.0.0)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): + resolution: {integrity: sha512-97Qcm9laquXen7GMOkQ2syvKlvY6VaAN3zalXnxEDHZiSgUhthWrVFJp2G5CsqP9c5lpl4RkUcF2PkYek8J2Jw==} peerDependencies: '@emotion/react': ^11.11.3 '@guardian/libs': ^18.0.0 @@ -4624,7 +4624,7 @@ packages: optional: true dependencies: '@emotion/react': 11.11.3(@types/react@18.3.1)(react@18.3.1) - '@guardian/libs': 18.0.0(tslib@2.6.2)(typescript@5.5.3) + '@guardian/libs': 16.1.0(tslib@2.6.2)(typescript@5.5.3) '@guardian/source': 8.0.0(@emotion/react@11.11.3)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@types/react': 18.3.1 react: 18.3.1 From 7b63044b89d9dfedee5fd18fd90a507c1e337af2 Mon Sep 17 00:00:00 2001 From: Anna Beddow Date: Tue, 8 Oct 2024 12:34:16 +0100 Subject: [PATCH 3/8] Use large image size for default splash (#12506) --- dotcom-rendering/src/components/FlexibleGeneral.tsx | 8 +++++++- dotcom-rendering/src/components/FlexibleSpecial.tsx | 13 +++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/dotcom-rendering/src/components/FlexibleGeneral.tsx b/dotcom-rendering/src/components/FlexibleGeneral.tsx index 92dc1b4209c..2193c0d766b 100644 --- a/dotcom-rendering/src/components/FlexibleGeneral.tsx +++ b/dotcom-rendering/src/components/FlexibleGeneral.tsx @@ -70,6 +70,7 @@ type BoostedSplashProperties = { headlineSizeOnTablet: SmallHeadlineSize; imagePositionOnDesktop: ImagePositionType; imagePositionOnMobile: ImagePositionType; + imageSize: ImageSizeType; supportingContentAlignment: Alignment; }; @@ -89,6 +90,7 @@ const decideSplashCardProperties = ( headlineSizeOnTablet: 'tiny', imagePositionOnDesktop: 'right', imagePositionOnMobile: 'bottom', + imageSize: 'large', supportingContentAlignment: supportingContentLength >= 4 ? 'horizontal' : 'vertical', }; @@ -99,6 +101,7 @@ const decideSplashCardProperties = ( headlineSizeOnTablet: 'small', imagePositionOnDesktop: 'right', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: supportingContentLength >= 4 ? 'horizontal' : 'vertical', }; @@ -109,6 +112,7 @@ const decideSplashCardProperties = ( headlineSizeOnTablet: 'medium', imagePositionOnDesktop: 'bottom', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: 'horizontal', }; case 'gigaboost': @@ -118,6 +122,7 @@ const decideSplashCardProperties = ( headlineSizeOnTablet: 'medium', imagePositionOnDesktop: 'bottom', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: 'horizontal', }; } @@ -145,6 +150,7 @@ export const SplashCardLayout = ({ headlineSizeOnTablet, imagePositionOnDesktop, imagePositionOnMobile, + imageSize, supportingContentAlignment, } = decideSplashCardProperties( card.boostLevel ?? 'default', @@ -165,7 +171,7 @@ export const SplashCardLayout = ({ headlineSizeOnTablet={headlineSizeOnTablet} imagePositionOnDesktop={imagePositionOnDesktop} imagePositionOnMobile={imagePositionOnMobile} - imageSize="jumbo" + imageSize={imageSize} trailText={card.trailText} supportingContent={card.supportingContent} supportingContentAlignment={supportingContentAlignment} diff --git a/dotcom-rendering/src/components/FlexibleSpecial.tsx b/dotcom-rendering/src/components/FlexibleSpecial.tsx index 9f1d119d715..f7d60a4d2fd 100644 --- a/dotcom-rendering/src/components/FlexibleSpecial.tsx +++ b/dotcom-rendering/src/components/FlexibleSpecial.tsx @@ -4,7 +4,10 @@ import type { DCRFrontCard, DCRGroupedTrails, } from '../types/front'; -import type { ImagePositionType } from './Card/components/ImageWrapper'; +import type { + ImagePositionType, + ImageSizeType, +} from './Card/components/ImageWrapper'; import { LI } from './Card/components/LI'; import { UL } from './Card/components/UL'; import type { Loading } from './CardPicture'; @@ -25,6 +28,7 @@ type BoostProperties = { headlineSizeOnTablet: SmallHeadlineSize; imagePositionOnDesktop: ImagePositionType; imagePositionOnMobile: ImagePositionType; + imageSize: ImageSizeType; supportingContentAlignment: Alignment; }; @@ -44,6 +48,7 @@ const determineCardProperties = ( headlineSizeOnTablet: 'small', imagePositionOnDesktop: 'right', imagePositionOnMobile: 'bottom', + imageSize: 'large', supportingContentAlignment: supportingContentLength >= 3 ? 'horizontal' : 'vertical', }; @@ -54,6 +59,7 @@ const determineCardProperties = ( headlineSizeOnTablet: 'medium', imagePositionOnDesktop: 'right', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: supportingContentLength >= 3 ? 'horizontal' : 'vertical', }; @@ -64,6 +70,7 @@ const determineCardProperties = ( headlineSizeOnTablet: 'medium', imagePositionOnDesktop: 'bottom', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: 'horizontal', }; case 'gigaboost': @@ -73,6 +80,7 @@ const determineCardProperties = ( headlineSizeOnTablet: 'large', imagePositionOnDesktop: 'bottom', imagePositionOnMobile: 'bottom', + imageSize: 'jumbo', supportingContentAlignment: 'horizontal', }; } @@ -99,6 +107,7 @@ export const OneCardLayout = ({ headlineSizeOnTablet, imagePositionOnDesktop, imagePositionOnMobile, + imageSize, supportingContentAlignment, } = determineCardProperties( card.boostLevel ?? 'default', @@ -118,7 +127,7 @@ export const OneCardLayout = ({ headlineSizeOnTablet={headlineSizeOnTablet} imagePositionOnDesktop={imagePositionOnDesktop} imagePositionOnMobile={imagePositionOnMobile} - imageSize="jumbo" + imageSize={imageSize} trailText={card.trailText} supportingContent={card.supportingContent} supportingContentAlignment={supportingContentAlignment} From 84ef849b214593d8a06344577fa80b7b0777bace Mon Sep 17 00:00:00 2001 From: Anna Beddow Date: Tue, 8 Oct 2024 15:37:53 +0100 Subject: [PATCH 4/8] Set supporting content positioning (#12512) --- dotcom-rendering/src/components/Card/Card.tsx | 3 +-- dotcom-rendering/src/components/FlexibleGeneral.tsx | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dotcom-rendering/src/components/Card/Card.tsx b/dotcom-rendering/src/components/Card/Card.tsx index 43a642eb08f..e475f77affb 100644 --- a/dotcom-rendering/src/components/Card/Card.tsx +++ b/dotcom-rendering/src/components/Card/Card.tsx @@ -759,8 +759,7 @@ export const Card = ({ )} {sublinkPosition === 'outer' && supportingContentAlignment === 'horizontal' && - (imagePositionOnDesktop === 'right' || - imagePositionOnDesktop === 'left') && ( + imagePositionOnDesktop === 'right' && ( )} diff --git a/dotcom-rendering/src/components/FlexibleGeneral.tsx b/dotcom-rendering/src/components/FlexibleGeneral.tsx index 2193c0d766b..0a112d1af4d 100644 --- a/dotcom-rendering/src/components/FlexibleGeneral.tsx +++ b/dotcom-rendering/src/components/FlexibleGeneral.tsx @@ -304,6 +304,7 @@ export const StandardCardLayout = ({ imageLoading={imageLoading} imagePositionOnDesktop={'left'} supportingContent={card.supportingContent} + supportingContentAlignment="horizontal" imageSize={'medium'} aspectRatio="5:4" kickerText={card.kickerText} From f01e1c90496f056694c85b9bbda5c7d1b86c4646 Mon Sep 17 00:00:00 2001 From: Anna Beddow Date: Tue, 8 Oct 2024 15:38:36 +0100 Subject: [PATCH 5/8] Update dividing lines so they're full width horizontal and card height vertical (#12510) --- dotcom-rendering/src/components/Card/Card.tsx | 4 ++-- dotcom-rendering/src/components/FlexibleGeneral.tsx | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dotcom-rendering/src/components/Card/Card.tsx b/dotcom-rendering/src/components/Card/Card.tsx index e475f77affb..d290e5e781b 100644 --- a/dotcom-rendering/src/components/Card/Card.tsx +++ b/dotcom-rendering/src/components/Card/Card.tsx @@ -454,8 +454,8 @@ export const Card = ({ return ( diff --git a/dotcom-rendering/src/components/FlexibleGeneral.tsx b/dotcom-rendering/src/components/FlexibleGeneral.tsx index 0a112d1af4d..549dc9217db 100644 --- a/dotcom-rendering/src/components/FlexibleGeneral.tsx +++ b/dotcom-rendering/src/components/FlexibleGeneral.tsx @@ -242,7 +242,7 @@ export const BoostedCardLayout = ({ imageSize, } = decideCardProperties(card.boostLevel); return ( -
    +
    • { return ( -
        +
          {cards.map((card, cardIndex) => { return (
        • Date: Tue, 8 Oct 2024 18:28:10 +0100 Subject: [PATCH 6/8] @guardian/commercial@22.3.0 --- dotcom-rendering/package.json | 2 +- pnpm-lock.yaml | 65 +++++++++++++++-------------------- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/dotcom-rendering/package.json b/dotcom-rendering/package.json index c640608fabb..4d66c095252 100644 --- a/dotcom-rendering/package.json +++ b/dotcom-rendering/package.json @@ -41,7 +41,7 @@ "@guardian/bridget": "7.0.0", "@guardian/browserslist-config": "6.1.0", "@guardian/cdk": "50.13.0", - "@guardian/commercial": "22.1.0", + "@guardian/commercial": "22.3.0", "@guardian/core-web-vitals": "7.0.0", "@guardian/eslint-config": "7.0.1", "@guardian/eslint-config-typescript": "9.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b44528276e..185a1e5b41e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -341,8 +341,8 @@ importers: specifier: 50.13.0 version: 50.13.0(@swc/core@1.7.26)(@types/node@20.14.10)(aws-cdk-lib@2.100.0)(aws-cdk@2.100.0)(constructs@10.3.0)(typescript@5.5.3) '@guardian/commercial': - specifier: 22.1.0 - version: 22.1.0(@guardian/ab-core@8.0.0)(@guardian/core-web-vitals@7.0.0)(@guardian/identity-auth-frontend@4.0.0)(@guardian/identity-auth@2.1.0)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(react-dom@18.3.1)(react@18.3.1)(typescript@5.5.3) + specifier: 22.3.0 + version: 22.3.0(@guardian/ab-core@8.0.0)(@guardian/core-web-vitals@7.0.0)(@guardian/identity-auth-frontend@4.0.0)(@guardian/identity-auth@2.1.0)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(react-dom@18.3.1)(react@18.3.1)(typescript@5.5.3) '@guardian/core-web-vitals': specifier: 7.0.0 version: 7.0.0(@guardian/libs@18.0.0)(tslib@2.6.2)(typescript@5.5.3)(web-vitals@4.2.3) @@ -4166,8 +4166,8 @@ packages: - typescript dev: false - /@guardian/commercial@22.1.0(@guardian/ab-core@8.0.0)(@guardian/core-web-vitals@7.0.0)(@guardian/identity-auth-frontend@4.0.0)(@guardian/identity-auth@2.1.0)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(react-dom@18.3.1)(react@18.3.1)(typescript@5.5.3): - resolution: {integrity: sha512-DVbSyaFm0dXOShYWIdmWSCPbWg5ufjoohL8Opx3TzQyIHsIANJl+rMsmuYGP+aRnxoaTjDIHeZCLPalT1x68Lw==} + /@guardian/commercial@22.3.0(@guardian/ab-core@8.0.0)(@guardian/core-web-vitals@7.0.0)(@guardian/identity-auth-frontend@4.0.0)(@guardian/identity-auth@2.1.0)(@guardian/libs@18.0.0)(@guardian/source@8.0.0)(react-dom@18.3.1)(react@18.3.1)(typescript@5.5.3): + resolution: {integrity: sha512-59fbogstd5vA1WAwRvcEXVkL2O/UCFeKP+veVNXiRqsOkMACZst9SK5KIX1dQKPLczcHcbYe+6MQRmbDbid9zg==} peerDependencies: '@guardian/ab-core': ^8.0.0 '@guardian/core-web-vitals': ^7.0.0 @@ -4183,13 +4183,12 @@ packages: '@guardian/identity-auth': 2.1.0(@guardian/libs@18.0.0)(tslib@2.6.2)(typescript@5.5.3) '@guardian/identity-auth-frontend': 4.0.0(@guardian/identity-auth@2.1.0)(@guardian/libs@18.0.0)(tslib@2.6.2)(typescript@5.5.3) '@guardian/libs': 18.0.0(tslib@2.6.2)(typescript@5.5.3) - '@guardian/prebid.js': 8.52.0-4(react-dom@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) + '@guardian/prebid.js': 8.52.0-6(react-dom@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@guardian/source': 8.0.0(@emotion/react@11.11.3)(@types/react@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3) '@octokit/core': 6.1.2 fastdom: 1.0.12 lodash-es: 4.17.21 process: 0.11.10 - raven-js: 3.27.2 tslib: 2.6.2 typescript: 5.5.3 web-vitals: 4.2.3 @@ -4343,7 +4342,7 @@ packages: '@typescript-eslint/parser': 6.18.0(eslint@8.56.0)(typescript@5.5.3) eslint: 8.56.0 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.18.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) tslib: 2.6.2 typescript: 5.5.3 transitivePeerDependencies: @@ -4471,8 +4470,8 @@ packages: '@guardian/tsconfig': 1.0.0 dev: false - /@guardian/prebid.js@8.52.0-4(react-dom@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): - resolution: {integrity: sha512-rshCk2zJKdgCNMiqNy/d50SsZne/CFf8VQqQ3que5Hln5cxufOE5dEHIfmVKjqDeffKX5WEbsa3gVCtNx+sZaQ==} + /@guardian/prebid.js@8.52.0-6(react-dom@18.3.1)(react@18.3.1)(tslib@2.6.2)(typescript@5.5.3): + resolution: {integrity: sha512-YBsPkX5XxHSVNWw1PDX4c6WArH7e5FOomFM59QVIDuWNqrI2vyORvN7df2JukiDvCBxVggGUc1n77Lub2jstZw==} engines: {node: '>=12.0.0'} dependencies: '@babel/core': 7.25.2 @@ -4481,7 +4480,7 @@ packages: '@babel/register': 7.24.6(@babel/core@7.25.2) '@babel/runtime': 7.25.6 '@guardian/libs': 18.0.0(tslib@2.6.2)(typescript@5.5.3) - core-js: 3.38.1 + core-js: 3.33.3 core-js-pure: 3.38.1 criteo-direct-rsa-validate: 1.1.0 crypto-js: 4.2.0 @@ -6551,7 +6550,7 @@ packages: react-docgen-typescript: 2.2.2(typescript@5.5.3) tslib: 2.6.2 typescript: 5.5.3 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color dev: false @@ -8165,8 +8164,8 @@ packages: webpack: 5.x.x webpack-cli: 5.x.x dependencies: - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.94.0) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@5.0.4)(webpack@5.94.0) dev: false /@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.94.0): @@ -8176,8 +8175,8 @@ packages: webpack: 5.x.x webpack-cli: 5.x.x dependencies: - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.94.0) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@5.0.4)(webpack@5.94.0) dev: false /@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.0.4)(webpack@5.94.0): @@ -8191,8 +8190,8 @@ packages: webpack-dev-server: optional: true dependencies: - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.94.0) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@5.0.4)(webpack@5.94.0) webpack-dev-server: 5.0.4(webpack-cli@5.1.4)(webpack@5.94.0) dev: false @@ -8735,7 +8734,7 @@ packages: '@babel/core': 7.25.2 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /babel-plugin-istanbul@6.1.1: @@ -9773,11 +9772,6 @@ packages: requiresBuild: true dev: false - /core-js@3.38.1: - resolution: {integrity: sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==} - requiresBuild: true - dev: false - /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: false @@ -9936,7 +9930,7 @@ packages: postcss-modules-values: 4.0.0(postcss@8.4.41) postcss-value-parser: 4.2.0 semver: 7.5.4 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /css-loader@7.1.2(webpack@5.94.0): @@ -10895,7 +10889,7 @@ packages: enhanced-resolve: 5.17.0 eslint: 8.56.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.15.1 @@ -11926,7 +11920,7 @@ packages: semver: 7.5.4 tapable: 2.2.1 typescript: 5.5.3 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /form-data@3.0.1: @@ -16152,11 +16146,6 @@ packages: engines: {node: '>= 0.6'} dev: false - /raven-js@3.27.2: - resolution: {integrity: sha512-mFWQcXnhRFEQe5HeFroPaEghlnqy7F5E2J3Fsab189ondqUzcjwSVi7el7F36cr6PvQYXoZ1P2F5CSF2/azeMQ==} - deprecated: Please upgrade to @sentry/browser. See the migration guide https://bit.ly/3ybOlo7 - dev: false - /raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} @@ -17436,7 +17425,7 @@ packages: peerDependencies: webpack: ^5.0.0 dependencies: - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /stylelint-config-recommended@14.0.0(stylelint@16.5.0): @@ -17969,7 +17958,7 @@ packages: semver: 7.5.4 source-map: 0.7.4 typescript: 5.5.3 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /ts-node@10.9.2(@swc/core@1.7.26)(@types/node@16.18.68)(typescript@5.1.6): @@ -18754,7 +18743,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /webpack-dev-middleware@7.2.1(webpack@5.94.0): @@ -18772,7 +18761,7 @@ packages: on-finished: 2.4.1 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) dev: false /webpack-dev-middleware@7.4.2(webpack@5.94.0): @@ -18834,8 +18823,8 @@ packages: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.94.0) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@5.0.4)(webpack@5.94.0) webpack-dev-middleware: 7.2.1(webpack@5.94.0) ws: 8.17.1 transitivePeerDependencies: @@ -18880,7 +18869,7 @@ packages: webpack: ^5.47.0 dependencies: tapable: 2.2.1 - webpack: 5.94.0(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26)(esbuild@0.18.20)(webpack-cli@5.1.4) webpack-sources: 2.3.1 dev: false patched: true From 00f32f7646176fed5a27bfc6b6680c43f1ab0db9 Mon Sep 17 00:00:00 2001 From: James Mockett <1166188+jamesmockett@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:55:26 +0100 Subject: [PATCH 7/8] Small story carousel 'chevron' button positioning (#12515) * Add basic button layout styles * Align navigation buttons with title at tablet breakpoint * Pull navigation buttons out of container at `wide` breakpoint --- .../ScrollableSmallContainer.importable.tsx | 74 ++++++++++++++----- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx index 9a8c462fee1..dcf234c6267 100644 --- a/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx +++ b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx @@ -1,5 +1,10 @@ import { css } from '@emotion/react'; -import { from, space, until } from '@guardian/source/foundations'; +import { + from, + headlineMedium24Object, + space, + until, +} from '@guardian/source/foundations'; import { Button, Hide, @@ -24,6 +29,27 @@ type Props = { containerType: DCRContainerType; }; +/** + * This needs to match the `FrontSection` title font and is used to calculate + * the negative margin that aligns the navigation buttons with the title. + */ +const titlePreset = headlineMedium24Object; + +/** + * Grid sizing to calculate negative margin used to pull navigation buttons + * out side of `FrontSection` container at `wide` breakpoint. + */ +const gridColumnWidth = '60px'; +const gridGap = '20px'; + +const carouselContainerStyles = css` + display: flex; + flex-direction: column-reverse; + ${from.wide} { + flex-direction: row; + } +`; + const carouselStyles = css` display: grid; grid-auto-columns: 1fr; @@ -51,11 +77,6 @@ const itemStyles = css` grid-area: span 1; position: relative; margin: ${space[3]}px 10px; - :first-child { - ${from.tablet} { - margin-left: 0px; - } - } `; const verticalLineStyles = css` @@ -71,6 +92,28 @@ const verticalLineStyles = css` } `; +const buttonContainerStyles = css` + margin-left: auto; + ${from.tablet} { + margin-top: calc( + (-${titlePreset.fontSize} * ${titlePreset.lineHeight}) - + ${space[3]}px + ); + } + ${from.leftCol} { + margin-top: 0; + } + ${from.wide} { + margin-left: ${space[2]}px; + margin-right: calc(${space[2]}px - ${gridColumnWidth} - ${gridGap}); + } +`; + +const buttonLayoutStyles = css` + display: flex; + gap: ${space[1]}px; +`; + /** * Generates CSS styles for a grid layout used in a carousel. * @@ -161,7 +204,7 @@ export const ScrollableSmallContainer = ({ }, []); return ( -
          +
            - {/** TODO - put these buttons on the top right of the container */} - - {carouselLength > 2 && ( - <> -
            +
            + + {carouselLength > 2 && ( +
            -
            - - )} -
            + )} + +
            ); }; From 4f75a0dbaf5a5dd756b1e8a1bb0aafa542e398a3 Mon Sep 17 00:00:00 2001 From: Charlotte Emms <43961396+cemms1@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:11:30 +0100 Subject: [PATCH 8/8] Control top bar visibility on cards via props rather than container context (#12514) --- .../src/components/Card/Card.stories.tsx | 2 ++ dotcom-rendering/src/components/Card/Card.tsx | 8 ++++++-- .../components/Card/components/CardWrapper.tsx | 16 ++++++++-------- .../src/components/Carousel.importable.tsx | 2 ++ .../src/components/FlexibleGeneral.tsx | 6 ++++++ .../src/components/FlexibleSpecial.tsx | 4 ++++ .../ScrollableSmallContainer.importable.tsx | 3 ++- 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/dotcom-rendering/src/components/Card/Card.stories.tsx b/dotcom-rendering/src/components/Card/Card.stories.tsx index 39c97f8ea07..95479e56bde 100644 --- a/dotcom-rendering/src/components/Card/Card.stories.tsx +++ b/dotcom-rendering/src/components/Card/Card.stories.tsx @@ -1575,6 +1575,8 @@ export const WithALargeGap = () => { design: ArticleDesign.Comment, theme: Pillar.Opinion, }} + showTopBarDesktop={false} + showTopBarMobile={true} />
          diff --git a/dotcom-rendering/src/components/Card/Card.tsx b/dotcom-rendering/src/components/Card/Card.tsx index d290e5e781b..71b23cc5155 100644 --- a/dotcom-rendering/src/components/Card/Card.tsx +++ b/dotcom-rendering/src/components/Card/Card.tsx @@ -116,6 +116,8 @@ export type Props = { index?: number; /** The Splash card in a flexible container gets a different visual treatment to other cards*/ isFlexSplash?: boolean; + showTopBarDesktop?: boolean; + showTopBarMobile?: boolean; }; const starWrapper = (cardHasImage: boolean) => css` @@ -268,6 +270,8 @@ export const Card = ({ boostedFontSizes, index = 0, isFlexSplash, + showTopBarDesktop = true, + showTopBarMobile = false, }: Props) => { const hasSublinks = supportingContent && supportingContent.length > 0; const sublinkPosition = decideSublinkPosition( @@ -454,8 +458,8 @@ export const Card = ({ return ( diff --git a/dotcom-rendering/src/components/Card/components/CardWrapper.tsx b/dotcom-rendering/src/components/Card/components/CardWrapper.tsx index 665dc36601a..5a5653df200 100644 --- a/dotcom-rendering/src/components/Card/components/CardWrapper.tsx +++ b/dotcom-rendering/src/components/Card/components/CardWrapper.tsx @@ -14,8 +14,8 @@ type Props = { children: React.ReactNode; format: ArticleFormat; containerPalette?: DCRContainerPalette; - showTopBar?: boolean; - showMobileTopBar?: boolean; + showTopBarDesktop?: boolean; + showTopBarMobile?: boolean; isOnwardContent?: boolean; }; @@ -70,7 +70,7 @@ const sublinkHoverStyles = css` } `; -const topBarStyles = css` +const desktopTopBarStyles = css` :before { border-top: 1px solid ${palette('--card-border-top')}; content: ''; @@ -83,7 +83,7 @@ const topBarStyles = css` const mobileTopBarStyles = css` ${until.tablet} { - ${topBarStyles} + ${desktopTopBarStyles} } `; @@ -100,8 +100,8 @@ export const CardWrapper = ({ children, format, containerPalette, - showTopBar = true, - showMobileTopBar = false, + showTopBarDesktop = true, + showTopBarMobile = false, isOnwardContent = false, }: Props) => { return ( @@ -112,8 +112,8 @@ export const CardWrapper = ({ baseCardStyles, hoverStyles, sublinkHoverStyles, - showTopBar && topBarStyles, - showMobileTopBar && mobileTopBarStyles, + showTopBarDesktop && desktopTopBarStyles, + showTopBarMobile && mobileTopBarStyles, isOnwardContent && onwardContentStyles, ]} > diff --git a/dotcom-rendering/src/components/Carousel.importable.tsx b/dotcom-rendering/src/components/Carousel.importable.tsx index 76546c68d17..39a09094393 100644 --- a/dotcom-rendering/src/components/Carousel.importable.tsx +++ b/dotcom-rendering/src/components/Carousel.importable.tsx @@ -540,6 +540,8 @@ const CarouselCard = ({ absoluteServerTimes={absoluteServerTimes} starRating={starRating} index={index} + showTopBarDesktop={!isOnwardContent} + showTopBarMobile={false} />
        • ); diff --git a/dotcom-rendering/src/components/FlexibleGeneral.tsx b/dotcom-rendering/src/components/FlexibleGeneral.tsx index 549dc9217db..c757ebe77bc 100644 --- a/dotcom-rendering/src/components/FlexibleGeneral.tsx +++ b/dotcom-rendering/src/components/FlexibleGeneral.tsx @@ -181,6 +181,8 @@ export const SplashCardLayout = ({ showLivePlayable={card.showLivePlayable} boostedFontSizes={true} isFlexSplash={true} + showTopBarDesktop={false} + showTopBarMobile={true} />
        @@ -262,6 +264,8 @@ export const BoostedCardLayout = ({ aspectRatio="5:4" kickerText={card.kickerText} showLivePlayable={card.showLivePlayable} + showTopBarDesktop={false} + showTopBarMobile={true} />
      @@ -314,6 +318,8 @@ export const StandardCardLayout = ({ aspectRatio="5:4" kickerText={card.kickerText} showLivePlayable={false} + showTopBarDesktop={false} + showTopBarMobile={true} />
    • ); diff --git a/dotcom-rendering/src/components/FlexibleSpecial.tsx b/dotcom-rendering/src/components/FlexibleSpecial.tsx index f7d60a4d2fd..26e9663520e 100644 --- a/dotcom-rendering/src/components/FlexibleSpecial.tsx +++ b/dotcom-rendering/src/components/FlexibleSpecial.tsx @@ -137,6 +137,8 @@ export const OneCardLayout = ({ showLivePlayable={card.showLivePlayable} boostedFontSizes={true} isFlexSplash={true} + showTopBarDesktop={false} + showTopBarMobile={true} />
    @@ -192,6 +194,8 @@ const TwoCardOrFourCardLayout = ({ aspectRatio="5:4" kickerText={card.kickerText} showLivePlayable={false} + showTopBarDesktop={false} + showTopBarMobile={true} /> ); diff --git a/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx index dcf234c6267..cedbcb673ab 100644 --- a/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx +++ b/dotcom-rendering/src/components/ScrollableSmallContainer.importable.tsx @@ -239,7 +239,8 @@ export const ScrollableSmallContainer = ({ aspectRatio="5:4" kickerText={trail.kickerText} showLivePlayable={trail.showLivePlayable} - // TODO - specify card props + showTopBarDesktop={false} + showTopBarMobile={false} /> );