본문으로 건너뛰기

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의 sansmono 폰트 토큰은 모두 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-uishared-ui 자산을 소비하는 대표 프런트엔드 앱임.
  • 번들러는 Vite 6 계열을 사용함.
  • React + TypeScript strict 기준으로 페이지 엔트리 또는 앱 단위 SPA 엔트리와 공통 타입 계약을 관리함.
  • hub-apiapps/hub-ui/dist/hub-ui 경로로 직접 마운트함.
  • chess-apiapps/chess-ui/dist/chess-ui 경로로 직접 마운트함.
  • workout-apiapps/workout-ui/dist/workout-ui 경로로 직접 마운트함.
  • raid-apiapps/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-uishared-ui 자산을 소비하는 데스크톱 운영 화면 앱임.
  • 번들러는 Vite 6 계열을 사용함.
  • React + TypeScript strict 기준으로 단일 엔트리와 화면 분기 구조를 관리함.
  • rename-apiapps/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 컴포넌트임.
  • MobileSkeletonSkeletonBlock과 같은 props 계약을 제공하는 모바일 명명 wrapper임.
  • SpaRouteTransition은 SPA 라우트 전환 시 페이지 컨텐츠가 부드럽게 진입하도록 감싸는 공통 컴포넌트이며, 지원 브라우저에서는 View Transition snapshot 대상이 됨.
  • src/react/hooks는 SPA 라우트 변경 후 스크롤 초기화와 화면 안착 상태를 관리하는 useSpaRouteSettling, 빠른 요청의 로딩 UI 깜빡임을 줄이는 useStableLoading 같은 공통 hook을 제공함.
  • SegmentedTabsvalue, label, 선택적 icon, disabled를 갖는 옵션 목록을 받아 role=tablistrole=tab 접근성 계약으로 렌더링함.
  • SegmentedTabs는 대시보드 PC 탭의 약간 네모난 rounded-jb-sm 외형을 표준으로 사용하며, fill 옵션으로 컨테이너 폭을 균등 분할하고 scrollable 옵션으로 항목 수가 많은 필터 탭을 가로 스크롤할 수 있음.
  • 화면은 APP/SERVICE, 페이지 크기, 필터형 운동 부위, 대시보드 보기처럼 인라인 탭이 적합한 옵션 선택 UI를 직접 마크업하지 않고 SegmentedTabs를 우선 사용함.
  • BottomOptionPickervalue, label, 선택적 description, 선택적 icon, disabled를 갖는 문자열 옵션 목록을 받아 모바일 하단 선택 시트를 렌더링함.
  • 모바일 화면은 루틴 모드, 운동 부위, 단계 유형, 안내 방식처럼 현재 선택값을 먼저 보여주는 선택 UI에 jb-select 외형의 버튼과 BottomOptionPicker를 조합할 수 있음.
  • BottomOptionPicker는 열림 직후 현재 선택값을 내부 scroll container 기준으로 중앙 근처에 보이도록 정렬하며 문서 전체 스크롤 위치를 변경하지 않음.
  • BottomOptionPickeroptionAlign으로 옵션 본문 정렬을 제어할 수 있으며, 텍스트형 목록은 좌측 정렬, 숫자형 목록은 중앙 정렬을 사용함.
  • BottomOptionPicker는 불투명한 다크 패널 배경과 저대비 옵션 카드 톤을 자체적으로 포함하여, hub-ui-mobile.css를 로드하지 않는 PC/모바일 겸용 화면에서도 배경 컨텐츠와 겹쳐 읽기 어려운 상태를 만들지 않음.
  • BottomNumberPicker는 숫자 선택 전용 공개 API를 유지하는 얇은 wrapper이며, 실제 시트 외형과 스크롤 동작은 BottomOptionPicker를 재사용하고 옵션 텍스트는 중앙 정렬함.
  • src/react/utils는 토스트, HTTP 요청, 페이지 props 파서, SPA navigation 보조 유틸, Tabulator 점진 로딩 유틸, 포맷터, HTTP 오류 판정 유틸을 제공함.
  • src/react/utils/sortable.tsJUNKBOX_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은 createSpaNavigateOptionsrunSpaViewTransition을 함께 사용하여 브라우저 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-labelSegmentedTabs의 표준 외형과 폭 정책을 담당함.
  • 공통 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를 따름.