283 lines
7.7 KiB
Rust
283 lines
7.7 KiB
Rust
use crate::ui::UIWidget;
|
|
use maud::{Markup, Render, html};
|
|
|
|
macro_rules! string_class_widget {
|
|
($name:ident) => {
|
|
pub struct $name(Box<dyn UIWidget>, String);
|
|
|
|
impl Render for $name {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for $name {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
vec![self.1.clone()]
|
|
}
|
|
|
|
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 {
|
|
if self.0.as_ref().can_inherit() {
|
|
self.0
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.0.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
macro_rules! constructor {
|
|
($name:ident, $class:literal) => {
|
|
#[allow(non_snake_case)]
|
|
pub fn $name<T: UIWidget + 'static>(inner: T) -> Self {
|
|
Self(Box::new(inner), $class.to_string())
|
|
}
|
|
};
|
|
}
|
|
|
|
pub enum BreakValue {
|
|
Auto,
|
|
Avoid,
|
|
All,
|
|
AvoidPage,
|
|
Page,
|
|
Left,
|
|
Right,
|
|
Column,
|
|
}
|
|
|
|
impl BreakValue {
|
|
pub const fn to_value(&self) -> &str {
|
|
match self {
|
|
BreakValue::Auto => "auto",
|
|
BreakValue::Avoid => "avoid",
|
|
BreakValue::All => "all",
|
|
BreakValue::AvoidPage => "break-page",
|
|
BreakValue::Page => "page",
|
|
BreakValue::Left => "left",
|
|
BreakValue::Right => "right",
|
|
BreakValue::Column => "column",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn BreakAfter<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
|
|
BreakWidget(Box::new(inner), false, value)
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn BreakBefore<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
|
|
BreakWidget(Box::new(inner), true, value)
|
|
}
|
|
|
|
pub struct BreakWidget(Box<dyn UIWidget>, bool, BreakValue);
|
|
|
|
impl Render for BreakWidget {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for BreakWidget {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
if self.1 {
|
|
vec![format!("break-before-{}", self.2.to_value())]
|
|
} else {
|
|
vec![format!("break-after-{}", self.2.to_value())]
|
|
}
|
|
}
|
|
|
|
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 {
|
|
if self.0.as_ref().can_inherit() {
|
|
self.0
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.0.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum BreakInsideValue {
|
|
Auto,
|
|
Avoid,
|
|
AvoidPage,
|
|
AvoidColumn,
|
|
}
|
|
|
|
impl BreakInsideValue {
|
|
pub const fn to_value(&self) -> &str {
|
|
match self {
|
|
BreakInsideValue::Auto => "break-inside-auto",
|
|
BreakInsideValue::Avoid => "break-inside-avoid",
|
|
BreakInsideValue::AvoidPage => "break-inside-avoid-page",
|
|
BreakInsideValue::AvoidColumn => "break-inside-avoid-column",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn BreakInside<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
|
|
BreakWidget(Box::new(inner), true, value)
|
|
}
|
|
|
|
pub struct BreakInsideWidget(Box<dyn UIWidget>, BreakValue);
|
|
|
|
impl Render for BreakInsideWidget {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for BreakInsideWidget {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
vec![self.1.to_value().to_string()]
|
|
}
|
|
|
|
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 {
|
|
if self.0.as_ref().can_inherit() {
|
|
self.0
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.0.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
string_class_widget!(BoxDecorationBreak);
|
|
|
|
impl BoxDecorationBreak {
|
|
constructor!(Clone, "box-decoration-clone");
|
|
constructor!(Slice, "box-decoration-slice");
|
|
}
|
|
|
|
string_class_widget!(BoxSizing);
|
|
|
|
impl BoxSizing {
|
|
constructor!(Border, "box-border");
|
|
constructor!(Content, "box-content");
|
|
}
|
|
|
|
string_class_widget!(Display);
|
|
|
|
impl Display {
|
|
constructor!(Block, "block");
|
|
constructor!(InlineBlock, "inline-block");
|
|
constructor!(Inline, "inline");
|
|
constructor!(Flex, "flex");
|
|
constructor!(InlineFlex, "inline-flex");
|
|
constructor!(Table, "table");
|
|
constructor!(InlineTable, "inline-table");
|
|
constructor!(TableCaption, "table-caption");
|
|
constructor!(TableCell, "table-cell");
|
|
constructor!(TableColumn, "table-column");
|
|
constructor!(TableColumnGroup, "table-column-group");
|
|
constructor!(TableFooterGroup, "table-footer-group");
|
|
constructor!(TableHeaderGroup, "table-header-group");
|
|
constructor!(TableRowGroup, "table-row-group");
|
|
constructor!(TableRow, "table-row");
|
|
constructor!(FlowRoot, "flow-root");
|
|
constructor!(Grid, "grid");
|
|
constructor!(InlineGrid, "inline-grid");
|
|
constructor!(Contents, "contents");
|
|
constructor!(ListItem, "list-item");
|
|
constructor!(Hidden, "hidden");
|
|
}
|
|
|
|
string_class_widget!(Float);
|
|
|
|
impl Float {
|
|
constructor!(Start, "float-start");
|
|
constructor!(End, "float-end");
|
|
constructor!(Left, "float-left");
|
|
constructor!(Right, "float-right");
|
|
constructor!(None, "float-none");
|
|
}
|
|
|
|
string_class_widget!(Clear);
|
|
|
|
impl Clear {
|
|
constructor!(Start, "clear-start");
|
|
constructor!(End, "clear-end");
|
|
constructor!(Left, "clear-left");
|
|
constructor!(Right, "clear-right");
|
|
constructor!(Both, "clear-both");
|
|
constructor!(None, "clear-none");
|
|
}
|
|
|
|
string_class_widget!(ObjectFit);
|
|
|
|
impl ObjectFit {
|
|
constructor!(Contain, "object-contain");
|
|
constructor!(Cover, "object-cover");
|
|
constructor!(Fill, "object-fill");
|
|
constructor!(None, "object-none");
|
|
constructor!(ScaleDown, "object-scale-down");
|
|
}
|
|
|
|
string_class_widget!(Overflow);
|
|
|
|
impl Overflow {
|
|
constructor!(Auto, "overflow-auto");
|
|
constructor!(Hidden, "overflow-hidden");
|
|
constructor!(Clip, "overflow-clip");
|
|
constructor!(Visible, "overflow-visible");
|
|
constructor!(Scroll, "overflow-scroll");
|
|
constructor!(XAuto, "overflow-x-auto");
|
|
constructor!(YAuto, "overflow-y-auto");
|
|
constructor!(XHidden, "overflow-x-hidden");
|
|
constructor!(YHidden, "overflow-y-hidden");
|
|
constructor!(XClip, "overflow-x-clip");
|
|
constructor!(YClip, "overflow-y-clip");
|
|
constructor!(XVisible, "overflow-x-visible");
|
|
constructor!(YVisible, "overflow-y-visible");
|
|
constructor!(XScroll, "overflow-x-scroll");
|
|
constructor!(YScroll, "overflow-y-scroll");
|
|
}
|