Skip to content

Instantly share code, notes, and snippets.

@sheepla
Last active December 15, 2024 11:23
Show Gist options
  • Select an option

  • Save sheepla/a36e15bdc39b09a73c54a89b8f3d1b16 to your computer and use it in GitHub Desktop.

Select an option

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

sheepla commented Aug 14, 2024

Copy link
Copy Markdown
Author

結果

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

image
image

@sheepla

sheepla commented Dec 15, 2024

Copy link
Copy Markdown
Author

Jotai (useAtom)とか使ったほうがいいかも

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