다크모드
FE 메인테이너 — 관리비 탭 계층과 페이지별 대조
결정
EDS 탭의 구조 variant는 plane | line이다. TabsList의 default는 plane이며, plane은 plain이 아니라 형제 탭을 받치는 연속된 면을 뜻한다. 버튼 등의 form variant인 surface와 축을 섞지 않는다.
| 위치 | variant | 표면 규칙 |
|---|---|---|
| 패딩이 있는 PageHeader footer의 로컬·단계 탐색 | plane(default) | TabsList가 배경·padding·radius를 단독 소유 |
| 카드·콘텐츠 앞의 보기 전환 | plane(default) | 청구 축 탭과 같은 흰 pill inset 안에서 회색 탭 plane을 단독 소유 |
| 표면 경계에 직접 붙는 full-bleed 레일 | line | 기준선이 표면 경계 전체에 닿을 때만 사용 |
가로 트랙 너비 계약
@leysys/eds@1.2.3부터 가로 TabsList는 짧을 때 탭 trigger 합산 너비만 차지하고, 길 때 부모의 가용 폭까지만 커진 뒤 List 자체가 가로 스크롤한다. Tabs root와 TabsContent, PageHeader의 탐색 밴드는 계속 사용 가능한 전체 폭을 차지한다. plane 배경은 마지막 탭 뒤의 빈 밴드까지 늘어나지 않으며, 배경·padding·radius와 scroll viewport가 같은 List에 있어 스크롤 처음부터 끝까지 배경이 연속된다.
TabsList:align-self: flex-start; box-sizing: border-box; inline-size: fit-content; max-inline-size: 100%; overflow-x: autoTabsRoot·TabsContent·PageHeader: 전체 가용 폭과 배치 소유, Tabs trigger overflow는 소유하지 않음- 제품: exact 두께 class 없이 전역 기본 Native를 사용해 OS 자동 숨김 수명 보존
- 제품의
w-full min-w-0 overflow-x-auto, 로컬 CSS,!important, 임의w-fit보정 금지
페이지 코드는 공식 src/registry/vue/tabs 래퍼를 우선 사용한다. 레거시 빌드가 TypeScript SFC 래퍼를 처리하지 못하는 경우에는 Reka primitive를 직접 사용하되 EDS의 root/list/trigger 클래스를 빠짐없이 부여하고 별도 wrapper fork를 만들지 않는다. line을 쓰는 경우에만 indicator anatomy를 추가한다. 제품별 음수 margin·가상요소·로컬 CSS로 컨테이너 패딩을 상쇄하지 않는다. 관리비 콘솔에서 보기 전환을 작업 카드와 분리할 때는 기존 청구 축 탭의 page-header-below p-1 bg-neutral-minimal rounded-full 표면 계약을 재사용한다.
페이지 01 적용 매트릭스
| 화면 | 현재 실제 제품 (leyve-admin-frontend/v3-style) | 우리 선도 제품 (leyve-console-proto/main) |
|---|---|---|
| 관리비 목록 | 목록 로컬 탭을 plane으로 정리. 고지서 빌더는 disabled + 미구현 | 좌측에서 정기 관리비·중간정산을 전환하고 각 헤더는 일반 1개만 표시 |
| 관리비 회차 콘솔 | 기존 업무 탭을 plane으로 정리 | ConsoleTabBarOrg의 11개 업무를 단일 가로 탭 레일로 정리하고 planned 게이트 유지 |
| 부과 하위 보기 | 부과산정·참조를 기본 variant 단일 표면으로 정리 | 부과산정·유닛별·계약별·멤버별을 기본 variant 단일 표면으로 정리 |
두 제품의 업무 범위와 라벨은 같게 만들 대상이 아니다. 이번 대조는 탭의 계층·표면·상태 표현만 맞춘다.
코드 구조
EDS 래퍼
src/registry/vue/tabs/Tabs.vueTabsList.vueTabsTrigger.vueTabsContent.vueTabsIndicator.vue
leyve-console-proto의 래퍼 파일은 leysys-design/src/registry/vue/tabs와 byte-identical이어야 한다.
우리 선도 제품
- 목록:
src/components/service-charge/{actual,provisional}/HeaderOrg.vue - 설정:
src/components/service-charge/setting/{general,surcharge,collecting}/HeaderOrg.vue - 좌측 메뉴 SSOT:
src/composables/billingLines.js - 콘솔 공통:
src/components/billing/_core/console/ConsoleTabBarOrg.vue - 부과 하위 공통 탭:
src/components/service-charge/actual/console/charging/ChargingViewTabBarOrg.vue - 부과 하위 작업 표면:
assessment,allocation-unit,allocation-contract,allocation-member의MainOrg.vue
콘솔 공통 내비게이션은 billingLines.js의 consoleTabs를 단일 TabsRoot·TabsList에 렌더한다. consoleClusters는 데스크톱에서 인접 업무군 사이의 장식용 구분선만 결정하며 별도 선택 단계나 두 번째 업무 탭 줄을 만들지 않는다. 모바일은 같은 탭 레일을 좌우 스크롤하고 배지·구분선만 숨긴다. 활성 탭은 진입 후 레일 시작점 가까이 자동 정렬한다. planned 탭은 disabled 상태와 기존 배지·title을 유지한다.
탐색 소유권은 다음과 같다.
- 좌측 메뉴: 모듈 안의 업무 전환
- 페이지 헤더: 현재 좌측 업무의 로컬 하위 화면
- 본문 탭: 같은 페이지 안의 데이터 보기 축
관리비 목록의 정기 관리비·중간정산은 좌측 소유이므로 각 목록 헤더에는 일반만 렌더한다. 기본 설정의 /setting/general, /setting/surcharge, /setting/collecting은 하나의 좌측 기본 설정 아래 로컬 탭이다. LineAsideOrg는 activePrefixes로 세 route 모두에서 기본 설정을 활성 표시한다.
billingLines.js의 consoleNavigation은 회차 workflow와 모듈 업무 메뉴를 구분한다. service-charge의 회차 콘솔만 workflow로 여러 단계 탭을 표시한다. 임대차·판매·구매처럼 상위 콘솔 업무를 좌측 메뉴가 소유하는 라인은 헤더에 일반만 표시한다.
actual 부과 하위 네 route는 ChargingViewTabBarOrg를 공유하고 active prop만 다르게 전달한다. ChargingViewTabBarOrg는 기존 청구의 계약·유닛·멤버 축 탭과 동일한 page-header-below p-1 bg-neutral-minimal rounded-full 표면을 사용한다. 회색 tabs-list는 흰 표면 안에 4px inset으로 놓인다. 각 MainOrg의 card card-md card-filled card-divide-y는 알림·도구·표 body와 action footer만 소유하며, 탭을 card header에 넣지 않는다. 따라서 작업 카드 header는 이후 제목·상태·기능을 배치할 수 있다.
현재 실제 제품
- 목록:
src/views/ummsV3/transaction/general-settlement/list.vue - 콘솔:
console-view.vue - 부과 하위:
console-charging.vue
이 저장소의 vite.config.js는 .js JSX만 대상으로 하는 esbuild 설정 때문에 TypeScript SFC registry wrapper를 그대로 번들링하지 못한다. 이번 범위에서는 config/baseline을 넓게 바꾸지 않고 reka-ui의 TabsRoot, TabsList, TabsTrigger를 직접 소비하며, 각 primitive에 EDS의 tabs, tabs-horizontal, tabs-list, tabs-trigger 클래스를 명시했다. TabsIndicator와 tabs-indicator는 full-bleed line에서만 추가한다. 이 호환 seam에 제품 CSS나 변형 wrapper를 추가하지 않는다.
다음 페이지 적용 절차
- 탭이 패딩 컨테이너 안인지, 표면 경계에 직접 붙는 full-bleed 레일인지 먼저 분류한다.
- 패딩 컨테이너 안이면
plane을 적용한다.plane은 기본값이므로 생략해도 동일하다. line은 기준선이 표면 경계 전체에 닿을 때만 사용하고, 페이지의 음수 margin으로 full-bleed를 흉내 내지 않는다.- 기본 variant의 부모에서 중복 배경·padding·radius를 제거해 표면 소유자를 하나로 만든다.
- 미구현 기능은 숨기지 말고 disabled,
data-status="unimplemented",title="미구현"과 저채도 배지로 표시한다. - 두 제품의 같은 페이지를 나란히 검수하고, 업무 기능 차이는 별도 항목으로 기록한다.
검증
- Console targeted Vitest: 헤더 plane, 콘솔 planned gate, 부과 하위 탭 이동
- Admin targeted Vitest: 목록·콘솔 plane, 부과 하위 내비게이션·작업 표면 분리, 미구현 disabled
- 두 제품 SFC compiler 검증과 실제 제품 production build
- 브라우저에서 plane 활성 상태, 키보드 이동, disabled 탭 무동작, 가로 overflow를 확인
- 변경 레벨 L1 기준
412×915,768×1024,1440×900에서 단일TabsList의 활성 탭, 내부 가로 스크롤, 문서 전체 가로 overflow0px를 확인함 - 상호작용은
412×915에서 탭 스와이프·탭 이동·활성 탭 자동 노출을 확인하고,1440×900에서 클러스터 구분선과 키보드 이동을 확인함