'use client'; import Link from 'next/link'; import { useState } from 'react'; const kpis = [ { label: '월 활성 사용자', value: '124,832', change: '+12.4%', up: true, color: '#3b82f6', sparkline: [40, 55, 45, 70, 60, 85, 100] }, { label: '월 매출', value: '₩284M', change: '+8.7%', up: true, color: '#10b981', sparkline: [50, 60, 55, 75, 80, 78, 100] }, { label: '전환율', value: '3.62%', change: '-0.3%', up: false, color: '#f59e0b', sparkline: [90, 80, 85, 75, 70, 72, 68] }, { label: '고객 만족도', value: '4.8', change: '+0.2', up: true, color: '#8b5cf6', sparkline: [70, 72, 74, 76, 78, 80, 85] }, ]; const lineData = [ { month: 'Jan', revenue: 65, users: 48 }, { month: 'Feb', revenue: 78, users: 55 }, { month: 'Mar', revenue: 72, users: 52 }, { month: 'Apr', revenue: 89, users: 64 }, { month: 'May', revenue: 95, users: 71 }, { month: 'Jun', revenue: 82, users: 66 }, { month: 'Jul', revenue: 110, users: 88 }, { month: 'Aug', revenue: 128, users: 100 }, ]; const activities = [ { user: 'lee@company.com', action: '프리미엄 플랜 구독', time: '2분 전', status: 'success', avatar: 'L' }, { user: 'park@startup.io', action: 'API 한도 초과 경고', time: '14분 전', status: 'warning', avatar: 'P' }, { user: 'kim@corp.kr', action: '팀 멤버 5명 초대', time: '31분 전', status: 'info', avatar: 'K' }, { user: 'choi@brand.com', action: '결제 실패 (카드 만료)', time: '1시간 전', status: 'error', avatar: 'C' }, { user: 'jung@agency.co', action: '새 워크스페이스 생성', time: '2시간 전', status: 'success', avatar: 'J' }, ]; const menus = [ { id: 'overview', label: 'Overview', dot: '#3b82f6' }, { id: 'analytics', label: 'Analytics', dot: '#10b981' }, { id: 'users', label: 'Users', dot: null }, { id: 'revenue', label: 'Revenue', dot: null }, { id: 'reports', label: 'Reports', dot: null }, { id: 'settings', label: 'Settings', dot: null }, ]; const channels = [ { label: 'Organic Search', val: 78, color: '#3b82f6' }, { label: 'Direct', val: 55, color: '#10b981' }, { label: 'Social Media', val: 42, color: '#a855f7' }, { label: 'Email', val: 34, color: '#f59e0b' }, { label: 'Referral', val: 20, color: '#ec4899' }, ]; const alerts = [ { type: 'error', msg: 'API 응답 지연 (p99 > 2s)', time: '5분 전' }, { type: 'warning', msg: '스토리지 사용량 85% 초과', time: '32분 전' }, { type: 'success', msg: '일일 백업 완료', time: '1시간 전' }, ]; const statusColor: Record = { success: '#10b981', warning: '#f59e0b', error: '#ef4444', info: '#3b82f6' }; function SparkLine({ data, color }: { data: number[]; color: string }) { const max = Math.max(...data); const min = Math.min(...data); const h = 28; const w = 72; const step = w / (data.length - 1); const pts = data.map((v, i) => { const x = i * step; const y = h - ((v - min) / (max - min || 1)) * h; return `${x},${y}`; }).join(' '); return ( ); } function LineChart({ data }: { data: typeof lineData }) { const chartH = 130; const chartW = 440; const padL = 32; const padB = 24; const innerW = chartW - padL; const innerH = chartH - padB; const maxRev = Math.max(...data.map(d => d.revenue)); const revPts = data.map((d, i) => { const x = padL + (i / (data.length - 1)) * innerW; const y = (1 - d.revenue / maxRev) * innerH; return `${x},${y}`; }).join(' '); const usrPts = data.map((d, i) => { const x = padL + (i / (data.length - 1)) * innerW; const y = (1 - d.users / maxRev) * innerH; return `${x},${y}`; }).join(' '); return ( {/* Grid lines */} {[0, 0.25, 0.5, 0.75, 1].map((t, i) => ( {Math.round(maxRev * (1 - t))} ))} {/* Area fills */} {/* Lines */} {/* Dots at last point */} {[{ pts: revPts, color: '#3b82f6' }, { pts: usrPts, color: '#10b981' }].map(({ pts: p, color }) => { const last = p.split(' ').pop()!; const [lx, ly] = last.split(',').map(Number); return ; })} {/* X axis labels */} {data.map((d, i) => ( {d.month} ))} ); } export default function DashboardSample() { const [activeMenu, setActiveMenu] = useState('overview'); const [alertsVisible, setAlertsVisible] = useState(true); return (
{/* Back Banner */}
← 홈페이지 제작 서비스로 돌아가기 | SAMPLE · 관리자 대시보드
{/* Sidebar */} {/* Main */}
{/* Top bar */}
{/* Alert bell */}
{/* Alerts panel */} {alertsVisible && (
시스템 알림
{alerts.map((a, i) => (
{a.msg}
{a.time}
))}
)} {/* Page header */}

Overview

2024.08.14 · 오전 10:32 업데이트
{/* KPI Cards */}
{kpis.map((kpi) => (
{kpi.label}
{kpi.value}
{kpi.up ? '↑' : '↓'} {kpi.change}
))}
{/* Charts row */}
{/* Line Chart */}
월별 매출 & 사용자 추이
매출
사용자
{['1M', '3M', '6M', '1Y'].map((p) => ( ))}
{/* Channel Progress */}
채널별 전환율
{channels.map((p) => (
{p.label} {p.val}%
))} {/* Donut summary */}
{(() => { const total = channels.reduce((s, c) => s + c.val, 0); let offset = 0; const r = 20; const circ = 2 * Math.PI * r; return channels.map((c) => { const dash = (c.val / total) * circ; const el = ( ); offset += dash; return el; }); })()} ALL
Organic 채널이
최고 전환율 78%
달성 중
{/* Activity Table */}
최근 활동
{['사용자', '활동', '시간', '상태'].map((h) => ( ))} {activities.map((a, i) => ( ))}
{h}
{a.avatar}
{a.user}
{a.action} {a.time}
{a.status === 'success' ? 'OK' : a.status === 'warning' ? 'WARN' : a.status === 'error' ? 'ERR' : 'INFO'}
); }