From 159202a7af03c11d11b3f2e25b0d1e9fd7f80a2b Mon Sep 17 00:00:00 2001 From: schn33fuchs Date: Sun, 7 Jun 2026 12:11:32 +0200 Subject: [PATCH] Sidebar improvement It now works on mobile --- frontend/src/lib.rs | 40 ++++- frontend/src/pages/sidebar.rs | 151 ++++++++++++------- frontend/src/styles/components/_sidebar.scss | 149 +++++++++++++++--- frontend/src/styles/main.scss | 24 ++- 4 files changed, 283 insertions(+), 81 deletions(-) diff --git a/frontend/src/lib.rs b/frontend/src/lib.rs index 9300489..30772e4 100644 --- a/frontend/src/lib.rs +++ b/frontend/src/lib.rs @@ -90,9 +90,46 @@ pub struct SidebarShellProps { /// ``` #[component(SidebarShell)] fn sidebar_shell(props: &SidebarShellProps) -> Html { + let route = use_route::(); + let mobile_sidebar_open = use_state(|| false); + + // Close mobile sidebar automatically on any route transition + { + let mobile_sidebar_open = mobile_sidebar_open.clone(); + use_effect_with(route, move |_| { + mobile_sidebar_open.set(false); + || () + }); + } + + let on_open = { + let mobile_sidebar_open = mobile_sidebar_open.clone(); + Callback::from(move |_: MouseEvent| mobile_sidebar_open.set(true)) + }; + + let on_close = { + let mobile_sidebar_open = mobile_sidebar_open.clone(); + Callback::from(move |_: ()| mobile_sidebar_open.set(false)) + }; + + let on_close_click = { + let on_close = on_close.clone(); + Callback::from(move |_: MouseEvent| on_close.emit(())) + }; + html! {
- + + +
+ +
{ for props.children.iter() }
@@ -100,6 +137,7 @@ fn sidebar_shell(props: &SidebarShellProps) -> Html { } } + /// Props for the AdminCheckWrapper component. #[derive(Properties, PartialEq)] pub struct AdminCheckWrapperProps { diff --git a/frontend/src/pages/sidebar.rs b/frontend/src/pages/sidebar.rs index f37035f..e3380e1 100644 --- a/frontend/src/pages/sidebar.rs +++ b/frontend/src/pages/sidebar.rs @@ -133,7 +133,7 @@ pub fn sidebar_state_provider(props: &SidebarProps) -> Html { Callback::from(move |v: bool| { state.set(SidebarExpandState { ticket_open: v, - users_open: (*state).users_open, + users_open: state.users_open, }) }) }; @@ -141,10 +141,10 @@ pub fn sidebar_state_provider(props: &SidebarProps) -> Html { let toggle_tickets = { let state = state.clone(); Callback::from(move |_| { - let current = (*state).ticket_open; + let current = state.ticket_open; state.set(SidebarExpandState { ticket_open: !current, - users_open: (*state).users_open, + users_open: state.users_open, }); }) }; @@ -153,7 +153,7 @@ pub fn sidebar_state_provider(props: &SidebarProps) -> Html { let state = state.clone(); Callback::from(move |v: bool| { state.set(SidebarExpandState { - ticket_open: (*state).ticket_open, + ticket_open: state.ticket_open, users_open: v, }) }) @@ -162,9 +162,9 @@ pub fn sidebar_state_provider(props: &SidebarProps) -> Html { let toggle_users = { let state = state.clone(); Callback::from(move |_| { - let current = (*state).users_open; + let current = state.users_open; state.set(SidebarExpandState { - ticket_open: (*state).ticket_open, + ticket_open: state.ticket_open, users_open: !current, }); }) @@ -319,6 +319,11 @@ pub fn users_menu() -> Html { /// and administrative status. It fetches the current user's details via `/api/users/current` /// to determine what menu items to display. /// +/// # Mobile Support +/// On small screens: +/// - Slides into view from the left when `props.is_open` is `true`. +/// - Renders a close button (`✕`) in the header that emits `props.on_close`. +/// /// # Structure /// - Wraps its content in a [`SidebarStateProvider`] to allow nested menus to manage their state. /// - Contains a navigation (`