import { type ClassValue, clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; /** * Merge Tailwind CSS classes */ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } /** * Clamp a value between min and max */ export function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max); } /** * Linear interpolation */ export function lerp(a: number, b: number, t: number): number { return a + (b - a) * t; } /** * Calculate distance between two points */ export function distance(x1: number, y1: number, x2: number, y2: number): number { const dx = x2 - x1; const dy = y2 - y1; return Math.sqrt(dx * dx + dy * dy); } /** * Snap value to grid */ export function snapToGrid(value: number, gridSize: number): number { return Math.round(value / gridSize) * gridSize; } /** * Format bytes to human readable string */ export function formatBytes(bytes: number, decimals = 2): string { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } /** * Debounce function */ export function debounce any>( func: T, wait: number ): (...args: Parameters) => void { let timeout: NodeJS.Timeout | null = null; return (...args: Parameters) => { if (timeout) clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); }; } /** * Throttle function */ export function throttle any>( func: T, limit: number ): (...args: Parameters) => void { let inThrottle: boolean; return (...args: Parameters) => { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }