Initial commit: HMDesignSystem baseline
This commit is contained in:
commit
b6a0a61103
486 files changed
+68432
No files matched your search
@@ -0,0 +1,138 @@
|
||||
import type { ReactNode } from "react"
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite"
|
||||
import { Button } from "@hm-design/ui"
|
||||
import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardSurface } from "@hm-design/ui"
|
||||
import { Input } from "@hm-design/ui"
|
||||
import { StateBoard } from "@/components/story-board"
|
||||
import { STORY_KICKER, StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
||||
|
||||
// Story structure follows Button / Input / Select: one representative "Card" Story shows the ui_viz cases on one page,
|
||||
// the same specimens also exist as separate Stories tagged `verification` (hidden from the sidebar, see .storybook/main.ts).
|
||||
// ui_viz (content-container.md Type B Content Card) defines only the Default state, two surfaces, a Title with an optional
|
||||
// Meta / Action, and a body. Hover / Selected / Clickable, Footer and media are not defined, so they are not shown here
|
||||
// except in the Compatibility Story.
|
||||
|
||||
function Body({ children }: { children?: ReactNode }) {
|
||||
return <p className="text-sm">{children ?? "본문은 카드 안쪽 여백 24px 안에 놓입니다. 내용물의 모양은 각 컴포넌트가 정합니다."}</p>
|
||||
}
|
||||
|
||||
function Specimen({ surface = "surface", action, title = "프로젝트 정보", children }: { surface?: CardSurface; action?: boolean; title?: string; children?: ReactNode }) {
|
||||
return (
|
||||
<Card surface={surface}>
|
||||
<CardHeader>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
{action ? (
|
||||
<CardAction>
|
||||
<Button variant="primary" appearance="solid" size="sm">
|
||||
자세히 보기
|
||||
</Button>
|
||||
</CardAction>
|
||||
) : null}
|
||||
</CardHeader>
|
||||
<CardContent>{children ?? <Body />}</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
function FormSpecimen() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>입력 폼</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-2">
|
||||
<label htmlFor="card-form-name" className="text-sm font-medium text-muted-foreground">
|
||||
프로젝트명
|
||||
</label>
|
||||
<Input id="card-form-name" size="medium" placeholder="프로젝트명을 입력하세요" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
const meta = {
|
||||
title: "Components/Data & Display/Card",
|
||||
component: Card,
|
||||
parameters: { layout: "padded" },
|
||||
argTypes: {
|
||||
surface: { control: "inline-radio", options: ["surface", "content"], description: "ui_viz surface 축: White(기본) / Beige." },
|
||||
},
|
||||
} satisfies Meta<typeof Card>
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
// Representative Story: the common Story page (Overview → Variants → Usage) with every ui_viz case. Named after the component, as in ui_viz.
|
||||
// It is the only Card entry in the default sidebar, so Storybook shows Card as a single 1-depth item.
|
||||
export const All: Story = {
|
||||
name: "Card",
|
||||
parameters: { layout: "fullscreen", controls: { disable: true } },
|
||||
render: () => (
|
||||
<StoryPage>
|
||||
<StoryPageHeader
|
||||
kicker={STORY_KICKER.components}
|
||||
title="Card"
|
||||
description="제목과 본문을 하나의 면으로 묶는 콘텐츠 컨테이너입니다(ui_viz Content Card). Default 상태만 정의되어 있습니다."
|
||||
/>
|
||||
<StorySection title="Overview" description="surface를 생략한 기본 Card(White)입니다.">
|
||||
<StateBoard min={360} states={[{ id: "surface", label: "Surface · White (기본)", children: <Specimen /> }]} />
|
||||
</StorySection>
|
||||
<StorySection title="Variants" description="surface: content(Beige)와 제목 옆 Action입니다.">
|
||||
<StateBoard
|
||||
min={360}
|
||||
states={[
|
||||
{ id: "content", label: "Surface · Content (Beige)", children: <Specimen surface="content" /> },
|
||||
{ id: "action", label: "Title + Action", noteAfter: true, note: "Action은 Title 반대쪽 끝, 교차축 중앙 정렬. Title과 20px 이상 간격.", children: <Specimen action /> },
|
||||
]}
|
||||
/>
|
||||
</StorySection>
|
||||
<StorySection title="Usage">
|
||||
<StateBoard min={360} states={[{ id: "form", label: "본문 조합 · Input", children: <FormSpecimen /> }]} />
|
||||
</StorySection>
|
||||
</StoryPage>
|
||||
),
|
||||
}
|
||||
|
||||
// Verification Stories: the same specimens as separate Stories, hidden from the sidebar (tag `verification`).
|
||||
export const Surfaces: Story = {
|
||||
tags: ["verification"],
|
||||
render: () => (
|
||||
<div className="grid max-w-md gap-6">
|
||||
<Specimen />
|
||||
<Specimen surface="content" />
|
||||
</div>
|
||||
),
|
||||
}
|
||||
export const Action: Story = { tags: ["verification"], render: () => <div className="max-w-md"><Specimen action /></div> }
|
||||
|
||||
// HM only: not part of the ui_viz Card spec. Footer, Description and size="sm" are shadcn defaults that ui_viz does not define.
|
||||
export const Compatibility: Story = {
|
||||
tags: ["verification"],
|
||||
render: () => (
|
||||
<div className="grid max-w-md gap-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>shadcn 호환</CardTitle>
|
||||
<CardDescription>ui_viz에 없는 Description 입니다. shadcn 기본 스타일을 씁니다.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Body>Footer도 ui_viz 규격이 없어 shadcn 기본 표면을 씁니다.</Body>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button variant="cancel" appearance="solid" size="sm">
|
||||
닫기
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>size="sm"</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Body>shadcn 작은 크기(여백 12px)입니다. ui_viz에 없습니다.</Body>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
),
|
||||
}
|
||||
Reference in new issue
Block a user