0

Here is a simple bulma css navbar in yew. My question is howto add .is-active class to 'navbar-item' when navigate by click Route link?

It looks like I have to use some stateful utils here. But I can't intercept the onclick event in Route Link.

use yew::prelude::*;
use yew_router::prelude::*;

use crate::routes::app_routes::AppRoutes;

#[function_component]
pub fn Nav() -> Html {
    let navbar_active = use_state_eq(|| false);

    let toggle_navbar = {
        let navbar_active = navbar_active.clone();

        Callback::from(move |_| {
            navbar_active.set(!*navbar_active);
        })
    };

    let active_class = if !*navbar_active { "is-active" } else { "" };

    html! {
        <nav class="navbar is-primary" role="navigation" aria-label="main navigation">
            <div class="navbar-brand">
                <h1 class="navbar-item is-size-3">{ "UVW" }</h1>

                <button class={classes!("navbar-burger", "burger", active_class)}
                    aria-label="menu" aria-expanded="false"
                    onclick={toggle_navbar}
                >
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                </button>
            </div>
            <div class={classes!("navbar-menu", active_class)}>
                <div class="navbar-start">
                    <Link<AppRoutes> classes={classes!("navbar-item")} to={AppRoutes::Home}>
                        { "Home" }
                    </Link<AppRoutes>>

                    <Link<AppRoutes> classes={classes!("navbar-item")} to={AppRoutes::About}>
                        { "About" }
                    </Link<AppRoutes>>

                    <div class="navbar-item has-dropdown is-hoverable">
                        <div class="navbar-link">
                            { "More" }
                        </div>
                        <div class="navbar-dropdown">
                            <Link<AppRoutes> classes={classes!("navbar-item")} to={AppRoutes::Home}>
                                { "DropDown1" }
                            </Link<AppRoutes>>
                            <Link<AppRoutes> classes={classes!("navbar-item")} to={AppRoutes::Home}>
                                { "DropDown2" }
                            </Link<AppRoutes>>
                            <Link<AppRoutes> classes={classes!("navbar-item")} to={AppRoutes::Home}>
                                { "DropDown3" }
                            </Link<AppRoutes>>
                        </div>
                    </div>
                </div>
            </div>
        </nav>
    }
}
tempbottle
  • 33
  • 4

1 Answers1

1

I haven't found any "official" way to do this. But a possible solution is to hook into the route with use_route and just match against it.

I simplified this by creating my own fn component that checks if it is the current route.

#[derive(Properties, PartialEq)]
pub struct Props {
    pub children: Children,
    pub to: Route,
}
#[function_component(RouteLink)]
fn route_link(props: &Props) -> Html {
    let route = use_route::<Route>().unwrap_or_default();
    let classes = if route == props.to {
        classes!("text-gray-900")
    } else {
        classes!("text-gray-400")
    };

    html! {
        <Link<Route> classes={classes} to={props.to.clone()}>{for props.children.iter() }</Link<Route>>
    }
}

cengen
  • 61
  • 1
  • 3