🎨 Isolate infra and ui components

The src/base.rs is still to be reworked.
This commit is contained in:
2024-04-04 14:27:58 +02:00
parent 92bf860101
commit 0ce0764204
67 changed files with 64 additions and 59 deletions

View File

@@ -0,0 +1,218 @@
use dioxus::prelude::*;
use dioxus_free_icons::icons::io_icons::IoEye;
use dioxus_free_icons::icons::io_icons::IoEyeOff;
use dioxus_free_icons::Icon;
use super::icons::Pyramid;
turf::style_sheet!("src/ui/components/text_input.scss");
pub trait InputPropsData {}
#[derive(Props, Clone, PartialEq)]
pub struct InputProps<D: InputPropsData + 'static + std::cmp::PartialEq> {
value: Option<String>,
placeholder: Option<String>,
oninput: Option<EventHandler<Event<FormData>>>,
state: Option<Signal<D>>,
}
#[derive(Clone, PartialEq)]
pub struct TextInputState {
pub is_valid: bool,
pub helper_text: Option<String>,
}
impl TextInputState {
pub fn new() -> Self {
TextInputState {
is_valid: true,
helper_text: None,
}
}
pub fn reset(&mut self) {
self.is_valid = true;
self.helper_text = None;
}
pub fn invalidate(&mut self, helper_text: String) {
self.is_valid = false;
self.helper_text = Some(helper_text);
}
}
impl Default for TextInputState {
fn default() -> Self {
Self::new()
}
}
impl InputPropsData for TextInputState {}
pub fn TextInput(props: InputProps<TextInputState>) -> Element {
let mut criticity_class = "";
let mut helper_text = "".to_string();
if let Some(state) = props.state {
let state = state.read();
if !state.is_valid {
criticity_class = ClassName::INVALID;
}
if let Some(text) = &state.helper_text {
helper_text = text.to_string();
}
}
let input_classes_str = [ClassName::TEXT_INPUT_INPUT, criticity_class].join(" ");
rsx! {
style { {STYLE_SHEET} },
div {
class: ClassName::TEXT_INPUT,
input {
class: "{input_classes_str}",
r#type: "text",
placeholder: props.placeholder,
value: props.value,
oninput: move |evt| {
if let Some(cb) = &props.oninput {
cb.call(evt);
}
},
},
div {
class: ClassName::TEXT_INPUT_HELPER_TEXT,
p {
class: criticity_class,
{helper_text}
}
}
}
}
}
#[derive(Props, Clone, PartialEq)]
pub struct PasswordInputState {
text_input_state: TextInputState,
#[props(default = 0.0)]
pub score: f64,
}
impl PasswordInputState {
pub fn new() -> Self {
PasswordInputState {
text_input_state: TextInputState::new(),
score: 0.0,
}
}
pub fn reset(&mut self) {
self.text_input_state.reset()
}
pub fn invalidate(&mut self, helper_text: String) {
self.text_input_state.invalidate(helper_text)
}
}
impl Default for PasswordInputState {
fn default() -> Self {
Self::new()
}
}
impl InputPropsData for PasswordInputState {}
pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
let mut criticity_class = "";
let mut helper_text: String = "".to_string();
let mut score: Option<f64> = None;
let mut show_password = use_signal(|| false);
if let Some(state) = props.state {
let state = state.read();
if !state.text_input_state.is_valid {
criticity_class = ClassName::INVALID;
}
if let Some(text) = &state.text_input_state.helper_text {
helper_text = text.to_string();
}
score = Some(state.score);
}
let text_input_classes = [
ClassName::PASSWORD_TEXT_INPUT,
if score.is_none() {
ClassName::NO_STRENGTH
} else {
""
},
]
.join(" ");
let input_classes = [ClassName::PASSWORD_TEXT_INPUT_INPUT, criticity_class].join(" ");
rsx! {
style { {STYLE_SHEET} },
div {
class: "{text_input_classes}",
input {
class: "{input_classes}",
r#type: if *show_password.read() { "text" } else { "password" },
placeholder: props.placeholder,
value: props.value,
oninput: move |evt| {
if let Some(cb) = &props.oninput {
cb.call(evt);
}
},
},
if let Some(score) = score {
div {
class: ClassName::PASSWORD_TEXT_INPUT_STRENGTH_LEVEL,
Pyramid {
ratio: score,
}
}
},
div {
class: ClassName::PASSWORD_TEXT_INPUT_SHOW_TOGGLE,
onclick: move |_| {
let current_state = *show_password.read();
show_password.set(!current_state);
},
if *show_password.read() {
Icon {
icon: IoEyeOff,
}
}
else {
Icon {
icon: IoEye,
}
}
},
div {
class: ClassName::PASSWORD_TEXT_INPUT_HELPER_TEXT,
p {
class: criticity_class,
{helper_text}
}
},
}
}
}