use super::hooks::{collapse_tag_adjacent_newlines, escape_attr, RenderHooks};
use super::node::Block;
use super::shortcode::GridShortcode;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GridParts {
pub open_tag: String,
pub cells: Vec<GridCellParts>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GridCellParts {
pub inner: String,
pub carded: bool,
pub cover_color: Option<String>,
}
impl GridCellParts {
pub fn to_html(&self) -> String {
if self.carded {
let color = self
.cover_color
.as_deref()
.map(|c| {
format!(
r#" data-cover-color style="--moss-cover-color: {}""#,
escape_attr(c)
)
})
.unwrap_or_default();
format!(
r#"<div class="moss-grid-card"{}>{}</div>"#,
color, self.inner
)
} else {
self.inner.clone()
}
}
pub fn final_markup(html: String) -> Self {
Self {
inner: html,
carded: false,
cover_color: None,
}
}
}
impl GridParts {
pub fn to_html(&self) -> String {
let cells: Vec<String> = self.cells.iter().map(GridCellParts::to_html).collect();
Self::assemble(&self.open_tag, &cells)
}
pub fn assemble(open_tag: &str, cells: &[String]) -> String {
let mut out = String::with_capacity(open_tag.len() + 8);
out.push_str(open_tag);
out.push_str(&cells.join("\n"));
out.push_str("</div>");
out
}
}
pub fn render_grid_parts<H: RenderHooks + ?Sized>(
hooks: &H,
args: &GridShortcode,
source_line: Option<usize>,
) -> GridParts {
let mut open_tag = String::new();
{
let mut class_attr = String::from("moss-grid");
if !args.classes.is_empty() {
class_attr.push(' ');
class_attr.push_str(&args.classes);
}
open_tag.push_str(r#"<div class=""#);
open_tag.push_str(&escape_attr(&class_attr));
open_tag.push_str(r#"" data-columns=""#);
open_tag.push_str(&args.columns.to_string());
open_tag.push('"');
if let Some(r) = &args.ratio {
let cols = r
.split(':')
.map(|n| format!("minmax(0, {}fr)", n.trim()))
.collect::<Vec<_>>()
.join(" ");
open_tag.push_str(r#" style="--moss-grid-ratio:"#);
open_tag.push_str(&cols);
open_tag.push('"');
}
if let Some(w) = &args.width {
open_tag.push_str(r#" data-width=""#);
open_tag.push_str(w);
open_tag.push('"');
}
if let Some(n) = source_line {
open_tag.push_str(r#" data-source-range=""#);
open_tag.push_str(&n.to_string());
open_tag.push('-');
open_tag.push_str(&n.to_string());
open_tag.push('"');
}
open_tag.push('>');
}
let mut cells: Vec<GridCellParts> = Vec::with_capacity(args.cells.len());
hooks.begin_grid_cells(args.columns, args.width.as_deref());
for cell_blocks in &args.cells {
let mut cell_html = String::new();
super::render::render_blocks(hooks, &mut cell_html, cell_blocks);
let collapsed = collapse_tag_adjacent_newlines(&cell_html);
cells.push(GridCellParts {
inner: collapsed.trim().to_string(),
carded: !matches!(cell_blocks.as_slice(), [Block::LinkCard { .. }]),
cover_color: None,
});
}
hooks.end_grid_cells();
GridParts { open_tag, cells }
}