| 1 | import { clsx, type ClassValue } from "clsx"; |
| 2 | import { twMerge } from "tailwind-merge"; |
| 3 | |
| 4 | export function cn(...inputs: ClassValue[]): string { |
| 5 | return twMerge(clsx(inputs)); |
| 6 | } |
| 7 | |
| 8 | |
| 9 | export function formatPriceRange( |
| 10 | minCents: number | null, |
| 11 | maxCents: number | null, |
| 12 | currency = "USD", |
| 13 | ): string { |
| 14 | if (minCents == null && maxCents == null) return "Price TBA"; |
| 15 | const fmt = new Intl.NumberFormat("en-US", { |
| 16 | style: "currency", |
| 17 | currency, |
| 18 | minimumFractionDigits: 0, |
| 19 | maximumFractionDigits: minCents != null && minCents % 100 === 0 ? 0 : 2, |
| 20 | }); |
| 21 | if (minCents != null && maxCents != null && minCents !== maxCents) { |
| 22 | return `${fmt.format(minCents / 100)} - ${fmt.format(maxCents / 100)}`; |
| 23 | } |
| 24 | const single = (minCents ?? maxCents) as number; |
| 25 | return fmt.format(single / 100); |
| 26 | } |
| 27 | |
| 28 | export function formatCompact(n: number): string { |
| 29 | if (Math.abs(n) >= 10_000) { |
| 30 | return new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }).format(n); |
| 31 | } |
| 32 | return new Intl.NumberFormat("en-US").format(n); |
| 33 | } |
| 34 | |
| 35 | export function formatLatency(ms: number | null): string { |
| 36 | if (ms == null) return "-"; |
| 37 | if (ms < 1000) return `${Math.round(ms)}ms`; |
| 38 | return `${(ms / 1000).toFixed(1)}s`; |
| 39 | } |
| 40 | |
| 41 | export function sourceInitials(name: string): string { |
| 42 | const words = name.replace(/\b(api|discovery)\b/gi, "").trim().split(/\s+/).filter(Boolean); |
| 43 | if (words.length === 0) return "?"; |
| 44 | if (words.length === 1) return words[0]!.slice(0, 2).toUpperCase(); |
| 45 | return (words[0]![0]! + words[1]![0]!).toUpperCase(); |
| 46 | } |
| 47 | |
| 48 | export function sourceHue(id: string): number { |
| 49 | let h = 0; |
| 50 | for (let i = 0; i < id.length; i += 1) h = (h * 31 + id.charCodeAt(i)) % 360; |
| 51 | return h; |
| 52 | } |