Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
225ac70
fix: package.json pretty print Closes #4643
rkristelijn Jan 31, 2025
2628997
Merge branch 'master' into master
bharatkashyap Feb 3, 2025
9d0d2e3
Merge branch 'master' into master
bharatkashyap Feb 11, 2025
d9e28ea
Merge branch 'mui:master' into master
rkristelijn Feb 14, 2025
4769295
Merge branch 'mui:master' into master
rkristelijn Mar 14, 2025
5a2a52d
Merge branch 'mui:master' into master
rkristelijn Mar 19, 2025
982a79b
chore(dashboard-layout): add custom toolbar
rkristelijn Mar 28, 2025
e26102d
feat(dashboard-layout): add cart and custom toolbar
rkristelijn Mar 31, 2025
32ae5b6
chore: add example
rkristelijn Mar 31, 2025
434c893
fix: searchbar layout:
rkristelijn Mar 31, 2025
5f45f01
chore(dashboard-layout): applied comments
rkristelijn Apr 2, 2025
7723447
chore(playground): reverts changes
rkristelijn Apr 2, 2025
6ad6279
refactor(dashboard-layout): add properties
rkristelijn Apr 2, 2025
3062c81
refactor(dashboard-layout): removes extensive docs
rkristelijn Apr 2, 2025
be5fc8e
docs(dashboard-layout): Add custom toolbar
rkristelijn Apr 3, 2025
f0e8805
refactor(dashboard-layout): improve layout
rkristelijn Apr 3, 2025
be2f8e5
Merge branch 'mui:master' into master
rkristelijn Apr 7, 2025
cf9f2b4
chore: merge master
rkristelijn Apr 7, 2025
d37db35
chore: revert playground
rkristelijn Apr 7, 2025
92bbc8d
Merge branch 'mui:master' into master
rkristelijn Apr 14, 2025
0aa845e
Merge branch 'mui:master' into master
rkristelijn Apr 19, 2025
fd67d8b
refactor(dashboard-layout): reduced documentation, cleanup comments
rkristelijn Apr 19, 2025
1cd788e
docs: cleanup
rkristelijn Apr 19, 2025
53a3507
Merge branch 'mui:master' into master
rkristelijn Apr 22, 2025
50ae1a0
Merge branch 'mui:master' into master
rkristelijn Apr 24, 2025
602cda9
Merge remote-tracking branch 'origin/master' into feat/custom-toolbar
rkristelijn Apr 24, 2025
48213a4
fix(dashboard-layout): apply suggested comments
rkristelijn Apr 24, 2025
12b6770
chore: revert playground
rkristelijn Apr 24, 2025
b765060
fix(dashboard-layout): wrap the full appbar
rkristelijn Apr 24, 2025
283e31b
Merge branch 'mui:master' into master
rkristelijn Apr 26, 2025
695b23f
chore: revert accidantally toolbarActions property rename
rkristelijn Apr 26, 2025
675c984
Merge branch 'master' into feat/custom-toolbar
rkristelijn Apr 26, 2025
201a17b
Apply suggestions from code review
rkristelijn May 2, 2025
2753405
feat(dashboard-layout): add default example
rkristelijn May 6, 2025
bb6a3ad
feat(playground): ooops, that playground again
rkristelijn May 6, 2025
28bf06c
Review, add fixes and improvements, refactor DashboardHeader as separ…
apedroferreira May 7, 2025
9af5372
Add fixes
apedroferreira May 7, 2025
c639580
More updates
apedroferreira May 7, 2025
a930295
Update docs
apedroferreira May 7, 2025
fd56d94
Fix tests
apedroferreira May 7, 2025
0bd0cfa
Merge remote-tracking branch 'upstream/master' into feat/custom-toolbar
apedroferreira May 7, 2025
5235275
Test solution was wrong
apedroferreira May 7, 2025
742853e
Update docs demo
apedroferreira May 7, 2025
ceb06cd
Fix header slot props override
apedroferreira May 7, 2025
bb73107
Adjust one more docs demo
apedroferreira May 7, 2025
89fcb59
Add todo comment
apedroferreira May 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useMediaQuery from '@mui/material/useMediaQuery';
import type {} from '@mui/material/themeCssVarsAugmentation';
import MenuIcon from '@mui/icons-material/Menu';
import MenuOpenIcon from '@mui/icons-material/MenuOpen';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import { BrandingContext, NavigationContext, WindowContext } from '../shared/context';
import { Account, type AccountProps } from '../Account';
import { DashboardSidebarSubNavigation } from './DashboardSidebarSubNavigation';
Expand Down Expand Up @@ -40,6 +41,7 @@ export interface DashboardLayoutSlotProps {
toolbarActions?: {};
toolbarAccount?: AccountProps;
sidebarFooter?: SidebarFooterProps;
toolbar?: {};
}

