pub struct Colors;
impl Colors {
pub const YELLOW: &'static str = "\x1b[1;33m";
pub const CYAN: &'static str = "\x1b[1;36m";
pub const GREEN: &'static str = "\x1b[1;32m";
pub const WHITE: &'static str = "\x1b[1;37m";
pub const GRAY: &'static str = "\x1b[90m";
pub const MAGENTA: &'static str = "\x1b[1;35m";
pub const RESET: &'static str = "\x1b[0m";
}
#[derive(Clone, Copy, PartialEq)]
pub enum StepStatus {
Active,
Completed,
Pending,
}
pub fn render_steps(steps: &[(String, StepStatus)]) {
let mut parts = Vec::new();
for (i, (step, status)) in steps.iter().enumerate() {
if i > 0 {
parts.push(format!("{} {} ", Colors::GRAY, "|"));
}
let (indicator, color) = match status {
StepStatus::Active => ("◆", Colors::YELLOW),
StepStatus::Completed => ("◆", Colors::GREEN),
StepStatus::Pending => ("", Colors::GRAY),
};
let text_color = match status {
StepStatus::Active => Colors::GREEN,
StepStatus::Completed => Colors::GREEN,
StepStatus::Pending => Colors::WHITE,
};
if !indicator.is_empty() {
parts.push(format!("{}{}{} ", color, indicator, Colors::RESET));
}
parts.push(format!("{}{}{}", text_color, step, Colors::RESET));
}
print!("{}\r\n", parts.join(""));
}
pub fn render_title(title: &str) {
print!("{}{}{}\r\n", Colors::YELLOW, title, Colors::RESET);
}
pub fn render_subtitle(subtitle: &str) {
print!("{}{}{}\r\n", Colors::CYAN, subtitle, Colors::RESET);
}
pub fn render_success(message: &str) {
print!("{}{}{}\r\n", Colors::GREEN, message, Colors::RESET);
}
pub fn render_option(option: &str, is_selected: bool, _is_recommended: bool) {
let indicator = if is_selected {
format!("{}●{}", Colors::GREEN, Colors::RESET)
} else {
format!("{}○{}", Colors::GRAY, Colors::RESET)
};
let text_color = if is_selected {
Colors::WHITE
} else {
Colors::GRAY
};
print!(
" {} {}{}{}\r\n",
indicator,
text_color,
option,
Colors::RESET
);
}
pub fn render_config_preview(config: &str) {
print!("\r\n");
print!(
"{}Configuration preview:{}\r\n",
Colors::CYAN,
Colors::RESET
);
print!("{}\r\n", Colors::GRAY);
for line in config.lines() {
if line.trim().starts_with('[') {
print!("{}{}{}\r\n", Colors::YELLOW, line, Colors::RESET);
} else if line.contains('=') {
if let Some((key, value)) = line.split_once('=') {
print!(
"{}{}{}={}{}{}\r\n",
Colors::CYAN,
key.trim(),
Colors::RESET,
Colors::GRAY,
value.trim(),
Colors::RESET
);
} else {
print!("{}\r\n", line);
}
} else {
print!("{}\r\n", line);
}
}
print!("{}\r\n", Colors::RESET);
}
pub fn render_footer_shortcuts() {
let enter = format!("{}{}{}", Colors::GREEN, "Enter", Colors::GRAY);
let arrows = format!("{}{}{}", Colors::YELLOW, " ↑/↓", Colors::GRAY);
let type_key = format!("{}{}{}", Colors::CYAN, " Type", Colors::GRAY);
let esc = format!("{}\x1b[1;31m{}{}", Colors::RESET, " Esc", Colors::GRAY);
let gray = Colors::GRAY;
print!(
"{}{} confirm {}{} select {}{} search {}{} cancel\r\n",
enter, gray, arrows, gray, type_key, gray, esc, gray
);
}
pub fn render_error(message: &str) {
eprint!("\x1b[1;31m{}\x1b[0m\r\n", message);
}
pub fn render_warning(message: &str) {
print!("{}⚠️ {}{}\r\n", Colors::YELLOW, message, Colors::RESET);
}
pub fn render_info(message: &str) {
print!("{}{}{}\r\n", Colors::MAGENTA, message, Colors::RESET);
}
pub fn render_profile_name(profile_name: &str) {
print!(
"{}Profile{} {}{}\r\n",
Colors::GRAY,
Colors::RESET,
profile_name,
Colors::RESET
);
}
pub fn render_default_models(smart_model: &str, eco_model: &str) {
print!("{}Default models:{}\r\n", Colors::WHITE, Colors::RESET);
print!(
" {}Smart: {}{}\r\n",
Colors::GRAY,
Colors::WHITE,
smart_model
);
print!(" {}Eco: {}{}\r\n", Colors::GRAY, Colors::WHITE, eco_model);
print!("\r\n");
}
pub fn render_telemetry_disclaimer() {
let border = Colors::CYAN;
let r = Colors::RESET;
print!("\r\n");
print!(
"{}╭──────────────────────────────────────────────────────────╮{}\r\n",
border, r
);
print!(
"{}│{} {}Anonymous Telemetry{} {}│{}\r\n",
border,
r,
Colors::GREEN,
r,
border,
r
);
print!(
"{}│{} we collect anonymous telemetry to improve stakpak. {}│{}\r\n",
border, r, border, r
);
print!(
"{}│{} no prompts, code, or personal data is collected. {}│{}\r\n",
border, r, border, r
);
print!(
"{}│{} opt-out: set {}collect_telemetry = false{} in config {}│{}\r\n",
border,
r,
Colors::YELLOW,
r,
border,
r
);
print!(
"{}╰──────────────────────────────────────────────────────────╯{}\r\n",
border, r
);
print!("\r\n");
}