From 95ceaa8231ea89b648880cc71cdb6dc5f6d47623 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Tue, 21 Jan 2025 00:52:29 +0100 Subject: [PATCH] update --- src/ui/color.rs | 2 +- src/ui/mod.rs | 14 ++-- src/ui/primitives/cursor.rs | 73 +++++++++++++++++++ src/ui/primitives/mod.rs | 45 +++++++++++- src/ui/primitives/position.rs | 131 ++++++++++++++++++++++++++++++++++ src/ui/primitives/text.rs | 84 +++++++++++++++++++++- 6 files changed, 340 insertions(+), 9 deletions(-) diff --git a/src/ui/color.rs b/src/ui/color.rs index 4671712..e7baa05 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -12,7 +12,7 @@ pub trait ColorCircle { fn next(&self) -> Self; } -// todo : specific colors rgb +// todo : specific colors rgb -[#50d71e] macro_rules! color_map { ($name:ident, $id:literal) => { diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 3e37b3b..af4fedf 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -17,6 +17,7 @@ pub mod components; pub mod prelude { pub use super::color::*; pub use super::primitives::Context; + pub use super::primitives::NoBrowserAppearance; pub use super::primitives::Nothing; pub use super::primitives::Side; pub use super::primitives::Size; @@ -27,7 +28,7 @@ pub mod prelude { Border, BorderSide, BorderSize, BorderStyle, Outline, OutlineStyle, Ring, }; pub use super::primitives::container::Container; - pub use super::primitives::cursor::Cursor; + pub use super::primitives::cursor::{Action, Cursor, TouchAction}; pub use super::primitives::div::Div; pub use super::primitives::filter::{ Blur, Brightness, Contrast, Grayscale, HueRotate, Invert, Saturate, Sepia, @@ -41,7 +42,7 @@ pub mod prelude { pub use super::primitives::link::Link; pub use super::primitives::margin::Margin; pub use super::primitives::padding::Padding; - pub use super::primitives::position::{Position, PositionKind}; + pub use super::primitives::position::{Position, PositionKind, Resize, Resizeable}; pub use super::primitives::rounded::Rounded; pub use super::primitives::script; pub use super::primitives::shadow::Shadow; @@ -49,10 +50,11 @@ pub mod prelude { pub use super::primitives::space::{ScreenValue, SpaceBetween}; pub use super::primitives::svg::SVG; pub use super::primitives::text::{ - Code, DecorationKind, DecorationStyle, DecorationThickness, LetterSpacing, LineClamp, - LineHeight, ListStyle, NumberStyle, Paragraph, Span, Text, TextAlignment, TextContent, - TextDecoration, TextHyphens, TextOverflow, TextTransform, TextWhitespace, TextWordBreak, - TextWrap, UnderlineOffset, VerticalTextAlignment, + AccentColor, Code, DecorationKind, DecorationStyle, DecorationThickness, LetterSpacing, + LineClamp, LineHeight, ListStyle, NumberStyle, Paragraph, Span, Text, TextAlignment, + TextContent, TextCursorColor, TextDecoration, TextHyphens, TextOverflow, TextSelection, + TextTransform, TextWhitespace, TextWordBreak, TextWrap, UnderlineOffset, + VerticalTextAlignment, }; pub use super::primitives::transform::{ RenderTransformCPU, RenderTransformGPU, Rotate, Scale, Skew, Transform, TransformOrigin, diff --git a/src/ui/primitives/cursor.rs b/src/ui/primitives/cursor.rs index 1ab521e..d6d5141 100644 --- a/src/ui/primitives/cursor.rs +++ b/src/ui/primitives/cursor.rs @@ -122,3 +122,76 @@ impl UIWidget for CursorWidget { } } } + +#[allow(non_snake_case)] +pub fn TouchAction(action: Action, inner: T) -> TouchActionWidget { + TouchActionWidget(Box::new(inner), action) +} + +pub struct TouchActionWidget(Box, Action); + +impl Render for TouchActionWidget { + fn render(&self) -> Markup { + self.render_with_class("") + } +} + +impl UIWidget for TouchActionWidget { + fn can_inherit(&self) -> bool { + false + } + + fn base_class(&self) -> Vec { + vec![self.1.to_value().to_string()] + } + + fn extended_class(&self) -> Vec { + 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 Action { + Auto, + None, + PanX, + PanLeft, + PanRight, + PanY, + PanUp, + PanDown, + PinchZoom, + Manipulation, +} + +impl Action { + pub const fn to_value(&self) -> &str { + match self { + Action::Auto => "touch-auto", + Action::None => "touch-none", + Action::PanX => "touch-pan-x", + Action::PanLeft => "touch-pan-left", + Action::PanRight => "touch-pan-right", + Action::PanY => "touch-pan-y", + Action::PanUp => "touch-pan-up", + Action::PanDown => "touch-pan-down", + Action::PinchZoom => "touch-pinch-zoom", + Action::Manipulation => "touch-manipulation", + } + } +} diff --git a/src/ui/primitives/mod.rs b/src/ui/primitives/mod.rs index d0acf64..89bdd20 100644 --- a/src/ui/primitives/mod.rs +++ b/src/ui/primitives/mod.rs @@ -1,5 +1,5 @@ use super::UIWidget; -use maud::{PreEscaped, html}; +use maud::{Markup, PreEscaped, Render, html}; pub mod animation; pub mod aspect; @@ -135,3 +135,46 @@ impl Side { } } } + +#[allow(non_snake_case)] +pub fn NoBrowserAppearance(inner: T) -> NoBrowserAppearanceWidget { + NoBrowserAppearanceWidget(Box::new(inner)) +} + +pub struct NoBrowserAppearanceWidget(Box); + +impl Render for NoBrowserAppearanceWidget { + fn render(&self) -> Markup { + self.render_with_class("") + } +} + +impl UIWidget for NoBrowserAppearanceWidget { + fn can_inherit(&self) -> bool { + true + } + + fn base_class(&self) -> Vec { + vec!["appearance-none".to_string()] + } + + fn extended_class(&self) -> Vec { + 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!("appearance-none {class}")) + } else { + html! { + div class=(format!("appearance-none {class}")) { + (self.0.as_ref()) + } + } + } + } +} diff --git a/src/ui/primitives/position.rs b/src/ui/primitives/position.rs index 75531ce..2019981 100644 --- a/src/ui/primitives/position.rs +++ b/src/ui/primitives/position.rs @@ -2,6 +2,8 @@ use maud::{Markup, Render, html}; use crate::ui::UIWidget; +use super::Side; + #[allow(non_snake_case)] pub fn Position(kind: PositionKind, inner: T) -> Positioned { Positioned { @@ -208,3 +210,132 @@ impl PositionKind { } } } + +#[allow(non_snake_case)] +pub fn ObjectPosition(side: Side, inner: T) -> ObjectPositioned { + ObjectPositioned { + inner: Box::new(inner), + side, + } +} + +pub struct ObjectPositioned { + inner: Box, + side: Side, +} + +impl Render for ObjectPositioned { + fn render(&self) -> Markup { + self.render_with_class("") + } +} + +impl UIWidget for ObjectPositioned { + fn can_inherit(&self) -> bool { + true + } + + fn base_class(&self) -> Vec { + vec![ + match self.side { + Side::Start => "object-top", + Side::End => "object-bottom", + Side::Top => "object-top", + Side::Right => "object-right", + Side::Bottom => "object-bottom", + Side::Left => "object-left", + Side::StartStart => "object-left-top", + Side::StartEnd => "object-right-top", + Side::EndEnd => "object-right-bottom", + Side::EndStart => "object-left-bottom", + Side::TopLeft => "object-left-top", + Side::TopRight => "object-right-top", + Side::BottomRight => "object-right-bottom", + Side::BottomLeft => "object-left-bottom", + Side::Center => "object-center", + } + .to_string(), + ] + } + + fn extended_class(&self) -> Vec { + let mut c = self.base_class(); + c.extend_from_slice(&self.inner.extended_class()); + c + } + + fn render_with_class(&self, class: &str) -> Markup { + if self.inner.as_ref().can_inherit() { + self.inner + .as_ref() + .render_with_class(&format!("{} {class}", self.base_class().join(" "))) + } else { + html! { + div class=(format!("{} {class}", self.base_class().join(" "))) { + (self.inner.as_ref()) + } + } + } + } +} + +pub enum Resize { + None, + Y, + X, + Both, +} + +impl Resize { + pub const fn to_value(&self) -> &str { + match self { + Resize::None => "resize-none", + Resize::Y => "resize-y", + Resize::X => "resize-x", + Resize::Both => "resize", + } + } +} + +#[allow(non_snake_case)] +pub fn Resizeable(mode: Resize, inner: T) -> ResizeableWidget { + ResizeableWidget(Box::new(inner), mode) +} + +pub struct ResizeableWidget(Box, Resize); + +impl Render for ResizeableWidget { + fn render(&self) -> Markup { + self.render_with_class("") + } +} + +impl UIWidget for ResizeableWidget { + fn can_inherit(&self) -> bool { + false + } + + fn base_class(&self) -> Vec { + vec![self.1.to_value().to_string()] + } + + fn extended_class(&self) -> Vec { + 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()) + } + } + } + } +} diff --git a/src/ui/primitives/text.rs b/src/ui/primitives/text.rs index 5230a1f..43befe7 100644 --- a/src/ui/primitives/text.rs +++ b/src/ui/primitives/text.rs @@ -1,5 +1,5 @@ use crate::ui::{UIWidget, color::UIColor}; -use maud::{Markup, PreEscaped, Render}; +use maud::{Markup, PreEscaped, Render, html}; use super::{Nothing, space::ScreenValue}; @@ -31,6 +31,7 @@ pub fn Text(txt: &str) -> TextWidget { align: None, vert_align: None, list_style: None, + select: None, kind: TextKind::Paragraph, } } @@ -68,6 +69,7 @@ pub fn Paragraph(inner: T) -> TextWidget { list_style: None, clamp: None, align: None, + select: None, kind: TextKind::Paragraph, } } @@ -100,6 +102,7 @@ pub fn Span(txt: &str) -> TextWidget { clamp: None, align: None, pseudo: None, + select: None, kind: TextKind::Span, } } @@ -132,6 +135,7 @@ pub fn Code(txt: &str) -> TextWidget { clamp: None, align: None, pseudo: None, + select: None, kind: TextKind::Pre, } } @@ -160,10 +164,17 @@ pub struct TextWidget { pseudo: Option, align: Option, clamp: Option, + select: Option, title: Option, } impl TextWidget { + #[must_use] + pub fn select(mut self, select: TextSelection) -> Self { + self.select = Some(select); + self + } + #[must_use] pub fn whitespace(mut self, whitespace: TextWhitespace) -> Self { self.whitespace = Some(whitespace); @@ -527,6 +538,7 @@ impl UIWidget for TextWidget { add_option!(list_style, ret); add_option!(pseudo, ret); add_option!(line_height, ret); + add_option!(select, ret); if let Some(decoration) = &self.decoration { ret.extend_from_slice(&decoration.base_class()); @@ -1061,3 +1073,73 @@ impl TextHyphens { } } } + +pub enum TextSelection { + None, + Text, + All, + Auto, +} + +impl TextSelection { + pub const fn to_value(&self) -> &str { + match self { + TextSelection::None => "select-none", + TextSelection::Text => "select-text", + TextSelection::All => "select-all", + TextSelection::Auto => "select-auto ", + } + } +} + +macro_rules! color_widget { + ($constr:ident, $widget:ident, $class:literal) => { + #[allow(non_snake_case)] + pub fn $constr(color: C, inner: T) -> $widget { + $widget(Box::new(inner), Box::new(color)) + } + + pub struct $widget(Box, Box); + + impl Render for $widget { + fn render(&self) -> Markup { + self.render_with_class("") + } + } + + impl UIWidget for $widget { + fn can_inherit(&self) -> bool { + false + } + + fn base_class(&self) -> Vec { + let mut class = $class.to_string(); + class.push_str(&format!("-{}", self.1.color_class())); + vec![class] + } + + fn extended_class(&self) -> Vec { + 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()) + } + } + } + } + } + }; +} + +color_widget!(TextCursorColor, CaretColorWidget, "caret"); +color_widget!(AccentColor, AccentColorWidget, "accent");