--- description: 관리자 페이지 표준 스타일 가이드 - shadcn/ui 기반 일관된 디자인 시스템 globs: **/app/(main)/admin/**/*.tsx,**/components/admin/**/*.tsx --- # 관리자 페이지 표준 스타일 가이드 이 가이드는 관리자 페이지의 일관된 UI/UX를 위한 표준 스타일 규칙입니다. 모든 관리자 페이지는 이 가이드를 따라야 합니다. ## 1. 페이지 레이아웃 구조 ### 기본 페이지 템플릿 ```tsx export default function AdminPage() { return (
{/* 페이지 헤더 */}

페이지 제목

페이지 설명

{/* 메인 컨텐츠 */}
{/* Scroll to Top 버튼 (모바일/태블릿 전용) */}
); } ``` **필수 적용 사항:** - 최상위: `flex min-h-screen flex-col bg-background` - 컨텐츠 영역: `space-y-6 p-6` (24px 좌우 여백, 24px 간격) - 헤더 구분선: `border-b pb-4` (테두리 박스 사용 금지) - Scroll to Top: 모든 관리자 페이지에 포함 ## 2. Color System (색상 시스템) ### CSS Variables 사용 (하드코딩 금지) ```tsx // ❌ 잘못된 예시
// ✅ 올바른 예시
``` **표준 색상 토큰:** - `bg-background` / `text-foreground`: 기본 배경/텍스트 - `bg-card` / `text-card-foreground`: 카드 배경/텍스트 - `bg-muted` / `text-muted-foreground`: 보조 배경/텍스트 - `bg-primary` / `text-primary`: 메인 액션 - `bg-destructive` / `text-destructive`: 삭제/에러 - `border-border`: 테두리 - `ring-ring`: 포커스 링 ## 3. Typography (타이포그래피) ### 표준 텍스트 크기와 가중치 ```tsx // 페이지 제목

// 섹션 제목

// 본문 텍스트

// 보조 텍스트

// 라벨

// 24px // 섹션 레벨 간격
// 16px // 필드 레벨 간격
// 8px // 패딩
// 24px (카드)
// 16px (내부 섹션) // 갭
// 16px (flex/grid)
// 8px (버튼 그룹) ``` ## 5. 검색 툴바 (Toolbar) ### 패턴 A: 통합 검색 영역 (권장) ```tsx
{/* 검색 및 액션 영역 */}
{/* 검색 영역 */}
{/* 통합 검색 */}
{/* 고급 검색 토글 */}
{/* 액션 버튼 영역 */}
총{" "} {count.toLocaleString()} {" "} 건
{/* 고급 검색 옵션 */} {showAdvanced && (

고급 검색 옵션

설명

)}
``` ### 패턴 B: 제목 + 검색 + 버튼 한 줄 (공간 효율적) ```tsx { /* 상단 헤더: 제목 + 검색 + 버튼 */ }
{/* 왼쪽: 제목 */}

페이지 제목

