style(chart): open chart pages and surface/track tokens

- @hm-design/chart: add --hm-chart-track (radial tracks, horizontal bar
  hover band; warm neutral light) and --hm-chart-surface (slice / segment
  gaps, Dot rings, label halos, radial meter center; white by default)
- --hm-chart-bar-name-halo stays an optional override and falls back to
  --hm-chart-surface; official chart.tsx unchanged
- Storybook Chart pages (Bar / Line / Area / Donut / Pie / Radar / Radial):
  open layout without example cards, 2-4 responsive columns, one sample
  data notice per page, surface token set to the content background
- Same sample data, props, tooltip and interaction as the example cards;
  examples entry and consumer example unchanged
- README: surface / track token usage
This commit is contained in:
shkim4 committed 2026-11-12 17:12:09 +09:00
1 parent a7b56ff23e
commit 7ff852952a
15 files changed
+337 -214

No files matched your search

+37 -40
View File
@@ -1,18 +1,12 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
AreaCurveDotLabelExample,
AreaCurveExample,
AreaExpandedExample,
AreaStackedExample,
AreaStepDotLabelExample,
AreaStepExample,
AreaStraightColorLabelExample,
AreaStraightExample,
} from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMAreaChart } from "@hm-design/chart"
import { sampleLineCompare, sampleLinePointColors } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. The eight examples share the Line Chart data: connection styles as a plain area (left) and with Dots and
// value Labels (right), then Stacked (running total) and Expanded (each month normalized to 100%).
// Sample data only. The eight charts share the Line Chart data: connection styles as a plain area and with Dots and value
// Labels, then Stacked (running total) and Expanded (each month normalized to 100%). Same data and props as the
// @hm-design/chart/examples cards; open layout (no card): see chart-story.tsx.
const meta = {
title: "Chart/Area Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -23,34 +17,37 @@ type Story = StoryObj<typeof meta>
export const Area: Story = {
name: "Area Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Area Chart" />
{/* Same grid and order as Line Chart, plus a Stacked | Expanded row. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Curve">
<AreaCurveExample />
</StorySection>
<StorySection title="Curve · Dot + Label">
<AreaCurveDotLabelExample />
</StorySection>
<StorySection title="Straight">
<AreaStraightExample />
</StorySection>
<StorySection title="Straight · Color Dot + Label">
<AreaStraightColorLabelExample />
</StorySection>
<StorySection title="Step">
<AreaStepExample />
</StorySection>
<StorySection title="Step · Dot + Label">
<AreaStepDotLabelExample />
</StorySection>
<StorySection title="Stacked">
<AreaStackedExample />
</StorySection>
<StorySection title="Expanded">
<AreaExpandedExample />
</StorySection>
<ChartSampleNotice />
{/* Same grid and order as Line Chart, then a Stacked | Expanded row. */}
<StorySectionGrid className={chartGrid.pairs}>
<ChartSpecimen title="Curve" description="monotone">
<HMAreaChart {...sampleLineCompare} curve="monotone" label="월별 접수·완료 곡선형 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Curve · Dot + Label" description="monotone · Dot과 값 Label">
<HMAreaChart {...sampleLineCompare} curve="monotone" pointLabels label="월별 접수·완료 곡선형 Dot·값 Label 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Straight" description="linear">
<HMAreaChart {...sampleLineCompare} curve="linear" label="월별 접수·완료 직선형 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Straight · Color Dot + Label" description="linear · Dot 개별 색상 + 값 Label">
<HMAreaChart {...sampleLinePointColors} curve="linear" pointLabels label="월별 접수·완료 직선형 포인트별 색상 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Step" description="step">
<HMAreaChart {...sampleLineCompare} curve="step" label="월별 접수·완료 계단형 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Step · Dot + Label" description="step · Dot과 값 Label">
<HMAreaChart {...sampleLineCompare} curve="step" pointLabels label="월별 접수·완료 계단형 Dot·값 Label 영역 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
<StorySectionGrid className={chartGrid.pair}>
<ChartSpecimen title="Stacked" description="값 누적">
<HMAreaChart {...sampleLineCompare} stacked label="월별 접수·완료 Stacked 영역 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Expanded" description="합계 100%">
<HMAreaChart {...sampleLineCompare} expanded label="월별 접수·완료 Expanded 영역 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),
+23 -25
View File
@@ -1,13 +1,11 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
BarChartExample,
HorizontalBarChartExample,
SignedBarChartExample,
StackedBarChartExample,
} from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMBarChart, HMHorizontalBarChart, HMSignedBarChart } from "@hm-design/chart"
import { sampleBar, sampleHorizontalBar, sampleSignedBar } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// shadcn/ui Chart (Recharts) with HM tokens, from the public @hm-design/chart entries. All values are sample data.
// shadcn/ui Chart (Recharts) with HM tokens, from the public @hm-design/chart entry. All values are sample data; each chart has
// the same data and props as the matching @hm-design/chart/examples card. Open layout (no card): see chart-story.tsx.
// Narrow widths: use the toolbar Viewport presets (HM Mobile · 390). The chart is fluid.
const meta = {
title: "Chart/Bar Chart",
@@ -19,24 +17,24 @@ type Story = StoryObj<typeof meta>
export const Bar: Story = {
name: "Bar Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Bar Chart" />
{/* Two sections per row from 1024px (HM desktop boundary), one below. Source order is the mobile order; on desktop it reads
row by row: Grouped | Horizontal, then Stacked | Positive / Negative. On desktop every row has the same height and each
card fills its section, so card tops, bottoms and chart areas line up. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Grouped">
<BarChartExample />
</StorySection>
<StorySection title="Horizontal">
<HorizontalBarChartExample />
</StorySection>
<StorySection title="Stacked">
<StackedBarChartExample />
</StorySection>
<StorySection title="Positive / Negative">
<SignedBarChartExample />
</StorySection>
<ChartSampleNotice />
{/* Two per row from 1024px, one below. Source order is the mobile order; desktop reads row by row:
Grouped | Horizontal, then Stacked | Positive / Negative. */}
<StorySectionGrid className={chartGrid.pair}>
<ChartSpecimen title="Grouped" description="월별 접수·완료 현황 · 상반기 월별 건수">
<HMBarChart {...sampleBar} label="월별 접수·완료 건수 막대 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Horizontal" description="항목별 처리 건수 · 가로 막대">
<HMHorizontalBarChart {...sampleHorizontalBar} label="항목별 처리 건수 가로 막대 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Stacked" description="월별 접수·완료 현황(누적)">
<HMBarChart {...sampleBar} stacked label="월별 접수·완료 건수 누적 막대 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Positive / Negative" description="월별 순증감 · 0 기준 양수·음수">
<HMSignedBarChart {...sampleSignedBar} label="월별 순증감 양수·음수 막대 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),
+76
View File
@@ -0,0 +1,76 @@
import type { ReactNode } from "react"
import { sampleDataNotice } from "@hm-design/chart/examples"
import { StorySection } from "@/components/story-page"
// Storybook presentation only (not part of @hm-design/chart): the open Chart page layout (2026-11-12, user request).
// Charts sit directly on the Storybook content background, without the example card (background, border, padding). Each chart
// is one StorySection: H2 variant name → description (what the example shows) → thin section divider → optional toolbar → chart.
// The charts themselves are the public @hm-design/chart components on the @hm-design/chart/examples sample data, with the same
// props as the matching *Example card, so data, legend, tooltip and interaction are unchanged. No common layout change; the page
// only sets the chart's own surface token (chartPageClass).
/**
* className of every Chart page's StoryPage. The charts sit on the Storybook content background (--hm-sem-bg-content), so the page
* sets the chart's public surface token to it (2026-11-12): slice / segment gaps, Dot rings, label halos and the radial meter's
* center read as background instead of white. Only the token value is set, as a consumer would; no chart internals are overridden.
*/
export const chartPageClass = "[--hm-chart-surface:var(--hm-sem-bg-content)]"
/** One sample-data notice per page, instead of a badge and a notice under every chart. */
export function ChartSampleNotice() {
return (
<p className="m-0 text-[length:var(--hm-label-font-size)] leading-[var(--hm-label-line-height)] text-[color:var(--hm-sem-fg-secondary)]">
{sampleDataNotice}
</p>
)
}
/**
* One chart of a Chart page. `toolbar` keeps the example card's control row (Select height, so the charts of a row start at the
* same height); pass `null` for an empty row of that height next to charts that have one.
*/
export function ChartSpecimen({
title,
description,
toolbar,
children,
}: {
title: string
description?: ReactNode
toolbar?: ReactNode
children: ReactNode
}) {
return (
<StorySection title={title} description={description}>
{toolbar !== undefined ? (
<div
data-slot="chart-story-toolbar"
aria-hidden={toolbar === null ? true : undefined}
className="mb-3 flex min-h-[34px] items-center text-sm text-muted-foreground"
>
{toolbar}
</div>
) : null}
{children}
</StorySection>
)
}
// Grid columns (className of StorySectionGrid). Widths are the preview iframe width, which already excludes the Storybook sidebar.
// A third column only from 1200px, where each column keeps about 340px (Radial needs 320px). Rows align at the top; every
// chart keeps its own height. Source order is the one-column (mobile) order. All breakpoints are px (min-[…]): Tailwind does not
// order a rem breakpoint (lg) against a px one, so `lg:grid-cols-2` would win over `min-[1200px]:grid-cols-3`.
const base = "grid-cols-1 items-start *:min-w-0"
export const chartGrid = {
/** Wide charts (Bar): two per row from 1024px. */
pair: `${base} min-[1024px]:grid-cols-2`,
/** Compact round charts (Donut, Pie, Radial): two per row from 1024px, three from 1200px. */
compact: `${base} min-[1024px]:grid-cols-2 min-[1200px]:grid-cols-3`,
/** Radar (four charts): two per row from 1024px, four in one row from 1600px. */
quad: `${base} min-[1024px]:grid-cols-2 min-[1600px]:grid-cols-4`,
/**
* Plain / labelled pairs (Line, Area): two per row from 1024px (each pair in one row); from 1200px three columns that fill
* top to bottom, so the plain styles form the first row and their Dot + Label versions the second.
*/
pairs: `${base} min-[1024px]:grid-cols-2 min-[1200px]:grid-flow-col min-[1200px]:grid-cols-3 min-[1200px]:grid-rows-2`,
} as const
+64 -32
View File
@@ -1,14 +1,14 @@
import { useState } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
DonutActiveExample,
DonutCenterExample,
DonutInteractiveExample,
DonutPlainExample,
DonutSolidExample,
} from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMDonutChart, HMSolidDonutChart } from "@hm-design/chart"
import { sampleDonutStates } from "@hm-design/chart/examples"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@hm-design/ui"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. The four examples share one data set, color mapping and item order.
// Sample data only. The five charts share one data set, color mapping and item order. Same data, props and toolbar text as the
// @hm-design/chart/examples cards; open layout (no card): see chart-story.tsx. Every chart has a toolbar row (Select height),
// so the donuts of a row start at the same height.
const meta = {
title: "Chart/Donut Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -16,29 +16,61 @@ const meta = {
export default meta
type Story = StoryObj<typeof meta>
// Interactive: Select and slice click share one active item (same as DonutInteractiveExample).
function DonutInteractive() {
const [activeId, setActiveId] = useState(sampleDonutStates.activeId)
return (
<ChartSpecimen
title="Interactive"
description="선택 또는 클릭"
toolbar={
<Select value={activeId} onValueChange={setActiveId}>
<SelectTrigger size="medium" aria-label="강조할 업무 상태 선택" className="w-full max-w-64">
<SelectValue />
</SelectTrigger>
<SelectContent>
{sampleDonutStates.data.map(item => (
<SelectItem key={item.id} value={item.id}>{item.label}</SelectItem>
))}
</SelectContent>
</Select>
}
>
<HMDonutChart
data={sampleDonutStates.data}
activeId={activeId}
onActiveChange={setActiveId}
label="업무 상태 도넛 차트, 항목을 선택하거나 조각을 클릭해 강조(예시 데이터)"
/>
</ChartSpecimen>
)
}
export const Donut: Story = {
name: "Donut Chart",
render: () => (
<StoryPage>
<StoryPageHeader title="Donut Chart" />
{/* Same grid as Bar and Line Chart: two per row from 1024px, one below; source order is the mobile order. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Basic">
<DonutPlainExample />
</StorySection>
<StorySection title="Basic · Center Text">
<DonutCenterExample />
</StorySection>
<StorySection title="Active">
<DonutActiveExample />
</StorySection>
<StorySection title="Interactive">
<DonutInteractiveExample />
</StorySection>
<StorySection title="Solid">
<DonutSolidExample />
</StorySection>
</StorySectionGrid>
</StoryPage>
),
render: () => {
const selected = sampleDonutStates.data.find(item => item.id === sampleDonutStates.activeId)
return (
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Donut Chart" />
<ChartSampleNotice />
{/* Two per row from 1024px, three from 1200px, one below; source order is the mobile order. */}
<StorySectionGrid className={chartGrid.compact}>
<ChartSpecimen title="Basic" description="기본" toolbar="중앙 표시 없음">
<HMDonutChart data={sampleDonutStates.data} label="업무 상태 도넛 차트, 가운데 값 없음(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Basic · Center Text" description="전체 합계" toolbar="중앙 표시: 전체 합계">
<HMDonutChart data={sampleDonutStates.data} totalLabel={sampleDonutStates.totalLabel} label="업무 상태 도넛 차트, 가운데 전체 합계(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Active" description="선택된 항목" toolbar={`선택 항목: ${selected?.label ?? ""}`}>
<HMDonutChart data={sampleDonutStates.data} activeId={sampleDonutStates.activeId} label="업무 상태 도넛 차트, 선택된 항목 강조(예시 데이터)" />
</ChartSpecimen>
<DonutInteractive />
<ChartSpecimen title="Solid" description="입체형" toolbar={null}>
<HMSolidDonutChart data={sampleDonutStates.data} totalLabel={sampleDonutStates.totalLabel} label="업무 상태 입체형 도넛 차트, 가운데 전체 합계(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
)
},
}
+30 -33
View File
@@ -1,16 +1,12 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
LineCurveDotLabelExample,
LineCurveExample,
LineStepDotLabelExample,
LineStepExample,
LineStraightColorLabelExample,
LineStraightExample,
} from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMLineChart } from "@hm-design/chart"
import { sampleLineCompare, sampleLinePointColors } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. All six examples share one data set and axis range, so connection styles compare directly: curve, straight
// and step, each as a plain line (left) and with Dots and value labels (right).
// Sample data only. All six charts share one data set and axis range, so connection styles compare directly: curve, straight
// and step, each as a plain line and with Dots and value labels. Same data and props as the @hm-design/chart/examples cards;
// open layout (no card): see chart-story.tsx.
const meta = {
title: "Chart/Line Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -21,29 +17,30 @@ type Story = StoryObj<typeof meta>
export const Line: Story = {
name: "Line Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Line Chart" />
{/* Same grid as Bar Chart: two per row from 1024px, one below. Source order is the mobile order; desktop reads row by row:
Curve | Curve + labels, Straight | Straight + colored labels, Step | Step + labels. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Curve">
<LineCurveExample />
</StorySection>
<StorySection title="Curve · Dot + Label">
<LineCurveDotLabelExample />
</StorySection>
<StorySection title="Straight">
<LineStraightExample />
</StorySection>
<StorySection title="Straight · Color Dot + Label">
<LineStraightColorLabelExample />
</StorySection>
<StorySection title="Step">
<LineStepExample />
</StorySection>
<StorySection title="Step · Dot + Label">
<LineStepDotLabelExample />
</StorySection>
<ChartSampleNotice />
{/* Source order is the mobile order. 1024px: Curve | Curve + labels per row. 1200px: three columns, plain styles in the
first row and their Dot + Label versions below. */}
<StorySectionGrid className={chartGrid.pairs}>
<ChartSpecimen title="Curve" description="monotone · Dot 없음">
<HMLineChart {...sampleLineCompare} curve="monotone" dots={false} label="월별 접수·완료 곡선형 선 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Curve · Dot + Label" description="monotone · Dot과 값 Label">
<HMLineChart {...sampleLineCompare} curve="monotone" pointLabels label="월별 접수·완료 곡선형 Dot·값 라벨 선 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Straight" description="linear · Dot 없음">
<HMLineChart {...sampleLineCompare} curve="linear" dots={false} label="월별 접수·완료 직선형 선 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Straight · Color Dot + Label" description="linear · Dot 개별 색상 + 값 Label">
<HMLineChart {...sampleLinePointColors} curve="linear" pointLabels label="월별 접수·완료 직선형 포인트별 색상 선 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Step" description="step · Dot 없음">
<HMLineChart {...sampleLineCompare} curve="step" dots={false} label="월별 접수·완료 계단형 선 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Step · Dot + Label" description="step · Dot과 값 Label">
<HMLineChart {...sampleLineCompare} curve="step" pointLabels label="월별 접수·완료 계단형 Dot·값 라벨 선 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),
+24 -20
View File
@@ -1,8 +1,11 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import { PieLabelExample, PieLabelListExample, PiePlainExample, PieSolidExample, PieStackedExample } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMPieChart, HMSolidPieChart, HMStackedPieChart } from "@hm-design/chart"
import { samplePie, sampleStackedPie } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. All pies share one item list and color mapping; the stacked pie draws two series as concentric rings.
// Same data and props as the @hm-design/chart/examples cards; open layout (no card): see chart-story.tsx.
const meta = {
title: "Chart/Pie Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -13,25 +16,26 @@ type Story = StoryObj<typeof meta>
export const Pie: Story = {
name: "Pie Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Pie Chart" />
{/* Same grid as Bar, Line and Donut Chart: two per row from 1024px, one below; source order is the mobile order. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Basic">
<PiePlainExample />
</StorySection>
<StorySection title="Label">
<PieLabelExample />
</StorySection>
<StorySection title="Label List">
<PieLabelListExample />
</StorySection>
<StorySection title="Stacked">
<PieStackedExample />
</StorySection>
<StorySection title="Solid">
<PieSolidExample />
</StorySection>
<ChartSampleNotice />
{/* Two per row from 1024px, three from 1200px, one below; source order is the mobile order. */}
<StorySectionGrid className={chartGrid.compact}>
<ChartSpecimen title="Basic" description="기본">
<HMPieChart {...samplePie} label="업무 상태 파이 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Label" description="이름과 값">
<HMPieChart {...samplePie} labels="outside" label="업무 상태 파이 차트, 조각 바깥 이름·값 Label(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Label List" description="조각 안 값">
<HMPieChart {...samplePie} labels="inside" label="업무 상태 파이 차트, 조각 안 값 Label(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Stacked" description="두 시리즈 링">
<HMStackedPieChart {...sampleStackedPie} label="분기별 업무 상태 Stacked 파이 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Solid" description="입체형">
<HMSolidPieChart {...samplePie} label="업무 상태 입체형 파이 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),
+22 -18
View File
@@ -1,8 +1,11 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import { RadarCustomLabelExample, RadarDotExample, RadarLinesOnlyExample, RadarPlainExample } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMRadarChart } from "@hm-design/chart"
import { sampleRadar } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. All radars share one data set (six axes, two series) and the 0-100 axis range.
// Sample data only. All radars share one data set (six axes, two series) and the 0-100 axis range. Same data and props as the
// @hm-design/chart/examples cards; open layout (no card): see chart-story.tsx.
const meta = {
title: "Chart/Radar Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -13,22 +16,23 @@ type Story = StoryObj<typeof meta>
export const Radar: Story = {
name: "Radar Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Radar Chart" />
{/* Same grid as the other Chart pages: two per row from 1024px, one below. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Basic">
<RadarPlainExample />
</StorySection>
<StorySection title="Dot">
<RadarDotExample />
</StorySection>
<StorySection title="Lines Only">
<RadarLinesOnlyExample />
</StorySection>
<StorySection title="Custom Label">
<RadarCustomLabelExample />
</StorySection>
<ChartSampleNotice />
{/* Two per row from 1024px, all four in one row from 1600px, one below. */}
<StorySectionGrid className={chartGrid.quad}>
<ChartSpecimen title="Basic" description="영역">
<HMRadarChart {...sampleRadar} label="단계별 처리 수준 방사형 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Dot" description="축별 Dot">
<HMRadarChart {...sampleRadar} dots label="단계별 처리 수준 방사형 차트, Dot(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Lines Only" description="선만">
<HMRadarChart {...sampleRadar} filled={false} label="단계별 처리 수준 방사형 차트, 선만(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Custom Label" description="축 Label">
<HMRadarChart {...sampleRadar} customLabels label="단계별 처리 수준 방사형 차트, 축 Label(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),
+28 -31
View File
@@ -1,15 +1,11 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
RadialGridExample,
RadialLabelExample,
RadialShapeExample,
RadialSimpleExample,
RadialStackedExample,
RadialTextExample,
} from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySection, StorySectionGrid } from "@/components/story-page"
import { HMRadialBarChart, HMRadialMeterChart, HMRadialStackedChart } from "@hm-design/chart"
import { sampleRadial, sampleRadialShape, sampleRadialStacked, sampleRadialText } from "@hm-design/chart/examples"
import { StoryPage, StoryPageHeader, StorySectionGrid } from "@/components/story-page"
import { ChartSampleNotice, ChartSpecimen, chartGrid, chartPageClass } from "./chart-story"
// Sample data only. One example per official shadcn/ui radial chart (radial-simple, -label, -grid, -text, -shape, -stacked).
// Sample data only. One chart per official shadcn/ui radial chart (radial-simple, -label, -grid, -text, -shape, -stacked).
// Same data and props (angles, radii, tracks) as the @hm-design/chart/examples cards; open layout (no card): see chart-story.tsx.
const meta = {
title: "Chart/Radial Chart",
parameters: { layout: "fullscreen", controls: { disable: true } },
@@ -20,28 +16,29 @@ type Story = StoryObj<typeof meta>
export const Radial: Story = {
name: "Radial Chart",
render: () => (
<StoryPage>
<StoryPage className={chartPageClass}>
<StoryPageHeader title="Radial Chart" />
{/* Same grid as the other Chart pages: two per row from 1024px, one below; source order is the mobile order. */}
<StorySectionGrid className="grid-cols-1 lg:auto-rows-fr lg:grid-cols-2 *:flex *:min-w-0 *:flex-col [&_.sb-page-section-body]:flex-1">
<StorySection title="Basic">
<RadialSimpleExample />
</StorySection>
<StorySection title="Label">
<RadialLabelExample />
</StorySection>
<StorySection title="Grid">
<RadialGridExample />
</StorySection>
<StorySection title="Text">
<RadialTextExample />
</StorySection>
<StorySection title="Shape">
<RadialShapeExample />
</StorySection>
<StorySection title="Stacked">
<RadialStackedExample />
</StorySection>
<ChartSampleNotice />
{/* Two per row from 1024px, three from 1200px, one below; source order is the mobile order. */}
<StorySectionGrid className={chartGrid.compact}>
<ChartSpecimen title="Basic" description="radial-simple · 항목별 막대">
<HMRadialBarChart {...sampleRadial} label="업무 상태 방사형 막대 차트(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Label" description="radial-label · 막대 안 항목명">
<HMRadialBarChart {...sampleRadial} labels startAngle={-90} endAngle={380} label="업무 상태 방사형 막대 차트, 항목명 Label(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Grid" description="radial-grid · 원형 Grid">
<HMRadialBarChart {...sampleRadial} grid label="업무 상태 방사형 막대 차트, Grid(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Text" description="radial-text · 중앙 Text">
<HMRadialMeterChart {...sampleRadialText} startAngle={0} endAngle={250} innerRadius={75} outerRadius={90} trackRadii={[88.5, 76.5]} cornerRadius={10} label="진행 중 건수 방사형 차트, 중앙 Text(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Shape" description="radial-shape · 링 트랙">
<HMRadialMeterChart {...sampleRadialShape} startAngle={0} endAngle={100} innerRadius={50} outerRadius={95} trackRadii={[90.5, 54.5]} label="진행 중 건수 방사형 차트, Shape(예시 데이터)" />
</ChartSpecimen>
<ChartSpecimen title="Stacked" description="radial-stacked · 반원 누적">
<HMRadialStackedChart {...sampleRadialStacked} label="업무 상태 방사형 Stacked 차트(예시 데이터)" />
</ChartSpecimen>
</StorySectionGrid>
</StoryPage>
),