Files
HMDesign/src/foundation/reference.tsx
T

47 lines
2.8 KiB
TypeScript

import { useEffect, useRef, useState, type ReactNode } from "react"
import { STORY_KICKER, StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
import "./foundation.css"
export function useResolvedProperties(properties: readonly string[]) {
const [values, setValues] = useState<Record<string, string>>({})
useEffect(() => {
let frame = 0
const read = () => {
cancelAnimationFrame(frame)
frame = requestAnimationFrame(() => {
const style = getComputedStyle(document.documentElement)
const next = Object.fromEntries(properties.map(property => [property, style.getPropertyValue(property).trim()]))
setValues(previous => properties.every(property => previous[property] === next[property]) ? previous : next)
})
}
read()
const observer = new MutationObserver(read)
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["style", "class", "data-hm-theme"] })
window.addEventListener("resize", read)
return () => { observer.disconnect(); window.removeEventListener("resize", read); cancelAnimationFrame(frame) }
}, [properties])
return values
}
// The page frame, title and sections are the common Story page (src/components/story-page.tsx); .hm-foundation styles the reference content.
export function ReferencePage({ title, intro, children }: { title: string; intro: string; children: ReactNode }) {
return <StoryPage className="hm-foundation"><StoryPageHeader kicker={STORY_KICKER.foundation} title={title} description={intro} />{children}</StoryPage>
}
export function ReferenceSection({ title, note, children, id }: { title: string; note: string; children: ReactNode; id?: string }) {
return <StorySection id={id} title={title} description={note}>{children}</StorySection>
}
export function Specimen({ label, size, line, weight }: { label: string; size: string; line: string; weight?: string }) {
const ref = useRef<HTMLDivElement>(null)
const [metrics, setMetrics] = useState("")
useEffect(() => {
let mounted = true
void document.fonts.ready.then(() => {
if (!mounted || !ref.current) return
const style = getComputedStyle(ref.current)
setMetrics(`${style.fontSize} / ${style.lineHeight} / ${style.fontWeight} · letter-spacing: ${style.letterSpacing}`)
})
return () => { mounted = false }
}, [])
return <div className="hm-foundation-specimen" ref={ref} data-typography-sample={label} style={{ fontSize: `var(${size})`, lineHeight: `var(${line})`, fontWeight: weight ? `var(${weight})` : "normal" }}><p lang="ko">가나다라마바사 아자차카타파하 · 한맥 프로젝트</p><p lang="en">ABCDEFGHIJKLMNOPQRSTUVWXYZ<br />abcdefghijklmnopqrstuvwxyz</p><p>0123456789</p><small className="hm-foundation-note" data-typography-metrics>{metrics}</small></div>
}