feat: integrate latest HMDesign design system updates
This commit is contained in:
1 parent
99faec189e
commit
1c4e0bb9a1
209 files changed
+8845
-552
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { useMemo, useState } from "react"
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite"
|
||||
import {
|
||||
Card, CardContent, PageHeader, PageHeaderContent, PageHeaderTitle, PageHeaderDescription,
|
||||
Badge,
|
||||
Button,
|
||||
Combobox,
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
useDataTable,
|
||||
type DataTableColumnDef,
|
||||
} from "@hm-design/ui"
|
||||
import "../list-screen.css"
|
||||
import { MoreHorizontalIcon } from "lucide-react"
|
||||
import { STORY_KICKER, StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
||||
import { formatDate, sameDay, sampleUsers, statusLabel, type SampleUser } from "./sample-users"
|
||||
@@ -99,83 +101,44 @@ const statusOptions = [
|
||||
const departmentOptions = [...new Set(sampleUsers.map((u) => u.department))].map((d) => ({ value: d, label: d }))
|
||||
|
||||
// Filter Bar → filter state → Data Table: search is the TanStack global filter, status / date are column filters.
|
||||
function WithFilterBar() {
|
||||
function WithFilterBar({ extended = true }: { extended?: boolean }) {
|
||||
const data = useMemo(() => sampleUsers, [])
|
||||
const table = useDataTable({ columns, data, getRowId: (row) => row.id })
|
||||
const [search, setSearch] = useState("")
|
||||
const [status, setStatus] = useState("all")
|
||||
const [date, setDate] = useState<Date | undefined>()
|
||||
const [department, setDepartment] = useState<string | undefined>()
|
||||
|
||||
const setSearchValue = (value: string) => {
|
||||
setSearch(value)
|
||||
table.setGlobalFilter(value || undefined)
|
||||
const apply = () => {
|
||||
table.setGlobalFilter(search || undefined)
|
||||
table.getColumn("status")?.setFilterValue(status === "all" ? undefined : status)
|
||||
table.getColumn("department")?.setFilterValue(department)
|
||||
table.getColumn("createdAt")?.setFilterValue(date)
|
||||
}
|
||||
const reset = () => {
|
||||
setSearch("")
|
||||
setStatus("all")
|
||||
setDate(undefined)
|
||||
setDepartment(undefined)
|
||||
table.resetGlobalFilter(true)
|
||||
table.resetColumnFilters(true)
|
||||
setSearch(""); setStatus("all"); setDate(undefined); setDepartment(undefined)
|
||||
table.resetGlobalFilter(true); table.resetColumnFilters(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid w-full gap-4">
|
||||
<FilterBar>
|
||||
<FilterBarSearch value={search} onValueChange={setSearchValue} placeholder="이름·부서 검색" />
|
||||
<Select
|
||||
value={status}
|
||||
onValueChange={(value) => {
|
||||
setStatus(value)
|
||||
table.getColumn("status")?.setFilterValue(value === "all" ? undefined : value)
|
||||
}}
|
||||
>
|
||||
<SelectTrigger size="medium" aria-label="상태">
|
||||
<SelectValue placeholder="상태" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">전체 상태</SelectItem>
|
||||
{statusOptions.map((o) => (
|
||||
<SelectItem key={o.value} value={o.value}>
|
||||
{o.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Combobox
|
||||
controlled
|
||||
size="medium"
|
||||
aria-label="부서"
|
||||
options={departmentOptions}
|
||||
value={department}
|
||||
placeholder="부서"
|
||||
onValueChange={(value) => {
|
||||
setDepartment(value)
|
||||
setSearchValue(value)
|
||||
}}
|
||||
/>
|
||||
<DatePicker
|
||||
controlled
|
||||
size="medium"
|
||||
aria-label="등록일"
|
||||
placeholder="등록일"
|
||||
value={date}
|
||||
onValueChange={(value) => {
|
||||
setDate(value)
|
||||
table.getColumn("createdAt")?.setFilterValue(value)
|
||||
}}
|
||||
/>
|
||||
<FilterBarActions>
|
||||
<Button type="button" variant="cancel" appearance="outline" onClick={reset}>
|
||||
초기화
|
||||
</Button>
|
||||
<DataTableViewOptions table={table} labels={columnLabels} />
|
||||
</FilterBarActions>
|
||||
</FilterBar>
|
||||
<DataTable table={table} emptyMessage="조건에 맞는 사용자가 없습니다." />
|
||||
</div>
|
||||
)
|
||||
return <div className="grid min-w-0 gap-4">
|
||||
<PageHeader><PageHeaderContent><PageHeaderTitle>사용자 목록</PageHeaderTitle><PageHeaderDescription>조건을 입력한 뒤 조회합니다.</PageHeaderDescription></PageHeaderContent></PageHeader>
|
||||
<Card className="min-w-0"><CardContent>
|
||||
<div className="grid min-w-0 gap-4">
|
||||
<form onSubmit={event => { event.preventDefault(); apply() }}>
|
||||
<FilterBar className={extended ? "hm-list-search-extended" : "hm-list-search-basic"}>
|
||||
<Select value={status} onValueChange={setStatus}>
|
||||
<SelectTrigger size="medium" aria-label="상태"><SelectValue placeholder="상태" /></SelectTrigger>
|
||||
<SelectContent><SelectItem value="all">전체 상태</SelectItem>{statusOptions.map(option => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}</SelectContent>
|
||||
</Select>
|
||||
{extended && <><Combobox controlled size="medium" aria-label="부서" options={departmentOptions} value={department} placeholder="부서" onValueChange={setDepartment} />
|
||||
<DatePicker controlled size="medium" aria-label="등록일" placeholder="등록일" value={date} onValueChange={setDate} /></>}
|
||||
<FilterBarSearch value={search} onValueChange={setSearch} placeholder="이름·부서 검색" />
|
||||
<FilterBarActions><Button type="submit" variant="primary" appearance="solid">조회</Button><Button type="button" variant="cancel" appearance="outline" onClick={reset}>초기화</Button></FilterBarActions>
|
||||
</FilterBar>
|
||||
</form>
|
||||
<div className="flex justify-end"><DataTableViewOptions table={table} labels={columnLabels} /></div>
|
||||
<DataTable table={table} emptyMessage="조건에 맞는 사용자가 없습니다." />
|
||||
</div>
|
||||
</CardContent></Card>
|
||||
</div>
|
||||
}
|
||||
|
||||
const meta = { title: "Patterns/Data/Data Table", parameters: { layout: "padded", controls: { disable: true } } } satisfies Meta
|
||||
@@ -196,6 +159,8 @@ export const All: Story = {
|
||||
<StorySection title="Overview" description="행 선택(헤더 혼합 상태), 정렬, 열 표시, 행 작업, 페이지 크기와 페이지 이동을 실제로 조작합니다.">
|
||||
<Basic />
|
||||
</StorySection>
|
||||
<StorySection title="기본 목록 검색" description="조건·검색어·조회·초기화를 8px 간격으로 가운데 정렬합니다. 제목은 Card 밖에 배치합니다."><WithFilterBar extended={false} /></StorySection>
|
||||
<StorySection title="추가 조건 목록 검색" description="부서·등록일을 제공하는 구성은 입력값과 관계없이 왼쪽 정렬합니다. 모바일 버튼 행은 우측 정렬합니다."><WithFilterBar /></StorySection>
|
||||
</StoryPage>
|
||||
),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user