Skip to content

Instantly share code, notes, and snippets.

@sheepla
Last active August 15, 2024 05:32
Show Gist options
  • Save sheepla/a36e15bdc39b09a73c54a89b8f3d1b16 to your computer and use it in GitHub Desktop.
Save sheepla/a36e15bdc39b09a73c54a89b8f3d1b16 to your computer and use it in GitHub Desktop.
React + MUIによるダークモードに切り換え可能なUIの実装
import React from "react";
import "./App.css";
import LoginBox from "./components/LoginBox";
import {
createTheme,
CssBaseline,
ThemeProvider,
useMediaQuery,
} from "@mui/material";
import { deepPurple, indigo } from "@mui/material/colors";
import MainAppBar from "./components/MainAppBar";
function App() {
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const [darkMode, setDarkMode] = React.useState<boolean>(prefersDarkMode);
const muiTheme = React.useMemo(
() =>
createTheme({
palette: {
mode: darkMode ? "dark" : "light",
primary: indigo,
secondary: deepPurple,
},
}),
[darkMode]
);
const handleToggle = () => {
setDarkMode((mode) => {
console.debug("Next dark mode status: ", !mode);
return !mode;
});
};
return (
<>
<ThemeProvider theme={muiTheme}>
<CssBaseline>
<MainAppBar darkMode={darkMode} handleToggle={handleToggle} />
<LoginBox />
</CssBaseline>
</ThemeProvider>
</>
);
}
export default App;
import React from "react";
import {
AppBar,
Toolbar,
Typography,
Container,
Paper,
TextField,
Button,
Grid,
Box,
Link,
} from "@mui/material";
import LoginIcon from "@mui/icons-material/Login";
interface Credential {
userName: string;
password: string;
}
function LoginBox() {
return (
<div
style={{ minHeight: "100vh", display: "flex", flexDirection: "column" }}
>
<Container
component="main"
maxWidth="xs"
sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Paper
elevation={10}
sx={{
padding: 3,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Box sx={{ display: "flex", alignItems: "center", b: 2 }}>
<LoginIcon sx={{ mr: 1 }} />
<Typography variant="h5">Login</Typography>
</Box>
<Box component="form" noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="user-name"
label="User Name"
name="text"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Login
</Button>
</Box>
</Paper>
</Container>
</div>
);
}
export default LoginBox;
import React from "react";
import {
AppBar,
Toolbar,
Typography,
Switch,
IconButton,
Box,
} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
import DarkModeIcon from "@mui/icons-material/DarkMode";
import LightModeIcon from "@mui/icons-material/LightMode";
function MainAppBar({
darkMode,
handleToggle,
}: {
darkMode: boolean;
handleToggle: () => void;
}) {
return (
<AppBar position="absolute">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" sx={{ flexGrow: 1 }}>
MyApp
</Typography>
<Box sx={{ display: "flex", alignItems: "center" }}>
{darkMode ? (
<DarkModeIcon sx={{ m: 1 }} />
) : (
<LightModeIcon sx={{ m: 1 }} />
)}
<Switch
checked={darkMode}
onChange={handleToggle}
inputProps={{ "aria-label": "toggle dark mode" }}
/>
</Box>
</Toolbar>
</AppBar>
);
}
export default MainAppBar;
{
"name": "mui-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@mui/icons-material": "^5.15.19",
"@mui/material": "^5.15.19",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.97",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.51.5",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
@sheepla
Copy link
Author

sheepla commented Aug 14, 2024

結果

AppBarに付いているトグルスイッチを押すとダークモードのON/OFFを切り替えられる。
ついでにアイコンも変化するようにした。

image
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment