Layout Components

First up, we're going to craft some general layout components for our app. This is a nice, gentle introduction to creating components, and we'll also get some reusable pieces out of it. We're going to create:

  • Header component
  • Footer component
  • We'll also tweak the App component to incorporate these new components

Components Folder

Time to get our code all nice and organized! We're going to make a components folder in our src directory. This is where we'll store all of our components. This way, we can easily import them into our main.rs file. Neat, right?

If you want to get a deeper understanding of how to structure your code within a Rust project, the Rust Lang book has a fantastic section on it called Managing Growing Projects with Packages, Crates, and Modules. Definitely worth checking out!

Here's what our new structure will look like:

└── src                # Source code
    ├── components     # Components folder
    │   ├── mod.rs     # Components module
    │   ├── footer.rs  # Footer component
    │   └── header.rs  # Header component

And let's take a peek at what our mod.rs file should look like:

#![allow(unused)]
fn main() {
mod footer;
mod header;

pub use footer::Footer;
pub use header::Header;
}

We've got our mod.rs pulling double duty here. First, it's declaring our footer and header modules. Then, it's making Footer and Header available for other modules to use. This sets us up nicely for using these components in our main.rs file.

Header Component

Alright, let's start with the Header component. For now, we're keeping it simple, just displaying our app's title and a logo.

Whenever you're building a new component or working in our main.rs file, remember to import dioxus::prelude::*. It gives you access to all the macros and functions you need.

Tailwind CSS

You can adjust the Tailwind classes to suit your style.

front/src/components/header.rs

#![allow(unused)]
fn main() {
use dioxus::prelude::*;

pub fn Header(cx: Scope) -> Element {
    cx.render(rsx!(
        header {
            class: "sticky top-0 z-10 text-gray-400 bg-blue-300 body-font shadow-md",
            div { class: "container mx-auto flex flex-wrap p-0 flex-col md:flex-row justify-between items-center",
                a {
                    class: "flex title-font font-medium items-center text-teal-950 mb-4 md:mb-0",
                    img {
                        class: "bg-transparent p-2 animate-jump",
                        alt: "ferris",
                        src: "ferris.png",
                        "loading": "lazy"
                    }
                    span { class: "ml-3 text-2xl", "Rusty films"}
                }
            }
        }
    ))
}
}

Next up, we're going to build the Footer component. This one's pretty straightforward – we're just going to stick a couple of images at the bottom of our app.

front/src/components/footer.rs

#![allow(unused)]
fn main() {
use dioxus::prelude::*;

pub fn Footer(cx: Scope) -> Element {
    cx.render(rsx!(
        footer {
            class: "bg-blue-200 w-full h-16 p-2 box-border gap-6 flex flex-row justify-center items-center text-teal-950",
            a {
                class: "w-auto h-full",
                href: "https://www.devbcn.com/",
                target: "_blank",
                img {
                    class: "h-full w-auto",
                    alt: "DevBcn",
                    src: "devbcn.png",
                    "loading": "lazy"
                }
            }
            svg {
                fill: "none",
                view_box: "0 0 24 24",
                stroke_width: "1.5",
                stroke: "currentColor",
                class: "w-6 h-6",
                path {
                    stroke_linecap: "round",
                    stroke_linejoin: "round",
                    d: "M6 18L18 6M6 6l12 12"
                }
            }
            a {
                class: "w-auto h-full",
                href: "https://www.meetup.com/es-ES/bcnrust/",
                target: "_blank",
                img {
                    class: "h-full w-auto",
                    alt: "BcnRust",
                    src: "bcnrust.png",
                    "loading": "lazy"
                }
            }
        }
    ))
}
}

Just like we did with the Header component, remember to import dioxus::prelude::* to have access to all the macros and functions we need. And feel free to change up the Tailwind classes to fit your design.

Now, we've got a Header and Footer ready to roll. Next, let's update our App component to use these new elements.

front/src/main.rs

#![allow(non_snake_case)]
// Import the Dioxus prelude to gain access to the `rsx!` macro and the `Scope` and `Element` types.
+mod components;

+use components::{Footer, Header};
use dioxus::prelude::*;


fn main() {
    // Launch the web application using the App component as the root.
    dioxus_web::launch(App);
}

// Define a component that renders a div with the text "Hello, world!"
fn App(cx: Scope) -> Element {
    cx.render(rsx! {
-       div {
-           "Hello, world!"
-       }
+       main {
+           class: "relative z-0 bg-blue-100 w-screen h-auto min-h-screen flex flex-col justify-start items-stretch",
+           Header {}
+           section {
+               class: "md:container md:mx-auto md:py-8 flex-1",
+           }
+           Footer {}
+       }
    })
}