Skip to content

Commit

Permalink
[DashboardLayout] Add hideNavigation prop (#4231)
Browse files Browse the repository at this point in the history
Co-authored-by: MUI bot <2109932+Janpot@users.noreply.github.com>
Co-authored-by: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 9, 2024
1 parent f860aaf commit 06ca8df
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { AppProvider } from '@toolpad/core/AppProvider';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';

const demoTheme = createTheme({
cssVariables: {
colorSchemeSelector: 'data-toolpad-color-scheme',
},
colorSchemes: { light: true, dark: true },
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 600,
lg: 1200,
xl: 1536,
},
},
});

function DemoPageContent({ pathname }) {
return (
<Box
sx={{
py: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
}}
>
<Typography>Dashboard content for {pathname}</Typography>
</Box>
);
}

DemoPageContent.propTypes = {
pathname: PropTypes.string.isRequired,
};

function DashboardLayoutSidebarHidden(props) {
const { window } = props;

const [pathname, setPathname] = React.useState('/dashboard');

const router = React.useMemo(() => {
return {
pathname,
searchParams: new URLSearchParams(),
navigate: (path) => setPathname(String(path)),
};
}, [pathname]);

// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;

return (
<AppProvider router={router} theme={demoTheme} window={demoWindow}>
<DashboardLayout hideNavigation>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
</AppProvider>
);
}

DashboardLayoutSidebarHidden.propTypes = {
/**
* Injected by the documentation to work in an iframe.
* Remove this when copying and pasting into your project.
*/
window: PropTypes.func,
};

export default DashboardLayoutSidebarHidden;
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as React from 'react';
import { createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { AppProvider } from '@toolpad/core/AppProvider';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import type { Router } from '@toolpad/core';

const demoTheme = createTheme({
cssVariables: {
colorSchemeSelector: 'data-toolpad-color-scheme',
},
colorSchemes: { light: true, dark: true },
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 600,
lg: 1200,
xl: 1536,
},
},
});

function DemoPageContent({ pathname }: { pathname: string }) {
return (
<Box
sx={{
py: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
}}
>
<Typography>Dashboard content for {pathname}</Typography>
</Box>
);
}

interface DemoProps {
/**
* Injected by the documentation to work in an iframe.
* Remove this when copying and pasting into your project.
*/
window?: () => Window;
}

