Web Frontend

This section discusses the frameworks you can use in Rust to build web frontends that run in the browser. If you are already familiar with the architecture of single-page web applications, you can skip down to the frameworks for a discussion of how they work.

Background

Websites use HTML for both content and structure. CSS is used to style how the website looks. The browser reads the HTML to get the content and layout, then applies CSS to style it, and finally renders it to the screen. When writing web applications, the first question is where and when this HTML is generated.

In traditional web applications, the HTML is created on the server. When the backend gets a request, it processes it and generates an HTML response. This response is then sent to the browser. On any interaction, such as a click on a link, press of a button or submission of a form, a new request is made to the browser, and a new HTML response is sent.

Traditional web application

The Rust web backend frameworks have good support for writing web applications this way, often combined with templating crates such as handlebars or tera. The downside to this traditional approach is higher latencies. Since the entire page needs to be regenerated, transmitted and rendered on every interaction, there is a noticeable delay. When structing a web application this way, it is difficult to implement interactive widgets on pages, or update information in real-time.

Modern web frontend applications are often single-page applications (SPAs), written in languages like JavaScript or TypeScript and run in the browser. They are called “single-page” because the entire app is loaded in the initial request. After that, the frontend reacts to interactions and dynamically updates the content, without needing to realod the page. Communication with the backend typically happens through an API. This keeps the app responsive while waiting for server responses and allows for real-time events from the server using technologies like WebSockets.

Modern web application

Since the standardization of WebAssembly and the broad browser support it has gained, it has been possible to write frontend web applications languages other than JavaScript. This section explores Rust frameworks that allow you to write single-page web applications for full-stack Rust projects.

Using Rust for web frontends has some benefits. It allows you to write performant frontends, make use of the Rust crate ecosystem, and share type definitions between your backend and frontend easily. However, the availability of this is a relatively new and JavaScript-based frameworks tend to be more mature. Finding frontend engineers that are familiar with JavaScript-based frameworks is also a lot easier. If you want to build a prototype frontend for an existing Rust project, it may be worth exploring these as it allows you use a single language across the project.

The Component Model

All Rust web frontend frameworks discussed here use the component model to implement applications. In web frontend development, the component model is a way to build applications using reusable and self-contained pieces called components. Each component has its own logic and can manage its own state and appearance. Components can be nested within other components to build complex user interfaces. If you are familiar with React or similar JavaScript frontend libraries, then you should already be familiar with the component model.

Component application

Typically, web frameworks use a HTML-like domain-specific language to represent the outputs of components. For example, the root component of this example application might look like this:

#![allow(unused)]
fn main() {
html! {
    <main>
        <Header />
        <div class="content">
            <SideBar />
            <Content />
        </div>
    </main>
}
}

Like functions can have arguments, components can have properties. These are inputs to the component. In this example, the HTML div element has the property class="content". In the same way, Rust components can have properties, which can be any Rust type.

As a convention, HTML native components are usually lowercased (such as main, div, p) whereas Rust components are uppercased (such as Header, SideBar, Content).

Components can also have state.

Finally, many frameworks also support context. Unlike properties, which a parent explicitly passes down to its child components, context is implicitly passed down to all child components (even children-of-children). This is often useful to pass global state such as whether the user is logged in down to all components in the tree, or utilities such as data caches.

The the web frameworks do is they handle changing of data. If any of the inputs to a component changes, whether that be properties, state or context, the component is re-rendered.

Component data model

The way frameworks can track these changes depend on the framework itself, but generally they are able to do so because they have hooks that allow them to track what is changed and when.

  • animation of changes propagating

In this section, we will not cover all available frontend frameworks, only a few of the post popular. As this is a relatively new development, there is a lot of activity in the various frameworks and you should expect some volatility in which frameworks are the most popular.

Raw Web APIs with web-sys

While most of the Rust web frameworks handle all of the interactions with the underlying web APIs, sometimes you may find the need to go “deeper” and interact with the raw APIs. The way you do this is by using the web-sys crate, which has safe Rust wrappers for all of the APIs the browser exposes.

Note

One quirk of the web-sys crate is that it puts every single API behind a feature flag. In doing so, it has over 1,500 features, and as such needs an exception to bypass the crates.io crate features limit. If you use it, don’t be surprised if you get compiler errors, make sure that you have enabled the correct set of features. The crate documentation shows you for every interface, which feature it requires.

Most frontend libraries will allow you to get raw access to the underlying DOM nodes and perform raw operations on them. One example is when you want to use a <canvas> element, you can use this to draw on it. Here is an example of what this looks like in Yew:

#![allow(unused)]
fn main() {
// todo
}

You must keep in mind how the framework renders, to make sure that your raw access is not broken by components refreshing.

Compiling and Deploying Frontend Applications

Deploying a Rust frontend web application in the browser is a bit more complex than just running cargo build, since the resulting WebAssembly blob still needs to be packaged in a way that a browser can consume, and it needs some JavaScript glue to make it usable. For this, a lot of frameworks use Trunk to bundle and ship the raw Rust WebAssembly binaries into something the browser can understand. The Trunk section below explains how that works and how you can configure it.

Some Rust web frontend frameworks also support server-side rendering, where it can fallback to a traditional web application style where the HTML is generated server-side. This can also help search engines index the websites better by not needing WebAssembly support to render the website. The frameworks support partial hydration, where parts of the website are rendered server-side, or full hydration where every page can be fully rendered server-side.

If you use this feature, you also need to integrate your frontend application with your backend.

Rendering Methods

Browsers represent a loaded website (with HTML and styling) in their Document Object Model. Web frontend frameworks have to update this DOM whenever components change their outputs. One important difference between frameworks is in how they do this.

Some frameworks have a shadow DOM (sometimes also called virtual DOM), which is a copy of the DOM that is in the browser, that components modify. The framework then synchronizes this copy with the real DOM.

Other frameworks modify the DOM directly, which can have some performance benefits.

WebAssembly Support in the Ecosystem

Thanks to Rust’s use of LLVM, a compiler infrastructure that makes it easy to write new backends for different targets, it gained support for targetting WebAssembly relatively early. This means you can write entire applications that live and run in the browser in Rust, and make use of Rust’s extensive ecosystem.

Not all of Rust crates will work on WebAssembly out-of-the-box, for example because they access native operating system APIs that do not exist in WebAssembly, but many will work out-of-the-box or have feature flags that can be enabled to add support for it.

All of the low-level APIs that are relevant for running in the browser are exposed by the web_sys crate. This is a large crate that is automatically generated, and you need to enable features to enable it’s various APIs. Ergonomic wrappers for a lot of functionality are exposed by the gloo crate, and you should use this if you can.

Async Support

Thanks to the hard work of the community, it is even possible to use Rust async code in a WebAssembly environment through the use of wasm-bindgen-futures. These map the interface of Rust’s Futures to JavaScript Promises.

For example, you can use this to spawn a future in the background to make a network request and get the body of some web resource using the reqwest library:

#![allow(unused)]
fn main() {
wasm_bindgen_futures::spawn_local(async {
    let test = reqwest::get("https://www.rust-lang.org")
        .await?
        .text()
        .await?;
});
}

Most frameworks have some kind of wrapper around these raw futures to be able to use them in the applications.

Server-Side Rendering

Differences between frameworks

The rest of this section discusses some frameworks for Rust-based frontend programming. Generally, the conceptual model of these frameworks is very similar, because they used the same component model.

Differences between the frameworks exist between:

  • The language they use to describe the output of a component. Usually, this is some kind of macro that allows you to specify a tree of components (HTML or native), their properties and children.
  • The method in which they render the output of the components into the browser (using direct rendering or a shadow DOM). Either rendering methods can have advantages, it depends on what you are doing. Unless you are rendering a large amount of data or update frequently, it likely does not make a difference.
  • The ecosystem of premade components and hooks. Some frameworks are more established and have third-part support for premade hooks and component libraries. These make your life easier.
  • The degree to which they allow you to access raw browser APIs. Frameworks that have multiple rendering backends might be more limited in their support for raw browser APIs for compatibility.
  • The syntax they use for defining components, properties and create and access hooks.
  • The build system they use and support (either Trunk or a custom build system)
  • Support for server-side rendering, for example having plugins for popular web backend crates such as axum or actix-web.

In the next sections, we will showcase some popular frameworks and attempt to give an overview of their features.

Yew

Yew is currently the most popular framework for web frontend development in Rust. It uses a reactive component model, has a useful ecosystem of plugins, supports server-side rendering, routing, and has a html! macro that makes it relatively easy to get started.

To define a component, you can either implement the Component trait, or use the function_component derive macro. In general, the latter leads to more concise code, and is the recommended way. Functional components return Html, using the html macro. This macro can output raw HTML, or other child components.

#![allow(unused)]
fn main() {
#[function_component]
fn app() -> Html {
    html! {
        <h1>{ "Hello World" }</h1>
    }
}
}

You can think of this function as always being run whenever your component needs to re-render, for example if any of the inputs (props or state) have changed. To declare state in your component, you use hooks. Here is an example:

