Drop page / section descriptions, state notes and repeated captions from the representative Stories of 44 components, the Patterns, Center Graphic and OrgChart pages. Value readouts, spec lists and captions hide only on the representative page; hidden verification Stories keep them. Tabs Default API and the Filter Bar draft / applied counts move to the hidden DefaultApi and DraftApplied Stories; Center Overview is hidden with its direct URL kept. Story IDs are unchanged. Align the component, pattern and OrgChart docs with the pages, point the quality reference check at the DraftApplied Story, and make the P8 styles check expect no section header on the preview-only Expanded page.
125 lines
4.9 KiB
TypeScript
125 lines
4.9 KiB
TypeScript
import type { ReactNode } from "react"
|
||
import type { Meta, StoryObj } from "@storybook/react-vite"
|
||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@hm-design/ui"
|
||
import { StateBoard } from "@/components/story-board"
|
||
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
||
|
||
// The representative Story shows real, draggable layouts; the same specimens also exist as Stories tagged `verification` (hidden
|
||
// from the sidebar). react-resizable-panels v4 sizes: a string without a unit ("30") or with "%" is a percentage, a number is
|
||
// pixels. The frames (size, border) and panel content are Story layout. These are not Dashboard layouts.
|
||
|
||
const frame = (node: ReactNode, height = 200) => (
|
||
<div className="rounded-md border" style={{ width: "100%", maxWidth: 560, height }}>
|
||
{node}
|
||
</div>
|
||
)
|
||
|
||
const Pane = ({ children }: { children: ReactNode }) => <div className="grid size-full place-items-center p-3 text-sm">{children}</div>
|
||
|
||
function Horizontal() {
|
||
return frame(
|
||
<ResizablePanelGroup orientation="horizontal" aria-label="가로 분할" id="h">
|
||
<ResizablePanel defaultSize="30" minSize="15" id="h-list">
|
||
<Pane>목록 (min 15%)</Pane>
|
||
</ResizablePanel>
|
||
<ResizableHandle aria-label="목록 폭 조절" />
|
||
<ResizablePanel defaultSize="70" minSize="20" id="h-detail">
|
||
<Pane>상세</Pane>
|
||
</ResizablePanel>
|
||
</ResizablePanelGroup>
|
||
)
|
||
}
|
||
|
||
function Vertical() {
|
||
return frame(
|
||
<ResizablePanelGroup orientation="vertical" aria-label="세로 분할" id="v">
|
||
<ResizablePanel defaultSize="40" minSize="20" id="v-top">
|
||
<Pane>위</Pane>
|
||
</ResizablePanel>
|
||
<ResizableHandle withHandle aria-label="높이 조절" />
|
||
<ResizablePanel defaultSize="60" minSize="20" id="v-bottom">
|
||
<Pane>아래</Pane>
|
||
</ResizablePanel>
|
||
</ResizablePanelGroup>,
|
||
240
|
||
)
|
||
}
|
||
|
||
function WithHandle() {
|
||
return frame(
|
||
<ResizablePanelGroup orientation="horizontal" aria-label="handle 분할" id="g">
|
||
<ResizablePanel defaultSize="50" minSize="20" id="g-a">
|
||
<Pane>A</Pane>
|
||
</ResizablePanel>
|
||
<ResizableHandle withHandle aria-label="A와 B 사이 조절" />
|
||
<ResizablePanel defaultSize="50" minSize="20" id="g-b">
|
||
<Pane>B</Pane>
|
||
</ResizablePanel>
|
||
</ResizablePanelGroup>
|
||
)
|
||
}
|
||
|
||
function MinMax() {
|
||
return frame(
|
||
<ResizablePanelGroup orientation="horizontal" aria-label="min max 분할" id="m">
|
||
<ResizablePanel defaultSize="40" minSize="25" maxSize="60" id="m-a">
|
||
<Pane>25% – 60%</Pane>
|
||
</ResizablePanel>
|
||
<ResizableHandle withHandle aria-label="min max 조절" />
|
||
<ResizablePanel defaultSize="60" minSize="20" id="m-b">
|
||
<Pane>나머지</Pane>
|
||
</ResizablePanel>
|
||
</ResizablePanelGroup>
|
||
)
|
||
}
|
||
|
||
function Collapsible() {
|
||
return frame(
|
||
<ResizablePanelGroup orientation="horizontal" aria-label="접힘 분할" id="c">
|
||
<ResizablePanel defaultSize="30" minSize="15" collapsible collapsedSize="0" id="c-side">
|
||
<Pane>사이드 (끌면 접힘)</Pane>
|
||
</ResizablePanel>
|
||
<ResizableHandle withHandle aria-label="사이드 폭 조절" />
|
||
<ResizablePanel defaultSize="70" minSize="30" id="c-main">
|
||
<Pane>본문</Pane>
|
||
</ResizablePanel>
|
||
</ResizablePanelGroup>
|
||
)
|
||
}
|
||
|
||
const sections = [
|
||
{ id: "horizontal", label: "Horizontal", node: <Horizontal /> },
|
||
{ id: "vertical", label: "Vertical with grip", node: <Vertical /> },
|
||
{ id: "handle", label: "Horizontal with grip", node: <WithHandle /> },
|
||
{ id: "minmax", label: "Min / max", node: <MinMax /> },
|
||
{ id: "collapsible", label: "Collapsible panel", node: <Collapsible /> },
|
||
]
|
||
|
||
const meta = { title: "Components/Disclosure/Resizable", component: ResizablePanelGroup, parameters: { layout: "padded" } } satisfies Meta<typeof ResizablePanelGroup>
|
||
export default meta
|
||
type Story = StoryObj<typeof meta>
|
||
|
||
const board = (...ids: string[]) => (
|
||
<StateBoard min={580} states={sections.filter((s) => ids.includes(s.id)).map((s) => ({ id: s.id, label: s.label, children: s.node }))} />
|
||
)
|
||
|
||
// Representative Story: the common Story page; the sections group the same specimens.
|
||
export const All: Story = {
|
||
name: "Resizable",
|
||
parameters: { layout: "fullscreen", controls: { disable: true } },
|
||
render: () => (
|
||
<StoryPage>
|
||
<StoryPageHeader
|
||
title="Resizable"
|
||
/>
|
||
<StorySection title="Overview">{board("horizontal")}</StorySection>
|
||
<StorySection title="Variants">{board("vertical", "handle")}</StorySection>
|
||
<StorySection title="Usage">{board("minmax", "collapsible")}</StorySection>
|
||
</StoryPage>
|
||
),
|
||
}
|
||
|
||
export const HorizontalLayout: Story = { tags: ["verification"], name: "Horizontal", render: () => <Horizontal /> }
|
||
export const VerticalLayout: Story = { tags: ["verification"], name: "Vertical", render: () => <Vertical /> }
|
||
export const MinMaxLayout: Story = { tags: ["verification"], name: "Min Max", render: () => <MinMax /> }
|