File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
"use client";
import { useState, type ReactNode } from "react";
import { FoxButton } from "../core/components/fox-button";
import { FoxTextButton } from "../core/components/fox-text-button";
import { FoxLinkButton } from "../core/components/fox-link-button";
import { FoxIconButton } from "../core/components/fox-icon-button";
export interface ComponentExample {
/** 해시 링크에 쓰이는 kebab-case 식별자. */
id: string;
name: string;
description?: string;
/** 눈으로 비교해야 하는 조합을 빠짐없이 넣는다 — 예제가 곧 회귀 확인 수단이다. */
variants: { label: string; node: ReactNode }[];
}
// 자리 확인용 도형. `currentColor`로 그려야 계열별 색이 입혀진다.
function DemoIcon() {
return (
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
<path d="M6 3l5 5-5 5" />
</svg>
);
}
function DemoStar() {
return (
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
<path d="M8 1.6l1.9 4 4.4.6-3.2 3 .8 4.3L8 11.5l-3.9 2 .8-4.3-3.2-3 4.4-.6z" />
</svg>
);
}
// overlay 계열은 어두운 반투명 배경이라 밝은 바탕 위에서는 대비를 볼 수 없다.
function OnPhoto({ children }: { children: ReactNode }) {
return (
<span
style={{
display: "inline-flex",
gap: "0.8rem",
padding: "0.8rem",
borderRadius: "0.8rem",
backgroundImage: "url(https://picsum.photos/seed/picsum/200/300)",
backgroundSize: "cover",
}}
>
{children}
</span>
);
}
// active는 호출부가 소유하므로 켜고 끄는 걸 보려면 예제가 상태를 들고 있어야 한다.
function IconToggleDemo() {
const [on, setOn] = useState(false);
return (
<>
<FoxIconButton
size="md"
type="default"
label={on ? "즐겨찾기 해제" : "즐겨찾기"}
icon={<DemoStar />}
active={on}
onAction={() => setOn((prev) => !prev)}
/>
<FoxIconButton
size="md"
type="ghost"
label={on ? "즐겨찾기 해제" : "즐겨찾기"}
icon={<DemoStar />}
active={on}
onAction={() => setOn((prev) => !prev)}
/>
<OnPhoto>
<FoxIconButton
size="md"
type="overlay"
label={on ? "즐겨찾기 해제" : "즐겨찾기"}
icon={<DemoStar />}
active={on}
onAction={() => setOn((prev) => !prev)}
/>
</OnPhoto>
</>
);
}
/** 컴포넌트를 만들 때마다 항목 하나를 추가한다 — 다른 파일은 고치지 않는다. */
export const COMPONENT_EXAMPLES: ComponentExample[] = [
{
id: "fox-button",
name: "FoxButton",
description:
"Figma 시안(관리자페이지 node 390:439)을 토큰만으로 옮겼습니다. 너비는 내용에 따라 가변이고 높이만 고정입니다. hover·pressed는 마우스를 올리거나 눌러 확인하세요. error 계열은 시안 미정이라 비어 있습니다.",
variants: [
{
label: "계열 (type) — hover·pressed 확인 가능",
node: (
<>
<FoxButton size="md" label="default" />
<FoxButton size="md" type="primary" label="primary" />
<FoxButton size="md" type="secondary" label="secondary" />
<FoxButton size="md" type="error" label="error (시안 미정)" />
</>
),
},
{
label: "크기 (size)",
node: (
<>
<FoxButton size="lg" label="lg" />
<FoxButton size="md" label="md" />
<FoxButton size="sm" label="sm" />
<FoxButton size="xsm" label="xsm" />
</>
),
},
{
label: "아이콘",
node: (
<>
<FoxButton size="md" label="leading" leadingIcon={<DemoIcon />} />
<FoxButton size="md" label="trailing" trailingIcon={<DemoIcon />} />
<FoxButton size="md" label="both" leadingIcon={<DemoIcon />} trailingIcon={<DemoIcon />} />
</>
),
},
{
label: "상태 — disabled / loading (둘 다 클릭이 막힌다)",
node: (
<>
<FoxButton size="md" label="normal" onAction={() => undefined} />
<FoxButton size="md" label="disabled" disabled />
<FoxButton size="md" label="loading" loading />
<FoxButton size="md" label="loading + icon" loading leadingIcon={<DemoIcon />} />
</>
),
},
{
label: "fullWidth",
node: <FoxButton size="md" label="fullWidth" fullWidth />,
},
{
label: "htmlType — 폼 안에서의 역할",
node: (
<>
<FoxButton size="md" label="button (기본)" />
<FoxButton size="md" label="submit" htmlType="submit" />
<FoxButton size="md" label="reset" htmlType="reset" />
</>
),
},
{
label: "hidden — 렌더되지 않는다(아래는 비어 있는 것이 정상)",
node: <FoxButton size="md" label="hidden" hidden />,
},
],
},
{
id: "fox-text-button",
name: "FoxTextButton",
description:
"Figma 시안(btn-txt, 컴포넌트 세트 106:2468)을 토큰만으로 옮겼습니다. 높이를 고정하지 않고 패딩과 line-height로만 크기를 잡습니다. lg만 상하 패딩과 간격이 한 단계 넓습니다.",
variants: [
{
label: "계열 (type) — primary는 굵기가 한 단계 더 굵다",
node: (
<>
<FoxTextButton size="md" type="primary" label="primary" />
<FoxTextButton size="md" type="secondary" label="secondary" />
</>
),
},
{
label: "크기 (size)",
node: (
<>
<FoxTextButton size="lg" label="lg" />
<FoxTextButton size="md" label="md" />
<FoxTextButton size="sm" label="sm" />
<FoxTextButton size="xsm" label="xsm" />
</>
),
},
{
label: "아이콘",
node: (
<>
<FoxTextButton size="md" label="leading" leadingIcon={<DemoIcon />} />
<FoxTextButton size="md" label="trailing" trailingIcon={<DemoIcon />} />
<FoxTextButton
size="md"
label="both"
leadingIcon={<DemoIcon />}
trailingIcon={<DemoIcon />}
/>
</>
),
},
{
label: "상태 — disabled",
node: (
<>
<FoxTextButton size="md" label="normal" onAction={() => undefined} />
<FoxTextButton size="md" label="disabled" disabled />
<FoxTextButton size="md" type="secondary" label="disabled (secondary)" disabled />
</>
),
},
],
},
{
id: "fox-link-button",
name: "FoxLinkButton",
description:
"Figma 시안(btn-lnk, 컴포넌트 세트 107:207)을 토큰만으로 옮겼습니다. href를 주면 <a>, 없으면 <button>으로 렌더합니다. 방문 색은 브라우저가 실제 방문 기록으로만 켜므로 아래에서 링크를 한 번 눌러 돌아오면 색이 바뀝니다. tertiary만 평소에 밑줄이 없고 hover에서만 생깁니다.",
variants: [
{
label: "계열 (type) — hover하면 tertiary에 밑줄이 생긴다",
node: (
<>
<FoxLinkButton size="md" type="primary" label="primary" href="https://example.com" />
<FoxLinkButton
size="md"
type="secondary"
label="secondary"
href="https://example.com"
/>
<FoxLinkButton size="md" type="tertiary" label="tertiary" href="https://example.com" />
</>
),
},
{
label: "크기 (size)",
node: (
<>
<FoxLinkButton size="lg" label="lg" href="https://example.com" />
<FoxLinkButton size="md" label="md" href="https://example.com" />
<FoxLinkButton size="sm" label="sm" href="https://example.com" />
</>
),
},
{
label: "아이콘 — 라벨 뒤에만 놓인다",
node: (
<>
<FoxLinkButton size="lg" label="lg" href="https://example.com" icon={<DemoIcon />} />
<FoxLinkButton size="md" label="md" href="https://example.com" icon={<DemoIcon />} />
<FoxLinkButton size="sm" label="sm" href="https://example.com" icon={<DemoIcon />} />
</>
),
},
{
label: "href 없음 — <button>으로 렌더된다(방문 색이 켜지지 않는다)",
node: (
<>
<FoxLinkButton size="md" label="onAction만" onAction={() => undefined} />
<FoxLinkButton size="md" type="tertiary" label="tertiary" onAction={() => undefined} />
</>
),
},
{
label: "상태 — disabled (앵커는 href가 빠져 포커스·클릭이 함께 사라진다)",
node: (
<>
<FoxLinkButton size="md" label="disabled (a)" href="https://example.com" disabled />
<FoxLinkButton size="md" label="disabled (button)" disabled />
</>
),
},
],
},
{
id: "fox-icon-button",
name: "FoxIconButton",
description:
"Figma 시안(btn-ico 400:6312 + btn-ico-toggle 404:5247)을 토큰만으로 옮겼습니다. 두 시안이 계열·크기·모양이 같고 켜짐 상태만 달라 한 컴포넌트로 합쳤습니다 — active를 주면 토글(aria-pressed)이 됩니다. ghost는 테두리가 없는 대신 아이콘이 한 단계 큽니다.",
variants: [
{
label: "계열 (type) — overlay는 사진 위에서 봐야 한다",
node: (
<>
<FoxIconButton size="md" type="default" label="default" icon={<DemoIcon />} />
<FoxIconButton size="md" type="ghost" label="ghost" icon={<DemoIcon />} />
<OnPhoto>
<FoxIconButton size="md" type="overlay" label="overlay" icon={<DemoIcon />} />
</OnPhoto>
</>
),
},
{
label: "크기 (size) — default 계열",
node: (
<>
<FoxIconButton size="lg" label="lg" icon={<DemoIcon />} />
<FoxIconButton size="md" label="md" icon={<DemoIcon />} />
<FoxIconButton size="sm" label="sm" icon={<DemoIcon />} />
<FoxIconButton size="xsm" label="xsm" icon={<DemoIcon />} />
</>
),
},
{
label: "크기 (size) — ghost는 같은 상자에 아이콘만 한 단계 크다",
node: (
<>
<FoxIconButton size="lg" type="ghost" label="lg" icon={<DemoIcon />} />
<FoxIconButton size="md" type="ghost" label="md" icon={<DemoIcon />} />
<FoxIconButton size="sm" type="ghost" label="sm" icon={<DemoIcon />} />
<FoxIconButton size="xsm" type="ghost" label="xsm" icon={<DemoIcon />} />
</>
),
},
{
label: "토글 — 눌러서 켜고 끈다 (active)",
node: <IconToggleDemo />,
},
{
label: "토글 켜짐 고정 — 계열별 색 비교",
node: (
<>
<FoxIconButton size="md" type="default" label="on" icon={<DemoStar />} active />
<FoxIconButton size="md" type="ghost" label="on" icon={<DemoStar />} active />
<OnPhoto>
<FoxIconButton size="md" type="overlay" label="on" icon={<DemoStar />} active />
</OnPhoto>
</>
),
},
{
label: "상태 — disabled (켜짐보다 우선한다)",
node: (
<>
<FoxIconButton size="md" label="disabled" icon={<DemoIcon />} disabled />
<FoxIconButton size="md" type="ghost" label="disabled" icon={<DemoIcon />} disabled />
<FoxIconButton
size="md"
type="overlay"
label="disabled"
icon={<DemoIcon />}
disabled
/>
<FoxIconButton
size="md"
label="active + disabled"
icon={<DemoStar />}
active
disabled
/>
</>
),
},
],
},
];