UNPKG

drift-chat-cli

Version:

Terminal-based chat client for Drift Chat - create and join temporary chat rooms from your command line

260 lines (207 loc) 9.58 kB
const chalk = require('chalk'); class Display { constructor() { this.inputBoxActive = false; this.suggestionsActive = false; this.suggestionLines = 0; this.redrawCallback = null; } displayBanner() { console.log(chalk.magentaBright(` ██████╗ ██████╗ ██╗███████╗████████╗ ██╔══██╗██╔══██╗██║██╔════╝╚══██╔══╝ ██║ ██║██████╔╝██║█████╗ ██║ ██║ ██║██╔══██╗██║██╔══╝ ██║ ██████╔╝██║ ██║██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ `)); console.log(chalk.blue.bold(' 🚀 CLI')); console.log(chalk.gray(' Connect to chat rooms from your terminal!\n')); } showChatIntro() { console.log(chalk.cyan('💬 You are now in the chat!! Type your messages and press Enter.')); console.log(chalk.gray('Commands: "/quit" to leave')); console.log(chalk.gray('Commands: "/room" for room code')); console.log(chalk.gray('Commands: "/help" for help')); console.log( chalk.yellow.bold('\n✨ ~~~ ') + chalk.cyanBright.underline.bold(' P A S T I M E ') + chalk.yellow.bold(' ~~~ ✨\n') ); console.log(chalk.gray('👉 ') + chalk.greenBright('/trivia') + chalk.white(' → Random trivias 🧠')); console.log(chalk.gray('👉 ') + chalk.blueBright('/fortune') + chalk.white(' → Quirky quotes 🍀')); console.log(chalk.gray('👉 ') + chalk.magentaBright('/art') + chalk.white(' → Fun ASCII art 🎨')); console.log(chalk.gray('\nOther Features:')); console.log(chalk.gray('👉 ') + chalk.yellowBright('/emojis') + chalk.white(' → Show emoji shortcuts 😊')); console.log(chalk.gray('👉 ') + chalk.gray('Type ":" for emoji suggestions (↑↓ to navigate, Tab to select)')); console.log(chalk.gray('👉 ') + chalk.gray('Use :) :D :heart: etc in messages for emojis!')); } displayMessage(message, currentNickname) { const time = new Date(message.timestamp).toLocaleTimeString(); const isOwnMessage = message.nickname === currentNickname; // Clear input and suggestions if active const wasInputActive = this.inputBoxActive; if (this.inputBoxActive) { this.clearInputBox(); } if (this.suggestionsActive) { this.clearEmojiSuggestions(); } if (isOwnMessage) { console.log(chalk.gray(`[${time}] `) + chalk.blue.bold(`You: `) + message.message); } else { console.log(chalk.gray(`[${time}] `) + chalk.green.bold(`${message.nickname}: `) + message.message); } // Restore input if it was active and we have a redraw callback if (wasInputActive && this.redrawCallback) { this.redrawCallback(); } } displaySystemMessage(text) { // Clear input and suggestions if active const wasInputActive = this.inputBoxActive; if (this.inputBoxActive) { this.clearInputBox(); } if (this.suggestionsActive) { this.clearEmojiSuggestions(); } console.log(chalk.yellow(`🔔 ${text}`)); // Restore input if it was active and we have a redraw callback if (wasInputActive && this.redrawCallback) { this.redrawCallback(); } } showHelpMessage(gameCommands) { // Clear input and suggestions if active const wasInputActive = this.inputBoxActive; if (this.inputBoxActive) { this.clearInputBox(); } if (this.suggestionsActive) { this.clearEmojiSuggestions(); } console.log(chalk.yellow('🎮 P A S T I M E:')); gameCommands.forEach(cmd => { console.log(chalk.gray(` ${cmd.command.padEnd(10)} - ${cmd.description}`)); }); console.log(chalk.gray(' /help - Show this help')); console.log(chalk.gray(' /room - Show room code')); console.log(chalk.gray(' /quit - Leave the room')); // Restore input if it was active and we have a redraw callback if (wasInputActive && this.redrawCallback) { this.redrawCallback(); } } showGameContent(gameData) { // Clear input and suggestions if active const wasInputActive = this.inputBoxActive; if (this.inputBoxActive) { this.clearInputBox(); } if (this.suggestionsActive) { this.clearEmojiSuggestions(); } console.log(gameData.header); gameData.content.forEach(line => { console.log(line); }); // Restore input if it was active and we have a redraw callback if (wasInputActive && this.redrawCallback) { this.redrawCallback(); } } clearInputBox() { if (!this.inputBoxActive) return; // Move to input line and clear it process.stdout.write('\u001b[2K'); // Clear entire line process.stdout.write('\u001b[1G'); // Move to beginning of line } redrawInputBox(currentInput, cursorPosition) { if (!this.inputBoxActive) { this.inputBoxActive = true; } // Clear the line and redraw this.clearInputBox(); const prompt = chalk.blue('> '); const displayText = currentInput; process.stdout.write(prompt + displayText); // Position cursor correctly const totalPromptLength = 2; // '> ' length without ANSI codes const targetPosition = totalPromptLength + cursorPosition; // Move cursor to correct position process.stdout.write('\u001b[1G'); // Go to start of line process.stdout.write(`\u001b[${targetPosition + 1}G`); // Move to target position } setInputBoxActive(active) { this.inputBoxActive = active; } setRedrawCallback(callback) { this.redrawCallback = callback; } displayEmojiSuggestions(suggestions, selectedIndex = 0) { if (!suggestions || suggestions.length === 0) { this.clearEmojiSuggestions(); return; } // Clear previous suggestions first this.clearEmojiSuggestions(); // Move cursor to next line for suggestions process.stdout.write('\n'); suggestions.forEach((suggestion, index) => { const isSelected = index === selectedIndex; const prefix = isSelected ? chalk.bgBlue.white(' ► ') : ' '; const emoji = chalk.yellow(suggestion.emoji); const shortcut = chalk.gray(suggestion.shortcut); const description = chalk.dim(suggestion.description); process.stdout.write(prefix + emoji + ' ' + shortcut + ' ' + description + '\n'); }); this.suggestionsActive = true; this.suggestionLines = suggestions.length; // Move cursor back to input line process.stdout.write(`\u001b[${suggestions.length + 1}A`); // Move up by number of suggestion lines + 1 } clearEmojiSuggestions() { if (!this.suggestionsActive || this.suggestionLines === 0) { return; } // Save current cursor position process.stdout.write('\u001b[s'); // Move to start of suggestions and clear them process.stdout.write('\n'); // Go to next line (where suggestions start) for (let i = 0; i < this.suggestionLines; i++) { process.stdout.write('\u001b[2K'); // Clear entire line if (i < this.suggestionLines - 1) { process.stdout.write('\u001b[1B'); // Move down one line } } // Move back to input line process.stdout.write(`\u001b[${this.suggestionLines}A`); // Move up by number of suggestion lines this.suggestionsActive = false; this.suggestionLines = 0; } updateSelectedSuggestion(suggestions, selectedIndex) { if (!this.suggestionsActive || !suggestions || suggestions.length === 0) { return; } // Move to suggestion area and redraw process.stdout.write('\n'); suggestions.forEach((suggestion, index) => { const isSelected = index === selectedIndex; const prefix = isSelected ? chalk.bgBlue.white(' ► ') : ' '; const emoji = chalk.yellow(suggestion.emoji); const shortcut = chalk.gray(suggestion.shortcut); const description = chalk.dim(suggestion.description); // Clear line and redraw process.stdout.write('\u001b[2K'); // Clear entire line process.stdout.write('\u001b[1G'); // Move to beginning of line process.stdout.write(prefix + emoji + ' ' + shortcut + ' ' + description); if (index < suggestions.length - 1) { process.stdout.write('\n'); } }); // Move cursor back to input line process.stdout.write(`\u001b[${suggestions.length}A`); // Move up by number of suggestion lines } } module.exports = Display;