Skip to main content

freya_components/
sidebar.rs

1use dioxus::prelude::*;
2use freya_core::platform::CursorIcon;
3use freya_elements as dioxus_elements;
4use freya_hooks::{
5    use_activable_route,
6    use_applied_theme,
7    use_platform,
8    SidebarItemTheme,
9    SidebarItemThemeWith,
10    SidebarTheme,
11    SidebarThemeWith,
12};
13
14use crate::{
15    ButtonStatus,
16    ScrollView,
17};
18
19#[allow(non_snake_case)]
20#[component]
21pub fn Sidebar(
22    /// Theme override.
23    theme: Option<SidebarThemeWith>,
24    /// This is what is rendered next to the sidebar.
25    children: Element,
26    /// This is what is rendered in the sidebar.
27    sidebar: Element,
28    /// Width of the sidebar.
29    #[props(default = "180".to_string())]
30    width: String,
31) -> Element {
32    let SidebarTheme {
33        spacing,
34        font_theme,
35        background,
36    } = use_applied_theme!(&theme, sidebar);
37
38    rsx!(
39        rect {
40            width: "100%",
41            height: "100%",
42            direction: "horizontal",
43            rect {
44                overflow: "clip",
45                width,
46                height: "100%",
47                background: "{background}",
48                color: "{font_theme.color}",
49                shadow: "2 0 5 0 rgb(0, 0, 0, 30)",
50                ScrollView {
51                    padding: "8",
52                    spacing,
53                    {sidebar}
54                }
55            }
56            rect {
57                overflow: "clip",
58                width: "fill",
59                height: "100%",
60                color: "{font_theme.color}",
61                {children}
62            }
63        }
64    )
65}
66
67#[allow(non_snake_case)]
68#[component]
69pub fn SidebarItem(
70    /// Theme override.
71    theme: Option<SidebarItemThemeWith>,
72    /// Inner content for the SidebarItem.
73    children: Element,
74    /// Optionally handle the `onpress` event in the SidebarItem.
75    onpress: Option<EventHandler<()>>,
76) -> Element {
77    let SidebarItemTheme {
78        margin,
79        hover_background,
80        background,
81        font_theme,
82    } = use_applied_theme!(&theme, sidebar_item);
83    let mut status = use_signal(ButtonStatus::default);
84    let platform = use_platform();
85    let is_active = use_activable_route();
86
87    use_drop(move || {
88        if *status.read() == ButtonStatus::Hovering {
89            platform.set_cursor(CursorIcon::default());
90        }
91    });
92
93    let onclick = move |_| {
94        if let Some(onpress) = &onpress {
95            onpress.call(());
96        }
97    };
98
99    let onmouseenter = move |_| {
100        platform.set_cursor(CursorIcon::Pointer);
101        status.set(ButtonStatus::Hovering);
102    };
103
104    let onmouseleave = move |_| {
105        platform.set_cursor(CursorIcon::default());
106        status.set(ButtonStatus::default());
107    };
108
109    let background = match *status.read() {
110        _ if is_active => hover_background,
111        ButtonStatus::Hovering => hover_background,
112        ButtonStatus::Idle => background,
113    };
114
115    rsx!(
116        rect {
117            overflow: "clip",
118            margin: "{margin}",
119            onclick,
120            onmouseenter,
121            onmouseleave,
122            width: "100%",
123            height: "auto",
124            color: "{font_theme.color}",
125            corner_radius: "99",
126            padding: "8 10",
127            background: "{background}",
128            {children}
129        }
130    )
131}