Skip to content

Commit 5c6c774

Browse files
committed
Refactor editorial category card grid
Copilot-Session: bb1440ac-bb8e-4dd5-a1b5-8d6998a2a8c9
1 parent ca20637 commit 5c6c774

12 files changed

Lines changed: 202 additions & 129 deletions

packages/react/src/recipes/Editorial/Category/Category.module.css

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,12 @@
1010
padding: var(--base-size-48) var(--base-size-32) var(--base-size-32);
1111
}
1212

13-
.sectionHeaderColumn,
14-
.cardGridFooterColumn {
15-
min-width: 0;
16-
}
17-
1813
.sortLabel {
1914
flex-shrink: 0;
2015
}
2116

2217
.cardGrid {
23-
--editorial-cardGrid-border: var(--brand-borderWidth-thin) solid var(--brand-color-border-muted);
24-
25-
border-inline: var(--editorial-cardGrid-border);
26-
}
27-
28-
.cardGridColumn {
29-
display: flex;
18+
border-inline: var(--brand-borderWidth-thin) solid var(--brand-color-border-muted);
3019
}
3120

3221
.cardGridItem {
@@ -38,16 +27,12 @@
3827
transition: background var(--brand-animation-duration-extended) var(--brand-animation-easing-default);
3928
}
4029

