use crate::components::{Box as RnkBox, Text};
use crate::core::{Color, Element, FlexDirection};
#[derive(Debug, Clone)]
pub struct Quote {
text: String,
author: Option<String>,
source: Option<String>,
style: QuoteStyle,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum QuoteStyle {
#[default]
Block,
Inline,
Fancy,
}
impl Quote {
pub fn new(text: impl Into<String>) -> Self {
Self {
text: text.into(),
author: None,
source: None,
style: QuoteStyle::Block,
}
}
pub fn author(mut self, author: impl Into<String>) -> Self {
self.author = Some(author.into());
self
}
pub fn source(mut self, source: impl Into<String>) -> Self {
self.source = Some(source.into());
self
}
pub fn style(mut self, style: QuoteStyle) -> Self {
self.style = style;
self
}
pub fn into_element(self) -> Element {
match self.style {
QuoteStyle::Block => self.render_block(),
QuoteStyle::Inline => self.render_inline(),
QuoteStyle::Fancy => self.render_fancy(),
}
}
fn render_block(self) -> Element {
let mut children = Vec::new();
children.push(
RnkBox::new()
.flex_direction(FlexDirection::Row)
.children(vec![
Text::new("│ ").color(Color::Cyan).into_element(),
Text::new(&self.text)
.color(Color::White)
.italic()
.into_element(),
])
.into_element(),
);
if self.author.is_some() || self.source.is_some() {
let mut attr = String::from(" — ");
if let Some(author) = &self.author {
attr.push_str(author);
}
if let Some(source) = &self.source {
if self.author.is_some() {
attr.push_str(", ");
}
attr.push_str(source);
}
children.push(Text::new(attr).color(Color::BrightBlack).into_element());
}
RnkBox::new()
.flex_direction(FlexDirection::Column)
.padding_y(0.5)
.children(children)
.into_element()
}
fn render_inline(self) -> Element {
let mut content = format!("\"{}\"", self.text);
if let Some(author) = &self.author {
content.push_str(&format!(" — {}", author));
}
Text::new(content).italic().into_element()
}
fn render_fancy(self) -> Element {
let mut children = Vec::new();
children.push(
Text::new("\u{201C}")
.color(Color::Cyan)
.bold()
.into_element(),
);
children.push(
Text::new(&self.text)
.color(Color::White)
.italic()
.into_element(),
);
children.push(
Text::new("\u{201D}")
.color(Color::Cyan)
.bold()
.into_element(),
);
if let Some(author) = &self.author {
children.push(
Text::new(format!(" — {}", author))
.color(Color::BrightBlack)
.into_element(),
);
}
RnkBox::new()
.flex_direction(FlexDirection::Row)
.children(children)
.into_element()
}
}
impl Default for Quote {
fn default() -> Self {
Self::new("")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quote_creation() {
let q = Quote::new("Test quote");
assert_eq!(q.text, "Test quote");
}
#[test]
fn test_quote_with_author() {
let q = Quote::new("Quote").author("Author");
assert_eq!(q.author, Some("Author".to_string()));
}
#[test]
fn test_quote_styles() {
let _ = Quote::new("Test").style(QuoteStyle::Block).into_element();
let _ = Quote::new("Test").style(QuoteStyle::Inline).into_element();
let _ = Quote::new("Test").style(QuoteStyle::Fancy).into_element();
}
}