The UI module provides a set of components and utilities for creating a consistent and user-friendly command-line interface. This document provides an overview of the UI module and how to use it.
Overview
The UI module is designed to provide a consistent visual language across the CLI, making it easier to create a polished and professional user experience. It includes:
Theme System: A centralized theme system that defines colors, typography, symbols, and spacing.
Enhanced Logger: An enhanced logger that uses the theme system to create visually appealing log messages.
Interactive Elements: Spinners, progress bars, and interactive prompts for better user interaction.
Command Output Enhancements: Banners, tables, and JSON output for better command output.
Getting Started
To use the UI module, import it in your code:
import * as ui from "../ui";
Theme System
The theme system provides a consistent visual language across the CLI. It includes:
Colors
The theme system defines a set of colors for different purposes:
// Primary colors
ui.colors.primary; // Blue - Primary brand color
ui.colors.secondary; // Purple - Secondary brand color
// Status colors
ui.colors.success; // Green - Success messages
ui.colors.warning; // Yellow - Warning messages
ui.colors.error; // Red - Error messages
ui.colors.info; // Blue - Info messages
// Neutral colors
ui.colors.muted; // Gray - Muted text
ui.colors.subtle; // Light gray - Subtle text
// Text colors
ui.colors.heading; // White bold - Headings
ui.colors.text; // White - Normal text
// Special colors
ui.colors.highlight; // Yellow - Highlighted text
ui.colors.link; // Blue underlined - Links
Symbols
The theme system defines a set of symbols for different message types:
The theme system defines a set of typography styles for consistent text formatting:
ui.typography.heading1("Heading 1"); // Bold white text
ui.typography.heading2("Heading 2"); // Bold white text
ui.typography.heading3("Heading 3"); // Bold white text
ui.typography.text("Normal text"); // White text
ui.typography.muted("Muted text"); // Gray text
ui.typography.code("Code"); // Code with background
Spacing
The theme system defines a set of spacing constants for consistent layout:
ui.spacing.xs; // 2 spaces - Extra small spacing
ui.spacing.sm; // 4 spaces - Small spacing
ui.spacing.md; // 8 spaces - Medium spacing
ui.spacing.lg; // 12 spaces - Large spacing
ui.spacing.xl; // 16 spaces - Extra large spacing
Utility Functions
The theme system provides utility functions for common tasks:
// Create indentation
ui.indent(2); // 8 spaces (2 * spacing.sm)
// Create a horizontal line
ui.line(); // 80 characters of "─"
ui.line(40); // 40 characters of "─"
ui.line(40, "="); // 40 characters of "="
// Apply theme to a message
ui.applyTheme("info", "Hello, world!"); // Blue "ℹ Hello, world!"
Enhanced Logger
The enhanced logger provides a more visually appealing and structured logging experience. It includes:
try {
// Some code that might throw an error
} catch (error) {
ui.logger.errorWithContext("Failed to process file", error, {
file: "example.txt",
line: 42,
});
// Red "✖ Failed to process file (file: example.txt, line: 42) Error: Something went wrong"
}
// Set output format to JSON
ui.logger.setOutputFormat("json");
// Log messages
ui.logger.info("Info message");
// {"level":"info","message":"Info message","timestamp":"2025-04-30T10:00:00.000Z"}
// Reset output format to text
ui.logger.setOutputFormat("text");
Log Levels
// Set log level
ui.logger.setLogLevel(ui.logger.LogLevel.DEBUG); // Show all logs
ui.logger.setLogLevel(ui.logger.LogLevel.INFO); // Show info and above
ui.logger.setLogLevel(ui.logger.LogLevel.ERROR); // Show only errors
ui.logger.setLogLevel("debug"); // String version
// Get current log level
const level = ui.logger.getLogLevel(); // Returns LogLevel enum value
const levelName = ui.logger.getLogLevelName(); // Returns string (e.g., "INFO")
Best Practices
Use the Theme System
Always use the theme system to ensure a consistent visual language across the CLI. This makes it easier to maintain and update the UI in the future.
// Good
console.log(ui.colors.primary("Primary text"));
// Bad
console.log("\x1b[34mPrimary text\x1b[0m");
Use the Enhanced Logger
Use the enhanced logger for all logging to ensure a consistent logging experience. The enhanced logger provides better formatting, support for structured output, and log levels.
// Good
ui.logger.info("Info message");
// Bad
console.log("Info message");
Group Related Logs
Use log groups to organize related logs. This makes it easier to understand the structure of the output.
// Good
ui.logger.group("Configuration", () => {
ui.logger.info("Loading configuration...");
ui.logger.info("Configuration loaded successfully.");
});
// Bad
ui.logger.info("Configuration:");
ui.logger.info("Loading configuration...");
ui.logger.info("Configuration loaded successfully.");
Use Appropriate Log Levels
Use the appropriate log level for each message. This allows users to control the verbosity of the output.
// Debug information (only shown with --debug)
ui.logger.debug("Detailed debug information");
// Verbose information (only shown with --verbose)
ui.logger.verbose("More details than normal");
// Normal information
ui.logger.info("Normal information");
// Success messages
ui.logger.success("Operation completed successfully");
// Warning messages
ui.logger.warn("Something might be wrong");
// Error messages
ui.logger.error("Something went wrong");
Spinner Component
Basic Usage
import * as ui from "../ui";
// Create and start a spinner
const spinner = new ui.Spinner({ text: "Loading..." }).start();
// Do some work
// ...
// Update the spinner text
spinner.text("Still loading...");
// Mark the spinner as succeeded
spinner.succeed("Loaded successfully!");
Spinner Options
const spinner = new ui.Spinner({
text: "Loading...", // Text to display next to the spinner
type: "dots", // Spinner type (default, dots, line, star, arrow, bouncingBar, bouncingBall)
color: "primary", // Color of the spinner (primary, secondary, success, warning, error, info, muted)
enabled: true, // Whether to show the spinner
});
Spinner Methods
// Start the spinner
spinner.start();
// Stop the spinner
spinner.stop();
// Update the spinner text
spinner.text("New text");
// Mark the spinner as succeeded
spinner.succeed("Success message");
// Mark the spinner as failed
spinner.fail("Error message");
// Mark the spinner as warned
spinner.warn("Warning message");
// Mark the spinner as information
spinner.info("Info message");
// Clear the spinner
spinner.clear();
// Reset the spinner
spinner.reset();
Static Methods
// Create and start a spinner
const spinner = ui.Spinner.start({ text: "Loading..." });
// Create a spinner for a promise
const result = await ui.Spinner.promise(
{ text: "Loading data..." },
fetchData(),
"Data loaded successfully!",
"Failed to load data",
);
Helper Functions
// Create and start a spinner
const spinner = ui.spinner({ text: "Loading..." });
// Create a spinner for a promise
const result = await ui.spinnerPromise(
{ text: "Loading data..." },
fetchData(),
"Data loaded successfully!",
"Failed to load data",
);
Progress Bar Component
Basic Usage
import * as ui from "../ui";
// Create and start a progress bar
const progressBar = new ui.ProgressBar({ total: 100 }).start();
// Update the progress bar
progressBar.update(25, { status: "Processing..." });
// Increment the progress bar
progressBar.increment(5, { status: "Still processing..." });
// Stop the progress bar
progressBar.stop();
Progress Bar Options
const progressBar = new ui.ProgressBar({
total: 100, // Total number of steps
start: 0, // Initial value
format: "{bar} {percentage}%", // Format string
barWidth: 40, // Width of the progress bar
barCompleteChar: "█", // Character for completed part
barIncompleteChar: "░", // Character for incomplete part
clearOnComplete: true, // Clear on completion
stopOnComplete: true, // Stop on completion
hideCursor: true, // Hide cursor
enabled: true, // Whether to show the progress bar
color: "primary", // Color of the progress bar
});
Progress Bar Methods
// Start the progress bar
progressBar.start(0, { status: "Starting..." });
// Update the progress bar
progressBar.update(50, { status: "Halfway done..." });
// Increment the progress bar
progressBar.increment(10, { status: "Making progress..." });
// Stop the progress bar
progressBar.stop();
// Update the total value
progressBar.setTotal(200);
Processing Arrays
// Process an array of items with a progress bar
const items = ["item1", "item2", "item3", "item4", "item5"];
const results = await ui.ProgressBar.forEachAsync(
{ total: items.length, color: "primary" },
items,
async (item, index) => {
// Process the item
await processItem(item);
return `Processed ${item}`;
},
(item, index) => `Processing ${item}...`,
);
// Or use the helper function
const results = await ui.progressForEach(
{ total: items.length, color: "primary" },
items,
async (item, index) => {
// Process the item
await processItem(item);
return `Processed ${item}`;
},
(item, index) => `Processing ${item}...`,
);
Multiple Progress Bars
// Create a multi-bar container
const multiBar = ui.ProgressBar.createMultiBar();
// Create progress bars in the container
const bar1 = multiBar.create("bar1", { total: 100, color: "primary" });
const bar2 = multiBar.create("bar2", { total: 200, color: "secondary" });
const bar3 = multiBar.create("bar3", { total: 300, color: "success" });
// Update the progress bars
bar1.update(25, { status: "Processing bar 1..." });
bar2.update(50, { status: "Processing bar 2..." });
bar3.update(75, { status: "Processing bar 3..." });
// Stop all progress bars
multiBar.stop();
Interactive Prompts Component
Basic Usage
import * as ui from "../ui";
// Initialize the prompt system
ui.init("DeepLint CLI");
// Show a text input prompt
const name = await ui.text({
message: "What is your name?",
placeholder: "Enter your name",
validate: (value) => {
if (!value) return "Name is required";
},
});
// Check if the user cancelled the prompt
if (ui.isCancel(name)) {
ui.cancel("Operation cancelled");
process.exit(1);
}
// Show a confirmation prompt
const confirm = await ui.confirm({
message: "Are you sure?",
initialValue: true,
});
// Show a select prompt
const option = await ui.select({
message: "Select an option",
options: [
{ value: "option1", label: "Option 1" },
{ value: "option2", label: "Option 2" },
{ value: "option3", label: "Option 3" },
],
});
// Show a multi-select prompt
const options = await ui.multiselect({
message: "Select options",
options: [
{ value: "option1", label: "Option 1" },
{ value: "option2", label: "Option 2" },
{ value: "option3", label: "Option 3" },
],
required: true,
});
// Show a note
ui.note("This is a note", "Note Title");
// Show a themed note
ui.info("This is an info note");
ui.success("This is a success note");
ui.warning("This is a warning note");
ui.error("This is an error note");
// Run a task with a spinner
const result = await ui.task(
"Running task...",
async () => {
// Do some work
return "Task result";
},
"Task completed successfully!",
"Task failed",
);
// End the prompt session
ui.done("All done!");
Helper Functions
The interactive prompts component provides several helper functions for common prompt types:
Text Input
const name = await ui.text({
message: "What is your name?",
placeholder: "Enter your name",
initialValue: "John Doe",
validate: (value) => {
if (!value) return "Name is required";
},
});
Password Input
const password = await ui.password({
message: "Enter your password",
validate: (value) => {
if (!value) return "Password is required";
if (value.length < 8) return "Password must be at least 8 characters";
},
});
// Regular note
ui.note("This is a note", "Note Title");
// Themed notes
ui.info("This is an info note");
ui.success("This is a success note");
ui.warning("This is a warning note");
ui.error("This is an error note");
Task with Spinner
const result = await ui.task(
"Running task...",
async () => {
// Do some work
return "Task result";
},
"Task completed successfully!",
"Task failed",
);
Cancellation
// Check if the user cancelled the prompt
if (ui.isCancel(result)) {
ui.cancel("Operation cancelled");
process.exit(1);
}
Session Management
// Initialize the prompt session
ui.init("DeepLint CLI");
// End the prompt session
ui.done("All done!");
Banner Component
Basic Usage
import * as ui from "../ui";
// Create a simple banner
const simpleBanner = ui.banner("Hello, world!", {
title: "Welcome",
borderColor: "primary",
});
console.log(simpleBanner);
Banner Options
const banner = ui.banner("Hello, world!", {
title: "Welcome", // Title of the banner
subtitle: "This is a subtitle", // Subtitle of the banner
borderStyle: "round", // Border style (single, double, round, bold, classic)
borderColor: "primary", // Border color (primary, secondary, success, warning, error, info, muted)
align: "center", // Text alignment (left, center, right)
padding: 1, // Padding (number or object)
margin: 1, // Margin (number or object)
width: 60, // Width of the banner
dimBorder: false, // Whether to dim the border
});
App Banner
// Create an app banner
const appBanner = ui.appBanner({
name: "DeepLint",
version: "1.0.0",
description: "A CLI tool for linting code with AI",
borderColor: "primary",
borderStyle: "bold",
});
console.log(appBanner);
Command Banner
// Create a command banner
const commandBanner = ui.commandBanner({
command: "init",
description: "Initialize DeepLint in the current project",
usage: "deeplint init [options]",
examples: ["deeplint init", "deeplint init --force"],
borderColor: "primary",
borderStyle: "round",
});
console.log(commandBanner);
Themed Banners
// Create a success banner
const successBanner = ui.successBanner("Operation completed successfully!", "Success");
// Create a warning banner
const warningBanner = ui.warningBanner("This operation might take a while.", "Warning");
// Create an error banner
const errorBanner = ui.errorBanner(
"An error occurred while processing your request.",
"Error",
);
// Create an info banner
const infoBanner = ui.infoBanner("This is an informational message.", "Info");
The table component provides a way to display structured data in the CLI. It uses a custom implementation that's designed to be robust and handle edge cases gracefully.
Basic Usage
import * as ui from "../ui";
// Create a simple table
const table = ui.createTable({
headers: ["Name", "Age", "Location"],
});
// Add rows to the table
table.push(["John", "25", "New York"]);
table.push(["Jane", "30", "San Francisco"]);
table.push(["Bob", "35", "Chicago"]);
// Display the table
console.log(table.toString());
The spinner component provides a loading indicator for long-running operations. It uses the library for the actual spinner implementation.
The progress bar component provides a visual indicator for tracking progress in long-running operations. It uses the library for the actual progress bar implementation.
The interactive prompts component provides a set of utilities for creating interactive prompts in the CLI. It uses the library for the actual prompt implementation.
The banner component provides a way to display headers and messages in the CLI. It uses the library for creating boxes around text.