1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::*;

/// Properties for NavLink component
#[derive(Properties, PartialEq)]
pub struct NavLinkProps {
    #[prop_or_default]
    pub to: String,
    #[prop_or_default]
    pub children: Children,
    #[prop_or_default]
    pub class: String,
}

/// Navigation link component
///
/// Use this when you want to display a navigation button or link
/// Make sure the `to` property starts with a forward slash `/`
///
/// example to display a link
/// ```rust
/// use webui::*;
///
/// fn component() -> Html {
///     html! {
///         <NavLink to="/some-page">{"A Link"}</NavLink>
///     }
/// }
/// ```
///
/// example to display a button
/// ```rust
/// use webui::*;
///
/// fn component() -> Html {
///     html! {
///         <NavLink to="/some-page">{"A Link"}</NavLink>
///     }
/// }
/// ```
pub struct NavLink {
    app_state_agent: Box<dyn Bridge<AppStateAgent>>,
    app_drawer_agent: Dispatcher<AppDrawerAgent>,
    is_active: bool,
}

impl Component for NavLink {
    type Message = AppStateReceiverMessage;
    type Properties = NavLinkProps;

    fn create(ctx: &Context<Self>) -> Self {
        Self {
            app_state_agent: AppStateAgent::bridge(
                ctx.link()
                    .callback(AppStateReceiverMessage::AppStateMessage),
            ),
            app_drawer_agent: AppDrawerAgent::dispatcher(),
            is_active: interop::is_current_path(ctx.props().to.to_owned()),
        }
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            AppStateReceiverMessage::AppStateMessage(request) => {
                let to_send = request.clone();
                match request {
                    AppStateRequest::PathUpdate(path) => {
                        if ctx.props().to.to_lowercase() == path.to_lowercase() {
                            if self.is_active {
                                return false;
                            }
                            self.is_active = true;
                            self.app_state_agent.send(to_send.to_owned());
                            self.app_drawer_agent
                                .send(AppDrawerRequest::ToggleTopDrawer(None));
                            self.app_drawer_agent
                                .send(AppDrawerRequest::ToggleRightDrawer(None));
                            self.app_drawer_agent
                                .send(AppDrawerRequest::ToggleBottomDrawer(None));
                            self.app_drawer_agent
                                .send(AppDrawerRequest::ToggleLeftDrawer(None));
                            return true;
                        }
                        if self.is_active {
                            self.is_active = false;
                            return true;
                        }
                        return false;
                    }
                }
            }
            AppStateReceiverMessage::None => (),
        }
        false
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        let props = ctx.props();
        let classes = &mut Classes::new();
        classes.push("navlink");

        if !props.class.is_empty() {
            classes.push(&props.class);
        }

        if self.is_active {
            classes.push("active".to_owned());
        }

        let onclick = {
            let path = props.to.to_owned();
            ctx.link().callback(move |_| {
                AppStateReceiverMessage::AppStateMessage(AppStateRequest::PathUpdate(
                    path.to_string(),
                ))
            })
        };

        html! {
            <a href={props.to.to_string()} class={classes.clone()} onclick={onclick}>
                { for props.children.iter() }
            </a>
        }
    }
}