# 네이버 클라우드 콘솔 UI 패턴 참조 > GUARDiA Manager UI는 네이버 클라우드 콘솔(console.ncloud.com)의 디자인 패턴을 참조한다. > 아래 코드 스니펫은 해당 패턴을 GUARDiA Manager에 맞게 재구현한 것이다. --- ## 1. DataTable 컴포넌트 (NCloud 리소스 목록) ```tsx // components/common/DataTable.tsx import { useState } from 'react'; import styles from './DataTable.module.css'; interface Column { key: keyof T | string; header: string; width?: string; render?: (row: T) => React.ReactNode; sortable?: boolean; } interface DataTableProps { columns: Column[]; data: T[]; onRowClick?: (row: T) => void; actions?: React.ReactNode; // 상단 액션 버튼 loading?: boolean; emptyMessage?: string; selectable?: boolean; onSelectionChange?: (selected: T[]) => void; } export function DataTable({ columns, data, onRowClick, actions, loading, emptyMessage, selectable = false, onSelectionChange, }: DataTableProps) { const [selected, setSelected] = useState>(new Set()); const [sortKey, setSortKey] = useState(null); const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc'); const toggleAll = () => { const next = selected.size === data.length ? new Set() : new Set(data.map(r => r.id)); setSelected(next); onSelectionChange?.(data.filter(r => next.has(r.id))); }; const toggleRow = (id: string | number) => { const next = new Set(selected); next.has(id) ? next.delete(id) : next.add(id); setSelected(next); onSelectionChange?.(data.filter(r => next.has(r.id))); }; return (
{/* 상단 액션 영역 */} {actions && (
{selected.size > 0 && ( {selected.size}개 선택됨 )}
{actions}
)} {selectable && ( )} {columns.map(col => ( ))} {loading ? ( ) : data.length === 0 ? ( ) : data.map(row => ( onRowClick?.(row)}> {selectable && ( )} {columns.map(col => ( ))} ))}
0} onChange={toggleAll} /> col.sortable && (setSortKey(String(col.key)), setSortDir(d => d === 'asc' ? 'desc' : 'asc'))}> {col.header} {sortKey === String(col.key) && ( {sortDir === 'asc' ? ' ↑' : ' ↓'} )}
로딩 중...
{emptyMessage ?? '데이터가 없습니다.'}
e.stopPropagation()}> toggleRow(row.id)} /> {col.render ? col.render(row) : String((row as any)[col.key] ?? '')}
); } ``` --- ## 2. ResourceCard 컴포넌트 (서버/서비스 카드) ```tsx // components/common/ResourceCard.tsx import { StatusBadge } from './StatusBadge'; interface ResourceCardProps { name: string; type: string; // '서버' | 'DB' | 'WAS' | 'API' status: 'running' | 'stopped' | 'error' | 'pending'; spec?: string; // '2vCPU / 4GB' 등 ip?: string; onClick?: () => void; } export function ResourceCard({ name, type, status, spec, ip, onClick }: ResourceCardProps) { return (
{type}
{name}
{spec &&
{spec}
} {ip &&
{ip}
}
); } ``` --- ## 3. SlidePanel 컴포넌트 (NCloud 상세 정보 패널) NCloud 콘솔에서 리소스 클릭 시 우측에서 슬라이드하는 상세 패널. ```tsx // components/common/SlidePanel.tsx import { useEffect } from 'react'; interface SlidePanelProps { open: boolean; onClose: () => void; title: string; width?: number; // 기본 480px children: React.ReactNode; actions?: React.ReactNode; } export function SlidePanel({ open, onClose, title, width = 480, children, actions }: SlidePanelProps) { useEffect(() => { const handler = (e: KeyboardEvent) => e.key === 'Escape' && onClose(); document.addEventListener('keydown', handler); return () => document.removeEventListener('keydown', handler); }, [onClose]); return ( <> {/* 오버레이 */} {open && (
)} {/* 패널 */}
{/* 헤더 */}

{title}

{/* 콘텐츠 */}
{children}
{/* 푸터 액션 */} {actions && (
{actions}
)}
); } ``` --- ## 4. StatCard 컴포넌트 (대시보드 통계 카드) ```tsx // components/common/StatCard.tsx interface StatCardProps { title: string; value: string | number; sub?: string; trend?: { value: number; positive: boolean }; icon?: string; color?: string; // 아이콘 배경색 onClick?: () => void; } export function StatCard({ title, value, sub, trend, icon, color = 'var(--brand-light)', onClick }: StatCardProps) { return (
{icon && (
{icon}
)}
{value}
{title}
{sub &&
{sub}
}
{trend && (
{trend.positive ? '▲' : '▼'} {Math.abs(trend.value)}% 전주 대비
)}
); } ``` --- ## 5. 사이드바 네비게이션 (NCloud 서비스 트리 스타일) ```tsx const MENU = [ { label: '대시보드', icon: '📊', path: '/' }, { label: '인프라 관리', icon: '🖥️', children: [ { label: '서버 목록', path: '/servers' }, { label: 'CMDB 현황', path: '/cmdb' }, { label: 'SSH 자격증명', path: '/credentials' }, ] }, { label: '배포/CI-CD', icon: '🚀', children: [ { label: '배포 이력', path: '/deployments' }, { label: '저장소 목록', path: '/repos' }, { label: '서비스 상태', path: '/services' }, ] }, { label: '사용자/테넌트', icon: '👥', children: [ { label: '사용자 관리', path: '/users' }, { label: '기관 관리', path: '/institutions' }, { label: '역할 설정', path: '/roles' }, ] }, { label: '보안', icon: '🔒', children: [ { label: 'API Key 관리', path: '/api-keys' }, { label: '감사 로그', path: '/audit' }, { label: '취약점 현황', path: '/vulns' }, ] }, { label: 'AI/LLM', icon: '🤖', children: [ { label: 'Ollama 모델', path: '/llm' }, { label: 'AI 에이전트', path: '/agents' }, ] }, { label: '시스템 설정', icon: '⚙️', children: [ { label: '환경변수', path: '/config/env' }, { label: 'Nginx 설정', path: '/config/nginx' }, { label: '알림 설정', path: '/config/notify' }, ] }, ]; ```