diff --git a/README.md b/README.md
index 7fab878e7193874c455a1e2f66dbebab687dc755..86370f05afaf6cb9a6766de1f20b5b7f2e0000f6 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,62 @@
-# Aep Schedule Generator Rusty
+# Générateur d'horaire de l'AEP v2
 
-**Disclaimer** This is not yet the official AEP schedule.
+## 🛠️ Objectif du projet
 
-## The Stack
-The stack is LAC (Leptos + Axum + CSV)
+Le Générateur d'horaire de l'AEP v2 est une refonte complète du générateur d'horaire étudiant, conçu pour être rapide, flexible et accessible. Ce projet modernise une base de code vieille de 15 ans et optimise l'expérience utilisateur en adoptant des technologies modernes.
 
+## ❓ FAQ
 
-Leptos is a great frontend framework in Rust with web assembly to make a responsive UI. Axum is the fast backend serving the HTTP in Rust. The storage is done with CSV, but that's only because Poly give us CSV to represent all the courses.
+### Pourquoi une refonte complète ?
 
-## Programming Languages used to make this
-- Rust
+L'ancien générateur, en maintenance depuis plus de 15 ans, était obsolète avec une base de code mêlant 5 langages différents. Une refonte était essentielle pour garantir la maintenabilité et améliorer les performances.
 
-## Credit
-Marc-Antoine Manningham for the backend and the frontend
+### Comment est-il aussi rapide ?
 
-Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier and Gabriel Billard have made a figma that's the inspiration for the style
\ No newline at end of file
+- **Traitement local** : Les horaires sont générés directement dans le navigateur via WebAssembly, éliminant les délais liés aux serveurs.
+- **Optimisation intelligente** : Seuls les meilleurs horaires sont calculés, grâce à des algorithmes comme le *branch and bound* pour réduire l'espace de recherche et respecter les contraintes définies.
+
+### Où puis-je soumettre des suggestions ou rapports de bugs ?
+
+- Utilisez le bouton **Signaler un bug** pour soumettre vos idées ou signaler un problème.
+- Contributions bienvenues ! Rejoignez-nous si vous avez des compétences en Rust.
+
+## 👥 Crédits
+
+- **Développement** : Marc-Antoine Manningham (front-end & back-end)
+- **Design** : Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier et Gabriel Billard, inspirés par leur maquette Figma.
+
+
+Voici une version mise à jour du README, incluant des instructions pour l'auto-hébergement avec Docker :
+
+## ⚙️ Auto-hébergement avec Docker
+
+### Prérequis
+
+1. **Docker** : Assurez-vous que Docker est installé. [Installation Docker](https://docs.docker.com/get-docker/)
+2. **Docker Compose** : (optionnel, selon votre configuration).
+
+### Instructions
+
+1. **Téléchargez et exécutez l'image Docker** :
+   ```bash
+   docker pull git.step.polymtl.ca/Lemark/aep-schedule-generator:latest
+   docker run -d -p 8080:8080 --name aep-schedule-generator git.step.polymtl.ca/Lemark/aep-schedule-generator:latest
+   ```
+
+2. **Accédez à l'application** :
+   Ouvrez votre navigateur à l'adresse [http://localhost:8080](http://localhost:8080).
+
+3. **Configurer avec Docker Compose** (facultatif) :
+   Créez un fichier `docker-compose.yml` :
+   ```yaml
+   version: '3'
+   services:
+     aep-schedule-generator:
+       image: git.step.polymtl.ca/Lemark/aep-schedule-generator:latest
+       ports:
+         - "8080:8080"
+   ```
+   Lancez les services :
+   ```bash
+   docker-compose up -d
+   ```
diff --git a/aep-schedule-website/Cargo.lock b/aep-schedule-website/Cargo.lock
index 4326bf6a2b803d36a904fe0b0871f1501b3fe6ab..02bb657a0fa539239d051b2dc1325c4272b15bb8 100644
--- a/aep-schedule-website/Cargo.lock
+++ b/aep-schedule-website/Cargo.lock
@@ -4,19 +4,13 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.22.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "gimli",
 ]
 
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
 [[package]]
 name = "adler2"
 version = "2.0.0"
