UNPKG

@jalasem/dss

Version:

Dev Spaces Switcher (DSS) - Seamlessly manage isolated development environments with separate SSH keys and Git configurations. Enhanced UI with beautiful tables and improved documentation.

303 lines (302 loc) 17.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UIHelper = void 0; const chalk_1 = __importDefault(require("chalk")); const perf_hooks_1 = require("perf_hooks"); class UIHelper { static success(message) { console.log(chalk_1.default.green(`✅ ${message}`)); } static error(message) { console.log(chalk_1.default.red(`❌ ${message}`)); } static warning(message) { console.log(chalk_1.default.yellow(`⚠️ ${message}`)); } static info(message) { console.log(chalk_1.default.blue(`ℹ️ ${message}`)); } static highlight(text) { return chalk_1.default.cyan(text); } static dim(text) { return chalk_1.default.dim(text); } static bold(text) { return chalk_1.default.bold(text); } static activeSpace(name) { return chalk_1.default.green(`🔥 ${name}`); } static inactiveSpace(name) { return chalk_1.default.white(name); } static spaceName(name, isActive = false) { return isActive ? this.activeSpace(name) : this.inactiveSpace(name); } static gradient(text) { // Create a simple gradient effect using different shades const colors = [chalk_1.default.blue, chalk_1.default.cyan, chalk_1.default.green, chalk_1.default.yellow]; const chars = text.split(''); return chars.map((char, index) => { const colorIndex = Math.floor((index / chars.length) * colors.length); return colors[colorIndex] ? colors[colorIndex](char) : char; }).join(''); } static badge(text, type = 'info') { const colors = { success: { bg: chalk_1.default.bgGreen, fg: chalk_1.default.black }, error: { bg: chalk_1.default.bgRed, fg: chalk_1.default.white }, warning: { bg: chalk_1.default.bgYellow, fg: chalk_1.default.black }, info: { bg: chalk_1.default.bgBlue, fg: chalk_1.default.white } }; const { bg, fg } = colors[type]; return bg(fg(` ${text} `)); } static progressBar(current, total, width = 20) { const percentage = Math.min(current / total, 1); const filled = Math.floor(percentage * width); const empty = width - filled; const bar = chalk_1.default.green('█'.repeat(filled)) + chalk_1.default.gray('░'.repeat(empty)); const percent = Math.floor(percentage * 100); return `${bar} ${percent}%`; } static command(cmd) { return chalk_1.default.cyan(`\`${cmd}\``); } static filename(path) { return chalk_1.default.magenta(path); } static url(url) { return chalk_1.default.blue.underline(url); } static printSeparator() { const terminalWidth = process.stdout.columns || 80; const width = Math.min(60, terminalWidth - 4); console.log(chalk_1.default.gray('─'.repeat(width))); } static printHeader(title) { const terminalWidth = process.stdout.columns || 80; const maxWidth = Math.min(Math.max(title.length + 8, 50), terminalWidth - 4); console.log(chalk_1.default.cyan('╭' + '─'.repeat(maxWidth) + '╮')); const titleLength = title.length; const padding = Math.max(0, Math.floor((maxWidth - titleLength) / 2)); const paddedTitle = ' '.repeat(padding) + title + ' '.repeat(maxWidth - titleLength - padding); console.log(chalk_1.default.cyan('│') + chalk_1.default.bold.white(paddedTitle) + chalk_1.default.cyan('│')); console.log(chalk_1.default.cyan('╰' + '─'.repeat(maxWidth) + '╯')); } // Helper function to get string length without ANSI escape codes static getDisplayLength(str) { // Remove ANSI escape codes to get actual display length // eslint-disable-next-line no-control-regex return str.replace(/\u001b\[[0-9;]*m/g, '').length; } // Helper function to pad string accounting for ANSI escape codes static padWithColors(str, targetLength) { const displayLength = this.getDisplayLength(str); const padding = Math.max(0, targetLength - displayLength); return str + ' '.repeat(padding); } static printSpaceTable(spaces, activeSpace) { if (spaces.length === 0) { this.warning('No spaces have been added yet.'); return; } const terminalWidth = process.stdout.columns || 80; const maxTableWidth = Math.min(terminalWidth - 4, 120); // Calculate column widths with responsive sizing const minNameWidth = 8; const minEmailWidth = 12; const minUserWidth = 8; const statusWidth = 8; // Get the actual content lengths const baseNameWidth = Math.max(minNameWidth, ...spaces.map(s => s.name.length)); const baseEmailWidth = Math.max(minEmailWidth, ...spaces.map(s => s.email.length)); const baseUserWidth = Math.max(minUserWidth, ...spaces.map(s => s.userName.length)); const totalBaseWidth = baseNameWidth + baseEmailWidth + baseUserWidth + statusWidth + 12; // 12 for borders and padding let nameWidth = baseNameWidth; let emailWidth = baseEmailWidth; let userWidth = baseUserWidth; // Adjust widths if table is too wide for terminal if (totalBaseWidth > maxTableWidth) { const availableWidth = maxTableWidth - statusWidth - 12; const totalContentWidth = baseNameWidth + baseEmailWidth + baseUserWidth; // Proportionally reduce each column nameWidth = Math.max(minNameWidth, Math.floor((baseNameWidth / totalContentWidth) * availableWidth)); emailWidth = Math.max(minEmailWidth, Math.floor((baseEmailWidth / totalContentWidth) * availableWidth)); userWidth = Math.max(minUserWidth, availableWidth - nameWidth - emailWidth); } // Create border components const topBorder = `┌${'─'.repeat(nameWidth + 2)}${'─'.repeat(emailWidth + 2)}${'─'.repeat(userWidth + 2)}${'─'.repeat(statusWidth + 2)}┐`; const separator = `├${'─'.repeat(nameWidth + 2)}${'─'.repeat(emailWidth + 2)}${'─'.repeat(userWidth + 2)}${'─'.repeat(statusWidth + 2)}┤`; const bottomBorder = `└${'─'.repeat(nameWidth + 2)}${'─'.repeat(emailWidth + 2)}${'─'.repeat(userWidth + 2)}${'─'.repeat(statusWidth + 2)}┘`; // Print table header console.log(chalk_1.default.cyan(topBorder)); const headerRow = `│ ${this.padWithColors(chalk_1.default.bold.white('Name'), nameWidth)}${this.padWithColors(chalk_1.default.bold.white('Email'), emailWidth)}${this.padWithColors(chalk_1.default.bold.white('User'), userWidth)}${this.padWithColors(chalk_1.default.bold.white('Status'), statusWidth)} │`; console.log(headerRow); console.log(chalk_1.default.cyan(separator)); // Print each space row spaces.forEach(space => { const isActive = space.name === activeSpace; // Truncate long values with ellipsis const truncatedName = space.name.length > nameWidth ? space.name.substring(0, nameWidth - 3) + '...' : space.name; const truncatedEmail = space.email.length > emailWidth ? space.email.substring(0, emailWidth - 3) + '...' : space.email; const truncatedUser = space.userName.length > userWidth ? space.userName.substring(0, userWidth - 3) + '...' : space.userName; // Apply styling based on active state const styledName = isActive ? this.activeSpace(truncatedName) : chalk_1.default.white(truncatedName); const styledEmail = isActive ? chalk_1.default.green(truncatedEmail) : chalk_1.default.gray(truncatedEmail); const styledUser = isActive ? chalk_1.default.green(truncatedUser) : chalk_1.default.gray(truncatedUser); const styledStatus = isActive ? this.badge('ACTIVE', 'success') : chalk_1.default.dim('inactive'); const row = `│ ${this.padWithColors(styledName, nameWidth)}${this.padWithColors(styledEmail, emailWidth)}${this.padWithColors(styledUser, userWidth)}${this.padWithColors(styledStatus, statusWidth)} │`; console.log(row); }); console.log(chalk_1.default.cyan(bottomBorder)); // Enhanced summary footer with better formatting const totalSpaces = spaces.length; const activeCount = activeSpace ? 1 : 0; const inactiveCount = totalSpaces - activeCount; console.log(''); console.log(chalk_1.default.dim('📊 Summary:'), chalk_1.default.cyan(`${totalSpaces} total`), chalk_1.default.green(`• ${activeCount} active`), chalk_1.default.gray(`• ${inactiveCount} inactive`)); if (activeSpace) { console.log(''); console.log(chalk_1.default.dim('🔥 Currently active:'), chalk_1.default.green.bold(activeSpace)); } console.log(''); console.log(chalk_1.default.dim('Commands:')); console.log(chalk_1.default.dim(' • '), this.command('dss switch'), chalk_1.default.dim(' - Change active space')); console.log(chalk_1.default.dim(' • '), this.command('dss inspect <space>'), chalk_1.default.dim(' - View detailed space info')); console.log(chalk_1.default.dim(' • '), this.command('dss test'), chalk_1.default.dim(' - Test GitHub access')); console.log(''); } static printProgress(message) { this.clearProgress(); this.progressState.active = true; this.progressState.startTime = perf_hooks_1.performance.now(); this.progressState.message = message; this.progressState.index = 0; const updateSpinner = () => { if (!this.progressState.active) return; const elapsed = Math.floor((perf_hooks_1.performance.now() - this.progressState.startTime) / 1000); const spinner = this.progressState.spinner[this.progressState.index % this.progressState.spinner.length]; const timeStr = elapsed > 0 ? ` (${elapsed}s)` : ''; process.stdout.write(`\r${chalk_1.default.yellow(spinner)} ${this.progressState.message}...${chalk_1.default.dim(timeStr)}`); this.progressState.index++; }; updateSpinner(); this.progressState.interval = setInterval(updateSpinner, 80); } static clearProgress() { if (this.progressState.interval) { clearInterval(this.progressState.interval); this.progressState.interval = null; } this.progressState.active = false; const terminalWidth = process.stdout.columns || 80; process.stdout.write('\r' + ' '.repeat(terminalWidth) + '\r'); } static updateProgress(message) { if (this.progressState.active) { this.progressState.message = message; } } static printKeyInstruction() { console.log(chalk_1.default.dim('\n💡 Tips:')); console.log(chalk_1.default.dim(' • Use arrow keys to navigate')); console.log(chalk_1.default.dim(' • Press Enter to select')); console.log(chalk_1.default.dim(' • Press Ctrl+C to cancel')); } static printSuccessBox(title, content) { const maxWidth = Math.max(title.length, ...content.map(line => line.length)); const terminalWidth = process.stdout.columns || 80; const width = Math.min(Math.max(maxWidth + 4, 40), terminalWidth - 4); console.log(chalk_1.default.green('╔' + '═'.repeat(width - 2) + '╗')); console.log(chalk_1.default.green('║') + chalk_1.default.green.bold(title.padStart((width + title.length) / 2).padEnd(width - 2)) + chalk_1.default.green('║')); console.log(chalk_1.default.green('╠' + '═'.repeat(width - 2) + '╣')); content.forEach(line => { const truncatedLine = line.length > width - 4 ? line.substring(0, width - 7) + '...' : line; console.log(chalk_1.default.green('║') + ` ${truncatedLine}`.padEnd(width - 2) + chalk_1.default.green('║')); }); console.log(chalk_1.default.green('╚' + '═'.repeat(width - 2) + '╝')); } static printErrorBox(title, content) { const maxWidth = Math.max(title.length, ...content.map(line => line.length)); const terminalWidth = process.stdout.columns || 80; const width = Math.min(Math.max(maxWidth + 4, 40), terminalWidth - 4); console.log(chalk_1.default.red('╔' + '═'.repeat(width - 2) + '╗')); console.log(chalk_1.default.red('║') + chalk_1.default.red.bold(title.padStart((width + title.length) / 2).padEnd(width - 2)) + chalk_1.default.red('║')); console.log(chalk_1.default.red('╠' + '═'.repeat(width - 2) + '╣')); content.forEach(line => { const truncatedLine = line.length > width - 4 ? line.substring(0, width - 7) + '...' : line; console.log(chalk_1.default.red('║') + ` ${truncatedLine}`.padEnd(width - 2) + chalk_1.default.red('║')); }); console.log(chalk_1.default.red('╚' + '═'.repeat(width - 2) + '╝')); } static printInfoBox(title, content) { const maxWidth = Math.max(title.length, ...content.map(line => line.length)); const terminalWidth = process.stdout.columns || 80; const width = Math.min(Math.max(maxWidth + 4, 40), terminalWidth - 4); console.log(chalk_1.default.blue('╔' + '═'.repeat(width - 2) + '╗')); console.log(chalk_1.default.blue('║') + chalk_1.default.blue.bold(title.padStart((width + title.length) / 2).padEnd(width - 2)) + chalk_1.default.blue('║')); console.log(chalk_1.default.blue('╠' + '═'.repeat(width - 2) + '╣')); content.forEach(line => { const truncatedLine = line.length > width - 4 ? line.substring(0, width - 7) + '...' : line; console.log(chalk_1.default.blue('║') + ` ${truncatedLine}`.padEnd(width - 2) + chalk_1.default.blue('║')); }); console.log(chalk_1.default.blue('╚' + '═'.repeat(width - 2) + '╝')); } static printStatus(label, value, status = 'info') { const statusIcon = { success: '✅', error: '❌', warning: '⚠️', info: 'ℹ️' }[status]; const statusColor = { success: chalk_1.default.green, error: chalk_1.default.red, warning: chalk_1.default.yellow, info: chalk_1.default.blue }[status]; console.log(`${statusIcon} ${chalk_1.default.bold(label)}: ${statusColor(value)}`); } static printWelcome() { const terminalWidth = process.stdout.columns || 80; const maxWidth = Math.min(70, terminalWidth - 4); console.log(''); console.log(chalk_1.default.cyan('╭' + '═'.repeat(maxWidth) + '╮')); console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.cyan(' '.repeat(Math.floor((maxWidth - 24) / 2)) + '🚀 Dev Spaces Switcher' + ' '.repeat(Math.ceil((maxWidth - 24) / 2))) + chalk_1.default.cyan('║')); console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(' '.repeat(Math.floor((maxWidth - 52) / 2)) + 'Manage isolated development environments with ease' + ' '.repeat(Math.ceil((maxWidth - 52) / 2))) + chalk_1.default.cyan('║')); console.log(chalk_1.default.cyan('╰' + '═'.repeat(maxWidth) + '╯')); console.log(''); } static printQuickHelp() { console.log(chalk_1.default.dim('Quick commands:')); console.log(chalk_1.default.dim(' • '), this.command('dss list'), chalk_1.default.dim(' - Show all spaces')); console.log(chalk_1.default.dim(' • '), this.command('dss add'), chalk_1.default.dim(' - Add new space')); console.log(chalk_1.default.dim(' • '), this.command('dss switch'), chalk_1.default.dim(' - Switch between spaces')); console.log(chalk_1.default.dim(' • '), this.command('dss --help'), chalk_1.default.dim(' - Show detailed help')); console.log(''); } static printSpaceSwitched(spaceName) { console.log(''); console.log(chalk_1.default.green('╭─────────────────────────────────────╮')); console.log(chalk_1.default.green('│') + chalk_1.default.green.bold(' ✨ Space Switched Successfully! ') + chalk_1.default.green('│')); console.log(chalk_1.default.green('├─────────────────────────────────────┤')); console.log(chalk_1.default.green('│') + chalk_1.default.white(` Active space: ${chalk_1.default.green.bold(spaceName)}`.padEnd(35)) + chalk_1.default.green('│')); console.log(chalk_1.default.green('╰─────────────────────────────────────╯')); console.log(''); } } exports.UIHelper = UIHelper; UIHelper.progressState = { active: false, startTime: 0, message: '', spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧'], index: 0, interval: null };