update
This commit is contained in:
parent
f3a85de02e
commit
86f61ff3f6
15 changed files with 918 additions and 41 deletions
|
@ -15,12 +15,16 @@ pub async fn index_page(ctx: RequestContext) -> StringResponse {
|
|||
h1 { "Hello World!" };
|
||||
|
||||
(Hover(
|
||||
Padding(Text("").color(&Gray::_400)).x(ScreenValue::_10),
|
||||
Link("/test", Text("Hello")).hx_get("/test").hx_get("/test").hx_trigger(
|
||||
Event::on_load().delay("2s")
|
||||
.and(Event::on_revealed())
|
||||
Cursor::NorthEastResize.on(
|
||||
Padding(Text("").color(&Gray::_400)).x(ScreenValue::_10)
|
||||
)
|
||||
))
|
||||
).on(
|
||||
Link("/test", Text("Hello")).hx_get("/test").hx_get("/test").hx_trigger(
|
||||
Event::on_load().delay("2s")
|
||||
.and(Event::on_revealed())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(content)
|
||||
|
||||
|
|
11
src/htmx.rs
11
src/htmx.rs
|
@ -1,8 +1,11 @@
|
|||
use crate::request::assets::DataResponse;
|
||||
use rocket::get;
|
||||
|
||||
use crate::request::{StringResponse, respond_script};
|
||||
|
||||
#[get("/assets/htmx.min.js")]
|
||||
pub fn htmx_script_route() -> StringResponse {
|
||||
respond_script(include_str!("htmx.min.js").to_string())
|
||||
pub fn htmx_script_route() -> DataResponse {
|
||||
DataResponse::new(
|
||||
include_str!("htmx.min.js").as_bytes().to_vec(),
|
||||
"application/javascript".to_string(),
|
||||
Some(60 * 60 * 24 * 3),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,17 +15,18 @@ pub mod components;
|
|||
// Preludes
|
||||
pub mod prelude {
|
||||
pub use super::color::*;
|
||||
pub use super::primitives::Nothing;
|
||||
pub use super::primitives::Context;
|
||||
pub use super::primitives::Nothing;
|
||||
pub use super::primitives::Side;
|
||||
pub use super::primitives::Size;
|
||||
pub use super::primitives::aspect::Aspect;
|
||||
pub use super::primitives::background::Background;
|
||||
pub use super::primitives::container::Container;
|
||||
pub use super::primitives::cursor::Cursor;
|
||||
pub use super::primitives::div::Div;
|
||||
pub use super::primitives::flex::{Flex, Justify};
|
||||
pub use super::primitives::header::Header;
|
||||
pub use super::primitives::height::Height;
|
||||
pub use super::primitives::height::HeightWidget;
|
||||
pub use super::primitives::image::Image;
|
||||
pub use super::primitives::link::Link;
|
||||
pub use super::primitives::margin::Margin;
|
||||
|
@ -36,7 +37,9 @@ pub mod prelude {
|
|||
pub use super::primitives::sized::Sized;
|
||||
pub use super::primitives::space::{ScreenValue, SpaceBetween};
|
||||
pub use super::primitives::text::{Paragraph, Span, Text};
|
||||
pub use super::primitives::visibility::Visibility;
|
||||
pub use super::primitives::width::Width;
|
||||
pub use super::primitives::zindex::ZIndex;
|
||||
pub use super::wrapper::Hover;
|
||||
}
|
||||
|
||||
|
|
124
src/ui/primitives/cursor.rs
Normal file
124
src/ui/primitives/cursor.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use crate::ui::UIWidget;
|
||||
use maud::{Markup, Render, html};
|
||||
|
||||
pub enum Cursor {
|
||||
Auto,
|
||||
Default,
|
||||
Pointer,
|
||||
Wait,
|
||||
Text,
|
||||
Move,
|
||||
Help,
|
||||
NotAllowed,
|
||||
None,
|
||||
ContextMenu,
|
||||
Progress,
|
||||
Cell,
|
||||
Crosshair,
|
||||
VerticalText,
|
||||
Alias,
|
||||
Copy,
|
||||
NoDrop,
|
||||
Grab,
|
||||
Grabbing,
|
||||
AllScroll,
|
||||
ColResize,
|
||||
RowResize,
|
||||
NorthResize,
|
||||
EastResize,
|
||||
SouthResize,
|
||||
WestResize,
|
||||
NorthEastResize,
|
||||
NorthWestResize,
|
||||
SouthEastResize,
|
||||
SouthWestResize,
|
||||
EastWestResize,
|
||||
NorthSouthResize,
|
||||
NorthEastSouthWestResize,
|
||||
NorthWestSouthEastResize,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
pub fn on<T: UIWidget + 'static>(self, inner: T) -> CursorWidget {
|
||||
CursorWidget(self, Box::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CursorWidget(Cursor, Box<dyn UIWidget>);
|
||||
|
||||
impl Render for CursorWidget {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for CursorWidget {
|
||||
fn can_inherit(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
let class = match self.0 {
|
||||
Cursor::Auto => "cursor-auto",
|
||||
Cursor::Default => "cursor-default",
|
||||
Cursor::Pointer => "cursor-pointer",
|
||||
Cursor::Wait => "cursor-wait",
|
||||
Cursor::Text => "cursor-text",
|
||||
Cursor::Move => "cursor-move",
|
||||
Cursor::Help => "cursor-help",
|
||||
Cursor::NotAllowed => "cursor-not-allowed",
|
||||
Cursor::None => "cursor-none",
|
||||
Cursor::ContextMenu => "cursor-context-menu",
|
||||
Cursor::Progress => "cursor-progress",
|
||||
Cursor::Cell => "cursor-cell",
|
||||
Cursor::Crosshair => "cursor-crosshair",
|
||||
Cursor::VerticalText => "cursor-vertical-text",
|
||||
Cursor::Alias => "cursor-alias",
|
||||
Cursor::Copy => "cursor-copy",
|
||||
Cursor::NoDrop => "cursor-no-drop",
|
||||
Cursor::Grab => "cursor-grab",
|
||||
Cursor::Grabbing => "cursor-grabbing",
|
||||
Cursor::AllScroll => "cursor-all-scroll",
|
||||
Cursor::ColResize => "cursor-col-resize",
|
||||
Cursor::RowResize => "cursor-row-resize",
|
||||
Cursor::NorthResize => "cursor-n-resize",
|
||||
Cursor::EastResize => "cursor-e-resize",
|
||||
Cursor::SouthResize => "cursor-s-resize",
|
||||
Cursor::WestResize => "cursor-w-resize",
|
||||
Cursor::NorthEastResize => "cursor-ne-resize",
|
||||
Cursor::NorthWestResize => "cursor-nw-resize",
|
||||
Cursor::SouthEastResize => "cursor-se-resize",
|
||||
Cursor::SouthWestResize => "cursor-sw-resize",
|
||||
Cursor::EastWestResize => "cursor-ew-resize",
|
||||
Cursor::NorthSouthResize => "cursor-ns-resize",
|
||||
Cursor::NorthEastSouthWestResize => "cursor-nesw-resize",
|
||||
Cursor::NorthWestSouthEastResize => "cursor-nwse-resize",
|
||||
Cursor::ZoomIn => "cursor-zoom-in",
|
||||
Cursor::ZoomOut => "cursor-zoom-out",
|
||||
};
|
||||
|
||||
vec![class.to_string()]
|
||||
}
|
||||
|
||||
fn extended_class(&self) -> Vec<String> {
|
||||
let mut c = self.base_class();
|
||||
c.extend_from_slice(&self.1.extended_class());
|
||||
c
|
||||
}
|
||||
|
||||
fn render_with_class(&self, class: &str) -> Markup {
|
||||
let inner = &self.1;
|
||||
|
||||
if inner.can_inherit() {
|
||||
inner.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
||||
} else {
|
||||
html! {
|
||||
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
||||
(inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,22 @@
|
|||
use crate::ui::UIWidget;
|
||||
use maud::{Markup, Render, html};
|
||||
|
||||
use super::space::{Fraction, ScreenValue};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Flex<T: UIWidget + 'static>(inner: T) -> FlexWidget {
|
||||
FlexWidget(Box::new(inner), vec![], false)
|
||||
}
|
||||
|
||||
pub enum Justify {
|
||||
Normal,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
Between,
|
||||
Around,
|
||||
Evenly,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
pub struct FlexWidget(Box<dyn UIWidget>, Vec<String>, bool);
|
||||
|
@ -33,11 +41,29 @@ impl FlexWidget {
|
|||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn direction(mut self, direction: Direction) -> Self {
|
||||
self.1.push(format!("flex-{}", direction.to_value()));
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn wrap(mut self, wrap: Wrap) -> Self {
|
||||
self.1.push(format!("flex-{}", wrap.to_value()));
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn justify(mut self, value: Justify) -> Self {
|
||||
let class = match value {
|
||||
Justify::Center => "justify-center".to_owned(),
|
||||
Justify::Between => "justify-between".to_owned(),
|
||||
Justify::Center => "justify-center".to_string(),
|
||||
Justify::Between => "justify-between".to_string(),
|
||||
Justify::Normal => "justify-normal".to_string(),
|
||||
Justify::Start => "justify-start".to_string(),
|
||||
Justify::End => "justify-end".to_string(),
|
||||
Justify::Around => "justify-around".to_string(),
|
||||
Justify::Evenly => "justify-evenly".to_string(),
|
||||
Justify::Stretch => "justify-stretch".to_string(),
|
||||
};
|
||||
|
||||
self.1.push(class);
|
||||
|
@ -51,10 +77,56 @@ impl FlexWidget {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gap(mut self, amount: u32) -> Self {
|
||||
self.1.push(format!("gap-{amount}"));
|
||||
pub fn gap(mut self, amount: ScreenValue) -> Self {
|
||||
self.1.push(format!("gap-{}", amount.to_value()));
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gap_x(mut self, amount: ScreenValue) -> Self {
|
||||
self.1.push(format!("gap-x-{}", amount.to_value()));
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gap_y(mut self, amount: ScreenValue) -> Self {
|
||||
self.1.push(format!("gap-y-{}", amount.to_value()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Direction {
|
||||
Row,
|
||||
RowReverse,
|
||||
Column,
|
||||
ColumnReverse,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub const fn to_value(&self) -> &str {
|
||||
match self {
|
||||
Direction::Row => "row",
|
||||
Direction::RowReverse => "row-reverse",
|
||||
Direction::Column => "col",
|
||||
Direction::ColumnReverse => "col-reverse",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Wrap {
|
||||
Wrap,
|
||||
Reverse,
|
||||
NoWrap,
|
||||
}
|
||||
|
||||
impl Wrap {
|
||||
pub const fn to_value(&self) -> &str {
|
||||
match self {
|
||||
Wrap::Wrap => "wrap",
|
||||
Wrap::Reverse => "wrap-reverse",
|
||||
Wrap::NoWrap => "nowrap",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for FlexWidget {
|
||||
|
@ -88,3 +160,242 @@ impl UIWidget for FlexWidget {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Either<R, L> {
|
||||
Right(R),
|
||||
Left(L),
|
||||
}
|
||||
|
||||
impl<R, L> Either<R, L> {
|
||||
pub fn map<X, Y, U>(self, lf: X, rf: Y) -> U
|
||||
where
|
||||
X: FnOnce(L) -> U,
|
||||
Y: FnOnce(R) -> U,
|
||||
{
|
||||
match self {
|
||||
Either::Right(r) => rf(r),
|
||||
Either::Left(l) => lf(l),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ScreenValue> for Either<ScreenValue, Fraction> {
|
||||
fn from(value: ScreenValue) -> Self {
|
||||
Self::Right(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fraction> for Either<ScreenValue, Fraction> {
|
||||
fn from(value: Fraction) -> Self {
|
||||
Self::Left(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn FlexBasis<T: UIWidget + 'static>(
|
||||
inner: T,
|
||||
value: Either<ScreenValue, Fraction>,
|
||||
) -> FlexBasisWidget {
|
||||
FlexBasisWidget(Box::new(inner), value)
|
||||
}
|
||||
|
||||
pub struct FlexBasisWidget(Box<dyn UIWidget>, Either<ScreenValue, Fraction>);
|
||||
|
||||
impl Render for FlexBasisWidget {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for FlexBasisWidget {
|
||||
fn can_inherit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
vec![format!(
|
||||
"basis-{}",
|
||||
self.1
|
||||
.clone()
|
||||
.map(|x| x.to_value().to_string(), |x| x.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, _: &str) -> Markup {
|
||||
if self.0.as_ref().can_inherit() {
|
||||
self.0
|
||||
.as_ref()
|
||||
.render_with_class(&format!("{}", self.base_class().join(" ")))
|
||||
} else {
|
||||
html! {
|
||||
div class=(format!("{}", self.base_class().join(" "))) {
|
||||
(self.0.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn FlexGrow<T: UIWidget + 'static>(strategy: Strategy, inner: T) -> FlexGrowWidget {
|
||||
FlexGrowWidget(strategy, Box::new(inner))
|
||||
}
|
||||
|
||||
pub struct FlexGrowWidget(Strategy, Box<dyn UIWidget>);
|
||||
|
||||
impl Render for FlexGrowWidget {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for FlexGrowWidget {
|
||||
fn can_inherit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
vec![self.0.to_value().to_string()]
|
||||
}
|
||||
|
||||
fn extended_class(&self) -> Vec<String> {
|
||||
let mut c = self.base_class();
|
||||
c.extend_from_slice(&self.1.extended_class());
|
||||
c
|
||||
}
|
||||
|
||||
fn render_with_class(&self, _: &str) -> Markup {
|
||||
if self.1.as_ref().can_inherit() {
|
||||
self.1
|
||||
.as_ref()
|
||||
.render_with_class(&format!("{}", self.base_class().join(" ")))
|
||||
} else {
|
||||
html! {
|
||||
div class=(format!("{}", self.base_class().join(" "))) {
|
||||
(self.1.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Strategy {
|
||||
/// Allow a flex item to shrink but not grow, taking into account its initial size.
|
||||
Initial,
|
||||
/// Allow a flex item to grow and shrink as needed, ignoring its initial size.
|
||||
Expand,
|
||||
/// Allow a flex item to grow and shrink, taking into account its initial size.
|
||||
Auto,
|
||||
/// Prevent a flex item from growing or shrinking.
|
||||
None,
|
||||
/// Allow a flex item to grow to fill any available space.
|
||||
Grow,
|
||||
/// Prevent a flex item from growing.
|
||||
NoGrow,
|
||||
/// Allow a flex item to shrink if needed.
|
||||
Shrink,
|
||||
/// Prevent a flex item from shrinking.
|
||||
NoShrink,
|
||||
}
|
||||
|
||||
impl Strategy {
|
||||
pub fn to_value(&self) -> &str {
|
||||
match self {
|
||||
Self::Initial => "flex-initial",
|
||||
Self::Expand => "flex-1",
|
||||
Self::Auto => "flex-auto",
|
||||
Self::None => "flex-none",
|
||||
Self::Grow => "grow",
|
||||
Self::NoGrow => "grow-0",
|
||||
Self::Shrink => "shrink",
|
||||
Self::NoShrink => "shrink-0",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Order {
|
||||
_1,
|
||||
_2,
|
||||
_3,
|
||||
_4,
|
||||
_5,
|
||||
_6,
|
||||
_7,
|
||||
_8,
|
||||
_9,
|
||||
_10,
|
||||
_11,
|
||||
_12,
|
||||
First,
|
||||
Last,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Order {
|
||||
pub fn on<T: UIWidget + 'static>(self, inner: T) -> OrderWidget {
|
||||
OrderWidget(self, Box::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OrderWidget(Order, Box<dyn UIWidget>);
|
||||
|
||||
impl Render for OrderWidget {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for OrderWidget {
|
||||
fn can_inherit(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
let class = match self.0 {
|
||||
Order::_1 => "order-1",
|
||||
Order::_2 => "order-2",
|
||||
Order::_3 => "order-3",
|
||||
Order::_4 => "order-4",
|
||||
Order::_5 => "order-5",
|
||||
Order::_6 => "order-6",
|
||||
Order::_7 => "order-7",
|
||||
Order::_8 => "order-8",
|
||||
Order::_9 => "order-9",
|
||||
Order::_10 => "order-10",
|
||||
Order::_11 => "order-11",
|
||||
Order::_12 => "order-12",
|
||||
Order::First => "order-first",
|
||||
Order::Last => "order-last",
|
||||
Order::None => "order-none",
|
||||
};
|
||||
|
||||
vec![class.to_string()]
|
||||
}
|
||||
|
||||
fn extended_class(&self) -> Vec<String> {
|
||||
let mut c = self.base_class();
|
||||
c.extend_from_slice(&self.1.extended_class());
|
||||
c
|
||||
}
|
||||
|
||||
fn render_with_class(&self, class: &str) -> Markup {
|
||||
let inner = &self.1;
|
||||
|
||||
if inner.can_inherit() {
|
||||
inner.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
||||
} else {
|
||||
html! {
|
||||
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
||||
(inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,24 +4,44 @@ use maud::{Markup, Render, html};
|
|||
use super::space::ScreenValue;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Width<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> Height {
|
||||
Height(Box::new(inner), size)
|
||||
pub fn Height<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> HeightWidget {
|
||||
HeightWidget(Box::new(inner), size, 0)
|
||||
}
|
||||
|
||||
pub struct Height(Box<dyn UIWidget>, ScreenValue);
|
||||
#[allow(non_snake_case)]
|
||||
pub fn MinHeight<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> HeightWidget {
|
||||
HeightWidget(Box::new(inner), size, 1)
|
||||
}
|
||||
|
||||
impl Render for Height {
|
||||
#[allow(non_snake_case)]
|
||||
pub fn MaxHeight<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> HeightWidget {
|
||||
HeightWidget(Box::new(inner), size, 2)
|
||||
}
|
||||
|
||||
pub struct HeightWidget(Box<dyn UIWidget>, ScreenValue, u8);
|
||||
|
||||
impl Render for HeightWidget {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for Height {
|
||||
impl UIWidget for HeightWidget {
|
||||
fn can_inherit(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
match self.2 {
|
||||
1 => {
|
||||
return vec![format!("min-h-{}", self.1.to_value())];
|
||||
}
|
||||
2 => {
|
||||
return vec![format!("max-h-{}", self.1.to_value())];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
vec![format!("h-{}", self.1.to_value())]
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ impl LinkWidget {
|
|||
/// Enable HTMX link capabilities
|
||||
#[must_use]
|
||||
pub fn use_htmx(self) -> Self {
|
||||
// todo : investigate htmx attrs
|
||||
let url = self.1.clone();
|
||||
self.hx_get(&url)
|
||||
.hx_target(Selector::Query("#main_content".to_string()))
|
||||
|
|
|
@ -5,6 +5,7 @@ use super::UIWidget;
|
|||
pub mod aspect;
|
||||
pub mod background;
|
||||
pub mod container;
|
||||
pub mod cursor;
|
||||
pub mod div;
|
||||
pub mod flex;
|
||||
pub mod header;
|
||||
|
@ -19,7 +20,9 @@ pub mod shadow;
|
|||
pub mod sized;
|
||||
pub mod space;
|
||||
pub mod text;
|
||||
pub mod visibility;
|
||||
pub mod width;
|
||||
pub mod zindex;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[must_use]
|
||||
|
|
|
@ -31,10 +31,6 @@ impl Shadow {
|
|||
pub fn _2xl<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "2xl".to_owned())
|
||||
}
|
||||
|
||||
pub fn inner<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "inner".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Shadow {
|
||||
|
@ -76,3 +72,75 @@ impl UIWidget for Shadow {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DropShadow(Box<dyn UIWidget>, String);
|
||||
|
||||
impl DropShadow {
|
||||
pub fn small<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "sm".to_owned())
|
||||
}
|
||||
|
||||
pub fn regular<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), String::new())
|
||||
}
|
||||
|
||||
pub fn medium<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "md".to_owned())
|
||||
}
|
||||
|
||||
pub fn large<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "lg".to_owned())
|
||||
}
|
||||
|
||||
pub fn none<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "none".to_owned())
|
||||
}
|
||||
|
||||
pub fn xl<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "xl".to_owned())
|
||||
}
|
||||
|
||||
pub fn _2xl<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "2xl".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for DropShadow {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for DropShadow {
|
||||
fn can_inherit(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
if self.1.is_empty() {
|
||||
vec!["drop-shadow".to_string()]
|
||||
} else {
|
||||
vec![format!("drop-shadow-{}", self.1)]
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ impl UIWidget for SpaceBetweenWidget {
|
|||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ScreenValue {
|
||||
_0,
|
||||
_0p5,
|
||||
|
@ -165,6 +166,7 @@ impl ScreenValue {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Fraction {
|
||||
_1on2,
|
||||
_1on3,
|
||||
|
|
|
@ -8,8 +8,10 @@ pub fn Text(txt: &str) -> TextWidget {
|
|||
TextWidget {
|
||||
inner: None,
|
||||
txt: txt.to_string(),
|
||||
family: String::new(),
|
||||
font: String::new(),
|
||||
color: String::new(),
|
||||
style: Vec::new(),
|
||||
size: String::new(),
|
||||
span: false,
|
||||
}
|
||||
|
@ -21,8 +23,10 @@ pub fn Paragraph<T: UIWidget + 'static>(inner: T) -> TextWidget {
|
|||
TextWidget {
|
||||
inner: Some(Box::new(inner)),
|
||||
font: String::new(),
|
||||
family: String::new(),
|
||||
color: String::new(),
|
||||
txt: String::new(),
|
||||
style: Vec::new(),
|
||||
size: String::new(),
|
||||
span: false,
|
||||
}
|
||||
|
@ -35,7 +39,9 @@ pub fn Span(txt: &str) -> TextWidget {
|
|||
TextWidget {
|
||||
inner: None,
|
||||
txt: txt.to_string(),
|
||||
family: String::new(),
|
||||
font: String::new(),
|
||||
style: Vec::new(),
|
||||
color: String::new(),
|
||||
size: String::new(),
|
||||
span: true,
|
||||
|
@ -45,6 +51,8 @@ pub fn Span(txt: &str) -> TextWidget {
|
|||
pub struct TextWidget {
|
||||
inner: Option<Box<dyn UIWidget>>,
|
||||
txt: String,
|
||||
family: String,
|
||||
style: Vec<String>,
|
||||
font: String,
|
||||
color: String,
|
||||
size: String,
|
||||
|
@ -52,6 +60,41 @@ pub struct TextWidget {
|
|||
}
|
||||
|
||||
impl TextWidget {
|
||||
// Weight
|
||||
|
||||
#[must_use]
|
||||
pub fn thin(mut self) -> Self {
|
||||
self.font = "font-thin".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn extralight(mut self) -> Self {
|
||||
self.font = "font-extralight".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn light(mut self) -> Self {
|
||||
self.font = "font-light".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn normal(mut self) -> Self {
|
||||
self.font = "font-normal".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Turn `Text` medium.
|
||||
///
|
||||
/// Adds the class `font-medium`
|
||||
#[must_use]
|
||||
pub fn medium(mut self) -> Self {
|
||||
self.font = "font-medium".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Turn `Text` semibold.
|
||||
///
|
||||
/// Adds the class `font-semibold`
|
||||
|
@ -70,12 +113,83 @@ impl TextWidget {
|
|||
self
|
||||
}
|
||||
|
||||
/// Turn `Text` medium.
|
||||
///
|
||||
/// Adds the class `font-medium`
|
||||
#[must_use]
|
||||
pub fn medium(mut self) -> Self {
|
||||
self.font = "font-medium".to_string();
|
||||
pub fn extrabold(mut self) -> Self {
|
||||
self.font = "font-extrabold".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn weight_black(mut self) -> Self {
|
||||
self.font = "font-black".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// Styles
|
||||
|
||||
#[must_use]
|
||||
pub fn italic(mut self, apply: bool) -> Self {
|
||||
if apply {
|
||||
self.style.push("italic".to_string());
|
||||
} else {
|
||||
self.style.push("not-italic".to_string())
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn number_style(mut self, s: NumberStyle) -> Self {
|
||||
self.style.push(s.to_value().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
// Sizes
|
||||
|
||||
#[must_use]
|
||||
pub fn _9xl(mut self) -> Self {
|
||||
self.size = "text-9xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn _8xl(mut self) -> Self {
|
||||
self.size = "text-8xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn _7xl(mut self) -> Self {
|
||||
self.size = "text-7xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn _6xl(mut self) -> Self {
|
||||
self.size = "text-6xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn _5xl(mut self) -> Self {
|
||||
self.size = "text-5xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn _4xl(mut self) -> Self {
|
||||
self.size = "text-4xl".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn large(mut self) -> Self {
|
||||
self.size = "text-lg".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn base_size(mut self) -> Self {
|
||||
self.size = "text-base".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -115,6 +229,17 @@ impl TextWidget {
|
|||
self
|
||||
}
|
||||
|
||||
/// Turn `Text` size to x small.
|
||||
///
|
||||
/// Adds the class `text-xs`
|
||||
#[must_use]
|
||||
pub fn xs(mut self) -> Self {
|
||||
self.size = "text-xs".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// Text Color
|
||||
|
||||
#[must_use]
|
||||
pub fn color<T: UIColor>(mut self, color: &T) -> Self {
|
||||
self.color = format!("text-{}", color.color_class());
|
||||
|
@ -132,6 +257,26 @@ impl TextWidget {
|
|||
self.color = "text-white".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// Font Family
|
||||
|
||||
#[must_use]
|
||||
pub fn sans(mut self) -> Self {
|
||||
self.family = "font-sans".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn serif(mut self) -> Self {
|
||||
self.family = "font-serif".to_string();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mono(mut self) -> Self {
|
||||
self.family = "font-mono".to_string();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for TextWidget {
|
||||
|
@ -146,7 +291,12 @@ impl UIWidget for TextWidget {
|
|||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
vec![self.color.clone(), self.font.clone(), self.size.clone()]
|
||||
vec![
|
||||
self.color.clone(),
|
||||
self.font.clone(),
|
||||
self.size.clone(),
|
||||
self.family.clone(),
|
||||
]
|
||||
}
|
||||
|
||||
fn extended_class(&self) -> Vec<String> {
|
||||
|
@ -179,3 +329,31 @@ impl UIWidget for TextWidget {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NumberStyle {
|
||||
Normal,
|
||||
Ordinal,
|
||||
SlashedZero,
|
||||
OldStyle,
|
||||
Lining,
|
||||
Proportional,
|
||||
Tabular,
|
||||
DiagonalFractions,
|
||||
StackedFractions,
|
||||
}
|
||||
|
||||
impl NumberStyle {
|
||||
pub const fn to_value(&self) -> &str {
|
||||
match self {
|
||||
NumberStyle::Normal => "normal-nums",
|
||||
NumberStyle::Ordinal => "ordinal",
|
||||
NumberStyle::SlashedZero => "slashed-zero",
|
||||
NumberStyle::OldStyle => "oldstyle-nums",
|
||||
NumberStyle::Lining => "lining-nums",
|
||||
NumberStyle::Proportional => "proportional-nums",
|
||||
NumberStyle::Tabular => "tabular-nums",
|
||||
NumberStyle::DiagonalFractions => "diagonal-fractions",
|
||||
NumberStyle::StackedFractions => "stacked-fractions",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
54
src/ui/primitives/visibility.rs
Normal file
54
src/ui/primitives/visibility.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::ui::UIWidget;
|
||||
use maud::{Markup, Render, html};
|
||||
|
||||
pub struct Visibility(Box<dyn UIWidget>, String);
|
||||
|
||||
impl Visibility {
|
||||
pub fn visible<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "visible".to_string())
|
||||
}
|
||||
|
||||
pub fn hidden<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "invisible".to_string())
|
||||
}
|
||||
|
||||
pub fn collapsed<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), "collapse".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Visibility {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for Visibility {
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,20 @@ use super::space::ScreenValue;
|
|||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Width<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> WidthWidget {
|
||||
WidthWidget(Box::new(inner), size)
|
||||
WidthWidget(Box::new(inner), size, 0)
|
||||
}
|
||||
|
||||
pub struct WidthWidget(Box<dyn UIWidget>, ScreenValue);
|
||||
#[allow(non_snake_case)]
|
||||
pub fn MinWidth<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> WidthWidget {
|
||||
WidthWidget(Box::new(inner), size, 1)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn MaxWidth<T: UIWidget + 'static>(size: ScreenValue, inner: T) -> WidthWidget {
|
||||
WidthWidget(Box::new(inner), size, 2)
|
||||
}
|
||||
|
||||
pub struct WidthWidget(Box<dyn UIWidget>, ScreenValue, u8);
|
||||
|
||||
impl Render for WidthWidget {
|
||||
fn render(&self) -> Markup {
|
||||
|
@ -22,6 +32,16 @@ impl UIWidget for WidthWidget {
|
|||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
match self.2 {
|
||||
1 => {
|
||||
return vec![format!("min-w-{}", self.1.to_value())];
|
||||
}
|
||||
2 => {
|
||||
return vec![format!("max-w-{}", self.1.to_value())];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
vec![format!("w-{}", self.1.to_value())]
|
||||
}
|
||||
|
||||
|
|
82
src/ui/primitives/zindex.rs
Normal file
82
src/ui/primitives/zindex.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use maud::{Markup, Render, html};
|
||||
|
||||
use crate::ui::UIWidget;
|
||||
|
||||
pub struct ZIndex(Box<dyn UIWidget>, u8);
|
||||
|
||||
impl Render for ZIndex {
|
||||
fn render(&self) -> Markup {
|
||||
self.render_with_class("")
|
||||
}
|
||||
}
|
||||
|
||||
impl ZIndex {
|
||||
pub fn auto<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 0)
|
||||
}
|
||||
|
||||
pub fn zero<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 1)
|
||||
}
|
||||
|
||||
pub fn one<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 2)
|
||||
}
|
||||
|
||||
pub fn two<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 3)
|
||||
}
|
||||
|
||||
pub fn three<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 4)
|
||||
}
|
||||
|
||||
pub fn four<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 5)
|
||||
}
|
||||
|
||||
pub fn five<T: UIWidget + 'static>(inner: T) -> Self {
|
||||
Self(Box::new(inner), 6)
|
||||
}
|
||||
}
|
||||
|
||||
impl UIWidget for ZIndex {
|
||||
fn can_inherit(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn base_class(&self) -> Vec<String> {
|
||||
let class = match self.1 {
|
||||
0 => "z-auto",
|
||||
1 => "z-0",
|
||||
2 => "z-10",
|
||||
3 => "z-20",
|
||||
4 => "z-30",
|
||||
5 => "z-40",
|
||||
6 => "z-50",
|
||||
_ => "z-auto",
|
||||
};
|
||||
|
||||
vec![class.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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,11 +3,11 @@ use maud::{Markup, Render, html};
|
|||
use crate::ui::UIWidget;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Hover<T: UIWidget + 'static, I: UIWidget + 'static>(inherit: I, inner: T) -> HoverWrapper {
|
||||
HoverWrapper(Box::new(inner), Box::new(inherit))
|
||||
pub fn Hover<I: UIWidget + 'static>(inherit: I) -> HoverWrapper {
|
||||
HoverWrapper(None, Box::new(inherit))
|
||||
}
|
||||
|
||||
pub struct HoverWrapper(Box<dyn UIWidget>, Box<dyn UIWidget>);
|
||||
pub struct HoverWrapper(Option<Box<dyn UIWidget>>, Box<dyn UIWidget>);
|
||||
|
||||
impl HoverWrapper {
|
||||
fn hovered_class(&self) -> Vec<String> {
|
||||
|
@ -18,6 +18,11 @@ impl HoverWrapper {
|
|||
.map(|x| format!("hover:{x}"))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn on<T: UIWidget + 'static>(mut self, inner: T) -> Self {
|
||||
self.0 = Some(Box::new(inner));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for HoverWrapper {
|
||||
|
@ -36,20 +41,19 @@ impl UIWidget for HoverWrapper {
|
|||
}
|
||||
|
||||
fn extended_class(&self) -> Vec<String> {
|
||||
let mut ret = self.base_class();
|
||||
ret.extend_from_slice(&self.0.extended_class());
|
||||
ret
|
||||
self.base_class()
|
||||
}
|
||||
|
||||
fn render_with_class(&self, class: &str) -> Markup {
|
||||
if self.0.as_ref().can_inherit() {
|
||||
if self.0.as_ref().unwrap().can_inherit() {
|
||||
self.0
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.render_with_class(&format!("{} {class}", self.hovered_class().join(" ")))
|
||||
} else {
|
||||
html! {
|
||||
div class=(format!("{} {class}", self.hovered_class().join(" "))) {
|
||||
(self.0.as_ref())
|
||||
(self.0.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue