Skip to main content

dioxus_docs_kit/components/blog/
blog_layout.rs

1use dioxus::prelude::*;
2use dioxus_free_icons::Icon;
3use dioxus_free_icons::icons::ld_icons::LdMenu;
4
5use crate::blog::registry::BlogRegistry;
6use crate::components::docs_layout::{DrawerOpen, SearchOpen};
7
8use super::mobile_drawer::BlogMobileDrawer;
9use super::search_modal::BlogSearchModal;
10use super::theme_toggle::BlogThemeToggle;
11
12/// Blog layout shell.
13///
14/// # Context requirements
15///
16/// - `&'static BlogRegistry` — provided by consumer
17/// - `BlogContext` — provided by consumer
18#[component]
19pub fn BlogLayout(
20    header: Option<Element>,
21    #[props(default = true)] show_header: bool,
22    children: Element,
23) -> Element {
24    let registry = use_context::<&'static BlogRegistry>();
25
26    let parent_search: Option<SearchOpen> = try_use_context();
27    let parent_drawer: Option<DrawerOpen> = try_use_context();
28
29    let local_search = use_signal(|| false);
30    let local_drawer = use_signal(|| false);
31
32    let search_open = parent_search.map(|s| s.0).unwrap_or(local_search);
33    let mut drawer_open = parent_drawer.map(|d| d.0).unwrap_or(local_drawer);
34
35    use_context_provider(|| SearchOpen(search_open));
36    use_context_provider(|| DrawerOpen(drawer_open));
37
38    // Theme state
39    crate::components::shared::use_theme_provider(registry.theme.clone());
40
41    // Keyboard shortcut: Cmd/Ctrl+K
42    crate::components::shared::use_search_hotkey(search_open);
43
44    rsx! {
45        div { class: "min-h-screen bg-base-100",
46            if show_header {
47                div { class: "sticky top-0 z-50",
48                    if let Some(hdr) = header {
49                        {hdr}
50                    } else {
51                        div { class: "navbar bg-base-200 border-b border-base-300 px-4 lg:px-8",
52                            div { class: "flex-1 gap-2",
53                                button {
54                                    class: "btn btn-ghost btn-sm btn-square lg:hidden",
55                                    onclick: move |_| drawer_open.toggle(),
56                                    Icon { class: "size-5", icon: LdMenu }
57                                }
58                            }
59                            div { class: "flex-none gap-1",
60                                BlogSearchButton { search_open }
61                                BlogThemeToggle {}
62                            }
63                        }
64                    }
65                }
66            }
67
68            div { class: "flex-1 min-w-0",
69                {children}
70            }
71        }
72
73        BlogMobileDrawer { open: drawer_open }
74        BlogSearchModal {}
75    }
76}
77
78/// Reusable search button for blog headers (same component as
79/// [`SearchButton`](crate::components::SearchButton), re-exported under the
80/// blog naming convention).
81pub use crate::components::docs_layout::SearchButton as BlogSearchButton;