UI 기본 요소 — 현장 가이드
모던 앱을 보면서 “저건 도대체 뭐라고 부르는 거지?”라고 생각해 본 적이 있다면 — 이 페이지가 바로 여러분을 위한 것입니다.
여러분이 사용하는 모든 인터페이스는 **UI 기본 요소(primitives)**라고 불리는 놀라울 정도로 적은 수의 재사용 가능한 빌딩 블록으로 만들어져 있습니다. 이것들에는 이름이 있습니다. 때로는 이상한 이름도 있습니다. 하지만 그 비유를 한 번 이해하면, 다시는 예전처럼 볼 수 없게 됩니다.
En Parlant~는 이 모든 것을 기본 제공하는 React 컴포넌트 라이브러리인 Mantine을 사용합니다. 여기 여러분의 현장 가이드가 있습니다.
가구처럼 들리는 것들
섹션 제목: “가구처럼 들리는 것들”Toast
섹션 제목: “Toast”**토스트(Toast)**는 화면 가장자리에서 튀어나와 몇 초간 머물다가 미끄러지듯 사라지는 작은 알림입니다. 토스터에서 식빵이 튀어나오는 것과 비슷한데 — 다만 중력이 반대로 작용해서 결국 다시 들어간다는 점이 다릅니다.
En Parlant~에서 토스트는 우측 하단에 나타납니다(Mantine의 @mantine/notifications 사용). 예를 들면:
- “Database loaded successfully” — 팝
- “TTS voice not configured” — 팝
- “Failed to connect to Lichess” — 팝, 그리고 약간 슬픈 기분이 듭니다
여러분이 요청한 적도 없습니다. 그냥 나타나서 메시지를 전달하고 떠납니다. UI 세계의 전서구 같은 존재입니다.
Card
섹션 제목: “Card”**카드(Card)**는 테두리나 그림자가 있는 직사각형 컨테이너로, 관련 콘텐츠를 하나로 묶어줍니다. 책상 위에 놓인 색인 카드를 상상해 보세요 — 뚜렷한 경계가 있고, 하나의 내용을 담고 있으며, 집어서 옮길 수 있습니다.
En Parlant~에서 카드는 다음과 같은 곳에 사용됩니다:
- 데이터베이스 브라우저의 게임 미리보기 (
GameCard) — 선수 이름, 결과, 날짜 - 보드 포지션 편집기 (
EditingCard) — 커스텀 포지션을 설정할 때 뒤집는 카드 - 데이터베이스 페이지의 데이터베이스 항목 — 각 데이터베이스가 그리드에서 자체 카드를 갖습니다
카드에는 Paper라는 가까운 친척이 있는데, 기본적으로 미술학교를 다닌 카드입니다. 같은 아이디어 — 테두리나 그림자가 있는 컨테이너 — 이지만 의미론적 의미가 더 적습니다. Paper는 단지 “나는 표면이야”라고 말합니다. 분석 패널과 데이터베이스 정보 표시 뒤의 배경으로 나타납니다.
Drawer / Sheet
섹션 제목: “Drawer / Sheet”현재 En Parlant~에서는 사용되지 않지만 알아두면 좋습니다: **드로어(Drawer)**는 화면 가장자리에서 미끄러져 들어오는 패널로, 책상 서랍 같은 것입니다. (그게 다입니다. 비유의 전부입니다. UI 디자이너들이 그날 매우 직설적이었던 모양입니다.)
길을 막는 것들
섹션 제목: “길을 막는 것들”Modal
섹션 제목: “Modal”**모달(Modal)**은 여러분의 주의를 요구하는 팝업 대화상자입니다. 배경을 회색으로 만들고, 다른 일을 하기 전에 이것부터 처리하도록 강제합니다. UI 패턴의 유아 같은 존재입니다 — “지금 당장 나 좀 봐!”
En Parlant~는 진정으로 여러분의 집중이 필요한 순간에 모달을 사용합니다:
- “모든 데이터를 정말 삭제하시겠습니까?” (
ClearDataModal) — 어떤 데이터를 없앨지 선택할 수 있는 체크박스 포함 - “업데이트가 있습니다” (
UpdateModal) — 다운로드 중 진행 바 표시 - “게임 가져오기” (
ImportModal) — PGN 붙여넣기, FEN 입력, 또는 링크 드롭 - “새 레퍼토리 만들기” (
CreateRepertoireModal) — 이름 짓기, 설정하기, 시작하기 - “En Parlant~ 정보” (
About) — 버전 정보, 크레딧, 일반적인 무대 뒤 이야기
모달은 이렇게 말합니다: “이건 대화야. 지금 해야 해.”
Dialog
섹션 제목: “Dialog”**다이얼로그(Dialog)**는 모달의 예의 바른 사촌입니다. Mantine에서는 본질적으로 같은 컴포넌트이지만, UI 디자인 이론에서 다이얼로그는 더 작고 집중적입니다 — 하나의 질문과 답변. “변경 사항을 저장하시겠습니까?” 예 / 아니오. 끝.
En Parlant~는 저장하지 않은 변경 사항을 폐기할지 확인하는 것처럼 빠른 예/아니오 순간에 ConfirmModal을 사용합니다.
나타났다 사라지는 것들
섹션 제목: “나타났다 사라지는 것들”Tooltip
섹션 제목: “Tooltip”**툴팁(Tooltip)**은 무언가 위에 마우스를 올리면 나타나는 작은 라벨입니다. 여러분이 혼란스러운 표정을 지을 때 답을 속삭여주는 친절한 낯선 사람 같은 존재입니다.
툴팁은 En Parlant~ 곳곳에 있습니다. 거의 모든 아이콘 버튼 위에 마우스를 올리면 하나를 볼 수 있습니다:
- ↻ 버튼 위에 마우스를 올리면 → “Reload”
- 잘린 파일 경로 위에 마우스를 올리면 → 전체 경로가 나타남
- 주석 기호 위에 마우스를 올리면 → 해당 기호의 의미
- 분석 패널의 수 위에 마우스를 올리면 → 미니어처 보드 미리보기가 나타남
툴팁은 원조 “매뉴얼 불필요”입니다.
Popover
섹션 제목: “Popover”**팝오버(Popover)**는 대학원을 다닌 툴팁입니다. 단순히 텍스트 라벨을 보여주는 대신, 버튼, 이미지, 심지어 작은 체스보드까지 무엇이든 담을 수 있습니다.
En Parlant~에서 엔진 분석의 수 위에 마우스를 올리면, 팝오버가 해당 포지션의 보드 미리보기를 렌더링합니다. 툴팁인데, 시각 자료를 가져온 것입니다.
Menu
섹션 제목: “Menu”**메뉴(Menu)**는 무언가를 클릭(또는 우클릭)하면 나타나는 액션 목록입니다. 컴퓨팅의 시작부터 사용해왔습니다 — File, Edit, View. 이미 잘 아시죠.
En Parlant~에는 두 가지 종류가 있습니다:
- 상단 바 메뉴 — Mantine의
Menu컴포넌트로 만들어진 클래식한 File / Edit / View 메뉴 바. 오른쪽에 키보드 단축키가 표시됩니다. 연금을 받을 만큼 오래된 디자인 패턴입니다. - 컨텍스트 메뉴 — 게임 트리에서 수를 우클릭하면 Promote Variation, Delete from Here, Copy Line 같은 옵션이 나옵니다. 더 세련된 마감을 위해
mantine-contextmenu라이브러리를 사용합니다.
메뉴에는 자체 하위 용어가 있습니다: Menu.Target(클릭하는 대상), Menu.Dropdown(나타나는 목록), Menu.Item(각 옵션), 그리고 Menu.Divider(“여기서부터 다른 섹션”이라고 말하는 가는 선).
공간을 정리하는 것들
섹션 제목: “공간을 정리하는 것들”Stack & Group
섹션 제목: “Stack & Group”이것들은 레이아웃의 땅콩버터와 젤리입니다.
- Stack은 항목을 세로로 배치합니다 — 하나 위에 하나씩. 책을 쌓는 것처럼.
- Group은 항목을 가로로 배치합니다 — 나란히. 선반에 체스 기물을 줄 세우는 것처럼.
각각 100개 이상의 파일에서 사용됩니다. 앱 전체에서 가장 흔한 컴포넌트입니다. 무언가가 깔끔하게 배치되어 있다면, Stack 또는 Group이 그 역할을 하고 있는 것입니다.
Flex
섹션 제목: “Flex”Flex는 Stack과 Group의 만능 사촌입니다. 항목들이 줄바꿈되거나, 늘어나거나, 줄어들거나, 역순으로 배치되거나, 그 외에 예상대로 작동하지 않아야 할 때, Flex가 CSS Flexbox 모델을 완전히 제어하며 나섭니다.
분석 패널의 수 목록에서 사용됩니다 — 텍스트처럼 줄바꿈되며 흐르는 수의 시퀀스가 보이시나요? 바로 Flex가 무거운 짐을 지고 있는 것입니다.
Box
섹션 제목: “Box”Box는 탑햇을 쓴 <div>입니다. 그 자체로는 아무것도 하지 않습니다 — 그냥 일반적인 컨테이너입니다. 하지만 Mantine의 스타일링 props를 받기 때문에, “이 다른 것 주위에 뭔가가 필요해”라는 상황에서 엄청나게 유용한 래퍼가 됩니다.
Box는 150개 이상의 파일에서 사용됩니다. 컴포넌트 라이브러리의 만능 테이프입니다.
Center
섹션 제목: “Center”이름 그대로의 역할을 합니다. 무언가를 가운데에 놓습니다. 가로로. 세로로. 둘 다. 끝.
빈 상태에서 나타납니다 — 연결된 계정이 없거나, 로드된 데이터베이스가 없거나, 아직 데이터가 없을 때. 큰 아이콘, 메시지, 그리고 완벽하게 위치를 잡아주는 Center. 중앙에서 벗어난 빈 상태를 좋아하는 사람은 없습니다.
SimpleGrid
섹션 제목: “SimpleGrid”심플한 그리드입니다. 몇 개의 열인지 알려주면 창 크기가 변할 때 리플로우되는 깔끔한 그리드로 카드를 배치합니다. 데이터베이스 페이지에서 반응형 그리드로 데이터베이스 카드를 배치하는 데 사용됩니다.
ScrollArea
섹션 제목: “ScrollArea”콘텐츠가 넘칠 때 스크롤되는 컨테이너입니다. CSS overflow: auto로 공짜일 것 같지만 — 어느 정도는 맞습니다 — ScrollArea는 스타일이 적용된 스크롤바, 관성 스크롤, 오버플로우 감지를 추가합니다. 게임 트리 패널, 분석 라인, 그리고 콘텐츠가 상자보다 커질 수 있는 모든 곳을 감쌉니다.
AppShell
섹션 제목: “AppShell”AppShell은 마스터 레이아웃 — 전체 애플리케이션의 골격입니다. 헤더가 어디에 가고, 사이드바가 어디에 가고, 메인 콘텐츠가 어디에 들어가는지 정의합니다. 다른 모든 것이 그 안에 중첩됩니다.
한 번만 사용합니다. 집의 기초와 같습니다.
Portal
섹션 제목: “Portal”Portal은 마법의 웜홀입니다. 컴포넌트를 DOM 트리에서 정상적인 위치가 아닌 다른 곳에 — 보통 문서의 루트에 — 렌더링합니다. 이것이 바로 팝오버와 보드 미리보기가 overflow: hidden이 설정된 부모 컨테이너에 의해 잘리지 않는 이유입니다.
Portal은 절대 보이지 않습니다. 그 효과만 보일 뿐입니다. UI 컴포넌트의 무대 스태프입니다.
상호작용하는 것들
섹션 제목: “상호작용하는 것들”Button
섹션 제목: “Button”텍스트가 있는 클릭 가능한 직사각형. 이건 아시죠. Mantine에서 버튼은 **변형(variants)**으로 제공됩니다:
- filled — 단색, 높은 강조. “나를 클릭해, 나는 중요해.”
- outline — 테두리만. “나는 옵션이야, 하지만 부담 없어.”
- subtle — 거의 보이지 않는. “필요하면 여기 있어.”
- default — 중립적인 중간 지대.
En Parlant~는 150개 이상의 파일에서 이 모든 것을 사용합니다. 가장 흔한 패턴: 모달 하단의 Group에 배치된 버튼들 — “Cancel”(subtle)과 “Confirm”(filled). 클래식합니다.
ActionIcon
섹션 제목: “ActionIcon”ActionIcon은 텍스트 라벨을 포기하고 아이콘 라이프스타일에 완전히 전념한 버튼입니다. 컴팩트하고, 정사각형이며, 목적을 전달하기 위해 아이콘(그리고 툴팁)에 의존합니다.
툴바 버튼, 패널 컨트롤, 닫기 버튼 — 모두 ActionIcon입니다. 액션을 제공하는 가장 공간 효율적인 방법입니다.
Switch
섹션 제목: “Switch”Switch는 작은 전등 스위치처럼 생긴 토글입니다. 왼쪽으로 넘기고, 오른쪽으로 넘기고. 켜기. 끄기.
설정에서 스위치는 이진 선택을 제어합니다:
- 소리 켜기/끄기
- TTS 내레이션 활성화/비활성화
- 다크 모드 / 라이트 모드
물리적 비유가 너무 뛰어나서 할머니, 할아버지도 이해하십니다.
Slider
섹션 제목: “Slider”Slider는 값을 선택하기 위해 핸들을 앞뒤로 드래그하는 트랙입니다. 납작해진 볼륨 노브 같은 것입니다.
En Parlant~에서 슬라이더는 다음에 사용됩니다:
- 글꼴 크기 — 드래그하여 조절
- 볼륨 — 드래그하여 조절 (당연하죠)
- CPU 코어 — 엔진이 몇 개의 코어를 사용할지?
- 해시 메모리 — 엔진의 해시 테이블에 얼마나 많은 RAM을?
범위를 선택하기 위한 핸들이 두 개인 RangeSlider도 있습니다 — Elo 레이팅(예: 2000–2200)과 기간으로 게임을 필터링하는 데 사용됩니다.
SegmentedControl
섹션 제목: “SegmentedControl”정확히 하나만 선택되는 버튼 행입니다. 자동차 라디오 프리셋 같습니다 — 하나를 누르면 나머지가 빠집니다.
다음 사이의 전환에 사용됩니다:
- 분석 차트에서 센티폰 평가 vs. 승/무/패 퍼센티지
- 다른 수 표기 형식
- 엔진 라인 수
Checkbox & Select
섹션 제목: “Checkbox & Select”이것들은 아시죠. 체크박스는 “해당하는 것 모두 선택”, Select 드롭다운은 “이 목록에서 하나 선택”. 앱 전체의 설정, 필터, 폼에서 나타납니다. Clear Data 모달에는 특히 만족스러운 체크박스 세트가 있어서 스스로의 파괴를 선택할 수 있습니다.
Autocomplete
섹션 제목: “Autocomplete”입력하는 동안 완성을 제안하는 텍스트 입력란입니다. 데이터베이스 브라우저의 선수 검색에서 사용됩니다 — 이름을 입력하기 시작하면 일치하는 선수가 아래에 나타납니다.
FileInput & DateInput
섹션 제목: “FileInput & DateInput”FileInput은 클릭하면 파일 선택기를 엽니다 — PGN 파일을 로드하기 위한 import 모달에서 사용됩니다. DateInput은 날짜를 선택하기 위한 캘린더를 팝업합니다 — 날짜별 게임 필터링에 사용됩니다. 덜 정밀한 선택이 필요할 때를 위한 MonthPickerInput과 YearPickerInput도 있습니다(Lichess 데이터베이스의 월별 필터링, Masters 데이터베이스의 연별 필터링).
진행 상황을 보여주는 것들
섹션 제목: “진행 상황을 보여주는 것들”Progress Bar
섹션 제목: “Progress Bar”무언가가 얼마나 진행되었는지 보여주기 위해 왼쪽에서 오른쪽으로 채워지는 가로 막대입니다. 앱 업데이트(다운로드 진행률) 중에 사용되며 — 더 창의적으로 — 분석 패널에서 승/무/패 확률을 표시하는 데 사용됩니다. 세 가지 색상 섹션(흰색, 회색, 검은색)이 비례적으로 막대를 채웁니다. 진행 표시기로 위장한 작은 막대 차트입니다.
Loader
섹션 제목: “Loader”Loader는 “작업 중이에요, 잠깐만요”라고 말하는 회전 애니메이션입니다. 데이터베이스가 로딩 중이거나, 선수 통계를 가져오는 중이거나, 비동기 작업이 진행 중일 때 나타납니다.
Skeleton
섹션 제목: “Skeleton”Skeleton은 아직 로드되지 않은 콘텐츠의 모양을 모방하는 회색 플레이스홀더입니다. 빈 화면이나 스피너 대신, 카드와 텍스트가 들어갈 곳의 유령 윤곽선이 보입니다. 로딩 상태의 건축 설계도 같은 것입니다 — “진짜 가구는 오는 중이에요.”
데이터베이스 페이지에서 카드 그리드가 로드되는 동안 스켈레톤을 사용합니다. 스피너만 있는 것보다 훨씬 우아합니다.
LoadingOverlay
섹션 제목: “LoadingOverlay”로딩 중인 컴포넌트 위에 덮어씌우는 반투명 블랭킷입니다. 분석 차트에서 사용됩니다 — 오버레이 뒤로 차트를 여전히 볼 수 있지만 어둡게 처리되고, 위에 스피너가 있습니다. “아직 여기 있어요, 업데이트 중일 뿐이에요.”
라벨을 붙이는 것들
섹션 제목: “라벨을 붙이는 것들”Badge
섹션 제목: “Badge”Badge는 작은 색상 라벨입니다 — 컨퍼런스의 명찰처럼. En Parlant~에서 SpeedBadge 컴포넌트는 색상 코딩과 함께 시간 컨트롤을 표시하기 위해 뱃지를 사용합니다:
- 🩷 핑크 — UltraBullet
- 🔴 빨강 — Bullet
- 🟠 주황 — Blitz
- 🟢 초록 — Rapid
- 🔵 파랑 — Classical
- 🟣 보라 — Correspondence
각 뱃지는 작고, 다채롭고, 게임 속도를 한눈에 즉시 전달합니다.
Kbd
섹션 제목: “Kbd”keyboard의 줄임말입니다. 특유의 돌출된 키 스타일로 키보드 키를 표시합니다. 키 바인딩 설정에서 Ctrl + Z 같은 것을 보여주는 데 사용됩니다. 여러분 키보드의 실제 물리적 키를 CSS로 재현한 것입니다. 유쾌한 스큐어모피즘입니다.
분리하고 접는 것들
섹션 제목: “분리하고 접는 것들”Divider
섹션 제목: “Divider”섹션을 구분하는 가로선입니다. 그게 다입니다. 선입니다. 하지만 스타일이 적용된 선이며, 선택적으로 가운데에 텍스트 라벨을 넣을 수 있습니다 — import 모달에서 “paste a PGN”과 “enter a FEN”을 구분하는 ”— OR —” 구분선처럼.
30개 이상의 파일에서 Divider를 사용합니다. 알고 보면, 분리해야 할 것들이 정말 많습니다.
Collapse
섹션 제목: “Collapse”Collapse는 부드러운 애니메이션으로 펼쳐지고 접히는 섹션입니다. 클릭하면 드러나고, 클릭하면 숨겨집니다. 데이터베이스 필터 옵션에서 사용됩니다 — 항상 모든 필터를 볼 필요는 없기 때문에, 원할 때까지 Collapse 뒤에 숨겨둡니다.
화려한 것들
섹션 제목: “화려한 것들”RichTextEditor
섹션 제목: “RichTextEditor”TipTap 위에 구축된 완전한 위지위그(WYSIWYG) 텍스트 편집기입니다. 굵게, 기울임, 목록 등 다양한 기능이 있습니다. 게임 주석 작성에 사용됩니다 — 어떤 수가 왜 훌륭했는지 또는 끔찍했는지 설명하기 위해 추가하는 해설 노트입니다.
이 기본 요소는 단일 세포보다는 복합 유기체에 가깝습니다. 내부적으로는 TipTap + ProseMirror + Mantine 스타일링입니다. 하지만 사용자 관점에서는 서식이 작동하는 텍스트 상자일 뿐입니다.
AreaChart
섹션 제목: “AreaChart”@mantine/charts(Recharts를 래핑)의 AreaChart는 평가 그래프를 구동합니다 — 분석 패널 하단에 흐르는 파형입니다. 중앙선 위의 흰색 영역은 백이 우세함을, 아래의 검은색은 흑이 우세함을 의미합니다.
차트의 어느 지점이든 클릭하면 해당 수로 이동할 수 있습니다. 인터랙티브 데이터 시각화와 체스 분석의 만남입니다. 게임 단계(오프닝 → 미들게임 → 엔드게임)를 표시하는 커스텀 툴팁과 참조선까지 있습니다.
DataTable
섹션 제목: “DataTable”mantine-datatable 라이브러리를 통해 — 정렬, 페이지네이션, 행 선택, 필터링 기능을 갖춘 완전한 기능의 데이터 테이블입니다. 데이터베이스 브라우저의 게임 목록, 선수 목록, 토너먼트 목록을 구동합니다. 자신이 체스 앱에 있다는 것을 아는 스프레드시트입니다.
보이지 않는 것들
섹션 제목: “보이지 않는 것들”일부 기본 요소는 스스로 가시적인 것을 렌더링하지 않지만 다른 모든 것이 작동하게 합니다:
- MantineProvider — 전체 앱을 감싸고 테마(색상, 다크 모드, 컴포넌트 기본값)를 제공합니다
- Portal — 렌더링된 콘텐츠를 DOM의 다른 부분으로 텔레포트합니다
- useHotkeys — 키보드 단축키를 연결하는 훅(컴포넌트가 아님)
- useForm — 폼 상태, 유효성 검사, 에러 처리를 관리합니다
- useDebouncedValue — 검색을 실행하기 전에 입력이 멈출 때까지 기다립니다. 예의 바른 훅입니다.
전체 목록
섹션 제목: “전체 목록”참고용으로, En Parlant~에서 사용되는 모든 기본 요소 패밀리를 기능별로 그룹화했습니다:
| 카테고리 | 기본 요소 |
|---|---|
| 레이아웃 | AppShell, Box, Center, Flex, Group, Stack, SimpleGrid, ScrollArea, Portal |
| 표면 | Card, Paper |
| 오버레이 | Modal, Tooltip, Popover, Menu, ContextMenu, LoadingOverlay |
| 알림 | Toast (@mantine/notifications 사용) |
| 버튼 | Button, ActionIcon, CloseButton, ThemeIcon |
| 입력 | TextInput, Textarea, NumberInput, Select, Autocomplete, Checkbox, Switch, Slider, RangeSlider, SegmentedControl, FileInput, DateInput, MonthPickerInput, YearPickerInput |
| 데이터 표시 | Table, DataTable, Badge, Code, Kbd, Rating, Image |
| 타이포그래피 | Text, Title, Anchor |
| 진행 상황 | Progress, Loader, Skeleton |
| 구조 | Divider, Collapse |
| 리치 콘텐츠 | RichTextEditor (TipTap), AreaChart (Recharts) |
| 테마 | MantineProvider, createTheme, useColorScheme |
| 훅 | useForm, useHotkeys, useToggle, useDebouncedValue, useClickOutside, useElementSize |
모두 Mantine v8와 해당 에코시스템 패키지에서 제공됩니다: @mantine/core, @mantine/notifications, @mantine/dates, @mantine/charts, @mantine/form, @mantine/tiptap, mantine-datatable, 그리고 mantine-contextmenu.
이제 아셨습니다
섹션 제목: “이제 아셨습니다”다음에 화면 구석에서 작은 메시지가 미끄러져 올라오는 걸 보면 — 그게 토스트입니다. 게임 미리보기를 둘러싼 직사각형 — 그게 카드입니다. 콘텐츠가 로드되기 전에 깜빡이는 회색 덩어리들 — 그게 스켈레톤입니다.
이름을 배우고 나면, 어디서나 보이기 시작합니다. 모든 앱. 모든 웹사이트. 같은 몇십 개의 기본 요소가 수천 가지 다른 방식으로 재배열되어 있습니다.
끝까지 레고입니다.