use crate::components::{Box as RnkBox, Text};
use crate::core::{Color, Element, FlexDirection};
#[derive(Debug, Clone)]
pub struct AccordionItem {
title: String,
content: String,
}
#[derive(Debug, Clone)]
pub struct Accordion {
items: Vec<AccordionItem>,
expanded: Option<usize>,
allow_multiple: bool,
expanded_set: Vec<usize>,
}
impl Accordion {
pub fn new() -> Self {
Self {
items: Vec::new(),
expanded: None,
allow_multiple: false,
expanded_set: Vec::new(),
}
}
pub fn item(mut self, title: impl Into<String>, content: impl Into<String>) -> Self {
self.items.push(AccordionItem {
title: title.into(),
content: content.into(),
});
self
}
pub fn expanded(mut self, index: usize) -> Self {
self.expanded = Some(index);
self
}
pub fn allow_multiple(mut self) -> Self {
self.allow_multiple = true;
self
}
pub fn expanded_items(mut self, indices: Vec<usize>) -> Self {
self.expanded_set = indices;
self.allow_multiple = true;
self
}
pub fn into_element(self) -> Element {
let mut children = Vec::new();
for (i, item) in self.items.iter().enumerate() {
let is_expanded = if self.allow_multiple {
self.expanded_set.contains(&i)
} else {
self.expanded == Some(i)
};
let indicator = if is_expanded { "▼" } else { "▶" };
children.push(
RnkBox::new()
.flex_direction(FlexDirection::Row)
.padding_x(1.0)
.background(Color::Ansi256(238))
.children(vec![
Text::new(indicator).color(Color::Cyan).into_element(),
Text::new(format!(" {}", item.title))
.color(Color::White)
.bold()
.into_element(),
])
.into_element(),
);
if is_expanded {
children.push(
RnkBox::new()
.padding_x(2.0)
.padding_y(0.5)
.background(Color::Ansi256(236))
.child(Text::new(&item.content).color(Color::White).into_element())
.into_element(),
);
}
}
RnkBox::new()
.flex_direction(FlexDirection::Column)
.children(children)
.into_element()
}
}
impl Default for Accordion {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_accordion_creation() {
let acc = Accordion::new();
assert!(acc.items.is_empty());
}
#[test]
fn test_accordion_items() {
let acc = Accordion::new()
.item("Title 1", "Content 1")
.item("Title 2", "Content 2");
assert_eq!(acc.items.len(), 2);
}
#[test]
fn test_accordion_expanded() {
let acc = Accordion::new().item("A", "a").item("B", "b").expanded(0);
assert_eq!(acc.expanded, Some(0));
}
#[test]
fn test_accordion_into_element() {
let _ = Accordion::new()
.item("Section", "Content")
.expanded(0)
.into_element();
}
#[test]
fn test_accordion_multiple() {
let _ = Accordion::new()
.item("A", "a")
.item("B", "b")
.allow_multiple()
.expanded_items(vec![0, 1])
.into_element();
}
}