Disambiguate expressions in rsx by requiring curlies
This commit is contained in:
53 files changed
+399
-373
No files matched your search
@@ -76,7 +76,11 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
"Hover, click, type or scroll to see the info down below"
|
||||
}
|
||||
div { events.read().iter().map(|event| rsx!( div { "{event:?}" } )) }
|
||||
div {
|
||||
for event in events.read().iter() {
|
||||
div { "{event:?}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
@@ -58,13 +58,13 @@ fn app(cx: Scope) -> Element {
|
||||
};
|
||||
|
||||
cx.render(rsx!(
|
||||
style { include_str!("./assets/calculator.css") }
|
||||
style { {include_str!("./assets/calculator.css")} }
|
||||
div { id: "wrapper",
|
||||
div { class: "app",
|
||||
div { class: "calculator",
|
||||
tabindex: "0",
|
||||
onkeydown: handle_key_down_event,
|
||||
div { class: "calculator-display", val.to_string() }
|
||||
div { class: "calculator-display", "{val}" }
|
||||
div { class: "calculator-keypad",
|
||||
div { class: "input-keys",
|
||||
div { class: "function-keys",
|
||||
@@ -103,14 +103,14 @@ fn app(cx: Scope) -> Element {
|
||||
div { class: "digit-keys",
|
||||
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
|
||||
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
|
||||
(1..10).map(|k| rsx!{
|
||||
for k in 1..10 {
|
||||
button {
|
||||
class: "calculator-key {k}",
|
||||
name: "key-{k}",
|
||||
onclick: move |_| input_digit(k),
|
||||
"{k}"
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class: "operator-keys",
|
||||
|
||||
+2
-2
@@ -32,12 +32,12 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
ul {
|
||||
emails_sent.read().iter().map(|message| cx.render(rsx! {
|
||||
for message in emails_sent.read().iter() {
|
||||
li {
|
||||
h3 { "email" }
|
||||
span {"{message}"}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ fn app(cx: Scope) -> Element {
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
||||
if let Some(element) = elements.read().get(focused) {
|
||||
element.set_focus(true);
|
||||
_ = element.set_focus(true).await;
|
||||
} else {
|
||||
focused = 0;
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ fn ClientList(cx: Scope) -> Element {
|
||||
Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" }
|
||||
Link { to: Route::Settings {}, class: "pure-button", "Settings" }
|
||||
|
||||
clients.read().iter().map(|client| rsx! {
|
||||
for client in clients.read().iter() {
|
||||
div {
|
||||
class: "client",
|
||||
style: "margin-bottom: 50px",
|
||||
@@ -70,7 +70,7 @@ fn ClientList(cx: Scope) -> Element {
|
||||
p { "Name: {client.first_name} {client.last_name}" }
|
||||
p { "Description: {client.description}" }
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -14,9 +14,9 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
render! {
|
||||
(0..count).map(|_| rsx!{
|
||||
{(0..count).map(|_| rsx!{
|
||||
drop_child {}
|
||||
})
|
||||
})}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -39,9 +39,9 @@ fn ChildWithRef(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
ul {
|
||||
names.read().iter().map(|f| rsx!{
|
||||
li { "hello: {f}" }
|
||||
})
|
||||
for name in names.read().iter() {
|
||||
li { "hello: {name}" }
|
||||
}
|
||||
}
|
||||
button {
|
||||
onclick: move |_| {
|
||||
|
||||
@@ -28,12 +28,12 @@ fn app(cx: Scope) -> Element {
|
||||
link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", }
|
||||
header {
|
||||
i { class: "material-icons icon-menu", "menu" }
|
||||
h1 { "Files: ", files.read().current() }
|
||||
h1 { "Files: ", {files.read().current()} }
|
||||
span { }
|
||||
i { class: "material-icons", onclick: move |_| files.write().go_up(), "logout" }
|
||||
}
|
||||
main {
|
||||
files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
|
||||
{files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
|
||||
let path_end = path.split('/').last().unwrap_or(path.as_str());
|
||||
let icon_type = if path_end.contains('.') {
|
||||
"description"
|
||||
@@ -52,15 +52,13 @@ fn app(cx: Scope) -> Element {
|
||||
h1 { "{path_end}" }
|
||||
}
|
||||
)
|
||||
}),
|
||||
files.read().err.as_ref().map(|err| {
|
||||
rsx! (
|
||||
div {
|
||||
code { "{err}" }
|
||||
button { onclick: move |_| files.write().clear_err(), "x" }
|
||||
}
|
||||
)
|
||||
})
|
||||
})},
|
||||
if let Some(err) = files.read().err.as_ref() {
|
||||
div {
|
||||
code { "{err}" }
|
||||
button { onclick: move |_| files.write().clear_err(), "x" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -66,9 +66,9 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
table {
|
||||
tbody {
|
||||
items.read().iter().enumerate().map(|(id, item)| {
|
||||
let is_in_danger = if (*selected).map(|s| s == id).unwrap_or(false) {"danger"} else {""};
|
||||
rsx!(tr { class: "{is_in_danger}",
|
||||
for (id, item) in items.read().iter().enumerate() {
|
||||
tr {
|
||||
class: if (*selected).map(|s| s == id).unwrap_or(false) { "danger" },
|
||||
td { class:"col-md-1" }
|
||||
td { class:"col-md-1", "{item.key}" }
|
||||
td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
|
||||
@@ -80,8 +80,9 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
}
|
||||
td { class: "col-md-6" }
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
span { class: "preloadicon glyphicon glyphicon-remove", aria_hidden: "true" }
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ const FIELDS: &[(&str, &str)] = &[
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div { margin_left: "30px",
|
||||
select_example(cx),
|
||||
{select_example(cx)},
|
||||
div {
|
||||
// handling inputs on divs will catch all input events below
|
||||
// so the value of our input event will be either huey, dewey, louie, or true/false (because of the checkboxe)
|
||||
@@ -114,7 +114,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
}
|
||||
|
||||
FIELDS.iter().map(|(field, value)| rsx! {
|
||||
for (field, value) in FIELDS.iter() {
|
||||
div {
|
||||
input {
|
||||
id: "{field}",
|
||||
@@ -131,7 +131,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
br {}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn LogOut(cx: Scope<ClientProps>) -> Element {
|
||||
}
|
||||
Err(error) => {
|
||||
rsx! {
|
||||
div { format!{"Failed to load disconnection url: {:?}", error} }
|
||||
div { "Failed to load disconnection url: {error:?}" }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -143,9 +143,9 @@ pub fn LoadClient(cx: Scope) -> Element {
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
log::info! {"Failed to load client: {:?}", error};
|
||||
rsx! {
|
||||
div { format!{"Failed to load client: {:?}", error} }
|
||||
log::info!{"Failed to load client: {:?}", error},
|
||||
div { "Failed to load client: {error:?}" }
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ pub fn AuthHeader(cx: Scope) -> Element {
|
||||
Ok(email) => {
|
||||
rsx! {
|
||||
div {
|
||||
div { email }
|
||||
div { {email} }
|
||||
LogOut { client_id: client_props.client_id, client: client_props.client }
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ pub fn AuthHeader(cx: Scope) -> Element {
|
||||
log::info!("Other issue with token");
|
||||
rsx! {
|
||||
div {
|
||||
div { error.to_string() }
|
||||
div { "{error}" }
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ use dioxus::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn NotFound(cx: Scope, route: Vec<String>) -> Element {
|
||||
let routes = route.join("");
|
||||
render! {rsx! {div{routes}}}
|
||||
render! {
|
||||
div{
|
||||
{route.join("")}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,11 @@ fn app(cx: Scope) -> Element {
|
||||
let state = use_ref(cx, Calculator::new);
|
||||
|
||||
cx.render(rsx! {
|
||||
style { include_str!("./assets/calculator.css") }
|
||||
style { {include_str!("./assets/calculator.css")} }
|
||||
div { id: "wrapper",
|
||||
div { class: "app",
|
||||
div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),
|
||||
div { class: "calculator-display", state.read().formatted_display() }
|
||||
div { class: "calculator-display", {state.read().formatted_display()} }
|
||||
div { class: "calculator-keypad",
|
||||
div { class: "input-keys",
|
||||
div { class: "function-keys",
|
||||
@@ -74,14 +74,14 @@ fn app(cx: Scope) -> Element {
|
||||
onclick: move |_| state.write().input_dot(),
|
||||
"●"
|
||||
}
|
||||
(1..10).map(move |k| rsx!{
|
||||
for k in 1..10 {
|
||||
CalculatorKey {
|
||||
key: "{k}",
|
||||
name: "key-{k}",
|
||||
onclick: move |_| state.write().input_digit(k),
|
||||
"{k}"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class: "operator-keys",
|
||||
@@ -130,7 +130,7 @@ fn CalculatorKey<'a>(cx: Scope<'a, CalculatorKeyProps<'a>>) -> Element {
|
||||
button {
|
||||
class: "calculator-key {cx.props.name}",
|
||||
onclick: move |e| cx.props.onclick.call(e),
|
||||
&cx.props.children
|
||||
{&cx.props.children}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
h1 {"Select an option"}
|
||||
h3 { "The radio is... ", state.is_playing(), "!" }
|
||||
h3 { "The radio is... ", {state.is_playing()}, "!" }
|
||||
button { onclick: move |_| state.make_mut().reduce(PlayerAction::Pause),
|
||||
"Pause"
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ impl FromQuery for ManualBlogQuerySegments {
|
||||
fn BlogPost(cx: Scope, query_params: ManualBlogQuerySegments) -> Element {
|
||||
render! {
|
||||
div{"This is your blogpost with a query segment:"}
|
||||
div{format!("{:?}", query_params)}
|
||||
div{ "{query_params:?}" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fn BlogPost(cx: Scope, query_params: ManualBlogQuerySegments) -> Element {
|
||||
fn AutomaticBlogPost(cx: Scope, name: String, surname: String) -> Element {
|
||||
render! {
|
||||
div{"This is your blogpost with a query segment:"}
|
||||
div{format!("name={}&surname={}", name, surname)}
|
||||
div{ "name={name}&surname={surname}" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,17 +36,17 @@ fn example(cx: Scope) -> Element {
|
||||
div { id: "asd",
|
||||
"your neighborhood spiderman"
|
||||
|
||||
items.iter().cycle().take(5).map(|f| rsx!{
|
||||
div { "{f.a}" }
|
||||
})
|
||||
for item in items.iter().cycle().take(5) {
|
||||
div { "{item.a}" }
|
||||
}
|
||||
|
||||
things_list.iter().map(|f| rsx!{
|
||||
div { "{f.a}" "{f.b}" }
|
||||
})
|
||||
for thing in things_list.iter() {
|
||||
div { "{thing.a}" "{thing.b}" }
|
||||
}
|
||||
|
||||
mything_read.as_ref().map(|f| rsx! {
|
||||
if let Some(f) = mything_read.as_ref() {
|
||||
div { "{f}" }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
|
||||
+17
-16
@@ -61,7 +61,7 @@ fn App(cx: Scope) -> Element {
|
||||
h1 {"Some text"}
|
||||
h1 {"Some text with {formatting}"}
|
||||
h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
||||
h1 {"Formatting without interpolation " formatting_tuple.0 "and" formatting_tuple.1 }
|
||||
h1 {"Formatting without interpolation " {formatting_tuple.0} "and" {formatting_tuple.1} }
|
||||
h2 {
|
||||
"Multiple"
|
||||
"Text"
|
||||
@@ -94,10 +94,10 @@ fn App(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
// Expressions can be used in element position too:
|
||||
rsx!(p { "More templating!" }),
|
||||
{rsx!(p { "More templating!" })},
|
||||
|
||||
// Iterators
|
||||
(0..10).map(|i| rsx!(li { "{i}" })),
|
||||
{(0..10).map(|i| rsx!(li { "{i}" }))},
|
||||
|
||||
// Iterators within expressions
|
||||
{
|
||||
@@ -117,24 +117,25 @@ fn App(cx: Scope) -> Element {
|
||||
// Conditional rendering
|
||||
// Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
|
||||
// You can convert a bool condition to rsx! with .then and .or
|
||||
true.then(|| rsx!(div {})),
|
||||
{true.then(|| rsx!(div {}))},
|
||||
|
||||
// Alternatively, you can use the "if" syntax - but both branches must be resolve to Element
|
||||
if false {
|
||||
rsx!(h1 {"Top text"})
|
||||
h1 {"Top text"}
|
||||
} else {
|
||||
rsx!(h1 {"Bottom text"})
|
||||
h1 {"Bottom text"}
|
||||
}
|
||||
|
||||
// Using optionals for diverging branches
|
||||
if true {
|
||||
// Note that since this is wrapped in curlies, it's interpreted as an expression
|
||||
{if true {
|
||||
Some(rsx!(h1 {"Top text"}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}}
|
||||
|
||||
// returning "None" without a diverging branch is a bit noisy... but rare in practice
|
||||
None as Option<()>,
|
||||
{None as Option<()>},
|
||||
|
||||
// can also just use empty fragments
|
||||
Fragment {}
|
||||
@@ -169,13 +170,13 @@ fn App(cx: Scope) -> Element {
|
||||
|
||||
// Can pass in props directly as an expression
|
||||
{
|
||||
let props = TallerProps {a: "hello", children: cx.render(rsx!(()))};
|
||||
let props = TallerProps {a: "hello", children: None };
|
||||
rsx!(Taller { ..props })
|
||||
}
|
||||
|
||||
// Spreading can also be overridden manually
|
||||
Taller {
|
||||
..TallerProps { a: "ballin!", children: cx.render(rsx!(()) )},
|
||||
..TallerProps { a: "ballin!", children: None },
|
||||
a: "not ballin!"
|
||||
}
|
||||
|
||||
@@ -204,16 +205,16 @@ fn App(cx: Scope) -> Element {
|
||||
|
||||
// helper functions
|
||||
// Anything that implements IntoVnode can be dropped directly into Rsx
|
||||
helper(cx, "hello world!")
|
||||
{helper(cx, "hello world!")}
|
||||
|
||||
// Strings can be supplied directly
|
||||
String::from("Hello world!")
|
||||
{String::from("Hello world!")}
|
||||
|
||||
// So can format_args
|
||||
format_args!("Hello {}!", "world")
|
||||
{format_args!("Hello {}!", "world")}
|
||||
|
||||
// Or we can shell out to a helper function
|
||||
format_dollars(10, 50)
|
||||
{format_dollars(10, 50)}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -269,7 +270,7 @@ pub struct TallerProps<'a> {
|
||||
#[component]
|
||||
pub fn Taller<'a>(cx: Scope<'a, TallerProps<'a>>) -> Element {
|
||||
cx.render(rsx! {
|
||||
&cx.props.children
|
||||
{&cx.props.children}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ fn app(cx: Scope) -> Element {
|
||||
button {
|
||||
onclick: move |_| {
|
||||
if let Some(header) = header_element.read().as_ref() {
|
||||
header.scroll_to(ScrollBehavior::Smooth);
|
||||
_ = header.scroll_to(ScrollBehavior::Smooth);
|
||||
}
|
||||
},
|
||||
"Scroll to top"
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// We can do boolean operations on the current signal value
|
||||
if count.value() > 5 {
|
||||
rsx!{ h2 { "High five!" } }
|
||||
h2 { "High five!" }
|
||||
}
|
||||
|
||||
// We can cleanly map signals with iterators
|
||||
@@ -41,9 +41,9 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// We can also use the signal value as a slice
|
||||
if let [ref first, .., ref last] = saved_values.read().as_slice() {
|
||||
rsx! { li { "First and last: {first}, {last}" } }
|
||||
li { "First and last: {first}, {last}" }
|
||||
} else {
|
||||
rsx! { "No saved values" }
|
||||
"No saved values"
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -8,17 +8,17 @@ fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
// Use Map directly to lazily pull elements
|
||||
(0..10).map(|f| rsx! { "{f}" }),
|
||||
{(0..10).map(|f| rsx! { "{f}" })},
|
||||
|
||||
// Collect into an intermediate collection if necessary, and call into_iter
|
||||
["a", "b", "c", "d", "e", "f"]
|
||||
{["a", "b", "c", "d", "e", "f"]
|
||||
.into_iter()
|
||||
.map(|f| rsx! { "{f}" })
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter(),
|
||||
.into_iter()},
|
||||
|
||||
// Use optionals
|
||||
Some(rsx! { "Some" }),
|
||||
{Some(rsx! { "Some" })},
|
||||
|
||||
// use a for loop where the body itself is RSX
|
||||
for name in 0..10 {
|
||||
@@ -27,7 +27,7 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// Or even use an unterminated conditional
|
||||
if true {
|
||||
rsx!{ "hello world!" }
|
||||
"hello world!"
|
||||
}
|
||||
}
|
||||
))
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ pub fn Die<'a>(cx: Scope<'a, DieProps<'a>>) -> Element {
|
||||
fill: "{fill}",
|
||||
}
|
||||
|
||||
dots
|
||||
{dots}
|
||||
}
|
||||
})
|
||||
}
|
||||
+33
-35
@@ -52,30 +52,30 @@ pub fn app(cx: Scope<()>) -> Element {
|
||||
TodoHeader { todos: todos }
|
||||
section { class: "main",
|
||||
if !todos.is_empty() {
|
||||
rsx! {
|
||||
input {
|
||||
id: "toggle-all",
|
||||
class: "toggle-all",
|
||||
r#type: "checkbox",
|
||||
onchange: move |_| {
|
||||
let check = active_todo_count != 0;
|
||||
for (_, item) in todos.make_mut().iter_mut() {
|
||||
item.checked = check;
|
||||
}
|
||||
},
|
||||
checked: if active_todo_count == 0 { "true" } else { "false" },
|
||||
}
|
||||
label { r#for: "toggle-all" }
|
||||
input {
|
||||
id: "toggle-all",
|
||||
class: "toggle-all",
|
||||
r#type: "checkbox",
|
||||
onchange: move |_| {
|
||||
let check = active_todo_count != 0;
|
||||
for (_, item) in todos.make_mut().iter_mut() {
|
||||
item.checked = check;
|
||||
}
|
||||
},
|
||||
checked: if active_todo_count == 0 { "true" } else { "false" },
|
||||
}
|
||||
label { r#for: "toggle-all" }
|
||||
}
|
||||
ul { class: "todo-list",
|
||||
filtered_todos.iter().map(|id| rsx!(TodoEntry {
|
||||
key: "{id}",
|
||||
id: *id,
|
||||
todos: todos,
|
||||
}))
|
||||
for id in filtered_todos.iter() {
|
||||
TodoEntry {
|
||||
key: "{id}",
|
||||
id: *id,
|
||||
todos: todos,
|
||||
}
|
||||
}
|
||||
}
|
||||
(!todos.is_empty()).then(|| rsx!(
|
||||
if !todos.is_empty() {
|
||||
ListFooter {
|
||||
active_todo_count: active_todo_count,
|
||||
active_todo_text: active_todo_text,
|
||||
@@ -83,7 +83,7 @@ pub fn app(cx: Scope<()>) -> Element {
|
||||
todos: todos,
|
||||
filter: filter,
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
PageFooter {}
|
||||
@@ -172,7 +172,7 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
|
||||
prevent_default: "onclick"
|
||||
}
|
||||
}
|
||||
is_editing.then(|| rsx!{
|
||||
if **is_editing {
|
||||
input {
|
||||
class: "edit",
|
||||
value: "{todo.contents}",
|
||||
@@ -186,7 +186,7 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -220,29 +220,27 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element {
|
||||
}
|
||||
ul { class: "filters",
|
||||
for (state , state_text , url) in [
|
||||
(FilterState::All, "All", "#/"),
|
||||
(FilterState::Active, "Active", "#/active"),
|
||||
(FilterState::Completed, "Completed", "#/completed"),
|
||||
] {
|
||||
(FilterState::All, "All", "#/"),
|
||||
(FilterState::Active, "Active", "#/active"),
|
||||
(FilterState::Completed, "Completed", "#/completed"),
|
||||
] {
|
||||
li {
|
||||
a {
|
||||
href: url,
|
||||
class: selected(state),
|
||||
onclick: move |_| cx.props.filter.set(state),
|
||||
prevent_default: "onclick",
|
||||
state_text
|
||||
{state_text}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if cx.props.show_clear_completed {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "clear-completed",
|
||||
onclick: move |_| cx.props.todos.make_mut().retain(|_, todo| !todo.checked),
|
||||
"Clear completed"
|
||||
}
|
||||
})
|
||||
button {
|
||||
class: "clear-completed",
|
||||
onclick: move |_| cx.props.todos.make_mut().retain(|_, todo| !todo.checked),
|
||||
"Clear completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user