유지보수 가능한 Tailwind와 shadcn/ui 기능 만들기
기존 primitive와 semantic token을 사용해 상태 안내 panel을 만드는 학습 과정을 안내합니다.
학습 결과
기존 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가 퍼진 화면을 정리해야 한다면 기존 화면 감사 방법으로 이동함