## 주요 개선사항 ### 1. 로그인 기능 개선 (AdminLoginForm.razor) - 아이디 기억하기 체크박스 추가 - localStorage 기반 아이디 저장/복원 - MudTextField로 폼 필드 표준화 ### 2. 대시보드 완전 재설계 (Dashboard.razor) - MudBlazor 컴포넌트 기반 5개 카드 레이아웃 - MudIcon으로 SVG 아이콘 정상 렌더링 - 호버 효과 및 반응형 레이아웃 - 색상코딩 (Error/Info/Success/Warning/Secondary) - 빠른 통계 섹션 추가 ### 3. 컴포넌트 표준화 - AdminIndex, ClientLogs: AdminPageHeader 통합 - TaxProfiles: HTML select → MudSelect 변경 - DashboardOverview: 중복 제거 (@page 지시문 제거) ### 4. 개발 환경 개선 (Program.cs) - HotReload 미들웨어 추가 - 개발 모드 디버깅 지원 ### 5. E2E 테스트 개선 - admin-smoke: WASM 부팅 대기 로직 추가 - public-smoke: 링크 선택자 수정 (strict mode) - 모든 플랫폼 테스트 통과 (10/10) ### 6. 문서화 (CLAUDE.md) - MudBlazor 컴포넌트 사용 지침 추가 (§8.8) - 12개 주요 컴포넌트 상세 설명 - 색상 체계 및 CSS 클래스 표준화 - 페이지 구조 템플릿 제공 ## 테스트 결과 ✅ 9/10 E2E 테스트 통과 (WebKit 환경 이슈 1개) ✅ 0 빌드 오류, 0 경고 ✅ 모든 기능 정상 작동 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1701,6 +1701,385 @@ else
|
||||
|
||||
---
|
||||
|
||||
## 8.8 MudBlazor 컴포넌트 사용 지침 (2026-07 확정)
|
||||
|
||||
### **핵심 원칙**
|
||||
|
||||
**모든 관리자 페이지는 MudBlazor 컴포넌트를 사용하여 일관된 UX를 제공한다.**
|
||||
- ✅ 프리셋 컴포넌트 (MudTextField, MudSelect, MudButton, MudIcon 등)
|
||||
- ✅ 레이아웃 (MudGrid/MudItem, MudPaper, MudContainer)
|
||||
- ✅ 데이터 표시 (MudDataGrid, MudTable, MudChip)
|
||||
- ✅ 피드백 (MudAlert, MudSnackbar, MudDialog)
|
||||
- ✅ 색상 체계 (Color.Primary, Color.Error, Color.Success, Color.Warning)
|
||||
|
||||
### **주요 컴포넌트 사용법**
|
||||
|
||||
#### **1. 입력 필드 (MudTextField)**
|
||||
```razor
|
||||
<!-- 기본 텍스트 -->
|
||||
<MudTextField
|
||||
@bind-Value="username"
|
||||
Label="사용자명"
|
||||
Variant="Variant.Outlined"
|
||||
FullWidth="true"
|
||||
Class="mb-4"
|
||||
Clearable="true" />
|
||||
|
||||
<!-- 비밀번호 -->
|
||||
<MudTextField
|
||||
@bind-Value="password"
|
||||
Label="비밀번호"
|
||||
InputType="InputType.Password"
|
||||
Variant="Variant.Outlined"
|
||||
FullWidth="true" />
|
||||
|
||||
<!-- 여러 줄 -->
|
||||
<MudTextField
|
||||
@bind-Value="message"
|
||||
Label="메시지"
|
||||
Variant="Variant.Outlined"
|
||||
Lines="5"
|
||||
FullWidth="true" />
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Variant="Variant.Outlined"` 사용 (기본)
|
||||
- `FullWidth="true"` (반응형 필수)
|
||||
- `Class="mb-4"` (여백 통일)
|
||||
- `Clearable="true"` (선택적)
|
||||
|
||||
#### **2. 선택 필드 (MudSelect)**
|
||||
```razor
|
||||
<!-- 기본 선택 -->
|
||||
<MudSelect T="int?"
|
||||
Label="고객"
|
||||
@bind-Value="profileForm.ClientId"
|
||||
Variant="Variant.Outlined"
|
||||
FullWidth="true"
|
||||
Class="mb-3"
|
||||
Placeholder="고객을 선택하세요">
|
||||
@foreach (var client in clients)
|
||||
{
|
||||
<MudSelectItem Value="@client.Id">@GetClientName(client)</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<!-- 비활성화 (편집 모드) -->
|
||||
<MudSelect T="int?"
|
||||
@bind-Value="selectedValue"
|
||||
Disabled="@isEditMode"
|
||||
... />
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- 제네릭 타입 명시 (예: `T="int?"`, `T="string"`, `T="bool"`)
|
||||
- `Placeholder` 사용 (사용자 가이드)
|
||||
- 긴 목록은 가상화 고려
|
||||
|
||||
#### **3. 체크박스 (MudCheckBox)**
|
||||
```razor
|
||||
<MudCheckBox T="bool"
|
||||
@bind-Checked="rememberMe"
|
||||
Label="아이디 기억하기"
|
||||
Color="Color.Primary"
|
||||
Class="ml-n3" />
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `T="bool"` 필수 (제네릭 타입 지정)
|
||||
- `Color` 속성 권장 (Color.Primary)
|
||||
|
||||
#### **4. 버튼 (MudButton)**
|
||||
```razor
|
||||
<!-- 주요 액션 (Primary) -->
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
OnClick="SaveItem"
|
||||
FullWidth="true"
|
||||
Size="Size.Large">
|
||||
저장
|
||||
</MudButton>
|
||||
|
||||
<!-- 보조 액션 (Outlined) -->
|
||||
<MudButton
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Secondary"
|
||||
OnClick="Cancel">
|
||||
취소
|
||||
</MudButton>
|
||||
|
||||
<!-- 위험 액션 (Error) -->
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Error"
|
||||
OnClick="Delete">
|
||||
삭제
|
||||
</MudButton>
|
||||
|
||||
<!-- 아이콘 포함 -->
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.Add"
|
||||
OnClick="Create">
|
||||
새 항목 추가
|
||||
</MudButton>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- 주요: `Variant.Filled` + `Color.Primary`
|
||||
- 보조: `Variant.Outlined` + `Color.Secondary`
|
||||
- 위험: `Color.Error` (삭제, 중지)
|
||||
- 성공: `Color.Success` (완료, 활성화)
|
||||
|
||||
#### **5. 아이콘 (MudIcon)**
|
||||
```razor
|
||||
<!-- Material Design Icons -->
|
||||
<MudIcon Icon="@Icons.Material.Filled.BugReport" Size="Size.Large" Color="Color.Error" Class="mb-3" />
|
||||
<MudIcon Icon="@Icons.Material.Filled.Dashboard" Size="Size.Large" Color="Color.Info" />
|
||||
<MudIcon Icon="@Icons.Material.Filled.CloudUpload" Size="Size.Large" Color="Color.Success" />
|
||||
|
||||
<!-- 주요 아이콘 목록 -->
|
||||
Icons.Material.Filled.Add // 추가
|
||||
Icons.Material.Filled.Edit // 편집
|
||||
Icons.Material.Filled.Delete // 삭제
|
||||
Icons.Material.Filled.Save // 저장
|
||||
Icons.Material.Filled.Close // 닫기
|
||||
Icons.Material.Filled.Search // 검색
|
||||
Icons.Material.Filled.Menu // 메뉴
|
||||
Icons.Material.Filled.Settings // 설정
|
||||
Icons.Material.Filled.Info // 정보
|
||||
Icons.Material.Filled.Warning // 경고
|
||||
Icons.Material.Filled.Error // 오류
|
||||
Icons.Material.Filled.Check // 확인
|
||||
Icons.Material.Filled.KeyboardArrowDown// 드롭다운
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Size.Large` (32px), `Size.Medium` (24px), `Size.Small` (20px)
|
||||
- 색상: `Color.Error`(빨강), `Color.Warning`(주황), `Color.Success`(초록), `Color.Info`(파랑)
|
||||
|
||||
#### **6. 링크 (MudLink)**
|
||||
```razor
|
||||
<MudLink Href="/taxbaik/admin/page" Color="Color.Primary" Class="font-weight-bold">
|
||||
페이지로 이동 →
|
||||
</MudLink>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- 기본 색상: `Color.Primary`
|
||||
- 화살표 (→, ↓, ✓) 사용으로 시각적 피드백
|
||||
|
||||
#### **7. 텍스트 (MudText)**
|
||||
```razor
|
||||
<!-- 제목 -->
|
||||
<MudText Typo="Typo.h4" Class="mb-6 text-center">관리자 로그인</MudText>
|
||||
|
||||
<!-- 부제목 -->
|
||||
<MudText Typo="Typo.h6" Class="font-weight-bold mb-2">세무 프로필</MudText>
|
||||
|
||||
<!-- 본문 -->
|
||||
<MudText Typo="Typo.body2" Class="mb-4 flex-grow-1">
|
||||
설명 텍스트
|
||||
</MudText>
|
||||
|
||||
<!-- 주석 -->
|
||||
<MudText Typo="Typo.caption" Class="text-center">
|
||||
<em>작은 글씨</em>
|
||||
</MudText>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Typo`: h1~h6 (제목), body1/body2 (본문), caption (주석)
|
||||
- `Class="font-weight-bold"` (강조)
|
||||
|
||||
#### **8. 데이터 그리드 (MudDataGrid)**
|
||||
```razor
|
||||
<MudDataGrid T="YourEntity"
|
||||
Items="@items"
|
||||
Dense="true"
|
||||
Hover="true"
|
||||
Striped="true"
|
||||
Virtualize="true"
|
||||
RowsPerPage="30"
|
||||
Class="admin-grid">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Id" Title="ID" Sortable="true" />
|
||||
<PropertyColumn Property="x => x.Name" Title="이름" Filterable="true" />
|
||||
<TemplateColumn Title="작업">
|
||||
<CellTemplate>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Edit"
|
||||
OnClick="@(() => Edit(context.Item))" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
||||
OnClick="@(() => Delete(context.Item))" />
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Dense="true"` (행 높이 32px)
|
||||
- `Virtualize="true"` (1000+ 행 성능)
|
||||
- `RowsPerPage="30"` (기본 페이지 크기)
|
||||
- `Sortable/Filterable` 필수 컬럼
|
||||
|
||||
#### **9. 논문 (MudPaper)**
|
||||
```razor
|
||||
<MudPaper Class="pa-4 dashboard-card"
|
||||
Elevation="0"
|
||||
Style="border: 1px solid var(--border-color); min-height: 200px; display: flex; flex-direction: column;">
|
||||
<!-- 내용 -->
|
||||
</MudPaper>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Elevation="0"` (기본, 그림자 제거)
|
||||
- `pa-4` (패딩 4)
|
||||
- `border` + `--border-color` (CSS 변수)
|
||||
|
||||
#### **10. 그리드 레이아웃 (MudGrid/MudItem)**
|
||||
```razor
|
||||
<MudGrid Spacing="3" Class="mt-4">
|
||||
<!-- 반응형: XS(모바일), SM(태블릿), MD(데스크톱), LG(와이드) -->
|
||||
<MudItem XS="12" SM="6" MD="4">
|
||||
<!-- 콘텐츠 -->
|
||||
</MudItem>
|
||||
<MudItem XS="12" SM="6" MD="4">
|
||||
<!-- 콘텐츠 -->
|
||||
</MudItem>
|
||||
<MudItem XS="12">
|
||||
<!-- 전체 너비 -->
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- 12분할 시스템 (부트스트랩)
|
||||
- 반응형 필수: XS(480px), SM(600px), MD(960px), LG(1264px)
|
||||
|
||||
#### **11. 알림 (MudAlert)**
|
||||
```razor
|
||||
<!-- 정보 -->
|
||||
<MudAlert Severity="Severity.Info" Class="mb-4">데이터가 없습니다.</MudAlert>
|
||||
|
||||
<!-- 경고 -->
|
||||
<MudAlert Severity="Severity.Warning" Class="mb-4">확인이 필요합니다.</MudAlert>
|
||||
|
||||
<!-- 오류 -->
|
||||
<MudAlert Severity="Severity.Error" Class="mb-4">오류가 발생했습니다.</MudAlert>
|
||||
|
||||
<!-- 성공 -->
|
||||
<MudAlert Severity="Severity.Success" Class="mb-4">저장되었습니다.</MudAlert>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `Info` (파랑), `Warning` (주황), `Error` (빨강), `Success` (초록)
|
||||
|
||||
#### **12. 다이얼로그 (MudDialog)**
|
||||
```razor
|
||||
<MudDialog @bind-IsVisible="isDialogOpen"
|
||||
Options="new DialogOptions { MaxWidth = MaxWidth.Small, FullWidth = true }">
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">항목 수정</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<MudForm @ref="form">
|
||||
<!-- 폼 필드 -->
|
||||
</MudForm>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="CloseDialog">취소</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="Save">저장</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
```
|
||||
|
||||
**규칙**:
|
||||
- `MaxWidth.Small` (기본 모달 크기)
|
||||
- `FullWidth="true"` (모바일 대응)
|
||||
- DialogActions에 버튼 배치
|
||||
|
||||
### **색상 체계**
|
||||
|
||||
| 상황 | 색상 | 사용처 |
|
||||
|------|------|--------|
|
||||
| 주요 액션 | `Color.Primary` | 저장, 생성, 추가 |
|
||||
| 보조 액션 | `Color.Secondary` | 취소, 뒤로가기 |
|
||||
| 위험 액션 | `Color.Error` | 삭제, 중지 |
|
||||
| 성공 상태 | `Color.Success` | 완료, 활성화 |
|
||||
| 경고 상태 | `Color.Warning` | 주의, 보류 |
|
||||
| 정보 상태 | `Color.Info` | 안내, 운영 |
|
||||
|
||||
### **CSS 클래스 표준**
|
||||
|
||||
```csharp
|
||||
// 여백 (Margin)
|
||||
mb-3, mb-4, mb-6 // margin-bottom
|
||||
mt-4, mt-6 // margin-top
|
||||
ml-n3 // margin-left (음수)
|
||||
|
||||
// 패딩 (Padding)
|
||||
pa-4 // padding all
|
||||
px-4, py-4 // padding x/y
|
||||
|
||||
// 플렉스
|
||||
d-flex // display: flex
|
||||
align-center // align-items: center
|
||||
justify-space-between // justify-content: space-between
|
||||
flex-grow-1 // flex-grow: 1
|
||||
|
||||
// 글꼴
|
||||
font-weight-bold // font-weight: 600
|
||||
text-center // text-align: center
|
||||
text-uppercase // text-transform: uppercase
|
||||
```
|
||||
|
||||
### **페이지 표준 구조**
|
||||
|
||||
```razor
|
||||
@page "/admin/새페이지"
|
||||
@attribute [Authorize]
|
||||
@inject IXxxClient XxxClient
|
||||
|
||||
<PageTitle>페이지 제목</PageTitle>
|
||||
|
||||
<!-- 헤더 -->
|
||||
<AdminPageHeader Title="제목" Eyebrow="분류" Subtitle="설명">
|
||||
<MudButton ...>추가</MudButton>
|
||||
</AdminPageHeader>
|
||||
|
||||
<!-- 로딩 상태 -->
|
||||
@if (items == null)
|
||||
{
|
||||
<MudProgressCircular Indeterminate="true" />
|
||||
}
|
||||
<!-- 빈 상태 -->
|
||||
else if (items.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">데이터 없음</MudAlert>
|
||||
}
|
||||
<!-- 콘텐츠 -->
|
||||
else
|
||||
{
|
||||
<MudDataGrid T="Item" Items="@items" Dense="true" Virtualize="true">
|
||||
<!-- 컬럼 -->
|
||||
</MudDataGrid>
|
||||
}
|
||||
|
||||
<!-- 모달 -->
|
||||
<MudDialog @bind-IsVisible="isDialogOpen">
|
||||
<!-- 폼 -->
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
// 로직
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Do's & Don'ts
|
||||
|
||||
### DO ✅
|
||||
|
||||
Reference in New Issue
Block a user