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),
+}