| export function toxicityColor(probability: number): string { |
| const pct = probability * 100; |
| if (pct >= 70) return "#ff4e45"; |
| if (pct >= 40) return "#f5a623"; |
| return "#2ba640"; |
| } |
|
|
| export function formatPct(probability: number): string { |
| return `${Math.round(probability * 100)}%`; |
| } |
|
|
| export function newId(): string { |
| return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; |
| } |
|
|
| const RTF = new Intl.RelativeTimeFormat("es", { numeric: "auto" }); |
|
|
| const TIME_UNITS: Array<[Intl.RelativeTimeFormatUnit, number]> = [ |
| ["year", 60 * 60 * 24 * 365], |
| ["month", 60 * 60 * 24 * 30], |
| ["day", 60 * 60 * 24], |
| ["hour", 60 * 60], |
| ["minute", 60], |
| ["second", 1], |
| ]; |
|
|
| export function relativeTime(input: string | number | Date): string { |
| const date = input instanceof Date ? input : new Date(input); |
| const seconds = (date.getTime() - Date.now()) / 1000; |
| if (!Number.isFinite(seconds)) return ""; |
| for (const [unit, secondsInUnit] of TIME_UNITS) { |
| if (Math.abs(seconds) >= secondsInUnit || unit === "second") { |
| return RTF.format(Math.round(seconds / secondsInUnit), unit); |
| } |
| } |
| return ""; |
| } |
|
|
| export function truncate(text: string, max = 140): string { |
| if (text.length <= max) return text; |
| return `${text.slice(0, max - 1).trimEnd()}…`; |
| } |
|
|
| const ADJECTIVES = [ |
| "happy", "lucky", "wild", "calm", "bright", "swift", "quiet", "lazy", |
| "brave", "fuzzy", "shiny", "sleepy", "quick", "noble", "loud", "humble", |
| "stormy", "sunny", "rainy", "frosty", "spicy", "salty", "sweet", "crazy", |
| "mighty", "silent", "epic", "cosmic", "rusty", "neon", "wandering", "lone", |
| ]; |
|
|
| const NOUNS = [ |
| "panda", "tiger", "falcon", "otter", "eagle", "wolf", "fox", "bear", |
| "lynx", "shark", "raven", "viper", "phoenix", "dragon", "jaguar", "koala", |
| "moose", "lion", "owl", "octopus", "rabbit", "hawk", "badger", "robin", |
| "cosmonaut", "drifter", "ninja", "wizard", "rider", "pilot", "skater", "gamer", |
| ]; |
|
|
| const SUFFIXES = ["", "_", "_", "_yt", "_hd", "_real", "99", "01", "_xd", "_v2", "_official", ""]; |
|
|
| |
| |
| |
| export function randomUsername(seed: string | number | undefined | null): string { |
| const str = seed == null ? "anon" : String(seed); |
| let hash = 5381; |
| for (let i = 0; i < str.length; i++) { |
| hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0; |
| } |
| const adj = ADJECTIVES[hash % ADJECTIVES.length] ?? "anon"; |
| const noun = NOUNS[Math.floor(hash / 32) % NOUNS.length] ?? "user"; |
| const suffix = SUFFIXES[Math.floor(hash / 1024) % SUFFIXES.length] ?? ""; |
| const needsNum = suffix === "" || suffix.endsWith("_"); |
| const num = needsNum ? String(hash % 1000) : ""; |
| return `${adj}_${noun}${suffix}${num}`; |
| } |
|
|