use crate::components::status::{StatusLevel, status_style};
use crate::components::{Box as RnkBox, Text};
use crate::core::{BorderStyle, Color, Element, FlexDirection};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AlertLevel {
#[default]
Info,
Success,
Warning,
Error,
}
impl From<AlertLevel> for StatusLevel {
fn from(level: AlertLevel) -> Self {
match level {
AlertLevel::Info => StatusLevel::Info,
AlertLevel::Success => StatusLevel::Success,
AlertLevel::Warning => StatusLevel::Warning,
AlertLevel::Error => StatusLevel::Error,
}
}
}
#[derive(Debug, Clone)]
pub struct Alert {
message: String,
level: AlertLevel,
title: Option<String>,
dismissible: bool,
}
impl Alert {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
level: AlertLevel::Info,
title: None,
dismissible: false,
}
}
pub fn info(message: impl Into<String>) -> Self {
Self::new(message).level(AlertLevel::Info)
}
pub fn success(message: impl Into<String>) -> Self {
Self::new(message).level(AlertLevel::Success)
}
pub fn warning(message: impl Into<String>) -> Self {
Self::new(message).level(AlertLevel::Warning)
}
pub fn error(message: impl Into<String>) -> Self {
Self::new(message).level(AlertLevel::Error)
}
pub fn level(mut self, level: AlertLevel) -> Self {
self.level = level;
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn dismissible(mut self) -> Self {
self.dismissible = true;
self
}
pub fn into_element(self) -> Element {
let style = status_style(self.level.into());
let icon = style.icon;
let color = style.fg;
let bg = style.bg;
let mut children = Vec::new();
let mut header_children = vec![
Text::new(format!("{} ", icon))
.color(color)
.bold()
.into_element(),
];
if let Some(title) = &self.title {
header_children.push(Text::new(title).color(color).bold().into_element());
} else {
header_children.push(Text::new(&self.message).color(Color::White).into_element());
}
if self.dismissible {
header_children.push(Text::new(" [x]").color(Color::BrightBlack).into_element());
}
children.push(
RnkBox::new()
.flex_direction(FlexDirection::Row)
.children(header_children)
.into_element(),
);
if self.title.is_some() {
children.push(
Text::new(format!(" {}", self.message))
.color(Color::White)
.into_element(),
);
}
RnkBox::new()
.flex_direction(FlexDirection::Column)
.padding_x(1.0)
.padding_y(0.5)
.background(bg)
.border_style(BorderStyle::Round)
.border_color(color)
.children(children)
.into_element()
}
}
impl Default for Alert {
fn default() -> Self {
Self::new("")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alert_creation() {
let a = Alert::new("Test message");
assert_eq!(a.message, "Test message");
}
#[test]
fn test_alert_levels() {
let _ = Alert::info("Info").into_element();
let _ = Alert::success("Success").into_element();
let _ = Alert::warning("Warning").into_element();
let _ = Alert::error("Error").into_element();
}
#[test]
fn test_alert_with_title() {
let a = Alert::error("Details").title("Error!");
assert_eq!(a.title, Some("Error!".to_string()));
}
}