Spaces:
Sleeping
Sleeping
| // @ts-check | |
| import wrap from "word-wrap"; | |
| import { encodeHTML } from "./html.js"; | |
| /** | |
| * Retrieves num with suffix k(thousands) precise to given decimal places. | |
| * | |
| * @param {number} num The number to format. | |
| * @param {number=} precision The number of decimal places to include. | |
| * @returns {string|number} The formatted number. | |
| */ | |
| const kFormatter = (num, precision) => { | |
| const abs = Math.abs(num); | |
| const sign = Math.sign(num); | |
| if (typeof precision === "number" && !isNaN(precision)) { | |
| return (sign * (abs / 1000)).toFixed(precision) + "k"; | |
| } | |
| if (abs < 1000) { | |
| return sign * abs; | |
| } | |
| return sign * parseFloat((abs / 1000).toFixed(1)) + "k"; | |
| }; | |
| /** | |
| * Convert bytes to a human-readable string representation. | |
| * | |
| * @param {number} bytes The number of bytes to convert. | |
| * @returns {string} The human-readable representation of bytes. | |
| * @throws {Error} If bytes is negative or too large. | |
| */ | |
| const formatBytes = (bytes) => { | |
| if (bytes < 0) { | |
| throw new Error("Bytes must be a non-negative number"); | |
| } | |
| if (bytes === 0) { | |
| return "0 B"; | |
| } | |
| const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]; | |
| const base = 1024; | |
| const i = Math.floor(Math.log(bytes) / Math.log(base)); | |
| if (i >= sizes.length) { | |
| throw new Error("Bytes is too large to convert to a human-readable string"); | |
| } | |
| return `${(bytes / Math.pow(base, i)).toFixed(1)} ${sizes[i]}`; | |
| }; | |
| /** | |
| * Split text over multiple lines based on the card width. | |
| * | |
| * @param {string} text Text to split. | |
| * @param {number} width Line width in number of characters. | |
| * @param {number} maxLines Maximum number of lines. | |
| * @returns {string[]} Array of lines. | |
| */ | |
| const wrapTextMultiline = (text, width = 59, maxLines = 3) => { | |
| const fullWidthComma = ","; | |
| const encoded = encodeHTML(text); | |
| const isChinese = encoded.includes(fullWidthComma); | |
| let wrapped = []; | |
| if (isChinese) { | |
| wrapped = encoded.split(fullWidthComma); // Chinese full punctuation | |
| } else { | |
| wrapped = wrap(encoded, { | |
| width, | |
| }).split("\n"); // Split wrapped lines to get an array of lines | |
| } | |
| const lines = wrapped.map((line) => line.trim()).slice(0, maxLines); // Only consider maxLines lines | |
| // Add "..." to the last line if the text exceeds maxLines | |
| if (wrapped.length > maxLines) { | |
| lines[maxLines - 1] += "..."; | |
| } | |
| // Remove empty lines if text fits in less than maxLines lines | |
| const multiLineText = lines.filter(Boolean); | |
| return multiLineText; | |
| }; | |
| export { kFormatter, formatBytes, wrapTextMultiline }; | |