"use client"; import { useSyncExternalStore } from "react"; import { COMPONENT_EXAMPLES } from "./component-registry"; import { ComponentEmpty, ComponentView } from "./component-view"; import { ThemeSwitch } from "./theme-switch"; import { TOKEN_GROUPS, TokenView } from "./token-view"; import { useTokenRegistry } from "./use-token-registry"; import styles from "./dev-test.module.scss"; // 선택 상태는 URL 해시가 SSOT다 — 새로고침하거나 링크를 공유해도 보던 섹션이 유지되고, // React state를 따로 두지 않으므로 둘이 어긋날 일이 없다. // 형식: `#token:color` / `#component:button` function subscribeHash(onChange: () => void): () => void { window.addEventListener("hashchange", onChange); return () => window.removeEventListener("hashchange", onChange); } function getHash(): string { return window.location.hash.slice(1); } function getServerHash(): string { return ""; } function useSelection(): { kind: string; id: string } | null { const hash = useSyncExternalStore(subscribeHash, getHash, getServerHash); const [kind, id] = hash.split(":"); return kind && id ? { kind, id } : null; } function select(kind: string, id: string): void { window.location.hash = `${kind}:${id}`; } export function DevTestPage() { const registry = useTokenRegistry(); const selection = useSelection(); if (!registry) { return (

토큰을 읽는 중…

); } // 사이드바에 뜰 토큰 그룹 — 정의된 순서를 우선하고, 목록에 없는 그룹은 뒤에 붙인다. const known = TOKEN_GROUPS.filter((group) => registry[group.key]?.length); const extra = Object.keys(registry) .filter((key) => !TOKEN_GROUPS.some((group) => group.key === key)) .map((key) => ({ key, label: key })); const tokenGroups = [...known, ...extra]; const current = selection ?? { kind: "token", id: tokenGroups[0]?.key ?? "" }; const totalTokens = Object.values(registry).reduce((sum, list) => sum + list.length, 0); return (
{current.kind === "component" ? ( (() => { const example = COMPONENT_EXAMPLES.find((entry) => entry.id === current.id); return example ? : ; })() ) : registry[current.id]?.length ? ( ) : (

선택한 토큰 그룹이 없습니다.

)}
); }