export interface DashboardLayoutSlots {
Expand All @@ -58,11 +60,20 @@ export interface DashboardLayoutSlots {
* @default Account
*/
toolbarAccount?: React.JSXElementConstructor<AccountProps>;
/**
Comment thread
rkristelijn marked this conversation as resolved.
* Optional footer component used in the layout sidebar.
* @default null
*/
toolbarCart?: React.JSXElementConstructor<{}>;
/**
* Optional footer component used in the layout sidebar.
* @default null
*/
sidebarFooter?: React.JSXElementConstructor<SidebarFooterProps>;
/**
* Optional toolbar component used in the layout header instead of the default.
*/
toolbar?: React.JSXElementConstructor<{}>;
}

export interface DashboardLayoutProps {
Expand Down Expand Up @@ -260,6 +271,7 @@ function DashboardLayout(props: DashboardLayoutProps) {

const ToolbarActionsSlot = slots?.toolbarActions ?? ToolbarActions;
const ToolbarAccountSlot = slots?.toolbarAccount ?? Account;
const ToolbarCartSlot = slots?.toolbarCart ?? React.Fragment;
const SidebarFooterSlot = slots?.sidebarFooter ?? null;

const getDrawerContent = React.useCallback(
Expand Down Expand Up @@ -385,10 +397,16 @@ function DashboardLayout(props: DashboardLayoutProps) {
<AppTitle branding={branding} {...slotProps?.appTitle} />
)}
</Stack>
<Stack direction="row" alignItems="center" spacing={1} sx={{ marginLeft: 'auto' }}>
<ToolbarActionsSlot {...slotProps?.toolbarActions} />
<ToolbarAccountSlot {...slotProps?.toolbarAccount} />
</Stack>
{/* show slots.toolbar if provided, else the stack */}
{slots?.toolbar ? (
<slots.toolbar {...slotProps?.toolbar} />
) : (
<Stack direction="row" alignItems="center" spacing={1} sx={{ marginLeft: 'auto' }}>
<ToolbarActionsSlot {...slotProps?.toolbarActions} />
<ToolbarAccountSlot {...slotProps?.toolbarAccount} />
<ToolbarCartSlot />
</Stack>
)}
</Stack>
</Toolbar>
</AppBar>
Expand Down
7 changes: 7 additions & 0 deletions playground/nextjs-pages/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Force development mode
Comment thread
rkristelijn marked this conversation as resolved.
Outdated
NODE_ENV=development
# Set up OAuth client: https://github.com/settings/developers
GITHUB_CLIENT_ID=""
# Read the docs: https://authjs.dev/guides/configuring-github
GITHUB_CLIENT_SECRET=""
# echo "AUTH_SECRET=$(openssl rand -base64 32)" >> .env.local
3 changes: 2 additions & 1 deletion playground/nextjs-pages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.13.0",
"private": true,
"scripts": {
"predev": "[ ! -f .env.local ] && cp .env.example .env.local && echo \"AUTH_SECRET=\"$(openssl rand -base64 32)\"\" >> .env.local || echo '.env.local already exists'",
"dev": "next dev",
"lint": "next lint"
},
Expand All @@ -22,4 +23,4 @@
"react-dom": "^19.0.0",
"zod": "3.24.2"
}
}
}
70 changes: 68 additions & 2 deletions playground/nextjs-pages/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { useRouter } from 'next/router';
import { NextAppProvider } from '@toolpad/core/nextjs';
import { PageContainer } from '@toolpad/core/PageContainer';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { DashboardLayout, ToolbarActions } from '@toolpad/core/DashboardLayout';
import Head from 'next/head';
import { AppCacheProvider } from '@mui/material-nextjs/v14-pagesRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
Expand All @@ -12,6 +12,9 @@ import type { AppProps } from 'next/app';
import type { Navigation } from '@toolpad/core/AppProvider';
import { SessionProvider, signIn, signOut, useSession } from 'next-auth/react';
import LinearProgress from '@mui/material/LinearProgress';
import { Box, Button, IconButton, InputBase, Paper, Stack } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import { Account } from '@toolpad/core/Account';

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: React.ReactElement<any>) => React.ReactNode;
Expand Down Expand Up @@ -48,6 +51,69 @@ const AUTHENTICATION = {
signOut,
};

function SearchBar() {
return (
<Paper
component="form"
elevation={0}
sx={{
alignItems: 'center',
width: { xl: 600, lg: 400, md: 'auto' },
height: 40,
px: 1.5,
borderRadius: 2,
backgroundColor: (theme) => theme.palette.action.hover,
}}
>
<IconButton type="submit" sx={{ p: '10px' }} aria-label="search" disableRipple>
<SearchIcon />
</IconButton>
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="Search"
inputProps={{ 'aria-label': 'search' }}
/>
</Paper>
);
}

