From 6c61edadc1639c2cb9834c3b36c9b86999c705b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=88=98=ED=98=84?= Date: Thu, 5 Nov 2026 15:59:41 +0900 Subject: [PATCH] fix(storybook): refine responsive page inner width - Story page Inner side margin: 16px up to a 480px viewport, linear to 60px at 768px, 60px beyond (no width jump) - Follow the 60px margins: Responsive 1920 row from a 2040px page (was 2000px); property compare 3 columns from 1125px, 2 columns from 787px (was 1080 / 720) - SW browser tests: drop the removed --sb-page-max-width override, compare thresholds 787 / 1125 --- .../tests/property-panel-comparison.browser.mjs | 4 +++- packages/sw/tests/text-weight.browser.mjs | 4 ++-- packages/sw/tests/theme-inheritance.browser.mjs | 1 - ...iewer-logo-document-menu-firefox.browser.mjs | 4 ++-- .../tests/viewer-logo-document-menu.browser.mjs | 1 - packages/sw/tests/viewer.browser.mjs | 9 +++++---- src/components/story-page.css | 8 +++++--- src/sw/sw-footer-stories.css | 2 +- src/sw/sw-stories.css | 17 +++++++++++------ 9 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/sw/tests/property-panel-comparison.browser.mjs b/packages/sw/tests/property-panel-comparison.browser.mjs index e717a5c..ca4006f 100644 --- a/packages/sw/tests/property-panel-comparison.browser.mjs +++ b/packages/sw/tests/property-panel-comparison.browser.mjs @@ -91,7 +91,9 @@ try { report.data[`gaps${width}`] = { colGap, colGap2, rowGap } // 2026-10-22 (user request): no Inner scroller; the page scrolls. 2 columns × 2 rows, one column below 720px. // 2026-10-26 (user request): from 1080px, 3 columns — none/all stacked in column 1, circle and expanded beside them. - const oneColumn = width < 720, threeColumns = width >= 1080 + // 2026-11-05: the Story page Inner keeps 60px on each side (story-page.css), so the steps moved to 787px / 1125px + // (sw-stories.css .sw-story-compare--grid). It keeps 16px up to 480px (growing to 60px at 768px), so 390px has 358px. + const oneColumn = width < 787, threeColumns = width >= 1125 if (threeColumns) { const gaps = { stack: b.cell.y - a.cell.bottom, col1: c.cell.x - Math.max(a.cell.right, b.cell.right), col2: d.cell.x - c.cell.right } report.data[`gaps${width}`] = gaps diff --git a/packages/sw/tests/text-weight.browser.mjs b/packages/sw/tests/text-weight.browser.mjs index c3f197f..b429bfd 100644 --- a/packages/sw/tests/text-weight.browser.mjs +++ b/packages/sw/tests/text-weight.browser.mjs @@ -140,8 +140,8 @@ await page.keyboard.press('Escape') report.reference = { more: refMore[0], documents: refDocs[0], viewerItem: refViewerItem[0], viewerLabel: refViewerLabel[0] } await goto('sw-viewer--viewer-header') -// The 1440px Story frame at full width (as the viewer suites): the header has room for every label. -await page.addStyleTag({ content: '.sb-page { --sb-page-max-width: 100vw; }' }); await page.waitForTimeout(200) +// The 1440px Story frame at full width (the 1920px page's Inner is 1800px): the header has room for every label. +await page.waitForTimeout(200) const vh = page.locator('.hm-sw-viewer-header').first() const vNames = await styles('.hm-sw-viewer-header >> nth=0 >> :is(.hm-sw-header__document-name, .hm-sw-viewer-header__document-name, .hm-sw-viewer-header__label, .hm-sw-viewer-header__tab)') report.viewer = vNames diff --git a/packages/sw/tests/theme-inheritance.browser.mjs b/packages/sw/tests/theme-inheritance.browser.mjs index d329eee..47c6f32 100644 --- a/packages/sw/tests/theme-inheritance.browser.mjs +++ b/packages/sw/tests/theme-inheritance.browser.mjs @@ -39,7 +39,6 @@ const newPage = async (width = 1440, height = 1000) => { const open = async (page, id) => { await page.goto(`${storybook}/iframe.html?id=${id}&viewMode=story`) await page.waitForSelector('#storybook-root > *') - await page.addStyleTag({ content: '.sb-page { --sb-page-max-width: 100vw; }' }) await page.evaluate(() => document.fonts.ready) await page.waitForTimeout(300) } diff --git a/packages/sw/tests/viewer-logo-document-menu-firefox.browser.mjs b/packages/sw/tests/viewer-logo-document-menu-firefox.browser.mjs index 3949eb6..77de065 100644 --- a/packages/sw/tests/viewer-logo-document-menu-firefox.browser.mjs +++ b/packages/sw/tests/viewer-logo-document-menu-firefox.browser.mjs @@ -46,8 +46,8 @@ const ev = async expr => { const r = await send('script.evaluate', { expression: const goto = async story => { await send('browsingContext.navigate', { context, url: `${base}/iframe.html?id=${story}&viewMode=story`, wait: 'complete' }) for (let i = 0; i < 40; i++) { if (await ev(`!!document.querySelector('.hm-sw-viewer-header')`)) break; await sleep(250) } - // Lift the Story page envelope like the Chromium suites; scroll instantly (the preview sets smooth scrolling). - await ev(`(() => { const s = document.createElement('style'); s.textContent = '.sb-page { --sb-page-max-width: 100vw; } html { scroll-behavior: auto !important; }'; document.head.append(s); return true })()`) + // Scroll instantly (the preview sets smooth scrolling). + await ev(`(() => { const s = document.createElement('style'); s.textContent = 'html { scroll-behavior: auto !important; }'; document.head.append(s); return true })()`) await ev('document.fonts.ready.then(() => true)'); await sleep(400) } const frames = () => ev('new Promise(r => requestAnimationFrame(() => requestAnimationFrame(() => r(true))))') diff --git a/packages/sw/tests/viewer-logo-document-menu.browser.mjs b/packages/sw/tests/viewer-logo-document-menu.browser.mjs index 5a83ad0..43fe652 100644 --- a/packages/sw/tests/viewer-logo-document-menu.browser.mjs +++ b/packages/sw/tests/viewer-logo-document-menu.browser.mjs @@ -29,7 +29,6 @@ const newPage = async (width = 1920, height = 1000) => { const open = async (page, id) => { await page.goto(story(id)) await page.waitForSelector('.hm-sw-viewer-header') - await page.addStyleTag({ content: '.sb-page { --sb-page-max-width: 100vw; }' }) await page.evaluate(() => document.fonts.ready) await page.waitForTimeout(200) } diff --git a/packages/sw/tests/viewer.browser.mjs b/packages/sw/tests/viewer.browser.mjs index 84939c8..8b3c4bc 100644 --- a/packages/sw/tests/viewer.browser.mjs +++ b/packages/sw/tests/viewer.browser.mjs @@ -24,9 +24,10 @@ const newPage = async (width = 1440, height = 900) => { page.on('console', message => { if (message.type() === 'error' && !/favicon|404/.test(message.text())) errors.push(`${page.url()}: ${message.text()}`) }) return page } -// 2026-10-23: waits for a visible header (the Responsive Story's first, 1920px row is hidden below a 2000px page). -// Test-only: lift the 1280px Story page envelope so the 1440px frames are measured at full width. -const open = async (page, id) => { await page.goto(story(id)); await page.waitForSelector('.hm-sw-viewer-header:visible'); await page.addStyleTag({ content: '.sb-page { --sb-page-max-width: 100vw; }' }); await page.evaluate(() => document.fonts.ready); await page.waitForTimeout(200) } +// 2026-10-23: waits for a visible header (the Responsive Story's first, 1920px row is hidden below a 2040px page). +// 2026-11-05: the Story page Inner is the page width minus 60px on each side from a 768px viewport (16px up to 480px, +// growing in between; story-page.css), so no envelope override is needed. +const open = async (page, id) => { await page.goto(story(id)); await page.waitForSelector('.hm-sw-viewer-header:visible'); await page.evaluate(() => document.fonts.ready); await page.waitForTimeout(200) } const log = page => page.locator('[data-callback-log]').first().innerText() const box = locator => locator.boundingBox() @@ -293,7 +294,7 @@ if (comparison.reference) { } { // Responsive: measured steps (full → icons only → More), no horizontal overflow; More collects the collapsed items. - // 2026-10-23: rows are picked by their data-width (not by position). The Story's 1920px row is hidden below a 2000px + // 2026-10-23: rows are picked by their data-width (not by position). The Story's 1920px row is hidden below a 2040px // page (sw-story-responsive-hidden), so the page is 2500px wide and every row is shown at its own maximum width. const page = await newPage(2500, 1200) await open(page, 'responsive') diff --git a/src/components/story-page.css b/src/components/story-page.css index 934db33..4793608 100644 --- a/src/components/story-page.css +++ b/src/components/story-page.css @@ -1,5 +1,5 @@ /* Storybook presentation only. Common page frame for representative Stories; all selectors stay inside .sb-page. - Inner (fluid, 60px each side; vertical gutter 16–40) and title (kicker 12 / title 28·36·700 / description, underlined) reuse Foundation / Color. + Inner (fluid; 16px each side up to 480px, growing to 60px at 768px; vertical gutter 16–40) and title (kicker 12 / title 28·36·700 / description, underlined) reuse Foundation / Color. Section reuses the Center Graphic / 교량 split: heading + description, a divider, then the specimen. */ .sb-page { --sb-page-gutter: clamp(16px, 3vw, 40px); @@ -12,8 +12,10 @@ } .sb-page > .sb-page-inner { box-sizing: border-box; - /* 2026-11-05 (user request): no max width; the Inner follows the page width and keeps 60px on each side. */ - width: calc(100% - 120px); + /* 2026-11-05 (user request): no max width; the Inner follows the page width. Side margin (each side) = 16px up to a + 480px viewport (358px Inner at 390px, so a 314px specimen fits), then linear to 60px at 768px (44px over 288px, + 11 / 72 of the viewport growth), 60px from 768px. The Inner keeps growing (about 0.69px per 1px), with no jump. */ + width: calc(100% - 2 * clamp(16px, calc(16px + (100vw - 480px) * 11 / 72), 60px)); min-width: 0; margin-inline: auto; } diff --git a/src/sw/sw-footer-stories.css b/src/sw/sw-footer-stories.css index 5c218b5..c8e3d13 100644 --- a/src/sw/sw-footer-stories.css +++ b/src/sw/sw-footer-stories.css @@ -32,7 +32,7 @@ .sw-footer-story-inline { display: inline-flex; flex-direction: column; padding: 0; } .sw-footer-story-width + .sw-footer-story-width { margin-top: 16px; } /* The hidden 1920px row (Responsive More, narrower than 1920px) takes its gap with it. */ -@container sw-story-page (max-width: 1999.98px) { .sw-story-responsive-hidden + .sw-footer-story-width { margin-top: 0; } } +@container sw-story-page (max-width: 2039.98px) { .sw-story-responsive-hidden + .sw-footer-story-width { margin-top: 0; } } .sw-footer-story-aux-compare { display: grid; grid-template-columns: repeat(auto-fill, minmax(560px, 1fr)); gap: 16px; } .sw-footer-story-aux-row { display: flex; align-items: center; gap: 12px; margin: 0; } .sw-footer-story-aux-row figcaption { flex: 0 0 120px; font-size: 12px; color: #3d4a45; } diff --git a/src/sw/sw-stories.css b/src/sw/sw-stories.css index 0ffd070..ecf37ee 100644 --- a/src/sw/sw-stories.css +++ b/src/sw/sw-stories.css @@ -1,12 +1,13 @@ /* Story canvas only: frames that simulate a header width. Never styles the header itself. */ .sw-story-scroller { max-width: 100%; overflow-x: auto; } /* Responsive More pages: the 1920px row (sw-story-responsive-hidden) shows when the page has 1920px of usable width — - the page (container sw-story-page, not the browser) minus its 40px gutters, so 2000px; with less room the whole row — + the page (container sw-story-page, not the browser) minus the Inner's 60px side margins (story-page.css, + 60px from a 768px viewport), so 2040px (2026-11-05; was 2000px with the former 40px gutters); with less room the whole row — title, header, background, margin — is hidden. 2026-10-23: it stays inside the Story column like every other row (the former reach-out of the 80vw Inner, sw-story-responsive-wide, is gone); its preview is at most 1920px wide. */ .sw-story-responsive { container-type: inline-size; } .sb-page:has(.sw-story-responsive) { container: sw-story-page / inline-size; } -@container sw-story-page (max-width: 1999.98px) { .sw-story-responsive-hidden { display: none; } } +@container sw-story-page (max-width: 2039.98px) { .sw-story-responsive-hidden { display: none; } } .sw-story-frame { background: #060606; } /* Shared drawing-area canvas of the SW Stories (2026-10-19): the SW/Viewer black grid — 40px cells, 1px lines of HM green #266651 at 18%, on #0A0A0B. Used behind the SW Header work area and dropdown room and the viewer frames. */ @@ -43,18 +44,22 @@ /* Property panel 4-state comparison at the panels' own size (314px wide, never shrunk). 2026-10-26 (user request): 3 columns — the short panels (none, all) stacked in column 1, the long ones (circle, expanded) side by side in columns 2 and 3. Rows are auto / 1fr so the long panels' height goes to row 2 only and - "all" sits 24px under "none". Narrower screens: 2 columns × 2 rows (3 × 314 + 2 gaps + gutters do not fit), and one - column below 720px; no Inner scroller and no sideways scroll (2026-10-22). */ + "all" sits 24px under "none". Narrower screens: 2 columns × 2 rows, and one column below 787px; no Inner scroller + and no sideways scroll (2026-10-22). 2026-11-05: each step needs its columns plus the Inner's 60px side margins + (120, story-page.css) and a ~15px vertical scrollbar (the media queries read the viewport): 3 columns from 1125px + (3 × 314 + 2 × 24 = 990), 2 columns from 787px (2 × 314 + 24 = 652). Before: 1080px / 720px with 16–40px gutters. + Both steps sit above 768px, where the margins are 60px. The single column always fits: the margins are 16px up to + 480px and grow to 60px by 768px (story-page.css), so 375 / 390px screens have 343 / 358px for the 314px panel. */ .sw-story-compare-page .sw-story-log { margin-top: 12px; } .sw-story-compare.sw-story-compare--grid { display: grid; grid-template-columns: repeat(2, max-content); align-items: start; gap: 24px; } -@media (min-width: 1080px) { +@media (min-width: 1125px) { .sw-story-compare.sw-story-compare--grid { grid-template-columns: repeat(3, max-content); grid-template-rows: auto 1fr; } .sw-story-compare--grid > [data-compare="none"] { grid-area: 1 / 1; } .sw-story-compare--grid > [data-compare="all"] { grid-area: 2 / 1; } .sw-story-compare--grid > [data-compare="circle"] { grid-area: 1 / 2 / span 2; } .sw-story-compare--grid > [data-compare="expanded"] { grid-area: 1 / 3 / span 2; } } -@media (max-width: 719.98px) { .sw-story-compare.sw-story-compare--grid { grid-template-columns: max-content; } } +@media (max-width: 786.98px) { .sw-story-compare.sw-story-compare--grid { grid-template-columns: max-content; } } /* Placement-only exception, same as the Overview Stage: the product clamps a panel to the viewport height; here the scroller provides the room so the 754px panel keeps its size. */ .sw-story-compare--grid .hm-sw-property { max-height: none; }