diff --git a/smart-house-web/frontend/src/main.rs b/smart-house-web/frontend/src/main.rs
index 86338a8..50fccde 100644
--- a/smart-house-web/frontend/src/main.rs
+++ b/smart-house-web/frontend/src/main.rs
@@ -1,61 +1,156 @@
+#![allow(non_snake_case)]
use leptos::prelude::*;
-#[allow(non_snake_case)]
-// Composing different components together is how we build
-// user interfaces. Here, we'll define a reusable .
-// You'll see how doc comments can be used to document components
-// and their properties.
-
-/// Shows progress toward a goal.
-#[component]
-fn ProgressBar(
- // Marks this as an optional prop. It will default to the default
- // value of its type, i.e., 0.
- #[prop(default = 100)]
- /// The maximum value of the progress bar.
- max: u16,
- // Will run `.into()` on the value passed into the prop.
- #[prop(into)]
- // `Signal` is a wrapper for several reactive types.
- // It can be helpful in component APIs like this, where we
- // might want to take any kind of reactive value
- /// How much progress should be displayed.
- progress: Signal,
-) -> impl IntoView {
- view! {
-
-
- }
-}
+// Iteration is a very common task in most applications.
+// So how do you take a list of data and render it in the DOM?
+// This example will show you the two ways:
+// 1) for mostly-static lists, using Rust iterators
+// 2) for lists that grow, shrink, or move items, using
#[component]
fn App() -> impl IntoView {
- let (count, set_count) = signal(0);
+ view! {
+
"Iteration"
+
"Static List"
+
"Use this pattern if the list itself is static."
+
+
"Dynamic List"
+
"Use this pattern if the rows in your list will change."
+
+ }
+}
- let double_count = move || count.get() * 2;
+/// A list of counters, without the ability
+/// to add or remove any.
+#[component]
+fn StaticList(
+ /// How many counters to include in this list.
+ length: usize,
+) -> impl IntoView {
+ // create counter signals that start at incrementing numbers
+ let counters = (1..=length).map(|idx| RwSignal::new(idx));
+
+ // when you have a list that doesn't change, you can
+ // manipulate it using ordinary Rust iterators
+ // and collect it into a Vec<_> to insert it into the DOM
+ let counter_buttons = counters
+ .map(|count| {
+ view! {
+
+
+
+ }
+ })
+ .collect::>();
+
+ // Note that if `counter_buttons` were a reactive list
+ // and its value changed, this would be very inefficient:
+ // it would rerender every row every time the list changed.
+ view! {
+
{counter_buttons}
+ }
+}
+
+/// A list of counters that allows you to add or
+/// remove counters.
+#[component]
+fn DynamicList(
+ /// The number of counters to begin with.
+ initial_length: usize,
+) -> impl IntoView {
+ // This dynamic list will use the component.
+ // is a keyed list. This means that each row
+ // has a defined key. If the key does not change, the row
+ // will not be re-rendered. When the list changes, only
+ // the minimum number of changes will be made to the DOM.
+
+ // `next_counter_id` will let us generate unique IDs
+ // we do this by simply incrementing the ID by one
+ // each time we create a counter
+ let mut next_counter_id = initial_length;
+
+ // we generate an initial list as in
+ // but this time we include the ID along with the signal
+ // see NOTE in add_counter below re: ArcRwSignal
+ let initial_counters = (0..initial_length)
+ .map(|id| (id, ArcRwSignal::new(id + 1)))
+ .collect::>();
+
+ // now we store that initial list in a signal
+ // this way, we'll be able to modify the list over time,
+ // adding and removing counters, and it will change reactively
+ let (counters, set_counters) = signal(initial_counters);
+
+ let add_counter = move |_| {
+ // create a signal for the new counter
+ // we use ArcRwSignal here, instead of RwSignal
+ // ArcRwSignal is a reference-counted type, rather than the arena-allocated
+ // signal types we've been using so far.
+ // When we're creating a collection of signals like this, using ArcRwSignal
+ // allows each signal to be deallocated when its row is removed.
+ let sig = ArcRwSignal::new(next_counter_id + 1);
+ // add this counter to the list of counters
+ set_counters.update(move |counters| {
+ // since `.update()` gives us `&mut T`
+ // we can just use normal Vec methods like `push`
+ counters.push((next_counter_id, sig))
+ });
+ // increment the ID so it's always unique
+ next_counter_id += 1;
+ };
view! {
-
-
- // If you have this open in CodeSandbox or an editor with
- // rust-analyzer support, try hovering over `ProgressBar`,
- // `max`, or `progress` to see the docs we defined above
-
- // Let's use the default max value on this one
- // the default is 100, so it should move half as fast
-
- // Signal::derive creates a Signal wrapper from our derived signal
- // using double_count means it should move twice as fast
-
+
+
+
+ // The component is central here
+ // This allows for efficient, key list rendering
+ instead of
+ each=move || counters.get()
+ // the key should be unique and stable for each row
+ // using an index is usually a bad idea, unless your list
+ // can only grow, because moving items around inside the list
+ // means their indices will change and they will all rerender
+ key=|counter| counter.0
+ // `children` receives each item from your `each` iterator
+ // and returns a view
+ children=move |(id, count)| {
+ // we can convert our ArcRwSignal to a Copy-able RwSignal
+ // for nicer DX when moving it into the view
+ let count = RwSignal::from(count);
+ view! {
+