Skip to content

Commit

Permalink
[core] Add toolbarActions and toolbarAccount slots to DashboardLayout (
Browse files Browse the repository at this point in the history
  • Loading branch information
apedroferreira authored Aug 29, 2024
1 parent b14f43f commit d1838c4
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { createTheme } from '@mui/material/styles';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import SearchIcon from '@mui/icons-material/Search';
import { AppProvider } from '@toolpad/core/AppProvider';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';

const NAVIGATION = [
{
kind: 'header',
title: 'Main items',
},
{
segment: 'dashboard',
title: 'Dashboard',
icon: <DashboardIcon />,
},
{
segment: 'orders',
title: 'Orders',
icon: <ShoppingCartIcon />,
},
];

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 SearchBar() {
return (
<TextField
id="search"
label="Search"
variant="outlined"
size="small"
slotProps={{
input: {
endAdornment: (
<IconButton type="button" aria-label="search" size="small">
<SearchIcon />
</IconButton>
),
sx: { pr: 0.5 },
},
}}
sx={{ mr: 1 }}
/>
);
}

function DashboardLayoutSlots(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
navigation={NAVIGATION}
router={router}
theme={demoTheme}
window={demoWindow}
>
<DashboardLayout slots={{ toolbarActions: SearchBar }}>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
</AppProvider>
);
}

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

export default DashboardLayoutSlots;
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { createTheme } from '@mui/material/styles';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import SearchIcon from '@mui/icons-material/Search';
import { AppProvider } from '@toolpad/core/AppProvider';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';

const NAVIGATION: Navigation = [
{
kind: 'header',
title: 'Main items',
},
{
segment: 'dashboard',
title: 'Dashboard',
icon: <DashboardIcon />,
},
{
segment: 'orders',
title: 'Orders',
icon: <ShoppingCartIcon />,
},
];

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>
);
}

function SearchBar() {
return (
<TextField
id="search"
label="Search"
variant="outlined"
size="small"
slotProps={{
input: {
endAdornment: (
<IconButton type="button" aria-label="search" size="small">
<SearchIcon />
</IconButton>
),
sx: { pr: 0.5 },
},
}}
sx={{ mr: 1 }}
/>
);
}

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 DashboardLayoutSlots(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
navigation={NAVIGATION}
router={router}
theme={demoTheme}
window={demoWindow}
>
<DashboardLayout slots={{ toolbarActions: SearchBar }}>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
</AppProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<DashboardLayout slots={{ toolbarActions: SearchBar }}>
<DemoPageContent pathname={pathname} />
</DashboardLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,10 @@ The use of an `iframe` may cause some spacing issues in the following demo.
:::

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

## Customization

Some areas of the layout can be replaced with custom components by using the `slots` and `slotProps` props.
For example, this allows you to add new items to the toolbar in the header, such as a search bar.

{{"demo": "DashboardLayoutSlots.js", "height": 400, "iframe": true}}
33 changes: 32 additions & 1 deletion docs/pages/toolpad/core/api/dashboard-layout.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
{
"props": { "children": { "type": { "name": "node" }, "required": true } },
"props": {
"children": { "type": { "name": "node" }, "required": true },
"slotProps": {
"type": {
"name": "shape",
"description": "{ toolbarAccount?: { signInLabel?: string, signOutLabel?: string, slotProps?: { avatar?: object, iconButton?: object, signInButton?: object, signOutButton?: object } }, toolbarActions?: object }"
},
"default": "{}"
},
"slots": {
"type": {
"name": "shape",
"description": "{ toolbarAccount?: elementType, toolbarActions?: elementType }"
},
"default": "{}",
"additionalInfo": { "slotsApi": true }
}
},
"name": "DashboardLayout",
"imports": [
"import { DashboardLayout } from '@toolpad/core/DashboardLayout';",
"import { DashboardLayout } from '@toolpad/core';"
],
"slots": [
{
"name": "toolbarActions",
"description": "The toolbar actions component used in the layout header.",
"default": "ToolbarActions",
"class": null
},
{
"name": "toolbarAccount",
"description": "The toolbar account component used in the layout header.",
"default": "Account",
"class": null
}
],
"classes": [],
"spread": true,
"themeDefaultProps": null,
Expand Down
32 changes: 32 additions & 0 deletions docs/pages/toolpad/core/api/sign-in-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,38 @@
"import { SignInPage } from '@toolpad/core/SignInPage';",
"import { SignInPage } from '@toolpad/core';"
],
"slots": [
{
"name": "emailField",
"description": "The custom email field component used in the credentials form.",
"default": "TextField",
"class": null
},
{
"name": "passwordField",
"description": "The custom password field component used in the credentials form.",
"default": "TextField",
"class": null
},
{
"name": "submitButton",
"description": "The custom submit button component used in the credentials form.",
"default": "LoadingButton",
"class": null
},
{
"name": "forgotPasswordLink",
"description": "The custom forgot password link component used in the credentials form.",
"default": "Link",
"class": null
},
{
"name": "signUpLink",
"description": "The custom sign up link component used in the credentials form.",
"default": "Link",
"class": null
}
],
"classes": [],
"spread": true,
"themeDefaultProps": false,
Expand Down
12 changes: 10 additions & 2 deletions docs/translations/api-docs/dashboard-layout/dashboard-layout.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
{
"componentDescription": "",
"propDescriptions": { "children": { "description": "The content of the dashboard." } },
"classDescriptions": {}
"propDescriptions": {
"children": { "description": "The content of the dashboard." },
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." }
},
"classDescriptions": {},
"slotDescriptions": {
"toolbarAccount": "The toolbar account component used in the layout header.",
"toolbarActions": "The toolbar actions component used in the layout header."
}
}
9 changes: 8 additions & 1 deletion docs/translations/api-docs/sign-in-page/sign-in-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,12 @@
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." }
},
"classDescriptions": {}
"classDescriptions": {},
"slotDescriptions": {
"emailField": "The custom email field component used in the credentials form.",
"forgotPasswordLink": "The custom forgot password link component used in the credentials form.",
"passwordField": "The custom password field component used in the credentials form.",
"signUpLink": "The custom sign up link component used in the credentials form.",
"submitButton": "The custom submit button component used in the credentials form."
}
}
4 changes: 2 additions & 2 deletions packages/toolpad-core/src/AppProvider/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ export interface Authentication {
signOut: () => void;
}

export const SessionContext = React.createContext<Session | null>(null);

export const AuthenticationContext = React.createContext<Authentication | null>(null);

export const SessionContext = React.createContext<Session | null>(null);

export type AppTheme = Theme | { light: Theme; dark: Theme };

export interface AppProviderProps {
Expand Down
Loading

0 comments on commit d1838c4

Please sign in to comment.