export default function DashboardLayoutSidebarHidden(props: DemoProps) {
const { window } = props;

const [pathname, setPathname] = React.useState('/dashboard');

const router = React.useMemo<Router>(() => {
return {
pathname,
searchParams: new URLSearchParams(),
navigate: (path) => setPathname(String(path)),
};
}, [pathname]);

// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;

return (
<AppProvider router={router} theme={demoTheme} window={demoWindow}>
<DashboardLayout hideNavigation>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
</AppProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<DashboardLayout hideNavigation>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ The layout sidebar is collapsible to a mini-drawer (with icons only) in desktop

{{"demo": "DashboardLayoutNoMiniSidebar.js", "height": 400, "iframe": true}}

### Hiding the sidebar

The layout sidebar can be hidden if needed with the `hideNavigation` prop.

{{"demo": "DashboardLayoutSidebarHidden.js", "height": 400, "iframe": true}}

## Account

The `DashboardLayout` comes integrated with the [`<Account />`](/toolpad/core/react-account/) component. It renders as an account management menu when a user is signed in – a `session` object is present – and a button when not.
Expand Down
1 change: 1 addition & 0 deletions docs/pages/toolpad/core/api/dashboard-layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"props": {
"children": { "type": { "name": "node" }, "required": true },
"disableCollapsibleSidebar": { "type": { "name": "bool" }, "default": "false" },
"hideNavigation": { "type": { "name": "bool" }, "default": "false" },
"slotProps": {
"type": {
"name": "shape",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"disableCollapsibleSidebar": {
"description": "Whether the sidebar should not be collapsible to a mini variant in desktop and tablet viewports."
},
"hideNavigation": {
"description": "Whether the navigation bar and menu icon should be hidden"
},
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." }
},
Expand Down
31 changes: 31 additions & 0 deletions packages/toolpad-core/src/DashboardLayout/DashboardLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,35 @@ describe('DashboardLayout', () => {
expect(within(desktopNavigation).getByText('Action 1')).toBeTruthy();
expect(within(desktopNavigation).getByText('Action 2')).toBeTruthy();
});

test('renders without the navigation and toggle button', async () => {
const NAVIGATION: Navigation = [
{
title: 'Dashboard',
segment: 'dashboard',
icon: <DashboardIcon />,
},
{
title: 'Orders',
segment: 'orders',
icon: <ShoppingCartIcon />,
},
];

render(
<AppProvider navigation={NAVIGATION}>
<DashboardLayout hideNavigation>Hello world</DashboardLayout>
</AppProvider>,
);

const desktopNavigation = screen.queryByRole('navigation', { name: 'Desktop' });
const navigationToggle = screen.queryByLabelText('Collapse menu');

// Expect that the navigation and toggle button are not rendered
expect(desktopNavigation).toBeNull();
expect(navigationToggle).toBeNull();

// Ensure the main content is still rendered
expect(screen.getByText('Hello world')).toBeTruthy();
});
});
134 changes: 79 additions & 55 deletions packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,11 @@ export interface DashboardLayoutProps {
toolbarActions?: {};
toolbarAccount?: AccountProps;
};
/**
* Whether the navigation bar and menu icon should be hidden
* @default false
*/
hideNavigation?: boolean;
}

/**
Expand All @@ -373,7 +378,13 @@ export interface DashboardLayoutProps {
* - [DashboardLayout API](https://mui.com/toolpad/core/api/dashboard-layout)
*/
function DashboardLayout(props: DashboardLayoutProps) {
const { children, disableCollapsibleSidebar = false, slots, slotProps } = props;
const {
children,
disableCollapsibleSidebar = false,
slots,
slotProps,
hideNavigation = false,
} = props;

const theme = useTheme();

Expand Down Expand Up @@ -545,22 +556,26 @@ function DashboardLayout(props: DashboardLayoutProps) {
<Toolbar
sx={{ backgroundColor: 'inherit', minWidth: '100vw', mx: { xs: -0.75, sm: -1.5 } }}
>
<Box
sx={{
mr: { sm: disableCollapsibleSidebar ? 0 : 1 },
display: { md: 'none' },
}}
>
{getMenuIcon(isMobileNavigationExpanded)}
</Box>
<Box
sx={{
display: { xs: 'none', md: disableCollapsibleSidebar ? 'none' : 'block' },
mr: disableCollapsibleSidebar ? 0 : 1,
}}
>
{getMenuIcon(isDesktopNavigationExpanded)}
</Box>
{!hideNavigation ? (
<React.Fragment>
<Box
sx={{
mr: { sm: disableCollapsibleSidebar ? 0 : 1 },
display: { md: 'none' },
}}
>
{getMenuIcon(isMobileNavigationExpanded)}
</Box>
<Box
sx={{
display: { xs: 'none', md: disableCollapsibleSidebar ? 'none' : 'block' },
mr: disableCollapsibleSidebar ? 0 : 1,
}}
>
{getMenuIcon(isDesktopNavigationExpanded)}
</Box>
</React.Fragment>
) : null}

<Box
sx={{
Expand Down Expand Up @@ -594,44 +609,48 @@ function DashboardLayout(props: DashboardLayoutProps) {
</Stack>
</Toolbar>
</AppBar>
<Drawer
container={appWindow?.document.body}
variant="temporary"
open={isMobileNavigationExpanded}
onClose={handleSetNavigationExpanded(false)}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: {
xs: 'block',
sm: disableCollapsibleSidebar ? 'block' : 'none',
md: 'none',
},
...getDrawerSharedSx(false),
}}
>
{getDrawerContent(false, 'Phone')}
</Drawer>
<Drawer
variant="permanent"
sx={{
display: {
xs: 'none',
sm: disableCollapsibleSidebar ? 'none' : 'block',
md: 'none',
},
...getDrawerSharedSx(isMobileMini),
}}
>
{getDrawerContent(isMobileMini, 'Tablet')}
</Drawer>
<Drawer
variant="permanent"
sx={{ display: { xs: 'none', md: 'block' }, ...getDrawerSharedSx(isDesktopMini) }}
>
{getDrawerContent(isDesktopMini, 'Desktop')}
</Drawer>
{!hideNavigation ? (
<React.Fragment>
<Drawer
container={appWindow?.document.body}
variant="temporary"
open={isMobileNavigationExpanded}
onClose={handleSetNavigationExpanded(false)}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: {
xs: 'block',
sm: disableCollapsibleSidebar ? 'block' : 'none',
md: 'none',
},
...getDrawerSharedSx(false),
}}
>
{getDrawerContent(false, 'Phone')}
</Drawer>
<Drawer
variant="permanent"
sx={{
display: {
xs: 'none',
sm: disableCollapsibleSidebar ? 'none' : 'block',
md: 'none',
},
...getDrawerSharedSx(isMobileMini),
}}
>
{getDrawerContent(isMobileMini, 'Tablet')}
</Drawer>
<Drawer
variant="permanent"
sx={{ display: { xs: 'none', md: 'block' }, ...getDrawerSharedSx(isDesktopMini) }}
>
{getDrawerContent(isDesktopMini, 'Desktop')}
</Drawer>
</React.Fragment>
) : null}

<Box
component="main"
Expand Down Expand Up @@ -665,6 +684,11 @@ DashboardLayout.propTypes /* remove-proptypes */ = {
* @default false
*/
disableCollapsibleSidebar: PropTypes.bool,
/**
* Whether the navigation bar and menu icon should be hidden
* @default false
*/
hideNavigation: PropTypes.bool,
/**
* The props used for each slot inside.
* @default {}
Expand Down

0 comments on commit 06ca8df

Please sign in to comment.