function CustomToolbar() {
return (
<Stack
direction="row"
spacing={2}
alignItems="center"
justifyContent="space-between"
className="custom-toolbar"
sx={{
flexGrow: 1,
px: 2,
py: 1,
}}
>
<Box sx={{ flexGrow: 1, display: 'flex', justifyContent: 'center' }}>
<Box sx={{ maxWidth: 400, width: '100%' }}>
<SearchBar />
</Box>
</Box>

<Stack direction="row" spacing={1} alignItems="center">
<ToolbarActions />
<Account />
<ToolbarCart />
</Stack>
</Stack>
);
}

function ToolbarCart() {
return (
<Button color="primary" aria-label="Shopping Cart">
<ShoppingCartIcon />
</Button>
);
}

function DefaultLayout({ page }: { page: React.ReactElement<any> }) {
const router = useRouter();
const { segments = [] } = router.query;
Expand All @@ -67,7 +133,7 @@ function DefaultLayout({ page }: { page: React.ReactElement<any> }) {
}, [orderId, router.asPath]);

return (
<DashboardLayout>
<DashboardLayout slots={{ toolbar: CustomToolbar }}>
<PageContainer title={title}>{page}</PageContainer>
</DashboardLayout>
);
Expand Down
7 changes: 7 additions & 0 deletions playground/nextjs/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Force development mode
NODE_ENV=development
# Set up OAuth client: https://github.com/settings/developers
GITHUB_CLIENT_ID=""
# Read the docs: https://authjs.dev/guides/configuring-github
GITHUB_CLIENT_SECRET=""
# echo "AUTH_SECRET=$(openssl rand -base64 32)" >> .env.local
3 changes: 2 additions & 1 deletion playground/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.13.0",
"private": true,
"scripts": {
"predev": "[ ! -f .env.local ] && cp .env.example .env.local && echo \"AUTH_SECRET=\"$(openssl rand -base64 32)\"\" >> .env.local || echo '.env.local already exists'",
"dev": "next dev",
"lint": "next lint"
},
Expand All @@ -23,4 +24,4 @@
"react-dom": "^19.0.0",
"zod": "3.24.2"
}
}
}
78 changes: 75 additions & 3 deletions playground/nextjs/src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';
import * as React from 'react';

import React from 'react';
import { usePathname, useParams } from 'next/navigation';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
Expand All @@ -16,8 +17,11 @@ import {
SignOutButton,
AccountPreviewProps,
} from '@toolpad/core/Account';
import { DashboardLayout, SidebarFooterProps } from '@toolpad/core/DashboardLayout';
import { DashboardLayout, SidebarFooterProps, ToolbarActions } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import { Box, Button, IconButton, InputBase, Paper } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';

const accounts = [
{
Expand Down Expand Up @@ -157,6 +161,69 @@ function SidebarFooterAccount({ mini }: SidebarFooterProps) {
);
}

function SearchBar() {
return (
<Paper
component="form"
elevation={0}
sx={{
alignItems: 'center',
height: 40,
px: 1.5,
borderRadius: 2,
backgroundColor: (theme) => theme.palette.action.hover,
width: { xl: 600, lg: 400, md: 'auto' },
}}
>
<IconButton type="submit" sx={{ p: '10px' }} aria-label="search" disableRipple>
<SearchIcon />
</IconButton>
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="Search"
inputProps={{ 'aria-label': 'search' }}
/>
</Paper>
);
}

function CustomToolbar() {
return (
<Stack
direction="row"
spacing={2}
alignItems="center"
justifyContent="space-between"
className="custom-toolbar"
sx={{
flexGrow: 1,
px: 2,
py: 1,
}}
>
<Box sx={{ flexGrow: 1, display: 'flex', justifyContent: 'center' }}>
<Box sx={{ maxWidth: 400, width: '100%' }}>
<SearchBar />
</Box>
</Box>

<Stack direction="row" spacing={1} alignItems="center">
<ToolbarActions />
<Account />
<ToolbarCart />
</Stack>
</Stack>
);
}

function ToolbarCart() {
return (
<Button color="primary" aria-label="Shopping Cart">
<ShoppingCartIcon />
</Button>
);
}

export default function DashboardPagesLayout(props: { children: React.ReactNode }) {
const pathname = usePathname();
const params = useParams();
Expand All @@ -176,7 +243,12 @@ export default function DashboardPagesLayout(props: { children: React.ReactNode
}, [orderId, pathname]);

return (
<DashboardLayout slots={{ sidebarFooter: SidebarFooterAccount, toolbarAccount: () => null }}>
<DashboardLayout
slots={{
sidebarFooter: SidebarFooterAccount,
toolbar: CustomToolbar,
}}
>
<PageContainer title={title}>{props.children}</PageContainer>
</DashboardLayout>
);
Expand Down