refactor(storybook): fold SW Header Options stories into SW/Header
Remove the separate SW/Header/Options sidebar item. Its examples move to two
Stories directly under SW/Header (src/sw/sw-header-open.stories.tsx):
- Document Open: Open placement, label, 10-width responsive, composed bar,
composed (controls) responsive
- Hidden Sub Controls: document New / Open and layer freeze / lock removal
No public API or component change. Tests and inventory follow the new IDs
(integrated 97/97, existing Stories pixel-identical 28/28, unused-removal
83/83). The two remaining overview failures are pre-existing historical
assertions (also failing on 5faa1f1), not new defects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
55179b4577
commit
e8409eff44
17 files changed
+168
-87
No files matched your search
@@ -49,21 +49,36 @@ function useLog() {
|
||||
return [view, (line: string) => setLog(lines => [...lines.slice(-7), line])] as const
|
||||
}
|
||||
|
||||
// Two Stories directly under SW/Header (no separate Options menu): Document Open and Hidden Sub Controls.
|
||||
const meta = {
|
||||
title: "SW/Header/Options",
|
||||
title: "SW/Header",
|
||||
id: "sw-header",
|
||||
parameters: { layout: "fullscreen", controls: { disable: true } },
|
||||
} satisfies Meta
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
function OpenPlacementPage() {
|
||||
function DocumentOpenPage() {
|
||||
const [log, record] = useLog()
|
||||
const [layerId, setLayerId] = useState("wall")
|
||||
const header = (props: Partial<SWHeaderProps>) => (
|
||||
<SWHeader {...base} onDocumentOpen={() => record("onDocumentOpen")} onDocumentNew={() => record("onDocumentNew")} {...props} />
|
||||
)
|
||||
// Composed layouts that need responsive behavior use SWHeader itself (controls + documentOpenPlacement):
|
||||
// the one existing More logic serves them, no second More is created.
|
||||
const viewer = (width: number) => (
|
||||
<div key={width} data-width={width}>
|
||||
<Frame width={width}>
|
||||
<SWHeader {...base} documentOpenPlacement="header" documentOpenLabel="파일 열기"
|
||||
controls={[{ id: "document" }, { id: "layer" }, { id: "color" }, { id: "popupGuide" }]}
|
||||
colors={[{ id: "red", color: "#ff0000", label: "빨강" }, { id: "green", color: "#00ff00", label: "초록" }]}
|
||||
onDocumentOpen={() => record("onDocumentOpen")} onColorSelect={option => record(`onColorSelect(${option.id})`)} onPopupGuide={() => record("onPopupGuide")} />
|
||||
</Frame>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<StoryPage>
|
||||
<StoryPageHeader kicker={KICKER} title="파일 열기 위치 (documentOpenPlacement)"
|
||||
<StoryPageHeader kicker={KICKER} title="파일 열기 (documentOpenPlacement)"
|
||||
description="documentOpenPlacement="header"이면 Open이 로고 바로 오른쪽에 파일명과 같은 면(hm-sw-header__document-button)으로 표시되고, 문서 Dropdown의 Open은 숨겨집니다. 두 곳 모두 onDocumentOpen과 documentOpenLabel을 씁니다. 공간이 부족하면(실측) Open은 More로 이동합니다." />
|
||||
{log}
|
||||
<StorySection title="기본값 (menu) — 변경 없음" description="documentOpenPlacement를 주지 않으면 기존과 같습니다(Open은 Dropdown 하단).">
|
||||
@@ -73,18 +88,35 @@ function OpenPlacementPage() {
|
||||
<div data-open-placement="header"><Frame width={1920}>{header({ documentOpenPlacement: "header" })}</Frame></div>
|
||||
</StorySection>
|
||||
<StorySection title="header + documentOpenLabel="파일 열기"" description="버튼·More 항목 글자는 documentOpenLabel입니다(기본 Open).">
|
||||
<Frame width={1920}>{header({ documentOpenPlacement: "header", documentOpenLabel: "파일 열기" })}</Frame>
|
||||
<div data-open-label=""><Frame width={1920}>{header({ documentOpenPlacement: "header", documentOpenLabel: "파일 열기" })}</Frame></div>
|
||||
</StorySection>
|
||||
<StorySection title="반응형 (10개 폭)" description="파일명이 먼저 줄고, 그래도 넘치면 Open이 More(⋯)로 이동합니다.">
|
||||
<div data-responsive-open="">
|
||||
{OPTION_WIDTHS.map(width => <div key={width} data-width={width}><Frame width={width}>{header({ documentOpenPlacement: "header" })}</Frame></div>)}
|
||||
</div>
|
||||
</StorySection>
|
||||
<StorySection title="조합형 막대 — 로고 → 파일 열기 → 문서 → 레이어" description="SWHeader 없이 같은 구성: SWHeaderHome → SWToolButton appearance="document" → SWHeaderDocumentTitle showOpen={false}. 배치용 CSS만 소비 프로젝트가 작성합니다. 이 막대에는 More가 없습니다.">
|
||||
<Frame width={1440}>
|
||||
<SWTheme className="sw-story-composed-bar" data-composed-open="">
|
||||
<SWHeaderHome logoSrc={placeholderLogo} logoAlt="임시 로고" onClick={() => record("onHomeClick")} />
|
||||
<SWToolButton appearance="document" onClick={() => record("onDocumentOpen")}>Open</SWToolButton>
|
||||
<SWHeaderDocumentTitle title={DOCUMENTS[0].name} documents={DOCUMENTS} activeDocumentId="doc-1" showOpen={false}
|
||||
onDocumentSelect={document => record(`onDocumentSelect(${document.id})`)} onNew={() => record("onNew")} />
|
||||
<div className="sw-story-composed-surface">
|
||||
<SWHeaderLayerMenu value={{ name: LAYERS.find(layer => layer.id === layerId)!.name }} layers={LAYERS} activeLayerId={layerId}
|
||||
onLayerSelect={layer => { setLayerId(layer.id); record(`onLayerSelect(${layer.id})`) }} />
|
||||
</div>
|
||||
</SWTheme>
|
||||
</Frame>
|
||||
</StorySection>
|
||||
<StorySection title="조합형 구성의 반응형 (SWHeader controls, 10개 폭)" description="로고 → 파일 열기 → 파일 → 레이어 → 색상 → K만 쓰는 구성을 SWHeader의 controls / documentOpenPlacement로 만들면 기존 More와 가용 공간 판단이 그대로 동작합니다.">
|
||||
<div data-composed-responsive="">{OPTION_WIDTHS.map(viewer)}</div>
|
||||
</StorySection>
|
||||
</StoryPage>
|
||||
)
|
||||
}
|
||||
|
||||
export const OpenPlacement: Story = { name: "Open Placement", render: () => <OpenPlacementPage /> }
|
||||
export const DocumentOpen: Story = { name: "Document Open", render: () => <DocumentOpenPage /> }
|
||||
|
||||
function HiddenSubControlsPage() {
|
||||
const [log, record] = useLog()
|
||||
@@ -106,57 +138,3 @@ function HiddenSubControlsPage() {
|
||||
}
|
||||
|
||||
export const HiddenSubControls: Story = { name: "Hidden Sub Controls", render: () => <HiddenSubControlsPage /> }
|
||||
|
||||
function ComposedOpenPage() {
|
||||
const [log, record] = useLog()
|
||||
const [layerId, setLayerId] = useState("wall")
|
||||
return (
|
||||
<StoryPage>
|
||||
<StoryPageHeader kicker={KICKER} title="조합형 Header의 파일 열기"
|
||||
description="SWHeader 없이 같은 구성: SWHeaderHome → SWToolButton appearance="document" → SWHeaderDocumentTitle showOpen={false}. 배치용 CSS(.app-*)만 소비 프로젝트가 작성합니다." />
|
||||
{log}
|
||||
<StorySection title="로고 → 파일 열기 → 문서 → 레이어">
|
||||
<Frame width={1440}>
|
||||
<SWTheme className="sw-story-composed-bar" data-composed-open="">
|
||||
<SWHeaderHome logoSrc={placeholderLogo} logoAlt="임시 로고" onClick={() => record("onHomeClick")} />
|
||||
<SWToolButton appearance="document" onClick={() => record("onDocumentOpen")}>Open</SWToolButton>
|
||||
<SWHeaderDocumentTitle title={DOCUMENTS[0].name} documents={DOCUMENTS} activeDocumentId="doc-1" showOpen={false}
|
||||
onDocumentSelect={document => record(`onDocumentSelect(${document.id})`)} onNew={() => record("onNew")} />
|
||||
<div className="sw-story-composed-surface">
|
||||
<SWHeaderLayerMenu value={{ name: LAYERS.find(layer => layer.id === layerId)!.name }} layers={LAYERS} activeLayerId={layerId}
|
||||
onLayerSelect={layer => { setLayerId(layer.id); record(`onLayerSelect(${layer.id})`) }} />
|
||||
</div>
|
||||
</SWTheme>
|
||||
</Frame>
|
||||
</StorySection>
|
||||
</StoryPage>
|
||||
)
|
||||
}
|
||||
|
||||
export const ComposedOpen: Story = { name: "Composed Open", render: () => <ComposedOpenPage /> }
|
||||
|
||||
// Composed layouts that need responsive behavior use SWHeader itself (controls + leading + documentOpenPlacement):
|
||||
// the one existing More logic serves them, no second More is created.
|
||||
function ComposedResponsivePage() {
|
||||
const [log, record] = useLog()
|
||||
const viewer = (width: number) => (
|
||||
<div key={width} data-width={width}>
|
||||
<Frame width={width}>
|
||||
<SWHeader {...base} documentOpenPlacement="header" documentOpenLabel="파일 열기"
|
||||
controls={[{ id: "document" }, { id: "layer" }, { id: "color" }, { id: "popupGuide" }]}
|
||||
colors={[{ id: "red", color: "#ff0000", label: "빨강" }, { id: "green", color: "#00ff00", label: "초록" }]}
|
||||
onDocumentOpen={() => record("onDocumentOpen")} onColorSelect={option => record(`onColorSelect(${option.id})`)} onPopupGuide={() => record("onPopupGuide")} />
|
||||
</Frame>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<StoryPage>
|
||||
<StoryPageHeader kicker={KICKER} title="조합형 구성의 반응형 (SWHeader controls)"
|
||||
description="뷰어처럼 로고 → 파일 열기 → 파일 → 레이어 → 색상 → K만 쓰는 구성을 SWHeader의 controls / documentOpenPlacement로 만들면 기존 More와 가용 공간 판단이 그대로 동작합니다. SWTheme로 직접 배치한 막대에는 More가 없습니다." />
|
||||
{log}
|
||||
<StorySection title="10개 폭"><div data-composed-responsive="">{OPTION_WIDTHS.map(viewer)}</div></StorySection>
|
||||
</StoryPage>
|
||||
)
|
||||
}
|
||||
|
||||
export const ComposedResponsive: Story = { name: "Composed Responsive", render: () => <ComposedResponsivePage /> }
|
||||
Reference in new issue
Block a user