이 페이지에서
JunkBox libs/shared-ui 가이드
1. 라이브러리 역할
shared-ui는 JunkBox 전역 UI 자산 라이브러리임.
공통 Tailwind preset, 공통 스타일 산출물, 공용 폰트 자산, 공통 템플릿, 공통 프런트 헬퍼 자산, 공통 React 유틸 계층을 제공함.
모든 앱과 화면이 동일한 공통 UI 자산을 재사용할 수 있도록 설계됨.
2. 설계 목표
앱별 CSS나 화면별 CSS 없이 공통 자산만으로 화면을 조합할 수 있게 함.
서버 렌더링 화면과 프런트 번들이 같은 스타일 자산과 설계 토큰을 공유하도록 함.
시각 원칙과 상호작용 원칙 자체는 docs/junkbox/common/guide-jb-common-ui.md를 단일 기준으로 따름.
3. 자산 구조
3.1 주요 파일
package.json은 스타일 빌드 의존성과 스크립트를 정의함.
tailwind.config.cjs는 로컬 빌드 진입점임.
src/junkbox_shared_ui/tailwind.preset.cjs는 앱 공통 preset임.
src/styles/hub-ui-base.css는 앱 셸, 패널, 폼, 버튼, 토스트, 공통 컴포넌트, 공통 SPA 전환 효과, skeleton, 터치 피드백, 공통 sortable/드래그 시각 규칙, 공통 시각 토큰의 소스 파일임.
src/styles/hub-ui-mobile.css는 모바일 고정 폭, 모바일 본문, 모바일 바텀 액션바, 모바일 시트, 모바일 로그인 레이아웃처럼 실제 모바일 레이아웃에 종속된 규칙의 소스 파일임.
src/styles/hub-ui-desktop.css는 데스크탑 관리자 레이아웃, 작업형 워크스페이스, 모달, 폼 그리드, no-scroll 화면 구조 소스 파일임.
src/styles/junkbox-tabulator.css는 Tabulator 전용 공통 소스 파일임.
scripts/build-styles.mjs는 분리된 CSS 소스를 각각 빌드하는 스타일 빌드 진입점임.
src/scripts/app-shell.ts는 공통 앱 셸 TypeScript 소스임.
src/react/는 공통 React 컴포넌트, 공통 유틸, 전역 타입 선언을 제공함.
src/react/components/SortableDragHandle.tsx는 Sortable 기반 정렬 UI에서 사용하는 6점 드래그 핸들 공통 컴포넌트임.
src/react/components/SegmentedTabs.tsx는 탭, 필터, 보기 전환처럼 같은 옵션 집합 중 하나를 고르는 공통 segmented tab 컴포넌트임.
src/react/components/BottomOptionPicker.tsx는 모바일 하단 선택 시트 공통 컴포넌트임.
src/react/components/BottomNumberPicker.tsx는 숫자 배열을 BottomOptionPicker 옵션 계약으로 변환하는 숫자 선택 wrapper임.
src/react/utils/sortable.ts는 Sortable 공통 옵션을 제공하며, 1초 지연 드래그와 공통 ghost/chosen/fallback 클래스 계약을 중앙화함.
src/junkbox_shared_ui/assets/hub-ui-base.css는 공통 CSS 빌드 산출물임.
src/junkbox_shared_ui/assets/hub-ui-mobile.css는 모바일 전용 CSS 빌드 산출물임.
src/junkbox_shared_ui/assets/hub-ui-desktop.css는 데스크탑 전용 CSS 빌드 산출물임.
src/junkbox_shared_ui/assets/junkbox-tabulator.css는 빌드 산출 Tabulator CSS임.
src/junkbox_shared_ui/assets/junkbox-tabulator.js는 Tabulator 공통 헬퍼임.
src/junkbox_shared_ui/assets/app-shell.js는 TypeScript 소스에서 생성된 공통 앱 셸 동작 산출물임.
src/junkbox_shared_ui/assets/app-icons/{app}/icon.svg는 앱별 미니멀 플랫 SVG 아이콘 원본임.
src/junkbox_shared_ui/assets/app-icons/{app}/icon-180.png, icon-192.png, icon-512.png는 favicon, apple touch icon, PWA manifest에서 사용할 수 있는 앱 아이콘 PNG 산출물임.
src/junkbox_shared_ui/templates/base.html은 공통 베이스 템플릿임.
src/junkbox_shared_ui/templates/_stylesheets.html은 공통 CSS와 Tabulator vendor CSS 링크를 선언하는 stylesheet 매크로 템플릿임.
src/junkbox_shared_ui/templates/_grid_head.html은 공통 그리드 헤더 템플릿임.
3.2 폰트 자산
PretendardVariable.woff2를 공용 폰트로 제공함.
한글, 영문, 숫자, 코드/JSON/메타 라벨을 포함한 화면 텍스트 전부 동일 폰트로 처리함.
폰트 파일은 assets/fonts/ 아래에 유지함.
@font-face와 루트 폰트 변수는 hub-ui-base.css 소스에서 중앙 관리함.
앱별 CSS, 화면별 CSS, 특정 컴포넌트 클래스에서 font-family를 중복 선언하지 않음.
Tabulator 전용 CSS는 자체 폰트명을 고정하지 않고 공통 루트 폰트를 상속함.
4. 시각 자산 기준
기본 sans는 Pretendard Variable 폰트 자산을 사용함.
Tailwind preset의 sans와 mono 폰트 토큰은 모두 Pretendard Variable을 사용함.
일반 본문 텍스트, JSON 뷰어, 상세 텍스트 뷰어, 브랜드 마크, eyebrow, 필드 라벨, 통계 라벨, 테이블 헤더는 모두 Pretendard 기준을 사용함.
JetBrains Mono, Fira Code, IBM Plex Mono, 브라우저 기본 monospace 폰트는 JunkBox 화면 스타일 기준으로 사용하지 않음.
폰트 적용 경로는 공통 base CSS의 body와 상속 규칙을 기준으로 하며, 개별 화면이 자체 폰트 스택을 만들지 않음.
상세 색상, 레이아웃, 버튼, 토스트, 그리드, 모바일 예외 규칙은 이 문서에서 중복 정의하지 않고 docs/junkbox/common/guide-jb-common-ui.md를 기준으로 구현함.
공통 다크 톤은 저대비 레이어 중심 규칙을 구현함.
패널, 카드, 입력창, 칩, 상태 배지, 바텀시트는 같은 톤 체계 안에서 구현함.
5. Tailwind 사용 방식
5.1 preset 중심 구조
각 앱은 공용 preset을 가져와 동일한 토큰을 사용함.
색상, 폰트, spacing, radius, component layer 규칙은 preset 기준으로 통일함.
5.2 빌드 방식
shared-ui는 Node 기반 Tailwind 빌드 파이프라인을 사용함.
앱 셸 동작은 TypeScript 소스를 빌드하여 배포 가능한 자산으로 생성함.
빌드 결과물은 앱이 정적 자산으로 직접 서빙할 수 있어야 함.
Python 앱은 빌드 산출 CSS와 JS를 링크하여 사용함.
스타일 빌드는 hub-ui-base.css, hub-ui-mobile.css, hub-ui-desktop.css를 각각 생성하는 구조를 사용함.
tailwind.config.cjs의 content 범위에는 shared-ui 자체 소스와 hub-ui, workout-ui, workout-api의 TypeScript/TSX 소스가 포함됨. 앱 화면이 새 Tailwind 유틸리티 클래스를 사용하면 해당 클래스는 shared-ui 스타일 빌드에서 공통 산출물로 생성됨.
Tailwind utility layer는 hub-ui-base.css 산출물에 포함됨. UI 앱의 Vite 빌드는 앱 JavaScript 산출물만 갱신하므로, 새 Tailwind 유틸리티를 실제 브라우저 CSS에 반영하려면 shared-ui 빌드를 함께 실행해야 함.
화면 크기와 무관한 상호작용 효과는 hub-ui-base.css에 두고, 모바일 고정 폭이나 safe-area처럼 모바일 화면 구조에 직접 종속된 규칙만 hub-ui-mobile.css에 둠.
데스크탑 화면도 hub-ui-base.css를 로드하므로 SPA 전환, skeleton, 안정 로딩, 터치 피드백 같은 공통 장치를 필요 시 동일한 React 계층과 CSS 클래스로 사용할 수 있음.
5.3 앱 연동 방식
서버 렌더링 화면도 동일 산출 CSS를 링크함.
프런트 앱도 같은 preset과 자산을 공유함.
앱과 화면은 스타일 결정을 직접 하지 않고 jb-* 공통 클래스를 조합함.
공통 정적 자산 링크는 서버 템플릿이 버전 쿼리 파라미터를 붙여 생성함.
5.4 apps/hub-ui, apps/chess-ui, apps/workout-ui, apps/raid-ui 연동 구조
apps/hub-ui, apps/chess-ui, apps/workout-ui, apps/raid-ui는 shared-ui 자산을 소비하는 대표 프런트엔드 앱임.
번들러는 Vite 6 계열을 사용함.
React + TypeScript strict 기준으로 페이지 엔트리 또는 앱 단위 SPA 엔트리와 공통 타입 계약을 관리함.
hub-api는 apps/hub-ui/dist를 /hub-ui 경로로 직접 마운트함.
chess-api는 apps/chess-ui/dist를 /chess-ui 경로로 직접 마운트함.
workout-api는 apps/workout-ui/dist를 /workout-ui 경로로 직접 마운트함.
raid-api는 apps/raid-ui/dist를 /raid-ui 경로로 직접 마운트함.
서버 템플릿은 React 마운트 지점과 초기 props만 제공하고, 실제 화면 자산 로딩은 Vite manifest 기준으로 수행함.
템플릿은 해시된 정적 파일명을 직접 참조하지 않고 dist/.vite/manifest.json을 통해 최신 자산 경로를 해석함.
각 UI 앱의 타입 계약은 앱 자체 src/types/models.ts, 브라우저 전역 타입과 import.meta.env 타입은 각 앱 src/global.d.ts를 기준으로 관리함.
운영 자산은 백엔드가 빌드된 자산을 직접 서빙하는 구조를 사용함.
개발 자산은 hub 15001, chess 15002, workout 15003, raid 15009 Vite 개발 서버를 통해 제공할 수 있음.
5.5 apps/rename-ui 연동 구조
apps/rename-ui는 shared-ui 자산을 소비하는 데스크톱 운영 화면 앱임.
번들러는 Vite 6 계열을 사용함.
React + TypeScript strict 기준으로 단일 엔트리와 화면 분기 구조를 관리함.
rename-api는 apps/rename-ui/dist를 /rename-ui 경로로 직접 마운트함.
개발 자산은 15006 Vite 개발 서버를 통해 제공할 수 있음.
서버 템플릿은 React 마운트 지점과 초기 props만 제공하고, 실제 화면 자산 로딩은 Vite manifest 기준으로 수행함.
Rename 화면은 hub-ui-base.css + hub-ui-desktop.css + junkbox-tabulator.css 조합을 기본으로 사용함.
5.6 공통 React 계층
src/react/components는 공통 아이콘, 하단 선택 시트, 숫자 선택 시트, 단순 피드백 블록 같은 재사용 컴포넌트를 제공함.
SortableDragHandle은 포털 카드, 대시보드 큰 카드, 대시보드 투자 항목처럼 Sortable 정렬을 사용하는 화면의 표준 핸들 컴포넌트임.
SortableDragHandle은 2열 3행 6점 핸들 외형을 제공하며, 화면은 aria-label과 배치용 className만 전달함.
LoadingBlock은 인라인 블록과 오버레이 두 모드를 제공하는 공통 로딩 컴포넌트임.
SkeletonBlock은 앱 화면의 최상위 데이터 로딩 체감을 유지하기 위한 공통 skeleton 컴포넌트임.
MobileSkeleton은 SkeletonBlock과 같은 props 계약을 제공하는 모바일 명명 wrapper임.
SpaRouteTransition은 SPA 라우트 전환 시 페이지 컨텐츠가 부드럽게 진입하도록 감싸는 공통 컴포넌트이며, 지원 브라우저에서는 View Transition snapshot 대상이 됨.
src/react/hooks는 SPA 라우트 변경 후 스크롤 초기화와 화면 안착 상태를 관리하는 useSpaRouteSettling, 빠른 요청의 로딩 UI 깜빡임을 줄이는 useStableLoading 같은 공통 hook을 제공함.
SegmentedTabs는 value, label, 선택적 icon, disabled를 갖는 옵션 목록을 받아 role=tablist와 role=tab 접근성 계약으로 렌더링함.
SegmentedTabs는 대시보드 PC 탭의 약간 네모난 rounded-jb-sm 외형을 표준으로 사용하며, fill 옵션으로 컨테이너 폭을 균등 분할하고 scrollable 옵션으로 항목 수가 많은 필터 탭을 가로 스크롤할 수 있음.
화면은 APP/SERVICE, 페이지 크기, 필터형 운동 부위, 대시보드 보기처럼 인라인 탭이 적합한 옵션 선택 UI를 직접 마크업하지 않고 SegmentedTabs를 우선 사용함.
BottomOptionPicker는 value, label, 선택적 description, 선택적 icon, disabled를 갖는 문자열 옵션 목록을 받아 모바일 하단 선택 시트를 렌더링함.
모바일 화면은 루틴 모드, 운동 부위, 단계 유형, 안내 방식처럼 현재 선택값을 먼저 보여주는 선택 UI에 jb-select 외형의 버튼과 BottomOptionPicker를 조합할 수 있음.
BottomOptionPicker는 열림 직후 현재 선택값을 내부 scroll container 기준으로 중앙 근처에 보이도록 정렬하며 문서 전체 스크롤 위치를 변경하지 않음.
BottomOptionPicker는 optionAlign으로 옵션 본문 정렬을 제어할 수 있으며, 텍스트형 목록은 좌측 정렬, 숫자형 목록은 중앙 정렬을 사용함.
BottomOptionPicker는 불투명한 다크 패널 배경과 저대비 옵션 카드 톤을 자체적으로 포함하여, hub-ui-mobile.css를 로드하지 않는 PC/모바일 겸용 화면에서도 배경 컨텐츠와 겹쳐 읽기 어려운 상태를 만들지 않음.
BottomNumberPicker는 숫자 선택 전용 공개 API를 유지하는 얇은 wrapper이며, 실제 시트 외형과 스크롤 동작은 BottomOptionPicker를 재사용하고 옵션 텍스트는 중앙 정렬함.
src/react/utils는 토스트, HTTP 요청, 페이지 props 파서, SPA navigation 보조 유틸, Tabulator 점진 로딩 유틸, 포맷터, HTTP 오류 판정 유틸을 제공함.
src/react/utils/sortable.ts의 JUNKBOX_SORTABLE_BASE_OPTIONS는 Sortable의 animation, delay, delayOnTouchOnly, forceFallback, chosenClass, ghostClass, dragClass, fallbackClass 기준을 제공함.
HTTP 오류 판정 유틸은 RequestError 메시지 해석과 409 Conflict 또는 already-exists 계열 응답을 판정하는 isConflictError를 제공함.
SPA navigation 보조 유틸은 React Router navigation과 조합할 수 있는 createSpaNavigateOptions, 브라우저 View Transition fallback을 포함한 runSpaViewTransition을 제공함.
UI 앱은 공통 유틸을 직접 복제하지 않고 @shared-ui/* alias로 이 계층을 소비함.
5.7 SPA 적용 공통 틀
SPA 화면은 서버 템플릿이 공통 앱 셸, React 마운트 루트, 최소 page props, 단일 엔트리 스크립트만 제공하는 구조를 사용함.
화면별 실제 라우트 선택, URL path parameter, query string 해석은 React Router가 담당함.
서버 앱 셸 네비게이션 링크를 SPA 내부 이동으로 처리해야 하는 화면은 템플릿 컨텍스트에 spa_navigation=true를 전달함.
spa_navigation=true인 화면에서 app-shell.js는 동일 origin 링크 클릭을 가로채고 junkbox:spa-navigate 이벤트를 발행함.
React 앱은 junkbox:spa-navigate 이벤트를 수신해 React Router navigation으로 연결함.
React Router navigation은 createSpaNavigateOptions와 runSpaViewTransition을 함께 사용하여 브라우저 View Transition 지원 여부와 무관하게 동일한 호출 구조를 유지함.
라우트 본문은 SpaRouteTransition으로 감싸고, 라우트 key는 일반적으로 location.pathname을 사용함.
라우트 변경 직후 스크롤 초기화와 오브젝트 안착 상태는 useSpaRouteSettling으로 처리함.
빠르게 끝나는 요청의 skeleton 깜빡임은 useStableLoading으로 제어하고, 화면별 임의 타이머를 만들지 않음.
최상위 데이터 로딩 placeholder는 SkeletonBlock을 우선 사용함.
SpaRouteTransition, useSpaRouteSettling, useStableLoading, SkeletonBlock, runSpaViewTransition은 모바일 전용이 아니라 PC/모바일 양쪽에서 사용할 수 있는 공통 SPA/상호작용 기반임.
모바일 바텀 액션바 안착, 모바일 시트, 모바일 고정 폭 같은 화면 구조 종속 규칙은 mobile CSS 책임으로 유지함.
모바일 화면에서 .jb-spa-route-stage는 viewport fixed 요소가 문서 끝으로 밀리지 않도록 containment, route animation, will-change 기반 격리 효과를 비활성화함.
6. 템플릿과 스크립트 규칙
6.1 베이스 템플릿
공통 베이스 템플릿은 앱 셸, 글로벌 자산 링크, page props 주입 지점을 제공함.
서버 앱은 베이스 템플릿에 필요한 컨텍스트를 주입하고 화면별 블록만 채움.
shared-ui stylesheet 매크로는 hub-ui-base.css, hub-ui-mobile.css, hub-ui-desktop.css, Tabulator vendor CSS, junkbox-tabulator.css 같은 공통 스타일 링크의 단일 선언 지점임.
공통 베이스 템플릿은 stylesheet 매크로를 import하고, include_mobile_css, include_desktop_css, include_tabulator_css 값으로 CSS 조합을 결정함.
개별 화면 템플릿과 standalone HTML 템플릿은 공통 CSS 링크를 직접 선언하지 않고 stylesheet 매크로를 호출함.
공통 베이스 템플릿은 inline <style> 블록을 포함하지 않음.
공통 앱 셸을 상속하지 않는 로그인 화면과 체스 샌드박스 HTML도 같은 stylesheet 매크로를 사용해 CSS 공급 경로를 중앙화함.
모바일 로그인 화면은 hub-ui-base.css + hub-ui-mobile.css 조합을 사용하고 Tabulator CSS를 로드하지 않음.
체스 샌드박스 HTML은 hub-ui-base.css + hub-ui-desktop.css + vendor/tabulator/tabulator_simple.min.css + junkbox-tabulator.css 조합을 사용함.
공통 베이스 템플릿은 viewport-fit=cover, theme-color, 서비스 워커 등록 같은 모바일/PWA 공통 진입점을 제공함.
공통 베이스 템플릿은 favicon_url 컨텍스트가 있으면 <link rel="icon">을 렌더링함.
stylesheet 매크로와 공통 베이스 템플릿은 shared_ui_asset(asset_name) 헬퍼를 통해 hub-ui-base.css, hub-ui-mobile.css, hub-ui-desktop.css, junkbox-tabulator.css, app-shell.js에 버전 쿼리를 붙인 URL을 렌더링함.
공통 베이스 템플릿은 기본적으로 body_mode_class 기준으로 모바일 화면에는 base + mobile, 데스크탑 화면에는 base + desktop 조합을 로드함.
화면 컨텍스트의 include_mobile_css, include_desktop_css 값은 기본 CSS 조합에 필요한 모드 CSS를 추가로 포함할 때 사용함.
/portal은 본문 모바일 고정 폭과 공통 메뉴바 반응형 동작을 함께 만족해야 하므로 base + mobile + desktop 조합을 사용함.
Vite dev client와 React refresh preamble도 같은 베이스 템플릿의 단일 선언 지점에서 처리함.
spa_navigation=true 컨텍스트를 받은 화면은 공통 앱 셸 링크 클릭을 junkbox:spa-navigate 브라우저 이벤트로 전환할 수 있음.
개별 화면 템플릿은 개발 모드 여부와 무관하게 화면 엔트리 스크립트만 선언함.
6.2 그리드 헤더 템플릿
단일 그리드형 화면과 2패널 작업형 화면 모두 같은 공통 헤더 구조를 재사용할 수 있도록 제공함.
6.3 Tabulator 헬퍼
junkbox-tabulator.js는 공통 요청, 피드백, 토스트, HTML 이스케이프를 담당함.
화면별 TypeScript 코드는 이 헬퍼를 기준으로 API 호출과 사용자 피드백을 처리함.
사용자 노출 문구는 화면 코드나 템플릿에 한국어 문구로 직접 작성함.
공통코드 라벨과 메타 설정값처럼 데이터 자체가 마스터데이터인 값만 DB 조회 구조를 사용함.
6.4 앱 셸 스크립트
앱 셸 로직의 소스 오브 트루스는 app-shell.ts임.
app-shell.js는 전역 메뉴 토글과 공통 셸 상호작용을 담당하는 배포 산출물임.
spa_navigation=true인 화면에서 app-shell.js는 동일 origin 링크 클릭을 가로채고 React 앱이 처리할 수 있는 junkbox:spa-navigate 이벤트를 발행함.
앱별로 메뉴 동작을 다시 구현하지 않음.
포털 카드, 모바일 고정 폭, 모바일 본문 고정 폭, safe-area, 모바일 바텀 액션바 같은 예외 레이아웃도 공통 CSS 클래스에서 관리함.
workout 모바일 헤더 변형도 같은 공통 템플릿/공통 자산 기준으로 처리함.
버전 쿼리가 붙는 공통 자산 링크는 CDN이 이전 배포의 CSS/JS를 고정 경로 기준으로 계속 캐시하는 문제를 줄이기 위한 기본 구조임.
단일 통합 번들 hub-ui.css는 사용하지 않으며, 분리 자산 조합을 현재 기준으로 사용함.
6.5 개발 모드 템플릿 연동
서버 템플릿 컨텍스트는 요청 헤더 기준 dev server origin을 해석할 수 있음.
hub 개발 모드 엔트리 경로는 /hub-ui/src/entries/*.tsx 기준을 사용함.
hub Vite dev client 경로는 /hub-ui/@vite/client임.
hub React refresh runtime 경로는 /hub-ui/@react-refresh임.
workout 개발 모드 엔트리 경로는 /workout-ui/src/entries/workout.tsx 기준을 사용함.
workout Vite dev client 경로는 /workout-ui/@vite/client임.
workout React refresh runtime 경로는 /workout-ui/@react-refresh임.
workout 개발 모드에서 PWA manifest와 service worker 링크는 공통 베이스 템플릿이 렌더링하지만, /workout.webmanifest, /workout-sw.js 요청의 실제 프록시는 apps/workout-ui Vite 설정이 담당함.
앱별 Vite 설정은 공통 베이스 템플릿이 생성한 PWA 동일 origin URL이 개발 서버 origin에서 404로 처리되지 않도록 해당 앱 백엔드로 프록시해야 함.
rename 개발 모드 엔트리 경로는 /rename-ui/src/entries/*.tsx 기준을 사용함.
rename Vite dev client 경로는 /rename-ui/@vite/client임.
rename React refresh runtime 경로는 /rename-ui/@react-refresh임.
raid 개발 모드 엔트리 경로는 /raid-ui/src/entries/*.tsx 기준을 사용함.
raid Vite dev client 경로는 /raid-ui/@vite/client임.
raid React refresh runtime 경로는 /raid-ui/@react-refresh임.
chess 개발 모드 엔트리 경로는 /chess-ui/src/entries/chess.tsx 기준을 사용함.
chess Vite dev client 경로는 /chess-ui/@vite/client임.
chess React refresh runtime 경로는 /chess-ui/@react-refresh임.
루트 리다이렉트와 프록시 분기는 각 UI 앱의 Vite 설정이 담당하고, 공통 베이스 템플릿은 계산된 자산 URL만 소비함.
7. 공통 레이아웃 및 컴포넌트 제공 범위
shared-ui는 앱 셸, 패널, 버튼, 입력창, 칩, 토스트, 모달, 그리드 래퍼, 모바일 고정 폭 클래스 같은 공통 자산을 제공함.
shared-ui는 공통 SVG 아이콘과 공통 브라우저 유틸도 제공함.
shared-ui는 화면 크기와 무관한 SPA 전환용 .jb-spa-route-stage, .jb-spa-route-settling 기반 안착 애니메이션, jb-skeleton 계열 클래스를 base CSS로 제공함.
shared-ui는 터치 환경에서 버튼, 카드, segmented tab, 다크 필드가 가볍게 눌리는 피드백을 공통 base CSS로 제공함.
shared-ui는 액션 영역 칸막이용 jb-action-divider, Sortable 핸들/ghost/chosen/fallback 공통 클래스, 대시보드 카드 드래그 클래스, 투자 항목 드래그 클래스를 base CSS로 제공함.
jb-segmented-tabs, jb-segmented-tabs--fill, jb-segmented-tabs--scrollable, jb-segmented-tab, jb-segmented-tab-icon, jb-segmented-tab-label은 SegmentedTabs의 표준 외형과 폭 정책을 담당함.
공통 segmented tab은 대시보드 PC 탭의 낮은 대비, 얇은 경계선, rounded-jb-sm 반경을 기준으로 하며, 과하게 둥근 pill 외형을 표준으로 사용하지 않음.
jb-portal-card-title은 포털 APP/SERVICE 카드 이름을 normal weight로 표시하는 제목 클래스이며, 카드 이름에 별도 굵은 강조를 적용하지 않음.
jb-sortable-drag-handle, jb-sortable-drag-dots, jb-sortable-drag-dot은 공통 드래그 핸들 외형을 담당함.
jb-sortable-chosen, jb-sortable-ghost, jb-sortable-dragging, jb-sortable-fallback은 Sortable 상태별 시각 규칙을 담당함.
jb-dashboard-grid는 PC 기준 4열 x 2행 고정 슬롯 대시보드 배치를 제공하고, 모바일 기준 1열 자연 높이 목록으로 전환됨.
jb-dashboard-card-shell, jb-dashboard-card-head-actions, jb-dashboard-card-drag, jb-dashboard-asset-drag은 대시보드 큰 카드와 카드 내부 투자 항목 정렬을 같은 공통 sortable 규칙에 연결하기 위한 클래스임.
jb-dashboard-icon-button, jb-dashboard-favorite-button은 대시보드 카드 헤더의 아이콘 버튼과 즐겨찾기 활성 상태를 표현함.
jb-dashboard-news-list, jb-dashboard-asset-list, jb-dashboard-process-list는 PC 고정 카드 높이 안에서 내부 스크롤을 사용할 수 있는 대시보드 목록 영역임.
jb-dashboard-mobile-tab-trigger, jb-dashboard-mobile-tab-main은 모바일 대시보드에서 현재 보기 선택 버튼을 표시하고, PC 인라인 탭과 같은 옵션 집합을 하단 선택 시트로 연결하기 위한 클래스임.
shared-ui는 모바일 바텀 액션바, 모바일 시트, 모바일 고정 폭처럼 실제 모바일 레이아웃에 종속된 규칙만 mobile CSS로 제공함.
shared-ui는 데스크톱 작업 화면용 jb-workspace-screen-fit, jb-grid-panel-viewport, 공통 카운트 칩, 플랫 로딩 오버레이 스타일을 제공함.
jb-input은 텍스트 입력 전용 시각 규칙을 사용하며 select chevron 배경을 포함하지 않음.
jb-select는 select 성격 UI에만 chevron 배경, 우측 구분선, 우측 padding을 제공함.
jb-select를 모바일 선택 시트 trigger 버튼 외형으로 사용할 때 화면 컴포넌트는 별도 chevron 텍스트나 아이콘을 중복 추가하지 않음.
텍스트 선택 시 입력창, select, 버튼의 selection 색상은 공통 다크 테마 안에서 안정적으로 보이도록 shared-ui가 관리함.
jb-mobile-card, jb-mobile-card-soft, jb-dark-field, jb-dark-chip, jb-dark-status 계열 클래스는 workout과 hub 양쪽에서 공유하는 다크 톤 자산임.
jb-dark-field는 input/select 공통 다크 필드로 사용할 수 있으며, select option과 optgroup도 공통 다크 배경과 밝은 글자를 사용함.
jb-chess-* 계열 클래스는 체스 샌드박스의 360px 좌측 컬럼, Game History Tabulator 영역, FHD 3컬럼 로그 관전 화면, 모바일 단일 컬럼 화면을 지원하는 공통 base CSS 클래스임.
jb-chess-board-meta는 체스판 하단의 판세/판단 메타 grid이며, 모바일에서는 2열, PC/FHD 기준에서는 3열을 사용함.
jb-chess-log-stream은 카드가 많아질 때 페이지 전체가 아니라 로그 영역 내부에서 스크롤되도록 구성됨.
jb-chess-log-card 계열 클래스는 체스 로그 카드를 미니멀하고 플랫한 시각 규칙으로 표시하며, 상태/경고/오류 변형만 낮은 강도의 색상 차이를 사용함.
jb-chess-log-card--selectable은 완료된 과거 게임의 move 로그 카드처럼 클릭 또는 키보드 선택으로 보드 시점을 바꿀 수 있는 카드에 사용함.
jb-chess-log-card--selected는 중앙 체스판에 현재 반영된 과거 move 로그 카드를 표시하는 선택 상태 클래스임.
jb-chess-log-toggle 계열 클래스는 로그 카드 하단의 PGN/기보 영역 표시 전환을 지원함.
jb-chess-meta-row--wide는 좌측 메타 grid 안에서 날짜시간처럼 긴 값을 2컬럼 전체 폭으로 표시하고, 보드 메타에서는 PC/FHD 기준 3컬럼 전체 폭을 표시하는 행에 사용함.
jb-chess-log-move는 체스 로그 카드의 move 배지를 thought 본문 앞 inline 요소로 배치하는 데 사용함.
jb-chess-history-* 계열 클래스는 체스 Game History 패널, Tabulator 높이, 페이지네이션, 결과 텍스트 색상 규칙을 지원함.
jb-mobile-page, jb-mobile-bottom-bar, jb-workout-set-grid, jb-workout-latest-record-* 계열 클래스는 workout 모바일 편집 UX를 공통 규칙 안에서 구현하는 클래스임.
jb-workout-set-head는 세트 입력 그리드 헤더의 크기, 두께, 자간, muted 색상만 담당하며 대문자 변환을 강제하지 않음. 따라서 중량(kg) 같은 단위 표기는 소스 문구의 대소문자를 그대로 유지함.
jb-mobile-bottom-bar는 모바일 viewport 하단 고정 액션 영역이며, SPA 라우트 전환 컨테이너 안에서도 화면 하단 기준으로 동작해야 함.
어떤 레이아웃과 시각 규칙을 선택해야 하는지는 docs/junkbox/common/guide-jb-common-ui.md를 따르고, 이 문서는 그 규칙을 구현하는 클래스와 산출물 위치를 설명하는 데 집중함.
8. Tabulator 연동 기준
8.1 공통 자산
편집형 표는 Tabulator를 기준으로 함.
Tabulator 원본 자산과 커스텀 CSS는 shared-ui가 제공함.
공통 JS 헬퍼는 요청, 피드백, 토스트 처리에 사용함.
선택 체크박스 컬럼, hover/selected 행 강조, 기본 줄무늬 비활성화 같은 시각 규칙도 공통 Tabulator CSS에서 제공함.
list editor 셀에 공통 chevron 표시를 주는 jb-cell-editor-list 클래스도 공통 Tabulator CSS에서 제공함.
Tabulator list editor 드롭다운과 select 성격 입력 UI는 브라우저 기본 흰색 팝업 대신 공통 다크 테마 규칙을 사용함.
레이드 점수형 셀처럼 숫자 자체는 플랫하게 유지하고, 잠정 상태만 셀 배경으로 강조하는 패턴도 공통 Tabulator CSS에서 제공함.
8.2 구현 전제
그리드는 부모 높이를 채우는 구조를 사용함.
그리드 로딩 정책 자체는 docs/junkbox/common/guide-jb-common-ui.md를 기준으로 결정하며, shared-ui는 그 정책을 구현할 수 있는 공통 레이아웃과 시각 자산 제공에 집중함.
점진적 스크롤 로딩형 Tabulator 화면은 내부 tableholder 생성 시점이 비동기적일 수 있으므로, 관련 초기화 헬퍼가 이 전제를 처리하는 구조를 사용함.
9. 운영 원칙
공통 UI 규칙은 개별 앱에 복제하지 않음.
화면 전용 CSS 파일을 만들지 않음.
새 스타일이 필요하면 먼저 shared-ui에 공통 클래스로 추가함.
테마 변경과 레이아웃 토큰 변경은 shared-ui에서 먼저 수행함.
공통 스타일 산출물 밖에서 CSS 또는 inline style을 추가하지 않음.
앱 화면은 공통 Tailwind 유틸리티와 jb-* 클래스를 조합함. 화면에 새 utility class를 추가한 경우에는 shared-ui CSS 산출물을 재생성한 뒤 해당 앱을 빌드하고, 실제 대상 viewport에서 적용 여부와 문서 스크롤 여부를 함께 검증함.
폰트 선언과 폰트 상속 규칙은 hub-ui-base.css를 단일 진입점으로 유지함.
스타일 산출물은 배포 전 빌드 상태를 보장해야 함.
공통 프런트 로직 소스는 TypeScript 기준으로 유지함.
.js 파일은 배포 산출물 또는 외부 라이브러리 자산일 때만 허용함.
10. 관련 문서
화면 조합 규칙과 구현 체크리스트는 docs/junkbox/common/guide-jb-common-ui.md를 따름.
프로젝트 전체 구조는 docs/junkbox/common/guide-jb-core.md를 따름.
hub 프런트 앱 구조는 docs/junkbox/apps/guide-apps-hub-ui.md를 따름.
rename 프런트 앱 구조는 docs/junkbox/apps/guide-apps-rename-ui.md를 따름.
workout 프런트 앱 구조는 docs/junkbox/apps/guide-apps-workout-ui.md를 따름.
chess 프런트 앱 구조는 docs/junkbox/apps/guide-apps-chess-ui.md를 따름.