217 lines
5.2 KiB
Rust
217 lines
5.2 KiB
Rust
use maud::{Markup, Render, html};
|
|
|
|
use crate::ui::UIWidget;
|
|
|
|
use super::{div::Div, space::ScreenValue};
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn Table<T: UIWidget + 'static + Clone>(inner: Vec<Vec<T>>) -> TableWidget {
|
|
let inner = Div().vanish().push_for_each(&inner, |row| {
|
|
TableRow(
|
|
Div()
|
|
.vanish()
|
|
.push_for_each(&row, |col| TableData(col.clone())),
|
|
)
|
|
});
|
|
|
|
TableWidget(Box::new(inner), Vec::new(), None, None)
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn TableRaw<T: UIWidget + 'static + Clone>(inner: T) -> TableWidget {
|
|
TableWidget(Box::new(inner), Vec::new(), None, None)
|
|
}
|
|
|
|
pub struct TableWidget(
|
|
Box<dyn UIWidget>,
|
|
Vec<String>,
|
|
Option<Box<dyn UIWidget>>,
|
|
Option<Caption>,
|
|
);
|
|
|
|
impl TableWidget {
|
|
pub fn header<T: UIWidget + 'static>(mut self, header: T) -> Self {
|
|
self.2 = Some(Box::new(header));
|
|
self
|
|
}
|
|
|
|
pub fn caption(mut self, caption: Caption) -> Self {
|
|
self.3 = Some(caption);
|
|
self
|
|
}
|
|
|
|
pub fn border_collapse(mut self) -> Self {
|
|
self.1.push("border-collapse".to_string());
|
|
self
|
|
}
|
|
|
|
pub fn border_seperate(mut self) -> Self {
|
|
self.1.push("border-separate".to_string());
|
|
self
|
|
}
|
|
|
|
pub fn border_spacing(mut self, spacing: ScreenValue) -> Self {
|
|
self.1
|
|
.push(format!("border-spacing-{}", spacing.to_value()));
|
|
self
|
|
}
|
|
|
|
pub fn border_spacing_x(mut self, spacing: ScreenValue) -> Self {
|
|
self.1
|
|
.push(format!("border-spacing-x-{}", spacing.to_value()));
|
|
self
|
|
}
|
|
|
|
pub fn border_spacing_y(mut self, spacing: ScreenValue) -> Self {
|
|
self.1
|
|
.push(format!("border-spacing-y-{}", spacing.to_value()));
|
|
self
|
|
}
|
|
|
|
pub fn layout_fixed(mut self) -> Self {
|
|
self.1.push("table-fixed".to_string());
|
|
self
|
|
}
|
|
|
|
pub fn layout_auto(mut self) -> Self {
|
|
self.1.push("table-auto".to_string());
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Render for TableWidget {
|
|
fn render(&self) -> maud::Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for TableWidget {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
self.1.clone()
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
self.base_class()
|
|
}
|
|
|
|
fn render_with_class(&self, class: &str) -> maud::Markup {
|
|
html! {
|
|
table class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
@if let Some(caption) = &self.3 {
|
|
(caption)
|
|
}
|
|
|
|
@if let Some(header) = &self.2 {
|
|
thead {
|
|
(header)
|
|
};
|
|
};
|
|
|
|
(self.0.as_ref())
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Caption(Box<dyn UIWidget>, bool);
|
|
|
|
impl Caption {
|
|
#[allow(non_snake_case)]
|
|
pub fn Top<T: UIWidget + 'static>(inner: T) -> Self {
|
|
Self(Box::new(inner), true)
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn Bottom<T: UIWidget + 'static>(inner: T) -> Self {
|
|
Self(Box::new(inner), false)
|
|
}
|
|
}
|
|
|
|
impl Render for Caption {
|
|
fn render(&self) -> maud::Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for Caption {
|
|
fn can_inherit(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
if self.1 {
|
|
vec!["caption-top".to_string()]
|
|
} else {
|
|
vec!["caption-bottom".to_string()]
|
|
}
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
self.base_class()
|
|
}
|
|
|
|
fn render_with_class(&self, _: &str) -> maud::Markup {
|
|
html! {
|
|
caption class=(self.base_class().join(" ")) {
|
|
(self.0.as_ref())
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! element_widget {
|
|
($name:ident, $widget:ident, $element:ident) => {
|
|
#[allow(non_snake_case)]
|
|
pub fn $name<T: UIWidget + 'static>(inner: T) -> $widget {
|
|
$widget(Box::new(inner))
|
|
}
|
|
|
|
pub struct $widget(Box<dyn UIWidget>);
|
|
|
|
impl Render for $widget {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for $widget {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
Vec::new()
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
let mut c = self.base_class();
|
|
c.extend_from_slice(&self.0.extended_class());
|
|
c
|
|
}
|
|
|
|
fn render_with_class(&self, class: &str) -> Markup {
|
|
html! {
|
|
$element class=(class) {
|
|
(self.0.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
element_widget!(TableRow, TableRowWidget, tr);
|
|
element_widget!(TableHead, TableHeadWidget, th);
|
|
element_widget!(TableData, TableDataWidget, td);
|
|
element_widget!(Header, HeaderWidget, header);
|
|
|
|
// https://flowbite.com/docs/components/tables/
|
|
// TODO : tables
|
|
// table options
|
|
// wrap data to table (crud)
|
|
|
|
// TODO: TABLE https://flowbite.com/docs/components/pagination/#table-data-pagination
|