use crate::widgets::markdown_widget::foundation::elements::MarkdownElement;
use ratatui::style::{Color, Style};
use ratatui::text::{Line, Span};
pub fn render(
_element: &MarkdownElement,
fields: &[(String, String)],
collapsed: bool,
width: usize,
) -> Vec<Line<'static>> {
let border_style = Style::default().fg(Color::DarkGray);
let key_style = Style::default().fg(Color::Rgb(240, 113, 120)); let value_style = Style::default().fg(Color::Rgb(170, 217, 76)); let collapse_icon_style = Style::default().fg(Color::Yellow);
let border_char = "\u{2500}";
if collapsed {
let context_id = fields
.iter()
.find(|(k, _)| k == "context_id")
.map(|(_, v)| v.as_str())
.unwrap_or("frontmatter");
let prefix = "\u{25b6} \u{2500}\u{2500}\u{2500} ";
let suffix = " ";
let used_width =
prefix.chars().count() + context_id.chars().count() + suffix.chars().count();
let remaining = width.saturating_sub(used_width);
let border_fill = border_char.repeat(remaining);
vec![Line::from(vec![
Span::styled("\u{25b6} ", collapse_icon_style),
Span::styled("\u{2500}\u{2500}\u{2500} ", border_style),
Span::styled(context_id.to_string(), key_style),
Span::styled(" ", Style::default()),
Span::styled(border_fill, border_style),
])]
} else {
let mut lines = Vec::new();
let prefix_len = 2; let top_border = border_char.repeat(width.saturating_sub(prefix_len));
lines.push(Line::from(vec![
Span::styled("\u{25bc} ", collapse_icon_style),
Span::styled(top_border, border_style),
]));
for (key, value) in fields {
let key_prefix = format!("{}: ", key);
let key_prefix_len = key_prefix.chars().count();
let value_width = width.saturating_sub(key_prefix_len);
if value_width == 0 || value.chars().count() <= value_width {
lines.push(Line::from(vec![
Span::styled(key_prefix, key_style),
Span::styled(value.clone(), value_style),
]));
} else {
let wrapped = wrap_text(value, value_width);
for (i, line_text) in wrapped.iter().enumerate() {
if i == 0 {
lines.push(Line::from(vec![
Span::styled(key_prefix.clone(), key_style),
Span::styled(line_text.clone(), value_style),
]));
} else {
let continuation_indent = " ".repeat(key_prefix_len);
lines.push(Line::from(vec![
Span::styled(continuation_indent, Style::default()),
Span::styled(line_text.clone(), value_style),
]));
}
}
}
}
let bottom_border = border_char.repeat(width);
lines.push(Line::from(vec![Span::styled(bottom_border, border_style)]));
lines
}
}
pub fn render_start(collapsed: bool, context_id: Option<&str>, width: usize) -> Line<'static> {
let border_style = Style::default().fg(Color::DarkGray);
let key_style = Style::default().fg(Color::Rgb(240, 113, 120)); let collapse_icon_style = Style::default().fg(Color::Yellow);
let border_char = "\u{2500}";
if collapsed {
let ctx = context_id.unwrap_or("frontmatter");
let prefix = "\u{25b6} \u{2500}\u{2500}\u{2500} ";
let suffix = " ";
let used_width = prefix.chars().count() + ctx.chars().count() + suffix.chars().count();
let remaining = width.saturating_sub(used_width);
let border_fill = border_char.repeat(remaining);
Line::from(vec![
Span::styled("\u{25b6} ", collapse_icon_style),
Span::styled("\u{2500}\u{2500}\u{2500} ", border_style),
Span::styled(ctx.to_string(), key_style),
Span::styled(" ", Style::default()),
Span::styled(border_fill, border_style),
])
} else {
let prefix_len = 2; let top_border = border_char.repeat(width.saturating_sub(prefix_len));
Line::from(vec![
Span::styled("\u{25bc} ", collapse_icon_style),
Span::styled(top_border, border_style),
])
}
}
pub fn render_field(key: &str, value: &str, width: usize) -> Vec<Line<'static>> {
let key_style = Style::default().fg(Color::Rgb(240, 113, 120)); let value_style = Style::default().fg(Color::Rgb(170, 217, 76));
let key_prefix = format!("{}: ", key);
let key_prefix_len = key_prefix.chars().count();
let value_width = width.saturating_sub(key_prefix_len);
if value_width == 0 || value.chars().count() <= value_width {
vec![Line::from(vec![
Span::styled(key_prefix, key_style),
Span::styled(value.to_string(), value_style),
])]
} else {
let wrapped = wrap_text(value, value_width);
let mut lines = Vec::new();
for (i, line_text) in wrapped.iter().enumerate() {
if i == 0 {
lines.push(Line::from(vec![
Span::styled(key_prefix.clone(), key_style),
Span::styled(line_text.clone(), value_style),
]));
} else {
let continuation_indent = " ".repeat(key_prefix_len);
lines.push(Line::from(vec![
Span::styled(continuation_indent, Style::default()),
Span::styled(line_text.clone(), value_style),
]));
}
}
lines
}
}
pub fn render_end(width: usize) -> Line<'static> {
let border_style = Style::default().fg(Color::DarkGray);
let border_char = "\u{2500}";
let bottom_border = border_char.repeat(width);
Line::from(vec![Span::styled(bottom_border, border_style)])
}
fn wrap_text(text: &str, width: usize) -> Vec<String> {
if width == 0 || text.is_empty() {
return vec![text.to_string()];
}
let mut lines = Vec::new();
let mut current_line = String::new();
let mut current_width = 0;
for word in text.split_whitespace() {
let word_width = word.chars().count();
if current_width == 0 {
current_line = word.to_string();
current_width = word_width;
} else if current_width + 1 + word_width <= width {
current_line.push(' ');
current_line.push_str(word);
current_width += 1 + word_width;
} else {
lines.push(current_line);
current_line = word.to_string();
current_width = word_width;
}
}
if !current_line.is_empty() {
lines.push(current_line);
}
if lines.is_empty() {
lines.push(String::new());
}
lines
}