● Zion Boggan
repos/Drophawk/frontend/lib/utils.ts
zionboggan.com ↗
52 lines · typescript
History for this file →
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
}