41-
.cardGridColumnMiddleMobileRow .cardGridItem {
42-
border-block: var(--editorial-cardGrid-border);
43-
}
44-
45-
.cardGridColumnArrowHover .cardGridItem:is(:hover, :focus-within) {
30+
.cardGridItem:is(:hover, :focus-within) {
4631
background: linear-gradient(to top, var(--editorial-cardGrid-hover-overlay) 0%, transparent 100%),
4732
var(--brand-color-canvas-default);
4833
}
4934

50-
[data-color-mode='dark'] .cardGridColumnArrowHover .cardGridItem:is(:hover, :focus-within) {
35+
[data-color-mode='dark'] .cardGridItem:is(:hover, :focus-within) {
5136
--editorial-cardGrid-hover-overlay: color-mix(in srgb, var(--base-color-scale-gray-0) 10%, transparent);
5237
}
5338

@@ -62,39 +47,3 @@
6247
.paginationFrame {
6348
padding-inline: var(--base-size-32);
6449
}
65-
66-
@media screen and (min-width: 48rem) and (max-width: 63.24rem) {
67-
.cardGridColumnMiddleMobileRow .cardGridItem {
68-
border-block: 0;
69-
}
70-
71-
.cardGridColumnTabletDivider .cardGridItem {
72-
border-inline-start: var(--editorial-cardGrid-border);
73-
}
74-
75-
.cardGridColumnTabletEndDivider .cardGridItem {
76-
border-inline-end: var(--editorial-cardGrid-border);
77-
}
78-
79-
.cardGridColumnTabletLastCompleteRow .cardGridItem {
80-
border-block-end: var(--editorial-cardGrid-border);
81-
}
82-
83-
.cardGridColumnMiddleTabletRow .cardGridItem {
84-
border-block: var(--editorial-cardGrid-border);
85-
}
86-
}
87-
88-
@media screen and (min-width: 63.25rem) {
89-
.cardGridColumnMiddleMobileRow .cardGridItem {
90-
border-block: 0;
91-
}
92-
93-
.cardGridColumnDesktopStartDivider .cardGridItem {
94-
border-inline-start: var(--editorial-cardGrid-border);
95-
}
96-
97-
.cardGridColumnMiddleDesktopRow .cardGridItem {
98-
border-block: var(--editorial-cardGrid-border);
99-
}
100-
}
Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
declare const styles: {
22
readonly cardGrid: string
3-
readonly cardGridColumn: string
4-
readonly cardGridColumnArrowHover: string
5-
readonly cardGridColumnDesktopStartDivider: string
6-
readonly cardGridColumnMiddleDesktopRow: string
7-
readonly cardGridColumnMiddleMobileRow: string
8-
readonly cardGridColumnMiddleTabletRow: string
9-
readonly cardGridColumnTabletDivider: string
10-
readonly cardGridColumnTabletEndDivider: string
11-
readonly cardGridColumnTabletLastCompleteRow: string
12-
readonly cardGridFooterColumn: string
133
readonly cardGridItem: string
144
readonly hero: string
155
readonly heroSection: string
166
readonly paginationFrame: string
177
readonly resourceCard: string
188
readonly sectionHeader: string
19-
readonly sectionHeaderColumn: string
209
readonly sortLabel: string
2110
}
2211
export = styles

packages/react/src/recipes/Editorial/Category/Category.stories.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {INITIAL_VIEWPORTS} from 'storybook/viewport'
22
import type {Meta, StoryObj} from '@storybook/react'
33
import {useTranslation} from 'react-i18next'
44

5-
import {getLocalizedEditorialCategoryContent} from './Category.content'
5+
import {defaultEditorialCategoryContent, getLocalizedEditorialCategoryContent} from './Category.content'
66
import {Category as CategoryComponent, CategoryTemplate} from './Category'
77

88
const meta = {
@@ -28,3 +28,30 @@ export const Category: Story = {
2828
return <CategoryTemplate content={getLocalizedEditorialCategoryContent(t)} />
2929
},
3030
}
31+
32+
const incompleteCategoryContent = {
33+
...defaultEditorialCategoryContent,
34+
featured: {
35+
...defaultEditorialCategoryContent.featured,
36+
cards: defaultEditorialCategoryContent.resources.cards.slice(0, 5),
37+
},
38+
resources: {
39+
...defaultEditorialCategoryContent.resources,
40+
cards: defaultEditorialCategoryContent.resources.cards.slice(0, 5),
41+
},
42+
}
43+
44+
export const CardGridIncomplete: Story = {
45+
name: 'Card grid incomplete',
46+
render: () => <CategoryTemplate content={incompleteCategoryContent} />,
47+
}
48+
49+
export const CardGridTablet: Story = {
50+
name: 'Card grid Tablet',
51+
render: () => <CategoryTemplate content={incompleteCategoryContent} />,
52+
}
53+
54+
export const CardGridNarrow: Story = {
55+
name: 'Card grid Narrow',
56+
render: () => <CategoryTemplate content={incompleteCategoryContent} />,
57+
}

packages/react/src/recipes/Editorial/Category/Category.tsx

Lines changed: 26 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import {clsx} from 'clsx'
21
import React, {useCallback, useState} from 'react'
32

43
import {
54
Box,
65
Card,
7-
Grid,
86
Heading,
97
Hero,
108
MinimalFooter,
@@ -18,6 +16,7 @@ import {
1816
import {RedlineBackground} from '../../../component-helpers'
1917

2018
import {defaultEditorialCategoryContent, type EditorialCategoryContent} from './Category.content'
19+
import {EditorialCardGrid} from '../EditorialCardGrid'
2120
import editorialStyles from '../Editorial.module.css'
2221
import styles from './Category.module.css'
2322

@@ -132,50 +131,28 @@ type CardGridProps = {
132131
}
133132

134133
function CardGrid({cards, heading, sortLabel, footer}: CardGridProps) {
135-
const lastTabletRowStartIndex = cards.length - (cards.length % 2 || 2)
136-
const lastDesktopRowStartIndex = cards.length - (cards.length % 3 || 3)
137-
138134
return (
139-
<Grid columnGap="none" rowGap="none" enableGutters={false} className={styles.cardGrid}>
140-
<Grid.Column span={12} className={styles.sectionHeaderColumn}>
141-
<Stack
142-
className={styles.sectionHeader}
143-
direction={{narrow: 'vertical', regular: 'horizontal'}}
144-
gap={24}
145-
alignItems={{narrow: 'flex-start', regular: 'flex-end'}}
146-
justifyContent="space-between"
147-
padding="none"
148-
>
149-
<Heading as="h2" size="5" weight="normal">
150-
{heading}
151-
</Heading>
152-
{sortLabel ? (
153-
<Text size="100" variant="muted" className={styles.sortLabel}>
154-
{sortLabel}
155-
</Text>
156-
) : null}
157-
</Stack>
158-
</Grid.Column>
159-
{cards.map((card, index) => (
160-
<Grid.Column
161-
key={card.heading}
162-
span={{xsmall: 12, medium: 6, large: 4}}
163-
className={clsx(
164-
styles.cardGridColumn,
165-
styles.cardGridColumnArrowHover,
166-
index % 2 === 1 && styles.cardGridColumnTabletDivider,
167-
cards.length % 2 === 1 && index === cards.length - 1 && styles.cardGridColumnTabletEndDivider,
168-
cards.length % 2 === 1 &&
169-
index >= lastTabletRowStartIndex - 2 &&
170-
index < lastTabletRowStartIndex &&
171-
styles.cardGridColumnTabletLastCompleteRow,
172-
index % 3 !== 0 && styles.cardGridColumnDesktopStartDivider,
173-
index > 0 && index < cards.length - 1 && styles.cardGridColumnMiddleMobileRow,
174-
index >= 2 && index < lastTabletRowStartIndex && styles.cardGridColumnMiddleTabletRow,
175-
index >= 3 && index < lastDesktopRowStartIndex && styles.cardGridColumnMiddleDesktopRow,
176-
)}
177-
>
178-
<Box className={styles.cardGridItem}>
135+
<div className={styles.cardGrid}>
136+
<Stack
137+
className={styles.sectionHeader}
138+
direction={{narrow: 'vertical', regular: 'horizontal'}}
139+
gap={24}
140+
alignItems={{narrow: 'flex-start', regular: 'flex-end'}}
141+
justifyContent="space-between"
142+
padding="none"
143+
>
144+
<Heading as="h2" size="5" weight="normal">
145+
{heading}
146+
</Heading>
147+
{sortLabel ? (
148+
<Text size="100" variant="muted" className={styles.sortLabel}>
149+
{sortLabel}
150+
</Text>
151+
) : null}
152+
</Stack>
153+
<EditorialCardGrid layout="responsive">
154+
{cards.map(card => (
155+
<Box key={card.heading} className={styles.cardGridItem}>
179156
<Card href={card.href} fullWidth ctaVariant="none" className={styles.resourceCard} backgroundColor="none">
180157
<Card.Tokens>
181158
{card.tokens.map((token, tokenIndex) => (
@@ -186,13 +163,9 @@ function CardGrid({cards, heading, sortLabel, footer}: CardGridProps) {
186163
<Card.Description>{card.description}</Card.Description>
187164
</Card>
188165
</Box>
189-
</Grid.Column>
190-
))}
191-
{footer ? (
192-
<Grid.Column span={12} className={styles.cardGridFooterColumn}>
193-
{footer}
194-
</Grid.Column>
195-
) : null}
196-
</Grid>
166+
))}
167+
</EditorialCardGrid>
168+
{footer}
169+
</div>
197170
)
198171
}

packages/react/src/recipes/Editorial/Category/Category.visual.spec.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,48 @@ test.describe('Visual Comparison: Category', () => {
1313
})
1414
await page.locator('body.sb-show-main').waitFor({state: 'visible'})
1515

16-
await page.waitForTimeout(4000)
16+
await page.waitForTimeout(500)
1717
await expect(page).toHaveScreenshot({fullPage: true})
1818
})
19+
20+
test('Category / Card grid incomplete', async ({page}) => {
21+
await page.goto(
22+
'http://localhost:6006/iframe.html?args=&id=recipes-editorial-category--card-grid-incomplete&viewMode=story',
23+
{waitUntil: 'networkidle'},
24+
)
25+
await page.locator('body.sb-show-main').waitFor({state: 'visible'})
26+
27+
await page.waitForTimeout(500)
28+
await expect(page).toHaveScreenshot({fullPage: true})
29+
})
30+
31+
// eslint-disable-next-line i18n-text/no-en
32+
test.describe('Tablet viewport test for Card grid Tablet', () => {
33+
test.use({viewport: {width: 834, height: 1112}})
34+
test('Category / Card grid Tablet', async ({page}) => {
35+
await page.goto(
36+
'http://localhost:6006/iframe.html?args=&id=recipes-editorial-category--card-grid-tablet&viewMode=story',
37+
{waitUntil: 'networkidle'},
38+
)
39+
await page.locator('body.sb-show-main').waitFor({state: 'visible'})
40+
41+
await page.waitForTimeout(500)
42+
await expect(page).toHaveScreenshot({fullPage: true})
43+
})
44+
})
45+
46+
// eslint-disable-next-line i18n-text/no-en
47+
test.describe('Mobile viewport test for Card grid Narrow', () => {
48+
test.use({viewport: {width: 360, height: 800}})
49+
test('Category / Card grid Narrow', async ({page}) => {
50+
await page.goto(
51+
'http://localhost:6006/iframe.html?args=&id=recipes-editorial-category--card-grid-narrow&viewMode=story',
52+
{waitUntil: 'networkidle'},
53+
)
54+
await page.locator('body.sb-show-main').waitFor({state: 'visible'})
55+
56+
await page.waitForTimeout(500)
57+
await expect(page).toHaveScreenshot({fullPage: true})
58+
})
59+
})
1960
})
Loading
Loading

packages/react/src/recipes/Editorial/Editorial.module.css

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,62 @@
2626
margin-top: calc(var(--base-size-48) - var(--brand-borderWidth-thin));
2727
}
2828

29+
.cardGridCells {
30+
--editorial-cardGrid-border: var(--brand-borderWidth-thin) solid var(--brand-color-border-muted);
31+
}
32+
33+
.cardGridCell {
34+
display: flex;
35+
min-width: 0;
36+
}
37+
38+
.cardGridCell:not(:first-child) {
39+
border-block-start: var(--editorial-cardGrid-border);
40+
}
41+
42+
@media screen and (min-width: 48rem) and (max-width: 63.24rem) {
43+
.cardGridCells--responsive .cardGridCell {
44+
border-block-start: 0;
45+
}
46+
47+
.cardGridCells--responsive .cardGridCell:nth-child(even) {
48+
border-inline-start: var(--editorial-cardGrid-border);
49+
}
50+
51+
.cardGridCells--responsive .cardGridCell:nth-child(n + 3) {
52+
border-block-start: var(--editorial-cardGrid-border);
53+
}
54+
}
55+
56+
@media screen and (min-width: 48rem) {
57+
.cardGridCells--threeColumn .cardGridCell {
58+
border-block-start: 0;
59+
}
60+
61+
.cardGridCells--threeColumn .cardGridCell:not(:nth-child(3n + 1)) {
62+
border-inline-start: var(--editorial-cardGrid-border);
63+
}
64+
65+
.cardGridCells--threeColumn .cardGridCell:nth-child(n + 4) {
66+
border-block-start: var(--editorial-cardGrid-border);
67+
}
68+
}
69+
70+
@media screen and (min-width: 63.25rem) {
71+
.cardGridCells--responsive .cardGridCell {
72+
border-block-start: 0;
73+
border-inline-start: 0;
74+
}
75+
76+
.cardGridCells--responsive .cardGridCell:not(:nth-child(3n + 1)) {
77+
border-inline-start: var(--editorial-cardGrid-border);
78+
}
79+
80+
.cardGridCells--responsive .cardGridCell:nth-child(n + 4) {
81+
border-block-start: var(--editorial-cardGrid-border);
82+
}
83+
}
84+
2985
.redlineBackground {
3086
display: flex;
3187
flex-direction: column;

0 commit comments

Comments
 (0)