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.
109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
import { Button, Input, Popover, PopoverClose, PopoverContent, PopoverTrigger } from "@hm-design/ui"
|
|
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
|
|
|
// Popover is a non-modal Radix overlay (Portal). The representative Story opens the real panels from their triggers;
|
|
// the verification Story starts one open. Radix owns outside click / Escape close and focus return.
|
|
|
|
function Info({ defaultOpen }: { defaultOpen?: boolean }) {
|
|
return (
|
|
<Popover defaultOpen={defaultOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="primary" appearance="outline">
|
|
정보 보기
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent aria-label="프로젝트 안내">
|
|
<div className="grid gap-1">
|
|
<p className="font-bold">프로젝트 안내</p>
|
|
<p>일정과 담당자 정보를 현재 화면 위에서 확인합니다. 바깥을 누르거나 Esc를 누르면 닫힙니다.</p>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
)
|
|
}
|
|
|
|
function FormPanel() {
|
|
return (
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="primary" appearance="outline">
|
|
이름 변경
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent align="start" aria-label="프로젝트 이름 변경">
|
|
<div className="grid gap-3">
|
|
<label htmlFor="popover-name" className="text-sm font-medium text-muted-foreground">
|
|
프로젝트명
|
|
</label>
|
|
<Input id="popover-name" size="medium" placeholder="프로젝트명을 입력하세요" />
|
|
<div className="flex justify-end gap-2">
|
|
<PopoverClose asChild>
|
|
<Button variant="cancel" appearance="solid" size="sm">
|
|
취소
|
|
</Button>
|
|
</PopoverClose>
|
|
<PopoverClose asChild>
|
|
<Button variant="primary" appearance="solid" size="sm">
|
|
저장
|
|
</Button>
|
|
</PopoverClose>
|
|
</div>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
)
|
|
}
|
|
|
|
function Aligned() {
|
|
return (
|
|
<div className="flex w-full max-w-md justify-between gap-3">
|
|
{(["start", "center", "end"] as const).map((align) => (
|
|
<Popover key={align}>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="primary" appearance="outline" size="sm">
|
|
{`align ${align}`}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent align={align} side="bottom" aria-label={`정렬 예제: ${align}`}>
|
|
<p>{`align="${align}"`}</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const meta = { title: "Components/Overlay/Popover", component: Popover, parameters: { layout: "centered" } } satisfies Meta<typeof Popover>
|
|
export default meta
|
|
type Story = StoryObj<typeof meta>
|
|
|
|
export const All: Story = {
|
|
name: "Popover",
|
|
parameters: { layout: "fullscreen", controls: { disable: true } },
|
|
render: () => (
|
|
<StoryPage>
|
|
<StoryPageHeader title="Popover" />
|
|
<StorySection title="Overview">
|
|
<Info />
|
|
</StorySection>
|
|
<StorySection title="Variants">
|
|
<Aligned />
|
|
</StorySection>
|
|
<StorySection title="Usage">
|
|
<FormPanel />
|
|
</StorySection>
|
|
</StoryPage>
|
|
),
|
|
}
|
|
|
|
export const Open: Story = {
|
|
tags: ["verification"],
|
|
parameters: { layout: "fullscreen" },
|
|
render: () => (
|
|
<div className="flex min-h-[320px] justify-center p-8">
|
|
<Info defaultOpen />
|
|
</div>
|
|
),
|
|
}
|