Skip to main content

patternfly_yew/components/page/
mod.rs

1//! Full Page components
2use crate::prelude::{Button, ButtonType, ButtonVariant};
3use std::rc::Rc;
4use yew::prelude::*;
5
6mod section;
7mod sidebar;
8
9pub use section::*;
10pub use sidebar::*;
11
12/// Properties for [`Page`]
13#[derive(Clone, PartialEq, Properties)]
14pub struct PageProperties {
15    #[prop_or_default]
16    pub children: Html,
17    #[prop_or_default]
18    pub sidebar: ChildrenWithProps<PageSidebar>,
19    #[prop_or_default]
20    pub tools: Html,
21
22    /// The brand section.
23    ///
24    /// Expected to be a single [`MastheadBrand`] component.
25    ///
26    /// NOTE: Future versions might enforce the child requirement without prior deprecation.
27    #[prop_or_default]
28    pub brand: Html,
29
30    #[prop_or_default]
31    pub nav: Html,
32    #[prop_or(true)]
33    pub open: bool,
34    #[prop_or_default]
35    pub full_height: bool,
36
37    #[prop_or_default]
38    pub id: Option<AttrValue>,
39    #[prop_or_default]
40    pub on_main_scroll: Callback<Event>,
41}
42
43/// A full page
44///
45/// > The page component is used to define the basic layout of a page with either vertical or horizontal navigation.
46///
47/// See: <https://www.patternfly.org/components/page>
48///
49/// ## Properties
50///
51/// Defined by [`PageProperties`].
52///
53/// ## Elements
54///
55/// * **Sidebar**: Contains a single [`PageSidebar`], hosting the main navigation.
56/// * **Navigation**: The top header navigation section.
57/// * **Tools**: Tools, shown in the header section of the page.
58/// * **Brand**: A brand logo, shown in the navigation header section.
59/// * **Children**: The actual page content, probably wrapped into [`PageSection`] components.
60///
61#[component]
62pub fn Page(props: &PageProperties) -> Html {
63    let open = use_state_eq(|| props.open);
64
65    let onclick = use_callback(open.clone(), |_, open| {
66        open.set(!(**open));
67    });
68
69    let onscroll = props.on_main_scroll.clone();
70
71    let mut class = classes!["pf-v6-c-page__main-container"];
72
73    if props.full_height {
74        class.push("pf-m-fill");
75    }
76
77    html! (
78        <div class="pf-v6-c-page" id={&props.id} role="main" tabindex="-1">
79            <header class="pf-v6-c-masthead">
80                <div class="pf-v6-c-masthead__main">
81                    // If the sidebar is empty then the toggle button is not
82                    // shown
83                    if !props.sidebar.is_empty() {
84                        <span class="pf-v6-c-masthead__toggle">
85                            <Button
86                                r#type={ButtonType::Button}
87                                variant={ButtonVariant::Plain}
88                                {onclick}
89                            >
90                                <i class="fas fa-bars" aria-hidden="true" />
91                            </Button>
92                        </span>
93                    }
94                    { props.brand.clone() }
95                </div>
96                <div class="pf-v6-c-masthead__content">
97                    // TODO: Should migrate props
98                    { props.nav.clone() }
99                    { props.tools.clone() }
100                </div>
101            </header>
102            { for props.sidebar.iter().map(|mut s|{
103                let props = Rc::make_mut(&mut s.props);
104                props.open = *open;
105                s
106            }) }
107            <div {class}>
108                <main class="pf-v6-c-page__main" tabindex="-1" {onscroll}>
109                    { props.children.clone() }
110                </main>
111            </div>
112        </div>
113    )
114}
115
116#[derive(Clone, Debug, PartialEq, Properties)]
117pub struct MastheadBrandProperties {
118    /// Expected to be a single [`crate::prelude::Brand`] component.
119    ///
120    /// NOTE: Future versions might enforce the child requirement without prior deprecation.
121    #[prop_or_default]
122    pub children: Html,
123
124    /// Called when the user clicks on the brand logo.
125    #[prop_or_default]
126    pub onclick: Option<Callback<()>>,
127}
128
129/// Masthead brand component.
130///
131/// ## Properties
132///
133/// Defined by [`MastheadBrandProperties`].
134///
135/// ## Children
136///
137/// A single [`crate::prelude::Brand`] component. The children may be wrapped in an `a` element when the `onclick`
138/// callback is set.
139#[component]
140pub fn MastheadBrand(props: &MastheadBrandProperties) -> Html {
141    match &props.onclick {
142        Some(onclick) => {
143            let onclick = onclick.reform(|_| ());
144            html!(
145                <a class="pf-v6-c-masthead__brand" href="#" {onclick}>{ props.children.clone() }</a>
146            )
147        }
148        None => {
149            html!(<div class="pf-v6-c-masthead__brand">{ props.children.clone() }</div>)
150        }
151    }
152}