{/* 오른쪽: 검색 + 버튼 */}
{/* 필터 선택 */}
{/* 검색 입력 */}
{/* 초기화 버튼 */} {/* 주요 액션 버튼 */} {/* 조건부 버튼 (선택 시) */} {selectedCount > 0 && ( )}
; ``` **필수 적용 사항:** - ❌ 검색 영역에 박스/테두리 사용 금지 - ✅ 검색창 권장 너비: `w-full sm:w-[240px]` ~ `sm:w-[400px]` - ✅ 필터/Select 권장 너비: `w-full sm:w-[160px]` ~ `sm:w-[200px]` - ✅ 고급 검색 필드: placeholder만 사용 (라벨 제거) - ✅ 검색 아이콘: `Search` (lucide-react) - ✅ Input/Select 높이: `h-10` (40px) - ✅ 상단 헤더에 `relative` 추가 (드롭다운 표시용) ## 6. Button (버튼) ### 표준 버튼 variants와 크기 ```tsx // Primary 액션 // Secondary 액션 // Ghost 버튼 (아이콘 전용) // Destructive ``` **표준 크기:** - `h-10`: 기본 버튼 (40px) - `h-9`: 작은 버튼 (36px) - `h-8`: 아이콘 버튼 (32px) **아이콘 크기:** - `h-4 w-4`: 버튼 내 아이콘 (16px) ## 7. Input (입력 필드) ### 표준 Input 스타일 ```tsx // 기본 // 검색 (아이콘 포함)
// 로딩/액티브 // 비활성화 ``` **필수 적용 사항:** - 높이: `h-10` (40px) - 텍스트: `text-sm` - 포커스: 자동 적용 (`ring-2 ring-ring`) ## 8. Table & Card (테이블과 카드) ### 반응형 테이블/카드 구조 ```tsx // 실제 데이터 렌더링 return ( <> {/* 데스크톱 테이블 뷰 (lg 이상) */}
컬럼 데이터
{/* 모바일/태블릿 카드 뷰 (lg 미만) */}
{items.map((item) => (
{/* 헤더 */}

{item.name}

{item.id}

{/* 정보 */}
필드 {item.value}
{/* 액션 */}
))}
); ``` **테이블 표준:** - 헤더: `h-12` (48px), `bg-muted/50`, `font-semibold` - 데이터 행: `h-16` (64px), `hover:bg-muted/50` - 텍스트: `text-sm` **카드 표준:** - 컨테이너: `rounded-lg border bg-card p-4 shadow-sm` - 헤더 제목: `text-base font-semibold` - 부제목: `text-sm text-muted-foreground` - 정보 라벨: `text-sm text-muted-foreground` - 정보 값: `text-sm font-medium` - 버튼: `h-9 flex-1 gap-2 text-sm` ## 9. Loading States (로딩 상태) ### Skeleton UI 패턴 ```tsx // 테이블 스켈레톤 (데스크톱)
... {Array.from({ length: 10 }).map((_, index) => (
))}
// 카드 스켈레톤 (모바일/태블릿)
{Array.from({ length: 6 }).map((_, index) => (
{Array.from({ length: 5 }).map((_, i) => (
))}
))}
``` ## 10. Empty States (빈 상태) ### 표준 Empty State ```tsx

데이터가 없습니다.

``` ## 11. Error States (에러 상태) ### 표준 에러 메시지 ```tsx

오류가 발생했습니다

{errorMessage}

``` ## 12. Responsive Design (반응형) ### Breakpoints - `sm`: 640px (모바일 가로/태블릿) - `md`: 768px (태블릿) - `lg`: 1024px (노트북) - `xl`: 1280px (데스크톱) ### 모바일 우선 패턴 ```tsx // 레이아웃
// 그리드
// 검색창
// 테이블/카드 전환
{/* 데스크톱 테이블 */}
{/* 모바일 카드 */} // 간격
``` ## 13. 좌우 레이아웃 (Side-by-Side Layout) ### 사이드바 + 메인 영역 구조 ```tsx
{/* 좌측 사이드바 (20-30%) */}

사이드바 제목

{/* 사이드바 컨텐츠 */}

항목

설명

{/* 우측 메인 영역 (70-80%) */}

메인 제목

