/** Summarize a URL for display in tool pages. */ export function summarizeUrl(value: string): string { try { const url = new URL(value); const lastSegment = url.pathname.split("/").filter(Boolean).pop(); return lastSegment ? `${url.host}/.../${lastSegment}` : url.host; } catch { return value.length > 72 ? `${value.slice(0, 34)}...${value.slice(-28)}` : value; } } /** Format a byte count to human-readable file size. */ export function formatFileSize(bytes: number): string { if (!Number.isFinite(bytes) || bytes <= 0) return "0 KB"; if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(2)} MB`; return `${(bytes / 1024).toFixed(1)} KB`; } /** Read a File as a data URL string via FileReader. */ export function fileToDataUrl(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result || "")); reader.onerror = () => reject(new Error("读取素材失败")); reader.readAsDataURL(file); }); } /** Return a Promise that resolves after the given milliseconds. */ export function wait(ms: number): Promise { return new Promise((resolve) => window.setTimeout(resolve, ms)); }