Files
buzz/lib/utils.ts
T
dmgnr 4d0f459bdb
Build and Push Image / build-backend (push) Successful in 2m42s
Build and Push Image / build-frontend (push) Successful in 4m1s
Build and Push Image / push (push) Successful in 2m5s
feat: chat widget
2026-07-28 11:24:20 +07:00

90 lines
2.1 KiB
TypeScript
Executable File

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export const b2s = (t: number) => {
let e = (Math.log2(t) / 10) | 0;
return `${(t / 1024 ** (e = e <= 0 ? 0 : e)).toFixed(1)}${" KMGP"[e]}B`;
};
type Node = { count: number; next: Map<string, Node> };
function node(): Node {
return { count: 0, next: new Map() };
}
// find unique shortest code for each string
export function shortestPrefixes(values: readonly string[]) {
const uniq = [...new Set(values)];
const root = node();
for (const v of uniq) {
let cur = root;
for (const ch of v) {
let n = cur.next.get(ch);
if (!n) cur.next.set(ch, (n = node()));
n.count++;
cur = n;
}
}
const res = new Map<string, string>();
for (const v of uniq) {
let cur = root;
let prefix = "";
for (const ch of v) {
const n = cur.next.get(ch)!;
prefix += ch;
if (n.count === 1) break;
cur = n;
}
res.set(v, prefix);
}
return res;
}
export async function fileToDataUrl(file: File) {
const buffer = Buffer.from(await file.arrayBuffer());
return `data:${file.type};base64,${buffer.toString("base64")}`;
}
export function parseSearchNumber(
param: string | string[] | undefined,
def: number = 0,
) {
if (Array.isArray(param)) return parseSearchNumber(param[0], def);
const parsed = parseFloat(param ?? "");
return Number.isNaN(parsed) ? def : parsed;
}
export function parseSearchString(
param: string | string[] | undefined,
def: string = "",
) {
if (Array.isArray(param)) return parseSearchString(param[0], def);
return param ?? def;
}
export function pausePass<R>(time: number): (res: R) => Promise<R> {
return (res) => new Promise((r) => setTimeout(() => r(res), time));
}
// taken from astral/api
export class ResponseNotOkError extends Error {
constructor(
readonly status: number,
readonly response: Response,
) {
super(`RESPONSE_NOT_OK: Got status ${status}`);
}
}
export function throwNotOk(res: Response) {
if (!res.ok) throw new ResponseNotOkError(res.status, res);
return res;
}