@trap_stevo/filetide
Version:
Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities wi
349 lines (348 loc) • 10.6 kB
JavaScript
"use strict";
const chalk = require("chalk");
class ConsoleTable {
constructor(options = {}) {
this.options = {
padding: 1,
headerAlign: "center",
cellAlign: "left",
borderStyle: "solid",
headerColor: null,
borderColor: null,
cellColor: (content, columnName, rowData) => content,
columnOrder: null,
columnNames: {},
title: "",
tableNumber: null,
gradient: {
title: null,
header: null,
border: null,
cell: null
},
...options
};
this.borderChars = this.getBorderChars(this.options.borderStyle);
}
getBorderChars(style) {
const styles = {
solid: {
topLeft: "┌",
topRight: "┐",
bottomLeft: "└",
bottomRight: "┘",
horizontal: "─",
vertical: "│",
topJoin: "┬",
bottomJoin: "┴",
leftJoin: "├",
rightJoin: "┤",
center: "┼"
},
double: {
topLeft: "╔",
topRight: "╗",
bottomLeft: "╚",
bottomRight: "╝",
horizontal: "═",
vertical: "║",
topJoin: "╦",
bottomJoin: "╩",
leftJoin: "╠",
rightJoin: "╣",
center: "╬"
},
round: {
topLeft: "╭",
topRight: "╮",
bottomLeft: "╰",
bottomRight: "╯",
horizontal: "─",
vertical: "│",
topJoin: "┬",
bottomJoin: "┴",
leftJoin: "├",
rightJoin: "┤",
center: "┼"
},
bold: {
topLeft: "┏",
topRight: "┓",
bottomLeft: "┗",
bottomRight: "┛",
horizontal: "━",
vertical: "┃",
topJoin: "┳",
bottomJoin: "┻",
leftJoin: "┣",
rightJoin: "┫",
center: "╋"
}
};
return styles[style] || styles["solid"];
}
setData(data) {
if (Array.isArray(data)) {
this.data = data;
} else if (typeof data === "object") {
this.data = Object.values(data);
} else {
throw new Error("Array or an object only.");
}
this.extractColumns();
this.calculateColumnWidths();
}
extractColumns() {
if (this.options.columnOrder && Array.isArray(this.options.columnOrder)) {
this.columns = this.options.columnOrder;
} else {
const columnsSet = new Set();
this.data.forEach(item => {
Object.keys(item).forEach(key => columnsSet.add(key));
});
this.columns = Array.from(columnsSet);
}
}
calculateColumnWidths() {
const {
padding
} = this.options;
this.columnWidths = {};
this.totalWidth = 0;
this.columns.forEach(column => {
const headerName = this.options.columnNames[column] || column;
let maxWidth = String(headerName).length;
this.data.forEach(item => {
const cellContent = item[column] !== undefined ? String(item[column]) : "";
maxWidth = Math.max(maxWidth, cellContent.length);
});
const columnWidth = maxWidth + padding * 2;
this.columnWidths[column] = columnWidth;
this.totalWidth += columnWidth;
});
this.totalWidth += this.columns.length + 1;
}
alignText(text, width, align) {
const {
padding
} = this.options;
const textLength = text.length;
let totalPadding = width - textLength;
let leftPadding = " ".repeat(padding);
let rightPadding = " ".repeat(padding);
if (totalPadding < padding * 2) {
leftPadding = "";
rightPadding = "";
} else {
totalPadding -= padding * 2;
if (align === "left") {
rightPadding += " ".repeat(totalPadding);
} else if (align === "right") {
leftPadding += " ".repeat(totalPadding);
} else {
const half = Math.floor(totalPadding / 2);
leftPadding += " ".repeat(half);
rightPadding += " ".repeat(totalPadding - half);
}
}
return leftPadding + text + rightPadding;
}
generateGradientText(text, startColor, endColor) {
const length = text.length;
const startRGB = this.hexToRgb(startColor);
const endRGB = this.hexToRgb(endColor);
let gradientText = "";
for (let i = 0; i < length; i++) {
const ratio = i / (length - 1 || 1);
const color = {
r: Math.round(startRGB.r + ratio * (endRGB.r - startRGB.r)),
g: Math.round(startRGB.g + ratio * (endRGB.g - startRGB.g)),
b: Math.round(startRGB.b + ratio * (endRGB.b - startRGB.b))
};
gradientText += chalk.rgb(color.r, color.g, color.b)(text[i]);
}
return gradientText;
}
hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
generateBorder(type) {
const {
columns,
columnWidths
} = this;
let {
horizontal,
vertical,
topLeft,
topRight,
bottomLeft,
bottomRight,
topJoin,
bottomJoin,
leftJoin,
rightJoin,
center
} = this.borderChars;
const {
borderColor
} = this.options;
const borderGradient = this.options.gradient.border;
if (borderGradient && borderGradient.length === 2) {
const chars = [topLeft, topRight, bottomLeft, bottomRight, horizontal, vertical, topJoin, bottomJoin, leftJoin, rightJoin, center];
const coloredChars = {};
chars.forEach((char, index) => {
coloredChars[char] = this.generateGradientText(char, borderGradient[0], borderGradient[1]);
});
bottomRight = coloredChars[bottomRight];
bottomLeft = coloredChars[bottomLeft];
topRight = coloredChars[topRight];
topLeft = coloredChars[topLeft];
horizontal = coloredChars[horizontal];
vertical = coloredChars[vertical];
bottomJoin = coloredChars[bottomJoin];
rightJoin = coloredChars[rightJoin];
leftJoin = coloredChars[leftJoin];
topJoin = coloredChars[topJoin];
center = coloredChars[center];
} else if (borderColor) {
bottomRight = borderColor(bottomRight);
bottomLeft = borderColor(bottomLeft);
topRight = borderColor(topRight);
topLeft = borderColor(topLeft);
horizontal = borderColor(horizontal);
vertical = borderColor(vertical);
bottomJoin = borderColor(bottomJoin);
rightJoin = borderColor(rightJoin);
leftJoin = borderColor(leftJoin);
topJoin = borderColor(topJoin);
center = borderColor(center);
}
let border = "";
columns.forEach((column, index) => {
const first = index === 0;
const last = index === columns.length - 1;
const width = columnWidths[column];
const line = horizontal.repeat(width);
if (type === "top") {
border += first ? topLeft : topJoin;
} else if (type === "bottom") {
border += first ? bottomLeft : bottomJoin;
} else {
border += first ? leftJoin : center;
}
border += line;
if (last) {
if (type === "top") {
border += topRight;
} else if (type === "bottom") {
border += bottomRight;
} else {
border += rightJoin;
}
}
});
return border;
}
generateRow(rowData, headerRow = false) {
const {
columns,
columnWidths
} = this;
let {
vertical
} = this.borderChars;
const {
headerAlign,
cellAlign,
headerColor,
cellColor
} = this.options;
const align = headerRow ? headerAlign : cellAlign;
const headerGradient = this.options.gradient.header;
const cellGradient = this.options.gradient.cell;
const borderGradient = this.options.gradient.border;
if (borderGradient && borderGradient.length === 2) {
vertical = this.generateGradientText(vertical, borderGradient[0], borderGradient[1]);
} else if (this.options.borderColor) {
vertical = this.options.borderColor(vertical);
}
let row = "";
columns.forEach((column, index) => {
const content = rowData[column] !== undefined ? String(rowData[column]) : "";
const width = columnWidths[column];
const alignedText = this.alignText(content, width, align);
let cellContent = alignedText;
const first = index === 0;
if (headerRow) {
if (headerGradient && headerGradient.length === 2) {
cellContent = this.generateGradientText(cellContent, headerGradient[0], headerGradient[1]);
} else if (headerColor) {
cellContent = headerColor(cellContent);
}
} else {
if (cellGradient && cellGradient.length === 2) {
cellContent = this.generateGradientText(cellContent, cellGradient[0], cellGradient[1]);
} else if (cellColor) {
cellContent = cellColor(cellContent, column, rowData);
}
}
if (first) {
row += vertical;
}
row += cellContent + vertical;
});
return row;
}
setTitle(title, tableNumber = null) {
this.options.title = title;
if (tableNumber !== null) {
this.options.tableNumber = tableNumber;
}
}
renderTitle() {
let titleText = this.options.title;
if (this.options.tableNumber !== null) {
titleText = titleText;
}
const totalWidth = this.totalWidth - 2;
const titleLength = titleText.length;
let leftPadding = Math.floor((totalWidth - titleLength) / 2);
if (leftPadding < 0) leftPadding = 0;
let titleLine = " ".repeat(leftPadding) + titleText;
const titleGradient = this.options.gradient.title;
if (titleGradient && titleGradient.length === 2) {
titleLine = this.generateGradientText(titleLine.trim(), titleGradient[0], titleGradient[1]);
}
return titleLine;
}
render() {
const {
data
} = this;
if (!data || data.length === 0) return "";
const lines = [];
if (this.options.title) {
const title = this.renderTitle();
lines.push(title);
}
lines.push(this.generateBorder("top"));
const headerData = {};
this.columns.forEach(column => {
headerData[column] = this.options.columnNames[column] || column;
});
lines.push(this.generateRow(headerData, true));
lines.push(this.generateBorder("middle"));
data.forEach(rowData => {
lines.push(this.generateRow(rowData));
});
lines.push(this.generateBorder("bottom"));
return lines.join("\n");
}
}
module.exports = ConsoleTable;