524 lines
11 KiB
Markdown
524 lines
11 KiB
Markdown
# shadcn/ui 적용 상태 분석 보고서
|
|
|
|
> 작성일: 2025-01-27
|
|
> 기준: shadcn/ui 공식 문서 (https://ui.shadcn.com)
|
|
|
|
## 📋 목차
|
|
|
|
1. [개요](#개요)
|
|
2. [적용 상태 요약](#적용-상태-요약)
|
|
3. [양호한 부분](#양호한-부분)
|
|
4. [개선이 필요한 부분](#개선이-필요한-부분)
|
|
5. [우선순위별 개선 사항](#우선순위별-개선-사항)
|
|
6. [구체적인 수정 필요 파일](#구체적인-수정-필요-파일)
|
|
|
|
---
|
|
|
|
## 개요
|
|
|
|
이 보고서는 프로젝트 전반에 걸쳐 shadcn/ui 공식 문서 기준을 얼마나 잘 준수하고 있는지 분석한 결과입니다.
|
|
|
|
**분석 범위:**
|
|
|
|
- 설정 파일 (components.json, globals.css, tailwind.config)
|
|
- UI 컴포넌트 (`frontend/components/ui/`)
|
|
- 비즈니스 컴포넌트 (`frontend/components/`, `frontend/lib/registry/`)
|
|
- 스타일 가이드 준수 여부
|
|
|
|
---
|
|
|
|
## 적용 상태 요약
|
|
|
|
### ✅ 잘 적용된 부분 (70%)
|
|
|
|
1. **기본 설정**
|
|
|
|
- `components.json` 설정 올바름
|
|
- CSS 변수 시스템 정상 작동
|
|
- `cn()` 유틸리티 함수 사용
|
|
|
|
2. **기본 UI 컴포넌트**
|
|
- Button, Card, Input 등 기본 컴포넌트는 shadcn 표준 따름
|
|
- 다크모드 지원 구조 정상
|
|
|
|
### ⚠️ 개선이 필요한 부분 (30%)
|
|
|
|
1. **하드코딩된 색상 사용** (약 2,000+ 건)
|
|
|
|
- `bg-blue-500`, `bg-gray-50`, `text-red-500` 등 직접 색상 사용
|
|
- `#ffffff`, `#f9fafb` 등 인라인 스타일 색상
|
|
|
|
2. **비표준 스타일 패턴**
|
|
|
|
- `border-blue-500`, `ring-blue-100` 등 직접 색상 사용
|
|
- `focus:border-orange-500` 등 커스텀 포커스 색상
|
|
|
|
3. **중첩 박스 문제**
|
|
- 일부 컴포넌트에서 불필요한 중첩 구조 발견
|
|
|
|
---
|
|
|
|
## 양호한 부분
|
|
|
|
### 1. 기본 설정 ✅
|
|
|
|
**components.json**
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://ui.shadcn.com/schema.json",
|
|
"style": "new-york",
|
|
"rsc": true,
|
|
"tsx": true,
|
|
"tailwind": {
|
|
"baseColor": "neutral",
|
|
"cssVariables": true
|
|
}
|
|
}
|
|
```
|
|
|
|
✅ shadcn 공식 설정과 일치
|
|
|
|
**globals.css**
|
|
|
|
```css
|
|
:root {
|
|
--background: 0 0% 100%;
|
|
--foreground: 222.2 84% 4.9%;
|
|
--primary: 222.2 47.4% 11.2%;
|
|
/* ... */
|
|
}
|
|
```
|
|
|
|
✅ HSL 형식, 공식 기본값 사용
|
|
|
|
### 2. 기본 UI 컴포넌트 ✅
|
|
|
|
**Button 컴포넌트** (`frontend/components/ui/button.tsx`)
|
|
|
|
```tsx
|
|
const buttonVariants = cva("inline-flex items-center justify-center ...", {
|
|
variants: {
|
|
variant: {
|
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
destructive: "bg-destructive text-white ...",
|
|
// ...
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
✅ shadcn 공식 패턴 준수
|
|
|
|
**Card 컴포넌트** (`frontend/components/ui/card.tsx`)
|
|
|
|
```tsx
|
|
function Card({ className, ...props }) {
|
|
return (
|
|
<div className={cn("bg-card text-card-foreground rounded-xl border ...")} />
|
|
);
|
|
}
|
|
```
|
|
|
|
✅ CSS 변수 사용, 표준 구조
|
|
|
|
**Input 컴포넌트** (`frontend/components/ui/input.tsx`)
|
|
|
|
```tsx
|
|
className={cn(
|
|
"border-input bg-transparent ...",
|
|
"focus-visible:border-ring focus-visible:ring-ring/50 ...",
|
|
className
|
|
)}
|
|
```
|
|
|
|
✅ 시맨틱 색상 사용
|
|
|
|
### 3. 유틸리티 함수 ✅
|
|
|
|
**lib/utils.ts**
|
|
|
|
```typescript
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
```
|
|
|
|
✅ 공식 구현과 동일
|
|
|
|
---
|
|
|
|
## 개선이 필요한 부분
|
|
|
|
### 1. 하드코딩된 색상 사용 ❌
|
|
|
|
#### 문제점
|
|
|
|
**직접 색상 클래스 사용** (약 1,600+ 건)
|
|
|
|
```tsx
|
|
// ❌ 잘못된 예시
|
|
<div className="bg-blue-500 text-white">버튼</div>
|
|
<div className="bg-gray-50 text-gray-700">카드</div>
|
|
<span className="text-red-500">에러</span>
|
|
```
|
|
|
|
**인라인 스타일 색상** (약 354건)
|
|
|
|
```tsx
|
|
// ❌ 잘못된 예시
|
|
<div style={{ backgroundColor: "#ffffff" }}>
|
|
<div style={{ backgroundColor: "#f9fafb" }}>
|
|
<div style={{ color: "#64748b" }}>
|
|
```
|
|
|
|
#### 올바른 패턴
|
|
|
|
```tsx
|
|
// ✅ 올바른 예시
|
|
<div className="bg-primary text-primary-foreground">버튼</div>
|
|
<div className="bg-muted text-muted-foreground">카드</div>
|
|
<span className="text-destructive">에러</span>
|
|
```
|
|
|
|
### 2. 비표준 포커스 스타일 ❌
|
|
|
|
#### 문제점
|
|
|
|
**직접 색상 사용**
|
|
|
|
```tsx
|
|
// ❌ 잘못된 예시 (TextInputComponent.tsx)
|
|
className={`
|
|
${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"}
|
|
focus:border-orange-500 focus:ring-2 focus:ring-orange-100
|
|
`}
|
|
```
|
|
|
|
#### 올바른 패턴
|
|
|
|
```tsx
|
|
// ✅ 올바른 예시
|
|
className={cn(
|
|
"border-input",
|
|
isSelected && "border-ring ring-2 ring-ring/50",
|
|
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2"
|
|
)}
|
|
```
|
|
|
|
### 3. 불필요한 인라인 스타일 ❌
|
|
|
|
#### 문제점
|
|
|
|
**하드코딩된 색상 값**
|
|
|
|
```tsx
|
|
// ❌ 잘못된 예시 (TableListComponent.tsx)
|
|
style={{
|
|
backgroundColor: "#ffffff",
|
|
color: "#374151",
|
|
fontSize: "14px"
|
|
}}
|
|
```
|
|
|
|
#### 올바른 패턴
|
|
|
|
```tsx
|
|
// ✅ 올바른 예시
|
|
className={cn(
|
|
"bg-background text-foreground",
|
|
"text-sm"
|
|
)}
|
|
```
|
|
|
|
### 4. 중첩 박스 문제 ⚠️
|
|
|
|
**일부 컴포넌트에서 발견**
|
|
|
|
```tsx
|
|
// ⚠️ 중첩된 구조 (CardLayoutRenderer.tsx)
|
|
<Card>
|
|
<CardContent>
|
|
<div className="border rounded-lg p-4">
|
|
{" "}
|
|
{/* 중첩된 박스 */}
|
|
내용
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
```
|
|
|
|
**권장 구조**
|
|
|
|
```tsx
|
|
// ✅ 단일 레벨
|
|
<Card>
|
|
<CardContent>내용</CardContent>
|
|
</Card>
|
|
```
|
|
|
|
---
|
|
|
|
## 우선순위별 개선 사항
|
|
|
|
### 🔴 Priority 1: 핵심 컴포넌트 수정 (즉시)
|
|
|
|
**대상 파일:**
|
|
|
|
1. `frontend/lib/registry/components/text-input/TextInputComponent.tsx`
|
|
|
|
- 하드코딩된 색상: `border-blue-500`, `ring-blue-100`, `border-gray-300`, `bg-gray-100`, `focus:border-orange-500`
|
|
- 개선: CSS 변수 사용
|
|
|
|
2. `frontend/lib/registry/components/date-input/DateInputComponent.tsx`
|
|
|
|
- 동일한 문제 패턴
|
|
|
|
3. `frontend/lib/registry/components/table-list/TableListComponent.tsx`
|
|
- 인라인 스타일 색상: `#ffffff`, `#374151`, `#64748b`
|
|
|
|
### 🟡 Priority 2: 페이지 레벨 수정 (단기)
|
|
|
|
**대상 파일:**
|
|
|
|
1. `frontend/app/(main)/dashboard/page.tsx`
|
|
|
|
- `bg-blue-500`, `text-white`, `bg-gray-50`, `text-gray-900` 등
|
|
|
|
2. `frontend/app/(main)/dashboard/[dashboardId]/page.tsx`
|
|
|
|
- 동일한 패턴
|
|
|
|
3. `frontend/components/screen/InteractiveScreenViewer.tsx`
|
|
- `bg-gray-50`, `text-gray-700` 등
|
|
|
|
### 🟢 Priority 3: 위젯/차트 컴포넌트 (중기)
|
|
|
|
**대상 파일:**
|
|
|
|
1. `frontend/components/dashboard/widgets/*.tsx`
|
|
|
|
- 위젯별 커스텀 색상이 필요할 수 있으나, 가능한 한 CSS 변수 사용
|
|
|
|
2. `frontend/components/admin/dashboard/widgets/*.tsx`
|
|
- 동일
|
|
|
|
### ⚪ Priority 4: 기타 (장기)
|
|
|
|
**대상 파일:**
|
|
|
|
- 나머지 모든 파일에서 하드코딩된 색상 점진적 교체
|
|
|
|
---
|
|
|
|
## 구체적인 수정 필요 파일
|
|
|
|
### 📁 핵심 컴포넌트 (즉시 수정 필요)
|
|
|
|
#### 1. TextInputComponent.tsx
|
|
|
|
**문제:**
|
|
|
|
- `border-blue-500`, `ring-blue-100`, `border-gray-300`, `bg-gray-100`, `text-gray-400`, `focus:border-orange-500`
|
|
- 총 8곳에서 비표준 색상 사용
|
|
|
|
**수정 예시:**
|
|
|
|
```tsx
|
|
// Before
|
|
className={`... ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ...`}
|
|
|
|
// After
|
|
className={cn(
|
|
"border-input",
|
|
isSelected && "border-ring ring-2 ring-ring/50",
|
|
"focus-visible:border-ring focus-visible:ring-ring/50"
|
|
)}
|
|
```
|
|
|
|
#### 2. DateInputComponent.tsx
|
|
|
|
**문제:**
|
|
|
|
- TextInputComponent와 동일한 패턴
|
|
|
|
#### 3. TableListComponent.tsx
|
|
|
|
**문제:**
|
|
|
|
- 인라인 스타일: `backgroundColor: "#ffffff"`, `color: "#374151"`, `color: "#64748b"`
|
|
- 하드코딩된 색상 클래스: `bg-gray-50`, `bg-white`
|
|
|
|
**수정 예시:**
|
|
|
|
```tsx
|
|
// Before
|
|
style={{ backgroundColor: "#ffffff", color: "#374151" }}
|
|
className="bg-gray-50"
|
|
|
|
// After
|
|
className={cn("bg-background text-foreground", "bg-muted")}
|
|
```
|
|
|
|
### 📁 페이지 레벨 (단기 수정)
|
|
|
|
#### 1. dashboard/page.tsx
|
|
|
|
**문제:**
|
|
|
|
- `bg-blue-500`, `text-white`, `hover:bg-blue-600`
|
|
- `bg-gray-50`, `text-gray-900`, `text-gray-600`
|
|
|
|
**수정 예시:**
|
|
|
|
```tsx
|
|
// Before
|
|
<button className="bg-blue-500 text-white hover:bg-blue-600">
|
|
<h1 className="text-gray-900">제목</h1>
|
|
|
|
// After
|
|
<Button>버튼</Button>
|
|
<h1 className="text-foreground">제목</h1>
|
|
```
|
|
|
|
#### 2. screen/InteractiveScreenViewer.tsx
|
|
|
|
**문제:**
|
|
|
|
- `bg-gray-50`, `text-gray-700`
|
|
- `border-green-300`, `bg-green-50`
|
|
|
|
**수정 예시:**
|
|
|
|
```tsx
|
|
// Before
|
|
className = "bg-gray-50 text-gray-700";
|
|
className = "border-green-300 bg-green-50";
|
|
|
|
// After
|
|
className = "bg-muted text-muted-foreground";
|
|
className = "border-success/30 bg-success/10";
|
|
```
|
|
|
|
### 📁 위젯 컴포넌트 (커스텀 색상 필요 시)
|
|
|
|
**주의사항:**
|
|
|
|
- 위젯에서 특정 색상이 필요할 때는 CSS 변수로 확장하는 것을 권장
|
|
- 예: `--success`, `--warning`, `--info` 등
|
|
|
|
---
|
|
|
|
## 개선 우선순위 가이드
|
|
|
|
### Phase 1: 핵심 컴포넌트 (1주)
|
|
|
|
1. ✅ TextInputComponent.tsx
|
|
2. ✅ DateInputComponent.tsx
|
|
3. ✅ TableListComponent.tsx
|
|
|
|
### Phase 2: 주요 페이지 (2주)
|
|
|
|
1. ✅ Dashboard 페이지들
|
|
2. ✅ Screen 페이지들
|
|
3. ✅ Admin 페이지들
|
|
|
|
### Phase 3: 위젯/차트 (3주)
|
|
|
|
1. ✅ Dashboard 위젯들
|
|
2. ✅ 차트 컴포넌트들
|
|
3. ✅ 3D 위젯들
|
|
|
|
### Phase 4: 전체 정리 (장기)
|
|
|
|
1. ✅ 나머지 모든 파일 점진적 교체
|
|
2. ✅ 린터 규칙 추가 (하드코딩 색상 금지)
|
|
3. ✅ 코드 리뷰 가이드라인 업데이트
|
|
|
|
---
|
|
|
|
## 개선 효과
|
|
|
|
### 예상 효과
|
|
|
|
1. **일관성 향상**
|
|
|
|
- 모든 컴포넌트가 동일한 색상 시스템 사용
|
|
- 다크모드 전환 시 자동 대응
|
|
|
|
2. **유지보수성 향상**
|
|
|
|
- 색상 변경 시 CSS 변수만 수정하면 전체 반영
|
|
- 테마 커스터마이징 용이
|
|
|
|
3. **접근성 향상**
|
|
|
|
- 시맨틱 색상 사용으로 의미 전달 명확
|
|
- 다크모드 지원 자동화
|
|
|
|
4. **코드 품질 향상**
|
|
- 하드코딩 제거로 코드 간결화
|
|
- shadcn 공식 문서 준수
|
|
|
|
---
|
|
|
|
## 체크리스트
|
|
|
|
### 기본 설정
|
|
|
|
- [x] components.json 설정 올바름
|
|
- [x] globals.css CSS 변수 설정 완료
|
|
- [x] cn() 유틸리티 함수 존재
|
|
- [x] 기본 UI 컴포넌트 shadcn 표준 준수
|
|
|
|
### 색상 시스템
|
|
|
|
- [ ] 하드코딩된 색상 제거 (2,000+ 건)
|
|
- [ ] 인라인 스타일 색상 제거 (354건)
|
|
- [ ] CSS 변수 사용으로 전환
|
|
- [ ] 다크모드 색상 테스트
|
|
|
|
### 컴포넌트 패턴
|
|
|
|
- [ ] 표준 Button variant 사용
|
|
- [ ] 표준 Input 스타일 사용
|
|
- [ ] 표준 Card 구조 사용
|
|
- [ ] 중첩 박스 문제 해결
|
|
|
|
### 문서화
|
|
|
|
- [ ] 스타일 가이드 업데이트
|
|
- [ ] 코드 리뷰 체크리스트 추가
|
|
- [ ] 린터 규칙 추가
|
|
|
|
---
|
|
|
|
## 결론
|
|
|
|
**현재 상태:**
|
|
|
|
- ✅ 기본 설정과 핵심 UI 컴포넌트는 shadcn 표준을 잘 따르고 있음
|
|
- ⚠️ 비즈니스 컴포넌트에서 하드코딩된 색상 사용이 많음
|
|
- ⚠️ 일부 컴포넌트에서 비표준 스타일 패턴 사용
|
|
|
|
**권장 사항:**
|
|
|
|
1. **즉시 조치**: 핵심 컴포넌트 (TextInput, DateInput, TableList) 색상 통일
|
|
2. **단기 조치**: 주요 페이지 레벨 색상 교체
|
|
3. **중기 조치**: 위젯/차트 컴포넌트 점진적 개선
|
|
4. **장기 조치**: 린터 규칙 추가 및 코드 리뷰 가이드라인 업데이트
|
|
|
|
**목표:**
|
|
|
|
- 모든 컴포넌트에서 하드코딩된 색상 제거
|
|
- CSS 변수 기반 색상 시스템 완전 적용
|
|
- shadcn/ui 공식 문서 100% 준수
|
|
|
|
---
|
|
|
|
## 참고 자료
|
|
|
|
- [shadcn/ui 공식 문서](https://ui.shadcn.com)
|
|
- [프로젝트 shadcn 가이드](./shadcn-ui-완전가이드.md)
|
|
- [프로젝트 스타일 가이드](../.cursor/rules/admin-page-style-guide.mdc)
|