리액트에서 많이 쓰는 UI 라이브러리
설치
npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
속성들은 https://mui.com/components
에서 참고하자
타이포그래피 (Typography)
import React from 'react';
import { Typography } from '@mui/material';
export default function Create() {
return (
<div>
<Typography
variant='h6'
component='h2'
color='textSecondary'
gutterBottom
>
Create a New Note
</Typography>
</div>
);
}
variant 적용될 태그
component DOM에 올라갈 태그
color 폰트컬러
gutterbottom 텍스트 밑에 마진이 생긴다
편하게 코딩하기 위해 익스텐션
vscode-styled-components 설치
import { styled } from '@mui/material/styles';
const StyledButton = styled(Button)`
font-size: 1rem;
&:hover {
background-color: blue;
}
`;
<StyledButton
// className={classes}
onClick={() => console.log('clicked')}
type='submit'
color='secondary'
variant='contained'
size='large'
endIcon={<KeyboardArrowRightIcon />}
>
Submit
</StyledButton>
기본 설정 되어 있는 테마 : https://mui.com/customization/default-theme/#main-content
import { createTheme, ThemeProvider } from '@mui/material';
import { grey, purple } from '@mui/material/colors';
const theme = createTheme({
status: {
danger: '#e53e3e',
},
palette: {
primary: {
main: '#0971f1',
dark: '#053e85',
},
neutral: {
main: '#64748B',
contrastText: '#fff',
},
secondary: grey,
},
typography: {
fontFamily: 'Hubballi',
fontWeightLight: 400,
fontWeightMedium: 500,
fontWeightRegular: 600,
fontWeightBold: 700,
},
});
<ThemeProvider theme={theme}>
<CustomCheckbox defaultChecked />
</ThemeProvider>
테마를 적용하고 싶은 컴포넌트 위에 ThemeProvider로 덮으면 된다.
@mui/material/colors에 있는 컬러를 이용하면 main,light,dark들도 다 설정된다
index.css
@import url('https://fonts.googleapis.com/css2?family=Hubballi&display=swap');
폰트도 테마로 적용가능하다
테마합치기
import { deepmerge } from '@mui/utils';
import { createTheme } from '@mui/material/styles';
const theme = createTheme(deepmerge(options1, options2));
FormControl,FormLabel RadioGroup FormControlLabel Radio
<StyledForm>
<FormLabel>Note Category</FormLabel>
<RadioGroup
value={category}
onChange={(e) => {
setCategory(e.target.value);
}}
>
<FormControlLabel value='money' control={<Radio />} label='Money' />
<FormControlLabel value='todos' control={<Radio />} label='Todos' />
<FormControlLabel
value='reminders'
control={<Radio />}
label='Reminders'
/>
<FormControlLabel value='work' control={<Radio />} label='Work' />
</RadioGroup>
</StyledForm>
12열의 그리드시스템을 지원한다
반응형 웹을 지원한다.
<Container>
<Grid container>
{notes.map((note) => (
<Grid item xs={12} sm={8} md={4} lg={3} key={note.id}>
<Paper>{note.title}</Paper>
</Grid>
))}
</Grid>
</Container>
Grid container로 감싸고 각 아이템은 Grid item으로 채운다.
xs sm md lg는 각각 화면 크기에 맞춰서 열을 얼마나 채울지 정한다.
<Layout>
<Routes>
<Route path='/' element={<Notes />} />
<Route path='/create' element={<Create />} />
</Routes>
</Layout>
레이아웃 컴포넌트에서 children을 받아서 출력해준다
import { Drawer, Paper, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
const drawerWidth = `240px`;
const StyledDiv = styled('div')`
background-color: #f9f9f9;
width: 100%;
`;
const RootDiv = styled('div')`
display: flex;
`;
const StyledDrawer = styled(Drawer)`
width: ${drawerWidth};
& > div {
width: ${drawerWidth};
}
`;
export default function Layout({ children }) {
return (
<RootDiv>
<StyledDrawer variant='permanent' anchor='left'>
<div>
<Typography variant='h5'>Ninja Notes</Typography>
</div>
</StyledDrawer>
<StyledDiv>{children}</StyledDiv>
</RootDiv>
);
}
<RootDiv>
<StyledDrawer variant='permanent' anchor='left'>
<div>
<Typography variant='h5'>Ninja Notes</Typography>
</div>
<List sx={{ '& .active': { bgcolor: '#e0e0e0' } }}>
{/* <ListItem>
<ListItemText primary='hello'></ListItemText>
</ListItem> */}
{menuitems.map((item, i) => (
<ListItem
key={i}
button
onClick={() => navigate(item.path)}
className={location.pathname === item.path ? 'active' : null}
>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
))}
</List>
</StyledDrawer>
<StyledDiv>{children}</StyledDiv>
</RootDiv>
const StyledDiv = styled('div')`
background-color: #f9f9f9;
width: 100%;
padding: ${(props) => props.theme.spacing(3)};
`;
${} 를 사용하면 StyledDiv의 props를 받아서 사용하가능하다
themeprovider의 자식컴포넌트라면 theme도 불러서 사용가능하다!!!!
const StyledCard = styled(Card)`
border: ${(props) =>
props.note.category === 'reminders' ? '1px solid red' : ''};
`;
<StyledCard elevation={1} note={note}>
{children}
</StyledCard>
.appbar {
width: calc(100% - ${drawerWidth});
.avatar {
margin-left: ${({ theme }) => theme.spacing(2)};
}
}
<AppBar className='appbar' color='default' elevation={0}>
<Toolbar>
<Typography className='date'>
Today is the {format(new Date(), 'do MMMM Y')}
</Typography>
<Typography>Mario</Typography>
<Avatar className='avatar' src='/mario-av.png' />
</Toolbar>
</AppBar>
길이가 다른 리스트 아이템들을 예쁘게 보여줄 수 있다.
const breakpoints = {
default: 3,
1100: 2,
700: 1,
};
const StyledContainer = styled(Container)`
.my-masonry-grid {
/* display: -webkit-box; */
/* display: -ms-flexbox; */
display: flex;
margin-left: -30px;
width: auto;
}
.my-masonry-grid-column {
padding-left: 30px;
background-clip: padding-box;
}
.my-masonry-grid-column > div {
/* background-color: grey; */
margin-bottom: 30px;
}
`;
<Masonry
breakpointCols={breakpoints}
className='my-masonry-grid'
columnClassName='my-masonry-grid-column'
>
{notes.map((note) => (
<div key={note.id}>
<NoteCard note={note} handleDelete={handleDelete} />
</div>
))}
</Masonry>