Skip to content

Instantly share code, notes, and snippets.

@rebo
Last active June 19, 2020 05:58
Show Gist options
  • Save rebo/a556debf7b7508293d52bede5e1856cc to your computer and use it in GitHub Desktop.
Save rebo/a556debf7b7508293d52bede5e1856cc to your computer and use it in GitHub Desktop.
#[derive(Clone)]
struct Todo{
idx: usize,
description: String,
complete: bool,
}
// Atom of state, a vector holding Todo structs
#[state]
fn todos()-> Vec<Todo>{
vec![]
}
#[derive(Clone, PartialEq)]
enum FilterStatus {
ShowAll,
Complete,
Incomplete,
}
// The state of the chosen filter method, defaults to show all
#[state]
fn filter_state()-> FilterStatus {
FilterStatus::ShowAll
}
// Automatically computes filtered todos when (and only when todos are updated)
#[computed]
fn filtered_todos() -> Vec<Todo> {
let todos = link_state(todos());
let filter = link_state(filter_state());
match filter {
FilterStatus::ShowAll => todos,
FilterStatus::Complete => todos.iter().filter(|t| t.complete).cloned().collect::<Vec<_>>(),
FilterStatus::Incomplete => todos.iter().filter(|t| !t.complete).cloned().collect::<Vec<_>>(),
}
}
// Automatically generates a show-all button dependent upon the filter state
#[computed]
fn show_all_button() -> Node<Msg> {
let filter = link_state(filter_state());
fancy_button![
if filter == FilterStatus::ShowAll{
s().bg_color(rgb(0,255,0)).font_weight_v900()
} else {
s().bg_color(rgb(180,120,120))
},
"Show All",
mouse_ev(Ev::Click, |_|
filter_state().update(|s| *s = FilterStatus::ShowAll )
)
]
}
// Automatically generates a show-complete button dependent upon the filter state
#[computed]
fn show_complete_button() -> Node<Msg> {
let filter == link_state(filter_state());
fancy_button![
if filter = FilterStatus::Complete {
s().bg_color(rgb(0,255,0)).font_weight_v900()
} else {
s().bg_color(rgb(180,120,120))
},
"Show Complete",
mouse_ev(Ev::Click, |_|
filter_state().update(|s| *s = FilterStatus::Complete)
)
]
}
// Automatically generates a show-incomplete button snippet dependent upon the filter state
#[computed]
fn show_incomplete_button() -> Node<Msg> {
let filter = link_state(filter_state());
fancy_button![
if filter == FilterStatus::Incomplete{
s().bg_color(rgb(0,255,0)).font_weight_v900()
} else {
s().bg_color(rgb(180,120,120))
},
"Show Incomplete",
mouse_ev(Ev::Click, |_|
filter_state().update(|s| *s = FilterStatus::Incomplete)
)
]
}
// Input state for the button element, defaults to empty string
#[state]
fn todo_input_state() -> String {
"".to_string()
}
// Main view a column of items. Title, Input, Controls, then Todos.
pub fn view(_model: &Model) -> Node<Msg> {
Column![
Item![
align = ColumnAlign::TopCenter,
h1!["Todos"]
],
Item![
align = ColumnAlign::TopCenter,
flex = Flex::None,
input![
attrs!(At::Value => todo_input_state().get()),
s().b_style_solid().b_width(px(1)).b_color(seed_colors::Gray::No7),
input_ev(Ev::Input, |s| todo_input_state().update(|t| *t = s))
],
fancy_button![
s().bg_color(seed_colors::Blue::No4),
"Add Todo",
mouse_ev(Ev::Click, |_|
// if "add todo" is pressed then update the "todos" atom state.
// and clear the input atom state
todos().update(|t|{
t.push(
Todo {
idx: t.len(),
description: todo_input_state().get(),
complete: false,
}
);
todo_input_state().update(|t|
*t = "".to_string()
)
})
)
]
],
Item![
align = ColumnAlign::TopCenter,
flex = Flex::None,
show_all_button().get(),
show_complete_button().get(),
show_incomplete_button().get()
],
Item![
align = ColumnAlign::TopCenter,
filtered_todos().get().iter().map(|todo| {
let todo_idx = todo.idx;
li![
s().display_flex().justify_content_flex_end().align_content_center(),
center![todo.description.clone()],
fancy_button![
if todo.complete{
s().bg_color(seed_colors::Green::No4)
} else {
s().bg_color(seed_colors::Gray::No4)
}
,"X",
mouse_ev(Ev::Click, move |_| {
todos().update(|ts|
for t in ts.iter_mut(){
if t.idx == todo_idx {t.complete = !t.complete}
}
)
})
]
]
}
)
]
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment