Files
HMDesign/src/foundation/color.stories.tsx
T

47 lines
2.8 KiB
TypeScript

import type { Meta, StoryObj } from "@storybook/react-vite"
import { runtimeThemeContract, type RuntimeThemeToken } from "@hm-design/ui/theme"
import { ReferencePage, ReferenceSection, useResolvedProperties } from "./reference"
// Keep the confirmed eight stages; presentation changes never alter Theme values.
const stages = ["light-4", "light-3", "light-2", "light-1", "default", "dark-1", "dark-2", "dark-3"] as const
const palettes = [
{ name: "한맥그린", prefix: "green" },
{ name: "한맥브라운", prefix: "brown" },
{ name: "한맥오렌지", prefix: "orange" },
] as const
type ColorStage = typeof stages[number]
type PalettePrefix = typeof palettes[number]["prefix"]
const stageLabel = (stage: ColorStage) => stage === "default" ? "Default · 기본색" : stage.replaceAll("-", " ").replace(/^./, letter => letter.toUpperCase())
const paletteToken = (prefix: PalettePrefix, stage: ColorStage) => `color.palette.${prefix}-${stage}` as RuntimeThemeToken
const colorProperties = palettes.flatMap(palette => stages.map(stage => runtimeThemeContract[paletteToken(palette.prefix, stage)].property))
// Read the current CSS value rather than duplicating Theme HEX values.
function colorHex(value: string | undefined) {
if (value === undefined) return "확인 중"
if (!value) return "미정의"
if (/^#[\da-f]{6}$/i.test(value)) return value.toUpperCase()
const rgb = value.match(/^rgb\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)\s*\)$/)
return rgb ? `#${rgb.slice(1).map(channel => Number(channel).toString(16).padStart(2, "0")).join("").toUpperCase()}` : value
}
function ColorChip({ prefix, stage, values }: { prefix: PalettePrefix; stage: ColorStage; values: Record<string, string> }) {
const token = paletteToken(prefix, stage)
const definition = runtimeThemeContract[token]
return <article className="hm-brand-color-chip" data-color-stage={stage} data-color-token={token} data-base={stage === "default" ? "" : undefined}>
<div className="hm-foundation-swatch" style={{ background: `var(${definition.property})` }} />
<h3>{stageLabel(stage)}</h3><p data-color-value>{colorHex(values[definition.property])}</p>
</article>
}
function ColorReferencePage() {
const values = useResolvedProperties(colorProperties)
return <ReferencePage title="Color" intro="한맥 브랜드 컬러">
{palettes.map(palette => <ReferenceSection key={palette.name} title={palette.name} note="">
<div className="hm-brand-color-row">{stages.map(stage => <ColorChip key={stage} prefix={palette.prefix} stage={stage} values={values} />)}</div>
</ReferenceSection>)}
</ReferencePage>
}
const meta = { title: "Foundation/Color", parameters: { layout: "fullscreen" } } satisfies Meta
export default meta
export const All: StoryObj<typeof meta> = { name: "Color", render: () => <ColorReferencePage /> }