Skip to content

Commit ff9406a

Browse files
authored
[material-ui][docs] Open Material UI template with CodeSandbox/StackBlitz (#43604)
1 parent 4977aa0 commit ff9406a

File tree

107 files changed

+2045
-6856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2045
-6856
lines changed

.circleci/config.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,6 @@ jobs:
299299
command: |
300300
pnpm docs:link-check
301301
git add -A && git diff --exit-code --staged
302-
- run:
303-
name: Update the templates shared themes
304-
command: pnpm template:update-theme
305-
- run:
306-
name: '`pnpm template:update-theme` changes committed?'
307-
command: git add -A && git diff --exit-code --staged
308302
test_types:
309303
<<: *default-job
310304
resource_class: 'medium+'

docs/data/material/getting-started/faq/faq.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,81 @@ return (
261261

262262
If you are getting the error: `TypeError: Cannot convert a Symbol value to a string`, take a look at the [styled()](/system/styled/#how-to-use-components-selector-api) docs page for instructions on how you can fix this.
263263

264+
## How can I contribute to the free templates?
265+
266+
The templates are built using a [shared theme](https://github.com/mui/material-ui/tree/v6.0.2/docs/data/material/getting-started/templates/shared-theme). Below are the structure to create a new template:
267+
268+
### Template page
269+
270+
Create a new page in the `docs/pages/material-ui/getting-started/templates/<name>.js` directory with the following code:
271+
272+
```js
273+
import * as React from 'react';
274+
import AppTheme from 'docs/src/modules/components/AppTheme';
275+
import TemplateFrame from 'docs/src/modules/components/TemplateFrame';
276+
import Template from 'docs/data/material/getting-started/templates/<name>/<Template>';
277+
278+
export default function Page() {
279+
return (
280+
<AppTheme>
281+
<TemplateFrame>
282+
<Template />
283+
</TemplateFrame>
284+
</AppTheme>
285+
);
286+
}
287+
```
288+
289+
Then create a template file at `docs/data/material/getting-started/templates/<name>/<Template>.tsx` (add more files if needed):
290+
291+
> Note: The `<Template>` must be a pascal case string of the `<name>` folder.
292+
293+
### Shared theme
294+
295+
The template must use `AppTheme` from `../shared-theme/AppTheme` to ensure a consistent look and feel across all templates.
296+
297+
If the template includes custom-themed components, such as the dashboard template with MUI X themed components, pass them to the `AppTheme`'s `themedComponents` prop:
298+
299+
```js
300+
import AppTheme from '../shared-theme/AppTheme';
301+
302+
const xThemeComponents = {
303+
...chartsCustomizations,
304+
...dataGridCustomizations,
305+
...datePickersCustomizations,
306+
...treeViewCustomizations,
307+
};
308+
309+
export default function Dashboard(props: { disableCustomTheme?: boolean }) {
310+
return (
311+
<AppTheme {...props} themeComponents={xThemeComponents}>...</AppTheme>
312+
)
313+
}
314+
```
315+
316+
### Color mode toggle
317+
318+
The shared theme provides 2 appearance of the color mode toggle, `ColorModeSelect` and `ColorModeIconDropdown`.
319+
You can use either of them in your template, it will be hidden within the `TemplateFrame` but will be visible in the Code Sandbox and Stackblitz.
320+
321+
### Template frame
322+
323+
If the template has a sidebar or a header that needs to stick to the top, refer to the CSS variable `--template-frame-height` to adjust.
324+
325+
For example, the dashboard template has a fixed header that needs to be accounted for the template frame height:
326+
327+
```js
328+
<AppBar
329+
position="fixed"
330+
sx={{
331+
top: 'var(--template-frame-height, 0px)',
332+
// ...other styles
333+
}}
334+
>
335+
```
336+
337+
This will make the `AppBar` stay below the `TemplateFrame` in a preview mode but stick to the top in the CodeSandbox and Stackblitz.
338+
264339
## [legacy] I have several instances of styles on the page
265340

266341
If you are seeing a warning message in the console like the one below, you probably have several instances of `@mui/styles` initialized on the page.
Lines changed: 45 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,60 @@
11
import * as React from 'react';
2-
import { createTheme, ThemeProvider, alpha } from '@mui/material/styles';
2+
3+
import { alpha } from '@mui/material/styles';
34
import CssBaseline from '@mui/material/CssBaseline';
45
import Box from '@mui/material/Box';
56
import Stack from '@mui/material/Stack';
6-
import getDashboardTheme from './theme/getDashboardTheme';
77
import AppNavbar from './components/AppNavbar';
88
import Header from './components/Header';
99
import MainGrid from './components/MainGrid';
1010
import SideMenu from './components/SideMenu';
11-
import TemplateFrame from './TemplateFrame';
12-
13-
export default function Dashboard() {
14-
const [mode, setMode] = React.useState('light');
15-
const [showCustomTheme, setShowCustomTheme] = React.useState(true);
16-
const dashboardTheme = createTheme(getDashboardTheme(mode));
17-
const defaultTheme = createTheme({ palette: { mode } });
18-
// This code only runs on the client side, to determine the system color preference
19-
React.useEffect(() => {
20-
// Check if there is a preferred mode in localStorage
21-
const savedMode = localStorage.getItem('themeMode');
22-
if (savedMode) {
23-
setMode(savedMode);
24-
} else {
25-
// If no preference is found, it uses system preference
26-
const systemPrefersDark = window.matchMedia(
27-
'(prefers-color-scheme: dark)',
28-
).matches;
29-
setMode(systemPrefersDark ? 'dark' : 'light');
30-
}
31-
}, []);
32-
33-
const toggleColorMode = () => {
34-
const newMode = mode === 'dark' ? 'light' : 'dark';
35-
setMode(newMode);
36-
localStorage.setItem('themeMode', newMode); // Save the selected mode to localStorage
37-
};
11+
import AppTheme from '../shared-theme/AppTheme';
12+
import {
13+
chartsCustomizations,
14+
dataGridCustomizations,
15+
datePickersCustomizations,
16+
treeViewCustomizations,
17+
} from './theme/customizations';
3818

39-
const toggleCustomTheme = () => {
40-
setShowCustomTheme((prev) => !prev);
41-
};
19+
const xThemeComponents = {
20+
...chartsCustomizations,
21+
...dataGridCustomizations,
22+
...datePickersCustomizations,
23+
...treeViewCustomizations,
24+
};
4225

26+
export default function Dashboard(props) {
4327
return (
44-
<TemplateFrame
45-
toggleCustomTheme={toggleCustomTheme}
46-
showCustomTheme={showCustomTheme}
47-
mode={mode}
48-
toggleColorMode={toggleColorMode}
49-
>
50-
<ThemeProvider theme={showCustomTheme ? dashboardTheme : defaultTheme}>
51-
<CssBaseline enableColorScheme />
52-
<Box sx={{ display: 'flex' }}>
53-
<SideMenu />
54-
<AppNavbar />
55-
{/* Main content */}
56-
<Box
57-
component="main"
58-
sx={(theme) => ({
59-
flexGrow: 1,
60-
backgroundColor: alpha(theme.palette.background.default, 1),
61-
overflow: 'auto',
62-
})}
28+
<AppTheme {...props} themeComponents={xThemeComponents}>
29+
<CssBaseline enableColorScheme />
30+
<Box sx={{ display: 'flex' }}>
31+
<SideMenu />
32+
<AppNavbar />
33+
{/* Main content */}
34+
<Box
35+
component="main"
36+
sx={(theme) => ({
37+
flexGrow: 1,
38+
backgroundColor: theme.vars
39+
? `rgba(${theme.vars.palette.background.defaultChannel} / 1)`
40+
: alpha(theme.palette.background.default, 1),
41+
overflow: 'auto',
42+
})}
43+
>
44+
<Stack
45+
spacing={2}
46+
sx={{
47+
alignItems: 'center',
48+
mx: 3,
49+
pb: 10,
50+
mt: { xs: 8, md: 0 },
51+
}}
6352
>
64-
<Stack
65-
spacing={2}
66-
sx={{
67-
alignItems: 'center',
68-
mx: 3,
69-
pb: 10,
70-
mt: { xs: 8, md: 0 },
71-
}}
72-
>
73-
<Header />
74-
<MainGrid />
75-
</Stack>
76-
</Box>
53+
<Header />
54+
<MainGrid />
55+
</Stack>
7756
</Box>
78-
</ThemeProvider>
79-
</TemplateFrame>
57+
</Box>
58+
</AppTheme>
8059
);
8160
}
Lines changed: 48 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,63 @@
11
import * as React from 'react';
2-
import {
3-
PaletteMode,
4-
createTheme,
5-
ThemeProvider,
6-
alpha,
7-
} from '@mui/material/styles';
2+
import type {} from '@mui/x-date-pickers/themeAugmentation';
3+
import type {} from '@mui/x-charts/themeAugmentation';
4+
import type {} from '@mui/x-data-grid/themeAugmentation';
5+
import type {} from '@mui/x-tree-view/themeAugmentation';
6+
import { alpha } from '@mui/material/styles';
87
import CssBaseline from '@mui/material/CssBaseline';
98
import Box from '@mui/material/Box';
109
import Stack from '@mui/material/Stack';
11-
import getDashboardTheme from './theme/getDashboardTheme';
1210
import AppNavbar from './components/AppNavbar';
1311
import Header from './components/Header';
1412
import MainGrid from './components/MainGrid';
1513
import SideMenu from './components/SideMenu';
16-
import TemplateFrame from './TemplateFrame';
17-
18-
export default function Dashboard() {
19-
const [mode, setMode] = React.useState<PaletteMode>('light');
20-
const [showCustomTheme, setShowCustomTheme] = React.useState(true);
21-
const dashboardTheme = createTheme(getDashboardTheme(mode));
22-
const defaultTheme = createTheme({ palette: { mode } });
23-
// This code only runs on the client side, to determine the system color preference
24-
React.useEffect(() => {
25-
// Check if there is a preferred mode in localStorage
26-
const savedMode = localStorage.getItem('themeMode') as PaletteMode | null;
27-
if (savedMode) {
28-
setMode(savedMode);
29-
} else {
30-
// If no preference is found, it uses system preference
31-
const systemPrefersDark = window.matchMedia(
32-
'(prefers-color-scheme: dark)',
33-
).matches;
34-
setMode(systemPrefersDark ? 'dark' : 'light');
35-
}
36-
}, []);
37-
38-
const toggleColorMode = () => {
39-
const newMode = mode === 'dark' ? 'light' : 'dark';
40-
setMode(newMode);
41-
localStorage.setItem('themeMode', newMode); // Save the selected mode to localStorage
42-
};
14+
import AppTheme from '../shared-theme/AppTheme';
15+
import {
16+
chartsCustomizations,
17+
dataGridCustomizations,
18+
datePickersCustomizations,
19+
treeViewCustomizations,
20+
} from './theme/customizations';
4321

44-
const toggleCustomTheme = () => {
45-
setShowCustomTheme((prev) => !prev);
46-
};
22+
const xThemeComponents = {
23+
...chartsCustomizations,
24+
...dataGridCustomizations,
25+
...datePickersCustomizations,
26+
...treeViewCustomizations,
27+
};
4728

29+
export default function Dashboard(props: { disableCustomTheme?: boolean }) {
4830
return (
49-
<TemplateFrame
50-
toggleCustomTheme={toggleCustomTheme}
51-
showCustomTheme={showCustomTheme}
52-
mode={mode}
53-
toggleColorMode={toggleColorMode}
54-
>
55-
<ThemeProvider theme={showCustomTheme ? dashboardTheme : defaultTheme}>
56-
<CssBaseline enableColorScheme />
57-
<Box sx={{ display: 'flex' }}>
58-
<SideMenu />
59-
<AppNavbar />
60-
{/* Main content */}
61-
<Box
62-
component="main"
63-
sx={(theme) => ({
64-
flexGrow: 1,
65-
backgroundColor: alpha(theme.palette.background.default, 1),
66-
overflow: 'auto',
67-
})}
31+
<AppTheme {...props} themeComponents={xThemeComponents}>
32+
<CssBaseline enableColorScheme />
33+
<Box sx={{ display: 'flex' }}>
34+
<SideMenu />
35+
<AppNavbar />
36+
{/* Main content */}
37+
<Box
38+
component="main"
39+
sx={(theme) => ({
40+
flexGrow: 1,
41+
backgroundColor: theme.vars
42+
? `rgba(${theme.vars.palette.background.defaultChannel} / 1)`
43+
: alpha(theme.palette.background.default, 1),
44+
overflow: 'auto',
45+
})}
46+
>
47+
<Stack
48+
spacing={2}
49+
sx={{
50+
alignItems: 'center',
51+
mx: 3,
52+
pb: 10,
53+
mt: { xs: 8, md: 0 },
54+
}}
6855
>
69-
<Stack
70-
spacing={2}
71-
sx={{
72-
alignItems: 'center',
73-
mx: 3,
74-
pb: 10,
75-
mt: { xs: 8, md: 0 },
76-
}}
77-
>
78-
<Header />
79-
<MainGrid />
80-
</Stack>
81-
</Box>
56+
<Header />
57+
<MainGrid />
58+
</Stack>
8259
</Box>
83-
</ThemeProvider>
84-
</TemplateFrame>
60+
</Box>
61+
</AppTheme>
8562
);
8663
}

0 commit comments

Comments
 (0)