synpad 0.1.0

A full-featured Matrix chat client built with Dioxus
use dioxus::prelude::*;

use crate::app::Route;
use crate::components::breadcrumbs::Breadcrumbs;
use crate::components::keyboard_shortcuts::KeyboardShortcutsDialog;
use crate::components::message_effects::MessageEffectsOverlay;
use crate::components::spotlight_search::SpotlightSearch;
use crate::pages::rageshake::RageshakeDialog;
use crate::room::call::call_view::CallView;
use crate::room_list::room_list_panel::RoomListPanel;
use crate::room_list::spaces_bar::SpacesBar;
use crate::state::app_state::{AppState, AuthStatus, RightPanelView};
use crate::right_panel::file_panel::FilePanel;
use crate::right_panel::member_info::MemberInfoPanel;
use crate::right_panel::room_info::RoomInfoPanel;
use crate::right_panel::member_list::MemberListPanel;
use crate::right_panel::notification_panel::NotificationPanel;
use crate::right_panel::pinned_messages::PinnedMessagesPanel;
use crate::right_panel::thread_panel::ThreadPanel;

/// Main layout for authenticated users.
///
/// Three-panel layout: Spaces bar | Room list | Content (| Right panel)
#[component]
pub fn MainLayout() -> Element {
    let mut state = use_context::<Signal<AppState>>();
    let state_read = state.read();

    // Redirect to login if not logged in
    if matches!(state_read.auth_status, AuthStatus::Unknown) {
        return rsx! {
            div {
                class: "main-layout__loading",
                div { class: "spinner" }
                p { "Loading..." }
            }
        };
    }

    if !matches!(state_read.auth_status, AuthStatus::LoggedIn) {
        // Drop the read guard before navigating
        drop(state_read);
        let nav = navigator();
        nav.push(Route::LoginPage {});
        return rsx! {
            div {
                class: "main-layout__loading",
                p { "Redirecting to login..." }
            }
        };
    }

    let show_spotlight = state_read.spotlight_search_open;
    let has_call = state_read.call_state.is_active();
    let active_effect = state_read.active_effect.clone();
    let mut show_keyboard_shortcuts = use_signal(|| false);
    let mut show_rageshake = use_signal(|| false);

    let right_panel = state_read.right_panel.clone();

    rsx! {
        div {
            class: "main-layout",
            role: "application",
            aria_label: "Netrix Chat",
            // Global keyboard shortcuts (Ctrl+K for spotlight search)
            tabindex: "0",
            onkeydown: move |evt: Event<KeyboardData>| {
                if evt.modifiers().ctrl() && evt.key() == Key::Character("k".to_string()) {
                    evt.prevent_default();
                    let mut s = state.write();
                    s.spotlight_search_open = !s.spotlight_search_open;
                } else if evt.modifiers().ctrl() && evt.key() == Key::Character("/".to_string()) {
                    evt.prevent_default();
                    let current = *show_keyboard_shortcuts.read();
                    show_keyboard_shortcuts.set(!current);
                } else if evt.modifiers().ctrl() && evt.modifiers().shift() && evt.key() == Key::Character("D".to_string()) {
                    evt.prevent_default();
                    show_rageshake.set(true);
                }
            },

            // Spotlight search overlay
            if show_spotlight {
                SpotlightSearch {}
            }

            // Keyboard shortcuts dialog
            if *show_keyboard_shortcuts.read() {
                KeyboardShortcutsDialog {
                    on_close: move |_| show_keyboard_shortcuts.set(false),
                }
            }

            // Active call overlay
            if has_call {
                CallView {}
            }

            // Message effects overlay
            MessageEffectsOverlay {
                effect: active_effect,
                on_complete: move |_| {
                    state.write().active_effect = None;
                },
            }

            // Rageshake dialog (Ctrl+Shift+D)
            if *show_rageshake.read() {
                RageshakeDialog {
                    on_close: move |_| show_rageshake.set(false),
                }
            }

            // Spaces sidebar (far left)
            aside {
                class: "main-layout__spaces",
                role: "navigation",
                aria_label: "Spaces",
                SpacesBar {}
            }

            // Room list panel
            aside {
                class: "main-layout__room-list",
                role: "navigation",
                aria_label: "Room list",
                RoomListPanel {}
            }

            // Main content area
            main {
                class: "main-layout__content",
                role: "main",
                // Breadcrumbs bar (recent rooms)
                Breadcrumbs {}
                Outlet::<Route> {}
            }

            // Right panel (conditional)
            match right_panel {
                RightPanelView::Closed => rsx! {},
                RightPanelView::RoomInfo => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Room information",
                        RoomInfoPanel {}
                    }
                },
                RightPanelView::MemberList => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Member list",
                        MemberListPanel {}
                    }
                },
                RightPanelView::MemberDetail(user_id) => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Member details",
                        MemberInfoPanel {
                            user_id,
                        }
                    }
                },
                RightPanelView::PinnedMessages => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Pinned messages",
                        PinnedMessagesPanel {}
                    }
                },
                RightPanelView::FilePanel => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Shared files",
                        FilePanel {}
                    }
                },
                RightPanelView::NotificationPanel => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Room notifications",
                        NotificationPanel {}
                    }
                },
                RightPanelView::Thread(eid) => rsx! {
                    aside {
                        class: "main-layout__right-panel",
                        role: "complementary",
                        aria_label: "Thread conversation",
                        ThreadPanel {
                            thread_root_event_id: eid,
                        }
                    }
                },
            }
        }
    }
}