diff --git a/services/frontend-leptos/frontend/src/app.rs b/services/frontend-leptos/frontend/src/app.rs index 050f0a2..cbfa661 100644 --- a/services/frontend-leptos/frontend/src/app.rs +++ b/services/frontend-leptos/frontend/src/app.rs @@ -1,5 +1,11 @@ use leptos::prelude::*; +// Temporary stub until Task 4 creates the real UiContext +#[derive(Clone)] +pub struct UiContext { + pub active_tab: RwSignal, +} + #[component] pub fn App() -> impl IntoView { view! { diff --git a/services/frontend-leptos/frontend/src/layout/dashboard_layout.rs b/services/frontend-leptos/frontend/src/layout/dashboard_layout.rs new file mode 100644 index 0000000..64a7005 --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/dashboard_layout.rs @@ -0,0 +1,28 @@ +// services/frontend-leptos/frontend/src/layout/dashboard_layout.rs +use leptos::children::Children; +use leptos::prelude::*; +use super::header::Header; +use super::mobile_tab_bar::MobileTabBar; +use super::sidebar::Sidebar; +use super::tab_strip::TabStrip; + +#[component] +pub fn DashboardLayout( + children: Children, +) -> impl IntoView { + view! { +
+
+
+ +
+ +
+ {children()} +
+
+
+ +
+ } +} diff --git a/services/frontend-leptos/frontend/src/layout/header.rs b/services/frontend-leptos/frontend/src/layout/header.rs new file mode 100644 index 0000000..4b8a95e --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/header.rs @@ -0,0 +1,56 @@ +// services/frontend-leptos/frontend/src/layout/header.rs +use leptos::prelude::*; +use crate::ws::context::WsContext; +use crate::ws::socket::WsStatus; + +#[component] +pub fn Header() -> impl IntoView { + let ws = use_context::().expect("WsContext not provided"); + let ws_status = ws.status; + + let indicator_text_memo = create_memo(move |_| match ws_status.get() { + WsStatus::Connected => "Online", + WsStatus::Connecting => "Menghubungkan...", + WsStatus::Disconnected => "Offline", + WsStatus::Error(_) => "Error", + }); + let indicator_color_memo = create_memo(move |_| match ws_status.get() { + WsStatus::Connected => "var(--color-success)", + WsStatus::Connecting => "var(--color-warning)", + WsStatus::Disconnected => "var(--text-tertiary)", + WsStatus::Error(_) => "var(--color-error)", + }); + + view! { +
+
+ + "IMPHNEN" + + + "Guild Watcher" + +
+ +
+
+ + {move || indicator_text_memo.get()} +
+
+
+ } +} diff --git a/services/frontend-leptos/frontend/src/layout/mobile_tab_bar.rs b/services/frontend-leptos/frontend/src/layout/mobile_tab_bar.rs new file mode 100644 index 0000000..9de8dcd --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/mobile_tab_bar.rs @@ -0,0 +1,63 @@ +// services/frontend-leptos/frontend/src/layout/mobile_tab_bar.rs +use leptos::prelude::*; +use shared_types::ui_state::Tab; +use crate::app::UiContext; + +#[component] +pub fn MobileTabBar() -> impl IntoView { + let ui = use_context::().expect("UiContext not provided"); + + view! { +
+ + + +
+ } +} + +#[component] +fn MobileTabItem( + icon: &'static str, + label: &'static str, + tab: Tab, + ui: UiContext, +) -> impl IntoView { + let tab_active = tab.clone(); + let tab_click = tab; + view! { + + } +} diff --git a/services/frontend-leptos/frontend/src/layout/mod.rs b/services/frontend-leptos/frontend/src/layout/mod.rs new file mode 100644 index 0000000..63c4a67 --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/mod.rs @@ -0,0 +1,6 @@ +// services/frontend-leptos/frontend/src/layout/mod.rs +pub mod dashboard_layout; +pub mod header; +pub mod mobile_tab_bar; +pub mod sidebar; +pub mod tab_strip; diff --git a/services/frontend-leptos/frontend/src/layout/sidebar.rs b/services/frontend-leptos/frontend/src/layout/sidebar.rs new file mode 100644 index 0000000..764e569 --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/sidebar.rs @@ -0,0 +1,71 @@ +// services/frontend-leptos/frontend/src/layout/sidebar.rs +use leptos::prelude::*; +use shared_types::ui_state::Tab; +use crate::app::UiContext; + +#[component] +pub fn Sidebar() -> impl IntoView { + let ui = use_context::().expect("UiContext not provided"); + let (collapsed, _set_collapsed) = create_signal(false); + + view! { + + } +} + +#[component] +fn NavItem( + icon: &'static str, + label: &'static str, + tab: Tab, + ui: UiContext, +) -> impl IntoView { + let tab_bg = tab.clone(); + let tab_clr = tab.clone(); + let tab_click = tab; + let handle_click = move |_| ui.active_tab.set(tab_click.clone()); + + view! { + + } +} diff --git a/services/frontend-leptos/frontend/src/layout/tab_strip.rs b/services/frontend-leptos/frontend/src/layout/tab_strip.rs new file mode 100644 index 0000000..7052f3f --- /dev/null +++ b/services/frontend-leptos/frontend/src/layout/tab_strip.rs @@ -0,0 +1,54 @@ +// services/frontend-leptos/frontend/src/layout/tab_strip.rs +use leptos::prelude::*; +use shared_types::ui_state::Tab; +use crate::app::UiContext; + +#[component] +pub fn TabStrip() -> impl IntoView { + let ui = use_context::().expect("UiContext not provided"); + + view! { +
+ + + +
+ } +} + +#[component] +fn TabItem( + label: &'static str, + tab: Tab, + ui: UiContext, +) -> impl IntoView { + let tab_color = tab.clone(); + let tab_border = tab.clone(); + let tab_click = tab; + view! { + + } +} diff --git a/services/frontend-leptos/frontend/src/lib.rs b/services/frontend-leptos/frontend/src/lib.rs index 5f76023..e2ac5be 100644 --- a/services/frontend-leptos/frontend/src/lib.rs +++ b/services/frontend-leptos/frontend/src/lib.rs @@ -1,5 +1,6 @@ pub mod api; pub mod app; +pub mod layout; pub mod ui; pub mod ws;