#![allow(unused)]
fn main() {
#[function_component]
fn App() -> Html {
    let state = use_state(|| 0);

    let increment_counter = {
        let state = state.clone();
        Callback::from(move |_| state.set(*state + 1))
    };

    let decrement_counter = {
        let state = state.clone();
        Callback::from(move |_| state.set(*state - 1))
    };

    html! {
        <>
            <p> {"current count: "} {*state} </p>
            <button onclick={increment_counter}> {"+"} </button>
            <button onclick={decrement_counter}> {"-"} </button>
        </>
    }
}
}

Simple hooks come built-in, but there are also external crates offering more hooks.

The idea is that you can compose these small components into bigger applications. Yew also comes with a plugin for routing.

One thing that is nice about Yew is that the html! macro it uses very closely resembles HTML. There is not a steep learning curve if you are familiar with it. The only downside with it is that values require quoting, you can see that to have text inside a paragraph element, you need to write <p>{"Text here"}</p>. Another downside of it is that the state handles it uses require cloning, which adds some clutter to the code.

Example: Yew Todo App

Here is an example of a todo-list application written in Yew. It showcases props, child components, raw HTML rendering, the use_state hook and how to package it with trunk.

  • .gitignore
  • .gitlab-ci.yml
  • Cargo.lock
  • Cargo.toml
  • README.md
  • index.html
  • src/
    • lib.rs
    • main.rs
    • style.css
/target
/dist
stages:
  - publish

# build application with trunk, use pinned versions for reproducible build.
pages:
  stage: publish
  image: rust:1.80
  variables:
    TRUNK_VERSION: 0.20.3
    TRUNK_BUILD_PUBLIC_URL: "/$CI_PROJECT_NAME"
  before_script:
    - rustup target add wasm32-unknown-unknown
    - wget -qO- https://github.com/thedodd/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -C /usr/local/bin
  script:
    - trunk build --release
    - mv dist public
  artifacts:
    paths:
      - public
  only:
    - master
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "addr2line"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
 "gimli",
]

