Files
certifai/src/components/sidebar.rs
Sharang Parnerkar a588be306a
All checks were successful
CI / Format (push) Successful in 6m30s
CI / Clippy (push) Successful in 2m25s
CI / Security Audit (push) Successful in 1m53s
CI / Tests (push) Successful in 2m50s
CI / Deploy (push) Successful in 4s
feat(dash): improved frontend dashboard (#6)
Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com>
Reviewed-on: #6
2026-02-19 11:52:41 +00:00

157 lines
5.2 KiB
Rust

use dioxus::prelude::*;
use dioxus_free_icons::icons::bs_icons::{
BsBoxArrowRight, BsBuilding, BsChatDots, BsCloudArrowUp, BsCodeSlash, BsCollection, BsGithub,
BsGrid, BsHouseDoor, BsPuzzle,
};
use dioxus_free_icons::Icon;
use crate::Route;
/// Navigation entry for the sidebar.
struct NavItem {
label: &'static str,
route: Route,
/// Bootstrap icon element rendered beside the label.
icon: Element,
}
/// Fixed left sidebar containing header, navigation, logout, and footer.
///
/// # Arguments
///
/// * `email` - Email address displayed beneath the avatar placeholder.
/// * `avatar_url` - URL for the avatar image (unused placeholder for now).
#[component]
pub fn Sidebar(email: String, avatar_url: String) -> Element {
let nav_items: Vec<NavItem> = vec![
NavItem {
label: "Dashboard",
route: Route::DashboardPage {},
icon: rsx! { Icon { icon: BsHouseDoor, width: 18, height: 18 } },
},
NavItem {
label: "Providers",
route: Route::ProvidersPage {},
icon: rsx! { Icon { icon: BsCloudArrowUp, width: 18, height: 18 } },
},
NavItem {
label: "Chat",
route: Route::ChatPage {},
icon: rsx! { Icon { icon: BsChatDots, width: 18, height: 18 } },
},
NavItem {
label: "Tools",
route: Route::ToolsPage {},
icon: rsx! { Icon { icon: BsPuzzle, width: 18, height: 18 } },
},
NavItem {
label: "Knowledge Base",
route: Route::KnowledgePage {},
icon: rsx! { Icon { icon: BsCollection, width: 18, height: 18 } },
},
NavItem {
label: "Developer",
route: Route::AgentsPage {},
icon: rsx! { Icon { icon: BsCodeSlash, width: 18, height: 18 } },
},
NavItem {
label: "Organization",
route: Route::OrgPricingPage {},
icon: rsx! { Icon { icon: BsBuilding, width: 18, height: 18 } },
},
];
// Determine current path to highlight the active nav link.
let current_route = use_route::<Route>();
rsx! {
aside { class: "sidebar",
SidebarHeader { email: email.clone(), avatar_url }
nav { class: "sidebar-nav",
for item in nav_items {
{
// Active detection for nested routes: highlight the parent nav
// item when any child route within the nested shell is active.
let is_active = match &current_route {
Route::AgentsPage {} | Route::FlowPage {} | Route::AnalyticsPage {} => {
item.label == "Developer"
}
Route::OrgPricingPage {} | Route::OrgDashboardPage {} => {
item.label == "Organization"
}
_ => item.route == current_route,
};
let cls = if is_active { "sidebar-link active" } else { "sidebar-link" };
rsx! {
Link { to: item.route, class: cls,
{item.icon}
span { "{item.label}" }
}
}
}
}
}
div { class: "sidebar-logout",
Link {
to: NavigationTarget::<Route>::External("/auth/logout".into()),
class: "sidebar-link logout-btn",
Icon { icon: BsBoxArrowRight, width: 18, height: 18 }
span { "Logout" }
}
}
SidebarFooter {}
}
}
}
/// Avatar circle and email display at the top of the sidebar.
///
/// # Arguments
///
/// * `email` - User email to display.
/// * `avatar_url` - Placeholder for future avatar image URL.
#[component]
fn SidebarHeader(email: String, avatar_url: String) -> Element {
// Extract initials from email (first two chars before @).
let initials: String = email
.split('@')
.next()
.unwrap_or("U")
.chars()
.take(2)
.collect::<String>()
.to_uppercase();
rsx! {
div { class: "sidebar-header",
div { class: "avatar-circle",
span { class: "avatar-initials", "{initials}" }
}
p { class: "sidebar-email", "{email}" }
}
}
}
/// Footer section with version string and placeholder social links.
#[component]
fn SidebarFooter() -> Element {
let version = env!("CARGO_PKG_VERSION");
rsx! {
footer { class: "sidebar-footer",
div { class: "sidebar-social",
a { href: "#", class: "social-link", title: "GitHub",
Icon { icon: BsGithub, width: 16, height: 16 }
}
a { href: "#", class: "social-link", title: "Impressum",
Icon { icon: BsGrid, width: 16, height: 16 }
}
}
p { class: "sidebar-version", "v{version}" }
}
}
}