DevTI
DESIGN SYSTEM

COMPONENT LAB

공통/feature 컴포넌트를 회색 와이어프레임 골격으로 단순화해 그리고, 각 영역에 어떤 prop이 채워지는지 점선으로 가리킨다. 왼쪽 설명·인자표·코드와 오른쪽 골격을 함께 보며 "이 prop → 화면의 이 부분" 흐름을 익힌다. 미리보기 우측 상단 와이어프레임 ↔ 실물 토글로 실제 렌더 모습도 바로 확인할 수 있다.

공통 컴포넌트 - src/components/common
01 · COMMON

Button - variant 로 색만 갈아끼우는 버튼

네이티브 <button> 을 감싼 공통 버튼. children 이 글자, variant 가 배경/테두리 색을 정한다. disabled 면 흐려지고 클릭이 막힌다. 나머지 button 속성(onClick·type 등)은 그대로 전달된다.

인자 (props)
  • variant"primary" | "secondary" | "neutral"배경/테두리 색 (기본 primary)
  • childrenReactNode버튼 안 글자/아이콘
  • disabledboolean흐리게 + 클릭 불가
  • ...propsButtonHTMLAttributesonClick·type 등 네이티브 속성
<Button variant="primary" onClick={save}>
  저장
</Button>
<Button>
저장
children
primarysecondaryneutralvariant
비활성disabled
02 · COMMON

Input - label 유무로 묶음/인라인이 갈리는 입력

label 을 주면 위에 라벨을 단 세로 묶음으로, 없으면 <input> 만 렌더해 flex 행 안 인라인 입력으로 쓴다. theme='hud' 면 어두운 글래스 룩(다크 폼·인증). placeholder·value 등은 네이티브 속성으로 전달.

인자 (props)
  • labelstring?있으면 라벨 + 입력 세로 묶음, 없으면 input 단독
  • theme"light" | "hud"밝은 배경 / 어두운 글래스 (기본 light)
  • labelClassNamestring?라벨 색·타이포 덮어쓰기
  • ...propsInputHTMLAttributesplaceholder·value·onChange 등
<Input
  label="닉네임"
  theme="hud"
  placeholder="이름을 입력"
/>
<Input>
label
placeholder
theme
03 · COMMON

Select - options 배열이 그대로 목록이 되는 셀렉트

label 은 위 라벨, options(value·label 쌍 배열)가 펼침 목록이 된다. 선택값/변경은 네이티브 select 속성(value·onChange)으로 다룬다.

인자 (props)
  • labelstring?위 라벨
  • options{ value; label }[]각 항목 = 한 <option>
  • ...propsSelectHTMLAttributesvalue·onChange 등
<Select
  label="정렬"
  value={sort}
  onChange={onSort}
  options={[
    { value: "new", label: "최신순" },
    { value: "like", label: "좋아요순" },
  ]}
/>
<Select>
label
options
04 · COMMON

ColorBadge - color 로 꽉 찬 단색 배지

color(hex) 가 배경을 꽉 채우고, 글자색은 배경 밝기(YIQ)에 따라 검정/흰색으로 자동 대비된다. children 이 라벨. 직무 라벨 등 캐릭터 색을 입힐 때 쓴다.

인자 (props)
  • colorstring배경 hex - 글자색 자동 대비
  • childrenReactNode배지 글자
  • classNamestring?px/py/크기 등 덮어쓰기
<ColorBadge color="#321DFA">
  프론트엔드
</ColorBadge>
<ColorBadge>
프론트엔드color
백엔드← 밝은 배경엔 검정 글자 자동
05 · COMMON

GhostBadge - 반투명 보조 라벨

테두리 + 반투명 채움 + 블러의 직각 배지. 이미지/어두운 배경 위 보조 라벨(연차·성별, 스킬칩)에 쓴다. as='li' 로 주면 목록 항목으로 렌더된다.

인자 (props)
  • childrenReactNode배지 글자
  • as"span" | "li"렌더 태그 (기본 span, 스킬칩 목록은 li)
  • classNamestring?px/py/크기 덮어쓰기
<GhostBadge>3년차</GhostBadge>
<GhostBadge as="li">React</GhostBadge>
<GhostBadge>
3년차여성children
  • React
  • Spring
  • as
06 · COMMON

Spinner - size·color 만 받는 로딩 인디케이터

두 겹으로 도는 SF 풍 로딩 표시. size 로 한 변 px, color 로 호 색을 정한다(기본 밝은 회색). 캐릭터 카드 로딩 땐 그 캐릭터 테마색으로 덮어쓴다.

