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

65 lines
3.6 KiB
TypeScript

import { useEffect, useRef, useState } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import { typographyProperties, typographyReferences } from "./reference-data"
import { ReferencePage, ReferenceSection, useResolvedProperties } from "./reference"
type TypographyReference = (typeof typographyReferences)[number]
const weights = [
{ property: "--hm-input-font-weight", label: "Regular" },
{ property: "--hm-font-weight-medium", label: "Medium" },
{ property: "--hm-font-weight-bold", label: "Bold" },
]
// Left table: text styles. Right table: form controls. Together they cover every entry in typographyReferences.
const textLabels = ["Page Header · title", "Card · title", "Page Header · description", "Label"]
const textRows = typographyReferences.filter(item => textLabels.includes(item.label))
const controlRows = typographyReferences.filter(item => !textLabels.includes(item.label))
function SpecimenRow({ label, size, line, weight }: TypographyReference & { weight?: string }) {
const ref = useRef<HTMLDivElement>(null)
const [metrics, setMetrics] = useState({ main: "", spacing: "" })
useEffect(() => {
let mounted = true
void document.fonts.ready.then(() => {
if (!mounted || !ref.current) return
const style = getComputedStyle(ref.current)
setMetrics({ main: `${style.fontSize} / ${style.lineHeight} / ${style.fontWeight}`, spacing: `letter-spacing: ${style.letterSpacing}` })
})
return () => { mounted = false }
}, [])
return <tr>
<th scope="row">{label}</th>
<td><div ref={ref} className="hm-typo-sample" data-typography-sample={label} lang="ko" style={{ fontSize: `var(${size})`, lineHeight: `var(${line})`, fontWeight: weight ? `var(${weight})` : "normal" }}>한맥 Hanmac 0123</div></td>
<td className="hm-typo-metrics" data-typography-metrics><span>{metrics.main}</span><small className="hm-foundation-note">{metrics.spacing}</small></td>
</tr>
}
function SpecimenTable({ rows }: { rows: readonly TypographyReference[] }) {
return <table className="hm-typo-table">
<thead><tr><th scope="col">Component</th><th scope="col">Sample</th><th scope="col">Size / Line / Weight</th></tr></thead>
<tbody>{rows.map(item => <SpecimenRow key={item.label} {...item} />)}</tbody>
</table>
}
function TypographyReferencePage() {
const values = useResolvedProperties(typographyProperties)
return <ReferencePage title="Typography">
<ReferenceSection title="Font Family">
<p className="hm-typo-family"><span>Noto Sans KR → 맑은 고딕 → 시스템 sans-serif</span><code className="hm-foundation-note">--hm-font-family-base: {values["--hm-font-family-base"]}</code></p>
</ReferenceSection>
<ReferenceSection title="Font Weight">
<div className="hm-typo-weights">{weights.map(({ property, label }) => <article className="hm-foundation-card hm-typo-weight" key={property}>
<p className="hm-typo-weight-meta"><strong>{label}</strong> <span className="hm-foundation-note">{values[property]}</span></p>
<p className="hm-typo-weight-preview" style={{ fontWeight: `var(${property})` }}>한맥 Hanmac 0123</p>
<code className="hm-foundation-note">{property}</code>
</article>)}</div>
</ReferenceSection>
<ReferenceSection title="Typography Specimens">
<div className="hm-typo-tables"><SpecimenTable rows={textRows} /><SpecimenTable rows={controlRows} /></div>
</ReferenceSection>
</ReferencePage>
}
const meta = { title: "Foundation/Typography", parameters: { layout: "fullscreen" } } satisfies Meta
export default meta
export const All: StoryObj<typeof meta> = { name: "Typography", render: () => <TypographyReferencePage /> }