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