[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"

[[package]]
name = "anymap2"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"

[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"

[[package]]
name = "backtrace"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
 "addr2line",
 "cc",
 "cfg-if",
 "libc",
 "miniz_oxide",
 "object",
 "rustc-demangle",
]

[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
 "serde",
]

[[package]]
name = "boolinator"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"

[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"

[[package]]
name = "bytes"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"

[[package]]
name = "cc"
version = "1.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
dependencies = [
 "shlex",
]

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
 "cfg-if",
 "wasm-bindgen",
]

[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"

[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
 "percent-encoding",
]

[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-io",
 "futures-sink",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
 "futures-core",
 "futures-sink",
]

[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"

[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"

[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"

[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"

[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-io",
 "futures-macro",
 "futures-sink",
 "futures-task",
 "memchr",
 "pin-project-lite",
 "pin-utils",
 "slab",
]

[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
 "cfg-if",
 "js-sys",
 "libc",
 "wasi",
 "wasm-bindgen",
]

[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"

[[package]]
name = "gloo"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d"
dependencies = [
 "gloo-console 0.2.3",
 "gloo-dialogs 0.1.1",
 "gloo-events 0.1.2",
 "gloo-file 0.2.3",
 "gloo-history 0.1.5",
 "gloo-net 0.3.1",
 "gloo-render 0.1.1",
 "gloo-storage 0.2.2",
 "gloo-timers 0.2.6",
 "gloo-utils 0.1.7",
 "gloo-worker 0.2.1",
]

[[package]]
name = "gloo"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249"
dependencies = [
 "gloo-console 0.3.0",
 "gloo-dialogs 0.2.0",
 "gloo-events 0.2.0",
 "gloo-file 0.3.0",
 "gloo-history 0.2.2",
 "gloo-net 0.4.0",
 "gloo-render 0.2.0",
 "gloo-storage 0.3.0",
 "gloo-timers 0.3.0",
 "gloo-utils 0.2.0",
 "gloo-worker 0.4.0",
]

[[package]]
name = "gloo-console"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f"
dependencies = [
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-console"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261"
dependencies = [
 "gloo-utils 0.2.0",
 "js-sys",
 "serde",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-dialogs"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-dialogs"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-events"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-events"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-file"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
dependencies = [
 "gloo-events 0.1.2",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-file"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
dependencies = [
 "gloo-events 0.2.0",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-history"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f"
dependencies = [
 "gloo-events 0.1.2",
 "gloo-utils 0.1.7",
 "serde",
 "serde-wasm-bindgen 0.5.0",
 "serde_urlencoded",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-history"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6"
dependencies = [
 "getrandom",
 "gloo-events 0.2.0",
 "gloo-utils 0.2.0",
 "serde",
 "serde-wasm-bindgen 0.6.5",
 "serde_urlencoded",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-net"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-sink",
 "gloo-utils 0.1.7",
 "http",
 "js-sys",
 "pin-project",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-net"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-sink",
 "gloo-utils 0.2.0",
 "http",
 "js-sys",
 "pin-project",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-render"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-render"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-storage"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480"
dependencies = [
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-storage"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a"
dependencies = [
 "gloo-utils 0.2.0",
 "js-sys",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "gloo-timers"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "gloo-utils"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
dependencies = [
 "js-sys",
 "serde",
 "serde_json",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
dependencies = [
 "js-sys",
 "serde",
 "serde_json",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-worker"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a"
dependencies = [
 "anymap2",
 "bincode",
 "gloo-console 0.2.3",
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-worker"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400"
dependencies = [
 "bincode",
 "futures",
 "gloo-utils 0.2.0",
 "gloo-worker-macros",
 "js-sys",
 "pinned",
 "serde",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-worker-macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7"
dependencies = [
 "proc-macro-crate",
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"

[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"

[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
 "bytes",
 "fnv",
 "itoa",
]

[[package]]
name = "implicit-clone"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8a9aa791c7b5a71b636b7a68207fdebf171ddfc593d9c8506ec4cbc527b6a84"
dependencies = [
 "implicit-clone-derive",
 "indexmap",
]

[[package]]
name = "implicit-clone-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b"
dependencies = [
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "indexmap"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
 "equivalent",
 "hashbrown",
]

[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"

[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
 "wasm-bindgen",
]

[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"

[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"

[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"

[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
 "adler",
]

[[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 = "object"
version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
dependencies = [
 "memchr",
]

[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"

[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"

[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
 "pin-project-internal",
]

[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"

[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "pinned"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
dependencies = [
 "futures",
 "rustversion",
 "thiserror",
]

[[package]]
name = "prettyplease"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
dependencies = [
 "proc-macro2",
 "syn 2.0.77",
]

[[package]]
name = "proc-macro-crate"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
 "once_cell",
 "toml_edit",
]

[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
 "proc-macro-error-attr",
 "proc-macro2",
 "quote",
 "syn 1.0.109",
 "version_check",
]

[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
 "proc-macro2",
 "quote",
 "version_check",
]

[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "prokio"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488"
dependencies = [
 "futures",
 "gloo 0.8.1",
 "num_cpus",
 "once_cell",
 "pin-project",
 "pinned",
 "tokio",
 "tokio-stream",
 "wasm-bindgen-futures",
]

[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"

[[package]]
name = "rustversion"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"

[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"

[[package]]
name = "serde"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
 "serde_derive",
]

[[package]]
name = "serde-wasm-bindgen"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
dependencies = [
 "js-sys",
 "serde",
 "wasm-bindgen",
]

[[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.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "serde_json"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
dependencies = [
 "itoa",
 "memchr",
 "ryu",
 "serde",
]

[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
 "form_urlencoded",
 "itoa",
 "ryu",
 "serde",
]

[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"

[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
 "autocfg",
]

[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
 "proc-macro2",
 "unicode-ident",
]

[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
 "thiserror-impl",
]

[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "todo-yew"
version = "0.1.0"
dependencies = [
 "web-sys",
 "yew",
]

[[package]]
name = "tokio"
version = "1.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
dependencies = [
 "backtrace",
 "pin-project-lite",
]

[[package]]
name = "tokio-stream"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
dependencies = [
 "futures-core",
 "pin-project-lite",
 "tokio",
]

[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"

[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
 "indexmap",
 "toml_datetime",
 "winnow",
]

[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
 "pin-project-lite",
 "tracing-attributes",
 "tracing-core",
]

[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]

[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
 "once_cell",
]

[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
 "cfg-if",
 "once_cell",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
 "bumpalo",
 "log",
 "once_cell",
 "proc-macro2",
 "quote",
 "syn 2.0.77",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
 "cfg-if",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.77",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"

[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "winnow"
version = "0.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
dependencies = [
 "memchr",
]

[[package]]
name = "yew"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac"
dependencies = [
 "console_error_panic_hook",
 "futures",
 "gloo 0.10.0",
 "implicit-clone",
 "indexmap",
 "js-sys",
 "prokio",
 "rustversion",
 "serde",
 "slab",
 "thiserror",
 "tokio",
 "tracing",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
 "yew-macro",
]

[[package]]
name = "yew-macro"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2"
dependencies = [
 "boolinator",
 "once_cell",
 "prettyplease",
 "proc-macro-error",
 "proc-macro2",
 "quote",
 "syn 2.0.77",
]
[package]
name = "todo-yew"
version = "0.1.0"
edition = "2021"

[dependencies]
web-sys = { version = "0.3.70", features = ["HtmlInputElement"] }
yew = { version = "0.21.0", features = ["csr"] }
# Yew Todo App

A port of a [React Todo
App](https://www.digitalocean.com/community/tutorials/how-to-build-a-react-to-do-app-with-react-hooks)
to use the [Yew](https://yew.rs) framework.

This is an example project for the [Web
Frontend](https://rustprojectprimer.com/ecosystem/web-frontend.html) section of
the [Rust Project Primer](https://rustprojectprimer.com/) book.

## Prerequisites

You need two prerequisites to build this:

- Rust 1.80 with support for `wasm32-unknown-unknown` target
- Trunk build tool

### Setup

You can install Rust using [Rustup](https://rustup.rs):

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

You need to tell Rustup to add the WebAssembly target:

    rustup target add wasm32-unknown-unknown

You need to install [Trunk](https://trunkrs.dev) to build and serve it:

    cargo install trunk

## Running it

You can run it locally with Trunk:

    trunk serve

This will build and serve it, and watch the project for any changes. When you
edit the code, it will recompile and cause your browser to refresh.
<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link data-trunk rel="rust" />
        <link data-trunk data-inline rel="css" href="src/style.css" />
        <title>Todo Yew</title>
    </head>
    <body>
    </body>
</html>
use web_sys::HtmlInputElement;
use yew::prelude::*;

/// Represents a single Todo item.
#[derive(PartialEq, Clone)]
pub struct Todo {
    pub text: String,
    pub completed: bool,
}

impl Todo {
    /// Create a new todo item that is not completed.
    fn new<S: Into<String>>(text: S) -> Self {
        Self {
            text: text.into(),
            completed: false,
        }
    }

    fn complete(&mut self) {
        self.completed = !self.completed;
    }
}

#[function_component]
pub fn App() -> Html {
    // list of default todos to show
    let items = use_state(|| {
        vec![
            Todo::new("Buy milk"),
            Todo::new("Learn Rust"),
            Todo::new("Drink enough water"),
            Todo::new("Spend time with family"),
        ]
    });

    // submit a new todo item to the list
    let submit = {
        let items = items.clone();
        move |entry: String| {
            let mut current = (*items).clone();
            current.push(Todo::new(entry));
            items.set(current);
        }
    };

    html! {
        <div class="app">
            <div class="heading">
                {"Todo List"}
            </div>
            <div class="todo-list">
                {
                    items.iter().enumerate().map(|(index, item)| {
                        // mark current todo entry as completed
                        let complete = {
                            let items = items.clone();
                            move |()| {
                                let mut current = (*items).clone();
                                current[index].complete();
                                items.set(current);
                            }
                        };

                        // remove current todo entry
                        let remove = {
                            let items = items.clone();
                            move |()| {
                                let mut current = (*items).clone();
                                current.remove(index);
                                items.set(current);
                            }
                        };

                        html! {
                            <TodoRow key={index} item={item.clone()} {complete} {remove} />
                        }
                    }).collect::<Html>()
                }
            </div>
            <div class="footer">
                <TodoForm {submit} />
            </div>
        </div>
    }
}

/// Props for the todo row. Takes a todo item, and callbacks for what happens when the complete and
/// remove buttons are clicked.
#[derive(PartialEq, Properties, Clone)]
struct TodoRowProps {
    item: Todo,
    #[prop_or_default]
    complete: Callback<()>,
    #[prop_or_default]
    remove: Callback<()>,
}

/// Represents a single todo line, with buttons to mark it as complete and a button to delete it.
#[function_component]
fn TodoRow(props: &TodoRowProps) -> Html {
    let props = props.clone();
    html! {
        <div class={classes!("todo", props.item.completed.then_some("completed"))}>
            { &props.item.text }
            <div>
                <button class="complete" onclick={move |_| props.complete.emit(())}>{"✓"}</button>
                <button class="remove" onclick={move |_| props.remove.emit(())}>{"⨯"}</button>
            </div>
        </div>
    }
}

#[derive(PartialEq, Properties)]
struct TodoFormProps {
    #[prop_or_default]
    submit: Callback<String>,
}

/// Represents a form for adding iodos, as a text-input field.
#[function_component]
fn TodoForm(props: &TodoFormProps) -> Html {
    let value = use_state(String::default);

    let onsubmit = {
        let value = value.clone();
        let submit = props.submit.clone();
        move |event: SubmitEvent| {
            event.prevent_default();
            if !value.is_empty() {
                submit.emit((*value).clone());
            }
            value.set(String::default());
        }
    };

    let onchange = {
        let value = value.clone();
        move |event: Event| {
            let target: HtmlInputElement = event.target_dyn_into().unwrap();
            value.set(target.value());
        }
    };

    html! {
        <form {onsubmit}>
            <input r#type="text" class="input" value={value.as_str().to_string()} {onchange} />
        </form>
    }
}
use todo_yew::App;

fn main() {
    yew::Renderer::<App>::new().render();
}
body {
  background: #209cee;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}

.app {
  height: 100vh;
  padding: 10px;
  padding-top: 20px;
  padding-bottom: 20px;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.app .heading {
  padding: 5px;
  padding-top: 10px;
  padding-bottom: 10px;
  text-align: center;
  font-size: 20px;
  font-weight: 600;
  border-radius: 7px 7px 0px 0px;

  background: #e8e8e8;

  border: 1px solid #d8d8d8;
  border-bottom: 1px solid #b4b4b4;

  background: linear-gradient(to bottom,  #f6f6f6 0%,#dadada 100%);
}

.app .todo-list {
  padding: 5px;
  background: #ffffff;

  /*border-top: 1px solid #b4b4b4;*/
  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
}

.app .footer {
  padding: 5px;
  border-radius: 0px 0px 7px 7px;
  background: #ffffff;
  padding-bottom: 10px;

  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
  border-bottom: 1px solid #d8d8d8;
}

.app .footer form * {
  box-sizing: border-box;
  width: 100%;
}

.todo-list .todo {
  align-items: center;
  background: #f0f0f0;
  border-radius: 3px;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.15);
  display: flex;
  font-size: 14px;
  justify-content: space-between;
  margin-bottom: 6px;
  padding: 3px 10px;
}

.todo-list .todo button {
  width: 20px;
  height: 20px;
  font-size: 10px;
  background: #f9f9f9;
  border-radius: 50%;
  margin: 0 4px 0 0;
  opacity: 20%;
  text-align: center;

  background: #e9e9e9;
  border: 1px solid #e0e0e0;
}

.todo-list .todo button:hover {
  opacity: 100%;
  transition: 100ms;
}

.todo-list .todo button.complete {
  background: #27C93F;
  border: 1px solid #1DAD2B;
  transition: 100ms;
}

.todo-list .todo button.remove {
  background: #FF6057;
  border: 1px solid #E14640;
  transition: 100ms;
}

.todo.completed {
  text-decoration: line-through;
}

You can see this application in action here. In this example, you can see how properties in Yew are structs that derive the Properties trait. You can also see how state is represented with the use_state() hook, and how Callback is used to pass callbacks down to child components. The html! macro is used to output HTML elements and child components, and the classes! macro is used to create a list of classes.

Leptos

Leptos is a web frontend framework for Rust that is quite similar to Yew. The primary difference is in how it renders: Yew renders to a shadow DOM, and then synchronizes it to the real DOM, while Leptos directly updates the DOM. This has some implications in terms of speed.

#![allow(unused)]
fn main() {
#[component]
pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
    // create a reactive signal with the initial value
    let (value, set_value) = create_signal(initial_value);

    // create event handlers for our buttons
    // note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures
    let clear = move |_| set_value(0);
    let decrement = move |_| set_value.update(|value| *value -= 1);
    let increment = move |_| set_value.update(|value| *value += 1);

    // create user interfaces with the declarative `view!` macro
    view! {
        <div>
            <button on:click=clear>Clear</button>
            <button on:click=decrement>-1</button>
            // text nodes can be quoted or unquoted
            <span>"Value: " {value} "!"</span>
            <button on:click=increment>+1</button>
        </div>
    }
}
}

One thing to note is that the view! macro it uses to create the component output tree has some slightly different syntax from regular HTML. For example, it uses on:click=value instead of onclick=value. An upside is that values do not require being put into braces, so <span>"Hello"</span> is valid. Also, the state handles it uses do not require cloning as they do in Yew.

Example: Todo App

Here is an example of a todo-list application written using Leptos. It showcases defining components, rendering child components, passing down properties, handling state and passing callbacks to child components.

  • .gitignore
  • .gitlab-ci.yml
  • Cargo.lock
  • Cargo.toml
  • README.md
  • index.html
  • src/
    • lib.rs
    • main.rs
    • style.css
/target
/dist
stages:
  - publish

# build application with trunk, use pinned versions for reproducible build.
pages:
  stage: publish
  image: rust:1.80
  variables:
    TRUNK_VERSION: 0.20.3
    TRUNK_BUILD_PUBLIC_URL: "/$CI_PROJECT_NAME"
  before_script:
    - rustup target add wasm32-unknown-unknown
    - wget -qO- https://github.com/thedodd/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -C /usr/local/bin
  script:
    - trunk build --release
    - mv dist public
  artifacts:
    paths:
      - public
  only:
    - master
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
 "memchr",
]

[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"

[[package]]
name = "async-recursion"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "attribute-derive"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f1ee502851995027b06f99f5ffbeffa1406b38d0b318a1ebfa469332c6cbafd"
dependencies = [
 "attribute-derive-macro",
 "derive-where",
 "manyhow",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "attribute-derive-macro"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3601467f634cfe36c4780ca9c75dea9a5b34529c1f2810676a337e7e0997f954"
dependencies = [
 "collection_literals",
 "interpolator",
 "manyhow",
 "proc-macro-utils",
 "proc-macro2",
 "quote",
 "quote-use",
 "syn",
]

[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"

[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"

[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"

[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"

[[package]]
name = "bytes"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"

[[package]]
name = "camino"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[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 = "collection_literals"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"

[[package]]
name = "config"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
dependencies = [
 "convert_case",
 "lazy_static",
 "nom",
 "pathdiff",
 "serde",
 "toml",
]

[[package]]
name = "const_format"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
dependencies = [
 "const_format_proc_macros",
]

[[package]]
name = "const_format_proc_macros"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
 "unicode-segmentation",
]

[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"

[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
 "cfg-if",
 "hashbrown",
 "lock_api",
 "once_cell",
 "parking_lot_core",
]

[[package]]
name = "derive-where"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "drain_filter_polyfill"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408"

[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"

[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"

[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
 "percent-encoding",
]

[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-executor",
 "futures-io",
 "futures-sink",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
 "futures-core",
 "futures-sink",
]

[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"

[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
 "futures-core",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"

[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"

[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"

[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-io",
 "futures-macro",
 "futures-sink",
 "futures-task",
 "memchr",
 "pin-project-lite",
 "pin-utils",
 "slab",
]

[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
 "cfg-if",
 "js-sys",
 "libc",
 "wasi",
 "wasm-bindgen",
]

[[package]]
name = "gloo-net"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-sink",
 "gloo-utils",
 "http",
 "js-sys",
 "pin-project",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
dependencies = [
 "js-sys",
 "serde",
 "serde_json",
 "wasm-bindgen",
 "web-sys",
]

[[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.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"

[[package]]
name = "html-escape"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
dependencies = [
 "utf8-width",
]

[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
 "bytes",
 "fnv",
 "itoa",
]

[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
 "unicode-bidi",
 "unicode-normalization",
]

[[package]]
name = "indexmap"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
dependencies = [
 "equivalent",
 "hashbrown",
]

[[package]]
name = "interpolator"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"

[[package]]
name = "inventory"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"

[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
 "either",
]

[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"

[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
 "wasm-bindgen",
]

[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"

[[package]]
name = "leptos"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15911b4e53bb6e1b033d717eadb39924418a4a288279128122e5a65c70ba3e6"
dependencies = [
 "cfg-if",
 "leptos_config",
 "leptos_dom",
 "leptos_macro",
 "leptos_reactive",
 "leptos_server",
 "server_fn",
 "tracing",
 "typed-builder",
 "typed-builder-macro",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "leptos_config"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc4d78fba18c1ccab48ffc9f3d35b39821f896b0a28bdd616a846b6241036c9"
dependencies = [
 "config",
 "regex",
 "serde",
 "thiserror",
 "typed-builder",
]

[[package]]
name = "leptos_dom"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ccb04d4763603bb665fa35cb9642d0bd75313117d10efda9b79243c023e69df"
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",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "leptos_hot_reload"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cc61e5cce26761562cd3332630b3fbaddb1c4f77744e41474c7212ad279c5d9"
dependencies = [
 "anyhow",
 "camino",
 "indexmap",
 "parking_lot",
 "proc-macro2",
 "quote",
 "rstml",
 "serde",
 "syn",
 "walkdir",
]

[[package]]
name = "leptos_macro"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90eaea005cabb879c091c84cfec604687ececfd540469e5a30a60c93489a2f23"
dependencies = [
 "attribute-derive",
 "cfg-if",
 "convert_case",
 "html-escape",
 "itertools",
 "leptos_hot_reload",
 "prettyplease",
 "proc-macro-error",
 "proc-macro2",
 "quote",
 "rstml",
 "server_fn_macro",
 "syn",
 "tracing",
 "uuid",
]

[[package]]
name = "leptos_reactive"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef2f99f377472459b0d320b46e9a9516b0e68dee5ed8c9eeb7e8eb9fefec5d2"
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",
 "tracing",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "leptos_server"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f07be202a433baa8c50050de4f9c116efccffc57208bcda7bd1bb9b8e87dca9"
dependencies = [
 "inventory",
 "lazy_static",
 "leptos_macro",
 "leptos_reactive",
 "serde",
 "server_fn",
 "thiserror",
 "tracing",
]

[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"

[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
 "autocfg",
 "scopeguard",
]

[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"

[[package]]
name = "manyhow"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91ea592d76c0b6471965708ccff7e6a5d277f676b90ab31f4d3f3fc77fade64"
dependencies = [
 "manyhow-macros",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "manyhow-macros"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64621e2c08f2576e4194ea8be11daf24ac01249a4f53cd8befcbb7077120ead"
dependencies = [
 "proc-macro-utils",
 "proc-macro2",
 "quote",
]

[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"

[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"

[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
 "memchr",
 "minimal-lexical",
]

[[package]]
name = "oco_ref"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51ebcefb2f0b9a5e0bea115532c8ae4215d1b01eff176d0f4ba4192895c2708"
dependencies = [
 "serde",
 "thiserror",
]

[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"

[[package]]
name = "pad-adapter"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63"

[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
 "lock_api",
 "parking_lot_core",
]

[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
 "cfg-if",
 "libc",
 "redox_syscall",
 "smallvec",
 "windows-targets",
]

[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"

[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"

[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"

[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
 "pin-project-internal",
]

[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"

[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "prettyplease"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
dependencies = [
 "proc-macro2",
 "syn",
]

[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
 "proc-macro-error-attr",
 "proc-macro2",
 "quote",
 "version_check",
]

[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
 "proc-macro2",
 "quote",
 "version_check",
]

[[package]]
name = "proc-macro-utils"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8"
dependencies = [
 "proc-macro2",
 "quote",
 "smallvec",
]

[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "proc-macro2-diagnostics"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "version_check",
 "yansi",
]

[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "quote-use"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e96ac59974192a2fa6ee55a41211cf1385c5b2a8636a4c3068b3b3dd599ece"
dependencies = [
 "quote",
 "quote-use-macros",
]

[[package]]
name = "quote-use-macros"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c57308e9dde4d7be9af804f6deeaa9951e1de1d5ffce6142eb964750109f7e"
dependencies = [
 "derive-where",
 "proc-macro-utils",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "redox_syscall"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
dependencies = [
 "bitflags",
]

[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
 "aho-corasick",
 "memchr",
 "regex-automata",
 "regex-syntax",
]

[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
 "aho-corasick",
 "memchr",
 "regex-syntax",
]

[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"

[[package]]
name = "rstml"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe542870b8f59dd45ad11d382e5339c9a1047cde059be136a7016095bbdefa77"
dependencies = [
 "proc-macro2",
 "proc-macro2-diagnostics",
 "quote",
 "syn",
 "syn_derive",
 "thiserror",
]

[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"

[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"

[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
 "winapi-util",
]

[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"

[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
dependencies = [
 "futures-core",
]

[[package]]
name = "serde"
version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
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.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "serde_json"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
dependencies = [
 "itoa",
 "memchr",
 "ryu",
 "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_spanned"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
dependencies = [
 "serde",
]

[[package]]
name = "server_fn"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "024b400db1aca5bd4188714f7bbbf7a2e1962b9a12a80b2a21e937e509086963"
dependencies = [
 "bytes",
 "ciborium",
 "const_format",
 "dashmap",
 "futures",
 "gloo-net",
 "http",
 "js-sys",
 "once_cell",
 "send_wrapper",
 "serde",
 "serde_json",
 "serde_qs",
 "server_fn_macro_default",
 "thiserror",
 "url",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "wasm-streams",
 "web-sys",
 "xxhash-rust",
]

[[package]]
name = "server_fn_macro"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf0e6f71fc924df36e87f27dfbd447f0bedd092d365db3a5396878256d9f00c"
dependencies = [
 "const_format",
 "convert_case",
 "proc-macro2",
 "quote",
 "syn",
 "xxhash-rust",
]

[[package]]
name = "server_fn_macro_default"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556e4fd51eb9ee3e7d9fb0febec6cef486dcbc8f7f427591dfcfebee1abe1ad4"
dependencies = [
 "server_fn_macro",
 "syn",
]

[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
 "autocfg",
]

[[package]]
name = "slotmap"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
dependencies = [
 "serde",
 "version_check",
]

[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"

[[package]]
name = "syn"
version = "2.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "syn_derive"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
dependencies = [
 "proc-macro-error",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
 "thiserror-impl",
]

[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "tinyvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
dependencies = [
 "tinyvec_macros",
]

[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

[[package]]
name = "todo-leptos"
version = "0.1.0"
dependencies = [
 "leptos",
]

[[package]]
name = "toml"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
 "serde",
 "serde_spanned",
 "toml_datetime",
 "toml_edit",
]

[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
 "serde",
]

[[package]]
name = "toml_edit"
version = "0.22.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
dependencies = [
 "indexmap",
 "serde",
 "serde_spanned",
 "toml_datetime",
 "winnow",
]

[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
 "pin-project-lite",
 "tracing-attributes",
 "tracing-core",
]

[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
 "once_cell",
]

[[package]]
name = "typed-builder"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add"
dependencies = [
 "typed-builder-macro",
]

[[package]]
name = "typed-builder-macro"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"

[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
dependencies = [
 "tinyvec",
]

[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"

[[package]]
name = "unicode-xid"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"

[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
 "form_urlencoded",
 "idna",
 "percent-encoding",
]

[[package]]
name = "utf8-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"

[[package]]
name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
dependencies = [
 "getrandom",
]

[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
 "same-file",
 "winapi-util",
]

[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
 "cfg-if",
 "once_cell",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
 "bumpalo",
 "log",
 "once_cell",
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
 "cfg-if",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"

[[package]]
name = "wasm-streams"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
 "futures-util",
 "js-sys",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
 "windows-sys",
]

[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
 "windows-targets",
]

[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
 "windows_aarch64_gnullvm",
 "windows_aarch64_msvc",
 "windows_i686_gnu",
 "windows_i686_gnullvm",
 "windows_i686_msvc",
 "windows_x86_64_gnu",
 "windows_x86_64_gnullvm",
 "windows_x86_64_msvc",
]

[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"

[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"

[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"

[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"

[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"

[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"

[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"

[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

[[package]]
name = "winnow"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
dependencies = [
 "memchr",
]

[[package]]
name = "xxhash-rust"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984"

[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[package]
name = "todo-leptos"
version = "0.1.0"
edition = "2021"

[dependencies]
leptos = { version = "0.6.14", features = ["csr"] }
# Todo App Leptos

A port of a [React Todo
App](https://www.digitalocean.com/community/tutorials/how-to-build-a-react-to-do-app-with-react-hooks)
to use the [Leptos](https://leptos.dev) framework.

This is an example project for the [Web
Frontend](https://rustprojectprimer.com/ecosystem/web-frontend.html) section of
the [Rust Project Primer](https://rustprojectprimer.com/) book.

## Prerequisites

You need two prerequisites to build this:

- Rust 1.80 with support for `wasm32-unknown-unknown` target
- Trunk build tool

### Setup

You can install Rust using [Rustup](https://rustup.rs):

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

You need to tell Rustup to add the WebAssembly target:

    rustup target add wasm32-unknown-unknown

You need to install [Trunk](https://trunkrs.dev) to build and serve it:

    cargo install trunk

## Running it

You can run it locally with Trunk:

    trunk serve

This will build and serve it, and watch the project for any changes. When you
edit the code, it will recompile and cause your browser to refresh.
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link data-trunk rel="rust" />
    <link data-trunk data-inline rel="css" href="src/style.css" />
    <title>Todo Leptos</title>
  </head>
  <body></body>
</html>
use leptos::*;

/// Represents a single Todo item.
#[derive(PartialEq, Clone)]
pub struct Todo {
    pub text: String,
    pub completed: bool,
}

impl Todo {
    /// Create a new todo item that is not completed.
    fn new<S: Into<String>>(text: S) -> Self {
        Self {
            text: text.into(),
            completed: false,
        }
    }

    fn complete(&mut self) {
        self.completed = !self.completed;
    }
}

/// Main application, consists of title, todo list and entry form.
#[component]
pub fn App() -> impl IntoView {
    // signal that holds all of the todo entries.
    let (todos, set_todos) = create_signal(vec![
        Todo::new("Buy milk"),
        Todo::new("Learn Rust"),
        Todo::new("Drink enough water"),
        Todo::new("Spend time with family"),
    ]);

    let submit = move |string| {
        let mut todos = todos.get().clone();
        todos.push(Todo::new(string));
        set_todos.set(todos);
    };

    view! {
        <div class="app">
            <div class="heading">
                "Todo List"
            </div>
            <div class="todo-list">
                {
                    move || {
                        todos.get().iter().enumerate().map(|(index, todo)| {
                            let complete = move |()| {
                                let mut todos = todos.get().clone();
                                todos[index].complete();
                                set_todos.set(todos);
                            };
                            let remove = move |()| {
                                let mut todos = todos.get().clone();
                                todos.remove(index);
                                set_todos.set(todos);
                            };
                            view! {
                                <TodoRow item={todo.clone()} complete remove />
                            }
                        }).collect_view()
                    }
                }
            </div>
            <div class="footer">
                <TodoForm submit />
            </div>
        </div>
    }
}

/// Contains the todo text and buttons to mark as complete and delete.
#[component]
pub fn TodoRow(
    item: Todo,
    #[prop(into)] complete: Callback<()>,
    #[prop(into)] remove: Callback<()>,
) -> impl IntoView {
    view! {
        <div class:todo=true class:completed=item.completed>
            <div class:text=true>
                {&item.text}
            </div>
            <div>
                <button class:complete=true on:click={move |_| complete.call(())}>{"✓"}</button>
                <button class:remove=true on:click={move |_| remove.call(())}>{"⨯"}</button>
            </div>
        </div>
    }
}

/// Entry form to add new todo item to list.
#[component]
pub fn TodoForm(#[prop(into)] submit: Callback<String>) -> impl IntoView {
    let (input, set_input) = create_signal(String::new());

    let submit_form = move |event: ev::SubmitEvent| {
        submit.call(input.get().clone());
        set_input.set(String::new());
        event.prevent_default();
    };

    view! {
        <form on:submit=submit_form>
            <input
                type="text"
                class="input"
                on:input=move |ev| set_input.set(event_target_value(&ev))
                prop:value=input
            />
        </form>
    }
}
use leptos::*;
use todo_leptos::App;

fn main() {
    mount_to_body(|| view! { <App /> })
}
body {
  background: #209cee;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}

.app {
  height: 100vh;
  padding: 10px;
  padding-top: 20px;
  padding-bottom: 20px;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.app .heading {
  padding: 5px;
  padding-top: 10px;
  padding-bottom: 10px;
  text-align: center;
  font-size: 20px;
  font-weight: 600;
  border-radius: 7px 7px 0px 0px;

  background: #e8e8e8;

  border: 1px solid #d8d8d8;
  border-bottom: 1px solid #b4b4b4;

  background: linear-gradient(to bottom,  #f6f6f6 0%,#dadada 100%);
}

.app .todo-list {
  padding: 5px;
  background: #ffffff;

  /*border-top: 1px solid #b4b4b4;*/
  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
}

.app .footer {
  padding: 5px;
  border-radius: 0px 0px 7px 7px;
  background: #ffffff;
  padding-bottom: 10px;

  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
  border-bottom: 1px solid #d8d8d8;
}

.app .footer form * {
  box-sizing: border-box;
  width: 100%;
}

.todo-list .todo {
  align-items: center;
  background: #f0f0f0;
  border-radius: 3px;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.15);
  display: flex;
  font-size: 14px;
  justify-content: space-between;
  margin-bottom: 6px;
  padding: 3px 10px;
}

.todo-list .todo button {
  width: 20px;
  height: 20px;
  font-size: 10px;
  background: #f9f9f9;
  border-radius: 50%;
  margin: 0 4px 0 0;
  opacity: 20%;
  text-align: center;

  background: #e9e9e9;
  border: 1px solid #e0e0e0;
}

.todo-list .todo button:hover {
  opacity: 100%;
  transition: 100ms;
}

.todo-list .todo button.complete {
  background: #27C93F;
  border: 1px solid #1DAD2B;
  transition: 100ms;
}

.todo-list .todo button.remove {
  background: #FF6057;
  border: 1px solid #E14640;
  transition: 100ms;
}

.todo.completed {
  text-decoration: line-through;
}

You can see this app in action here. You can see how Leptos represents properties using function parameters when defining components. You can also see how Leptos manages state using create_signal(), which returns a getter and a setter for the signal value. It further showcases how the view! macro is used to construct a tree of HTML elements and child components, and how Callback can be used to pass callbacks down to child components.

Dioxus

Dioxus is another frontend framework. Like Yew and Leptos, it also uses the component model, hooks and has a domain-specific language for describing the graph of HTML elements and components that a component renders into.

What makes Dioxus interesting is that it is easy to build Desktop and Mobile applications with it. The Dioxus team is also working on Blitz, a minimal web renderer for use with writing Desktop applications with Dioxus but without the need for a full browser engine. Dioxus also used to support rendering to the Terminal, but it appears as if the support for this has been dropped since 0.4.3.

The domain-specific language of Dioxus uses the rsx! macro and is distinct from the XML-style that the other frameworks use.

#![allow(unused)]
fn main() {
fn app() -> Element {
    rsx! {
        div { "Hello, world!" }
    }
}
}

Dioxus comes with its own CLI to use for initializing, building and serving Dioxus applications. I was not able to get it working with Trunk.

Example: Todo App

This is an example todo application written using Dioxus. It looks and functions similar to the example applications written with Yew and Leptos.

  • .gitignore
  • .gitlab-ci.yml
  • Cargo.lock
  • Cargo.toml
  • Dioxus.toml
  • README.md
  • assets/
    • style.css
  • src/
    • lib.rs
    • main.rs
# Generated by Cargo
# will have compiled files and executables
/target/
/dist/
/static/
/.dioxus/

# this file will generate by tailwind:
/assets/tailwind.css

# These are backup files generated by rustfmt
**/*.rs.bk
stages:
  - publish

# build application with trunk, use pinned versions for reproducible build.
pages:
  stage: publish
  image: rust:1.80
  before_script:
    - rustup target add wasm32-unknown-unknown
    - cargo install dioxus-cli
  script:
    - dx build --release
    - mv dist public
  artifacts:
    paths:
      - public
  only:
    - master
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
 "cfg-if",
 "once_cell",
 "version_check",
 "zerocopy",
]

[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"

[[package]]
name = "anymap2"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"

[[package]]
name = "async-channel"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
dependencies = [
 "concurrent-queue",
 "event-listener-strategy",
 "futures-core",
 "pin-project-lite",
]

[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"

[[package]]
name = "async-trait"
version = "0.1.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"

[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"

[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"

[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
 "serde",
]

[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
dependencies = [
 "serde",
]

[[package]]
name = "blocking"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
dependencies = [
 "async-channel",
 "async-task",
 "futures-io",
 "futures-lite",
 "piper",
]

[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"

[[package]]
name = "bytes"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"

[[package]]
name = "camino"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
dependencies = [
 "serde",
]

[[package]]
name = "cargo-platform"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
dependencies = [
 "serde",
]

[[package]]
name = "cargo_metadata"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
dependencies = [
 "camino",
 "cargo-platform",
 "semver",
 "serde",
 "serde_json",
 "thiserror",
]

[[package]]
name = "cfg-expr"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
 "smallvec",
]

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[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 = "concurrent-queue"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
 "crossbeam-utils",
]

[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
 "cfg-if",
 "wasm-bindgen",
]

[[package]]
name = "const_format"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b"
dependencies = [
 "const_format_proc_macros",
]

[[package]]
name = "const_format_proc_macros"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "constcat"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08"

[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
 "unicode-segmentation",
]

[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"

[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"

[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
 "darling_core",
 "darling_macro",
]

[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
 "fnv",
 "ident_case",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
 "darling_core",
 "quote",
 "syn",
]

[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
 "cfg-if",
 "hashbrown",
 "lock_api",
 "once_cell",
 "parking_lot_core",
]

[[package]]
name = "dioxus"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e7fe217b50d43b27528b0f24c89b411f742a3e7564d1cfbf85253f967954db"
dependencies = [
 "dioxus-config-macro",
 "dioxus-core",
 "dioxus-core-macro",
 "dioxus-fullstack",
 "dioxus-hooks",
 "dioxus-hot-reload",
 "dioxus-html",
 "dioxus-router",
 "dioxus-signals",
 "dioxus-web",
]

[[package]]
name = "dioxus-cli-config"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7dffc452ed91af6ef772b0d9a5899573f6785314e97c533733ec55413c01df3"
dependencies = [
 "once_cell",
 "serde",
 "serde_json",
 "tracing",
]

[[package]]
name = "dioxus-config-macro"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb1a1aa34cc04c1f7fcbb7a10791ba773cc02d834fe3ec1fe05647699f3b101f"
dependencies = [
 "proc-macro2",
 "quote",
]

[[package]]
name = "dioxus-core"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3730d2459ab66951cedf10b09eb84141a6eda7f403c28057cbe010495be156b7"
dependencies = [
 "futures-channel",
 "futures-util",
 "generational-box",
 "longest-increasing-subsequence",
 "rustc-hash",
 "serde",
 "slab",
 "slotmap",
 "tracing",
 "tracing-subscriber",
]

[[package]]
name = "dioxus-core-macro"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d9c0dfe0e6a46626fa716c4aa1d2ccb273441337909cfeacad5bb6fcfb947d2"
dependencies = [
 "constcat",
 "convert_case",
 "dioxus-rsx",
 "prettyplease",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "dioxus-debug-cell"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ea539174bb236e0e7dc9c12b19b88eae3cb574dedbd0252a2d43ea7e6de13e2"

[[package]]
name = "dioxus-fullstack"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b80f0ac18166302341164e681322e0385131c08a11c3cc1c51ee8df799ab0d3d"
dependencies = [
 "async-trait",
 "base64",
 "bytes",
 "ciborium",
 "dioxus-hot-reload",
 "dioxus-lib",
 "dioxus-web",
 "dioxus_server_macro",
 "futures-util",
 "once_cell",
 "serde",
 "serde_json",
 "server_fn",
 "tracing",
 "web-sys",
]

[[package]]
name = "dioxus-hooks"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8f9c661eea82295219d25555d5c0b597e74186b029038ceb5e3700ccbd4380"
dependencies = [
 "dioxus-core",
 "dioxus-debug-cell",
 "dioxus-signals",
 "futures-channel",
 "futures-util",
 "generational-box",
 "slab",
 "thiserror",
 "tracing",
]

[[package]]
name = "dioxus-hot-reload"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77d01246cb1b93437fb0bbd0dd11cfc66342d86b4311819e76654f2017ce1473"
dependencies = [
 "dioxus-core",
 "dioxus-html",
 "dioxus-rsx",
 "interprocess-docfix",
 "serde",
 "serde_json",
]

[[package]]
name = "dioxus-html"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f01a0826f179adad6ea8d6586746e8edde0c602cc86f4eb8e5df7a3b204c4018"
dependencies = [
 "async-trait",
 "dioxus-core",
 "dioxus-html-internal-macro",
 "enumset",
 "euclid",
 "futures-channel",
 "generational-box",
 "keyboard-types",
 "serde",
 "serde-value",
 "serde_json",
 "serde_repr",
 "tracing",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "dioxus-html-internal-macro"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b96f35a608d0ab8f4ca6f66ce1828354e4ebd41580b12454f490221a11da93c"
dependencies = [
 "convert_case",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "dioxus-interpreter-js"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351fad098c657d14f3ac2900362d2b86e83c22c4c620a404839e1ab628f3395b"
dependencies = [
 "js-sys",
 "md5",
 "sledgehammer_bindgen",
 "sledgehammer_utils",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "dioxus-lib"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bd39b2c41dd1915dcb91d914ea72d8b646f1f8995aaeff82816b862ec586ecd"
dependencies = [
 "dioxus-core",
 "dioxus-core-macro",
 "dioxus-hooks",
 "dioxus-html",
 "dioxus-rsx",
 "dioxus-signals",
]

[[package]]
name = "dioxus-logger"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fe09dc9773dc1f1bb0d38529203d6555d08f67aadca5cf955ac3d1a9e69880"
dependencies = [
 "console_error_panic_hook",
 "tracing",
 "tracing-subscriber",
 "tracing-wasm",
]

[[package]]
name = "dioxus-router"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c235c5dbeb528c0c2b0424763da812e7500df69b82eddac54db6f4975e065c5f"
dependencies = [
 "dioxus-cli-config",
 "dioxus-lib",
 "dioxus-router-macro",
 "gloo",
 "gloo-utils 0.1.7",
 "js-sys",
 "tracing",
 "url",
 "urlencoding",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "dioxus-router-macro"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7cd1c5137ba361f2150cdea6b3bc9ddda7b1af84b22c9ee6b5499bf43e1381"
dependencies = [
 "proc-macro2",
 "quote",
 "slab",
 "syn",
]

[[package]]
name = "dioxus-rsx"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c400bc8a779107d8f3a67b14375db07dbd2bc31163bf085a8e9097f36f7179"
dependencies = [
 "dioxus-core",
 "internment",
 "krates",
 "proc-macro2",
 "quote",
 "syn",
 "tracing",
]

[[package]]
name = "dioxus-signals"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3e224cd3d3713f159f0199fc088c292a0f4adb94996b48120157f6a8f8342d"
dependencies = [
 "dioxus-core",
 "futures-channel",
 "futures-util",
 "generational-box",
 "once_cell",
 "parking_lot",
 "rustc-hash",
 "tracing",
]

[[package]]
name = "dioxus-web"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0855ac81fcc9252a0863930a7a7cbb2504fc1b6efe893489c8d0e23aaeb2cb9"
dependencies = [
 "async-trait",
 "console_error_panic_hook",
 "dioxus-core",
 "dioxus-html",
 "dioxus-interpreter-js",
 "futures-channel",
 "futures-util",
 "generational-box",
 "js-sys",
 "rustc-hash",
 "serde",
 "serde-wasm-bindgen",
 "serde_json",
 "tracing",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "dioxus_server_macro"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5ef2cad17001c1155f019cb69adbacd620644566d78a77d0778807bb106a337"
dependencies = [
 "convert_case",
 "proc-macro2",
 "quote",
 "server_fn_macro",
 "syn",
]

[[package]]
name = "enumset"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293"
dependencies = [
 "enumset_derive",
]

[[package]]
name = "enumset_derive"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242"
dependencies = [
 "darling",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"

[[package]]
name = "euclid"
version = "0.22.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
dependencies = [
 "num-traits",
 "serde",
]

[[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.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
dependencies = [
 "event-listener",
 "pin-project-lite",
]

[[package]]
name = "fastrand"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"

[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"

[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
 "percent-encoding",
]

[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-executor",
 "futures-io",
 "futures-sink",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
 "futures-core",
 "futures-sink",
]

[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"

[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
 "futures-core",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"

[[package]]
name = "futures-lite"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
 "futures-core",
 "pin-project-lite",
]

[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"

[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"

[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-io",
 "futures-macro",
 "futures-sink",
 "futures-task",
 "memchr",
 "pin-project-lite",
 "pin-utils",
 "slab",
]

[[package]]
name = "generational-box"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "557cf2cbacd0504c6bf8c29f52f8071e0de1d9783346713dc6121d7fa1e5d0e0"
dependencies = [
 "parking_lot",
]

[[package]]
name = "gloo"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d"
dependencies = [
 "gloo-console",
 "gloo-dialogs",
 "gloo-events",
 "gloo-file",
 "gloo-history",
 "gloo-net 0.3.1",
 "gloo-render",
 "gloo-storage",
 "gloo-timers",
 "gloo-utils 0.1.7",
 "gloo-worker",
]

[[package]]
name = "gloo-console"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f"
dependencies = [
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-dialogs"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-events"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-file"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
dependencies = [
 "gloo-events",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-history"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f"
dependencies = [
 "gloo-events",
 "gloo-utils 0.1.7",
 "serde",
 "serde-wasm-bindgen",
 "serde_urlencoded",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-net"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-sink",
 "gloo-utils 0.1.7",
 "http 0.2.12",
 "js-sys",
 "pin-project",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-net"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-sink",
 "gloo-utils 0.2.0",
 "http 1.1.0",
 "js-sys",
 "pin-project",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "gloo-render"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764"
dependencies = [
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-storage"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480"
dependencies = [
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "serde_json",
 "thiserror",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "gloo-utils"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
dependencies = [
 "js-sys",
 "serde",
 "serde_json",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
dependencies = [
 "js-sys",
 "serde",
 "serde_json",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "gloo-worker"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a"
dependencies = [
 "anymap2",
 "bincode",
 "gloo-console",
 "gloo-utils 0.1.7",
 "js-sys",
 "serde",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[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.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
 "ahash",
 "allocator-api2",
]

[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
 "bytes",
 "fnv",
 "itoa",
]

[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
 "bytes",
 "fnv",
 "itoa",
]

[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"

[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
 "unicode-bidi",
 "unicode-normalization",
]

[[package]]
name = "indexmap"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
 "equivalent",
 "hashbrown",
]

[[package]]
name = "internment"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e8e537b529b8674e97e9fb82c10ff168a290ac3867a0295f112061ffbca1ef"
dependencies = [
 "hashbrown",
 "parking_lot",
]

[[package]]
name = "interprocess-docfix"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b84ee245c606aeb0841649a9288e3eae8c61b853a8cd5c0e14450e96d53d28f"
dependencies = [
 "blocking",
 "cfg-if",
 "futures-core",
 "futures-io",
 "intmap",
 "libc",
 "once_cell",
 "rustc_version",
 "spinning",
 "thiserror",
 "to_method",
 "winapi",
]

[[package]]
name = "intmap"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9"

[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"

[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
 "wasm-bindgen",
]

[[package]]
name = "keyboard-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
 "bitflags",
 "serde",
 "unicode-segmentation",
]

[[package]]
name = "krates"
version = "0.16.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcb3baf2360eb25ad31f0ada3add63927ada6db457791979b82ac199f835cb9"
dependencies = [
 "cargo-platform",
 "cargo_metadata",
 "cfg-expr",
 "petgraph",
 "semver",
]

[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"

[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"

[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
 "autocfg",
 "scopeguard",
]

[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"

[[package]]
name = "longest-increasing-subsequence"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"

[[package]]
name = "lru"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
dependencies = [
 "hashbrown",
]

[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"

[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"

[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
 "overload",
 "winapi",
]

[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
 "autocfg",
]

[[package]]
name = "once_cell"
version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe"

[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
dependencies = [
 "num-traits",
]

[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"

[[package]]
name = "parking"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"

[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
 "lock_api",
 "parking_lot_core",
]

[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
 "cfg-if",
 "libc",
 "redox_syscall",
 "smallvec",
 "windows-targets",
]

[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"

[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
 "fixedbitset",
 "indexmap",
]

[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
 "pin-project-internal",
]

[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"

[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "piper"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
 "atomic-waker",
 "fastrand",
 "futures-io",
]

[[package]]
name = "prettyplease"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
dependencies = [
 "proc-macro2",
 "syn",
]

[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "redox_syscall"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
dependencies = [
 "bitflags",
]

[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"

[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
 "semver",
]

[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"

[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"

[[package]]
name = "semver"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
dependencies = [
 "serde",
]

[[package]]
name = "send_wrapper"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
dependencies = [
 "futures-core",
]

[[package]]
name = "serde"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
 "serde_derive",
]

[[package]]
name = "serde-value"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
 "ordered-float",
 "serde",
]

[[package]]
name = "serde-wasm-bindgen"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
dependencies = [
 "js-sys",
 "serde",
 "wasm-bindgen",
]

[[package]]
name = "serde_derive"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "serde_json"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
dependencies = [
 "itoa",
 "memchr",
 "ryu",
 "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_repr"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
 "form_urlencoded",
 "itoa",
 "ryu",
 "serde",
]

[[package]]
name = "server_fn"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fae7a3038a32e5a34ba32c6c45eb4852f8affaf8b794ebfcd4b1099e2d62ebe"
dependencies = [
 "bytes",
 "const_format",
 "dashmap",
 "futures",
 "gloo-net 0.6.0",
 "http 1.1.0",
 "js-sys",
 "once_cell",
 "send_wrapper",
 "serde",
 "serde_json",
 "serde_qs",
 "server_fn_macro_default",
 "thiserror",
 "url",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "wasm-streams",
 "web-sys",
 "xxhash-rust",
]

[[package]]
name = "server_fn_macro"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faaaf648c6967aef78177c0610478abb5a3455811f401f3c62d10ae9bd3901a1"
dependencies = [
 "const_format",
 "convert_case",
 "proc-macro2",
 "quote",
 "syn",
 "xxhash-rust",
]

[[package]]
name = "server_fn_macro_default"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2aa8119b558a17992e0ac1fd07f080099564f24532858811ce04f742542440"
dependencies = [
 "server_fn_macro",
 "syn",
]

[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
 "lazy_static",
]

[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
 "autocfg",
]

[[package]]
name = "sledgehammer_bindgen"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcfaf791ff02f48f3518ce825d32cf419c13a43c1d8b1232f74ac89f339c46d2"
dependencies = [
 "sledgehammer_bindgen_macro",
 "wasm-bindgen",
]

[[package]]
name = "sledgehammer_bindgen_macro"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc90d3e8623d29a664cd8dba5078b600dd203444f00b9739f744e4c6e7aeaf2"
dependencies = [
 "quote",
 "syn",
]

[[package]]
name = "sledgehammer_utils"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f20798defa0e9d4eff9ca451c7f84774c7378a9c3b5a40112cfa2b3eadb97ae2"
dependencies = [
 "lru",
 "once_cell",
 "rustc-hash",
]

[[package]]
name = "slotmap"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
dependencies = [
 "serde",
 "version_check",
]

[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"

[[package]]
name = "spinning"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b"
dependencies = [
 "lock_api",
]

[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
 "thiserror-impl",
]

[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
 "cfg-if",
 "once_cell",
]

[[package]]
name = "tinyvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
dependencies = [
 "tinyvec_macros",
]

[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

[[package]]
name = "to_method"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"

[[package]]
name = "todo-dioxus"
version = "0.1.0"
dependencies = [
 "dioxus",
 "dioxus-logger",
]

[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
 "pin-project-lite",
 "tracing-attributes",
 "tracing-core",
]

[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
 "once_cell",
 "valuable",
]

[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
 "log",
 "once_cell",
 "tracing-core",
]

[[package]]
name = "tracing-subscriber"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
 "nu-ansi-term",
 "sharded-slab",
 "smallvec",
 "thread_local",
 "tracing-core",
 "tracing-log",
]

[[package]]
name = "tracing-wasm"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07"
dependencies = [
 "tracing",
 "tracing-subscriber",
 "wasm-bindgen",
]

[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"

[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"

[[package]]
name = "unicode-normalization"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
dependencies = [
 "tinyvec",
]

[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"

[[package]]
name = "unicode-xid"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"

[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
 "form_urlencoded",
 "idna",
 "percent-encoding",
]

[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"

[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"

[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
 "cfg-if",
 "once_cell",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
 "bumpalo",
 "log",
 "once_cell",
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
 "cfg-if",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"

[[package]]
name = "wasm-streams"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
 "futures-util",
 "js-sys",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
 "windows_aarch64_gnullvm",
 "windows_aarch64_msvc",
 "windows_i686_gnu",
 "windows_i686_gnullvm",
 "windows_i686_msvc",
 "windows_x86_64_gnu",
 "windows_x86_64_gnullvm",
 "windows_x86_64_msvc",
]

[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"

[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"

[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"

[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"

[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"

[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"

[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"

[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

[[package]]
name = "xxhash-rust"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984"

[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
 "zerocopy-derive",
]

[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]
[package]
name = "todo-dioxus"
version = "0.1.0"
authors = ["Patrick Elsen <pelsen@xfbs.net>"]
edition = "2021"

[dependencies]

dioxus = { version = "0.5", features = ["web"] }
dioxus-logger = "0.5.1"
[application]
name = "todo-dioxus"
default_platform = "web"
out_dir = "dist"
asset_dir = "assets"

[web.app]
title = "Todo App"

[web.watcher]
reload_html = true
watch_path = ["src", "assets"]

[web.resource]
style = ["style.css"]
script = []

[web.resource.dev]
script = []
# Development

Run the following command in the root of the project to start the Dioxus dev server:

```bash
dx serve --hot-reload
```

- Open the browser to http://localhost:8080
body {
  background: #209cee;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}

.app {
  height: 100vh;
  padding: 10px;
  padding-top: 20px;
  padding-bottom: 20px;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.app .heading {
  padding: 5px;
  padding-top: 10px;
  padding-bottom: 10px;
  text-align: center;
  font-size: 20px;
  font-weight: 600;
  border-radius: 7px 7px 0px 0px;

  background: #e8e8e8;

  border: 1px solid #d8d8d8;
  border-bottom: 1px solid #b4b4b4;

  background: linear-gradient(to bottom,  #f6f6f6 0%,#dadada 100%);
}

.app .todo-list {
  padding: 5px;
  background: #ffffff;

  /*border-top: 1px solid #b4b4b4;*/
  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
}

.app .footer {
  padding: 5px;
  border-radius: 0px 0px 7px 7px;
  background: #ffffff;
  padding-bottom: 10px;

  border-left: 1px solid #d8d8d8;
  border-right: 1px solid #d8d8d8;
  border-bottom: 1px solid #d8d8d8;
}

.app .footer form * {
  box-sizing: border-box;
  width: 100%;
}

.todo-list .todo {
  align-items: center;
  background: #f0f0f0;
  border-radius: 3px;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.15);
  display: flex;
  font-size: 14px;
  justify-content: space-between;
  margin-bottom: 6px;
  padding: 3px 10px;
}

.todo-list .todo button {
  width: 20px;
  height: 20px;
  font-size: 10px;
  background: #f9f9f9;
  border-radius: 50%;
  margin: 0 4px 0 0;
  opacity: 20%;
  text-align: center;

  background: #e9e9e9;
  border: 1px solid #e0e0e0;
}

.todo-list .todo button:hover {
  opacity: 100%;
  transition: 100ms;
}

.todo-list .todo button.complete {
  background: #27C93F;
  border: 1px solid #1DAD2B;
  transition: 100ms;
}

.todo-list .todo button.remove {
  background: #FF6057;
  border: 1px solid #E14640;
  transition: 100ms;
}

.todo.completed {
  text-decoration: line-through;
}
use dioxus::prelude::*;

/// Represents a single Todo item.
#[derive(PartialEq, Clone)]
pub struct Todo {
    pub text: String,
    pub completed: bool,
}

impl Todo {
    /// Create a new todo item that is not completed.
    fn new<S: Into<String>>(text: S) -> Self {
        Self {
            text: text.into(),
            completed: false,
        }
    }

    fn complete(&mut self) {
        self.completed = !self.completed;
    }
}

/// Main application, contains title, todo list and entry form.
#[component]
pub fn App() -> Element {
    // stores the todo list. this signal is handed down to children for modification.
    let todos = use_signal(|| {
        vec![
            Todo::new("Buy milk"),
            Todo::new("Learn Rust"),
            Todo::new("Drink enough water"),
            Todo::new("Spend time with family"),
        ]
    });

    rsx! {
        div { class: "app",
            div { class: "heading",
                {"Todo List"}
            }
            div { class: "todo-list",
                for (i, _) in todos().into_iter().enumerate() {
                    TodoRow {
                        key: "{i}",
                        index: i,
                        todos: todos.clone(),
                    }
                }
            }
            div { class: "footer",
                TodoForm {
                    todos: todos.clone(),
                }
            }
        }
    }
}

/// Single Todo row, includes buttons for marking as complete and deletion.
#[component]
pub fn TodoRow(index: usize, todos: Signal<Vec<Todo>>) -> Element {
    // current todo
    let todo = todos()[index].clone();

    rsx! {
        div {
            class: "todo",
            class: if todo.completed { "completed" },
            { todo.text }
            div {
                button {
                    class: "complete",
                    onclick: move |_| {
                        let mut cur = todos().clone();
                        cur[index].complete();
                        todos.set(cur)
                    },
                },
                button {
                    class: "remove",
                    onclick: move |_| {
                        let mut cur = todos().clone();
                        cur.remove(index);
                        todos.set(cur);
                    },
                }
            }
        }
    }
}

/// Entry form to add new todo.
#[component]
pub fn TodoForm(todos: Signal<Vec<Todo>>) -> Element {
    let mut value = use_signal(String::new);
    rsx! {
        form {
            onsubmit: move |_| {
                let mut cur = todos().clone();
                cur.push(Todo::new(value()));
                todos.set(cur);
                value.set(String::new());
            },
            input {
                r#type: "text",
                class: "input",
                value: "{value}",
                oninput: move |event| value.set(event.value())
            }
        }
    }
}
use dioxus::prelude::*;
use dioxus_logger::tracing::{info, Level};
use todo_dioxus::App;

fn main() {
    dioxus_logger::init(Level::INFO).expect("failed to init logger");
    info!("starting app");
    launch(App);
}

You can see this application in action here. Note that this implementation is slightly different from the Yew and Leptos implementations, because here we pass the signal that contains the list of todo items directly down to the child components and have them change it, rather than using callbacks to update it.

Trunk

Trunk is is a build tool for Rust web frontends. It handles some of the nitty-gritty in getting a WebAssembly blog runnable in a browser. You can install it by running:

cargo install trunk --locked

If you have not done so already, you also need to enable compiling to WebAssembly. If you installed Rust using rustup, you can do this easily:

rustup target add wasm32-unknown-unknown

Some interesting points is that it has some integration with external tooling, such as wasm-opt to optimize and slim down WebAssembly binaries, and Tailwind CSS for generating CSS styles.

Setup

To get started with Trunk, you need to create an index.html file. This is used by Trunk as a template, and it contains some metadata for Trunk that tells it what assets you want to include in the build.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8"/>
        <title>Hello World</title>
        <link data-trunk rel="rust" data-wasm-opt="z">
    </head>
    <body>
    </body>
</html>

Info

The data-wasm-opt property here tells Trunk to call wasm-opt over the resulting WebAssembly output when doing a release build.

Assets

Most of the content of this does not matter. Trunk only cares about any tags that have the data-trunk property. In this example, we have only one entry that Trunk processes, which is the rel=rust one. This tells Trunk to link the current crate into this site, and run wasm-opt on it to optimize the WebAssembly.

You can include some CSS in the output of your site like this:

<link data-trunk rel="rust" data-wasm-opt="z">

If you want to use Tailwind CSS, you can use this to tell Trunk to run it and include the generated CSS file in your site:

<link data-trunk rel="tailwind-css" href="src/tailwind.css">

See the Trunk Assets documentation page for a full list of the types of assets that Trunk supports including in your application. It can run the SASS preprocessor, copy static assets such as images, inline content, copy files or directory,

Configuration

Trunk also has an additional configuration file that you can use to configure how it works, Trunk.toml. In this file, you can configure some hooks, which are run before, during or after the build for custom steps, set up proxying for the Trunk development server, or change where and how your site is built.

Request Forwarding

A common pattern for developing is to use trunk serve to build and serve your frontend, and to have it talk to your backend via API requests. To make it easier to route the API requests to your backend, you can tell Trunk to forward proxy requests matching a specific route to another service.

[[proxy]]
rewrite = "/api/v1/"
backend = "http://localhost:9000/"

Example: Trunk and Tailwind CSS

Example: Proxying API requests to backend

Reading

Are We Web Yet: Web Frameworks on Are We Web Yet

List of frontend web frameworks for Rust along with some statistics indicating popularity. Good for discovery of new and rising frameworks or to explore all the different ideas.

Rust Web Framework Comparison by Markus Kohlhase

Overview of different Rust frontend and backend frameworks. Unfortunately, it marks some frameworks that are still heavily used as outdated, so take that with a grain of salt.

Full-stack Rust: A complete tutorial with examples by Mario Zupan

Tutorial showing how to build a full-stack Rust web application using Yew, Tokio, Postgres, and Warp. Good tutorial to see how everything fits together, unfortunately it is a bit older and uses an outdated version of Yew that is pre-functional components. But it is still a good article to get a feeling for how a full-stack Rust application fits together.

Full Stack Rust with Leptos

Rust and WebAssembly Book

Book that explains how to use Rust to target WebAssembly. Has some good low-level information, such as how to debug and profile WebAssembly applications, keeping code size small, interoperation with JavaScript.

A Rust web server / frontend setup like it’s 2022 (with axum and yew) by Robert Krahn

Shows how to setup a full-stack Rust web application with Yew and Axum from scratch.

Using Dioxus with Rust to build performant single-page apps by Eze Sunday

Eze shows how to use Dioxus to implement a todo application. Uses an older version of Dioxus, the interface has since changed.