feat: implement radio button element and rename checkbox
This commit is contained in:
1 parent
4985e1596c
commit
2befd9225c
3 files changed
+17
-111
No files matched your search
@@ -1,99 +0,0 @@
|
|||||||
use leptos::prelude::*;
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn Checkbox(
|
|
||||||
#[prop()] checked: Signal<bool>,
|
|
||||||
#[prop(into)] on_change: Callback<(), ()>,
|
|
||||||
#[prop(into)] value: String,
|
|
||||||
#[prop(default = RwSignal::new(false))] disabled: RwSignal<bool>,
|
|
||||||
) -> impl IntoView {
|
|
||||||
view! {
|
|
||||||
<label for=value
|
|
||||||
class="flex items-center">
|
|
||||||
<input
|
|
||||||
// Using the "peer" class links this input with the div "peer" at the same level.
|
|
||||||
// By using the "peer-checked" selector this div can toggle states based on this
|
|
||||||
// input's state (checked/unchecked)
|
|
||||||
class="
|
|
||||||
relative peer shrink-0
|
|
||||||
hidden"
|
|
||||||
type="checkbox"
|
|
||||||
id={value.clone()}
|
|
||||||
on:change = move |_| on_change.run(())
|
|
||||||
prop:checked = checked
|
|
||||||
disabled = disabled
|
|
||||||
/>
|
|
||||||
// This div displays the box for the checkbox, and applies some styling to the child
|
|
||||||
// span element.
|
|
||||||
<div
|
|
||||||
class="relative inline-block h-5 w-5 m-1 mr-2 rounded-sm border border-gray-300 bg-white
|
|
||||||
transition-bg duration-150 peer-checked:bg-red-700 peer-checked:border-red-700
|
|
||||||
[&>span]:opacity-0 peer-checked:[&>span]:opacity-100
|
|
||||||
peer-disabled:bg-gray-600/33 peer-disabled:border-gray-600
|
|
||||||
peer-disabled:peer-checked:bg-gray-600"
|
|
||||||
>
|
|
||||||
// This span is the check icon. It is centered within the div and has a border on the bottom
|
|
||||||
// and right sides, which is then rotated to appear like a checkmark.
|
|
||||||
<span
|
|
||||||
class="absolute left-1/2 top-1/2 block h-3 w-1.5 -translate-x-1/2 -translate-y-1/2
|
|
||||||
rotate-45 transform border-b-3 border-r-3
|
|
||||||
border-white transition-opacity duration-150"
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
<span>{value.clone()}</span>
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn CheckboxList(
|
|
||||||
#[prop(default = RwSignal::new(vec![]))] selected: RwSignal<Vec<String>>,
|
|
||||||
#[prop()] items: Vec<String>,
|
|
||||||
#[prop(default = RwSignal::new(false))] disabled: RwSignal<bool>,
|
|
||||||
) -> impl IntoView {
|
|
||||||
view! {
|
|
||||||
// Checkbox elements go in here. Each one will have a derived signal
|
|
||||||
// that checks if the name/value of that checkbox is in the selected items
|
|
||||||
// vec. If so, display as selected. If not, clear that checkbox.
|
|
||||||
|
|
||||||
// Somehow create a derived signal??
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{
|
|
||||||
items.into_iter().map(|item| {
|
|
||||||
let is_checked = {
|
|
||||||
let item_name = item.clone();
|
|
||||||
move || {
|
|
||||||
// Check if this checkbox should be selected
|
|
||||||
selected.get().contains(&item_name)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let checked_signal = Signal::derive(is_checked);
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<Checkbox
|
|
||||||
checked = checked_signal
|
|
||||||
on_change = {
|
|
||||||
// Clone this value to avoid moving it into the closure
|
|
||||||
let item_name = item.clone();
|
|
||||||
move || {
|
|
||||||
selected.update(|list| {
|
|
||||||
// Check if the list contains this element. If so, remove it. If not, add it.
|
|
||||||
if let Some(index) = list.iter().position(|val| *val == item_name) {
|
|
||||||
list.remove(index);
|
|
||||||
} else {
|
|
||||||
list.push(item_name.clone());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The actual selected values are tracked by this element, not by the checkboxes themselves.
|
|
||||||
value = item.clone()
|
|
||||||
disabled = disabled />
|
|
||||||
}
|
|
||||||
}).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+6
-11
@@ -1,19 +1,14 @@
|
|||||||
mod action_button;
|
mod action_button;
|
||||||
|
mod checkbox;
|
||||||
mod loading;
|
mod loading;
|
||||||
mod multi_entry;
|
mod multi_entry;
|
||||||
mod text_field;
|
|
||||||
mod select;
|
|
||||||
mod checkboxes;
|
|
||||||
mod panel;
|
mod panel;
|
||||||
|
mod radio;
|
||||||
mod row;
|
mod row;
|
||||||
|
mod select;
|
||||||
|
mod text_field;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
action_button::*,
|
action_button::*, checkbox::*, loading::*, multi_entry::*, panel::*, radio::*, row::*,
|
||||||
loading::*,
|
select::*, text_field::*,
|
||||||
multi_entry::*,
|
|
||||||
text_field::*,
|
|
||||||
select::*,
|
|
||||||
checkboxes::*,
|
|
||||||
panel::*,
|
|
||||||
row::*
|
|
||||||
};
|
};
|
||||||
+11
-1
@@ -9,6 +9,7 @@ use crate::app::Unauthenticated;
|
|||||||
use crate::common::{StudentInfo, StudentInfoReactive, UserClaims};
|
use crate::common::{StudentInfo, StudentInfoReactive, UserClaims};
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
ActionButton, CheckboxList, Loading, OutlinedTextField, Panel, Row, Select,
|
ActionButton, CheckboxList, Loading, OutlinedTextField, Panel, Row, Select,
|
||||||
|
RadioList
|
||||||
};
|
};
|
||||||
use leptos::leptos_dom::logging::console_log;
|
use leptos::leptos_dom::logging::console_log;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
@@ -122,6 +123,7 @@ pub fn HomePage() -> impl IntoView {
|
|||||||
let select_value = RwSignal::new(String::from("Math"));
|
let select_value = RwSignal::new(String::from("Math"));
|
||||||
let chk_select = RwSignal::new(vec!["Testing 2".into()]);
|
let chk_select = RwSignal::new(vec!["Testing 2".into()]);
|
||||||
let elements_disabled = RwSignal::new(false);
|
let elements_disabled = RwSignal::new(false);
|
||||||
|
let radio_value = RwSignal::new(String::from("Test"));
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
@@ -171,6 +173,14 @@ pub fn HomePage() -> impl IntoView {
|
|||||||
value=select_value
|
value=select_value
|
||||||
disabled=elements_disabled
|
disabled=elements_disabled
|
||||||
/>
|
/>
|
||||||
|
<RadioList
|
||||||
|
selected=radio_value
|
||||||
|
items=vec!["Test", "Testing 2"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.into())
|
||||||
|
.collect()
|
||||||
|
disabled=elements_disabled
|
||||||
|
/>
|
||||||
<CheckboxList
|
<CheckboxList
|
||||||
selected=chk_select
|
selected=chk_select
|
||||||
items=vec!["Testing 1", "Testing 2"]
|
items=vec!["Testing 1", "Testing 2"]
|
||||||
@@ -183,7 +193,7 @@ pub fn HomePage() -> impl IntoView {
|
|||||||
<Row>
|
<Row>
|
||||||
<ActionButton on:click=move |_| {
|
<ActionButton on:click=move |_| {
|
||||||
console_log(
|
console_log(
|
||||||
format!("Found value {:?}", chk_select.get()).as_str(),
|
format!("Found value {:?}", radio_value.get()).as_str(),
|
||||||
);
|
);
|
||||||
submit_action
|
submit_action
|
||||||
.dispatch(CreateSampleSubmission {
|
.dispatch(CreateSampleSubmission {
|
||||||
|
|||||||
Reference in new issue
Block a user