import { clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; export function cn(...inputs) { return twMerge(clsx(inputs)); } export function formatBytes(bytes, decimals = 2) { if (!bytes || bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } export function formatUptime(seconds) { const d = Math.floor(seconds / 86400); const h = Math.floor((seconds % 86400) / 3600); const m = Math.floor((seconds % 3600) / 60); if (d > 0) return `${d}d ${h}h`; if (h > 0) return `${h}h ${m}m`; return `${m}m`; } export function getStatusColor(status) { const map = { online: 'text-green-400', running: 'text-cyan-400', active: 'text-green-400', stopped: 'text-slate-400', offline: 'text-red-400', error: 'text-red-400', warning: 'text-yellow-400', unknown: 'text-gray-400', paused: 'text-yellow-400', exited: 'text-slate-400', }; return map[status?.toLowerCase()] ?? 'text-gray-400'; } export function getStatusDot(status) { const map = { online: 'bg-green-400', running: 'bg-cyan-400', active: 'bg-green-400', stopped: 'bg-slate-500', offline: 'bg-red-400', error: 'bg-red-400', warning: 'bg-yellow-400', unknown: 'bg-gray-500', paused: 'bg-yellow-400', exited: 'bg-slate-500', }; return map[status?.toLowerCase()] ?? 'bg-gray-500'; } export function getSecurityGradeColor(grade) { const map = { A: 'text-green-400', B: 'text-cyan-400', C: 'text-yellow-400', D: 'text-orange-400', F: 'text-red-400' }; return map[grade] ?? 'text-gray-400'; } export function timeAgo(date) { if (!date) return 'Never'; const d = new Date(date); const seconds = Math.floor((new Date() - d) / 1000); if (seconds < 60) return `${seconds}s ago`; if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`; if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`; return `${Math.floor(seconds / 86400)}d ago`; }