termo 0.16.0

yet another terminal ui framework
Documentation
use std::{error::Error, io::{self, Write, Read}};

use crossterm::{terminal::{self, ClearType}, cursor, event::{self, KeyEvent, KeyCode}};
use kdam::term::Colorizer;

use crate::Printable;

///│ ASKS ─·─► USERNAME
///╭───────╯
///│ please enter your username
///╰─► [input]   
pub fn input(name: impl Into<String>, message: impl Into<String>) -> String {
    "│ [dim_gray]ASKS ─·─► [magenda]{}[/]".print_with(vec![name.into()]);
    "│ [dim_gray]╭─────╯[/]".print();
    "│ [dim_gray]│ [/][yellow]{}[/]".print_with(vec![message.into()]);
    "│ [dim_gray]╰─► [/]".print();
    let mut input = String::new();
    //move cursor to end of ─► (up 1, right 3)
    print!("{}", cursor::MoveUp(1).to_string());
    print!("{}", cursor::MoveRight(5).to_string());
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()

}



#[derive(Clone)]
pub struct Opt<T>
where
    T: Clone,
{
    option: String,
    description: String,
    action: fn() -> T,
}

impl<T> Opt<T>
where
    T: Clone,
{
    pub fn new(option: impl Into<String>, description: impl Into<String>, action: fn() -> T) -> Opt<T> {
        Opt {
            option: option.into(),
            description: description.into(),
            action: action,
        }
    }
}

pub fn selection<T>(options: Vec<Opt<T>>) -> T
where
    T: Clone,
{
    let mut selected_index = 0;
    loop {
        // Clear the terminal
        // terminal::clear(ClearType::All).unwrap();

        // Move the cursor to the top left
        cursor::MoveTo(0, 0);

        // Display the menu options
        println!("Please select an option:");
        for (i, opt) in options.iter().enumerate() {
            if i == selected_index {
                print!("\x1b[33m> \x1b[0m"); // Highlight selected with a '>'
            } else {
                print!("  "); // Add space for unselected
            }
            println!("{} - {}", opt.option, opt.description);
        }

        // Get user input
        if event::poll(std::time::Duration::from_millis(100)).unwrap() {
            if let event::Event::Key(KeyEvent { code, .. }) = event::read().unwrap() {
                match code {
                    KeyCode::Up => {
                        if selected_index > 0 {
                            selected_index -= 1;
                        }
                    }
                    KeyCode::Down => {
                        if selected_index < options.len() - 1 {
                            selected_index += 1;
                        }
                    }
                    KeyCode::Enter => return (options[selected_index].action)(),
                    _ => {}
                }
            }
        }
    }
}