Agents: - ui-scout: Playwright MCP + Variant(variant.com/community) visual capture - design-system-architect: unified design tokens (CSS vars / RN StyleSheet) - component-refactor-engineer: per-system component refactoring - visual-qa-tester: before/after screenshot comparison Skills: - ui-overhaul-orchestrator: E2E pipeline (capture->tokens->refactor->QA) - playwright-visual-capture: Playwright MCP + Variant workflow - design-token-system: tokens.css with Pretendard, 4px grid, brand colors - component-refactor: Button/Card/Badge patterns for 4 systems Bot: /design capture|variant|tokens|homepage|itsm|manager|app|qa|ab Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
191 lines
6.8 KiB
Markdown
191 lines
6.8 KiB
Markdown
---
|
|
name: component-refactor
|
|
description: "zio 4개 시스템 UI 컴포넌트 전면 리팩토링 스킬. Variant 레퍼런스를 보면서 tokens.css를 적용하고, Header·Footer·Button·Card·Table·Form을 현대적으로 개편한다. A/B 테스트 가능한 Swappable 컴포넌트 구조로 구현. 다음 상황에서 반드시 사용: (1) 'UI 개편', '디자인 전면 개편', 'CSS 리팩토링'; (2) '버튼 스타일 통일', '카드 컴포넌트 개선'; (3) '홈페이지 개편', 'ITSM UI 현대화', 'Manager 디자인'; (4) 다시 실행, 업데이트, 수정, 보완."
|
|
---
|
|
|
|
# UI 컴포넌트 전면 리팩토링 스킬
|
|
|
|
## 개편 원칙
|
|
|
|
1. **tokens.css 우선** — 하드코딩 색상/크기 금지
|
|
2. **Variant 레퍼런스 준수** — ui-scout 캡처 스크린샷 참조
|
|
3. **Swappable 구조** — A/B 테스트 가능하게 컴포넌트 분리
|
|
4. **기존 기능 유지** — 디자인만 변경, 로직 무변경
|
|
|
|
---
|
|
|
|
## 공통 컴포넌트 (4개 시스템 공유 개념)
|
|
|
|
### Button 컴포넌트 표준
|
|
|
|
```css
|
|
/* Primary Button */
|
|
.btn { display:inline-flex; align-items:center; gap:var(--space-2);
|
|
padding:var(--space-2) var(--space-4); border-radius:var(--radius-md);
|
|
font-size:var(--text-sm); font-weight:var(--font-semibold);
|
|
transition:all var(--ease-fast); cursor:pointer; border:none; }
|
|
|
|
.btn-primary { background:var(--color-primary-500); color:var(--color-neutral-0); }
|
|
.btn-primary:hover { background:var(--color-primary-600); box-shadow:var(--shadow-md); }
|
|
.btn-primary:active { transform:translateY(1px); }
|
|
|
|
.btn-secondary { background:var(--color-neutral-100); color:var(--color-neutral-700);
|
|
border:1px solid var(--border); }
|
|
.btn-secondary:hover { background:var(--color-neutral-200); }
|
|
|
|
.btn-ghost { background:transparent; color:var(--color-primary-500); }
|
|
.btn-ghost:hover { background:var(--color-primary-50); }
|
|
|
|
.btn-danger { background:var(--color-danger); color:white; }
|
|
|
|
/* 크기 */
|
|
.btn-sm { padding:var(--space-1) var(--space-3); font-size:var(--text-xs); }
|
|
.btn-lg { padding:var(--space-3) var(--space-6); font-size:var(--text-base); }
|
|
```
|
|
|
|
### Card 컴포넌트 표준
|
|
|
|
```css
|
|
.card {
|
|
background:var(--bg-card); border-radius:var(--radius-lg);
|
|
box-shadow:var(--shadow-sm); border:1px solid var(--border);
|
|
overflow:hidden; transition:box-shadow var(--ease-normal);
|
|
}
|
|
.card:hover { box-shadow:var(--shadow-md); }
|
|
.card-body { padding:var(--space-6); }
|
|
.card-header { padding:var(--space-4) var(--space-6);
|
|
border-bottom:1px solid var(--border);
|
|
font-weight:var(--font-semibold); font-size:var(--text-base); }
|
|
```
|
|
|
|
### Badge/Status 표준
|
|
|
|
```css
|
|
.badge { display:inline-flex; align-items:center; padding:2px var(--space-2);
|
|
border-radius:var(--radius-full); font-size:var(--text-xs); font-weight:var(--font-semibold); }
|
|
.badge-success { background:var(--color-success-bg); color:var(--color-success); }
|
|
.badge-warning { background:var(--color-warning-bg); color:var(--color-warning); }
|
|
.badge-danger { background:var(--color-danger-bg); color:var(--color-danger); }
|
|
.badge-info { background:var(--color-info-bg); color:var(--color-info); }
|
|
```
|
|
|
|
---
|
|
|
|
## 시스템별 주요 개편 코드
|
|
|
|
### 1. 홈페이지 Hero 섹션
|
|
|
|
```jsx
|
|
// Home.jsx 히어로 — 그라디언트 + 애니메이션
|
|
<section style={{
|
|
background: 'linear-gradient(135deg, var(--color-primary-900) 0%, var(--color-primary-600) 60%, var(--color-accent-600) 100%)',
|
|
padding: 'var(--space-24) 0',
|
|
position: 'relative', overflow: 'hidden',
|
|
}}>
|
|
<div style={{ position:'absolute', inset:0,
|
|
background: 'radial-gradient(ellipse at 70% 50%, rgba(0,163,224,.15) 0%, transparent 60%)' }} />
|
|
<div className="container" style={{ position:'relative', zIndex:1 }}>
|
|
<h1 style={{ fontSize:'var(--text-5xl)', fontWeight:'var(--font-black)',
|
|
color:'white', lineHeight:'var(--leading-tight)', marginBottom:'var(--space-6)' }}>
|
|
AI가 운영하는<br/><span style={{ color:'var(--color-accent-400)' }}>인프라 자동화</span>
|
|
</h1>
|
|
</div>
|
|
</section>
|
|
```
|
|
|
|
### 2. ITSM 사이드바 현대화
|
|
|
|
```css
|
|
/* itsm/static/style.css — 사이드바 토큰 적용 */
|
|
#sidebar {
|
|
width: 240px;
|
|
background: var(--bg-surface);
|
|
border-right: 1px solid var(--border);
|
|
transition: width var(--ease-normal);
|
|
}
|
|
#sidebar.collapsed { width: 64px; }
|
|
|
|
.nav-item {
|
|
display: flex; align-items: center; gap: var(--space-3);
|
|
padding: var(--space-2) var(--space-4);
|
|
border-radius: var(--radius-md); margin: var(--space-1) var(--space-2);
|
|
color: var(--text-muted); font-size: var(--text-sm);
|
|
transition: all var(--ease-fast); cursor: pointer;
|
|
}
|
|
.nav-item:hover { background: var(--color-primary-50); color: var(--color-primary-500); }
|
|
.nav-item.active { background: var(--color-primary-500); color: white;
|
|
box-shadow: var(--shadow-sm); }
|
|
```
|
|
|
|
### 3. Manager 통계 카드
|
|
|
|
```tsx
|
|
// manager/frontend/src/components/common/StatCard.tsx
|
|
function StatCard({ label, value, unit, change, icon, color = 'primary' }) {
|
|
return (
|
|
<div style={{ background:'var(--bg-card)', borderRadius:'var(--radius-lg)',
|
|
padding:'var(--space-6)', boxShadow:'var(--shadow-sm)',
|
|
borderTop:`4px solid var(--color-${color}-500)` }}>
|
|
<div style={{ display:'flex', justifyContent:'space-between' }}>
|
|
<div>
|
|
<p style={{ fontSize:'var(--text-xs)', color:'var(--text-muted)',
|
|
fontWeight:'var(--font-semibold)', textTransform:'uppercase', letterSpacing:'.05em' }}>
|
|
{label}
|
|
</p>
|
|
<p style={{ fontSize:'var(--text-3xl)', fontWeight:'var(--font-black)',
|
|
color:'var(--text-main)', marginTop:'var(--space-1)' }}>
|
|
{value}<span style={{ fontSize:'var(--text-lg)' }}>{unit}</span>
|
|
</p>
|
|
</div>
|
|
<div style={{ fontSize:32 }}>{icon}</div>
|
|
</div>
|
|
{change && <p style={{ fontSize:'var(--text-xs)', color: change > 0 ? 'var(--color-success)' : 'var(--color-danger)',
|
|
marginTop:'var(--space-2)' }}>
|
|
{change > 0 ? '↑' : '↓'} {Math.abs(change)}% 전월 대비
|
|
</p>}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 4. Messenger 공통 컴포넌트
|
|
|
|
```tsx
|
|
// app/components/ui/Card.tsx
|
|
import { tokens } from '@/constants/tokens';
|
|
import { View, StyleSheet } from 'react-native';
|
|
|
|
export function Card({ children, elevated = true, style }) {
|
|
return (
|
|
<View style={[styles.card, elevated && styles.elevated, style]}>
|
|
{children}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
card: {
|
|
backgroundColor: '#ffffff',
|
|
borderRadius: tokens.radii.lg,
|
|
padding: tokens.spacing[4],
|
|
borderWidth: 1,
|
|
borderColor: '#e2e8f0',
|
|
},
|
|
elevated: tokens.shadows.md,
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## A/B 테스트 Swappable 구조
|
|
|
|
```jsx
|
|
// 컴포넌트 버전 토글 — feature flag 기반
|
|
const UI_VARIANT = process.env.REACT_APP_UI_VARIANT || 'A';
|
|
|
|
export function HeroSection() {
|
|
if (UI_VARIANT === 'B') return <HeroSectionV2 />;
|
|
return <HeroSectionV1 />;
|
|
}
|
|
```
|