Files
HMDesign/src/components/command.stories.tsx
T
shkim4 da0e647b49 docs(storybook): simplify sidebar Story pages around the UI
Drop the category kicker from the 83 sidebar Stories (kicker is now optional;
hidden verification Stories keep it) and shorten or remove repeated, obvious
or internal page/section descriptions. Required specs, limits, virtual-data
and undecided-value notices stay. Story IDs, exports, fixtures, shared state
notes and package code are unchanged. Record: docs/reports/storybook-ui-simplification-2026-10-22.md
2026-10-22 16:13:58 +09:00

115 lines
4.2 KiB
TypeScript

import { useState, type ReactNode } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import { CalendarIcon, SettingsIcon, UserIcon } from "lucide-react"
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from "@hm-design/ui"
import { StateBoard } from "@/components/story-board"
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
// The representative "Command" Story shows real, typeable lists; the same specimens also exist as Stories tagged `verification`
// (hidden from the sidebar). Filtering is cmdk's. The bordered box is Story composition (Command draws no border of its own).
// A selection log shows that Enter / click reach `onSelect`.
const box = (node: ReactNode) => <div className="w-full max-w-sm rounded-md border">{node}</div>
function Basic() {
const [last, setLast] = useState("-")
return (
<div className="grid gap-2">
{box(
<Command>
<CommandInput placeholder="검색..." />
<CommandList>
<CommandEmpty>결과가 없습니다.</CommandEmpty>
<CommandItem onSelect={setLast}>사과</CommandItem>
<CommandItem onSelect={setLast}>바나나</CommandItem>
<CommandItem onSelect={setLast} disabled>
체리 (품절)
</CommandItem>
<CommandItem onSelect={setLast}>포도</CommandItem>
</CommandList>
</Command>
)}
<span className="text-sm text-muted-foreground" data-testid="last">{`선택: ${last}`}</span>
</div>
)
}
function Grouped() {
return box(
<Command>
<CommandInput placeholder="명령 검색..." />
<CommandList>
<CommandEmpty>결과가 없습니다.</CommandEmpty>
<CommandGroup heading="제안">
<CommandItem>
<CalendarIcon />
일정 보기
</CommandItem>
<CommandItem>
<UserIcon />
프로필
<CommandShortcut>⌘P</CommandShortcut>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="설정">
<CommandItem>
<SettingsIcon />
환경설정
<CommandShortcut>⌘,</CommandShortcut>
</CommandItem>
<CommandItem disabled>결제 (사용 불가)</CommandItem>
</CommandGroup>
</CommandList>
</Command>
)
}
function Long() {
return box(
<Command>
<CommandInput placeholder="항목 검색..." />
<CommandList>
<CommandEmpty>결과가 없습니다.</CommandEmpty>
{Array.from({ length: 30 }, (_, i) => (
<CommandItem key={i}>{`항목 ${i + 1} — 긴 항목 이름도 줄바꿈 없이 한 줄로 이어질 수 있습니다`}</CommandItem>
))}
</CommandList>
</Command>
)
}
const sections = [
{ id: "basic", label: "Search + disabled item", node: <Basic /> },
{ id: "grouped", label: "Groups, icons, shortcut", node: <Grouped /> },
{ id: "long", label: "Long list (list scrolls)", node: <Long /> },
]
const meta = { title: "Components/Search & Date/Command", component: Command, parameters: { layout: "padded" } } satisfies Meta<typeof Command>
export default meta
type Story = StoryObj<typeof meta>
const board = (...ids: string[]) => (
<StateBoard min={360} 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: "Command",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
title="Command"
description="Combobox와 명령 팔레트의 기반"
/>
<StorySection title="Overview">{board("basic")}</StorySection>
<StorySection title="Variants">{board("grouped")}</StorySection>
<StorySection title="Usage">{board("long")}</StorySection>
</StoryPage>
),
}
export const Search: Story = { tags: ["verification"], render: () => <Basic /> }
export const GroupedList: Story = { tags: ["verification"], name: "Grouped", render: () => <Grouped /> }