logicaffeine_web/ui/components/
page_layout.rs1use dioxus::prelude::*;
15use crate::ui::components::main_nav::{MainNav, ActivePage};
16use crate::ui::components::footer::{Footer, FooterVariant};
17
18const PAGE_LAYOUT_STYLES: &str = r#"
19.page-layout {
20 display: flex;
21 flex-direction: column;
22 min-height: 100vh;
23 background: var(--bg-dark, #060814);
24}
25
26.page-layout-content {
27 flex: 1;
28 display: flex;
29 flex-direction: column;
30}
31
32/* For full-height app pages (Studio, Workspace) that need no footer */
33.page-layout.no-footer .page-layout-content {
34 flex: 1;
35 overflow: hidden;
36}
37"#;
38
39#[derive(Clone, Copy, PartialEq, Default)]
41pub enum LayoutVariant {
42 #[default]
43 Standard,
44 Minimal,
45 NoFooter,
46 Landing,
47}
48
49#[component]
50pub fn PageLayout(
51 #[props(default)]
52 active_page: ActivePage,
53 #[props(default)]
54 subtitle: Option<&'static str>,
55 #[props(default = true)]
56 show_nav_links: bool,
57 #[props(default)]
58 variant: LayoutVariant,
59 children: Element,
60) -> Element {
61 let layout_class = match variant {
62 LayoutVariant::NoFooter => "page-layout no-footer",
63 _ => "page-layout",
64 };
65
66 rsx! {
67 style { "{PAGE_LAYOUT_STYLES}" }
68 div { class: layout_class,
69 MainNav {
70 active: active_page,
71 subtitle: subtitle,
72 show_nav_links: show_nav_links,
73 }
74
75 main { class: "page-layout-content",
76 {children}
77 }
78
79 match variant {
81 LayoutVariant::Standard => rsx! { Footer { variant: FooterVariant::Full } },
82 LayoutVariant::Minimal => rsx! { Footer { variant: FooterVariant::Minimal } },
83 LayoutVariant::NoFooter => rsx! {},
84 LayoutVariant::Landing => rsx! {}, }
86 }
87 }
88}