인자 (props)
  • sizenumber?한 변 px (기본 28)
  • colorstring?호 색 (기본 #d4d4d8)
  • classNamestring?여백 등 추가
<Spinner size={40} color="#321DFA" />
<Spinner>
size
color
07 · COMMON

CountStats - 조회·좋아요·댓글 수 한 줄

카드의 세 숫자를 한 줄로 묶어 보여주는 표시 요소. 세 카운트는 필수, 색·글자크기는 화면마다 달라 className 으로 덮어쓴다.

인자 (props)
  • viewCountnumber조회수
  • likeCountnumber좋아요수
  • commentCountnumber댓글수
  • classNamestring?색·크기 덮어쓰기
<CountStats
  viewCount={card.viewCount}
  likeCount={card.likeCount}
  commentCount={card.commentCount}
/>
<CountStats>
조회
viewCount
likeCount
💬
commentCount
08 · COMMON

Pagination - page·totalPages 로 그리는 페이저

page(0-based)·totalPages 로 버튼을 그리고, 클릭하면 onChange(다음 page) 가 불린다. variant 로 표시 방식(compact·numbered·arrows)을 고른다. 페이지가 1개 이하면 렌더하지 않는다.

인자 (props)
  • pagenumber현재 페이지 (0-based)
  • totalPagesnumber전체 페이지 수
  • onChange(page) => void버튼 클릭 시 호출
  • variant"compact" | "numbered" | "arrows"표시 방식 (기본 compact)
<Pagination
  page={page}
  totalPages={data.totalPages}
  onChange={setPage}
  variant="numbered"
/>
<Pagination>
이전
/
다음
현재/전체pagetotalPages
버튼 클릭onChange
feature 핵심 컴포넌트 - src/features/*
09 · FEATURE

LikeButton - cardId 로 토글하는 좋아요

cardId 가 좋아요를 보낼 대상 카드, initialLikeCount 가 첫 표시 숫자다. 누르는 즉시 ♡↔♥ 와 카운트가 바뀐다(낙관적 업데이트 - 서버 응답을 기다리지 않고, 실패 시 되돌림). 비로그인 시 /login 으로 보낸다. (서버에 '내 좋아요 여부' 조회가 없어 응답/에러코드로 보정)

인자 (props)
  • cardIdnumber좋아요 보낼 대상 카드
  • initialLikeCountnumber첫 표시 좋아요 수
<LikeButton
  cardId={card.id}
  initialLikeCount={card.likeCount}
/>
<LikeButton>
initialLikeCount
클릭 → 서버 호출 대상cardId
누르면 채워짐 (내부 상태)
10 · FEATURE

CommentItem - comment 한 개 + 본인 액션

comment 객체가 작성자·시간·본문을 채운다. isOwner 면 수정(인라인)/삭제 버튼이 붙고, 수정·삭제는 낙관적으로 즉시 반영된다(useUpdateComment·useDeleteComment 가 ['comments', cardId] 캐시를 갱신). BLINDED 상태면 가린 내용으로 보인다.

인자 (props)
  • commentComment작성자·시간·본문·상태(cardId 포함)
  • isOwnerbooleantrue 면 수정/삭제 버튼 노출
<CommentItem
  comment={c}
  isOwner={c.authorId === myId}
/>
<CommentItem>
comment
수정삭제isOwner
수정·삭제 → 낙관적 즉시 반영
11 · FEATURE

StatBars - stat 5종을 가로 막대로

능력치 객체(stat, 각 0~100)를 5개 가로 막대로 쌓는다. accent 가 채움색(미지정 시 흰색). 상세의 레이더와 같은 데이터를 막대로 한 번 더 보여줘 형태를 달리한다.

인자 (props)
  • statDevCardStat능력치 5종 (각 0~100)
  • accentstring?막대 채움색 hex (기본 흰색)
<StatBars stat={card.stat} accent="#321DFA" />
<StatBars>
stat채움색 =accent
12 · FEATURE

CharacterAvatar - character 로 그리는 캐릭터 이미지

character(타입·성별·이미지 URL)로 캐릭터 그림을 그린다. thumbnail=true 면 목록용 썸네일, false 면 상세용 원본. 업로드 이미지 → 고정 일러스트 → MBTI 라벨 박스 순으로 폴백한다.

인자 (props)
  • characterPick<MbtiCharacter, …>타입·성별·이름·이미지 URL
  • thumbnailboolean?true=썸네일(목록) / false=원본(상세)
  • classNamestring?크기·비율 등
<CharacterAvatar
  character={card.character}
  thumbnail
  className="aspect-[3/4] w-40"
/>
<CharacterAvatar>
캐릭터 이미지
character
썸네일/원본 선택thumbnail

업로드 → 고정 일러스트 → 라벨 박스 순 폴백

13 · FEATURE

CardSplashPanel - card·rank 로 그리는 풀스크린 카드

풀스크린 목록의 카드 한 장. card 의 타입·이름·직무·이미지가 도형+일러스트+텍스트로 합쳐지고, rank 가 우상단 큰 순번이 된다. 카드 표면은 비워 어두운 배경이 비친다. 이동은 호버 시 뜨는 VIEW MORE 버튼에만 건다.

인자 (props)
  • cardDevCardSummary타입·이름·직무·이미지 등 요약
  • ranknumber전체 기준 순번 (우상단 큰 숫자)
<CardSplashPanel card={card} rank={i + 1} />
<CardSplashPanel>
04rank
일러스트
이미지·텍스트 데이터card

골격은 실물이 아니라 구조를 단순화한 그림이다 - 정확한 동작/스타일은 각 컴포넌트 파일(src/components/common·src/features/*)이 단일 출처.