refactor(sw): simplify storybook navigation and examples

This commit is contained in:
shkim4 committed 2026-10-20 13:17:15 +09:00
1 parent 47972c55ff
commit 2b0e1a2262
19 files changed
+438 -92

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

+2
View File
@@ -221,6 +221,8 @@ const SMALL_COMMAND = { width: 120, ["--hm-sw-footer-command-expanded-height" as
export const FigmaVariants: Story = {
name: "Figma 디자인별 Variant (35 노드)",
// 2026-10-20 sidebar simplification: Figma node verification; ID and direct URL kept.
tags: ["verification"],
render: () => (
<StoryPage>
<StoryPageHeader kicker={KICKER} title="Figma 디자인별 Variant" description={<>요청된 35개 노드 전체. 왼쪽 = Figma 렌더(get_screenshot), 오른쪽 = 같은 순서의 구현 상태(Hover는 Story 전용 <code>data-sb-hover</code>로 고정). 노드 → 컴포넌트·Props 매핑은 <code>docs/sw/sw-footer-figma-mapping-2026-10-20.md</code>.</>} />
+9 -81
View File
@@ -13,15 +13,13 @@ import {
figmaHomeMenuItemIds, figmaHomeMenuSections, figmaRecentFiles, figmaTileNodes, figmaTitleNodes, withRecentFiles,
} from "./sw-home-menu-fixture"
import placeholderLogo from "./assets/sw-header-logo-placeholder.svg"
import figmaHomeOn from "./assets/home-menu/figma-26-10591.png"
import figmaHomeOnOutline from "./assets/home-menu/figma-662-67267.png"
import figmaRecent from "./assets/home-menu/662-67331_recent-files.png"
import figmaPreview from "./assets/home-menu/662-67471_file-preview-2depth.png"
import figmaPropertyBar from "./assets/home-menu/figma-26-10492.png"
// Owner: docs/sw/figma-additional/analysis-report.md (Figma rj6wpsfk24lOWvWiVRAANP 26:10591 / 662:67267).
// 2026-10-19: the former SW/Home Menu Stories live under SW/Header (SW normal mode only; SW/Viewer has no logo menu).
// "Home Menu" is the sidebar Story; the other Stories keep their checks reachable by URL (verification tag).
// "Home Menu" and "Home Menu · 단독 사용 · 조합형" are the sidebar Stories; the other Stories keep their checks reachable
// by URL (verification tag). 2026-10-20: Figma screenshot comparisons that no test or document used were removed;
// the Figma originals stay in docs/sw/figma-additional/screenshots/.
const KICKER = "HM DESIGN SYSTEM / SW"
const meta = {
@@ -136,21 +134,16 @@ export const HomeMenu: Story = {
<StorySection title="반응형 · 헤더 폭 조절 · 더보기(⋯)" description="메뉴 위치와 폭은 고정 x가 아니라 Header를 측정해 정합니다(객체 수정 영역 −2px ~ 창 영역). 폭이 부족한 Header에서는 기존 더보기(…) 규칙이 그대로 동작하고, 메뉴는 가로 스크롤 없이 들어가는 섹션만 앞에서부터 보여 주며 나머지는 끝의 더보기(⋯) 섹션으로 옮깁니다. 더보기를 누르면 옮긴 섹션이 텍스트 메뉴(섹션 제목 + 기능 목록, 그룹 사이 구분선)로 아래에 열리고(Hover·Active·클릭은 타일과 같음, 최근파일은 기존 목록을 엶), 폭이 넓어지면 원래 자리로 돌아갑니다. 브라우저 폭이나 슬라이더로 확인합니다(슬라이더 최대 = 현재 페이지 폭).">
<ResizableHeaderWithMenu />
</StorySection>
<StorySection title="Figma 26:10591 비교 (현재 폭)" description="위는 구현(열림, 현재 폭), 아래는 Figma 스크린샷(1920px을 현재 폭에 맞춰 축소)입니다. 1:1 비교는 'Home Menu · Figma 재현 (26:10591)' Story(1920px)에서 합니다. 열림 동안 로고는 Home On(노란 테두리), Header 상·하단에 #5F4B0F 2px 선이 표시되고 닫으면 기본으로 돌아갑니다(Figma 662:67267).">
<StorySection title="열림 (현재 폭)" description="열림 동안 로고는 Home On(노란 테두리), Header 상·하단에 #5F4B0F 2px 선이 표시되고 닫으면 기본으로 돌아갑니다(Figma 26:10591 / 662:67267).">
<HeaderWithMenu defaultOpen autoFocus={false} />
<img className="sw-home-menu-story__figma-fit" src={figmaHomeOn} alt="Figma 26:10591 home on" width={1920} height={78} />
</StorySection>
<StorySection title="Default / Variant2 · Hover / Variant3 · Active" description="Figma 버튼 세트 15개(26:11355 … 26:11631)는 모두 같은 SWHomeMenuItem입니다. Variant2(Hover)는 마우스를 올려 확인하며 Figma에서 Variant3와 시각 속성이 같습니다. Variant3는 activeIds로 지정합니다.">
<SWTheme className="sw-home-menu-story__stage"><SWHomeMenu defaultOpen autoFocus={false} sections={figmaHomeMenuSections} closeOnBackgroundClick={false} aria-label="Default" /></SWTheme>
<SWTheme className="sw-home-menu-story__stage"><SWHomeMenu defaultOpen autoFocus={false} sections={figmaHomeMenuSections} activeIds={figmaHomeMenuItemIds} closeOnBackgroundClick={false} aria-label="Active" /></SWTheme>
{tileTable}
</StorySection>
<StorySection title="최근파일 하위 패널 (662:67267)" description="최근파일 타일을 누르면(Variant3) 메뉴 하단 강조가 전체 2px 외곽선으로 바뀌고 그 아래에 최근파일 목록이 열립니다. 행에 마우스를 올리면 2뎁스 미리보기가 옆에 나타납니다. 다시 누르거나 Escape로 닫습니다. 최근파일이 더보기 안에 있으면 목록은 더보기 타일 아래에 열리고 더보기 타일이 Variant3가 됩니다. 목록과 미리보기 이미지는 Story 데이터입니다. 1920px 1:1은 'Home Menu · 최근파일 하위 패널' Story입니다.">
<StorySection title="최근파일 하위 패널 (662:67267)" description="최근파일 타일을 누르면(Variant3) 메뉴 하단 강조가 전체 2px 외곽선으로 바뀌고 그 아래에 최근파일 목록이 열립니다. 행에 마우스를 올리면 2뎁스 미리보기가 옆에 나타납니다. 다시 누르거나 Escape로 닫습니다. 최근파일이 더보기 안에 있으면 목록은 더보기 타일 아래에 열리고 더보기 타일이 Variant3가 됩니다. 목록과 미리보기 이미지는 Story 데이터입니다.">
<div className="sw-home-menu-story__tall"><HeaderWithMenu defaultOpen autoFocus={false} defaultActiveIds={["recent"]}>{log => log}</HeaderWithMenu></div>
<div className="sw-home-menu-story__figma-row">
<img src={figmaRecent} alt="Figma 662:67331 최근파일" width={362} height={758} />
<img src={figmaPreview} alt="Figma 662:67471 파일출력 2뎁스" width={315} height={276} />
</div>
</StorySection>
<StorySection title="통합 · 속성창 · SWPopup · Escape" description="Escape는 Focus가 있는 곳을 먼저 닫습니다(메뉴 안: 하위 패널 → 메뉴, Popup 안: 그 Popup). Focus가 모두의 밖이면 가장 최근에 열거나 사용한 하나만 닫습니다.">
<IntegrationDemo />
@@ -159,38 +152,16 @@ export const HomeMenu: Story = {
),
}
export const HomeMenuFigma: Story = {
name: "Home Menu · Figma 재현 (26:10591)",
tags: ["verification"],
render: () => (
<StoryPage>
<StoryPageHeader kicker={KICKER} title="로고 클릭 메뉴 — Figma 26:10591 재현"
description="1920px Header 위에 SWHomeMenu를 겹친 상태입니다. 위는 구현, 아래는 Figma 스크린샷(1x)입니다. 로고를 다시 누르면 닫힙니다." />
<StorySection title="구현 (1920px)" description="SWHeader가 객체 수정 영역 시작(−2px)~창 영역 시작을 DOM에서 측정해 메뉴를 놓습니다. 열림 동안 로고는 Home On(노란 테두리), Header 상·하단에 #5F4B0F 2px 선이 표시되고 닫으면 기본으로 돌아갑니다(Figma 662:67267).">
<div className="sw-home-menu-story__scroll"><HeaderWithMenu width={1920} defaultOpen /></div>
</StorySection>
<StorySection title="Figma 26:10591">
<div className="sw-home-menu-story__scroll"><img className="sw-home-menu-story__figma" src={figmaHomeOn} alt="Figma 26:10591 home on" width={1920} height={78} /></div>
</StorySection>
</StoryPage>
),
}
/** 1:1 capture canvas for pixel comparison with the Figma 1920 x 77 frame (no story page chrome). */
function FigmaCanvas({ active, accent, recent }: { active?: boolean; accent?: SWHomeMenuAccent; recent?: boolean }) {
const sections = recent ? withRecentFiles(figmaHomeMenuSections, <SWRecentFiles files={figmaRecentFiles} />) : figmaHomeMenuSections
/** 1:1 capture canvas at the Figma 1920 x 77 frame (no story page chrome); home-menu-integration.browser.mjs measures it. */
function FigmaCanvas() {
return (
<div className="sw-home-menu-story__frame" style={{ width: 1920, height: recent ? 840 : 80 }}>
<div className="sw-home-menu-story__frame" style={{ width: 1920, height: 80 }}>
{/* The integrated placement (measured by SWHeader), not a fixed x: it must land on Figma x 375. */}
<SWHeader {...headerArgs} defaultHomeMenuOpen homeMenu={{ sections, accent, autoFocus: false,
activeIds: active ? figmaHomeMenuItemIds : recent ? ["recent"] : undefined }} />
<SWHeader {...headerArgs} defaultHomeMenuOpen homeMenu={{ sections: figmaHomeMenuSections, autoFocus: false }} />
</div>
)
}
export const HomeMenuCaptureDefault: Story = { name: "Home Menu · 비교 캔버스 · Default", tags: ["!autodocs", "verification"], render: () => <FigmaCanvas /> }
export const HomeMenuCaptureActive: Story = { name: "Home Menu · 비교 캔버스 · Variant3", tags: ["!autodocs", "verification"], render: () => <FigmaCanvas active /> }
export const HomeMenuCaptureOutline: Story = { name: "Home Menu · 비교 캔버스 · outline", tags: ["!autodocs", "verification"], render: () => <FigmaCanvas accent="outline" /> }
export const HomeMenuCaptureRecent: Story = { name: "Home Menu · 비교 캔버스 · 최근파일", tags: ["!autodocs", "verification"], render: () => <FigmaCanvas recent /> }
export const HomeMenuHeaderComposition: Story = {
name: "Home Menu · Header 조합 · 로고 클릭",
@@ -206,27 +177,6 @@ export const HomeMenuHeaderComposition: Story = {
),
}
export const HomeMenuVariants: Story = {
name: "Home Menu · 3가지 Variant",
tags: ["verification"],
render: () => (
<StoryPage>
<StoryPageHeader kicker={KICKER} title="Default / Variant2 / Variant3"
description="Figma 버튼 세트 15개(26:11355 … 26:11631)는 모두 같은 SWHomeMenuItem입니다. Variant2(Hover)는 마우스를 올려 확인하며, Figma에서 Variant3와 시각 속성이 같습니다. Variant3는 activeIds로 지정합니다." />
<StorySection title="Default">
<SWTheme className="sw-home-menu-story__stage"><SWHomeMenu defaultOpen sections={figmaHomeMenuSections} closeOnBackgroundClick={false} aria-label="Default" /></SWTheme>
</StorySection>
<StorySection title="Variant2 · Hover" description="마우스를 올린 타일만 Variant2입니다. 누르는 동안 Variant3이고 클릭 후에는 Default로 돌아갑니다(실행 버튼). 최근파일만 목록이 열린 동안 Variant3입니다.">
<SWTheme className="sw-home-menu-story__stage"><SWHomeMenu defaultOpen sections={figmaHomeMenuSections} closeOnBackgroundClick={false} aria-label="Hover" /></SWTheme>
</StorySection>
<StorySection title="Variant3 · Active (activeIds = 15개 전체)" description="Figma Variant3 시각 확인용으로 host가 activeIds를 직접 지정한 상태입니다(표시 전용). 클릭으로는 바뀌지 않습니다.">
<SWTheme className="sw-home-menu-story__stage"><SWHomeMenu defaultOpen sections={figmaHomeMenuSections} activeIds={figmaHomeMenuItemIds} closeOnBackgroundClick={false} aria-label="Active" /></SWTheme>
</StorySection>
<StorySection title="Figma 노드 대응" description="섹션 제목 tit_* 와 타일 세트">{tileTable}</StorySection>
</StoryPage>
),
}
function DynamicDemo() {
const [sections, setSections] = useState<SWHomeMenuSectionData[]>(figmaHomeMenuSections)
const [selection, setSelection] = useState<"multiple" | "single">("multiple")
@@ -304,7 +254,6 @@ function StandaloneDemo() {
export const HomeMenuStandalone: Story = {
name: "Home Menu · 단독 사용 · 조합형",
tags: ["verification"],
render: () => (
<StoryPage>
<StoryPageHeader kicker={KICKER} title="SWTheme 안에서 단독 사용"
@@ -314,27 +263,6 @@ export const HomeMenuStandalone: Story = {
),
}
export const HomeMenuRecentFiles: Story = {
name: "Home Menu · 최근파일 하위 패널 (662:67267)",
tags: ["verification"],
render: () => (
<StoryPage>
<StoryPageHeader kicker={KICKER} title="최근파일 — Figma 662:67267 + 662:67331 + 662:67471"
description="Figma 주석 '최근파일' 상태입니다. 최근파일 타일을 누르면(Variant3) 메뉴 하단 강조가 전체 2px 외곽선으로 바뀌고 그 아래에 최근파일 목록이 열립니다. 행에 마우스를 올리면 2뎁스 미리보기가 옆에 나타납니다. 다시 누르거나 Escape로 닫습니다. 목록과 미리보기 이미지는 Story 데이터입니다. K 미리보기(Variant5)는 기존 SWHeader K 가이드 Hover가 담당합니다." />
<StorySection title="구현 (1920px)">
<div className="sw-home-menu-story__scroll sw-home-menu-story__tall"><HeaderWithMenu width={1920} defaultOpen defaultActiveIds={["recent"]}>{log => log}</HeaderWithMenu></div>
</StorySection>
<StorySection title="Figma 662:67267 · 662:67331 · 662:67471">
<div className="sw-home-menu-story__scroll"><img className="sw-home-menu-story__figma" src={figmaHomeOnOutline} alt="Figma 662:67267" width={1935} height={193} /></div>
<div className="sw-home-menu-story__figma-row">
<img src={figmaRecent} alt="Figma 662:67331 최근파일" width={362} height={758} />
<img src={figmaPreview} alt="Figma 662:67471 파일출력 2뎁스" width={315} height={276} />
</div>
</StorySection>
</StoryPage>
),
}
// Property bar check (Figma 26:10492) against the current SWHeaderPropertyBar. Values are the Figma sample; the
// bar itself is unchanged (3 differences, awaiting approval: home-menu-integration report §속성Bar).
const barProperties: SWHeaderProperty[] = [
+8 -5
View File
@@ -65,7 +65,7 @@ const callbacks = {
const meta = {
title: "SW/Header",
excludeStories: ["ComposedDemo"],
excludeStories: ["ComposedDemo", "PropertyPanelComparePage"],
component: SWHeader,
parameters: { layout: "fullscreen" },
args: { ...figmaArgs, ...callbacks },
@@ -289,6 +289,8 @@ function MotionSpecimen({ time }: { time?: number }) {
export const WindowMoveMotion: Story = {
name: "Window Move Motion",
// 2026-10-20 sidebar simplification: GIF frame verification; ID and direct URL kept.
tags: ["verification"],
parameters: { controls: { disable: true } },
render: () => (
<StoryPage>
@@ -939,6 +941,8 @@ function usePropertyMenus(record: (line: string) => void, setProperties: (update
export const KGuide: Story = {
name: "K Guide",
// 2026-10-20 sidebar simplification: the same Header as Overview (K guide on hover); ID and direct URL kept.
tags: ["verification"],
parameters: { controls: { disable: true } },
render: () => <StoryPage><StoryPageHeader kicker={KICKER} title="K 가이드 반복 애니메이션" description="기존 K 버튼 Hover/Focus → 원본 이미지 Pan·Zoom 반복. 영역을 벗어나면 정지, 재진입은 처음부터. Reduced Motion은 정지 이미지." /><div className="sw-story-property-room"><SWHeader {...figmaArgs} {...callbacks} /></div></StoryPage>,
}
@@ -992,8 +996,7 @@ function PropertyCompare() {
</div>
</>
}
export const PropertyPanelCompare: Story = {
name: "Property Panel · 4개 비교",
parameters: { controls: { disable: true } },
render: () => <StoryPage className="sw-story-compare-page"><StoryPageHeader kicker={KICKER} title="속성창 4개 상태 비교" description="네 패널은 같은 SWHeaderPropertyPanel입니다. 실제 Header에서는 현재 선택 객체의 패널 하나만 표시합니다." /><PropertyCompare /></StoryPage>,
/** Rendered by SW/Popup › Property Panel · 4개 비교 (sw-property-panel.stories.tsx, ID sw-header--property-panel-compare). */
export function PropertyPanelComparePage() {
return <StoryPage className="sw-story-compare-page"><StoryPageHeader kicker={KICKER} title="속성창 4개 상태 비교" description="네 패널은 같은 SWHeaderPropertyPanel입니다. 실제 Header에서는 현재 선택 객체의 패널 하나만 표시합니다." /><PropertyCompare /></StoryPage>
}
-3
View File
@@ -11,8 +11,5 @@
.sw-home-menu-story__table { border-collapse: collapse; font-size: 13px; }
.sw-home-menu-story__table :is(th, td) { padding: 4px 8px; border: 1px solid #ccc; text-align: left; }
.sw-home-menu-story__tall .sw-home-menu-story__frame { height: 860px; }
.sw-home-menu-story__figma-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 16px; margin-top: 12px; }
.sw-home-menu-story__figma-row > img { max-width: 100%; height: auto; }
.sw-home-menu-story__figma-fit { display: block; width: 100%; height: auto; margin-top: 12px; }
.sw-home-menu-story__width { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 13px; }
.sw-home-menu-story__width input { width: min(480px, 60vw); }
+17
View File
@@ -0,0 +1,17 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import { PropertyPanelComparePage } from "./sw-header.stories"
const meta = {
title: "SW/Popup",
// 2026-10-20: moved from SW/Header to SW/Popup in the sidebar only; the id keeps sw-header--property-panel-compare
// for existing tests, documents and bookmarks. The file name sorts after sw-popup.stories.tsx, so this Story follows
// Custom Content and Multiple Popups.
id: "sw-header",
parameters: { layout: "fullscreen", controls: { disable: true } },
} satisfies Meta
export default meta
export const PropertyPanelCompare: StoryObj<typeof meta> = {
name: "Property Panel · 4개 비교",
render: () => <PropertyPanelComparePage />,
}