diff --git a/default_environment/stylesheet/main.css b/default_environment/stylesheet/main.css index b648058..b7af2a4 100644 --- a/default_environment/stylesheet/main.css +++ b/default_environment/stylesheet/main.css @@ -14,6 +14,10 @@ --src-block-language-background: #84828f; --quote-block-border-color: #84828f; + + --table-border-color: #6a687a; + --table-odd-background-color: #0a0a0a; + --table-even-background-color: #141414; } body { @@ -184,4 +188,37 @@ body { } } } + + .org_table { + table-layout: fixed; + border-collapse: collapse; + border: 1px solid var(--table-border-color); + > tbody { + border-width: 1px 0; + border-style: solid; + border-color: var(--table-border-color); + > tr { + > td { + padding: 0.2rem; + } + } + > tr:nth-child(odd) { + background-color: var(--table-odd-background-color); + } + > tr:nth-child(even) { + background-color: var(--table-even-background-color); + } + } + > thead { + border-width: 1px 0; + border-style: solid; + border-color: var(--table-border-color); + > tr { + > th { + padding: 0.2rem; + font-weight: 600; + } + } + } + } } diff --git a/default_environment/templates/html/table.dust b/default_environment/templates/html/table.dust index a77e7c3..8995220 100644 --- a/default_environment/templates/html/table.dust +++ b/default_environment/templates/html/table.dust @@ -1 +1,5 @@ -{#.children}{>table_row/}{/.children}
+{#.children}{@select key=.type} + {@eq value="head"}{>table_head/}{/eq} + {@eq value="body"}{>table_body/}{/eq} + {@none}{!TODO: make this panic!}ERROR: Unrecognized type {.type}.{/none} +{/select}{/.children}
diff --git a/default_environment/templates/html/table_body.dust b/default_environment/templates/html/table_body.dust new file mode 100644 index 0000000..1044fa4 --- /dev/null +++ b/default_environment/templates/html/table_body.dust @@ -0,0 +1 @@ +{#.children}{>table_row/}{/.children} diff --git a/default_environment/templates/html/table_head.dust b/default_environment/templates/html/table_head.dust new file mode 100644 index 0000000..8a028de --- /dev/null +++ b/default_environment/templates/html/table_head.dust @@ -0,0 +1 @@ +{#.children}{>table_head_row/}{/.children} diff --git a/default_environment/templates/html/table_head_cell.dust b/default_environment/templates/html/table_head_cell.dust new file mode 100644 index 0000000..f58637b --- /dev/null +++ b/default_environment/templates/html/table_head_cell.dust @@ -0,0 +1 @@ +{#.children}{>object/}{/.children} diff --git a/default_environment/templates/html/table_head_row.dust b/default_environment/templates/html/table_head_row.dust new file mode 100644 index 0000000..957a659 --- /dev/null +++ b/default_environment/templates/html/table_head_row.dust @@ -0,0 +1 @@ +{#.children}{>table_head_cell/}{/.children} diff --git a/src/context/mod.rs b/src/context/mod.rs index adff5cf..8594f5d 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -59,6 +59,7 @@ mod subscript; mod superscript; mod table; mod table_cell; +mod table_group; mod table_row; mod target; mod timestamp; diff --git a/src/context/table.rs b/src/context/table.rs index 045d7a6..d5cf721 100644 --- a/src/context/table.rs +++ b/src/context/table.rs @@ -1,8 +1,10 @@ use serde::Serialize; use super::render_context::RenderContext; +use super::table_group::RenderTableGroup; use crate::error::CustomError; use crate::intermediate::ITable; +use crate::intermediate::ITableGroup; use super::macros::render; use super::table_row::RenderTableRow; @@ -11,15 +13,29 @@ use super::table_row::RenderTableRow; #[serde(tag = "type")] #[serde(rename = "table")] pub(crate) struct RenderTable { - children: Vec, + children: Vec, post_blank: organic::types::PostBlank, } render!(RenderTable, ITable, original, render_context, { let children = { let mut ret = Vec::new(); - for obj in original.children.iter() { - ret.push(RenderTableRow::new(render_context.clone(), obj)?); + for group in original.children.iter() { + let mut rows = Vec::new(); + match group { + ITableGroup::Head(irows) => { + for obj in irows { + rows.push(RenderTableRow::new(render_context.clone(), obj)?); + } + ret.push(RenderTableGroup::Head { children: rows }); + } + ITableGroup::Body(irows) => { + for obj in irows { + rows.push(RenderTableRow::new(render_context.clone(), obj)?); + } + ret.push(RenderTableGroup::Body { children: rows }); + } + } } ret }; diff --git a/src/context/table_group.rs b/src/context/table_group.rs new file mode 100644 index 0000000..bc2960b --- /dev/null +++ b/src/context/table_group.rs @@ -0,0 +1,12 @@ +use super::table_row::RenderTableRow; +use serde::Serialize; + +#[derive(Debug, Serialize)] +#[serde(tag = "type")] +pub(crate) enum RenderTableGroup { + #[serde(rename = "head")] + Head { children: Vec }, + + #[serde(rename = "body")] + Body { children: Vec }, +} diff --git a/src/intermediate/mod.rs b/src/intermediate/mod.rs index 3516d15..2d6e34f 100644 --- a/src/intermediate/mod.rs +++ b/src/intermediate/mod.rs @@ -59,6 +59,7 @@ mod subscript; mod superscript; mod table; mod table_cell; +mod table_group; mod table_row; mod target; mod timestamp; @@ -126,6 +127,7 @@ pub(crate) use subscript::ISubscript; pub(crate) use superscript::ISuperscript; pub(crate) use table::ITable; pub(crate) use table_cell::ITableCell; +pub(crate) use table_group::ITableGroup; pub(crate) use table_row::ITableRow; pub(crate) use target::ITarget; pub(crate) use timestamp::ITimestamp; diff --git a/src/intermediate/table.rs b/src/intermediate/table.rs index c52977e..85ad76b 100644 --- a/src/intermediate/table.rs +++ b/src/intermediate/table.rs @@ -1,11 +1,12 @@ use super::macros::intermediate; use super::table_row::ITableRow; use crate::error::CustomError; +use crate::intermediate::table_group::ITableGroup; use organic::types::StandardProperties; #[derive(Debug, Clone)] pub(crate) struct ITable { - pub(crate) children: Vec, + pub(crate) children: Vec, pub(crate) post_blank: organic::types::PostBlank, } @@ -15,10 +16,40 @@ intermediate!( original, intermediate_context, { - let children = { + // Separate groups by lines, multiple contiguous lines are the same as one. + // If there is only one group, it is a tbody. + // If there are more than one group, the first is thead and the rest are tbody. + + let sections = group_into_sections(&original.children); + + let children = if sections.len() == 1 { + // If there is only one section, then it is a body. let mut ret = Vec::new(); - for obj in original.children.iter() { - ret.push(ITableRow::new(intermediate_context.clone(), obj).await?); + for group in sections.into_iter() { + let mut rows = Vec::new(); + for obj in group.into_iter() { + rows.push(ITableRow::new(intermediate_context.clone(), obj).await?) + } + ret.push(ITableGroup::Body(rows)); + } + ret + } else { + // If there are more than one section, the first is a head and the rest are body. + let mut ret = Vec::new(); + let mut sections = sections.into_iter(); + if let Some(group) = sections.next() { + let mut rows = Vec::new(); + for obj in group.into_iter() { + rows.push(ITableRow::new(intermediate_context.clone(), obj).await?) + } + ret.push(ITableGroup::Head(rows)); + } + for group in sections { + let mut rows = Vec::new(); + for obj in group.into_iter() { + rows.push(ITableRow::new(intermediate_context.clone(), obj).await?) + } + ret.push(ITableGroup::Body(rows)); } ret }; @@ -29,3 +60,41 @@ intermediate!( }) } ); + +enum GroupIntoSectionsState<'orig, 'parse> { + NonSection, + Section(Vec<&'orig organic::types::TableRow<'parse>>), +} + +fn group_into_sections<'orig, 'parse>( + rows: &'orig Vec>, +) -> Vec>> { + let mut sections = Vec::new(); + let mut rows = rows.into_iter(); + let mut state = GroupIntoSectionsState::NonSection; + loop { + state = match (state, rows.next()) { + (GroupIntoSectionsState::NonSection, None) => break, + (GroupIntoSectionsState::NonSection, Some(row)) if row.children.is_empty() => { + GroupIntoSectionsState::NonSection + } + (GroupIntoSectionsState::NonSection, Some(row)) => { + GroupIntoSectionsState::Section(vec![row]) + } + (GroupIntoSectionsState::Section(section), None) => { + sections.push(section); + break; + } + (GroupIntoSectionsState::Section(section), Some(row)) if row.children.is_empty() => { + sections.push(section); + GroupIntoSectionsState::NonSection + } + (GroupIntoSectionsState::Section(mut section), Some(row)) => { + section.push(row); + GroupIntoSectionsState::Section(section) + } + } + } + + sections +} diff --git a/src/intermediate/table_group.rs b/src/intermediate/table_group.rs new file mode 100644 index 0000000..5822fb2 --- /dev/null +++ b/src/intermediate/table_group.rs @@ -0,0 +1,7 @@ +use super::ITableRow; + +#[derive(Debug, Clone)] +pub(crate) enum ITableGroup { + Head(Vec), + Body(Vec), +}