{/* 메인 컨텐츠 */}
{/* 컨텐츠 */}
``` **필수 적용 사항:** - ✅ 좌우 구분: `border-r` 사용 (세로 구분선) - ✅ 간격: `gap-6` (24px) - ✅ 사이드바 패딩: `pr-6` (오른쪽 24px) - ✅ 메인 영역 패딩: `pl-0` (gap으로 간격 확보) - ✅ 비율: 20:80 또는 30:70 - ❌ 과도한 구분선 사용 금지 (세로 구분선 1개만) - ❌ 사이드바와 메인 영역 각각에 추가 border 금지 ## 14. Custom Dropdown (커스텀 드롭다운) ### 커스텀 Select/Dropdown 구조 ```tsx { /* 드롭다운 컨테이너 */ }
{/* 트리거 버튼 */} {/* 드롭다운 메뉴 */} {isOpen && (
{/* 검색 (선택사항) */}
setSearchText(e.target.value)} className="h-8 text-sm" onClick={(e) => e.stopPropagation()} />
{/* 옵션 목록 */}
{options.map((option) => (
{ setValue(option.value); setIsOpen(false); }} > {option.label}
))}
)}
; ``` **필수 적용 사항:** - ✅ z-index: `z-[100]` (다른 요소 위에 표시) - ✅ 그림자: `shadow-lg` (명확한 레이어 구분) - ✅ 최소 너비: `min-w-[200px]` (내용이 잘리지 않도록) - ✅ 최대 높이: `max-h-48` (스크롤 가능) - ✅ 애니메이션: 화살표 아이콘 회전 (`rotate-180`) - ✅ 부모 요소: `relative` 클래스 필요 - ⚠️ 부모에 `overflow-hidden` 사용 시 드롭다운 잘림 주의 **드롭다운이 잘릴 때 해결방법:** ```tsx // 부모 요소의 overflow 제거
// overflow-hidden 제거 // 또는 상단 헤더에 relative 추가
// 드롭다운 포지셔닝 기준점 ``` ## 15. Scroll to Top Button ### 모바일/태블릿 전용 버튼 ```tsx import { ScrollToTop } from "@/components/common/ScrollToTop"; // 페이지에 추가 ; ``` **특징:** - 데스크톱에서 숨김 (`lg:hidden`) - 스크롤 200px 이상 시 나타남 - 부드러운 페이드 인/아웃 애니메이션 - 오른쪽 하단 고정 위치 - 원형 디자인 (`rounded-full`) ## 14. Accessibility (접근성) ### 필수 적용 사항 ```tsx // Label과 Input 연결 // 버튼에 aria-label // Switch에 aria-label // 포커스 표시 (자동 적용) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ``` ## 15. Class 순서 (일관성) ### 표준 클래스 작성 순서 1. Layout: `flex`, `grid`, `block` 2. Position: `fixed`, `absolute`, `relative` 3. Sizing: `w-full`, `h-10` 4. Spacing: `p-4`, `m-2`, `gap-4` 5. Typography: `text-sm`, `font-medium` 6. Colors: `bg-primary`, `text-white` 7. Border: `border`, `rounded-md` 8. Effects: `shadow-sm`, `opacity-50` 9. States: `hover:`, `focus:`, `disabled:` 10. Responsive: `sm:`, `md:`, `lg:` ## 16. 금지 사항 ### ❌ 절대 사용하지 말 것 1. 하드코딩된 색상 (`bg-gray-50`, `text-blue-500` 등) 2. 인라인 스타일로 색상 지정 (`style={{ color: '#3b82f6' }}`) 3. 포커스 스타일 제거 (`outline-none`만 단독 사용) 4. 중첩된 박스 (Card 안에 Card, Border 안에 Border) 5. 검색 영역에 불필요한 박스/테두리 6. 검색 필드에 라벨 (placeholder만 사용) 7. 반응형 무시 (데스크톱 전용 스타일) 8. **이모지 사용** (사용자가 명시적으로 요청하지 않는 한 절대 사용 금지) 9. 과도한 구분선 사용 (최소한으로 유지) 10. 드롭다운 부모에 `overflow-hidden` (잘림 발생) ## 17. 체크리스트 새로운 관리자 페이지 작성 시 다음을 확인하세요: ### 페이지 레벨 - [ ] `bg-background` 사용 (하드코딩 금지) - [ ] `space-y-6 p-6` 구조 - [ ] 페이지 헤더에 `border-b pb-4` - [ ] `ScrollToTop` 컴포넌트 포함 ### 검색 툴바 - [ ] 박스/테두리 없음 - [ ] 검색창 최대 너비 `sm:w-[400px]` - [ ] 고급 검색 필드에 라벨 없음 (placeholder만) - [ ] 반응형 레이아웃 적용 ### 테이블/카드 - [ ] 데스크톱: 테이블 (`hidden lg:block`) - [ ] 모바일: 카드 (`lg:hidden`) - [ ] 표준 높이와 간격 적용 - [ ] 로딩/Empty 상태 구현 ### 버튼 - [ ] 표준 variants 사용 - [ ] 표준 높이: `h-10`, `h-9`, `h-8` - [ ] 아이콘 크기: `h-4 w-4` - [ ] `gap-2`로 아이콘과 텍스트 간격 ### 반응형 - [ ] 모바일 우선 디자인 - [ ] Breakpoints 적용 (`sm:`, `lg:`) - [ ] 테이블/카드 전환 - [ ] Scroll to Top 버튼 ### 접근성 - [ ] Label `htmlFor` / Input `id` 연결 - [ ] 버튼 `aria-label` - [ ] Switch `aria-label` - [ ] 포커스 표시 유지 ## 참고 파일 완성된 예시: ### 기본 패턴 - [사용자 관리 페이지]() - 기본 페이지 구조 - [검색 툴바](mdc:frontend/components/admin/UserToolbar.tsx) - 패턴 A (통합 검색) - [테이블/카드](mdc:frontend/components/admin/UserTable.tsx) - 반응형 테이블/카드 - [Scroll to Top](mdc:frontend/components/common/ScrollToTop.tsx) - 스크롤 버튼 ### 고급 패턴 - [메뉴 관리 페이지]() - 좌우 레이아웃 + 패턴 B (제목+검색+버튼) - [메뉴 관리 컴포넌트](mdc:frontend/components/admin/MenuManagement.tsx) - 커스텀 드롭다운 + 좌우 레이아웃