학습 결과
기존 Card와 Button을 조합해 theme 변경과 제품 문구 변경이 서로 다른
파일에서 처리되는 작은 기능을 완성함
이 튜토리얼은 jongminchung 저장소에서 읽기 전용 상태 안내 panel을 만든다고 가정한다. 실제 제품 동작보다 변경 owner를 나누는 감각을 익히는 것이 목표다.
준비
- 저장소 root에서 작업함
apps/web/components.json과DESIGN_SYSTEM.md를 먼저 확인함- 새 registry component를 설치하지 않고 기존
Card와Button을 사용함 - 예시는 Server Component로 유지함
현재 component API를 확인함
공용 primitive의 실제 export와 variant를 source에서 확인함
rg -n "export.*Card|buttonVariants" packages/ui/src/components pnpm exec shadcn info --json -c apps/web이 단계의 목적은 기억에 의존해 새 wrapper나 존재하지 않는 variant를 만들지 않는 데 있음
제품 composition을 앱에 만듦
apps/web이 문구와 상태를 소유하고 공용 primitive는 범용 외형과 접근성을 유지하게 함import { buttonVariants } from "@jongminchung/ui/components/button"; import { Card, CardDescription, CardFooter, CardHeader, CardTitle, } from "@jongminchung/ui/components/card"; import Link from "next/link"; import type { ComponentProps } from "react"; export function DocumentationHealthPanel({ className, ...props }: ComponentProps<typeof Card>) { return ( <Card {...props} className={className}> <CardHeader> <CardTitle>문서 계약이 최신임</CardTitle> <CardDescription> locale pair와 내부 링크가 마지막 build에서 검증됨 </CardDescription> </CardHeader> <CardFooter> <Link className={buttonVariants({ variant: "outline", size: "sm" })} href="/ko/series" > 시리즈 확인 </Link> </CardFooter> </Card> ); }composition은 제품 문구를 소유하고
CardHeader·CardFooter는 내부 spacing을 소유함. button의 focus·size·색상은 primitive가 소유함semantic token으로 시각 의미를 표현함
상태 설명에는
text-muted-foreground, 주 동작에는 기존 button variant를 사용함.text-gray-500,bg-white dark:bg-*와text-white를 추가하지 않음새 색이 필요해 보여도 먼저 기존 역할로 의미를 표현할 수 있는지 확인함. 제품 전체에서 반복되는 새 역할일 때만 light·dark provider, foreground pair와 adapter를 함께 추가함
page는 배치만 결정함
호출 위치에서는 panel의 외부 너비와 grid 위치만 지정함
<DocumentationHealthPanel className="max-w-xl lg:col-span-2" />실제 component가
className을 받는다면 내부 색상이나 padding을 호출부에서 덮어쓰지 않도록 API 설명과 review 기준을 유지함가까운 검사부터 실행함
pnpm run fmt:check pnpm --filter @jongminchung/web run typecheck pnpm --filter @jongminchung/web run test pnpm --filter @jongminchung/web run build화면이 달라졌다면 light·dark와 mobile·wide viewport를 확인함. 공용 primitive 자체를 수정했다면 UI package test와 다른 consumer build까지 범위를 넓힘
완료 상태를 확인함
- 제품 문구와 흐름이
apps/web에 남아 있음 - 공용 primitive에 제품 이름의 variant가 추가되지 않음
- raw palette와 동적 class fragment가 없음
- styling만을 이유로
"use client"가 추가되지 않음 - formatter, typecheck, 관련 test와 build가 통과함
다음 학습
이미 override와 raw color가 퍼진 화면을 정리해야 한다면 기존 화면 감사 방법으로 이동함