From b0a429a51f837805c13ba987f2e620cbe18f0fc5 Mon Sep 17 00:00:00 2001 From: Ionut Neagu Date: Mon, 22 Jun 2026 16:00:27 +0200 Subject: [PATCH 1/2] feat(onboarding): show 4 starter sites per row on laptop and up Widen the onboarding starter-sites grid from 3 to 4 columns at the laptop breakpoint (>=992px) so users see ~8 templates at once instead of leaving large empty margins on wider screens. Tablet stays at 2 columns, mobile at 1. Keep the JS in sync with the new column count: - Page size 9 -> 12 (initial useState, the reset effect, and the lazy-load increment) so each render fills whole rows. 12 divides evenly by both 3 and 4, so rows stay full at every breakpoint. - Search "Browse more" divider padding % 3 -> % 4 so the divider lands on a clean row boundary under the 4-column grid. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01QrGf4K9upxDKhRPVCztoLs --- onboarding/src/Components/Sites.js | 10 +++++----- onboarding/src/scss/_general.scss | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/onboarding/src/Components/Sites.js b/onboarding/src/Components/Sites.js index a0ef9747..efee2918 100644 --- a/onboarding/src/Components/Sites.js +++ b/onboarding/src/Components/Sites.js @@ -27,11 +27,11 @@ const Sites = ( { sortBy, selectedColors, } ) => { - const [ maxShown, setMaxShown ] = useState( 9 ); + const [ maxShown, setMaxShown ] = useState( 12 ); const { sites = {} } = getSites; useEffect( () => { - setMaxShown( 9 ); + setMaxShown( 12 ); }, [ editor, category, searchQuery, sortBy, selectedColors ] ); const getBuilders = () => Object.keys( sites ); @@ -218,9 +218,9 @@ const Sites = ( { const rest = filterByColors( filterByCategory( ranked, category ) ).filter( ( site ) => site && site.slug && ! inMatches[ site.slug ] ); - const remainder = matches.length % 3; + const remainder = matches.length % 4; const pad = - remainder === 0 ? 0 : Math.min( 3 - remainder, rest.length ); + remainder === 0 ? 0 : Math.min( 4 - remainder, rest.length ); return { list: [ ...matches, ...rest ], @@ -280,7 +280,7 @@ const Sites = ( { return false; } - setMaxShown( ( shown ) => shown + 9 ); + setMaxShown( ( shown ) => shown + 12 ); } } > Date: Mon, 22 Jun 2026 17:23:07 +0200 Subject: [PATCH 2/2] test(onboarding): match All/Free filter buttons exactly The grid now renders a full page of 12 cards, so card page-shot buttons (e.g. "Gallery", "Ballet Blog", "All Courses") contain "all" as a substring. The non-exact getByRole('button', { name: 'All' }) locator then resolved to multiple elements (Playwright strict mode violation). Match the All/Free filter buttons by exact name. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01GYVWBEDjCM3wzBP6Ew1Ku4 --- e2e-tests/specs/onboarding.spec.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/e2e-tests/specs/onboarding.spec.js b/e2e-tests/specs/onboarding.spec.js index d737ce93..fbbf6673 100644 --- a/e2e-tests/specs/onboarding.spec.js +++ b/e2e-tests/specs/onboarding.spec.js @@ -48,9 +48,12 @@ test.describe('Onboarding', () => { expect(await page.locator('.ss-card .ss-badge').count()).toBeGreaterThan(0); // 'All' and 'Free' should show after you select a category. + // Match exactly: card page-shot buttons (e.g. "Gallery", "Ballet Blog", + // "All Courses") also contain "all" as a substring, so a non-exact name + // match resolves to multiple elements once the grid renders a full page. await page.locator('.ob-cat-wrap').first().click(); - await expect(page.getByRole('button', { name: 'All' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Free' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'All', exact: true })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Free', exact: true })).toBeVisible(); // Check card structure. const firstListedSiteCard = page.locator('.ss-card-wrap').first();