⚰️ Simplify class handling

This commit is contained in:
Manuel Cillero 2023-11-01 23:26:36 +01:00
parent 6dd9eb28f5
commit 80139d9153
11 changed files with 47 additions and 80 deletions

View file

@ -74,14 +74,11 @@ impl ThemeTrait for Bulmix {
}
_ => {}
};
match a.anchor_type() {
AnchorType::Button => {
if let AnchorType::Button = a.anchor_type() {
a.alter_classes(
ClassesOp::Replace(a.anchor_type().to_string()),
"button is-primary",
);
}
_ => {}
};
}
COMPONENT_BASE_HEADING => {
@ -90,12 +87,12 @@ impl ThemeTrait for Bulmix {
HeadingDisplay::Subtitle => {
h.alter_classes(ClassesOp::Replace(h.display().to_string()), "subtitle")
}
_ => h.alter_classes(ClassesOp::AddDefault, "title"),
_ => h.alter_classes(ClassesOp::Add, "title"),
};
}
COMPONENT_BASE_PARAGRAPH => {
let p = component_as_mut::<Paragraph>(component);
p.alter_classes(ClassesOp::AddDefault, "block");
p.alter_classes(ClassesOp::Add, "block");
match p.font_size() {
FontSize::ExtraLarge => {
p.alter_classes(ClassesOp::Replace(p.font_size().to_string()), "is-size-1");

View file

@ -18,7 +18,7 @@ pub struct Block {
impl ComponentTrait for Block {
fn new() -> Self {
Block::default().with_classes(ClassesOp::AddDefault, "block")
Block::default().with_classes(ClassesOp::Add, "block")
}
fn handle(&self) -> Handle {

View file

@ -21,8 +21,7 @@ pub struct Container {
impl ComponentTrait for Container {
fn new() -> Self {
Container::default()
.with_classes(ClassesOp::AddDefault, flex::Direction::Default.to_string())
Container::default().with_classes(ClassesOp::Add, flex::Direction::Default.to_string())
}
fn handle(&self) -> Handle {

View file

@ -23,8 +23,8 @@ pub struct Item {
impl ComponentTrait for Item {
fn new() -> Self {
Item::default()
.with_item_classes(ClassesOp::AddDefault, "pt-flex__item")
.with_inner_classes(ClassesOp::AddDefault, "pt-flex__item-inner")
.with_item_classes(ClassesOp::Add, "pt-flex__item")
.with_inner_classes(ClassesOp::Add, "pt-flex__item-inner")
}
fn handle(&self) -> Handle {

View file

@ -26,7 +26,7 @@ pub struct Button {
impl ComponentTrait for Button {
fn new() -> Self {
Button::default().with_classes(ClassesOp::AddDefault, "btn btn-primary form-button")
Button::default().with_classes(ClassesOp::Add, "btn btn-primary form-button")
}
fn handle(&self) -> Handle {

View file

@ -23,7 +23,7 @@ pub struct Date {
impl ComponentTrait for Date {
fn new() -> Self {
Date::default().with_classes(ClassesOp::AddDefault, "form-item form-type-date")
Date::default().with_classes(ClassesOp::Add, "form-item form-type-date")
}
fn handle(&self) -> Handle {

View file

@ -28,7 +28,7 @@ pub struct Form {
impl ComponentTrait for Form {
fn new() -> Self {
Form::default()
.with_classes(ClassesOp::AddDefault, "form")
.with_classes(ClassesOp::Add, "form")
.with_charset("UTF-8")
}

View file

@ -39,7 +39,7 @@ pub struct Input {
impl ComponentTrait for Input {
fn new() -> Self {
Input::default()
.with_classes(ClassesOp::AddDefault, "form-item form-type-textfield")
.with_classes(ClassesOp::Add, "form-item form-type-textfield")
.with_size(Some(60))
.with_maxlength(Some(128))
}
@ -177,7 +177,7 @@ impl Input {
if let Some(previous) = self.name.get() {
self.alter_classes(ClassesOp::Remove, concat_string!("form-item-", previous));
}
self.alter_classes(ClassesOp::AddDefault, concat_string!("form-item-", name));
self.alter_classes(ClassesOp::Add, concat_string!("form-item-", name));
self.name.alter_value(name);
self
}

View file

@ -28,7 +28,7 @@ pub struct Image {
impl ComponentTrait for Image {
fn new() -> Self {
Image::default().with_classes(ClassesOp::AddDefault, IMG_FLUID)
Image::default().with_classes(ClassesOp::Add, IMG_FLUID)
}
fn handle(&self) -> Handle {
@ -70,19 +70,19 @@ impl Image {
pub fn with(source: &str) -> Self {
Image::default()
.with_source(source)
.with_classes(ClassesOp::AddDefault, IMG_FLUID)
.with_classes(ClassesOp::Add, IMG_FLUID)
}
pub fn fixed(source: &str) -> Self {
Image::default()
.with_source(source)
.with_classes(ClassesOp::AddDefault, IMG_FIXED)
.with_classes(ClassesOp::Add, IMG_FIXED)
}
pub fn pagetop() -> Self {
Image::default()
.with_source("/base/pagetop-logo.svg")
.with_classes(ClassesOp::AddDefault, IMG_FIXED)
.with_classes(ClassesOp::Add, IMG_FIXED)
.with_size(ImageSize::Size(64, 64))
}

View file

@ -30,8 +30,8 @@ pub struct Wrapper {
impl ComponentTrait for Wrapper {
fn new() -> Self {
Wrapper::default()
.with_classes(ClassesOp::AddDefault, "container")
.with_inner_classes(ClassesOp::AddDefault, "container")
.with_classes(ClassesOp::Add, "container")
.with_inner_classes(ClassesOp::Add, "container")
}
fn handle(&self) -> Handle {
@ -100,32 +100,32 @@ impl ComponentTrait for Wrapper {
impl Wrapper {
pub fn header() -> Self {
let mut c = Wrapper::default()
.with_classes(ClassesOp::AddDefault, "header")
.with_inner_classes(ClassesOp::AddDefault, "container");
.with_classes(ClassesOp::Add, "header")
.with_inner_classes(ClassesOp::Add, "container");
c.wrapper_type = WrapperType::Header;
c
}
pub fn footer() -> Self {
let mut c = Wrapper::default()
.with_classes(ClassesOp::AddDefault, "footer")
.with_inner_classes(ClassesOp::AddDefault, "container");
.with_classes(ClassesOp::Add, "footer")
.with_inner_classes(ClassesOp::Add, "container");
c.wrapper_type = WrapperType::Footer;
c
}
pub fn main() -> Self {
let mut c = Wrapper::default()
.with_classes(ClassesOp::AddDefault, "main")
.with_inner_classes(ClassesOp::AddDefault, "container");
.with_classes(ClassesOp::Add, "main")
.with_inner_classes(ClassesOp::Add, "container");
c.wrapper_type = WrapperType::Main;
c
}
pub fn section() -> Self {
let mut c = Wrapper::default()
.with_classes(ClassesOp::AddDefault, "section")
.with_inner_classes(ClassesOp::AddDefault, "container");
.with_classes(ClassesOp::Add, "section")
.with_inner_classes(ClassesOp::Add, "container");
c.wrapper_type = WrapperType::Section;
c
}

View file

@ -3,33 +3,24 @@
//! This *helper* differentiates between default classes (generally associated with styles provided
//! by the theme) and user classes (for customizing components based on application styles).
//!
//! Default classes can be added using [AddDefault], while user classes can be added using [Add].
//! Operations to [Remove], [Replace] or [ReplaceIfExists] a class, as well as to [Reset] user
//! classes, are also provided.
//! Classes can be added using [Add]. Operations to [Remove], [Replace] or [Toggle] a class, as well
//! as [Clear] all classes, are also provided.
//!
//! Although the order of the classes is irrelevant (<https://stackoverflow.com/a/1321712>), default
//! classes will be presented before user classes and duplicate classes will not be allowed.
//! **OptionClasses** assumes that the order of the classes is irrelevant
//! (<https://stackoverflow.com/a/1321712>), and duplicate classes will not be allowed.
use crate::fn_builder;
pub enum ClassesOp {
AddDefault,
Add,
Remove,
Replace(String),
Toggle,
Reset,
Clear,
}
#[derive(Clone, PartialEq)]
enum ClassType {
Default,
User,
}
#[derive(Default)]
pub struct OptionClasses(Vec<(String, ClassType)>);
pub struct OptionClasses(Vec<String>);
impl OptionClasses {
pub fn new() -> Self {
@ -50,52 +41,38 @@ impl OptionClasses {
let classes: Vec<&str> = classes.split_ascii_whitespace().collect();
match op {
ClassesOp::AddDefault => {
let pos = match self.0.iter().position(|(_, t)| t.eq(&ClassType::User)) {
Some(pos) => pos,
None => self.0.len(),
};
self.add(&classes, pos, ClassType::Default);
}
ClassesOp::Add => {
self.add(&classes, self.0.len(), ClassType::User);
self.add(&classes, self.0.len());
}
ClassesOp::Remove => {
for class in classes {
self.0.retain(|(c, _)| c.ne(&class.to_string()));
self.0.retain(|c| c.ne(&class.to_string()));
}
}
ClassesOp::Replace(classes_to_replace) => {
let mut pos = self.0.len();
let mut class_type = ClassType::Default;
let replace: Vec<&str> = classes_to_replace.split_ascii_whitespace().collect();
for class in replace {
if let Some(replace_pos) = self.0.iter().position(|(c, _)| c.eq(class)) {
let (_, replace_type) = self.0.remove(replace_pos);
if let Some(replace_pos) = self.0.iter().position(|c| c.eq(class)) {
self.0.remove(replace_pos);
if pos > replace_pos {
pos = replace_pos;
}
if replace_type.eq(&ClassType::Default) {
class_type = replace_type;
}
}
}
self.add(&classes, pos, class_type);
self.add(&classes, pos);
}
ClassesOp::Toggle => {
for class in classes {
if !class.is_empty() {
if let Some(pos) = self.0.iter().position(|(c, _)| c.eq(class)) {
if let Some(pos) = self.0.iter().position(|c| c.eq(class)) {
self.0.remove(pos);
} else {
self.0.push((class.to_string(), ClassType::User));
self.0.push(class.to_string());
}
}
}
}
ClassesOp::Reset => {
self.0.retain(|(_, t)| t.ne(&ClassType::User));
}
ClassesOp::Clear => {
self.0.clear();
}
@ -104,10 +81,10 @@ impl OptionClasses {
}
#[inline]
fn add(&mut self, classes: &Vec<&str>, mut pos: usize, class_type: ClassType) {
fn add(&mut self, classes: &Vec<&str>, mut pos: usize) {
for class in classes {
if !class.is_empty() && !self.0.iter().any(|(c, _)| c.eq(class)) {
self.0.insert(pos, (class.to_string(), class_type.clone()));
if !class.is_empty() && !self.0.iter().any(|c| c.eq(class)) {
self.0.insert(pos, class.to_string());
pos += 1;
}
}
@ -117,20 +94,14 @@ impl OptionClasses {
pub fn exists(&self, class: impl Into<String>) -> bool {
let class: String = class.into();
self.0.iter().any(|(c, _)| c.eq(&class))
self.0.iter().any(|c| c.eq(&class))
}
pub fn get(&self) -> Option<String> {
if self.0.is_empty() {
None
} else {
Some(
self.0
.iter()
.map(|(c, _)| c.to_owned())
.collect::<Vec<String>>()
.join(" "),
)
Some(self.0.join(" "))
}
}
}