@@ -54,10 +48,10 @@ dependencies = [
  "reqwest",
  "serde",
  "simple_logger",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
- "tower 0.5.0",
- "tower-http",
+ "tower",
+ "tower-http 0.5.2",
  "tracing",
  "url-escape",
  "wasm-bindgen",
@@ -126,9 +120,9 @@ dependencies = [
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.18"
+version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "android-tzdata"
@@ -145,17 +139,29 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "any_spawner"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41058deaa38c9d9dd933d6d238d825227cffa668e2839b52879f6619c63eee3b"
+dependencies = [
+ "futures",
+ "thiserror 2.0.6",
+ "tokio",
+ "wasm-bindgen-futures",
+]
+
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
 
 [[package]]
 name = "arrayref"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
 
 [[package]]
 name = "arrayvec"
@@ -165,9 +171,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
 [[package]]
 name = "async-compression"
-version = "0.4.12"
+version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa"
+checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522"
 dependencies = [
  "flate2",
  "futures-core",
@@ -177,25 +183,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "async-recursion"
-version = "1.1.1"
+name = "async-lock"
+version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
+checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.76",
+ "event-listener",
+ "event-listener-strategy",
+ "pin-project-lite",
 ]
 
 [[package]]
 name = "async-trait"
-version = "0.1.81"
+version = "0.1.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -206,45 +212,45 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
 [[package]]
 name = "attribute-derive"
-version = "0.9.2"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f1ee502851995027b06f99f5ffbeffa1406b38d0b318a1ebfa469332c6cbafd"
+checksum = "0053e96dd3bec5b4879c23a138d6ef26f2cb936c9cdc96274ac2b9ed44b5bb54"
 dependencies = [
  "attribute-derive-macro",
  "derive-where",
  "manyhow",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "attribute-derive-macro"
-version = "0.9.2"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3601467f634cfe36c4780ca9c75dea9a5b34529c1f2810676a337e7e0997f954"
+checksum = "463b53ad0fd5b460af4b1915fe045ff4d946d025fb6c4dc3337752eaa980f71b"
 dependencies = [
  "collection_literals",
  "interpolator",
  "manyhow",
- "proc-macro-utils 0.8.0",
+ "proc-macro-utils",
  "proc-macro2",
  "quote",
  "quote-use",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "axum"
-version = "0.7.5"
+version = "0.7.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
 dependencies = [
  "async-trait",
  "axum-core",
@@ -268,9 +274,9 @@ dependencies = [
  "serde_json",
  "serde_path_to_error",
  "serde_urlencoded",
- "sync_wrapper 1.0.1",
+ "sync_wrapper 1.0.2",
  "tokio",
- "tower 0.4.13",
+ "tower",
  "tower-layer",
  "tower-service",
  "tracing",
@@ -278,9 +284,9 @@ dependencies = [
 
 [[package]]
 name = "axum-core"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
+checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
 dependencies = [
  "async-trait",
  "bytes",
@@ -291,7 +297,7 @@ dependencies = [
  "mime",
  "pin-project-lite",
  "rustversion",
- "sync_wrapper 0.1.2",
+ "sync_wrapper 1.0.2",
  "tower-layer",
  "tower-service",
  "tracing",
@@ -299,29 +305,28 @@ dependencies = [
 
 [[package]]
 name = "axum-macros"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa"
+checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
 dependencies = [
- "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "backtrace"
-version = "0.3.73"
+version = "0.3.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 dependencies = [
  "addr2line",
- "cc",
  "cfg-if",
  "libc",
- "miniz_oxide 0.7.4",
+ "miniz_oxide",
  "object",
  "rustc-demangle",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -344,9 +349,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
 
 [[package]]
 name = "binstring"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e0d60973d9320722cb1206f412740e162a33b8547ea8d6be75d7cff237c7a85"
+checksum = "ed79c2a8151273c70956b5e3cdfdc1ff6c1a8b9779ba59c6807d281b32ee2f86"
 
 [[package]]
 name = "bitflags"
@@ -388,41 +393,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
-
-[[package]]
-name = "cached"
-version = "0.45.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90eb5776f28a149524d1d8623035760b4454ec881e8cf3838fa8d7e1b11254b3"
-dependencies = [
- "cached_proc_macro",
- "cached_proc_macro_types",
- "hashbrown 0.13.2",
- "instant",
- "once_cell",
- "thiserror",
-]
-
-[[package]]
-name = "cached_proc_macro"
-version = "0.18.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "cached_proc_macro_types"
-version = "0.1.1"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
 
 [[package]]
 name = "camino"
@@ -441,9 +414,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.14"
+version = "1.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932"
+checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
 dependencies = [
  "shlex",
 ]
@@ -456,9 +429,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -479,33 +452,6 @@ dependencies = [
  "stacker",
 ]
 
-[[package]]
-name = "ciborium"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
-dependencies = [
- "ciborium-io",
- "ciborium-ll",
- "serde",
-]
-
-[[package]]
-name = "ciborium-io"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
-
-[[package]]
-name = "ciborium-ll"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
-dependencies = [
- "ciborium-io",
- "half",
-]
-
 [[package]]
 name = "cipher"
 version = "0.4.4"
@@ -518,15 +464,26 @@ dependencies = [
 
 [[package]]
 name = "coarsetime"
-version = "0.1.34"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13b3839cf01bb7960114be3ccf2340f541b6d0c81f8690b007b2b39f750f7e5d"
+checksum = "4252bf230cb600c19826a575b31c8c9c84c6f11acfab6dfcad2e941b10b6f8e2"
 dependencies = [
  "libc",
  "wasix",
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "codee"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d3ad3122b0001c7f140cf4d605ef9a9e2c24d96ab0b4fb4347b76de2425f445"
+dependencies = [
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+]
+
 [[package]]
 name = "collection_literals"
 version = "1.0.1"
@@ -558,14 +515,22 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "concurrent-queue"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+dependencies = [
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "config"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
+checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf"
 dependencies = [
  "convert_case",
- "lazy_static",
  "nom",
  "pathdiff",
  "serde",
@@ -600,29 +565,35 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
 [[package]]
 name = "const_format"
-version = "0.2.32"
+version = "0.2.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
+checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd"
 dependencies = [
  "const_format_proc_macros",
 ]
 
 [[package]]
 name = "const_format_proc_macros"
-version = "0.2.32"
+version = "0.2.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
+checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-xid",
 ]
 
+[[package]]
+name = "const_str_slice_concat"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b"
+
 [[package]]
 name = "constant_time_eq"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
 
 [[package]]
 name = "convert_case"
@@ -651,9 +622,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.13"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
 dependencies = [
  "libc",
 ]
@@ -668,10 +639,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "crunchy"
-version = "0.2.2"
+name = "crossbeam-utils"
+version = "0.8.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 
 [[package]]
 name = "crypto-bigint"
@@ -698,9 +669,9 @@ dependencies = [
 
 [[package]]
 name = "ct-codecs"
-version = "1.1.1"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
+checksum = "b916ba8ce9e4182696896f015e8a5ae6081b305f74690baa8465e35f5a142ea4"
 
 [[package]]
 name = "ctr"
@@ -711,48 +682,14 @@ dependencies = [
  "cipher",
 ]
 
-[[package]]
-name = "darling"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
-dependencies = [
- "darling_core",
- "darling_macro",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
-dependencies = [
- "darling_core",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "dashmap"
-version = "5.5.3"
+version = "6.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
 dependencies = [
  "cfg-if",
+ "crossbeam-utils",
  "hashbrown 0.14.5",
  "lock_api",
  "once_cell",
@@ -787,7 +724,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -802,6 +739,17 @@ dependencies = [
  "subtle",
 ]
 
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "drain_filter_polyfill"
 version = "0.1.3"
@@ -849,6 +797,15 @@ version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 
+[[package]]
+name = "either_of"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d1e2e7b8b6deaf1ae68f1d8796dec8732cff85d27fdbf4bc4460145a067ed0b"
+dependencies = [
+ "pin-project-lite",
+]
+
 [[package]]
 name = "elliptic-curve"
 version = "0.13.8"
@@ -872,9 +829,9 @@ dependencies = [
 
 [[package]]
 name = "email-encoding"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60d1d33cdaede7e24091f039632eb5d3c7469fe5b066a985281a34fc70fa317f"
+checksum = "ea3d894bbbab314476b265f9b2d46bf24b123a36dd0e96b06a1b49545b9d9dcc"
 dependencies = [
  "base64",
  "memchr",
@@ -888,9 +845,9 @@ checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
 
 [[package]]
 name = "encoding_rs"
-version = "0.8.34"
+version = "0.8.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
 dependencies = [
  "cfg-if",
 ]
@@ -903,19 +860,40 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "event-listener"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
+dependencies = [
+ "event-listener",
+ "pin-project-lite",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.1.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "ff"
@@ -929,12 +907,12 @@ dependencies = [
 
 [[package]]
 name = "flate2"
-version = "1.0.33"
+version = "1.0.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
 dependencies = [
  "crc32fast",
- "miniz_oxide 0.8.0",
+ "miniz_oxide",
 ]
 
 [[package]]
@@ -969,9 +947,9 @@ dependencies = [
 
 [[package]]
 name = "futures"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -984,9 +962,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -994,55 +972,56 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
 dependencies = [
  "futures-core",
  "futures-task",
  "futures-util",
+ "num_cpus",
 ]
 
 [[package]]
 name = "futures-io"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
 
 [[package]]
 name = "futures-task"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 
 [[package]]
 name = "futures-util"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -1092,9 +1071,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.29.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "gloo-net"
@@ -1111,7 +1090,7 @@ dependencies = [
  "pin-project",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "web-sys",
@@ -1141,11 +1120,17 @@ dependencies = [
  "subtle",
 ]
 
+[[package]]
+name = "guardian"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "493913a18c0d7bebb75127a26a432162c59edbe06f6cf712001e3e769345e8b5"
+
 [[package]]
 name = "h2"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
 dependencies = [
  "atomic-waker",
  "bytes",
@@ -1160,22 +1145,6 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "half"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
-dependencies = [
- "cfg-if",
- "crunchy",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-
 [[package]]
 name = "hashbrown"
 version = "0.14.5"
@@ -1187,10 +1156,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "heck"
-version = "0.4.1"
+name = "hashbrown"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 
 [[package]]
 name = "hermit-abi"
@@ -1218,24 +1187,24 @@ dependencies = [
 
 [[package]]
 name = "hmac-sha1-compact"
-version = "1.1.4"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9d405ec732fa3fcde87264e54a32a84956a377b3e3107de96e59b798c84a7"
+checksum = "18492c9f6f9a560e0d346369b665ad2bdbc89fa9bceca75796584e79042694c3"
 
 [[package]]
 name = "hmac-sha256"
-version = "1.1.7"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3688e69b38018fec1557254f64c8dc2cc8ec502890182f395dbb0aa997aa5735"
+checksum = "4a8575493d277c9092b988c780c94737fb9fd8651a1001e16bee3eccfc1baedb"
 dependencies = [
  "digest",
 ]
 
 [[package]]
 name = "hmac-sha512"
-version = "1.1.5"
+version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4ce1f4656bae589a3fab938f9f09bf58645b7ed01a2c5f8a3c238e01a4ef78a"
+checksum = "b0b3a0f572aa8389d325f5852b9e0a333a15b0f86ecccbb3fdb6e97cd86dc67c"
 dependencies = [
  "digest",
 ]
@@ -1262,9 +1231,9 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
 dependencies = [
  "bytes",
  "fnv",
@@ -1296,15 +1265,15 @@ dependencies = [
 
 [[package]]
 name = "http-range-header"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
+checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
 
 [[package]]
 name = "httparse"
-version = "1.9.4"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 
 [[package]]
 name = "httpdate"
@@ -1312,11 +1281,27 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
 
+[[package]]
+name = "hydration_context"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef13071fe13b55c85fe2b70246d2e3b49d2c6a764fd3e0edaf262cc385ff1854"
+dependencies = [
+ "futures",
+ "js-sys",
+ "once_cell",
+ "or_poisoned",
+ "pin-project-lite",
+ "serde",
+ "throw_error",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "hyper"
-version = "1.4.1"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
+checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1335,9 +1320,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-rustls"
-version = "0.27.2"
+version = "0.27.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
 dependencies = [
  "futures-util",
  "http",
@@ -1368,9 +1353,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-util"
-version = "0.1.7"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1381,16 +1366,15 @@ dependencies = [
  "pin-project-lite",
  "socket2",
  "tokio",
- "tower 0.4.13",
  "tower-service",
  "tracing",
 ]
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.60"
+version = "0.1.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -1421,29 +1405,152 @@ dependencies = [
 ]
 
 [[package]]
-name = "ident_case"
-version = "1.0.1"
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
 name = "idna"
-version = "0.5.0"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
 dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "icu_normalizer",
+ "icu_properties",
 ]
 
 [[package]]
 name = "indexmap"
-version = "2.4.0"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.5",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -1455,15 +1562,6 @@ dependencies = [
  "generic-array",
 ]
 
-[[package]]
-name = "instant"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
-dependencies = [
- "cfg-if",
-]
-
 [[package]]
 name = "interpolator"
 version = "0.5.0"
@@ -1478,9 +1576,9 @@ checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
 
 [[package]]
 name = "ipnet"
-version = "2.9.0"
+version = "2.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
+checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
 
 [[package]]
 name = "iso8601"
@@ -1493,33 +1591,33 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "js-sys"
-version = "0.3.70"
+version = "0.3.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
 dependencies = [
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "jwt-simple"
-version = "0.12.9"
+version = "0.12.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "094661f5aad510abe2658bff20409e89046b753d9dc2d4007f5c100b6d982ba0"
+checksum = "b00e03c08ce71da10a3ad9267b963c03fc4234a56713d87648547b3fdda872a6"
 dependencies = [
  "anyhow",
  "binstring",
@@ -1537,15 +1635,15 @@ dependencies = [
  "serde",
  "serde_json",
  "superboring",
- "thiserror",
+ "thiserror 2.0.6",
  "zeroize",
 ]
 
 [[package]]
 name = "k256"
-version = "0.13.3"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b"
+checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
 dependencies = [
  "cfg-if",
  "ecdsa",
@@ -1566,18 +1664,35 @@ dependencies = [
 
 [[package]]
 name = "leptos"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a15911b4e53bb6e1b033d717eadb39924418a4a288279128122e5a65c70ba3e6"
+checksum = "ba5046c590aea121f6ad5e71fcb75453a933425d39527b9a3b1b295235afc8df"
 dependencies = [
+ "any_spawner",
+ "base64",
  "cfg-if",
+ "either_of",
+ "futures",
+ "hydration_context",
  "leptos_config",
  "leptos_dom",
+ "leptos_hot_reload",
  "leptos_macro",
- "leptos_reactive",
  "leptos_server",
+ "oco_ref",
+ "or_poisoned",
+ "paste",
+ "rand",
+ "reactive_graph",
+ "rustc-hash",
+ "send_wrapper",
+ "serde",
+ "serde_qs",
  "server_fn",
- "tracing",
+ "slotmap",
+ "tachys",
+ "thiserror 2.0.6",
+ "throw_error",
  "typed-builder",
  "typed-builder-macro",
  "wasm-bindgen",
@@ -1586,14 +1701,15 @@ dependencies = [
 
 [[package]]
 name = "leptos_axum"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee520a923a9c93f68ca78d6b8884fc69066c6d88ce294eafa0fb9a157873bec0"
+checksum = "7b0d388392939f629c45b8c7bcc83997cb6c6026813b57f50953651ad5be63d8"
 dependencies = [
+ "any_spawner",
  "axum",
- "cfg-if",
+ "dashmap",
  "futures",
- "http-body-util",
+ "hydration_context",
  "leptos",
  "leptos_integration_utils",
  "leptos_macro",
@@ -1601,61 +1717,45 @@ dependencies = [
  "leptos_router",
  "once_cell",
  "parking_lot",
- "serde_json",
  "server_fn",
  "tokio",
- "tokio-util",
- "tracing",
+ "tower",
+ "tower-http 0.6.2",
 ]
 
 [[package]]
 name = "leptos_config"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbc4d78fba18c1ccab48ffc9f3d35b39821f896b0a28bdd616a846b6241036c9"
+checksum = "5e2d64c43e2554108c26da3127f8384d92ca76c6f0b7288d1c09c8cc68152064"
 dependencies = [
  "config",
  "regex",
  "serde",
- "thiserror",
+ "thiserror 2.0.6",
  "typed-builder",
 ]
 
 [[package]]
 name = "leptos_dom"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ccb04d4763603bb665fa35cb9642d0bd75313117d10efda9b79243c023e69df"
+checksum = "6c15aca81dc2edd040b51c46734f65c6f36e6ba8a31347c1354c94b958044ae0"
 dependencies = [
- "async-recursion",
- "cfg-if",
- "drain_filter_polyfill",
- "futures",
- "getrandom",
- "html-escape",
- "indexmap",
- "itertools",
  "js-sys",
- "leptos_reactive",
- "once_cell",
- "pad-adapter",
- "paste",
- "rustc-hash",
- "serde",
- "serde_json",
- "server_fn",
- "smallvec",
- "tracing",
+ "or_poisoned",
+ "reactive_graph",
+ "send_wrapper",
+ "tachys",
  "wasm-bindgen",
- "wasm-bindgen-futures",
  "web-sys",
 ]
 
 [[package]]
 name = "leptos_hot_reload"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc61e5cce26761562cd3332630b3fbaddb1c4f77744e41474c7212ad279c5d9"
+checksum = "0445f3a62696d2d66bef288911af34405718880b4b8dd6c5cfb7751fd8ffcc6b"
 dependencies = [
  "anyhow",
  "camino",
@@ -1665,29 +1765,30 @@ dependencies = [
  "quote",
  "rstml",
  "serde",
- "syn 2.0.76",
+ "syn",
  "walkdir",
 ]
 
 [[package]]
 name = "leptos_integration_utils"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac080e02d0230481d80aa6920be2d634a2243f1ebbc2b8c1d57bf1bd46ca8a5b"
+checksum = "d293a2f64a558d4ca10ef01125d055134f3582f27c407102c4259bb54ca8b55b"
 dependencies = [
  "futures",
+ "hydration_context",
  "leptos",
  "leptos_config",
- "leptos_hot_reload",
  "leptos_meta",
- "tracing",
+ "leptos_router",
+ "reactive_graph",
 ]
 
 [[package]]
 name = "leptos_macro"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90eaea005cabb879c091c84cfec604687ececfd540469e5a30a60c93489a2f23"
+checksum = "92f690c955274f1722ee6c66463ace79301d53a8c2bf7f6e4e61b978ca239e20"
 dependencies = [
  "attribute-derive",
  "cfg-if",
@@ -1696,111 +1797,92 @@ dependencies = [
  "itertools",
  "leptos_hot_reload",
  "prettyplease",
- "proc-macro-error",
+ "proc-macro-error2",
  "proc-macro2",
  "quote",
  "rstml",
  "server_fn_macro",
- "syn 2.0.76",
- "tracing",
+ "syn",
  "uuid",
 ]
 
 [[package]]
 name = "leptos_meta"
-version = "0.6.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "779bc68f8c05b15dde6557f9eb7baef4fa606a5bc450c1d6ff8787b092d0ae93"
-dependencies = [
- "cfg-if",
- "indexmap",
- "leptos",
- "tracing",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "leptos_reactive"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef2f99f377472459b0d320b46e9a9516b0e68dee5ed8c9eeb7e8eb9fefec5d2"
+checksum = "7c651d788bbbf1c57ee95dd3835f9d433b85a409b6256f338c3c7146eb8b7f53"
 dependencies = [
- "base64",
- "cfg-if",
  "futures",
  "indexmap",
- "js-sys",
- "oco_ref",
- "paste",
- "pin-project",
- "rustc-hash",
- "self_cell",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "slotmap",
- "thiserror",
- "tokio",
- "tracing",
+ "leptos",
+ "once_cell",
+ "or_poisoned",
+ "send_wrapper",
  "wasm-bindgen",
- "wasm-bindgen-futures",
  "web-sys",
 ]
 
 [[package]]
 name = "leptos_router"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5006e35b7c768905286dbea0d3525396cd39d961cb7b9fb664aa00b0c984ae6"
+checksum = "32a4f1784486ebf36805dac22faee21e3e610aa64b6662a7386f065eeec27ae8"
 dependencies = [
- "cached",
- "cfg-if",
+ "any_spawner",
+ "either_of",
+ "futures",
  "gloo-net",
- "itertools",
  "js-sys",
- "lazy_static",
  "leptos",
- "leptos_integration_utils",
- "leptos_meta",
- "linear-map",
- "lru",
+ "leptos_router_macro",
  "once_cell",
+ "or_poisoned",
  "percent-encoding",
- "regex",
+ "reactive_graph",
  "send_wrapper",
- "serde",
- "serde_json",
- "serde_qs 0.13.0",
- "thiserror",
- "tracing",
+ "tachys",
+ "thiserror 2.0.6",
  "url",
  "wasm-bindgen",
- "wasm-bindgen-futures",
  "web-sys",
 ]
 
+[[package]]
+name = "leptos_router_macro"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eee7ecef3f1c69b51864190c564e4873d84f200e44efb37934208f9525f02a5f"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+]
+
 [[package]]
 name = "leptos_server"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f07be202a433baa8c50050de4f9c116efccffc57208bcda7bd1bb9b8e87dca9"
+checksum = "93450589df3b3e398c7f5ea64d8f1c8369b1ba9b90e1f70f6cb996b8d443ca3e"
 dependencies = [
- "inventory",
- "lazy_static",
- "leptos_macro",
- "leptos_reactive",
+ "any_spawner",
+ "base64",
+ "codee",
+ "futures",
+ "hydration_context",
+ "or_poisoned",
+ "reactive_graph",
+ "send_wrapper",
  "serde",
+ "serde_json",
  "server_fn",
- "thiserror",
- "tracing",
+ "tachys",
 ]
 
 [[package]]
 name = "lettre"
-version = "0.11.7"
+version = "0.11.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a62049a808f1c4e2356a2a380bd5f2aca3b011b0b482cf3b914ba1731426969"
+checksum = "ab4c9a167ff73df98a5ecc07e8bf5ce90b583665da3d1762eb1f775ad4d0d6f5"
 dependencies = [
  "async-trait",
  "base64",
@@ -1826,25 +1908,21 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.158"
+version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 
 [[package]]
 name = "libm"
-version = "0.2.8"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
+checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
 
 [[package]]
 name = "linear-map"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee"
-dependencies = [
- "serde",
- "serde_test",
-]
 
 [[package]]
 name = "linux-raw-sys"
@@ -1852,6 +1930,12 @@ version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
+[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+
 [[package]]
 name = "lock_api"
 version = "0.4.12"
@@ -1868,34 +1952,25 @@ version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
-[[package]]
-name = "lru"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21"
-dependencies = [
- "hashbrown 0.14.5",
-]
-
 [[package]]
 name = "manyhow"
-version = "0.10.4"
+version = "0.11.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91ea592d76c0b6471965708ccff7e6a5d277f676b90ab31f4d3f3fc77fade64"
+checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
 dependencies = [
  "manyhow-macros",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "manyhow-macros"
-version = "0.10.4"
+version = "0.11.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64621e2c08f2576e4194ea8be11daf24ac01249a4f53cd8befcbb7077120ead"
+checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
 dependencies = [
- "proc-macro-utils 0.8.0",
+ "proc-macro-utils",
  "proc-macro2",
  "quote",
 ]
@@ -1934,15 +2009,6 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
-[[package]]
-name = "miniz_oxide"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
-dependencies = [
- "adler",
-]
-
 [[package]]
 name = "miniz_oxide"
 version = "0.8.0"
@@ -1954,11 +2020,10 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
- "hermit-abi",
  "libc",
  "wasi",
  "windows-sys 0.52.0",
@@ -1998,6 +2063,12 @@ dependencies = [
  "tempfile",
 ]
 
+[[package]]
+name = "next_tuple"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28"
+
 [[package]]
 name = "nom"
 version = "7.1.3"
@@ -2061,6 +2132,16 @@ dependencies = [
  "libm",
 ]
 
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
 [[package]]
 name = "num_threads"
 version = "0.1.7"
@@ -2072,28 +2153,28 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.3"
+version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "oco_ref"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c51ebcefb2f0b9a5e0bea115532c8ae4215d1b01eff176d0f4ba4192895c2708"
+checksum = "64b94982fe39a861561cf67ff17a7849f2cedadbbad960a797634032b7abb998"
 dependencies = [
  "serde",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "opaque-debug"
@@ -2103,9 +2184,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
 
 [[package]]
 name = "openssl"
-version = "0.10.66"
+version = "0.10.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -2124,7 +2205,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -2135,9 +2216,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.103"
+version = "0.9.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
 dependencies = [
  "cc",
  "libc",
@@ -2145,6 +2226,12 @@ dependencies = [
  "vcpkg",
 ]
 
+[[package]]
+name = "or_poisoned"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd"
+
 [[package]]
 name = "p256"
 version = "0.13.2"
@@ -2170,10 +2257,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "pad-adapter"
-version = "0.1.1"
+name = "parking"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
 
 [[package]]
 name = "parking_lot"
@@ -2206,9 +2293,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "pathdiff"
-version = "0.2.1"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
 
 [[package]]
 name = "pem-rfc7468"
@@ -2227,29 +2314,29 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pin-project"
-version = "1.1.5"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
+checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.5"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
+checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
 
 [[package]]
 name = "pin-utils"
@@ -2280,9 +2367,9 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "polyval"
@@ -2313,12 +2400,12 @@ dependencies = [
 
 [[package]]
 name = "prettyplease"
-version = "0.2.21"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a909e6e8053fa1a5ad670f5816c7d93029ee1fa8898718490544a6b0d5d38b3e"
+checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
 dependencies = [
  "proc-macro2",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -2354,14 +2441,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "proc-macro-utils"
-version = "0.8.0"
+name = "proc-macro-error-attr2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
 dependencies = [
  "proc-macro2",
  "quote",
- "smallvec",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
@@ -2377,9 +2475,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -2392,16 +2490,16 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
  "version_check",
  "yansi",
 ]
 
 [[package]]
 name = "psm"
-version = "0.1.21"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
+checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
 dependencies = [
  "cc",
 ]
@@ -2431,10 +2529,10 @@ version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35"
 dependencies = [
- "proc-macro-utils 0.10.0",
+ "proc-macro-utils",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -2473,20 +2571,69 @@ dependencies = [
  "getrandom",
 ]
 
+[[package]]
+name = "reactive_graph"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c27f54685c1416af1f323a0c40e71cbdae281a1ebc623591790d367222d0ac65"
+dependencies = [
+ "any_spawner",
+ "async-lock",
+ "futures",
+ "guardian",
+ "hydration_context",
+ "or_poisoned",
+ "pin-project-lite",
+ "rustc-hash",
+ "send_wrapper",
+ "serde",
+ "slotmap",
+ "thiserror 2.0.6",
+ "web-sys",
+]
+
+[[package]]
+name = "reactive_stores"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efe3f866edc7647e19a68a229a2e5cc9730549836d722eeaa073116f2b07966e"
+dependencies = [
+ "guardian",
+ "itertools",
+ "or_poisoned",
+ "paste",
+ "reactive_graph",
+ "reactive_stores_macro",
+ "rustc-hash",
+]
+
+[[package]]
+name = "reactive_stores_macro"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d86e4f08f361b05d11422398cef4bc4cf356f2fdd2f06a96646b0e9cd902226"
+dependencies = [
+ "convert_case",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "redox_syscall"
-version = "0.5.3"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2496,9 +2643,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2507,15 +2654,15 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "reqwest"
-version = "0.12.7"
+version = "0.12.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
+checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
 dependencies = [
  "base64",
  "bytes",
@@ -2542,7 +2689,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_urlencoded",
- "sync_wrapper 1.0.1",
+ "sync_wrapper 1.0.2",
  "system-configuration",
  "tokio",
  "tokio-native-tls",
@@ -2581,9 +2728,9 @@ dependencies = [
 
 [[package]]
 name = "rsa"
-version = "0.9.6"
+version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
+checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519"
 dependencies = [
  "const-oid",
  "digest",
@@ -2602,16 +2749,17 @@ dependencies = [
 
 [[package]]
 name = "rstml"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe542870b8f59dd45ad11d382e5339c9a1047cde059be136a7016095bbdefa77"
+checksum = "51187e564f12336ef40cd04f6f4d805d6919188001dcf1e0a021898ea0fe28ce"
 dependencies = [
+ "derive-where",
  "proc-macro2",
  "proc-macro2-diagnostics",
  "quote",
- "syn 2.0.76",
+ "syn",
  "syn_derive",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -2622,28 +2770,28 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
-version = "1.1.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "0.38.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "rustls"
-version = "0.23.12"
+version = "0.23.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
+checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
 dependencies = [
  "once_cell",
  "rustls-pki-types",
@@ -2654,25 +2802,24 @@ dependencies = [
 
 [[package]]
 name = "rustls-pemfile"
-version = "2.1.3"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
 dependencies = [
- "base64",
  "rustls-pki-types",
 ]
 
 [[package]]
 name = "rustls-pki-types"
-version = "1.8.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
 
 [[package]]
 name = "rustls-webpki"
-version = "0.102.6"
+version = "0.102.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
 dependencies = [
  "ring",
  "rustls-pki-types",
@@ -2681,9 +2828,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
 
 [[package]]
 name = "ryu"
@@ -2702,11 +2849,11 @@ dependencies = [
 
 [[package]]
 name = "schannel"
-version = "0.1.23"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2744,20 +2891,14 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.11.1"
+version = "2.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
+checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
 dependencies = [
  "core-foundation-sys",
  "libc",
 ]
 
-[[package]]
-name = "self_cell"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
-
 [[package]]
 name = "send_wrapper"
 version = "0.6.0"
@@ -2769,40 +2910,29 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.209"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
 dependencies = [
  "serde_derive",
 ]
 
-[[package]]
-name = "serde-wasm-bindgen"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
-dependencies = [
- "js-sys",
- "serde",
- "wasm-bindgen",
-]
-
 [[package]]
 name = "serde_derive"
-version = "1.0.209"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.127"
+version = "1.0.133"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
 dependencies = [
  "itoa",
  "memchr",
@@ -2820,17 +2950,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "serde_qs"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c"
-dependencies = [
- "percent-encoding",
- "serde",
- "thiserror",
-]
-
 [[package]]
 name = "serde_qs"
 version = "0.13.0"
@@ -2839,23 +2958,14 @@ checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6"
 dependencies = [
  "percent-encoding",
  "serde",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "serde_test"
-version = "1.0.177"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
 dependencies = [
  "serde",
 ]
@@ -2874,13 +2984,12 @@ dependencies = [
 
 [[package]]
 name = "server_fn"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "024b400db1aca5bd4188714f7bbbf7a2e1962b9a12a80b2a21e937e509086963"
+checksum = "033cb8014aa86a7ce0c6ee58d23dce1a078b2e320dc6c53bb439663993199b1f"
 dependencies = [
  "axum",
  "bytes",
- "ciborium",
  "const_format",
  "dashmap",
  "futures",
@@ -2891,13 +3000,15 @@ dependencies = [
  "inventory",
  "js-sys",
  "once_cell",
+ "pin-project-lite",
  "send_wrapper",
  "serde",
  "serde_json",
- "serde_qs 0.12.0",
+ "serde_qs",
  "server_fn_macro_default",
- "thiserror",
- "tower 0.4.13",
+ "thiserror 2.0.6",
+ "throw_error",
+ "tower",
  "tower-layer",
  "url",
  "wasm-bindgen",
@@ -2909,26 +3020,26 @@ dependencies = [
 
 [[package]]
 name = "server_fn_macro"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf0e6f71fc924df36e87f27dfbd447f0bedd092d365db3a5396878256d9f00c"
+checksum = "0249e8a55ca464a1e69f02a95d562f2c65e92e301093a02ebf15d21f68f2a99e"
 dependencies = [
  "const_format",
  "convert_case",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
  "xxhash-rust",
 ]
 
 [[package]]
 name = "server_fn_macro_default"
-version = "0.6.14"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "556e4fd51eb9ee3e7d9fb0febec6cef486dcbc8f7f427591dfcfebee1abe1ad4"
+checksum = "91c54a6d43cd0f3d2bdf0c85b6119f378b6b89d528159af9cde77f229faeecbc"
 dependencies = [
  "server_fn_macro",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -2994,7 +3105,6 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
 dependencies = [
- "serde",
  "version_check",
 ]
 
@@ -3006,9 +3116,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "socket2"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -3030,17 +3140,23 @@ dependencies = [
  "der",
 ]
 
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
 [[package]]
 name = "stacker"
-version = "0.1.16"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95a5daa25ea337c85ed954c0496e3bdd2c7308cc3b24cf7b50d04876654c579f"
+checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b"
 dependencies = [
  "cc",
  "cfg-if",
  "libc",
  "psm",
- "windows-sys 0.36.1",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -3049,12 +3165,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
 [[package]]
 name = "subtle"
 version = "2.6.1"
@@ -3063,9 +3173,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
 
 [[package]]
 name = "superboring"
-version = "0.1.2"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbde97f499e51ef384f585dc8f8fb6a9c3a71b274b8d12469b516758e6540607"
+checksum = "515cce34a781d7250b8a65706e0f2a5b99236ea605cb235d4baed6685820478f"
 dependencies = [
  "getrandom",
  "hmac-sha256",
@@ -3076,20 +3186,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.109"
+version = "2.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.76"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3105,7 +3204,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -3116,13 +3215,24 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
 
 [[package]]
 name = "sync_wrapper"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
 dependencies = [
  "futures-core",
 ]
 
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "system-configuration"
 version = "0.6.1"
@@ -3144,11 +3254,43 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "tachys"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8be68dfd4abf192e11a1bdd484239daa84ffa6fcd27c25cf4f011b2b0fb27ddb"
+dependencies = [
+ "any_spawner",
+ "const_str_slice_concat",
+ "drain_filter_polyfill",
+ "either_of",
+ "futures",
+ "html-escape",
+ "indexmap",
+ "itertools",
+ "js-sys",
+ "linear-map",
+ "next_tuple",
+ "oco_ref",
+ "once_cell",
+ "or_poisoned",
+ "parking_lot",
+ "paste",
+ "reactive_graph",
+ "reactive_stores",
+ "rustc-hash",
+ "send_wrapper",
+ "slotmap",
+ "throw_error",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "tempfile"
-version = "3.12.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -3159,29 +3301,58 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.63"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
+dependencies = [
+ "thiserror-impl 2.0.6",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.63"
+version = "2.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
+]
+
+[[package]]
+name = "throw_error"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4ef8bf264c6ae02a065a4a16553283f0656bd6266fc1fcb09fd2e6b5e91427b"
+dependencies = [
+ "pin-project-lite",
 ]
 
 [[package]]
 name = "time"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
 dependencies = [
  "deranged",
  "itoa",
@@ -3202,34 +3373,29 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
 dependencies = [
  "num-conv",
  "time-core",
 ]
 
 [[package]]
-name = "tinyvec"
-version = "1.8.0"
+name = "tinystr"
+version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
 dependencies = [
- "tinyvec_macros",
+ "displaydoc",
+ "zerovec",
 ]
 
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
 [[package]]
 name = "tokio"
-version = "1.39.3"
+version = "1.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
 dependencies = [
  "backtrace",
  "bytes",
@@ -3251,7 +3417,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -3266,26 +3432,23 @@ dependencies = [
 
 [[package]]
 name = "tokio-rustls"
-version = "0.26.0"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
 dependencies = [
  "rustls",
- "rustls-pki-types",
  "tokio",
 ]
 
 [[package]]
 name = "tokio-util"
-version = "0.7.11"
+version = "0.7.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
+checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
 dependencies = [
  "bytes",
  "futures-core",
  "futures-sink",
- "futures-util",
- "hashbrown 0.14.5",
  "pin-project-lite",
  "tokio",
 ]
@@ -3313,9 +3476,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.22.20"
+version = "0.22.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
 dependencies = [
  "indexmap",
  "serde",
@@ -3326,14 +3489,14 @@ dependencies = [
 
 [[package]]
 name = "tower"
-version = "0.4.13"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
+checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
 dependencies = [
  "futures-core",
  "futures-util",
- "pin-project",
  "pin-project-lite",
+ "sync_wrapper 0.1.2",
  "tokio",
  "tower-layer",
  "tower-service",
@@ -3341,29 +3504,40 @@ dependencies = [
 ]
 
 [[package]]
-name = "tower"
-version = "0.5.0"
+name = "tower-http"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7"
+checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
 dependencies = [
+ "async-compression",
+ "bitflags",
+ "bytes",
  "futures-core",
  "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "http-range-header",
+ "httpdate",
+ "mime",
+ "mime_guess",
+ "percent-encoding",
  "pin-project-lite",
- "sync_wrapper 0.1.2",
+ "tokio",
+ "tokio-util",
  "tower-layer",
  "tower-service",
+ "tracing",
 ]
 
 [[package]]
 name = "tower-http"
-version = "0.5.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
+checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697"
 dependencies = [
- "async-compression",
  "bitflags",
  "bytes",
- "futures-core",
  "futures-util",
  "http",
  "http-body",
@@ -3395,9 +3569,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
  "log",
  "pin-project-lite",
@@ -3407,20 +3581,20 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
 name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
 dependencies = [
  "once_cell",
 ]
@@ -3433,22 +3607,22 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
 name = "typed-builder"
-version = "0.18.2"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add"
+checksum = "7e14ed59dc8b7b26cacb2a92bad2e8b1f098806063898ab42a3bd121d7d45e75"
 dependencies = [
  "typed-builder-macro",
 ]
 
 [[package]]
 name = "typed-builder-macro"
-version = "0.18.2"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63"
+checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
 ]
 
 [[package]]
@@ -3459,45 +3633,27 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "unicase"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
-dependencies = [
- "version_check",
-]
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.23"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
-dependencies = [
- "tinyvec",
-]
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.11.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
 
 [[package]]
 name = "universal-hash"
@@ -3517,9 +3673,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
 
 [[package]]
 name = "url"
-version = "2.5.2"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -3535,17 +3691,29 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
 [[package]]
 name = "utf8-width"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
 
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
 [[package]]
 name = "uuid"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
+checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
 dependencies = [
  "getrandom",
  "wasm-bindgen",
@@ -3599,9 +3767,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -3610,24 +3778,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.43"
+version = "0.4.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -3637,9 +3805,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -3647,28 +3815,28 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
 
 [[package]]
 name = "wasm-streams"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
 dependencies = [
  "futures-util",
  "js-sys",
@@ -3696,9 +3864,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.70"
+version = "0.3.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -3762,19 +3930,6 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
-dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -3845,12 +4000,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
-
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
@@ -3863,12 +4012,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
-[[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
-
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
@@ -3887,12 +4030,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
-[[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
-
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
@@ -3905,12 +4042,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
@@ -3935,12 +4066,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
@@ -3955,13 +4080,25 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.18"
+version = "0.6.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
 dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
 [[package]]
 name = "xxhash-rust"
 version = "0.8.12"
@@ -3974,6 +4111,30 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
 
+[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
 [[package]]
 name = "zerocopy"
 version = "0.7.35"
@@ -3992,7 +4153,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.76",
+ "syn",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
 ]
 
 [[package]]
@@ -4000,3 +4182,25 @@ name = "zeroize"
 version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/aep-schedule-website/Cargo.toml b/aep-schedule-website/Cargo.toml
index 57f1e941dd66fb6037fcd4151666bd1c8b73e87d..b8aa580d491e1725af0665615c9e1768e8eb3b45 100644
--- a/aep-schedule-website/Cargo.toml
+++ b/aep-schedule-website/Cargo.toml
@@ -11,10 +11,10 @@ axum = { version = "0.7", optional = true, features = ["macros"] }
 console_error_panic_hook = "0.1"
 console_log = "1"
 cfg-if = "1"
-leptos = { version = "0.6", features = ["nightly"] }
-leptos_axum = { version = "0.6", optional = true }
-leptos_meta = { version = "0.6", features = ["nightly"] }
-leptos_router = { version = "0.6", features = ["nightly"] }
+leptos = { version = "0.7.0", features = ["nightly"] }
+leptos_router = { version = "0.7.0" }
+leptos_meta = { version = "0.7.0" }
+leptos_axum = { version = "0.7.0", optional = true }
 log = "0.4"
 rand = { version = "0.8", optional = true }
 simple_logger = "5"
@@ -26,7 +26,7 @@ tower-http = { version = "0.5", features = [
     "fs",
 ], optional = true }
 aep_schedule_generator = { path = "../aep-schedule-generator" }
-wasm-bindgen = "=0.2.93"
+wasm-bindgen = "=0.2.95"
 thiserror = "1.0.38"
 tracing = { version = "0.1.40", optional = true }
 serde = { version = "1.0", features = ["derive"] }
@@ -50,7 +50,7 @@ lettre = { version = "0.11.7", features = [
 ], optional = true }
 
 [features]
-hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
+hydrate = ["leptos/hydrate"]
 ssr = [
     "dep:axum",
     "dep:tokio",
@@ -60,10 +60,10 @@ ssr = [
     "dep:reqwest",
     "dep:lettre",
     "dep:rand",
+    "dep:tracing",
     "leptos/ssr",
     "leptos_meta/ssr",
     "leptos_router/ssr",
-    "dep:tracing",
 ]
 
 [profile.dev]
diff --git a/aep-schedule-website/src/backend/fileserv.rs b/aep-schedule-website/src/backend/fileserv.rs
index 41783dc1bfb8af3f82af8f4afa000ce23992eb68..9a0424e70bec000b73cef47fd51918fe41b6c423 100644
--- a/aep-schedule-website/src/backend/fileserv.rs
+++ b/aep-schedule-website/src/backend/fileserv.rs
@@ -6,7 +6,7 @@ use axum::{
     response::IntoResponse,
     response::Response,
 };
-use leptos::*;
+use leptos::prelude::*;
 use tower::ServiceExt;
 use tower_http::services::ServeDir;
 
@@ -21,7 +21,7 @@ pub async fn file_and_error_handler(
     if res.status() == StatusCode::OK {
         res.into_response()
     } else {
-        let handler = leptos_axum::render_app_to_stream(options.to_owned(), move || view! {<App/>});
+        let handler = leptos_axum::render_app_to_stream(move || view! { <App /> });
         handler(req).await.into_response()
     }
 }
diff --git a/aep-schedule-website/src/backend/routes.rs b/aep-schedule-website/src/backend/routes.rs
index 27f6ef6d3569a027f9a048b3454cb4d4156db835..094726113cdbc4384db8f842ff83d5d24d5232f9 100644
--- a/aep-schedule-website/src/backend/routes.rs
+++ b/aep-schedule-website/src/backend/routes.rs
@@ -6,7 +6,7 @@ use aep_schedule_generator::{
     icalendar::calendar::Calendar,
 };
 use compact_str::CompactString;
-use leptos::*;
+use leptos::prelude::*;
 
 use super::shared::user_builder::UserBuilder;
 
diff --git a/aep-schedule-website/src/backend/state.rs b/aep-schedule-website/src/backend/state.rs
index 453eb8cd6686288284215deb62a5299aa13d0a8c..4a04b8e2654a90c0eb75f846166b26ed6ec2d0bf 100644
--- a/aep-schedule-website/src/backend/state.rs
+++ b/aep-schedule-website/src/backend/state.rs
@@ -1,4 +1,4 @@
-use crate::frontend::app::App;
+use crate::frontend::app::shell;
 use aep_schedule_generator::data::courses::Courses;
 use aep_schedule_generator::icalendar::calendar::Calendar;
 use axum::{
@@ -8,9 +8,9 @@ use axum::{
     http::Request,
     response::{IntoResponse, Response},
 };
-use leptos::*;
+use leptos::prelude::*;
 use leptos_axum::handle_server_fns_with_context;
-use leptos_router::RouteListing;
+use leptos_axum::AxumRouteListing;
 use std::fs::File;
 use std::io::BufReader;
 use std::sync::Arc;
@@ -31,11 +31,11 @@ pub struct AppState {
     pub courses: Arc<RwLock<Courses>>,
     pub calendar: Arc<RwLock<Calendar>>,
     pub users_to_notify: Arc<Mutex<UsersToNotify>>,
-    pub routes: Vec<RouteListing>,
+    pub routes: Vec<AxumRouteListing>,
 }
 
 impl AppState {
-    pub async fn new(leptos_options: LeptosOptions, routes: Vec<RouteListing>) -> Self {
+    pub async fn new(leptos_options: LeptosOptions, routes: Vec<AxumRouteListing>) -> Self {
         #[cfg(not(debug_assertions))]
         {
             // Don't spam Poly when reloading the website in debug mode
@@ -130,15 +130,18 @@ pub async fn leptos_routes_handler(
     State(app_state): State<AppState>,
     req: Request<AxumBody>,
 ) -> Response {
+    let state = axum::extract::State(app_state.clone());
     let handler = leptos_axum::render_route_with_context(
-        app_state.leptos_options.clone(),
         app_state.routes.clone(),
         move || {
             provide_context(app_state.calendar.clone());
             provide_context(app_state.courses.clone());
             provide_context(app_state.users_to_notify.clone());
         },
-        App,
+        {
+            let leptos_options = app_state.leptos_options.clone();
+            move || shell(leptos_options.clone())
+        },
     );
-    handler(req).await.into_response()
+    handler(state, req).await.into_response()
 }
diff --git a/aep-schedule-website/src/frontend/app.rs b/aep-schedule-website/src/frontend/app.rs
index c53b5bfe1da144d81f26fb81c58355f5dc115104..961fe026b4ed505bcbc30fcd54401c097e8170fc 100644
--- a/aep-schedule-website/src/frontend/app.rs
+++ b/aep-schedule-website/src/frontend/app.rs
@@ -4,61 +4,116 @@ use crate::frontend::components::icons::IconWeight;
 use crate::frontend::pages::apropos::HomePage;
 use crate::frontend::pages::classroom::ClassRoomComponent;
 use crate::frontend::pages::generator::GeneratorPage;
-use leptos::*;
+use leptos::prelude::*;
 use leptos_meta::*;
-use leptos_router::*;
-
-#[component]
-pub fn App() -> impl IntoView {
-    // Provides context that manages stylesheets, titles, meta tags, etc.
-    provide_meta_context();
-
-    let (is_active, set_active) = create_signal(false);
+use leptos_router::{
+    components::{FlatRoutes, Route, Router, A},
+    StaticSegment,
+};
 
+pub fn shell(options: LeptosOptions) -> impl IntoView {
     view! {
+        <!DOCTYPE html>
+        <html lang="fr">
+            <head>
+                <meta charset="utf-8" />
+                <meta name="viewport" content="width=device-width, initial-scale=1" />
+                <AutoReload options=options.clone() />
+                <HydrationScripts options />
+                <link rel="stylesheet" id="leptos" href="/pkg/aep-schedule-website.css" />
+                <MetaTags />
+            </head>
+            <body>
+                <App />
+            </body>
+        </html>
+    }
+}
 
-        // injects a stylesheet into the document <head>
-        // id=leptos means cargo-leptos will hot-reload this stylesheet
-        <Stylesheet id="leptos" href="/pkg/aep-schedule-website.css"/>
+#[component]
+pub fn Nav() -> impl IntoView {
+    let (is_active, set_active) = signal(false);
 
-        // sets the document title
-        <Title text="Générateur d'horaire"/>
+    view! {
+        <header>
+            <nav class=("active", is_active) class="flex-wrap overflow-x-hidden">
+                <span class="text-2xl font-semibold leading-none font-sans tracking-tight">
+                    "Générateur d'horaire de l'AEP" <span class="text-amber-600">"v2"</span>
+                </span>
+                <span class="bg-red-200 text-red-800 text-lg font-sans tracking-tight font-medium me-2 px-2.5 py-0.5 rounded-full shrink">
+                    "Beta - "<a class="text-gray-800" href="https://horaires.aep.polymtl.ca/">
+                        "Retourner à l'ancien générateur"
+                    </a>
+                </span>
+                <A href="/">
+                    <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">
+                        "Générateur d'horaire"
+                    </span>
+                </A>
+                <A href="/local">
+                    <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">
+                        "Horaire d'un local"
+                    </span>
+                </A>
+                <A href="/apropos">
+                    <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">
+                        "À propos"
+                    </span>
+                </A>
 
-        // content for this welcome page
-        <Router>
-            <header>
-                <nav class=("active", is_active) class="flex-wrap overflow-x-hidden">
-                    <span class="text-2xl font-semibold leading-none font-sans tracking-tight">"Générateur d'horaire de l'AEP"
-                        <span class="text-amber-600">"v2"</span>
+                <a
+                    href="https://forms.gle/u5AWgGx7vcLbCPCc7"
+                    class="sources pad-left"
+                    target="_blank"
+                >
+                    <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">
+                        "Signaler un bug"
+                    </span>
+                    <Bug size="3vh" />
+                </a>
+                <a
+                    href="https://git.step.polymtl.ca/Lemark/aep-schedule-generator-rusty"
+                    class="sources"
+                    target="_blank"
+                >
+                    <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">
+                        "Sources "
                     </span>
-                    <span class="bg-red-200 text-red-800 text-lg font-sans tracking-tight font-medium me-2 px-2.5 py-0.5 rounded-full shrink">"Beta - "<a class="text-gray-800" href="https://horaires.aep.polymtl.ca/">"Retourner à l'ancien générateur"</a></span>
-                    <A class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight" href="/">"Générateur d'horaire"</A>
-                    <A class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight" href="/local">"Horaire d'un local"</A>
-                    <A class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight" href="/apropos">"À propos"</A>
+                    <GitlabLogo weight=IconWeight::Regular size="3vh" />
+                </a>
+            </nav>
+            <div
+                class=("active", is_active)
+                class="hamburger"
+                on:pointerdown=move |_| {
+                    set_active
+                        .update(|active| {
+                            *active = !*active;
+                        });
+                }
+            >
+                <span class="hamburger-bar"></span>
+                <span class="hamburger-bar"></span>
+                <span class="hamburger-bar"></span>
+            </div>
+        </header>
+    }
+}
 
+#[component]
+pub fn App() -> impl IntoView {
+    provide_meta_context();
 
-                    <a href="https://forms.gle/u5AWgGx7vcLbCPCc7" class="sources pad-left"  target="_blank">
-                        <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Signaler un bug"</span>
-                        <Bug weight=IconWeight::Regular size="3vh"/>
-                    </a>
-                    <a href="https://git.step.polymtl.ca/Lemark/aep-schedule-generator-rusty" class="sources" target="_blank" ><span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Sources "</span><GitlabLogo weight=IconWeight::Regular size="3vh"/></a>
-                </nav>
-                <div class=("active", is_active) class="hamburger" on:pointerdown=move |_| {
-                    set_active.update(|active| {
-                        *active = !*active;
-                    });
-                }>
-                    <span class="hamburger-bar"></span>
-                    <span class="hamburger-bar"></span>
-                    <span class="hamburger-bar"></span>
-                </div>
-            </header>
+    view! {
+        <Router>
+            <Title text="Générateur d'horaire" />
+            <Nav />
             <main class="h-full">
-                <Routes>
-                    <Route path="/" view=GeneratorPage/>
-                    <Route path="/apropos" view=HomePage/>
-                    <Route path="/local" view=ClassRoomComponent/>
-                </Routes>
+                <FlatRoutes fallback=|| "Not found">
+                    <Route path=StaticSegment("/") view=GeneratorPage />
+                    <Route path=StaticSegment("/apropos") view=HomePage />
+                    <Route path=StaticSegment("/local") view=ClassRoomComponent />
+                </FlatRoutes>
             </main>
         </Router>
     }
diff --git a/aep-schedule-website/src/frontend/components/common/autocomplete.rs b/aep-schedule-website/src/frontend/components/common/autocomplete.rs
index 4e1bf07571c67546625cce9f0729af7e2de346d6..21c930061ec84822848fc02014c52c0f27be1fda 100644
--- a/aep-schedule-website/src/frontend/components/common/autocomplete.rs
+++ b/aep-schedule-website/src/frontend/components/common/autocomplete.rs
@@ -1,5 +1,5 @@
 use crate::frontend::components::icons::plus_circle::PlusCircle;
-use leptos::*;
+use leptos::prelude::*;
 use std::{cmp, ops::Range};
 
 #[derive(Clone, PartialEq)]
@@ -42,10 +42,10 @@ pub fn AutoComplete<F: FnMut(String) + Copy + Clone + 'static>(
     id: &'static str,
     mut submit: F,
 ) -> impl IntoView {
-    let input = create_rw_signal(String::new());
-    let (suggestion_range, set_suggestion_range) = create_signal(0..0);
+    let input = RwSignal::new(String::new());
+    let (suggestion_range, set_suggestion_range) = signal(0..0);
     let suggestions = suggestion_list.clone();
-    let is_hidden = create_rw_signal(true);
+    let is_hidden = RwSignal::new(true);
 
     let on_input = move |ev| {
         let value = event_target_value(&ev);
@@ -72,28 +72,44 @@ pub fn AutoComplete<F: FnMut(String) + Copy + Clone + 'static>(
 
     view! {
         <div class="relative search-container ".to_owned() + &class>
-            <input type="text" class="py-2 px-3 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none text-black" on:input=on_input placeholder=placeholder prop:value=input id=id on:keyup=move |ev| {
-                if ev.key() == "Enter" && !is_hidden.get() {
-                    let course = input.get().trim().to_uppercase();
-                    select_choice(course);
+            <input
+                type="text"
+                class="py-2 px-3 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none text-black"
+                on:input=on_input
+                placeholder=placeholder
+                prop:value=input
+                id=id
+                on:keyup=move |ev| {
+                    if ev.key() == "Enter" && !is_hidden.get() {
+                        let course = input.get().trim().to_uppercase();
+                        select_choice(course);
+                    }
                 }
-            }
             />
-            <button class=button_theme on:pointerdown=move |_| {
-                let input = input.get().trim().to_uppercase();
-                select_choice(input);
-            }>
-                <PlusCircle size="2em"/>
+            <button
+                class=button_theme
+                on:pointerdown=move |_| {
+                    let input = input.get().trim().to_uppercase();
+                    select_choice(input);
+                }
+            >
+                <PlusCircle size="2em" />
             </button>
             <div class="result-box">
-                {suggestions.into_iter().enumerate().map(|(i, autocomplete)| view!{
-                    <div
-                        class=("hidden", move || {!suggestion_range.get().contains(&i)})
-                        on:pointerdown=move |_| select_choice(autocomplete.value.clone())
-                    >
-                        {autocomplete.label}
-                    </div>
-                }).collect_view()}
+                {suggestions
+                    .into_iter()
+                    .enumerate()
+                    .map(|(i, autocomplete)| {
+                        view! {
+                            <div
+                                class=("hidden", move || { !suggestion_range.get().contains(&i) })
+                                on:pointerdown=move |_| select_choice(autocomplete.value.clone())
+                            >
+                                {autocomplete.label}
+                            </div>
+                        }
+                    })
+                    .collect_view()}
             </div>
         </div>
     }
diff --git a/aep-schedule-website/src/frontend/components/common/number_input.rs b/aep-schedule-website/src/frontend/components/common/number_input.rs
index 5dc3e45ce787b44e41f7f36730ff1c0dab7a9db5..4c2e5a2aabf25eab6c94202bf536b7c18996f4fe 100644
--- a/aep-schedule-website/src/frontend/components/common/number_input.rs
+++ b/aep-schedule-website/src/frontend/components/common/number_input.rs
@@ -1,4 +1,4 @@
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn NumberInput<F>(
@@ -36,9 +36,25 @@ where
         <div class="flex flex-row gap-8 items-center">
             <p class="text-white font-sans font-medium tracking-tight">{label}</p>
             <div class="relative flex items-center max-w-20">
-                <button on:pointerdown=minus type="button" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none">
-                    <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2">
-                        <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/>
+                <button
+                    on:pointerdown=minus
+                    type="button"
+                    class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none"
+                >
+                    <svg
+                        class="w-3 h-3 text-gray-900"
+                        aria-hidden="true"
+                        xmlns="http://www.w3.org/2000/svg"
+                        fill="none"
+                        viewBox="0 0 18 2"
+                    >
+                        <path
+                            stroke="currentColor"
+                            stroke-linecap="round"
+                            stroke-linejoin="round"
+                            stroke-width="2"
+                            d="M1 1h16"
+                        />
                     </svg>
                 </button>
                 <input
@@ -46,14 +62,30 @@ where
                     class="bg-gray-50 border-x-0 border-gray-300 h-7 text-center text-gray-900 text-sm focus:ring-amber-500 focus:border-amber-500 block w-full py-2.5"
                     placeholder="0"
                     on:input=on_input
-                    type="number"
                     min="0"
                     max=max
                     prop:value=value
-                    required />
-                <button on:pointerdown=plus type="button" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none">
-                    <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
-                        <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/>
+                    required
+                />
+                <button
+                    on:pointerdown=plus
+                    type="button"
+                    class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none"
+                >
+                    <svg
+                        class="w-3 h-3 text-gray-900"
+                        aria-hidden="true"
+                        xmlns="http://www.w3.org/2000/svg"
+                        fill="none"
+                        viewBox="0 0 18 18"
+                    >
+                        <path
+                            stroke="currentColor"
+                            stroke-linecap="round"
+                            stroke-linejoin="round"
+                            stroke-width="2"
+                            d="M9 1v16M1 9h16"
+                        />
                     </svg>
                 </button>
             </div>
diff --git a/aep-schedule-website/src/frontend/components/common/schedule.rs b/aep-schedule-website/src/frontend/components/common/schedule.rs
index 94deb8bb0afbc7b45a6d3e907d3bc1805cc402f6..8962ea503b893c568fc100cd51dd513e83e3caa7 100644
--- a/aep-schedule-website/src/frontend/components/common/schedule.rs
+++ b/aep-schedule-website/src/frontend/components/common/schedule.rs
@@ -1,5 +1,5 @@
 use aep_schedule_generator::data::time::period::Period;
-use leptos::*;
+use leptos::prelude::*;
 use std::array;
 
 #[component]
@@ -21,16 +21,45 @@ pub fn Schedule(
 
     view! {
         <div class="schedule">
-            <div class="days" style={format!("grid-template-columns:2em 10px repeat({}, 1fr)", day_week.len())}>
+            <div
+                class="days"
+                style=format!("grid-template-columns:2em 10px repeat({}, 1fr)", day_week.len())
+            >
                 <div></div>
                 <div></div>
-                {day_week.iter().map(|d| view!{<div class="day">{*d}</div>}).collect_view()}
+                {day_week.iter().map(|d| view! { <div class="day">{*d}</div> }).collect_view()}
             </div>
-            <div class="content" style={format!("grid-template-columns:2em 10px repeat({}, 1fr);grid-template-rows: repeat(58, {});", day_week.len(), col_height)}>
-                {hours.clone().into_iter().enumerate().map(|(i, h)| view!{<div class="time" style={format!("grid-row:{}", 4 * (i + 1))}>{h}</div>}).collect_view()}
+            <div
+                class="content"
+                style=format!(
+                    "grid-template-columns:2em 10px repeat({}, 1fr);grid-template-rows: repeat(58, {});",
+                    day_week.len(),
+                    col_height,
+                )
+            >
+                {hours
+                    .clone()
+                    .into_iter()
+                    .enumerate()
+                    .map(|(i, h)| {
+                        view! {
+                            <div class="time" style=format!("grid-row:{}", 4 * (i + 1))>
+                                {h}
+                            </div>
+                        }
+                    })
+                    .collect_view()}
                 <div class="filler-col"></div>
-                {(3..=(day_week.len()+2)).map(|i| view!{<div class="col" style={format!("grid-column:{i}")}></div>}).collect_view()}
-                {(1..=hours.len()).map(|i| view!{<div class="row" style={format!("grid-row:{}/ span 2", 4 * i - 1)}></div>}).collect_view()}
+                {(3..=(day_week.len() + 2))
+                    .map(|i| view! { <div class="col" style=format!("grid-column:{i}")></div> })
+                    .collect_view()}
+                {(1..=hours.len())
+                    .map(|i| {
+                        view! {
+                            <div class="row" style=format!("grid-row:{}/ span 2", 4 * i - 1)></div>
+                        }
+                    })
+                    .collect_view()}
                 {children.map(|c| c())}
             </div>
         </div>
@@ -38,8 +67,8 @@ pub fn Schedule(
 }
 
 #[component]
-pub fn ScheduleEvent<'a>(
-    period: &'a Period,
+pub fn ScheduleEvent(
+    period: Period,
     children: Children,
     #[prop(optional)] class: String,
 ) -> impl IntoView {
@@ -53,7 +82,7 @@ pub fn ScheduleEvent<'a>(
         len * 4
     );
     view! {
-        <div style={style} class="event".to_owned() + &class>
+        <div style=style class="event".to_owned() + &class>
             {children()}
         </div>
     }
diff --git a/aep-schedule-website/src/frontend/components/common/tab.rs b/aep-schedule-website/src/frontend/components/common/tab.rs
index e330d3bcd7569118ad1f8c20d13a7ac18407decb..014ef07d282cf756979c139529518fcb4cbaab4c 100644
--- a/aep-schedule-website/src/frontend/components/common/tab.rs
+++ b/aep-schedule-website/src/frontend/components/common/tab.rs
@@ -1,9 +1,12 @@
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn Tab(active_tab: ReadSignal<String>, tab_id: String, children: Children) -> impl IntoView {
     view! {
-        <div class="relative card tab shrink w-full overflow-y-auto" class=("hidden", {move || tab_id != active_tab.get()})>
+        <div
+            class="relative card tab shrink w-full overflow-y-auto"
+            class=("hidden", { move || tab_id != active_tab.get() })
+        >
             {children()}
         </div>
     }
diff --git a/aep-schedule-website/src/frontend/components/icons/bell_ringing.rs b/aep-schedule-website/src/frontend/components/icons/bell_ringing.rs
index 8d7dc6837b19258a27115e894393377a95c1495b..a227007b9749486efc555705761a3cb17e500dcf 100644
--- a/aep-schedule-website/src/frontend/components/icons/bell_ringing.rs
+++ b/aep-schedule-website/src/frontend/components/icons/bell_ringing.rs
@@ -1,61 +1,20 @@
-//! GENERATED FILE
-
-use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn BellRinging(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
-    #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
-    #[prop(into, optional)] id: MaybeProp<TextProp>,
+    size: &'static str,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
-            IconWeight::Fill => view! {
-                <path d="M224,71.1a8,8,0,0,1-10.78-3.42,94.13,94.13,0,0,0-33.46-36.91,8,8,0,1,1,8.54-13.54,111.46,111.46,0,0,1,39.12,43.09A8,8,0,0,1,224,71.1ZM35.71,72a8,8,0,0,0,7.1-4.32A94.13,94.13,0,0,1,76.27,30.77a8,8,0,1,0-8.54-13.54A111.46,111.46,0,0,0,28.61,60.32,8,8,0,0,0,35.71,72Zm186.1,103.94A16,16,0,0,1,208,200H167.2a40,40,0,0,1-78.4,0H48a16,16,0,0,1-13.79-24.06C43.22,160.39,48,138.28,48,112a80,80,0,0,1,160,0C208,138.27,212.78,160.38,221.81,175.94ZM150.62,200H105.38a24,24,0,0,0,45.24,0Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path
-        d="M208,192H48a8,8,0,0,1-6.88-12C47.71,168.6,56,147.81,56,112a72,72,0,0,1,144,0c0,35.82,8.3,56.6,14.9,68A8,8,0,0,1,208,192Z"
-        opacity="0.2"
-    ></path>
-    <path d="M224,71.1a8,8,0,0,1-10.78-3.42,94.13,94.13,0,0,0-33.46-36.91,8,8,0,1,1,8.54-13.54,111.46,111.46,0,0,1,39.12,43.09A8,8,0,0,1,224,71.1ZM35.71,72a8,8,0,0,0,7.1-4.32A94.13,94.13,0,0,1,76.27,30.77a8,8,0,1,0-8.54-13.54A111.46,111.46,0,0,0,28.61,60.32,8,8,0,0,0,35.71,72Zm186.1,103.94A16,16,0,0,1,208,200H167.2a40,40,0,0,1-78.4,0H48a16,16,0,0,1-13.79-24.06C43.22,160.39,48,138.28,48,112a80,80,0,0,1,160,0C208,138.27,212.78,160.38,221.81,175.94ZM150.62,200H105.38a24,24,0,0,0,45.24,0ZM208,184c-10.64-18.27-16-42.49-16-72a64,64,0,0,0-128,0c0,29.52-5.38,53.74-16,72Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M222.13,67.55a3.94,3.94,0,0,1-1.84.45,4,4,0,0,1-3.55-2.16,99.41,99.41,0,0,0-34.87-38.46,4,4,0,1,1,4.26-6.76,107.34,107.34,0,0,1,37.71,41.54A4,4,0,0,1,222.13,67.55ZM39.26,65.84A99.41,99.41,0,0,1,74.13,27.38a4,4,0,0,0-4.26-6.76A107.34,107.34,0,0,0,32.16,62.16a4,4,0,0,0,1.71,5.39,3.94,3.94,0,0,0,1.84.45A4,4,0,0,0,39.26,65.84ZM218.36,178A12,12,0,0,1,208,196H163.77a36,36,0,0,1-71.54,0H48A12,12,0,0,1,37.64,178C47.17,161.56,52,139.37,52,112a76,76,0,0,1,152,0C204,139.36,208.83,161.55,218.36,178ZM155.71,196H100.29a28,28,0,0,0,55.42,0Zm55.73-14C201.19,164.34,196,140.79,196,112a68,68,0,0,0-136,0c0,28.8-5.19,52.34-15.44,70a4,4,0,0,0,0,4A3.89,3.89,0,0,0,48,188H208a3.89,3.89,0,0,0,3.43-2A4,4,0,0,0,211.44,182Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M225.81,74.65A11.86,11.86,0,0,1,220.3,76a12,12,0,0,1-10.67-6.47,90.1,90.1,0,0,0-32-35.38,12,12,0,1,1,12.8-20.29,115.25,115.25,0,0,1,40.54,44.62A12,12,0,0,1,225.81,74.65ZM46.37,69.53a90.1,90.1,0,0,1,32-35.38A12,12,0,1,0,65.6,13.86,115.25,115.25,0,0,0,25.06,58.48a12,12,0,0,0,5.13,16.17A11.86,11.86,0,0,0,35.7,76,12,12,0,0,0,46.37,69.53Zm173.51,98.35A20,20,0,0,1,204,200H171.81a44,44,0,0,1-87.62,0H52a20,20,0,0,1-15.91-32.12c7.17-9.33,15.73-26.62,15.88-55.94A76,76,0,0,1,204,112C204.15,141.26,212.71,158.55,219.88,167.88ZM147.6,200H108.4a20,20,0,0,0,39.2,0Zm48.74-24c-8.16-13-16.19-33.57-16.34-63.94A52,52,0,1,0,76,112c-.15,30.42-8.18,51-16.34,64Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M223.05,69.33A6,6,0,0,1,215,66.76,96,96,0,0,0,180.8,29.08a6,6,0,0,1,6.4-10.15,109.26,109.26,0,0,1,38.41,42.31A6,6,0,0,1,223.05,69.33ZM41,66.76A96,96,0,0,1,75.2,29.08a6,6,0,0,0-6.4-10.15A109.26,109.26,0,0,0,30.39,61.24,6,6,0,1,0,41,66.76Zm179,110.18A14,14,0,0,1,208,198h-42.5a38,38,0,0,1-75,0H48a14,14,0,0,1-12.06-21.06C45.13,161.09,50,138.63,50,112a78,78,0,0,1,156,0C206,139,210.74,160.86,220.08,176.94ZM153.29,198H102.71a26,26,0,0,0,50.58,0Zm56.42-15C199.29,165,194,141.15,194,112a66,66,0,0,0-132,0c0,29.16-5.29,53-15.71,71a2,2,0,0,0,0,2,1.9,1.9,0,0,0,1.7,1H208a1.9,1.9,0,0,0,1.7-1A2,2,0,0,0,209.71,183Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M224,71.1a8,8,0,0,1-10.78-3.42,94.13,94.13,0,0,0-33.46-36.91,8,8,0,1,1,8.54-13.54,111.46,111.46,0,0,1,39.12,43.09A8,8,0,0,1,224,71.1ZM35.71,72a8,8,0,0,0,7.1-4.32A94.13,94.13,0,0,1,76.27,30.77a8,8,0,1,0-8.54-13.54A111.46,111.46,0,0,0,28.61,60.32,8,8,0,0,0,35.71,72Zm186.1,103.94A16,16,0,0,1,208,200H167.2a40,40,0,0,1-78.4,0H48a16,16,0,0,1-13.79-24.06C43.22,160.39,48,138.28,48,112a80,80,0,0,1,160,0C208,138.27,212.78,160.38,221.81,175.94ZM150.62,200H105.38a24,24,0,0,0,45.24,0ZM208,184c-10.64-18.27-16-42.49-16-72a64,64,0,0,0-128,0c0,29.52-5.38,53.74-16,72Z"></path>
-}.into_view()
-        }
-    });
-
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
-    let height = size.clone();
-
     view! {
         <svg
             xmlns="http://www.w3.org/2000/svg"
-            width=move || size.get()
-            height=move || height.get()
-            fill=color
-            transform=transform
+            width=size
+            height=size
+            fill="currentColor"
             viewBox="0 0 256 256"
-            id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
         >
-            {body}
+            <path d="M224,71.1a8,8,0,0,1-10.78-3.42,94.13,94.13,0,0,0-33.46-36.91,8,8,0,1,1,8.54-13.54,111.46,111.46,0,0,1,39.12,43.09A8,8,0,0,1,224,71.1ZM35.71,72a8,8,0,0,0,7.1-4.32A94.13,94.13,0,0,1,76.27,30.77a8,8,0,1,0-8.54-13.54A111.46,111.46,0,0,0,28.61,60.32,8,8,0,0,0,35.71,72Zm186.1,103.94A16,16,0,0,1,208,200H167.2a40,40,0,0,1-78.4,0H48a16,16,0,0,1-13.79-24.06C43.22,160.39,48,138.28,48,112a80,80,0,0,1,160,0C208,138.27,212.78,160.38,221.81,175.94ZM150.62,200H105.38a24,24,0,0,0,45.24,0ZM208,184c-10.64-18.27-16-42.49-16-72a64,64,0,0,0-128,0c0,29.52-5.38,53.74-16,72Z"></path>
         </svg>
     }
 }
diff --git a/aep-schedule-website/src/frontend/components/icons/bug.rs b/aep-schedule-website/src/frontend/components/icons/bug.rs
index daafa574312ce8ce4cd33c633d3447971f516b73..54868b0f9b802a2743e3f72a2aed1bb240e2695f 100644
--- a/aep-schedule-website/src/frontend/components/icons/bug.rs
+++ b/aep-schedule-website/src/frontend/components/icons/bug.rs
@@ -1,57 +1,20 @@
-//! GENERATED FILE
-use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn Bug(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
-    #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
-    #[prop(into, optional)] id: MaybeProp<TextProp>,
+    size: &'static str,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
-            IconWeight::Fill => view! {
-                <path d="M168,92a12,12,0,1,1-12-12A12,12,0,0,1,168,92ZM100,80a12,12,0,1,0,12,12A12,12,0,0,0,100,80Zm116,64A87.76,87.76,0,0,1,213,167l22.24,9.72A8,8,0,0,1,232,192a7.89,7.89,0,0,1-3.2-.67L207.38,182a88,88,0,0,1-158.76,0L27.2,191.33A7.89,7.89,0,0,1,24,192a8,8,0,0,1-3.2-15.33L43,167A87.76,87.76,0,0,1,40,144v-8H16a8,8,0,0,1,0-16H40v-8a87.76,87.76,0,0,1,3-23L20.8,79.33a8,8,0,1,1,6.4-14.66L48.62,74a88,88,0,0,1,158.76,0l21.42-9.36a8,8,0,0,1,6.4,14.66L213,89.05a87.76,87.76,0,0,1,3,23v8h24a8,8,0,0,1,0,16H216Zm-80,0a8,8,0,0,0-16,0v64a8,8,0,0,0,16,0Zm64-32a72,72,0,0,0-144,0v8H200Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path d="M208,128v16a80,80,0,0,1-160,0V128Z" opacity="0.2"></path>
-    <path d="M144,92a12,12,0,1,1,12,12A12,12,0,0,1,144,92ZM100,80a12,12,0,1,0,12,12A12,12,0,0,0,100,80Zm116,64A87.76,87.76,0,0,1,213,167l22.24,9.72A8,8,0,0,1,232,192a7.89,7.89,0,0,1-3.2-.67L207.38,182a88,88,0,0,1-158.76,0L27.2,191.33A7.89,7.89,0,0,1,24,192a8,8,0,0,1-3.2-15.33L43,167A87.76,87.76,0,0,1,40,144v-8H16a8,8,0,0,1,0-16H40v-8a87.76,87.76,0,0,1,3-23L20.8,79.33a8,8,0,1,1,6.4-14.66L48.62,74a88,88,0,0,1,158.76,0l21.42-9.36a8,8,0,0,1,6.4,14.66L213,89.05a87.76,87.76,0,0,1,3,23v8h24a8,8,0,0,1,0,16H216ZM56,120H200v-8a72,72,0,0,0-144,0Zm64,95.54V136H56v8A72.08,72.08,0,0,0,120,215.54ZM200,144v-8H136v79.54A72.08,72.08,0,0,0,200,144Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M148,92a8,8,0,1,1,8,8A8,8,0,0,1,148,92Zm-48-8a8,8,0,1,0,8,8A8,8,0,0,0,100,84Zm144,44a4,4,0,0,1-4,4H212v12a83.64,83.64,0,0,1-3.87,25.2l25.47,11.13A4,4,0,0,1,232,188a4.09,4.09,0,0,1-1.6-.33l-25-10.95a84,84,0,0,1-154.72,0l-25,10.95A4.09,4.09,0,0,1,24,188a4,4,0,0,1-1.6-7.67L47.87,169.2A83.64,83.64,0,0,1,44,144V132H16a4,4,0,0,1,0-8H44V112a83.64,83.64,0,0,1,3.87-25.2L22.4,75.67a4,4,0,0,1,3.2-7.34l25,11a84,84,0,0,1,154.72,0l25-11a4,4,0,1,1,3.2,7.34L208.13,86.8A83.64,83.64,0,0,1,212,112v12h28A4,4,0,0,1,244,128ZM52,124H204V112a76,76,0,0,0-152,0Zm72,95.89V132H52v12A76.09,76.09,0,0,0,124,219.89ZM204,132H132v87.89A76.09,76.09,0,0,0,204,144Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M140,88a16,16,0,1,1,16,16A16,16,0,0,1,140,88ZM100,72a16,16,0,1,0,16,16A16,16,0,0,0,100,72Zm120,72a91.84,91.84,0,0,1-2.34,20.64L236.81,173a12,12,0,0,1-9.62,22l-18-7.85a92,92,0,0,1-162.46,0l-18,7.85a12,12,0,1,1-9.62-22l19.15-8.36A91.84,91.84,0,0,1,36,144v-4H16a12,12,0,0,1,0-24H36v-4a91.84,91.84,0,0,1,2.34-20.64L19.19,83a12,12,0,0,1,9.62-22l18,7.85a92,92,0,0,1,162.46,0l18-7.85a12,12,0,1,1,9.62,22l-19.15,8.36A91.84,91.84,0,0,1,220,112v4h20a12,12,0,0,1,0,24H220ZM60,116H196v-4a68,68,0,0,0-136,0Zm56,94.92V140H60v4A68.1,68.1,0,0,0,116,210.92ZM196,144v-4H140v70.92A68.1,68.1,0,0,0,196,144Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M146,92a10,10,0,1,1,10,10A10,10,0,0,1,146,92ZM100,82a10,10,0,1,0,10,10A10,10,0,0,0,100,82Zm146,46a6,6,0,0,1-6,6H214v10a85.88,85.88,0,0,1-3.45,24.08L234.4,178.5a6,6,0,0,1-4.8,11l-23.23-10.15a86,86,0,0,1-156.74,0L26.4,189.5a6,6,0,1,1-4.8-11l23.85-10.42A85.88,85.88,0,0,1,42,144V134H16a6,6,0,0,1,0-12H42V112a85.88,85.88,0,0,1,3.45-24.08L21.6,77.5a6,6,0,0,1,4.8-11L49.63,76.65a86,86,0,0,1,156.74,0L229.6,66.5a6,6,0,1,1,4.8,11L210.55,87.92A85.88,85.88,0,0,1,214,112v10h26A6,6,0,0,1,246,128ZM54,122H202V112a74,74,0,0,0-148,0Zm68,95.74V134H54v10A74.09,74.09,0,0,0,122,217.74ZM202,134H134v83.74A74.09,74.09,0,0,0,202,144Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M144,92a12,12,0,1,1,12,12A12,12,0,0,1,144,92ZM100,80a12,12,0,1,0,12,12A12,12,0,0,0,100,80Zm116,64A87.76,87.76,0,0,1,213,167l22.24,9.72A8,8,0,0,1,232,192a7.89,7.89,0,0,1-3.2-.67L207.38,182a88,88,0,0,1-158.76,0L27.2,191.33A7.89,7.89,0,0,1,24,192a8,8,0,0,1-3.2-15.33L43,167A87.76,87.76,0,0,1,40,144v-8H16a8,8,0,0,1,0-16H40v-8a87.76,87.76,0,0,1,3-23L20.8,79.33a8,8,0,1,1,6.4-14.66L48.62,74a88,88,0,0,1,158.76,0l21.42-9.36a8,8,0,0,1,6.4,14.66L213,89.05a87.76,87.76,0,0,1,3,23v8h24a8,8,0,0,1,0,16H216ZM56,120H200v-8a72,72,0,0,0-144,0Zm64,95.54V136H56v8A72.08,72.08,0,0,0,120,215.54ZM200,144v-8H136v79.54A72.08,72.08,0,0,0,200,144Z"></path>
-}.into_view()
-        }
-    });
-
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
-    let height = size.clone();
-
     view! {
         <svg
             xmlns="http://www.w3.org/2000/svg"
-            width=move || size.get()
-            height=move || height.get()
-            fill=color
-            transform=transform
+            width=size
+            height=size
+            fill="currentColor"
             viewBox="0 0 256 256"
-            id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
         >
-            {body}
+            <path d="M144,92a12,12,0,1,1,12,12A12,12,0,0,1,144,92ZM100,80a12,12,0,1,0,12,12A12,12,0,0,0,100,80Zm116,64A87.76,87.76,0,0,1,213,167l22.24,9.72A8,8,0,0,1,232,192a7.89,7.89,0,0,1-3.2-.67L207.38,182a88,88,0,0,1-158.76,0L27.2,191.33A7.89,7.89,0,0,1,24,192a8,8,0,0,1-3.2-15.33L43,167A87.76,87.76,0,0,1,40,144v-8H16a8,8,0,0,1,0-16H40v-8a87.76,87.76,0,0,1,3-23L20.8,79.33a8,8,0,1,1,6.4-14.66L48.62,74a88,88,0,0,1,158.76,0l21.42-9.36a8,8,0,0,1,6.4,14.66L213,89.05a87.76,87.76,0,0,1,3,23v8h24a8,8,0,0,1,0,16H216ZM56,120H200v-8a72,72,0,0,0-144,0Zm64,95.54V136H56v8A72.08,72.08,0,0,0,120,215.54ZM200,144v-8H136v79.54A72.08,72.08,0,0,0,200,144Z"></path>
         </svg>
     }
 }
diff --git a/aep-schedule-website/src/frontend/components/icons/calendar_check.rs b/aep-schedule-website/src/frontend/components/icons/calendar_check.rs
index 3ce85ad3992406522d319d22ad3efbe97355d9c1..880168aa17598dd8999175a6038b8dd0e27496e4 100644
--- a/aep-schedule-website/src/frontend/components/icons/calendar_check.rs
+++ b/aep-schedule-website/src/frontend/components/icons/calendar_check.rs
@@ -1,53 +1,42 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{either::EitherOf6, prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn CalendarCheck(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: Signal<IconWeight>,
+    #[prop(into)] size: &'static str,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
-            IconWeight::Fill => view! {
-                <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM169.66,133.66l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35a8,8,0,0,1,11.32,11.32ZM48,80V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path d="M216,48V88H40V48a8,8,0,0,1,8-8H208A8,8,0,0,1,216,48Z" opacity="0.2"></path>
-    <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-38.34-85.66a8,8,0,0,1,0,11.32l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35A8,8,0,0,1,169.66,122.34Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M208,36H180V24a4,4,0,0,0-8,0V36H84V24a4,4,0,0,0-8,0V36H48A12,12,0,0,0,36,48V208a12,12,0,0,0,12,12H208a12,12,0,0,0,12-12V48A12,12,0,0,0,208,36ZM48,44H76V56a4,4,0,0,0,8,0V44h88V56a4,4,0,0,0,8,0V44h28a4,4,0,0,1,4,4V84H44V48A4,4,0,0,1,48,44ZM208,212H48a4,4,0,0,1-4-4V92H212V208A4,4,0,0,1,208,212Zm-41.17-86.83a4,4,0,0,1,0,5.66l-48,48a4,4,0,0,1-5.66,0l-24-24a4,4,0,0,1,5.66-5.66L116,170.34l45.17-45.17A4,4,0,0,1,166.83,125.17Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M208,28H188V24a12,12,0,0,0-24,0v4H92V24a12,12,0,0,0-24,0v4H48A20,20,0,0,0,28,48V208a20,20,0,0,0,20,20H208a20,20,0,0,0,20-20V48A20,20,0,0,0,208,28ZM68,52a12,12,0,0,0,24,0h72a12,12,0,0,0,24,0h16V76H52V52ZM52,204V100H204V204Zm120.49-84.49a12,12,0,0,1,0,17l-48,48a12,12,0,0,1-17,0l-24-24a12,12,0,0,1,17-17L116,159l39.51-39.52A12,12,0,0,1,172.49,119.51Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M208,34H182V24a6,6,0,0,0-12,0V34H86V24a6,6,0,0,0-12,0V34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34ZM48,46H74V56a6,6,0,0,0,12,0V46h84V56a6,6,0,0,0,12,0V46h26a2,2,0,0,1,2,2V82H46V48A2,2,0,0,1,48,46ZM208,210H48a2,2,0,0,1-2-2V94H210V208A2,2,0,0,1,208,210Zm-39.76-86.24a6,6,0,0,1,0,8.48l-48,48a6,6,0,0,1-8.48,0l-24-24a6,6,0,0,1,8.48-8.48L116,167.51l43.76-43.75A6,6,0,0,1,168.24,123.76Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-38.34-85.66a8,8,0,0,1,0,11.32l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35A8,8,0,0,1,169.66,122.34Z"></path>
-}.into_view()
-        }
-    });
-
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
-    let height = size.clone();
+    let body = move || match weight.get() {
+        IconWeight::Fill => EitherOf6::A(view! {
+            <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM169.66,133.66l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35a8,8,0,0,1,11.32,11.32ZM48,80V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80Z"></path>
+        }),
+        IconWeight::Duotone => EitherOf6::B(view! {
+            <path d="M216,48V88H40V48a8,8,0,0,1,8-8H208A8,8,0,0,1,216,48Z" opacity="0.2"></path>
+            <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-38.34-85.66a8,8,0,0,1,0,11.32l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35A8,8,0,0,1,169.66,122.34Z"></path>
+        }),
+        IconWeight::Thin => EitherOf6::C(view! {
+            <path d="M208,36H180V24a4,4,0,0,0-8,0V36H84V24a4,4,0,0,0-8,0V36H48A12,12,0,0,0,36,48V208a12,12,0,0,0,12,12H208a12,12,0,0,0,12-12V48A12,12,0,0,0,208,36ZM48,44H76V56a4,4,0,0,0,8,0V44h88V56a4,4,0,0,0,8,0V44h28a4,4,0,0,1,4,4V84H44V48A4,4,0,0,1,48,44ZM208,212H48a4,4,0,0,1-4-4V92H212V208A4,4,0,0,1,208,212Zm-41.17-86.83a4,4,0,0,1,0,5.66l-48,48a4,4,0,0,1-5.66,0l-24-24a4,4,0,0,1,5.66-5.66L116,170.34l45.17-45.17A4,4,0,0,1,166.83,125.17Z"></path>
+        }),
+        IconWeight::Bold => EitherOf6::D(view! {
+            <path d="M208,28H188V24a12,12,0,0,0-24,0v4H92V24a12,12,0,0,0-24,0v4H48A20,20,0,0,0,28,48V208a20,20,0,0,0,20,20H208a20,20,0,0,0,20-20V48A20,20,0,0,0,208,28ZM68,52a12,12,0,0,0,24,0h72a12,12,0,0,0,24,0h16V76H52V52ZM52,204V100H204V204Zm120.49-84.49a12,12,0,0,1,0,17l-48,48a12,12,0,0,1-17,0l-24-24a12,12,0,0,1,17-17L116,159l39.51-39.52A12,12,0,0,1,172.49,119.51Z"></path>
+        }),
+        IconWeight::Light => EitherOf6::E(view! {
+            <path d="M208,34H182V24a6,6,0,0,0-12,0V34H86V24a6,6,0,0,0-12,0V34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34ZM48,46H74V56a6,6,0,0,0,12,0V46h84V56a6,6,0,0,0,12,0V46h26a2,2,0,0,1,2,2V82H46V48A2,2,0,0,1,48,46ZM208,210H48a2,2,0,0,1-2-2V94H210V208A2,2,0,0,1,208,210Zm-39.76-86.24a6,6,0,0,1,0,8.48l-48,48a6,6,0,0,1-8.48,0l-24-24a6,6,0,0,1,8.48-8.48L116,167.51l43.76-43.75A6,6,0,0,1,168.24,123.76Z"></path>
+        }),
+        IconWeight::Regular => EitherOf6::F(view! {
+            <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-38.34-85.66a8,8,0,0,1,0,11.32l-48,48a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L116,164.69l42.34-42.35A8,8,0,0,1,169.66,122.34Z"></path>
+        }),
+    };
 
     view! {
         <svg
             xmlns="http://www.w3.org/2000/svg"
-            width=move || size.get()
-            height=move || height.get()
-            fill=color
-            transform=transform
+            width=size
+            height=size
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/calendar_x.rs b/aep-schedule-website/src/frontend/components/icons/calendar_x.rs
index c2d86ea4bb2902e3ffb515fea94598bcaec2fe8a..f431dc7589b0dc5be00ac998de0f8e46ca5bef57 100644
--- a/aep-schedule-website/src/frontend/components/icons/calendar_x.rs
+++ b/aep-schedule-website/src/frontend/components/icons/calendar_x.rs
@@ -1,44 +1,37 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn CalendarX(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: IconWeight,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body =
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM157.66,170.34a8,8,0,0,1-11.32,11.32L128,163.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L116.69,152,98.34,133.66a8,8,0,0,1,11.32-11.32L128,140.69l18.34-18.35a8,8,0,0,1,11.32,11.32L139.31,152ZM208,80H48V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path d="M216,48V88H40V48a8,8,0,0,1,8-8H208A8,8,0,0,1,216,48Z" opacity="0.2"></path>
-    <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-50.34-74.34L139.31,152l18.35,18.34a8,8,0,0,1-11.32,11.32L128,163.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L116.69,152,98.34,133.66a8,8,0,0,1,11.32-11.32L128,140.69l18.34-18.35a8,8,0,0,1,11.32,11.32Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M208,36H180V24a4,4,0,0,0-8,0V36H84V24a4,4,0,0,0-8,0V36H48A12,12,0,0,0,36,48V208a12,12,0,0,0,12,12H208a12,12,0,0,0,12-12V48A12,12,0,0,0,208,36ZM48,44H76V56a4,4,0,0,0,8,0V44h88V56a4,4,0,0,0,8,0V44h28a4,4,0,0,1,4,4V84H44V48A4,4,0,0,1,48,44ZM208,212H48a4,4,0,0,1-4-4V92H212V208A4,4,0,0,1,208,212Zm-53.17-81.17L133.66,152l21.17,21.17a4,4,0,0,1-5.66,5.66L128,157.66l-21.17,21.17a4,4,0,0,1-5.66-5.66L122.34,152l-21.17-21.17a4,4,0,1,1,5.66-5.66L128,146.34l21.17-21.17a4,4,0,1,1,5.66,5.66Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M160.49,136.49,145,152l15.52,15.51a12,12,0,0,1-17,17L128,169l-15.51,15.52a12,12,0,0,1-17-17L111,152,95.51,136.49a12,12,0,1,1,17-17L128,135l15.51-15.52a12,12,0,1,1,17,17ZM228,48V208a20,20,0,0,1-20,20H48a20,20,0,0,1-20-20V48A20,20,0,0,1,48,28H68V24a12,12,0,0,1,24,0v4h72V24a12,12,0,0,1,24,0v4h20A20,20,0,0,1,228,48ZM52,52V76H204V52H188a12,12,0,0,1-24,0H92a12,12,0,0,1-24,0ZM204,204V100H52V204Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M208,34H182V24a6,6,0,0,0-12,0V34H86V24a6,6,0,0,0-12,0V34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34ZM48,46H74V56a6,6,0,0,0,12,0V46h84V56a6,6,0,0,0,12,0V46h26a2,2,0,0,1,2,2V82H46V48A2,2,0,0,1,48,46ZM208,210H48a2,2,0,0,1-2-2V94H210V208A2,2,0,0,1,208,210Zm-51.76-77.76L136.48,152l19.76,19.76a6,6,0,1,1-8.48,8.48L128,160.48l-19.76,19.76a6,6,0,0,1-8.48-8.48L119.52,152,99.76,132.24a6,6,0,1,1,8.48-8.48L128,143.52l19.76-19.76a6,6,0,1,1,8.48,8.48Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-50.34-74.34L139.31,152l18.35,18.34a8,8,0,0,1-11.32,11.32L128,163.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L116.69,152,98.34,133.66a8,8,0,0,1,11.32-11.32L128,140.69l18.34-18.35a8,8,0,0,1,11.32,11.32Z"></path>
-}.into_view()
-        }
-    });
+            }.into_any(),
+        IconWeight::Duotone => view! {
+            <path d="M216,48V88H40V48a8,8,0,0,1,8-8H208A8,8,0,0,1,216,48Z" opacity="0.2"></path>
+            <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-50.34-74.34L139.31,152l18.35,18.34a8,8,0,0,1-11.32,11.32L128,163.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L116.69,152,98.34,133.66a8,8,0,0,1,11.32-11.32L128,140.69l18.34-18.35a8,8,0,0,1,11.32,11.32Z"></path>
+        }.into_any(),
+        IconWeight::Thin => view! {
+            <path d="M208,36H180V24a4,4,0,0,0-8,0V36H84V24a4,4,0,0,0-8,0V36H48A12,12,0,0,0,36,48V208a12,12,0,0,0,12,12H208a12,12,0,0,0,12-12V48A12,12,0,0,0,208,36ZM48,44H76V56a4,4,0,0,0,8,0V44h88V56a4,4,0,0,0,8,0V44h28a4,4,0,0,1,4,4V84H44V48A4,4,0,0,1,48,44ZM208,212H48a4,4,0,0,1-4-4V92H212V208A4,4,0,0,1,208,212Zm-53.17-81.17L133.66,152l21.17,21.17a4,4,0,0,1-5.66,5.66L128,157.66l-21.17,21.17a4,4,0,0,1-5.66-5.66L122.34,152l-21.17-21.17a4,4,0,1,1,5.66-5.66L128,146.34l21.17-21.17a4,4,0,1,1,5.66,5.66Z"></path>
+        }.into_any(),
+        IconWeight::Bold => view! {
+            <path d="M160.49,136.49,145,152l15.52,15.51a12,12,0,0,1-17,17L128,169l-15.51,15.52a12,12,0,0,1-17-17L111,152,95.51,136.49a12,12,0,1,1,17-17L128,135l15.51-15.52a12,12,0,1,1,17,17ZM228,48V208a20,20,0,0,1-20,20H48a20,20,0,0,1-20-20V48A20,20,0,0,1,48,28H68V24a12,12,0,0,1,24,0v4h72V24a12,12,0,0,1,24,0v4h20A20,20,0,0,1,228,48ZM52,52V76H204V52H188a12,12,0,0,1-24,0H92a12,12,0,0,1-24,0ZM204,204V100H52V204Z"></path>
+        }.into_any(),
+        IconWeight::Light => view! {
+            <path d="M208,34H182V24a6,6,0,0,0-12,0V34H86V24a6,6,0,0,0-12,0V34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34ZM48,46H74V56a6,6,0,0,0,12,0V46h84V56a6,6,0,0,0,12,0V46h26a2,2,0,0,1,2,2V82H46V48A2,2,0,0,1,48,46ZM208,210H48a2,2,0,0,1-2-2V94H210V208A2,2,0,0,1,208,210Zm-51.76-77.76L136.48,152l19.76,19.76a6,6,0,1,1-8.48,8.48L128,160.48l-19.76,19.76a6,6,0,0,1-8.48-8.48L119.52,152,99.76,132.24a6,6,0,1,1,8.48-8.48L128,143.52l19.76-19.76a6,6,0,1,1,8.48,8.48Z"></path>
+        }.into_any(),
+        IconWeight::Regular => view! {
+            <path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-50.34-74.34L139.31,152l18.35,18.34a8,8,0,0,1-11.32,11.32L128,163.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L116.69,152,98.34,133.66a8,8,0,0,1,11.32-11.32L128,140.69l18.34-18.35a8,8,0,0,1,11.32,11.32Z"></path>
+        }.into_any()
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -46,8 +39,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/caret_double_right.rs b/aep-schedule-website/src/frontend/components/icons/caret_double_right.rs
index 9acd383aa3d4079d5613daad776f8475de4a273b..83b007a632925446b7293eb02aba464d8e722e2e 100644
--- a/aep-schedule-website/src/frontend/components/icons/caret_double_right.rs
+++ b/aep-schedule-website/src/frontend/components/icons/caret_double_right.rs
@@ -1,44 +1,37 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn CaretDoubleRight(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into, default = IconWeight::Regular)] weight: IconWeight,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body =
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M221.66,133.66l-80,80A8,8,0,0,1,128,208V147.31L61.66,213.66A8,8,0,0,1,48,208V48a8,8,0,0,1,13.66-5.66L128,108.69V48a8,8,0,0,1,13.66-5.66l80,80A8,8,0,0,1,221.66,133.66Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path d="M136,128,56,208V48Z" opacity="0.2"></path>
-    <path d="M141.66,122.34l-80-80A8,8,0,0,0,48,48V208a8,8,0,0,0,13.66,5.66l80-80A8,8,0,0,0,141.66,122.34ZM64,188.69V67.31L124.69,128Zm157.66-55-80,80a8,8,0,0,1-11.32-11.32L204.69,128,130.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,221.66,133.66Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M138.83,130.83l-80,80a4,4,0,0,1-5.66-5.66L130.34,128,53.17,50.83a4,4,0,0,1,5.66-5.66l80,80A4,4,0,0,1,138.83,130.83Zm80-5.66-80-80a4,4,0,0,0-5.66,5.66L210.34,128l-77.17,77.17a4,4,0,0,0,5.66,5.66l80-80A4,4,0,0,0,218.83,125.17Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M144.49,136.49l-80,80a12,12,0,0,1-17-17L119,128,47.51,56.49a12,12,0,0,1,17-17l80,80A12,12,0,0,1,144.49,136.49Zm80-17-80-80a12,12,0,1,0-17,17L199,128l-71.52,71.51a12,12,0,0,0,17,17l80-80A12,12,0,0,0,224.49,119.51Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M140.24,132.24l-80,80a6,6,0,0,1-8.48-8.48L127.51,128,51.76,52.24a6,6,0,0,1,8.48-8.48l80,80A6,6,0,0,1,140.24,132.24Zm80-8.48-80-80a6,6,0,0,0-8.48,8.48L207.51,128l-75.75,75.76a6,6,0,1,0,8.48,8.48l80-80A6,6,0,0,0,220.24,123.76Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M141.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L124.69,128,50.34,53.66A8,8,0,0,1,61.66,42.34l80,80A8,8,0,0,1,141.66,133.66Zm80-11.32-80-80a8,8,0,0,0-11.32,11.32L204.69,128l-74.35,74.34a8,8,0,0,0,11.32,11.32l80-80A8,8,0,0,0,221.66,122.34Z"></path>
-}.into_view()
-        }
-    });
+            }.into_any(),
+        IconWeight::Duotone => view! {
+            <path d="M136,128,56,208V48Z" opacity="0.2"></path>
+            <path d="M141.66,122.34l-80-80A8,8,0,0,0,48,48V208a8,8,0,0,0,13.66,5.66l80-80A8,8,0,0,0,141.66,122.34ZM64,188.69V67.31L124.69,128Zm157.66-55-80,80a8,8,0,0,1-11.32-11.32L204.69,128,130.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,221.66,133.66Z"></path>
+        }.into_any(),
+        IconWeight::Thin => view! {
+            <path d="M138.83,130.83l-80,80a4,4,0,0,1-5.66-5.66L130.34,128,53.17,50.83a4,4,0,0,1,5.66-5.66l80,80A4,4,0,0,1,138.83,130.83Zm80-5.66-80-80a4,4,0,0,0-5.66,5.66L210.34,128l-77.17,77.17a4,4,0,0,0,5.66,5.66l80-80A4,4,0,0,0,218.83,125.17Z"></path>
+        }.into_any(),
+        IconWeight::Bold => view! {
+            <path d="M144.49,136.49l-80,80a12,12,0,0,1-17-17L119,128,47.51,56.49a12,12,0,0,1,17-17l80,80A12,12,0,0,1,144.49,136.49Zm80-17-80-80a12,12,0,1,0-17,17L199,128l-71.52,71.51a12,12,0,0,0,17,17l80-80A12,12,0,0,0,224.49,119.51Z"></path>
+        }.into_any(),
+        IconWeight::Light => view! {
+            <path d="M140.24,132.24l-80,80a6,6,0,0,1-8.48-8.48L127.51,128,51.76,52.24a6,6,0,0,1,8.48-8.48l80,80A6,6,0,0,1,140.24,132.24Zm80-8.48-80-80a6,6,0,0,0-8.48,8.48L207.51,128l-75.75,75.76a6,6,0,1,0,8.48,8.48l80-80A6,6,0,0,0,220.24,123.76Z"></path>
+        }.into_any(),
+        IconWeight::Regular => view! {
+            <path d="M141.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L124.69,128,50.34,53.66A8,8,0,0,1,61.66,42.34l80,80A8,8,0,0,1,141.66,133.66Zm80-11.32-80-80a8,8,0,0,0-11.32,11.32L204.69,128l-74.35,74.34a8,8,0,0,0,11.32,11.32l80-80A8,8,0,0,0,221.66,122.34Z"></path>
+        }.into_any()
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -46,8 +39,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/download.rs b/aep-schedule-website/src/frontend/components/icons/download.rs
index 2621f7207a23c3e0872c2ceca4fe719a8d3db098..35cbea70246fe48f5f0bac00db0d917686eb9b81 100644
--- a/aep-schedule-website/src/frontend/components/icons/download.rs
+++ b/aep-schedule-website/src/frontend/components/icons/download.rs
@@ -1,47 +1,40 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn Download(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: IconWeight,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body =
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M74.34,85.66A8,8,0,0,1,85.66,74.34L120,108.69V24a8,8,0,0,1,16,0v84.69l34.34-34.35a8,8,0,0,1,11.32,11.32l-48,48a8,8,0,0,1-11.32,0ZM240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H84.4a4,4,0,0,1,2.83,1.17L111,145A24,24,0,0,0,145,145l23.8-23.8A4,4,0,0,1,171.6,120H224A16,16,0,0,1,240,136Zm-40,32a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path
-        d="M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z"
-        opacity="0.2"
-    ></path>
-    <path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M236,136v64a12,12,0,0,1-12,12H32a12,12,0,0,1-12-12V136a12,12,0,0,1,12-12H72a4,4,0,0,1,0,8H32a4,4,0,0,0-4,4v64a4,4,0,0,0,4,4H224a4,4,0,0,0,4-4V136a4,4,0,0,0-4-4H184a4,4,0,0,1,0-8h40A12,12,0,0,1,236,136Zm-110.83-5.17a4,4,0,0,0,5.66,0l48-48a4,4,0,1,0-5.66-5.66L132,118.34V24a4,4,0,0,0-8,0v94.34L82.83,77.17a4,4,0,0,0-5.66,5.66ZM196,168a8,8,0,1,0-8,8A8,8,0,0,0,196,168Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M71.51,88.49a12,12,0,0,1,17-17L116,99V24a12,12,0,0,1,24,0V99l27.51-27.52a12,12,0,0,1,17,17l-48,48a12,12,0,0,1-17,0ZM224,116H188a12,12,0,0,0,0,24h32v56H36V140H68a12,12,0,0,0,0-24H32a20,20,0,0,0-20,20v64a20,20,0,0,0,20,20H224a20,20,0,0,0,20-20V136A20,20,0,0,0,224,116Zm-20,52a16,16,0,1,0-16,16A16,16,0,0,0,204,168Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M238,136v64a14,14,0,0,1-14,14H32a14,14,0,0,1-14-14V136a14,14,0,0,1,14-14H72a6,6,0,0,1,0,12H32a2,2,0,0,0-2,2v64a2,2,0,0,0,2,2H224a2,2,0,0,0,2-2V136a2,2,0,0,0-2-2H184a6,6,0,0,1,0-12h40A14,14,0,0,1,238,136Zm-114.24-3.76a6,6,0,0,0,8.48,0l48-48a6,6,0,0,0-8.48-8.48L134,113.51V24a6,6,0,0,0-12,0v89.51L84.24,75.76a6,6,0,0,0-8.48,8.48ZM198,168a10,10,0,1,0-10,10A10,10,0,0,0,198,168Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path>
-}.into_view()
-        }
-    });
+            }.into_any(),
+        IconWeight::Duotone => view! {
+            <path
+                d="M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z"
+                opacity="0.2"
+            ></path>
+            <path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path>
+        }.into_any(),
+        IconWeight::Thin => view! {
+            <path d="M236,136v64a12,12,0,0,1-12,12H32a12,12,0,0,1-12-12V136a12,12,0,0,1,12-12H72a4,4,0,0,1,0,8H32a4,4,0,0,0-4,4v64a4,4,0,0,0,4,4H224a4,4,0,0,0,4-4V136a4,4,0,0,0-4-4H184a4,4,0,0,1,0-8h40A12,12,0,0,1,236,136Zm-110.83-5.17a4,4,0,0,0,5.66,0l48-48a4,4,0,1,0-5.66-5.66L132,118.34V24a4,4,0,0,0-8,0v94.34L82.83,77.17a4,4,0,0,0-5.66,5.66ZM196,168a8,8,0,1,0-8,8A8,8,0,0,0,196,168Z"></path>
+        }.into_any(),
+        IconWeight::Bold => view! {
+            <path d="M71.51,88.49a12,12,0,0,1,17-17L116,99V24a12,12,0,0,1,24,0V99l27.51-27.52a12,12,0,0,1,17,17l-48,48a12,12,0,0,1-17,0ZM224,116H188a12,12,0,0,0,0,24h32v56H36V140H68a12,12,0,0,0,0-24H32a20,20,0,0,0-20,20v64a20,20,0,0,0,20,20H224a20,20,0,0,0,20-20V136A20,20,0,0,0,224,116Zm-20,52a16,16,0,1,0-16,16A16,16,0,0,0,204,168Z"></path>
+        }.into_any(),
+        IconWeight::Light => view! {
+            <path d="M238,136v64a14,14,0,0,1-14,14H32a14,14,0,0,1-14-14V136a14,14,0,0,1,14-14H72a6,6,0,0,1,0,12H32a2,2,0,0,0-2,2v64a2,2,0,0,0,2,2H224a2,2,0,0,0,2-2V136a2,2,0,0,0-2-2H184a6,6,0,0,1,0-12h40A14,14,0,0,1,238,136Zm-114.24-3.76a6,6,0,0,0,8.48,0l48-48a6,6,0,0,0-8.48-8.48L134,113.51V24a6,6,0,0,0-12,0v89.51L84.24,75.76a6,6,0,0,0-8.48,8.48ZM198,168a10,10,0,1,0-10,10A10,10,0,0,0,198,168Z"></path>
+        }.into_any(),
+        IconWeight::Regular => view! {
+            <path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path>
+        }.into_any()
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -49,8 +42,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/gitlab_logo.rs b/aep-schedule-website/src/frontend/components/icons/gitlab_logo.rs
index e58337c2261f6b9506f2a017544fcae8a6e1fae5..1852a3a170cd1b81210e285bfe0d680f433bd3fc 100644
--- a/aep-schedule-website/src/frontend/components/icons/gitlab_logo.rs
+++ b/aep-schedule-website/src/frontend/components/icons/gitlab_logo.rs
@@ -1,47 +1,41 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn GitlabLogo(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: Signal<IconWeight>,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
+    let body = move || {
         match weight.get() {
             IconWeight::Fill => view! {
                 <path d="M230.15,117.1,210.25,41a11.94,11.94,0,0,0-22.79-1.11L169.78,88H86.22L68.54,39.87A11.94,11.94,0,0,0,45.75,41L25.85,117.1a57.19,57.19,0,0,0,22,61l73.27,51.76a11.91,11.91,0,0,0,13.74,0l73.27-51.76A57.19,57.19,0,0,0,230.15,117.1Zm-189.47,7L114.13,176,93.41,190.65,57.09,165A41.06,41.06,0,0,1,40.68,124.11Zm87.32,91-20.73-14.65L128,185.8l20.73,14.64ZM198.91,165l-36.32,25.66L141.87,176l73.45-51.9A41.06,41.06,0,0,1,198.91,165Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path
         d="M220.23,110.84,128,176,35.77,110.84,53.5,43A3.93,3.93,0,0,1,61,42.62L80.65,96h94.7L195,42.62a3.93,3.93,0,0,1,7.53.38Z"
         opacity="0.2"
     ></path>
     <path d="M230.15,117.1,210.25,41a11.94,11.94,0,0,0-22.79-1.11L169.78,88H86.22L68.54,39.87A11.94,11.94,0,0,0,45.75,41L25.85,117.1a57.19,57.19,0,0,0,22,61l73.27,51.76a11.91,11.91,0,0,0,13.74,0l73.27-51.76A57.19,57.19,0,0,0,230.15,117.1ZM58,57.5,73.13,98.76A8,8,0,0,0,80.64,104h94.72a8,8,0,0,0,7.51-5.24L198,57.5l13.07,50L128,166.21,44.9,107.5ZM40.68,124.11,114.13,176,93.41,190.65,57.09,165A41.06,41.06,0,0,1,40.68,124.11Zm87.32,91-20.73-14.65L128,185.8l20.73,14.64ZM198.91,165l-36.32,25.66L141.87,176l73.45-51.9A41.06,41.06,0,0,1,198.91,165Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M226.27,118.11,206.38,42a7.94,7.94,0,0,0-15.16-.75L172.57,92H83.43L64.78,41.24A7.94,7.94,0,0,0,49.62,42L29.73,118.11a53.16,53.16,0,0,0,20.44,56.68l73.27,51.76a7.9,7.9,0,0,0,9.12,0l73.27-51.76A53.16,53.16,0,0,0,226.27,118.11Zm-169-74L76.89,97.38A4,4,0,0,0,80.64,100h94.72a4,4,0,0,0,3.75-2.62l19.57-53.22,17,65L128,171.11,40.33,109.17Zm-19.84,76,.7-2.7L121.07,176,93.41,195.54,54.78,168.25A45.11,45.11,0,0,1,37.47,120.14ZM128,220l-27.66-19.54L128,180.9l27.66,19.54Zm73.22-51.73-38.63,27.29L134.93,176l82.9-58.56.7,2.7A45.11,45.11,0,0,1,201.22,168.25Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M234,116.09,214.13,40a15.94,15.94,0,0,0-30.42-1.48L167,84H89L72.29,38.49A15.94,15.94,0,0,0,41.87,40L22,116.09a61.19,61.19,0,0,0,23.57,65.23l73.27,51.77a15.93,15.93,0,0,0,18.36,0l73.27-51.77A61.19,61.19,0,0,0,234,116.09ZM58.61,70.86l10.76,29.28A12,12,0,0,0,80.64,108h94.72a12,12,0,0,0,11.27-7.86l10.76-29.28,9.14,35L128,161.31,49.47,105.83ZM44,131.37,107.2,176l-13.79,9.74-34-24A36.86,36.86,0,0,1,44,131.37Zm84,78.82-13.79-9.75L128,190.7l13.79,9.74Zm68.6-48.47-34,24L148.8,176,212,131.37A36.86,36.86,0,0,1,196.6,161.72Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M228.21,117.61,208.32,41.49a9.94,9.94,0,0,0-19-.93L171.17,90H84.83L66.66,40.56a9.94,9.94,0,0,0-19,.93L27.79,117.61A55.18,55.18,0,0,0,49,176.42l73.27,51.77a9.94,9.94,0,0,0,11.44,0L207,176.42A55.18,55.18,0,0,0,228.21,117.61ZM57.65,50.82,75,98.07A6,6,0,0,0,80.64,102h94.72A6,6,0,0,0,181,98.07l17.36-47.25,15,57.52L128,168.66,42.62,108.34ZM39.38,120.74,117.6,176,93.41,193.1,55.94,166.62A43.1,43.1,0,0,1,39.38,120.74ZM128,217.53l-24.19-17.09L128,183.35l24.19,17.09Zm72.06-50.91L162.59,193.1,138.4,176l78.22-55.26A43.1,43.1,0,0,1,200.06,166.62Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M230.15,117.1,210.25,41a11.94,11.94,0,0,0-22.79-1.11L169.78,88H86.22L68.54,39.87A11.94,11.94,0,0,0,45.75,41L25.85,117.1a57.19,57.19,0,0,0,22,61l73.27,51.76a11.91,11.91,0,0,0,13.74,0l73.27-51.76A57.19,57.19,0,0,0,230.15,117.1ZM58,57.5,73.13,98.76A8,8,0,0,0,80.64,104h94.72a8,8,0,0,0,7.51-5.24L198,57.5l13.07,50L128,166.21,44.9,107.5ZM40.68,124.11,114.13,176,93.41,190.65,57.09,165A41.06,41.06,0,0,1,40.68,124.11Zm87.32,91-20.73-14.65L128,185.8l20.73,14.64ZM198.91,165l-36.32,25.66L141.87,176l73.45-51.9A41.06,41.06,0,0,1,198.91,165Z"></path>
-}.into_view()
+}.into_any()
         }
-    });
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -49,8 +43,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/house.rs b/aep-schedule-website/src/frontend/components/icons/house.rs
index 05a35bcd8e651d6ba4938e586a60a90dbca9ddfd..10a2b428db4c6072ec4b9420b5647eb6a7b54ef4 100644
--- a/aep-schedule-website/src/frontend/components/icons/house.rs
+++ b/aep-schedule-website/src/frontend/components/icons/house.rs
@@ -1,47 +1,41 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn House(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: Signal<IconWeight>,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
+    let body = move || {
         match weight.get() {
             IconWeight::Fill => view! {
                 <path d="M224,120v96a8,8,0,0,1-8,8H160a8,8,0,0,1-8-8V164a4,4,0,0,0-4-4H108a4,4,0,0,0-4,4v52a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V120a16,16,0,0,1,4.69-11.31l80-80a16,16,0,0,1,22.62,0l80,80A16,16,0,0,1,224,120Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path
         d="M216,120v96H152V152H104v64H40V120a8,8,0,0,1,2.34-5.66l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,216,120Z"
         opacity="0.2"
     ></path>
     <path d="M219.31,108.68l-80-80a16,16,0,0,0-22.62,0l-80,80A15.87,15.87,0,0,0,32,120v96a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V160h32v56a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V120A15.87,15.87,0,0,0,219.31,108.68ZM208,208H160V152a8,8,0,0,0-8-8H104a8,8,0,0,0-8,8v56H48V120l80-80,80,80Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M216.49,111.51l-80-80a12,12,0,0,0-17,0l-80,80A12,12,0,0,0,36,120v96a4,4,0,0,0,4,4h64a4,4,0,0,0,4-4V156h40v60a4,4,0,0,0,4,4h64a4,4,0,0,0,4-4V120A12,12,0,0,0,216.49,111.51ZM212,212H156V152a4,4,0,0,0-4-4H104a4,4,0,0,0-4,4v60H44V120a4,4,0,0,1,1.17-2.83l80-80a4,4,0,0,1,5.66,0l80,80A4,4,0,0,1,212,120Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M222.14,105.85l-80-80a20,20,0,0,0-28.28,0l-80,80A19.86,19.86,0,0,0,28,120v96a12,12,0,0,0,12,12h64a12,12,0,0,0,12-12V164h24v52a12,12,0,0,0,12,12h64a12,12,0,0,0,12-12V120A19.86,19.86,0,0,0,222.14,105.85ZM204,204H164V152a12,12,0,0,0-12-12H104a12,12,0,0,0-12,12v52H52V121.65l76-76,76,76Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M217.9,110.1l-80-80a14,14,0,0,0-19.8,0l-80,80A13.92,13.92,0,0,0,34,120v96a6,6,0,0,0,6,6h64a6,6,0,0,0,6-6V158h36v58a6,6,0,0,0,6,6h64a6,6,0,0,0,6-6V120A13.92,13.92,0,0,0,217.9,110.1ZM210,210H158V152a6,6,0,0,0-6-6H104a6,6,0,0,0-6,6v58H46V120a2,2,0,0,1,.58-1.42l80-80a2,2,0,0,1,2.84,0l80,80A2,2,0,0,1,210,120Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M219.31,108.68l-80-80a16,16,0,0,0-22.62,0l-80,80A15.87,15.87,0,0,0,32,120v96a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V160h32v56a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V120A15.87,15.87,0,0,0,219.31,108.68ZM208,208H160V152a8,8,0,0,0-8-8H104a8,8,0,0,0-8,8v56H48V120l80-80,80,80Z"></path>
-}.into_view()
+}.into_any()
         }
-    });
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -49,8 +43,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/plus_circle.rs b/aep-schedule-website/src/frontend/components/icons/plus_circle.rs
index 5bd91ad0e9502b5bdcc51cf96c606024c2f5245e..e4b1f6b677bd408c38d4108441c842a813406d00 100644
--- a/aep-schedule-website/src/frontend/components/icons/plus_circle.rs
+++ b/aep-schedule-website/src/frontend/components/icons/plus_circle.rs
@@ -1,53 +1,44 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn PlusCircle(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(default = IconWeight::Regular)] weight: IconWeight,
+    size: &'static str,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body = move || {
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M128,24A104,104,0,1,0,232,128,104.13,104.13,0,0,0,128,24Zm40,112H136v32a8,8,0,0,1-16,0V136H88a8,8,0,0,1,0-16h32V88a8,8,0,0,1,16,0v32h32a8,8,0,0,1,0,16Z"></path>
-            }.into_view(),
-IconWeight::Duotone => view! {
-    <path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path>
-    <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm48-88a8,8,0,0,1-8,8H136v32a8,8,0,0,1-16,0V136H88a8,8,0,0,1,0-16h32V88a8,8,0,0,1,16,0v32h32A8,8,0,0,1,176,128Z"></path>
-}.into_view(),
-IconWeight::Thin => view! {
-    <path d="M128,28A100,100,0,1,0,228,128,100.11,100.11,0,0,0,128,28Zm0,192a92,92,0,1,1,92-92A92.1,92.1,0,0,1,128,220Zm44-92a4,4,0,0,1-4,4H132v36a4,4,0,0,1-8,0V132H88a4,4,0,0,1,0-8h36V88a4,4,0,0,1,8,0v36h36A4,4,0,0,1,172,128Z"></path>
-}.into_view(),
-IconWeight::Bold => view! {
-    <path d="M128,20A108,108,0,1,0,236,128,108.12,108.12,0,0,0,128,20Zm0,192a84,84,0,1,1,84-84A84.09,84.09,0,0,1,128,212Zm52-84a12,12,0,0,1-12,12H140v28a12,12,0,0,1-24,0V140H88a12,12,0,0,1,0-24h28V88a12,12,0,0,1,24,0v28h28A12,12,0,0,1,180,128Z"></path>
-}.into_view(),
-IconWeight::Light => view! {
-    <path d="M128,26A102,102,0,1,0,230,128,102.12,102.12,0,0,0,128,26Zm0,192a90,90,0,1,1,90-90A90.1,90.1,0,0,1,128,218Zm46-90a6,6,0,0,1-6,6H134v34a6,6,0,0,1-12,0V134H88a6,6,0,0,1,0-12h34V88a6,6,0,0,1,12,0v34h34A6,6,0,0,1,174,128Z"></path>
-}.into_view(),
-IconWeight::Regular => view! {
-    <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm48-88a8,8,0,0,1-8,8H136v32a8,8,0,0,1-16,0V136H88a8,8,0,0,1,0-16h32V88a8,8,0,0,1,16,0v32h32A8,8,0,0,1,176,128Z"></path>
-}.into_view()
+            }.into_any(),
+            IconWeight::Duotone => view! {
+                <path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path>
+                <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm48-88a8,8,0,0,1-8,8H136v32a8,8,0,0,1-16,0V136H88a8,8,0,0,1,0-16h32V88a8,8,0,0,1,16,0v32h32A8,8,0,0,1,176,128Z"></path>
+            }.into_any(),
+            IconWeight::Thin => view! {
+                <path d="M128,28A100,100,0,1,0,228,128,100.11,100.11,0,0,0,128,28Zm0,192a92,92,0,1,1,92-92A92.1,92.1,0,0,1,128,220Zm44-92a4,4,0,0,1-4,4H132v36a4,4,0,0,1-8,0V132H88a4,4,0,0,1,0-8h36V88a4,4,0,0,1,8,0v36h36A4,4,0,0,1,172,128Z"></path>
+            }.into_any(),
+            IconWeight::Bold => view! {
+                <path d="M128,20A108,108,0,1,0,236,128,108.12,108.12,0,0,0,128,20Zm0,192a84,84,0,1,1,84-84A84.09,84.09,0,0,1,128,212Zm52-84a12,12,0,0,1-12,12H140v28a12,12,0,0,1-24,0V140H88a12,12,0,0,1,0-24h28V88a12,12,0,0,1,24,0v28h28A12,12,0,0,1,180,128Z"></path>
+            }.into_any(),
+            IconWeight::Light => view! {
+                <path d="M128,26A102,102,0,1,0,230,128,102.12,102.12,0,0,0,128,26Zm0,192a90,90,0,1,1,90-90A90.1,90.1,0,0,1,128,218Zm46-90a6,6,0,0,1-6,6H134v34a6,6,0,0,1-12,0V134H88a6,6,0,0,1,0-12h34V88a6,6,0,0,1,12,0v34h34A6,6,0,0,1,174,128Z"></path>
+            }.into_any(),
+            IconWeight::Regular => view! {
+                <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm48-88a8,8,0,0,1-8,8H136v32a8,8,0,0,1-16,0V136H88a8,8,0,0,1,0-16h32V88a8,8,0,0,1,16,0v32h32A8,8,0,0,1,176,128Z"></path>
+            }.into_any()
         }
-    });
-
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
-    let height = size.clone();
+    };
 
     view! {
         <svg
             xmlns="http://www.w3.org/2000/svg"
-            width=move || size.get()
-            height=move || height.get()
-            fill=color
-            transform=transform
+            width=size
+            height=size
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/sun.rs b/aep-schedule-website/src/frontend/components/icons/sun.rs
index 55145bac25906348e10c2d5296563735a55fd534..cccb877a3a70ad4d3b86faeb9d5e1ac7bd215ffd 100644
--- a/aep-schedule-website/src/frontend/components/icons/sun.rs
+++ b/aep-schedule-website/src/frontend/components/icons/sun.rs
@@ -1,44 +1,38 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn Sun(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: Signal<IconWeight>,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
+    let body = move || {
         match weight.get() {
             IconWeight::Fill => view! {
                 <path d="M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm8,24a64,64,0,1,0,64,64A64.07,64.07,0,0,0,128,64ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path d="M184,128a56,56,0,1,1-56-56A56,56,0,0,1,184,128Z" opacity="0.2"></path>
     <path d="M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M124,40V16a4,4,0,0,1,8,0V40a4,4,0,0,1-8,0Zm64,88a60,60,0,1,1-60-60A60.07,60.07,0,0,1,188,128Zm-8,0a52,52,0,1,0-52,52A52.06,52.06,0,0,0,180,128ZM61.17,66.83a4,4,0,0,0,5.66-5.66l-16-16a4,4,0,0,0-5.66,5.66Zm0,122.34-16,16a4,4,0,0,0,5.66,5.66l16-16a4,4,0,0,0-5.66-5.66ZM192,68a4,4,0,0,0,2.83-1.17l16-16a4,4,0,1,0-5.66-5.66l-16,16A4,4,0,0,0,192,68Zm2.83,121.17a4,4,0,0,0-5.66,5.66l16,16a4,4,0,0,0,5.66-5.66ZM40,124H16a4,4,0,0,0,0,8H40a4,4,0,0,0,0-8Zm88,88a4,4,0,0,0-4,4v24a4,4,0,0,0,8,0V216A4,4,0,0,0,128,212Zm112-88H216a4,4,0,0,0,0,8h24a4,4,0,0,0,0-8Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M116,36V20a12,12,0,0,1,24,0V36a12,12,0,0,1-24,0Zm80,92a68,68,0,1,1-68-68A68.07,68.07,0,0,1,196,128Zm-24,0a44,44,0,1,0-44,44A44.05,44.05,0,0,0,172,128ZM51.51,68.49a12,12,0,1,0,17-17l-12-12a12,12,0,0,0-17,17Zm0,119-12,12a12,12,0,0,0,17,17l12-12a12,12,0,1,0-17-17ZM196,72a12,12,0,0,0,8.49-3.51l12-12a12,12,0,0,0-17-17l-12,12A12,12,0,0,0,196,72Zm8.49,115.51a12,12,0,0,0-17,17l12,12a12,12,0,0,0,17-17ZM48,128a12,12,0,0,0-12-12H20a12,12,0,0,0,0,24H36A12,12,0,0,0,48,128Zm80,80a12,12,0,0,0-12,12v16a12,12,0,0,0,24,0V220A12,12,0,0,0,128,208Zm108-92H220a12,12,0,0,0,0,24h16a12,12,0,0,0,0-24Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M122,40V16a6,6,0,0,1,12,0V40a6,6,0,0,1-12,0Zm68,88a62,62,0,1,1-62-62A62.07,62.07,0,0,1,190,128Zm-12,0a50,50,0,1,0-50,50A50.06,50.06,0,0,0,178,128ZM59.76,68.24a6,6,0,1,0,8.48-8.48l-16-16a6,6,0,0,0-8.48,8.48Zm0,119.52-16,16a6,6,0,1,0,8.48,8.48l16-16a6,6,0,1,0-8.48-8.48ZM192,70a6,6,0,0,0,4.24-1.76l16-16a6,6,0,0,0-8.48-8.48l-16,16A6,6,0,0,0,192,70Zm4.24,117.76a6,6,0,0,0-8.48,8.48l16,16a6,6,0,0,0,8.48-8.48ZM46,128a6,6,0,0,0-6-6H16a6,6,0,0,0,0,12H40A6,6,0,0,0,46,128Zm82,82a6,6,0,0,0-6,6v24a6,6,0,0,0,12,0V216A6,6,0,0,0,128,210Zm112-88H216a6,6,0,0,0,0,12h24a6,6,0,0,0,0-12Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"></path>
-}.into_view()
+}.into_any()
         }
-    });
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -46,8 +40,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/sun_horizon.rs b/aep-schedule-website/src/frontend/components/icons/sun_horizon.rs
index 5edb7d633063d67e133f05c99615c02b1dae7730..56dee9460eb61ef3e9e213c230a733b98db386dc 100644
--- a/aep-schedule-website/src/frontend/components/icons/sun_horizon.rs
+++ b/aep-schedule-website/src/frontend/components/icons/sun_horizon.rs
@@ -1,44 +1,38 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn SunHorizon(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into)] weight: Signal<IconWeight>,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
+    let body = move || {
         match weight.get() {
             IconWeight::Fill => view! {
                 <path d="M248,160a8,8,0,0,1-8,8H16a8,8,0,0,1,0-16H56.45a73.54,73.54,0,0,1-.45-8,72,72,0,0,1,144,0,73.54,73.54,0,0,1-.45,8H240A8,8,0,0,1,248,160Zm-40,32H48a8,8,0,0,0,0,16H208a8,8,0,0,0,0-16ZM80.84,59.58a8,8,0,0,0,14.32-7.16l-8-16a8,8,0,0,0-14.32,7.16ZM20.42,103.16l16,8a8,8,0,1,0,7.16-14.31l-16-8a8,8,0,1,0-7.16,14.31ZM216,112a8,8,0,0,0,3.57-.84l16-8a8,8,0,1,0-7.16-14.31l-16,8A8,8,0,0,0,216,112ZM164.42,63.16a8,8,0,0,0,10.74-3.58l8-16a8,8,0,0,0-14.32-7.16l-8,16A8,8,0,0,0,164.42,63.16Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path d="M192,144a64.33,64.33,0,0,1-2,16H66a64,64,0,1,1,126-16Z" opacity="0.2"></path>
     <path d="M240,152H199.55a73.54,73.54,0,0,0,.45-8,72,72,0,0,0-144,0,73.54,73.54,0,0,0,.45,8H16a8,8,0,0,0,0,16H240a8,8,0,0,0,0-16ZM72,144a56,56,0,1,1,111.41,8H72.59A56.13,56.13,0,0,1,72,144Zm144,56a8,8,0,0,1-8,8H48a8,8,0,0,1,0-16H208A8,8,0,0,1,216,200ZM72.84,43.58a8,8,0,0,1,14.32-7.16l8,16a8,8,0,0,1-14.32,7.16Zm-56,48.84a8,8,0,0,1,10.74-3.57l16,8a8,8,0,0,1-7.16,14.31l-16-8A8,8,0,0,1,16.84,92.42Zm192,15.16a8,8,0,0,1,3.58-10.73l16-8a8,8,0,1,1,7.16,14.31l-16,8a8,8,0,0,1-10.74-3.58Zm-48-55.16,8-16a8,8,0,0,1,14.32,7.16l-8,16a8,8,0,1,1-14.32-7.16Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M240,156H194.94A68,68,0,1,0,60,144a68.73,68.73,0,0,0,1.06,12H16a4,4,0,0,0,0,8H240a4,4,0,0,0,0-8ZM68,144a60,60,0,1,1,118.79,12H69.21A60.16,60.16,0,0,1,68,144Zm144,56a4,4,0,0,1-4,4H48a4,4,0,0,1,0-8H208A4,4,0,0,1,212,200ZM76.42,41.79a4,4,0,0,1,7.16-3.58l8,16a4,4,0,0,1-7.16,3.58Zm-56,52.42a4,4,0,0,1,5.37-1.79l16,8a4,4,0,0,1-3.58,7.16l-16-8A4,4,0,0,1,20.42,94.21Zm192,11.58a4,4,0,0,1,1.79-5.37l16-8a4,4,0,1,1,3.58,7.16l-16,8a4,4,0,0,1-5.37-1.79Zm-48-51.58,8-16a4,4,0,1,1,7.16,3.58l-8,16a4,4,0,0,1-7.16-3.58Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M240,148H203.89c.07-1.33.11-2.66.11-4a76,76,0,0,0-152,0c0,1.34,0,2.67.11,4H16a12,12,0,0,0,0,24H240a12,12,0,0,0,0-24ZM76,144a52,52,0,0,1,104,0c0,1.34-.07,2.67-.17,4H76.17C76.07,146.67,76,145.34,76,144Zm144,56a12,12,0,0,1-12,12H48a12,12,0,0,1,0-24H208A12,12,0,0,1,220,200ZM12.62,92.21a12,12,0,0,1,15.17-7.59l12,4a12,12,0,1,1-7.58,22.77l-12-4A12,12,0,0,1,12.62,92.21Zm56-48.41a12,12,0,1,1,22.76-7.59l4,12A12,12,0,1,1,72.62,55.8Zm140,60a12,12,0,0,1,7.59-15.18l12-4a12,12,0,0,1,7.58,22.77l-12,4a12,12,0,0,1-15.17-7.59Zm-48-55.59,4-12a12,12,0,1,1,22.76,7.59l-4,12a12,12,0,1,1-22.76-7.59Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M240,154H197.28a70.91,70.91,0,0,0,.72-10,70,70,0,0,0-140,0,70.91,70.91,0,0,0,.72,10H16a6,6,0,0,0,0,12H240a6,6,0,0,0,0-12ZM70,144a58,58,0,1,1,115.13,10H70.87A58.63,58.63,0,0,1,70,144Zm144,56a6,6,0,0,1-6,6H48a6,6,0,0,1,0-12H208A6,6,0,0,1,214,200ZM74.63,42.69a6,6,0,0,1,10.74-5.37l8,16a6,6,0,0,1-10.74,5.36Zm-56,50.63a6,6,0,0,1,8.05-2.69l16,8a6,6,0,0,1-5.36,10.74l-16-8A6,6,0,0,1,18.63,93.32Zm192,13.36a6,6,0,0,1,2.69-8.05l16-8a6,6,0,1,1,5.36,10.74l-16,8a6,6,0,0,1-8.05-2.69Zm-48-53.36,8-16a6,6,0,0,1,10.74,5.37l-8,16a6,6,0,1,1-10.74-5.36Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M240,152H199.55a73.54,73.54,0,0,0,.45-8,72,72,0,0,0-144,0,73.54,73.54,0,0,0,.45,8H16a8,8,0,0,0,0,16H240a8,8,0,0,0,0-16ZM72,144a56,56,0,1,1,111.41,8H72.59A56.13,56.13,0,0,1,72,144Zm144,56a8,8,0,0,1-8,8H48a8,8,0,0,1,0-16H208A8,8,0,0,1,216,200ZM72.84,43.58a8,8,0,0,1,14.32-7.16l8,16a8,8,0,0,1-14.32,7.16Zm-56,48.84a8,8,0,0,1,10.74-3.57l16,8a8,8,0,0,1-7.16,14.31l-16-8A8,8,0,0,1,16.84,92.42Zm192,15.16a8,8,0,0,1,3.58-10.73l16-8a8,8,0,1,1,7.16,14.31l-16,8a8,8,0,0,1-10.74-3.58Zm-48-55.16,8-16a8,8,0,0,1,14.32,7.16l-8,16a8,8,0,1,1-14.32-7.16Z"></path>
-}.into_view()
+}.into_any()
         }
-    });
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -46,8 +40,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/warning_circle.rs b/aep-schedule-website/src/frontend/components/icons/warning_circle.rs
index 2e7db7bd3a159ba36e6705b868732f6addbeafcc..75dc967dead88592b40d99de4507c7645cb083fb 100644
--- a/aep-schedule-website/src/frontend/components/icons/warning_circle.rs
+++ b/aep-schedule-website/src/frontend/components/icons/warning_circle.rs
@@ -1,44 +1,37 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn WarningCircle(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into, default = IconWeight::Regular)] weight: IconWeight,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body =
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm-8,56a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm8,104a12,12,0,1,1,12-12A12,12,0,0,1,128,184Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path>
     <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M128,28A100,100,0,1,0,228,128,100.11,100.11,0,0,0,128,28Zm0,192a92,92,0,1,1,92-92A92.1,92.1,0,0,1,128,220Zm-4-84V80a4,4,0,0,1,8,0v56a4,4,0,0,1-8,0Zm12,36a8,8,0,1,1-8-8A8,8,0,0,1,136,172Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M128,20A108,108,0,1,0,236,128,108.12,108.12,0,0,0,128,20Zm0,192a84,84,0,1,1,84-84A84.09,84.09,0,0,1,128,212Zm-12-80V80a12,12,0,0,1,24,0v52a12,12,0,0,1-24,0Zm28,40a16,16,0,1,1-16-16A16,16,0,0,1,144,172Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M128,26A102,102,0,1,0,230,128,102.12,102.12,0,0,0,128,26Zm0,192a90,90,0,1,1,90-90A90.1,90.1,0,0,1,128,218Zm-6-82V80a6,6,0,0,1,12,0v56a6,6,0,0,1-12,0Zm16,36a10,10,0,1,1-10-10A10,10,0,0,1,138,172Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path>
-}.into_view()
-        }
-    });
+}.into_any()
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -46,8 +39,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/icons/x.rs b/aep-schedule-website/src/frontend/components/icons/x.rs
index 0d3d03e78583d7c53ff49aeda3732ab7bcb2176b..cb32c138caf7a9e46b44faa65822a93c26b529c5 100644
--- a/aep-schedule-website/src/frontend/components/icons/x.rs
+++ b/aep-schedule-website/src/frontend/components/icons/x.rs
@@ -1,47 +1,40 @@
-//! GENERATED FILE
-
 use super::IconWeight;
-use leptos::*;
+use leptos::{prelude::*, text_prop::TextProp};
 
 #[component]
 pub fn X(
-    #[prop(into, default = MaybeSignal::Static(IconWeight::Regular))] weight: MaybeSignal<
-        IconWeight,
-    >,
-    #[prop(into, default = TextProp::from("1em"))] size: TextProp,
+    #[prop(into, default = IconWeight::Regular)] weight: IconWeight,
+    #[prop(into)] size: TextProp,
     #[prop(into, default = TextProp::from("currentColor"))] color: TextProp,
-    #[prop(into, default = MaybeSignal::Static(false))] mirrored: MaybeSignal<bool>,
     #[prop(into, optional)] id: MaybeProp<TextProp>,
     #[prop(into, optional)] class: MaybeProp<TextProp>,
 ) -> impl IntoView {
-    let body = Signal::derive(move || {
-        match weight.get() {
+    let body =
+        match weight {
             IconWeight::Fill => view! {
                 <path d="M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM181.66,170.34a8,8,0,0,1-11.32,11.32L128,139.31,85.66,181.66a8,8,0,0,1-11.32-11.32L116.69,128,74.34,85.66A8,8,0,0,1,85.66,74.34L128,116.69l42.34-42.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
-            }.into_view(),
+            }.into_any(),
 IconWeight::Duotone => view! {
     <path
         d="M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z"
         opacity="0.2"
     ></path>
     <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Thin => view! {
     <path d="M202.83,197.17a4,4,0,0,1-5.66,5.66L128,133.66,58.83,202.83a4,4,0,0,1-5.66-5.66L122.34,128,53.17,58.83a4,4,0,0,1,5.66-5.66L128,122.34l69.17-69.17a4,4,0,1,1,5.66,5.66L133.66,128Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Bold => view! {
     <path d="M208.49,191.51a12,12,0,0,1-17,17L128,145,64.49,208.49a12,12,0,0,1-17-17L111,128,47.51,64.49a12,12,0,0,1,17-17L128,111l63.51-63.52a12,12,0,0,1,17,17L145,128Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Light => view! {
     <path d="M204.24,195.76a6,6,0,1,1-8.48,8.48L128,136.49,60.24,204.24a6,6,0,0,1-8.48-8.48L119.51,128,51.76,60.24a6,6,0,0,1,8.48-8.48L128,119.51l67.76-67.75a6,6,0,0,1,8.48,8.48L136.49,128Z"></path>
-}.into_view(),
+}.into_any(),
 IconWeight::Regular => view! {
     <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
-}.into_view()
-        }
-    });
+}.into_any()
+    };
 
-    let transform = move || if mirrored.get() { "scale(-1, 1)" } else { "" };
     let height = size.clone();
 
     view! {
@@ -49,8 +42,7 @@ IconWeight::Regular => view! {
             xmlns="http://www.w3.org/2000/svg"
             width=move || size.get()
             height=move || height.get()
-            fill=color
-            transform=transform
+            fill=move || color.get()
             viewBox="0 0 256 256"
             id=move || id.get().map(|id| id.get())
             class=move || class.get().map(|cls| cls.get())
diff --git a/aep-schedule-website/src/frontend/components/notifications.rs b/aep-schedule-website/src/frontend/components/notifications.rs
index a701a7247b6c4cd4ff84a4a47b9502b3c9beec5c..61dde2871d804fe4baf3ee0ed01c7855529d8c90 100644
--- a/aep-schedule-website/src/frontend/components/notifications.rs
+++ b/aep-schedule-website/src/frontend/components/notifications.rs
@@ -1,5 +1,5 @@
 use aep_schedule_generator::data::group_sigle::SigleGroup;
-use leptos::*;
+use leptos::{html, prelude::*, task::spawn_local};
 
 use crate::{
     backend::{
@@ -14,11 +14,11 @@ pub fn Notifications(
     modal: ReadSignal<Option<SigleGroup>>,
     set_modal: WriteSignal<Option<SigleGroup>>,
 ) -> impl IntoView {
-    let input_element: NodeRef<html::Input> = create_node_ref();
+    let input_element: NodeRef<html::Input> = NodeRef::new();
 
     let on_submit = move |ev: leptos::ev::SubmitEvent| {
         ev.prevent_default();
-        let email = input_element().unwrap().value();
+        let email = input_element.get().unwrap().value();
         if email.is_empty() {
             return;
         }
@@ -44,18 +44,20 @@ pub fn Notifications(
     view! {
         <div class=class>
             <div class="notif-body">
-                <div class="close-button" on:pointerdown=move |_| {
-                    set_modal.set(None);
-                }>
+                <div
+                    class="close-button"
+                    on:pointerdown=move |_| {
+                        set_modal.set(None);
+                    }
+                >
                     <X size="2em"></X>
                 </div>
                 <form on:submit=on_submit>
-                    <p>"Entrez votre courriel pour recevoir des notifications quand la section ouvrira"</p>
-                    <input type="text"
-                        pattern=r"[^@\s]+@[^@\s]+\.[^@\s]+"
-                        node_ref=input_element
-                    />
-                    <input type="submit" value="Envoyer"/>
+                    <p>
+                        "Entrez votre courriel pour recevoir des notifications quand la section ouvrira"
+                    </p>
+                    <input type="text" pattern=r"[^@\s]+@[^@\s]+\.[^@\s]+" node_ref=input_element />
+                    <input type="submit" value="Envoyer" />
                 </form>
             </div>
         </div>
diff --git a/aep-schedule-website/src/frontend/components/options/courses_selector.rs b/aep-schedule-website/src/frontend/components/options/courses_selector.rs
index 162309c034e29265833b8980159728a981dc1311..40e3852095e7f054bac9c2e93747d31d71f5348c 100644
--- a/aep-schedule-website/src/frontend/components/options/courses_selector.rs
+++ b/aep-schedule-website/src/frontend/components/options/courses_selector.rs
@@ -1,68 +1,73 @@
 use crate::backend::routes::get_courses;
 use crate::frontend::components::common::tab::Tab;
-use crate::frontend::components::icons::bell_ringing::BellRinging;
+// use crate::frontend::components::icons::bell_ringing::BellRinging;
 use crate::frontend::components::icons::calendar_x::CalendarX;
 use crate::frontend::components::icons::x::X;
 use crate::frontend::components::icons::IconWeight;
 use crate::frontend::components::options::personal::PersonalTimeSelector;
 use crate::frontend::components::options::search::SearchCourse;
-use crate::frontend::pages::generator::SetModal;
+// use crate::frontend::pages::generator::SetModal;
 use crate::frontend::state::reactive_course::ReactiveCourse;
 use crate::frontend::state::reactive_course::ReactiveCourseType;
 use crate::frontend::state::OptionState;
 use aep_schedule_generator::data::group::Group;
 use aep_schedule_generator::data::group_sigle::GroupType;
-use aep_schedule_generator::data::group_sigle::SigleGroup;
+// use aep_schedule_generator::data::group_sigle::SigleGroup;
 use aep_schedule_generator::data::groups::Groups;
 use compact_str::CompactString;
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 fn GroupsChips<F>(
     open: RwSignal<bool>,
     group: Group,
-    course_sigle: CompactString,
-    group_type: GroupType,
+    _course_sigle: CompactString,
+    _group_type: GroupType,
     submit: F,
 ) -> impl IntoView
 where
     F: Fn() + Copy + 'static,
 {
-    let set_modal = SetModal::from_context();
+    // let set_modal = SetModal::from_context();
 
     view! {
-        <div on:pointerdown=move |_| {
+        <div
+            on:pointerdown=move |_| {
                 open.update(|b| *b = !*b);
                 submit();
             }
             class="gap-2 cursor-pointer items-center py-1.5 px-3 rounded-lg flex"
-            class=("bg-green-500", move || {open.get()})
-            class=("bg-red-500", move || {!open.get()})
+            class=("bg-green-500", move || { open.get() })
+            class=("bg-red-500", move || { !open.get() })
         >
             <span class="text-lg text-bold text-sans">{group.number.to_string()}</span>
             <div class="flex flex-col justify-between w-full">
-                {group.periods.iter().map(|p| {
-                    view!{
-                        <div class="flex group-text w-full justify-between">
-                            <span>{p.day.to_string()}</span>
-                            <span class="period-group">{p.hours.to_string()}</span>
-                            <span>{p.week_nb.to_string()}</span>
-                        </div>
-                    }
-                }).collect_view()}
+                {group
+                    .periods
+                    .iter()
+                    .map(|p| {
+                        view! {
+                            <div class="flex group-text w-full justify-between">
+                                <span>{p.day.to_string()}</span>
+                                <span class="period-group">{p.hours.to_string()}</span>
+                                <span>{p.week_nb.to_string()}</span>
+                            </div>
+                        }
+                    })
+                    .collect_view()}
             </div>
-            //{match group.open {
-            //    false => Some(view !{
-            //        <div on:pointerdown=move |ev| {
-            //            ev.stop_propagation();
-            //            let sigle_group = SigleGroup::new(course_sigle.clone(), group_type, group.number);
-            //            set_modal.set(Some(sigle_group));
-            //            }>
-            //            <BellRinging size="1em"/>
-            //        </div>
-            //    }),
-            //    true => None,
-            //}}
+        // {match group.open {
+        // false => Some(view !{
+        // <div on:pointerdown=move |ev| {
+        // ev.stop_propagation();
+        // let sigle_group = SigleGroup::new(course_sigle.clone(), group_type, group.number);
+        // set_modal.set(Some(sigle_group));
+        // }>
+        // <BellRinging size="1em"/>
+        // </div>
+        // }),
+        // true => None,
+        // }}
         </div>
     }
 }
@@ -79,127 +84,178 @@ where
     F: Fn() + Copy + 'static,
 {
     view! {
-        {groups.into_iter().enumerate().map(|(i, group)| {
+        {groups
+            .into_iter()
+            .enumerate()
+            .map(|(i, group)| {
                 let open = open[i];
                 view! {
-                    <GroupsChips open group course_sigle=course_sigle.clone() group_type submit/>
+                    <GroupsChips
+                        open
+                        group
+                        _course_sigle=course_sigle.clone()
+                        _group_type=group_type
+                        submit
+                    />
                 }
-            }).collect_view()
-        }
+            })
+            .collect_view()}
     }
 }
 
 #[component]
 fn CourseTab<F>(course: ReactiveCourse, active_tab: ReadSignal<String>, submit: F) -> impl IntoView
 where
-    F: Fn() + Copy + 'static,
+    F: Fn() + Copy + 'static + Send,
 {
     let course_sigle = course.sigle.clone();
     view! {
         <Tab active_tab tab_id=course.sigle.to_string()>
             <p>{course.name}</p>
             <div class="flex justify-around">
-                {
-                    match course.course_type {
-                        ReactiveCourseType::TheoOnly { theo_open, theo_groups } => {
-                            let groups = theo_groups;
-                            view!{
-                                <div class="flex gap-2 flex-col pb-2 max-h-[26rem] overflow-y-auto">
-                                    <h3>"Théorie"</h3>
-                                    <GroupsSettings groups open=theo_open course_sigle group_type=GroupType::TheoGroup submit/>
-                                </div>
-                            }.into_view()
-                        },
-                        ReactiveCourseType::LabOnly { lab_open, lab_groups } => {
-                            let groups = lab_groups;
-                            view!{
-                                <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
-                                    <h3>"Laboratoire"</h3>
-                                    <GroupsSettings groups open=lab_open course_sigle=course_sigle.clone() group_type=GroupType::LabGroup submit/>
-                                </div>
-                            }.into_view()
-                        },
-                        ReactiveCourseType::Both { theo_open, theo_groups, lab_open, lab_groups } => {
-                            let theo_groups = theo_groups;
-                            let lab_groups = lab_groups;
-                            view!{
-                                <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
-                                    <h3>"Théorie"</h3>
-                                    <GroupsSettings groups=theo_groups open=theo_open course_sigle=course_sigle.clone() group_type=GroupType::TheoGroup submit/>
-                                </div>
-                                <div class="vertical-bar"></div>
-                                <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
-                                    <h3>"Laboratoire"</h3>
-                                    <GroupsSettings groups=lab_groups open=lab_open course_sigle=course_sigle.clone() group_type=GroupType::LabGroup submit/>
-                                </div>
-                            }.into_view()
-                        },
-                        ReactiveCourseType::Linked { both_open, theo_groups, lab_groups } => {
-                            let groups = theo_groups.merge(lab_groups);
-                            view!{
-                                <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
-                                    <h3>"Théorie et laboratoire lié"</h3>
-                                    <GroupsSettings groups open=both_open course_sigle=course_sigle group_type=GroupType::LabGroup submit/>
-                                </div>
-                            }.into_view()
-                        },
+                {match course.course_type {
+                    ReactiveCourseType::TheoOnly { theo_open, theo_groups } => {
+                        let groups = theo_groups;
+                        view! {
+                            <div class="flex gap-2 flex-col pb-2 max-h-[26rem] overflow-y-auto">
+                                <h3>"Théorie"</h3>
+                                <GroupsSettings
+                                    groups
+                                    open=theo_open
+                                    course_sigle
+                                    group_type=GroupType::TheoGroup
+                                    submit
+                                />
+                            </div>
+                        }
+                            .into_any()
                     }
-                }
+                    ReactiveCourseType::LabOnly { lab_open, lab_groups } => {
+                        let groups = lab_groups;
+                        view! {
+                            <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
+                                <h3>"Laboratoire"</h3>
+                                <GroupsSettings
+                                    groups
+                                    open=lab_open
+                                    course_sigle=course_sigle.clone()
+                                    group_type=GroupType::LabGroup
+                                    submit
+                                />
+                            </div>
+                        }
+                            .into_any()
+                    }
+                    ReactiveCourseType::Both { theo_open, theo_groups, lab_open, lab_groups } => {
+                        let theo_groups = theo_groups;
+                        let lab_groups = lab_groups;
+                        view! {
+                            <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
+                                <h3>"Théorie"</h3>
+                                <GroupsSettings
+                                    groups=theo_groups
+                                    open=theo_open
+                                    course_sigle=course_sigle.clone()
+                                    group_type=GroupType::TheoGroup
+                                    submit
+                                />
+                            </div>
+                            <div class="vertical-bar"></div>
+                            <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
+                                <h3>"Laboratoire"</h3>
+                                <GroupsSettings
+                                    groups=lab_groups
+                                    open=lab_open
+                                    course_sigle=course_sigle.clone()
+                                    group_type=GroupType::LabGroup
+                                    submit
+                                />
+                            </div>
+                        }
+                            .into_any()
+                    }
+                    ReactiveCourseType::Linked { both_open, theo_groups, lab_groups } => {
+                        let groups = theo_groups.merge(lab_groups);
+                        view! {
+                            <div class="flex gap-2 flex-col pb-2 overflow-y-auto">
+                                <h3>"Théorie et laboratoire lié"</h3>
+                                <GroupsSettings
+                                    groups
+                                    open=both_open
+                                    course_sigle=course_sigle
+                                    group_type=GroupType::LabGroup
+                                    submit
+                                />
+                            </div>
+                        }
+                            .into_any()
+                    }
+                }}
             </div>
         </Tab>
     }
 }
 
 #[component]
-pub fn CoursesSelector<F>(state: OptionState, submit: F) -> impl IntoView
+pub fn CoursesSelector<F>(submit: F) -> impl IntoView
 where
-    F: Fn() + Copy + 'static,
+    F: Fn() + Copy + 'static + Send,
 {
-    let (active_tab, set_active_tab) = create_signal("".to_string());
+    let (active_tab, set_active_tab) = signal("".to_string());
 
-    let action_courses = state.action_courses;
+    let state = OptionState::from_context();
+    let courses = state.courses;
 
     view! {
-        <Await
-            future=get_courses
-            let:courses
-        >
-            <SearchCourse courses=courses.clone() action_courses set_active_tab/>
+        <Await future=get_courses() let:all_courses>
+            <SearchCourse set_active_tab all_courses=all_courses.clone() />
         </Await>
         <div class="flex w-full flex-wrap gap-1">
-            <button class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" class=("opacity-75", move || active_tab.get() != "") id="personal" on:pointerdown={
-                move |_| set_active_tab.set("".to_string())
-            }>
-                <CalendarX weight=IconWeight::Regular size="16px"/>
+            <button
+                class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition"
+                class=("opacity-75", move || active_tab.get() != "")
+                id="personal"
+                on:pointerdown=move |_| set_active_tab.set("".to_string())
+            >
+                <CalendarX weight=IconWeight::Regular size="16px" />
                 {"Horaire personnel"}
             </button>
             <For
-                each=move || {action_courses.value().get().unwrap_or_default()}
+                each=move || { courses.get() }
                 key=|c| c.sigle.clone()
                 children=move |course| {
                     let sigle = course.sigle.to_string();
                     let add_hidden = move || sigle != active_tab.get();
                     let sigle = course.sigle.to_string();
-                    view!{
-                        <button class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" class=("opacity-75", add_hidden) id=&sigle on:pointerdown={
-                            let sigle = sigle.clone();
-                            move |_| set_active_tab.set(sigle.clone())
-                        }>
-                        {&sigle}
-                        <button class="close" on:pointerdown={
-                            let sigle = sigle.clone();
-                            move |_| {
-                                action_courses.value().update(|courses| {
-                                    if let Some(courses) = courses {
-                                        courses.retain(|c| c.sigle.as_str() != sigle);
-                                    }}
-                                );
-                                state.stored_courses.update_value(|courses| {
-                                    courses.retain(|c| c.sigle.as_str() != sigle);
-                                });
-                                submit();
+                    let sigle2 = course.sigle.to_string();
+                    let sigle3 = course.sigle.to_string();
+                    view! {
+                        <button
+                            class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition"
+                            class=("opacity-75", add_hidden)
+                            id=sigle3
+                            on:pointerdown={
+                                let sigle = sigle.clone();
+                                move |_| set_active_tab.set(sigle.clone())
                             }
-                        }><X weight=IconWeight::Regular size="16px"/></button>
+                        >
+                            {sigle2}
+                            <button
+                                class="close"
+                                on:click={
+                                    let sigle = sigle.clone();
+                                    move |_| {
+                                        state
+                                            .courses
+                                            .update(|courses| {
+                                                courses.retain(|c| c.sigle.as_str() != sigle);
+                                            });
+                                        submit();
+                                    }
+                                }
+                            >
+                                <X weight=IconWeight::Regular size="16px" />
+                            </button>
                         </button>
                     }
                 }
@@ -208,12 +264,8 @@ where
         <Tab active_tab tab_id="".to_string()>
             <PersonalTimeSelector week=state.week submit></PersonalTimeSelector>
         </Tab>
-        <For
-            each=move || {action_courses.value().get().unwrap_or_default()}
-            key=|c| c.sigle.clone()
-            let:course
-        >
-            <CourseTab course active_tab submit/>
+        <For each=move || { courses.get() } key=|c| c.sigle.clone() let:course>
+            <CourseTab course active_tab submit />
         </For>
     }
 }
diff --git a/aep-schedule-website/src/frontend/components/options/form.rs b/aep-schedule-website/src/frontend/components/options/form.rs
index 07d06d665f84e42c238675fa808b997ad2c0a30f..f8e91c1ee5830b4bad1fb816259b69783146ae25 100644
--- a/aep-schedule-website/src/frontend/components/options/form.rs
+++ b/aep-schedule-website/src/frontend/components/options/form.rs
@@ -3,43 +3,37 @@ use crate::frontend::{
         common::number_input::NumberInput,
         options::{courses_selector::CoursesSelector, optimizations::SelectOptimizations},
     },
-    pages::generator::FirstGenerationDone,
     state::OptionState,
 };
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn OptionsForms() -> impl IntoView {
     let state = OptionState::from_context();
 
-    let first_generation_done: FirstGenerationDone = use_context().unwrap();
     let submit = move || {
-        state.validate();
-        if !first_generation_done.0.get() || state.step.get() < 5 {
-            return;
-        }
-        state.generate();
+        state.submit();
     };
 
-    create_local_resource(state.action_courses.pending(), move |_| {
-        submit();
-        async move {}
-    });
-
     let submit_mobile = move |_| {
-        state.validate();
-        if state.step.get() < 5 {
-            state.hide.set(true);
-            return;
-        }
-        state.generate();
+        state.submit_mobile();
     };
 
     view! {
-        <CoursesSelector state=state submit/>
+        <CoursesSelector submit />
         <span class="grow"></span>
-        <NumberInput value=state.max_nb_conflicts max=127 label="Nombre de période de cours en conflits maximum: " submit/>
-        <SelectOptimizations state=state submit/>
-        <button on:pointerdown=submit_mobile class="lg:hidden select-none rounded-lg bg-amber-500 py-2 text-xl px-4 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">"Générer les horaires"</button>
+        <NumberInput
+            value=state.max_nb_conflicts
+            max=127
+            label="Nombre de période de cours en conflits maximum: "
+            submit
+        />
+        <SelectOptimizations submit />
+        <button
+            on:pointerdown=submit_mobile
+            class="lg:hidden select-none rounded-lg bg-amber-500 py-2 text-xl px-4 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
+        >
+            "Générer les horaires"
+        </button>
     }
 }
diff --git a/aep-schedule-website/src/frontend/components/options/optimizations.rs b/aep-schedule-website/src/frontend/components/options/optimizations.rs
index 074d7668ec0d922ca363f982eed6a127977c633e..bbf62e87ce980ecdae89db8e19a09c221c071173 100644
--- a/aep-schedule-website/src/frontend/components/options/optimizations.rs
+++ b/aep-schedule-website/src/frontend/components/options/optimizations.rs
@@ -4,7 +4,7 @@ use crate::frontend::{
     },
     state::OptionState,
 };
-use leptos::*;
+use leptos::prelude::*;
 use std::cmp;
 
 fn weight(input: u8) -> IconWeight {
@@ -18,43 +18,64 @@ fn weight(input: u8) -> IconWeight {
 }
 
 #[component]
-pub fn SelectOptimizations<F>(state: OptionState, submit: F) -> impl IntoView
+pub fn SelectOptimizations<F>(submit: F) -> impl IntoView
 where
     F: Fn() + Copy + 'static,
 {
-    let weight_house = create_memo(move |_| weight(state.day_off.get()));
-    let weight_early = create_memo(move |_| weight((-cmp::min(0, state.morning.get())) as u8));
-    let weight_morning = create_memo(move |_| weight(cmp::max(0, state.morning.get()) as u8));
-    let weight_finish = create_memo(move |_| weight(state.finish_early.get()));
+    let state = OptionState::from_context();
+    let weight_house = Memo::new(move |_| weight(state.day_off.get()));
+    let weight_early = Memo::new(move |_| weight((-cmp::min(0, state.morning.get())) as u8));
+    let weight_morning = Memo::new(move |_| weight(cmp::max(0, state.morning.get()) as u8));
+    let weight_finish = Memo::new(move |_| weight(state.finish_early.get()));
 
     view! {
         <div class="three-col">
             <div class="flex flex-col items-center">
-                <House weight=weight_house size="10vh"/>
+                <House weight=weight_house size="10vh" />
                 <p class="font-sans font-medium tracking-tight">"Plus de congés"</p>
-                <input type="range" min="0" max="4" class="lg:w-24 w-16 accent-amber-500" prop:value=state.day_off  on:input=move |ev| {
-                    state.day_off.set(event_target_value(&ev).parse::<u8>().unwrap());
-                    submit();
-                }/>
+                <input
+                    type="range"
+                    min="0"
+                    max="4"
+                    class="lg:w-24 w-16 accent-amber-500"
+                    prop:value=state.day_off
+                    on:input=move |ev| {
+                        state.day_off.set(event_target_value(&ev).parse::<u8>().unwrap());
+                        submit();
+                    }
+                />
             </div>
             <div class="flex flex-col items-center">
                 <div class="flex">
-                    <SunHorizon weight=weight_early size="10vh"/>
-                    <Sun weight=weight_morning size="10vh"/>
+                    <SunHorizon weight=weight_early size="10vh" />
+                    <Sun weight=weight_morning size="10vh" />
                 </div>
                 <p class="font-sans font-medium tracking-tight">"Cours plus tôt ou plus tard"</p>
-                <input type="range" min="-4" max="4" class="lg:w-48 w-32 accent-amber-500" prop:value=state.morning  on:input=move |ev| {
-                    state.morning.set(event_target_value(&ev).parse::<i8>().unwrap());
-                    submit();
-                }/>
+                <input
+                    type="range"
+                    min="-4"
+                    max="4"
+                    class="lg:w-48 w-32 accent-amber-500"
+                    prop:value=state.morning
+                    on:input=move |ev| {
+                        state.morning.set(event_target_value(&ev).parse::<i8>().unwrap());
+                        submit();
+                    }
+                />
             </div>
             <div class="flex flex-col items-center">
-                <CalendarCheck weight=weight_finish size="10vh"/>
+                <CalendarCheck weight=weight_finish size="10vh" />
                 <p class="font-sans font-medium tracking-tight">"Finir plus tôt"</p>
-                <input type="range" min="0" max="4" class="lg:w-24 w-16 accent-amber-500" prop:value=state.finish_early  on:input=move |ev| {
-                    state.finish_early.set(event_target_value(&ev).parse::<u8>().unwrap());
-                    submit();
-                }
+                <input
+                    type="range"
+                    min="0"
+                    max="4"
+                    class="lg:w-24 w-16 accent-amber-500"
+                    prop:value=state.finish_early
+                    on:input=move |ev| {
+                        state.finish_early.set(event_target_value(&ev).parse::<u8>().unwrap());
+                        submit();
+                    }
                 />
             </div>
         </div>
diff --git a/aep-schedule-website/src/frontend/components/options/personal.rs b/aep-schedule-website/src/frontend/components/options/personal.rs
index bcfebc147a438d6c0d9d7049f089458aa0735ef1..3ebbf6989d14a62ea7d111045f6a938c6c3afb54 100644
--- a/aep-schedule-website/src/frontend/components/options/personal.rs
+++ b/aep-schedule-website/src/frontend/components/options/personal.rs
@@ -1,5 +1,5 @@
 use crate::frontend::components::common::schedule::Schedule;
-use leptos::*;
+use leptos::{ev, prelude::*};
 use web_sys::wasm_bindgen::JsCast;
 use web_sys::Element;
 
@@ -8,9 +8,9 @@ pub fn PersonalTimeSelector<F>(week: [RwSignal<u64>; 5], submit: F) -> impl Into
 where
     F: Fn() + Copy + 'static,
 {
-    let (initial, set_initial) = create_signal(None);
-    let (destination, set_destination) = create_signal((0, 0));
-    let (is_positive, set_positive) = create_signal(true);
+    let (initial, set_initial) = signal(None);
+    let (destination, set_destination) = signal((0, 0));
+    let (is_positive, set_positive) = signal(true);
     let selection = move || {
         let Some((initial_x, initial_y)) = initial.get() else {
             return String::from("display: none;");
@@ -60,39 +60,47 @@ where
     };
     view! {
         <Schedule col_height="0.4em">
-            {(0..5).into_iter().map(|i| {
-                (0..26).into_iter().map(|j| {
-                    let j = 2 * j;
-                    let style = format!(
-                        "grid-column:{};grid-row:{} / span {};",
-                        i + 3,
-                        j + 5,
-                        2
-                    );
-                    let class = move || {
-                        let day = week[i].get();
-                        let hour = day & (1 << j);
-                        if hour != 0 {
-                            "touch-none selected-hour"
-                        } else {
-                            "touch-none"
-                        }
-                    };
-                    view! {
-                        <div style=style class=class
-                            on:pointerdown=move |e| {
-                                set_initial.set(Some((i, j)));
-                                set_positive.set((week[i].get() & (1 << j)) == 0);
-                                let _ = e.target().unwrap().dyn_ref::<Element>().unwrap().release_pointer_capture(e.pointer_id());
+            {(0..5)
+                .into_iter()
+                .map(|i| {
+                    (0..26)
+                        .into_iter()
+                        .map(|j| {
+                            let j = 2 * j;
+                            let style = format!(
+                                "grid-column:{};grid-row:{} / span {};",
+                                i + 3,
+                                j + 5,
+                                2,
+                            );
+                            let class = move || {
+                                let day = week[i].get();
+                                let hour = day & (1 << j);
+                                if hour != 0 { "touch-none selected-hour" } else { "touch-none" }
+                            };
+                            view! {
+                                <div
+                                    style=style
+                                    class=class
+                                    on:pointerdown=move |e| {
+                                        set_initial.set(Some((i, j)));
+                                        set_positive.set((week[i].get() & (1 << j)) == 0);
+                                        let _ = e
+                                            .target()
+                                            .unwrap()
+                                            .dyn_ref::<Element>()
+                                            .unwrap()
+                                            .release_pointer_capture(e.pointer_id());
+                                    }
+                                    on:pointerover=move |_| {
+                                        set_destination.set((i, j));
+                                    }
+                                ></div>
                             }
-                            on:pointerover=move |_| {
-                                set_destination.set((i, j));
-                            }>
-                        </div>
-                    }
-                }).collect_view()
-            }).collect_view()}
-            <div style=selection class=selection_class></div>
+                        })
+                        .collect_view()
+                })
+                .collect_view()} <div style=selection class=selection_class></div>
         </Schedule>
     }
 }
diff --git a/aep-schedule-website/src/frontend/components/options/search.rs b/aep-schedule-website/src/frontend/components/options/search.rs
index 12a223fc02b06214c21407a7fe82052901fc5239..3b66f1adb1b655b8d567f9cd741171c46bec2b67 100644
--- a/aep-schedule-website/src/frontend/components/options/search.rs
+++ b/aep-schedule-website/src/frontend/components/options/search.rs
@@ -1,17 +1,16 @@
 use crate::frontend::{
     components::common::autocomplete::{AutoComplete, AutoCompleteOption},
-    state::reactive_course::ReactiveCourse,
+    state::action_add_course::ActionAddCourse,
 };
 use aep_schedule_generator::data::course::CourseName;
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn SearchCourse(
-    courses: Result<Vec<CourseName>, ServerFnError>,
+    all_courses: Result<Vec<CourseName>, ServerFnError>,
     set_active_tab: WriteSignal<String>,
-    action_courses: Action<String, Vec<ReactiveCourse>>,
 ) -> impl IntoView {
-    let Ok(courses) = courses else {
+    let Ok(courses) = all_courses else {
         return None;
     };
     let courses = courses
@@ -19,12 +18,18 @@ pub fn SearchCourse(
         .map(|c| AutoCompleteOption::new(c.sigle.clone(), c.sigle + " - " + &c.name))
         .collect();
 
+    let action_courses = ActionAddCourse::from_context().0;
     let on_submit = move |sigle: String| {
         set_active_tab(sigle.clone());
         action_courses.dispatch(sigle);
     };
 
     Some(view! {
-        <AutoComplete suggestion_list=courses placeholder="Cours" submit=on_submit id="course-submitter"/>
+        <AutoComplete
+            suggestion_list=courses
+            placeholder="Cours"
+            submit=on_submit
+            id="course-submitter"
+        />
     })
 }
diff --git a/aep-schedule-website/src/frontend/components/options/todo.rs b/aep-schedule-website/src/frontend/components/options/todo.rs
index 755e4633f640c3409206c2200dfd7e9617ab6b4a..8104fd7bcfc2d87c86a41f1c2902a7ef93103a0c 100644
--- a/aep-schedule-website/src/frontend/components/options/todo.rs
+++ b/aep-schedule-website/src/frontend/components/options/todo.rs
@@ -1,8 +1,8 @@
 use std::cmp::Ordering;
 
 use crate::frontend::components::icons::warning_circle::WarningCircle;
-use crate::frontend::{pages::generator::FirstGenerationDone, state::OptionState};
-use leptos::*;
+use crate::frontend::state::OptionState;
+use leptos::prelude::*;
 
 #[component]
 pub fn Step(
@@ -23,38 +23,52 @@ pub fn Step(
     view! {
         <div class="flex">
             <div class="flex flex-col items-center mr-4">
-              <div>
-                <div class=bg_color>
-                  <svg class="w-4 text-gray-600" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
-                    <line fill="none" stroke-miterlimit="10" x1="12" y1="2" x2="12" y2="22"></line>
-                    <polyline fill="none" stroke-miterlimit="10" points="19,15 12,22 5,15"></polyline>
-                  </svg>
+                <div>
+                    <div class=bg_color>
+                        <svg
+                            class="w-4 text-gray-600"
+                            stroke="currentColor"
+                            stroke-width="2"
+                            stroke-linecap="round"
+                            stroke-linejoin="round"
+                            viewBox="0 0 24 24"
+                        >
+                            <line
+                                fill="none"
+                                stroke-miterlimit="10"
+                                x1="12"
+                                y1="2"
+                                x2="12"
+                                y2="22"
+                            ></line>
+                            <polyline
+                                fill="none"
+                                stroke-miterlimit="10"
+                                points="19,15 12,22 5,15"
+                            ></polyline>
+                        </svg>
+                    </div>
                 </div>
-              </div>
-            <div class="w-px h-full bg-gray-300"></div>
-        </div>
-        <div class="pt-1 pb-8">
-          <p class="mb-2 text-lg font-bold">{n}" - "{title}</p>
-          <p class="text-gray-700">
-            {description}
-          </p>
-          {children.map(|c| c())}
+                <div class="w-px h-full bg-gray-300"></div>
+            </div>
+            <div class="pt-1 pb-8">
+                <p class="mb-2 text-lg font-bold">{n}" - "{title}</p>
+                <p class="text-gray-700">{description}</p>
+                {children.map(|c| c())}
+            </div>
         </div>
-      </div>
     }
 }
 
 #[component]
 pub fn Todo() -> impl IntoView {
     let state = OptionState::from_context();
-    let first_generation_done: FirstGenerationDone = use_context().unwrap();
-
     let submit = move |_| {
-        first_generation_done.0.set(true);
-        state.generate();
+        state.first_generation_done.set_value(true);
+        state.submit();
     };
 
-    let step = state.step;
+    let step: RwSignal<u8> = state.step;
 
     let disab = move || {
         let step = step.get();
@@ -68,35 +82,79 @@ pub fn Todo() -> impl IntoView {
         <div class="px-4 py-4 mx-auto">
             <div class="grid gap-6 row-gap-10">
                 <div class="lg:py-6 lg:pr-16">
-                    <Step n=1 step title="Ajoutez vos cours" description="Utilisez la barre de recherche à gauche pour trouver et sélectionner vos cours. Une fois les cours sélectionnés, ils apparaîtront comme un onglet."/>
-                    <Step n=2 step title="Ouvrez des sections" description="Assurez d'avoir au moins une section d'ouverte pour la théorie et la pratique. En sélectionnant l'onglet du cours et en appuyant sur les sections.">
-                        <div class="warning-box" class=("hidden", move || state.section_error.get().is_empty())>
-                            <WarningCircle size="2em"/>
-                            <span>
-                                {state.section_error}
-                            </span>
+                    <Step
+                        n=1
+                        step
+                        title="Ajoutez vos cours"
+                        description="Utilisez la barre de recherche à gauche pour trouver et sélectionner vos cours. Une fois les cours sélectionnés, ils apparaîtront comme un onglet."
+                    />
+                    <Step
+                        n=2
+                        step
+                        title="Ouvrez des sections"
+                        description="Assurez d'avoir au moins une section d'ouverte pour la théorie et la pratique. En sélectionnant l'onglet du cours et en appuyant sur les sections."
+                    >
+                        <div
+                            class="warning-box"
+                            class=("hidden", move || state.section_error.get().is_empty())
+                        >
+                            <WarningCircle size="2em" />
+                            <span>{state.section_error}</span>
                         </div>
                     </Step>
-                    <Step n=3 step title="Forcer des heures libres" description="Sélectionnez une plage de temps à avoir absolument libre en pressant et relâchant sur votre horaire personnel.">
-                        <div class="warning-box" class=("hidden", move || state.personal_error.get().is_empty())>
-                            <WarningCircle size="2em"/>
-                            <span>
-                                {state.personal_error}
-                            </span>
+                    <Step
+                        n=3
+                        step
+                        title="Forcer des heures libres"
+                        description="Sélectionnez une plage de temps à avoir absolument libre en pressant et relâchant sur votre horaire personnel."
+                    >
+                        <div
+                            class="warning-box"
+                            class=("hidden", move || state.personal_error.get().is_empty())
+                        >
+                            <WarningCircle size="2em" />
+                            <span>{state.personal_error}</span>
                         </div>
                     </Step>
-                    <Step n=4 step title="Ajustez les paramètres" description="Bougez les curseurs en bas pour ajuster vos préférences. Vous pouvez choisir d'avoir plus de congés, de commencer en moyenne les cours plus tôt ou plus tard, ou de finir en moyenne plus tôt."/>
+                    <Step
+                        n=4
+                        step
+                        title="Ajustez les paramètres"
+                        description="Bougez les curseurs en bas pour ajuster vos préférences. Vous pouvez choisir d'avoir plus de congés, de commencer en moyenne les cours plus tôt ou plus tard, ou de finir en moyenne plus tôt."
+                    />
                     <div class="flex items-center">
                         <div class="flex flex-col items-center mr-4">
                             <div>
-                                <div class="flex transition-colors items-center justify-center w-10 h-10 border rounded-full" class=("bg-gray-100", move || step.get() < 5) class=("bg-green-400", move || step.get() == 5)  class=("bg-amber-400", move || step.get() == 6) >
-                                    <svg class="w-6 text-gray-600" stroke="currentColor" viewBox="0 0 24 24">
-                                        <polyline fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="6,12 10,16 18,8"></polyline>
+                                <div
+                                    class="flex transition-colors items-center justify-center w-10 h-10 border rounded-full"
+                                    class=("bg-gray-100", move || step.get() < 5)
+                                    class=("bg-green-400", move || step.get() == 5)
+                                    class=("bg-amber-400", move || step.get() == 6)
+                                >
+                                    <svg
+                                        class="w-6 text-gray-600"
+                                        stroke="currentColor"
+                                        viewBox="0 0 24 24"
+                                    >
+                                        <polyline
+                                            fill="none"
+                                            stroke-width="2"
+                                            stroke-linecap="round"
+                                            stroke-linejoin="round"
+                                            stroke-miterlimit="10"
+                                            points="6,12 10,16 18,8"
+                                        ></polyline>
                                     </svg>
                                 </div>
                             </div>
                         </div>
-                        <button on:pointerdown=submit class="select-none rounded-lg bg-amber-500 py-1 text-lg font-sans font-semibold px-2 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none" prop:disabled=disab>"Générer les horaires"</button>
+                        <button
+                            on:pointerdown=submit
+                            class="select-none rounded-lg bg-amber-500 py-1 text-lg font-sans font-semibold px-2 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
+                            prop:disabled=disab
+                        >
+                            "Générer les horaires"
+                        </button>
                     </div>
                 </div>
             </div>
diff --git a/aep-schedule-website/src/frontend/components/schedule.rs b/aep-schedule-website/src/frontend/components/schedule.rs
index 1aefa4762ead52bf717193422f0da8a233cc0ce0..3a5d56946c912492767711e64dbb0a15442f74dd 100644
--- a/aep-schedule-website/src/frontend/components/schedule.rs
+++ b/aep-schedule-website/src/frontend/components/schedule.rs
@@ -1,4 +1,4 @@
-use std::rc::Rc;
+use std::sync::Arc;
 
 use crate::frontend::components::common::schedule::{Schedule, ScheduleEvent};
 use crate::frontend::components::icons::download::Download;
@@ -11,10 +11,10 @@ use aep_schedule_generator::{
     },
     data::time::{period::Period, week_number::WeekNumber},
 };
-use leptos::{html::A, *};
+use leptos::prelude::*;
 
 #[component]
-pub fn Course<'a>(i: usize, course: &'a TakenCourse) -> impl IntoView {
+pub fn Course(i: usize, course: TakenCourse) -> impl IntoView {
     let theo_group = course.theo_group().map(|g| format!("T: {}", g.number));
     let lab_group = course.lab_group().map(|g| format!("L: {}", g.number));
     let color_box = match i % 8 {
@@ -42,10 +42,10 @@ pub fn Course<'a>(i: usize, course: &'a TakenCourse) -> impl IntoView {
 }
 
 #[component]
-fn PeriodEvent<'a>(
+fn PeriodEvent(
     i: usize,
-    period: &'a Period,
-    course: &'a TakenCourse,
+    period: Period,
+    course: Arc<TakenCourse>,
     period_type: &'static str,
 ) -> impl IntoView {
     let mut location = period.hours.to_string() + " - " + period.room.as_str();
@@ -73,7 +73,7 @@ fn PeriodEvent<'a>(
     }
 
     view! {
-        <ScheduleEvent period=&period class=class>
+        <ScheduleEvent period=period class=class>
             <span>{location}</span>
             <span>{sigle}</span>
         </ScheduleEvent>
@@ -81,22 +81,28 @@ fn PeriodEvent<'a>(
 }
 
 #[component]
-fn CoursePeriods<'a>(i: usize, course: &'a TakenCourse) -> impl IntoView {
-    match &course.taken_course_type {
+fn CoursePeriods(i: usize, course: TakenCourse) -> impl IntoView {
+    let taken_course_type = course.taken_course_type.clone();
+    let course = Arc::new(course);
+    match taken_course_type {
         TakenCourseType::TheoOnly { theo_group } => theo_group
             .periods
-            .iter()
+            .into_iter()
             .map(|p| {
-                view! {<PeriodEvent i period=&p course=course period_type="T"/>}
+                let course = Arc::clone(&course);
+                view! { <PeriodEvent i period=p course period_type="T" /> }
             })
-            .collect_view(),
+            .collect_view()
+            .into_any(),
         TakenCourseType::LabOnly { lab_group } => lab_group
             .periods
-            .iter()
+            .into_iter()
             .map(|p| {
-                view! {<PeriodEvent i period=&p course=course period_type="L"/>}
+                let course = Arc::clone(&course);
+                view! { <PeriodEvent i period=p course period_type="L" /> }
             })
-            .collect_view(),
+            .collect_view()
+            .into_any(),
         TakenCourseType::Both {
             theo_group,
             lab_group,
@@ -105,44 +111,64 @@ fn CoursePeriods<'a>(i: usize, course: &'a TakenCourse) -> impl IntoView {
             theo_group,
             lab_group,
         } => view! {
-            {
-                theo_group.periods.iter().map(|p| {
-                    view! {<PeriodEvent i period=&p course=course period_type="T"/>}
-                }).collect_view()
-            }
-            {
-                lab_group.periods.iter().map(|p| {
-                    view! {<PeriodEvent i period=&p course=course period_type="L"/>}
-                }).collect_view()
-            }
+            {theo_group
+                .periods
+                .into_iter()
+                .map(|p| {
+                    let course = Arc::clone(&course);
+                    view! { <PeriodEvent i period=p course period_type="T" /> }
+                })
+                .collect_view()}
+            {lab_group
+                .periods
+                .into_iter()
+                .map(|p| {
+                    let course = Arc::clone(&course);
+                    view! { <PeriodEvent i period=p course period_type="L" /> }
+                })
+                .collect_view()}
         }
-        .into_view(),
+        .into_any(),
     }
 }
 
 #[component]
-pub fn ScheduleComponent(schedule: Schedule, calendar: Rc<Calendar>) -> impl IntoView {
+pub fn ScheduleComponent(schedule: Schedule, calendar: Arc<Calendar>) -> impl IntoView {
+    let courses = schedule.taken_courses.clone();
+    let courses2 = schedule.taken_courses.clone();
     let schedule2 = schedule.clone();
-    let (download, set_download) = create_signal("".to_string());
-    let link: NodeRef<A> = create_node_ref();
+    let (download, set_download) = signal("".to_string());
+    let link = NodeRef::new();
 
     view! {
         <div class="flex flex-col w-full items-center card p-2">
             <a class="hidden" download="cours.ics" href=move || download.get() node_ref=link></a>
             <table class="cours">
-                {schedule.taken_courses.iter().enumerate().map(|(i, c)| view!{<Course i course={c} />}).collect_view()}
+                {courses
+                    .into_iter()
+                    .enumerate()
+                    .map(|(i, c)| view! { <Course i course=c /> })
+                    .collect_view()}
             </table>
-            <Schedule last_day=schedule.last_day>
-                {schedule.taken_courses.iter().enumerate().map(|(i, c)| view!{<CoursePeriods i course=c />}).collect_view()}
+            <Schedule last_day=schedule
+                .last_day>
+                {courses2
+                    .into_iter()
+                    .enumerate()
+                    .map(|(i, c)| view! { <CoursePeriods i course=c /> })
+                    .collect_view()}
             </Schedule>
-            <button class="button-download flex" on:pointerdown=move |_| {
-               let ics = calendar.generate_ics(&schedule2);
-               let url = url_escape::encode_fragment(&ics);
-               set_download("data:text/plain;charset=utf-8,".to_string() + &url);
-               link().unwrap().click();
-            }>
-               <Download weight=IconWeight::Regular size="3vh"/>
-               <span>"Télécharger le calendrier de cet horaire"</span>
+            <button
+                class="button-download flex"
+                on:pointerdown=move |_| {
+                    let ics = calendar.generate_ics(&schedule2);
+                    let url = url_escape::encode_fragment(&ics);
+                    set_download("data:text/plain;charset=utf-8,".to_string() + &url);
+                    link.get().unwrap().click();
+                }
+            >
+                <Download weight=IconWeight::Regular size="3vh" />
+                <span>"Télécharger le calendrier de cet horaire"</span>
             </button>
         </div>
     }
diff --git a/aep-schedule-website/src/frontend/components/schedules.rs b/aep-schedule-website/src/frontend/components/schedules.rs
index 91086363bd03e1c36391679781a252895fda4cc4..4b661e4f9c2ba40e571a375dd72e0bed14578f41 100644
--- a/aep-schedule-website/src/frontend/components/schedules.rs
+++ b/aep-schedule-website/src/frontend/components/schedules.rs
@@ -1,10 +1,10 @@
-use std::rc::Rc;
+use std::sync::Arc;
 
 use crate::frontend::components::icons::warning_circle::WarningCircle;
 use crate::frontend::components::options::todo::Todo;
 use crate::frontend::state::OptionState;
 use crate::{backend::routes::get_calendar, frontend::components::schedule::ScheduleComponent};
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn SchedulesComponent() -> impl IntoView {
@@ -12,42 +12,45 @@ pub fn SchedulesComponent() -> impl IntoView {
 
     view! {
         <Await
-            future=get_calendar
+            future=get_calendar()
             children=move |calendar| {
+                let calendar = Arc::new(calendar.clone().unwrap());
                 let bad_generation = state.schedule.get().is_empty();
                 let generated = state.step.get() == 6;
-                match generated && !bad_generation {
-                    true => {
-                        let calendar = Rc::new(calendar.clone().unwrap());
-                        view !{
-                            <For
-                                each=move || state.schedule.get()
-                                key= |course| course.id
-                                children= move |schedule| {
-                                    let calendar = Rc::clone(&calendar);
-                                    view !{
-                                        <ScheduleComponent schedule calendar/>
-                                    }
-                                }
-                            />
-                        }.into_view()
-                    },
-                    _ => view ! {
-                        <Todo/>
-                        {
-                            match generated && bad_generation {
-                                true => Some(view !{
+                view! {
+                    {move || {
+                        let bad_generation = state.schedule.get().is_empty();
+                        let generated = state.step.get() == 6;
+                        if !(generated && !bad_generation) {
+                            Some(view! { <Todo /> })
+                        } else {
+                            None
+                        }
+                    }}
+                    {move || {
+                        if generated && bad_generation {
+                            Some(
+                                view! {
                                     <div class="warning-box">
-                                        <WarningCircle size="4em"/>
+                                        <WarningCircle size="4em" />
                                         <span>
                                             "Aucun horaire n'a pu être généré, augmentez le nombre de conflits ou ouvrez des sections. Probablement que deux groupes sont toujours en conflits."
                                         </span>
                                     </div>
-                                }),
-                                false => None,
-                            }
+                                },
+                            )
+                        } else {
+                            None
+                        }
+                    }}
+                    <For
+                        each=move || state.schedule.get()
+                        key=|course| course.id
+                        children=move |schedule| {
+                            let calendar = Arc::clone(&calendar);
+                            view! { <ScheduleComponent schedule calendar /> }
                         }
-                    }.into_view()
+                    />
                 }
             }
         />
diff --git a/aep-schedule-website/src/frontend/pages/apropos.rs b/aep-schedule-website/src/frontend/pages/apropos.rs
index 04e5edcaf37867c99cef36a8ded1b71f53a748a1..36406ba6f4b9637c2347882ec02f3fb392629a52 100644
--- a/aep-schedule-website/src/frontend/pages/apropos.rs
+++ b/aep-schedule-website/src/frontend/pages/apropos.rs
@@ -1,30 +1,49 @@
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
 pub fn HomePage() -> impl IntoView {
     view! {
         <section class="p-1 w-full h-full">
             <div class="container flex flex-col justify-center p-4 mx-auto md:p-8">
-                <p class="p-2 text-sm font-medium tracking-wider text-center uppercase">"Comment ça marche?"</p>
-                <h2 class="mb-12 text-4xl font-bold leading-none text-center sm:text-5xl">"Foires aux questions"</h2>
+                <p class="p-2 text-sm font-medium tracking-wider text-center uppercase">
+                    "Comment ça marche?"
+                </p>
+                <h2 class="mb-12 text-4xl font-bold leading-none text-center sm:text-5xl">
+                    "Foires aux questions"
+                </h2>
                 <div class="grid gap-10 md:gap-8 sm:p-3 md:grid-cols-2 lg:px-12">
                     <div>
-                        <h3 class="font-semibold">"Pourquoi avoir refait l'ancien générateur?"</h3>
+                        <h3 class="font-semibold">
+                            "Pourquoi avoir refait l'ancien générateur?"
+                        </h3>
                         <p class="mt-1 dark:text-gray-600">
-                            "L'ancien générateur d'horaire était en mode maintenance depuis au moins 15 ans et changer l'architecture aurait été très difficile, en effet la vénérable base de code contenait littéralement 5 langages de programmation différents!"<br/> "- Marc-Antoine Manningham"
+                            "L'ancien générateur d'horaire était en mode maintenance depuis au moins 15 ans et changer l'architecture aurait été très difficile, en effet la vénérable base de code contenait littéralement 5 langages de programmation différents!"
+                            <br /> "- Marc-Antoine Manningham"
                         </p>
                     </div>
                     <div>
-                        <h3 class="font-semibold">"Qui sont les auteurs de la refonte du générateur d'horaire?"</h3>
-                        <p class="mt-1 dark:text-gray-600">"Marc-Antoine Manningham - Création du frontend et du backend entièrement en Rust. Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier et Gabriel Billard - Inspiration de leur TP3 de LOG2420 pour l'interface de la refonte du générateur"</p>
+                        <h3 class="font-semibold">
+                            "Qui sont les auteurs de la refonte du générateur d'horaire?"
+                        </h3>
+                        <p class="mt-1 dark:text-gray-600">
+                            "Marc-Antoine Manningham - Création du frontend et du backend entièrement en Rust. Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier et Gabriel Billard - Inspiration de leur TP3 de LOG2420 pour l'interface de la refonte du générateur"
+                        </p>
                     </div>
                     <div>
-                        <h3 class="font-semibold">"Comment le générateur génère aussi vite?"</h3>
-                        <p class="mt-1 dark:text-gray-600">"D'abord, les horaires sont généré directement dans le navigateur de l'utilisateur en WebAssembly plutôt que sur le serveur. Aussi, plutôt que de générer tout les horaires, juste le top des horaires sont générés. Plusieurs techniques pour couper l'espace de combinaisons sont utilisées pour éliminer les branches qui ne respectent pas les contraintes ou qui sont sous-optimales. (branch and bound)"</p>
+                        <h3 class="font-semibold">
+                            "Comment le générateur génère aussi vite?"
+                        </h3>
+                        <p class="mt-1 dark:text-gray-600">
+                            "D'abord, les horaires sont généré directement dans le navigateur de l'utilisateur en WebAssembly plutôt que sur le serveur. Aussi, plutôt que de générer tout les horaires, juste le top des horaires sont générés. Plusieurs techniques pour couper l'espace de combinaisons sont utilisées pour éliminer les branches qui ne respectent pas les contraintes ou qui sont sous-optimales. (branch and bound)"
+                        </p>
                     </div>
                     <div>
-                        <h3 class="font-semibold">"Si j'ai des suggestions où aller les mettre?"</h3>
-                        <p class="mt-1 dark:text-gray-600">"Le bouton signaler un bug peut aussi être utilisé pour soumettre une fonctionnalité sur le GitLab. Sinon, les contributions sont aussi les bienvenues si vous êtes prêt à faire un peu de Rust!"</p>
+                        <h3 class="font-semibold">
+                            "Si j'ai des suggestions où aller les mettre?"
+                        </h3>
+                        <p class="mt-1 dark:text-gray-600">
+                            "Le bouton signaler un bug peut aussi être utilisé pour soumettre une fonctionnalité sur le GitLab. Sinon, les contributions sont aussi les bienvenues si vous êtes prêt à faire un peu de Rust!"
+                        </p>
                     </div>
                 </div>
             </div>
diff --git a/aep-schedule-website/src/frontend/pages/classroom.rs b/aep-schedule-website/src/frontend/pages/classroom.rs
index a3576be54d2d2ad56bccb0f8601ab8039dfb4d60..1e247cd63bcff251c996834e293081e2b467fd4d 100644
--- a/aep-schedule-website/src/frontend/pages/classroom.rs
+++ b/aep-schedule-website/src/frontend/pages/classroom.rs
@@ -7,10 +7,10 @@ use crate::{
     },
 };
 use aep_schedule_generator::data::time::{period::PeriodCourse, week_number::WeekNumber};
-use leptos::*;
+use leptos::prelude::*;
 
 #[component]
-fn PeriodEvent<'a>(i: usize, period_course: &'a PeriodCourse) -> impl IntoView {
+fn PeriodEvent(i: usize, period_course: PeriodCourse) -> impl IntoView {
     let time = period_course.period.hours.to_string();
     let sigle = period_course.sigle.to_string();
 
@@ -26,8 +26,10 @@ fn PeriodEvent<'a>(i: usize, period_course: &'a PeriodCourse) -> impl IntoView {
         _ => (),
     }
 
+    let period = period_course.period.clone();
+
     view! {
-        <ScheduleEvent period=&period_course.period class=class>
+        <ScheduleEvent period=period class=class>
             <span>{sigle}</span>
             <span>{time}</span>
         </ScheduleEvent>
@@ -36,10 +38,10 @@ fn PeriodEvent<'a>(i: usize, period_course: &'a PeriodCourse) -> impl IntoView {
 
 #[component]
 pub fn ClassRoomComponent() -> impl IntoView {
-    let (periods, set_periods) = create_signal(vec![]);
+    let (periods, set_periods) = signal(vec![]);
 
     let change_classroom =
-        create_action(|(room, set): &(String, WriteSignal<Vec<PeriodCourse>>)| {
+        Action::new(|(room, set): &(String, WriteSignal<Vec<PeriodCourse>>)| {
             let set = *set;
             let room = room.clone();
             async move {
@@ -49,29 +51,49 @@ pub fn ClassRoomComponent() -> impl IntoView {
             }
         });
 
-    let on_submit = move |sigle: String| change_classroom.dispatch((sigle, set_periods));
+    let on_submit = move |sigle: String| {change_classroom.dispatch((sigle, set_periods));};
     view! {
         <section class="flex flex-col w-full justify-between items-center p-4">
             <div class="warning-box">
-                <WarningCircle size="5em"/>
+                <WarningCircle size="5em" />
                 <span>
-                    <span>"Cet horaire est construit à partir de l'horaire général des cours de Polytechnique Montréal. D'autres activités peuvent occuper un local. Pour connaître l'horaire complet d'un local ou le réserver: "</span>
-                    <a href="https://www.polymtl.ca/renseignements-generaux/reserver-une-salle-ou-organiser-un-evenement">"Réserver une salle"</a>
+                    <span>
+                        "Cet horaire est construit à partir de l'horaire général des cours de Polytechnique Montréal. D'autres activités peuvent occuper un local. Pour connaître l'horaire complet d'un local ou le réserver: "
+                    </span>
+                    <a href="https://www.polymtl.ca/renseignements-generaux/reserver-une-salle-ou-organiser-un-evenement">
+                        "Réserver une salle"
+                    </a>
                 </span>
             </div>
-            <Await
-                future=|| get_classrooms()
-                let:classrooms
-            >
-                {classrooms.as_ref().map(|classrooms| {
-                    let classrooms = classrooms.iter().map(|c| AutoCompleteOption::new(c.to_string(), c.to_string())).collect();
-                    view!{
-                        <AutoComplete suggestion_list=classrooms placeholder="Local" class="w-96 shadow-2xl border-b-4 border-amber-500 focus:outline-none focus:ring-0" submit=on_submit id="input-classroom"/>
-                    }
-                }).ok()}
+            <Await future=get_classrooms() let:classrooms>
+                {classrooms
+                    .as_ref()
+                    .map(|classrooms| {
+                        let classrooms = classrooms
+                            .into_iter()
+                            .map(|c| AutoCompleteOption::new(c.to_string(), c.to_string()))
+                            .collect();
+                        view! {
+                            <AutoComplete
+                                suggestion_list=classrooms
+                                placeholder="Local"
+                                class="w-96 shadow-2xl border-b-4 border-amber-500 focus:outline-none focus:ring-0"
+                                submit=on_submit
+                                id="input-classroom"
+                            />
+                        }
+                    })
+                    .ok()}
             </Await>
             <Schedule last_day=5 col_height="0.6em">
-                {move || periods.get().iter().enumerate().map(|(i, p)| view!{<PeriodEvent i period_course=p/>}).collect_view()}
+                {move || {
+                    periods
+                        .get()
+                        .into_iter()
+                        .enumerate()
+                        .map(|(i, p)| view! { <PeriodEvent i period_course=p /> })
+                        .collect_view()
+                }}
             </Schedule>
         </section>
     }
diff --git a/aep-schedule-website/src/frontend/pages/generator.rs b/aep-schedule-website/src/frontend/pages/generator.rs
index d7fdf57eaef118fbb2b8322d3bb16f3f4ff1effc..40094dfe1e8c367fde55e969a451a9a69a976eac 100644
--- a/aep-schedule-website/src/frontend/pages/generator.rs
+++ b/aep-schedule-website/src/frontend/pages/generator.rs
@@ -1,9 +1,10 @@
 use crate::frontend::components::icons::{caret_double_right::CaretDoubleRight, IconWeight};
 use crate::frontend::components::notifications::Notifications;
 use crate::frontend::components::{options::form::OptionsForms, schedules::SchedulesComponent};
+use crate::frontend::state::action_add_course::ActionAddCourse;
 use crate::frontend::state::OptionState;
 use aep_schedule_generator::data::group_sigle::SigleGroup;
-use leptos::*;
+use leptos::prelude::*;
 
 #[derive(Clone, Copy)]
 pub struct SetModal(WriteSignal<Option<SigleGroup>>);
@@ -14,42 +15,36 @@ impl SetModal {
     }
 }
 
-#[derive(Clone, Copy)]
-pub struct FirstGenerationDone(pub RwSignal<bool>);
-
 #[component]
 pub fn GeneratorPage() -> impl IntoView {
-    let first_generation_done = create_rw_signal(false);
-    let (modal, set_modal) = create_signal(None);
+    let (modal, set_modal) = signal(None);
     let state = OptionState::default();
-
+    let hide = state.hide;
     provide_context(state);
     provide_context(SetModal(set_modal));
-    provide_context(FirstGenerationDone(first_generation_done));
+    provide_context(ActionAddCourse::new(state));
 
     view! {
-        <aside class="left-panel" class=("hide-left-panel", state.hide)>
-            <OptionsForms/>
+        <aside class="left-panel" class=("hide-left-panel", hide)>
+            <OptionsForms />
         </aside>
-        <section class="right-panel" on:scroll=move |ev| {
-            use web_sys::wasm_bindgen::JsCast;
-
-            let target = ev
-                .target()
-                .unwrap()
-                .dyn_into::<web_sys::Element>()
-                .unwrap();
-            let scroll_top = target.scroll_top() as f64;
-            let client_height = target.client_height() as f64;
-            let scroll_height = target.scroll_height() as f64;
-            if (scroll_top + client_height >= scroll_height - 500.0) && state.step.get() == 6 {
-                state.regenerate();
+        <div class="right-panel"
+            on:scroll:target=move |ev| {
+                use web_sys::wasm_bindgen::JsCast;
+                let target = ev.target().dyn_into::<web_sys::Element>().unwrap();
+                let scroll_top = target.scroll_top() as f64;
+                let client_height = target.client_height() as f64;
+                let scroll_height = target.scroll_height() as f64;
+                if (scroll_top + client_height >= scroll_height - 500.0) && state.step.get() == 6 {
+                    state.regenerate();
+                }
             }
-
-        }>
-            <SchedulesComponent/>
-        </section>
-        <Notifications modal set_modal/>
-        <button on:pointerdown=move |_| {state.hide.set(false)} id="go-back"><CaretDoubleRight weight=IconWeight::Regular size="3vh"/></button>
+        >
+            <SchedulesComponent />
+        </div>
+        <Notifications modal set_modal />
+        <button on:pointerdown=move |_| { hide.set(false) } id="go-back">
+            <CaretDoubleRight weight=IconWeight::Regular size="3vh" />
+        </button>
     }
 }
diff --git a/aep-schedule-website/src/frontend/state/action_add_course.rs b/aep-schedule-website/src/frontend/state/action_add_course.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8bd72411cd42d61fdaa68fdde46f099cdfdb64c5
--- /dev/null
+++ b/aep-schedule-website/src/frontend/state/action_add_course.rs
@@ -0,0 +1,31 @@
+use leptos::prelude::*;
+
+use crate::backend::routes::get_course;
+
+use super::OptionState;
+
+#[derive(Clone)]
+pub struct ActionAddCourse(pub Action<String, ()>);
+
+impl ActionAddCourse {
+    pub fn from_context() -> Self {
+        use_context().unwrap()
+    }
+
+    pub fn new(state: OptionState) -> Self {
+        let action_courses = Action::new(move |sigle: &String| {
+            let sigle = sigle.clone();
+            async move {
+                if let Ok(c) = get_course(sigle.clone()).await {
+                    state.courses.update(|courses| {
+                        if !courses.iter().any(|c| c.sigle == sigle) {
+                            courses.push(c.into());
+                        }
+                    });
+                    state.submit();
+                }
+            }
+        });
+        Self(action_courses)
+    }
+}
diff --git a/aep-schedule-website/src/frontend/state/mod.rs b/aep-schedule-website/src/frontend/state/mod.rs
index 6904f0a2539c2e0a8171dc7124a1f73a6dd8346e..3e73469ea30ef41e8795ea0d48922ce5d1877e7c 100644
--- a/aep-schedule-website/src/frontend/state/mod.rs
+++ b/aep-schedule-website/src/frontend/state/mod.rs
@@ -4,17 +4,16 @@ use aep_schedule_generator::{
     algorithm::{generation::SchedulesOptions, schedule::Schedule, scores::EvaluationOption},
     data::time::week::Week,
 };
-use leptos::*;
+use leptos::prelude::*;
 use reactive_course::ReactiveCourse;
 
-use crate::backend::routes::get_course;
-
+pub mod action_add_course;
 pub mod reactive_course;
 
 #[derive(Copy, Clone)]
 pub struct OptionState {
-    pub stored_courses: StoredValue<Vec<ReactiveCourse>>,
-    pub action_courses: Action<String, Vec<ReactiveCourse>>,
+    pub first_generation_done: StoredValue<bool>,
+    pub courses: RwSignal<Vec<ReactiveCourse>>,
     pub week: [RwSignal<u64>; 5],
     pub max_nb_conflicts: RwSignal<u8>,
     pub day_off: RwSignal<u8>,
@@ -33,10 +32,28 @@ impl OptionState {
         use_context().unwrap()
     }
 
-    pub fn validate(self) {
-        let mut options: SchedulesOptions = (&self).into();
+    pub fn submit(&self) {
+        self.validate();
+        if !self.first_generation_done.get_value() || self.step.get_untracked() < 5 {
+            return;
+        }
+        self.generate();
+    }
+
+    pub fn submit_mobile(&self) {
+        self.validate();
+        if self.step.get() < 5 {
+            self.hide.set(true);
+            return;
+        }
+        self.generate();
+    }
+
+    fn validate(&self) {
+        let mut options: SchedulesOptions = self.into();
         if options.courses_to_take.is_empty() {
             self.step.set(1);
+            self.schedule.set(vec![]);
             return;
         }
         let mut impossible_courses = options.get_impossible_course().into_iter();
@@ -49,6 +66,7 @@ impl OptionState {
             error.push_str(" sont toutes fermées.");
             self.section_error.set(error);
             self.step.set(2);
+            self.schedule.set(vec![]);
             return;
         }
         self.section_error.set("".to_string());
@@ -63,6 +81,7 @@ impl OptionState {
             error.push_str(" sont en conflits avec les heures libres sélectionnées.");
             self.personal_error.set(error);
             self.step.set(3);
+            self.schedule.set(vec![]);
             return;
         }
         self.personal_error.set("".to_string());
@@ -73,7 +92,7 @@ impl OptionState {
         });
     }
 
-    pub fn generate(&self) {
+    fn generate(&self) {
         self.max_size
             .update_value(|v| v.store(8, Ordering::Relaxed));
         self.hide.set(true);
@@ -100,38 +119,22 @@ impl OptionState {
 
 impl Default for OptionState {
     fn default() -> Self {
-        let stored_courses: StoredValue<Vec<ReactiveCourse>> = store_value(vec![]);
-
-        let action_courses = create_action(move |sigle: &String| {
-            let sigle = sigle.clone();
-            async move {
-                if let Ok(c) = get_course(sigle).await {
-                    if !stored_courses
-                        .get_value()
-                        .iter()
-                        .any(|react_c| react_c.sigle == c.sigle)
-                    {
-                        stored_courses.update_value(|courses| courses.push(c.into()));
-                    }
-                }
-                stored_courses.get_value()
-            }
-        });
+        let courses: RwSignal<Vec<ReactiveCourse>> = RwSignal::new(vec![]);
 
         Self {
-            stored_courses,
-            action_courses,
-            max_nb_conflicts: create_rw_signal(0),
-            week: std::array::from_fn(|_i| create_rw_signal(0)),
-            day_off: create_rw_signal(3),
-            morning: create_rw_signal(1),
-            finish_early: create_rw_signal(1),
-            section_error: create_rw_signal("".to_string()),
-            personal_error: create_rw_signal("".to_string()),
-            step: create_rw_signal(0),
-            schedule: create_rw_signal(vec![]),
-            hide: create_rw_signal(false),
-            max_size: store_value(AtomicUsize::from(8)),
+            first_generation_done: StoredValue::new(false),
+            courses,
+            max_nb_conflicts: RwSignal::new(0),
+            week: std::array::from_fn(|_i| RwSignal::new(0)),
+            day_off: RwSignal::new(3),
+            morning: RwSignal::new(1),
+            finish_early: RwSignal::new(1),
+            section_error: RwSignal::new("".to_string()),
+            personal_error: RwSignal::new("".to_string()),
+            step: RwSignal::new(0),
+            schedule: RwSignal::new(vec![]),
+            hide: RwSignal::new(false),
+            max_size: StoredValue::new(AtomicUsize::from(8)),
         }
     }
 }
@@ -139,10 +142,8 @@ impl Default for OptionState {
 impl From<&OptionState> for SchedulesOptions {
     fn from(state: &OptionState) -> Self {
         let courses_to_take = state
-            .action_courses
-            .value()
-            .get()
-            .unwrap_or_default()
+            .courses
+            .get_untracked()
             .into_iter()
             .map(|c| c.into())
             .collect();
@@ -150,13 +151,13 @@ impl From<&OptionState> for SchedulesOptions {
         state
             .max_size
             .update_value(|v| max_size = v.load(Ordering::Relaxed));
-        let max_nb_conflicts = state.max_nb_conflicts.get();
+        let max_nb_conflicts = state.max_nb_conflicts.get_untracked();
         let evaluation = EvaluationOption {
-            day_off: state.day_off.get(),
-            morning: state.morning.get(),
-            finish_early: state.finish_early.get(),
+            day_off: state.day_off.get_untracked(),
+            morning: state.morning.get_untracked(),
+            finish_early: state.finish_early.get_untracked(),
         };
-        let user_conflicts = Week::new(state.week.map(|s| s.get() << 2));
+        let user_conflicts = Week::new(state.week.map(|s| s.get_untracked() << 2));
         Self {
             courses_to_take,
             max_nb_conflicts,
diff --git a/aep-schedule-website/src/frontend/state/reactive_course.rs b/aep-schedule-website/src/frontend/state/reactive_course.rs
index 3e6b0648cc46624e267b2f23da6326722139bc16..8f18bb458a1fbe5afe6948fa836cf1ed1a26a8b4 100644
--- a/aep-schedule-website/src/frontend/state/reactive_course.rs
+++ b/aep-schedule-website/src/frontend/state/reactive_course.rs
@@ -1,6 +1,6 @@
 use aep_schedule_generator::data::{course::Course, course_type::CourseType, groups::Groups};
 use compact_str::CompactString;
-use leptos::*;
+use leptos::prelude::*;
 
 #[derive(Clone, Debug)]
 pub enum ReactiveCourseType {
@@ -61,10 +61,10 @@ impl From<ReactiveCourse> for Course {
                 mut lab_groups,
             } => {
                 for (i, theo) in theo_open.iter().enumerate() {
-                    theo_groups.get_mut(i.into()).unwrap().open = theo.get();
+                    theo_groups.get_mut(i.into()).unwrap().open = theo.get_untracked();
                 }
                 for (i, lab) in lab_open.iter().enumerate() {
-                    lab_groups.get_mut(i.into()).unwrap().open = lab.get();
+                    lab_groups.get_mut(i.into()).unwrap().open = lab.get_untracked();
                 }
                 CourseType::Both {
                     theo_groups,
diff --git a/aep-schedule-website/src/lib.rs b/aep-schedule-website/src/lib.rs
index d0e2c0854d23649b747b6a62c7c082f9eb884b28..9f9dba45f890643472203d2e24dc2715c5ef33d7 100644
--- a/aep-schedule-website/src/lib.rs
+++ b/aep-schedule-website/src/lib.rs
@@ -3,7 +3,6 @@ pub mod backend;
 pub mod frontend;
 
 cfg_if::cfg_if! { if #[cfg(feature = "hydrate")] {
-    use leptos::*;
     use wasm_bindgen::prelude::wasm_bindgen;
     use crate::frontend::app::App;
 
@@ -12,7 +11,6 @@ cfg_if::cfg_if! { if #[cfg(feature = "hydrate")] {
         // initializes logging using the `log` crate
         _ = console_log::init_with_level(log::Level::Debug);
         console_error_panic_hook::set_once();
-
-        leptos::mount_to_body(App);
+        leptos::mount::hydrate_body(App);
     }
 }}
diff --git a/aep-schedule-website/src/main.rs b/aep-schedule-website/src/main.rs
index 7f2f1bf57fea1e14d7178a0a9f51d369d9f6f20f..1bb04894d09b784725bcdc9255a1b987c865f989 100644
--- a/aep-schedule-website/src/main.rs
+++ b/aep-schedule-website/src/main.rs
@@ -5,7 +5,7 @@ cfg_if::cfg_if!(if #[cfg(feature = "ssr")] {
     };
     use std::future::IntoFuture;
     use leptos_axum::{generate_route_list, LeptosRoutes};
-    use leptos::*;
+    use leptos::prelude::*;
     use tower_http::compression::CompressionLayer;
     use aep_schedule_website::backend::fileserv::file_and_error_handler;
     use aep_schedule_website::frontend::app::App;
@@ -19,7 +19,7 @@ cfg_if::cfg_if!(if #[cfg(feature = "ssr")] {
         // <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
         // Alternately a file can be specified such as Some("Cargo.toml")
         // The file would need to be included with the executable when moved to deployment
-        let conf = get_configuration(None).await.unwrap();
+        let conf = get_configuration(None).unwrap();
         let leptos_options = conf.leptos_options;
         let routes = generate_route_list(App);
         let state = AppState::new(leptos_options.clone(), routes.clone()).await;
diff --git a/flake.lock b/flake.lock
index 26bce6555228969182f4b326643b5a876962c97f..c662d3b62f2f6808466a383e4c9091ce21334639 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1716137900,
-        "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=",
+        "lastModified": 1729880355,
+        "narHash": "sha256-RP+OQ6koQQLX5nw0NmcDrzvGL8HDLnyXt/jHhL1jwjM=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1",
+        "rev": "18536bf04cd71abd345f9579158841376fdd0c5a",
         "type": "github"
       },
       "original": {
@@ -42,11 +42,11 @@
         "systems": "systems"
       },
       "locked": {
-        "lastModified": 1710146030,
-        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+        "lastModified": 1726560853,
+        "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+        "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
         "type": "github"
       },
       "original": {