use console::{style, Color, Emoji, Style};
use std::fmt::Display;
struct Theme;
impl Theme {
fn success_style() -> Style {
Style::new().color256(46).bold() }
const ERROR: Color = Color::Red;
const WARNING: Color = Color::Yellow;
fn info_style() -> Style {
Style::new().color256(35) }
fn tip_style() -> Style {
Style::new().color256(35) }
fn dim_style() -> Style {
Style::new().dim()
}
}
pub struct Output;
impl Output {
pub fn success<T: Display>(message: T) {
println!("{} {}", Theme::success_style().apply_to("✓"), message);
}
pub fn error<T: Display>(message: T) {
println!("{} {}", style("✗").fg(Theme::ERROR), message);
}
pub fn warning<T: Display>(message: T) {
println!("{} {}", style("⚠").fg(Theme::WARNING), message);
}
pub fn info<T: Display>(message: T) {
println!("{} {}", Theme::info_style().apply_to("ℹ"), message);
}
pub fn sub_item<T: Display>(message: T) {
println!(" {} {}", Theme::dim_style().apply_to("→"), message);
}
pub fn bullet<T: Display>(message: T) {
println!(" {} {}", Theme::dim_style().apply_to("•"), message);
}
pub fn section<T: Display>(title: T) {
println!("\n{}", style(title).bold().underlined());
}
pub fn tip<T: Display>(message: T) {
println!(
"{} {}",
Theme::tip_style().apply_to("TIP:"),
Theme::dim_style().apply_to(message)
);
}
pub fn progress<T: Display>(message: T) {
print!("{} {}", Theme::info_style().apply_to("→"), message);
use std::io::{self, Write};
io::stdout().flush().unwrap();
}
pub fn success_inline() {
println!(" {}", Theme::success_style().apply_to("✓"));
}
pub fn error_inline<T: Display>(message: T) {
if message.to_string().is_empty() {
println!(" {}", style("✗").fg(Theme::ERROR));
} else {
println!(" {} {}", style("✗").fg(Theme::ERROR), message);
}
}
pub fn divider() {
println!("{}", Theme::dim_style().apply_to("─".repeat(50)));
}
pub fn stack_info(
name: &str,
id: &str,
base_branch: &str,
working_branch: Option<&str>,
is_active: bool,
) {
println!(
"{} {}",
Theme::info_style().apply_to("Stack:"),
style(name).bold()
);
Self::sub_item(format!("Stack ID: {}", Theme::dim_style().apply_to(id)));
Self::sub_item(format!(
"Base branch: {}",
Theme::info_style().apply_to(base_branch)
));
if let Some(working) = working_branch {
Self::sub_item(format!(
"Working branch: {}",
Theme::info_style().apply_to(working)
));
}
if is_active {
Self::sub_item(format!(
"Status: {}",
Theme::success_style().apply_to("Active")
));
}
}
pub fn next_steps(steps: &[&str]) {
println!();
Self::tip("Next steps:");
for step in steps {
Self::bullet(step);
}
}
pub fn command_example<T: Display>(command: T) {
println!(" {}", style(command).fg(Theme::WARNING));
}
pub fn check_start<T: Display>(message: T) {
println!("\n{} {}", style("🔍").bright(), style(message).bold());
}
pub fn solution<T: Display>(message: T) {
println!(" {}: {}", style("Solution").fg(Theme::WARNING), message);
}
pub fn numbered_item<T: Display>(number: usize, message: T) {
println!(" {}. {}", Theme::info_style().apply_to(number), message);
}
pub fn spacing() {
println!();
}
pub fn entry_status(is_submitted: bool, is_merged: bool) -> String {
if is_merged {
format!("{}", Theme::success_style().apply_to("[merged]"))
} else if is_submitted {
format!("{}", Theme::info_style().apply_to("[submitted]"))
} else {
format!("{}", style("[pending]").fg(Theme::WARNING))
}
}
}
pub struct Emojis;
impl Emojis {
pub const SUCCESS: Emoji<'_, '_> = Emoji("✓", "OK");
pub const ERROR: Emoji<'_, '_> = Emoji("✗", "ERROR");
pub const WARNING: Emoji<'_, '_> = Emoji("⚠", "WARNING");
pub const INFO: Emoji<'_, '_> = Emoji("ℹ", "INFO");
pub const TIP: Emoji<'_, '_> = Emoji("💡", "TIP");
pub const ROCKET: Emoji<'_, '_> = Emoji("🚀", "ROCKET");
pub const SEARCH: Emoji<'_, '_> = Emoji("🔍", "SEARCH");
pub const UPLOAD: Emoji<'_, '_> = Emoji("📤", "UPLOAD");
pub const STACK: Emoji<'_, '_> = Emoji("📊", "STACK");
}