add filters

This commit is contained in:
JMARyA 2025-01-20 05:51:22 +01:00
parent ec10e5a89d
commit f7db3333c5
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
5 changed files with 274 additions and 1 deletions

View file

@ -1,3 +1,5 @@
#![feature(const_vec_string_slice)]
use tokio::sync::OnceCell;
pub mod auth;

View file

@ -26,6 +26,9 @@ pub mod prelude {
pub use super::primitives::container::Container;
pub use super::primitives::cursor::Cursor;
pub use super::primitives::div::Div;
pub use super::primitives::filter::{
Blur, Brightness, Contrast, Grayscale, HueRotate, Invert, Saturate, Sepia,
};
pub use super::primitives::flex::{
Direction, Flex, FlexBasis, FlexGrow, Justify, Order, Strategy, Wrap,
};

265
src/ui/primitives/filter.rs Normal file
View file

@ -0,0 +1,265 @@
use crate::ui::UIWidget;
use maud::{Markup, Render, html};
use super::Size;
#[allow(non_snake_case)]
pub fn Blur<T: UIWidget + 'static>(amount: Size, inner: T) -> BlurWidget {
BlurWidget(Box::new(inner), amount, false)
}
pub struct BlurWidget(Box<dyn UIWidget>, Size, bool);
impl BlurWidget {
pub fn backdrop(mut self) -> Self {
self.2 = true;
self
}
}
impl Render for BlurWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for BlurWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let class = match &self.1 {
Size::Custom(s) => &format!(" blur-[{s}]"),
Size::None => "blur-none",
Size::Small => "blur-sm",
Size::Regular => "blur",
Size::Medium => "blur-md",
Size::Large => "blur-lg",
Size::XL => "blur-xl",
Size::_2XL => "blur-2xl",
Size::_3XL => "blur-3xl",
Size::Full => "blur-3xl",
};
if self.2 {
return vec![format!("backdrop-{class}")];
}
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())
}
}
}
}
}
macro_rules! build_value_widget {
($constr:ident, $widget:ident, $class:literal) => {
#[allow(non_snake_case)]
pub fn $constr<T: UIWidget + 'static>(value: f64, inner: T) -> $widget {
$widget(Box::new(inner), value, false)
}
pub struct $widget(Box<dyn UIWidget>, f64, bool);
impl $widget {
pub fn backdrop(mut self) -> Self {
self.2 = true;
self
}
}
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> {
let mut ret = $class.to_string();
ret.push_str(&format!("-[{:.2}]", self.1));
if self.2 {
return vec![format!("backdrop-{ret}")];
}
vec![ret]
}
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())
}
}
}
}
}
};
}
build_value_widget!(Brightness, BrightnessWidget, "brightness");
build_value_widget!(Contrast, ConstrastWidget, "contrast");
build_value_widget!(Saturate, SaturationWidget, "saturate");
macro_rules! build_on_off_widget {
($constr:ident, $widget:ident, $class:literal) => {
#[allow(non_snake_case)]
pub fn $constr<T: UIWidget + 'static>(inner: T) -> $widget {
$widget(Box::new(inner), true, false)
}
pub struct $widget(Box<dyn UIWidget>, bool, bool);
impl $widget {
pub fn none(mut self) -> Self {
self.1 = false;
self
}
pub fn backdrop(mut self) -> Self {
self.2 = true;
self
}
}
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> {
let class = if self.1 {
$class.to_string()
} else {
concat!($class, "-0").to_string()
};
if self.2 {
return vec![format!("backdrop-{class}")];
}
vec![class]
}
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())
}
}
}
}
}
};
}
build_on_off_widget!(Grayscale, GrayscaleWidget, "grayscale");
build_on_off_widget!(Invert, InvertWidget, "invert");
build_on_off_widget!(Sepia, SepiaWidget, "sepia");
#[allow(non_snake_case)]
pub fn HueRotate<T: UIWidget + 'static>(deg: u32, inner: T) -> HueRotateWidget {
HueRotateWidget(Box::new(inner), deg, false)
}
pub struct HueRotateWidget(Box<dyn UIWidget>, u32, bool);
impl HueRotateWidget {
pub fn backdrop(mut self) -> Self {
self.2 = true;
self
}
}
impl Render for HueRotateWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for HueRotateWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let class = format!("hue-rotate-[{:.2}deg]", self.1);
if self.2 {
return vec![format!("backdrop-{class}")];
}
vec![class]
}
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())
}
}
}
}
}

View file

@ -8,6 +8,7 @@ pub mod background;
pub mod container;
pub mod cursor;
pub mod div;
pub mod filter;
pub mod flex;
pub mod header;
pub mod height;
@ -62,6 +63,7 @@ pub fn script(script: &str) -> PreEscaped<String> {
}
pub enum Size {
Custom(String),
None,
Small,
Regular,
@ -77,6 +79,7 @@ impl Size {
#[must_use]
pub const fn to_value(&self) -> &str {
match self {
Self::Custom(str) => str.as_str(),
Self::None => "none",
Self::Small => "sm",
Self::Regular => "",

View file

@ -12,7 +12,7 @@ pub struct RoundedWidget(Box<dyn UIWidget>, Option<Size>, Option<Side>);
impl RoundedWidget {
#[must_use]
pub const fn size(mut self, size: Size) -> Self {
pub fn size(mut self, size: Size) -> Self {
self.1 = Some(size);
self
}