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#[function_component(Page)]
62pub fn page(props: &PageProperties) -> Html {
63    let open = use_state_eq(|| props.open);
64
65    let onclick = {
66        let open = open.clone();
67        Callback::from(move |_| {
68            open.set(!(*open));
69        })
70    };
71    let onscroll = props.on_main_scroll.clone();
72    html! (
73        <div class="pf-v5-c-page" id={&props.id} role="main" tabindex="-1">
74            <header class="pf-v5-c-masthead">
75                // If the sidebar is empty then the toggle button is not
76                // shown
77                if !props.sidebar.is_empty() {
78                    <span class="pf-v5-c-masthead__toggle">
79                        <Button
80                            r#type={ButtonType::Button}
81                            variant={ButtonVariant::Plain}
82                            {onclick}
83                        >
84                            <i class="fas fa-bars" aria-hidden="true" />
85                        </Button>
86                    </span>
87                }
88
89                <div class="pf-v5-c-masthead__main">
90                    { props.brand.clone() }
91                </div>
92
93                <div class="pf-v5-c-masthead__content"> // TODO: Should migrate props
94                    { props.nav.clone() }
95                    { props.tools.clone() }
96                </div>
97
98            </header>
99
100            { for props.sidebar.iter().map(|mut s|{
101                let props = Rc::make_mut(&mut s.props);
102                props.open = *open;
103                s
104            }) }
105
106            <main class="pf-v5-c-page__main" tabindex="-1" {onscroll}>
107                { props.children.clone() }
108            </main>
109        </div>
110    )
111}
112
113#[derive(Clone, Debug, PartialEq, Properties)]
114pub struct MastheadBrandProperties {
115    /// Expected to be a single [`crate::prelude::Brand`] component.
116    ///
117    /// NOTE: Future versions might enforce the child requirement without prior deprecation.
118    #[prop_or_default]
119    pub children: Html,
120
121    /// Called when the user clicks on the brand logo.
122    #[prop_or_default]
123    pub onclick: Option<Callback<()>>,
124}
125
126/// Masthead brand component.
127///
128/// ## Properties
129///
130/// Defined by [`MastheadBrandProperties`].
131///
132/// ## Children
133///
134/// A single [`crate::prelude::Brand`] component. The children may be wrapped in an `a` element when the `onclick`
135/// callback is set.
136#[function_component(MastheadBrand)]
137pub fn masthead_brand(props: &MastheadBrandProperties) -> Html {
138    match &props.onclick {
139        Some(onclick) => {
140            let onclick = onclick.reform(|_| ());
141            html!(
142                <a class="pf-v5-c-masthead__brand" href="#" {onclick}>
143                    { props.children.clone() }
144                </a>
145            )
146        }
147        None => {
148            html!(
149                <div class="pf-v5-c-masthead__brand">
150                    { props.children.clone() }
151                </div>
152            )
153        }
154    }
155}