Overview
Compare
Inspect
Four social surfaces reached from the profile tab — 친구 목록 (GroupedFeedList of up-to-3 conditional request/friend sections), 친구 찾기 (debounced name search with a per-row relationship state), 업적 (74 achievements grouped and tier-coded), and 연습 기록 (summary + log list with an add-practice sheet).
route · apps/mobile/app/profile/{friends,friends/add,achievements,practice}.tsx → profile/src/{friends,add-friend,achievements-gallery,practice-log}-screen.tsx
grounded in 4 source file(s)
packages/features/profile/src/friends-screen.tsxpackages/features/profile/src/add-friend-screen.tsxpackages/features/profile/src/achievements-gallery-screen.tsxpackages/features/profile/src/practice-log-screen.tsx
Spec
1
Foundations · 디자인 시스템
Spacing · 4px grid
$1 – $4
4 · 8 · 12 · 16 px
$5 – $10
20 · 24 · 32 · 40 · 48 · 64 px
Radius
$2 8 · $3 12 · $4 16 · $7 9999 (pill)
Color · Classic Grass (light)
Surface
$background #F8FBF9 · $card #FFFFFF · $surfaceTertiary #E5FAEA
Brand
$primary #006D37 · $primarySubtle #E5FAEA
Text
$text #0D100E · $textSecondary #4F5851 · $textTertiary #626C64
Border
$border #CAD4CC · $borderSubtle #DFE7E1
Status
$success #14804A · $warning #946200 · $error #B8332E
Badge intents
accent #E0F8F3/#007B6B · warning #FFF4D6/#946200 · error #FDECEC/#B8332E
Court
$courtClay #B84A2E · $courtHard #247BA0 · $courtGreen #006633
Typography · Pretendard
cardTitle · navTitle
16 / 24 · 600 · 17 / 22 · 600
cardBody · cardMeta
14 / 22 · 400 · 13 / 18 · 500
badge · micro
12 / 18 · 600 · 10 / 14 · 600
display Sm/Md/Lg/Xl
20/28 · 28/36 · 36/44 · 48/56 · 700
Primitives · @twomore/ui
Layout
YStack · XStack · Card (default/flat) · Well · Divider
Controls
Pressable · Badge · Icon · PillNav · MainTabShell · BottomCtaBand
Data viz
DateTile · CapacityRing · ProgressBar · AvatarStack · SegmentedDonutChart
Domain cards
SessionCard · ClubCard · VenueHero · SessionCompactRow · member row
Box sizes
AVATAR XS 28 · SM 32 · MD 40 · LG 44 · 2XL 88 · TOUCH_TARGET 44
Rationale
Every part is built from these — one 4px grid, the Pretendard type scale, the Classic-Grass palette, and the shared @twomore/ui primitives + domain cards.
2
친구 · 3-섹션 요청/목록
Structure
Header
HeaderIconButton uses UserPlus (friends-screen.tsx:300-304) → /profile/friends/add
List
GroupedFeedList (friends-screen.tsx:259-280) — NOT tabs; 3 sections rendered only when non-empty: 받은 요청 · 보낸 요청 · 친구 N
Rows
IncomingRow = avatar + name + region-only meta + 거절/수락 side-by-side ActionButtons; OutgoingRow = avatar + name + "대기 중" Badge (NO secondary text line) + single 요청 취소; FriendRow = "ELO n · region" → /profile/[userId]; Incoming/Outgoing titles carry titleLines={NAME_LINES} (2026-09-17) — a long name wraps to 2 lines instead of an ellipsis
3
친구 찾기 · 검색 상태머신
Structure
Search
SearchBar 300ms debounce autoFocus → useProfileSearch (display-name only, no QR/invite)
Row
SearchResultRow (add-friend-screen.tsx:49-104) — AvatarBubble LG + "ELO n · region" + trailing per state: 친구(text) / 요청 보냄(disabled outline) / 친구 추가(ActionButton primary, renamed 2026-09-17 from 친구 신청); title carries titleLines={NAME_LINES} (2-line wrap)
4
업적 · 74개 · 티어 타일
Structure
Groups
one Card per group, ordered attendance→social→growth→exploration→competitive→special (achievement.catalog.ts:57-64)
Row
BARE tier-accent Icon — no colored box (achievements-gallery-screen.tsx:213-215, a plain 28px-wide YStack) + name/desc + locked-quantitative inline ProgressBar + "cur/target" + AchievementStateBadge (달성/준비 중/잠김); locked at TERMINAL_MUTE_OPACITY; hidden+locked → "???"
5
연습 기록 · 요약 + 로그
Structure
Body
summary Card ("{count}회 · 총 {min}분") + FeedList of PracticeRow, each its OWN Card with gaps between (itemSeparator, not one continuous list) — icon bubble + type + date + duration Badge
Add
BottomCtaBand 연습 추가하기 → AddPracticeSheet ModalPanel: PillNav 7 types (서브/랠리/벽치기/레슨/드릴/연습 경기/기타) + PillNav duration (30/60/90/120분) + 취소/저장