4. Appbar, 메인 페이지 작업하기
백엔드와 어떻게 통신해야 할까?
나름 로고도 만들었으니, 로고가 들어갈 자리가 있어야 한다.
현재 스크린에서 가장 간단 명료하게 정보를 보여줄 수 있는 App bar를 이용한다.
Appbar 커스터마이징
Material-UI에서 기본 제공해주는 Appbar도 좋지만, 너무 모바일스러워서 커스터마이징하기로 했다
이곳에 로고를 넣고, 이후 필요한 버튼이 있다면 추가할 생각이다.
일단 레이아웃부터 변경하도록 하자.
// file: 'AppbarLayout.tsx'
import MuiAppBar, { AppBarProps } from '@material-ui/core/AppBar';
export default function AppBar(children: AppBarProps) {
return <MuiAppBar elevation={0} position="static" {...children} />;
}
props
로 AppBarProps
타입의 매개변수를 받는다.
spread operator
를 사용해 여러 개의 props
를 받아, MuiAppbar
의 속성을 오버라이드할 수 있도록 했다.
elevation={0}
은 말 그대로 고도가 0인 상태로, z축이 부모와 상대적으로 얼마나 떨어져 있어야 하는지를 나타낸다.
앞으로 튀어나와 있을 필요는 없으니까 0으로!
다음은 레이아웃을 바탕으로 AppBar
를 디자인해보자.
// file: 'Appbar.tsx'
interface Props extends WithStyles<typeof astyles> {}
const astyles = (theme: Theme) => ({
placeholder: toolbarStyles(theme).root,
toolbar: {
justifyContent: 'space-between',
},
right: {
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
},
langIcon: {
marginLeft: theme.spacing(2),
maxWidth: "48px",
},
left: {
flex: 1,
},
logo: {
marginTop: theme.spacing(1),
maxWidth: "300px",
}
});
...
저번에 배웠던 것처럼, 함수형 컴포넌트에 styles
을 주기 위해 인터페이스를 선언했다.
선언한 astyles
는 CSS와 굉장히 비슷하게 보이는데, 부모의 스타일을 오버라이드해서 적용시켰다.
// file: 'Appbar.tsx'
function AppBarView (props: Props) {
const { classes } = props;
return (
<div>
<AppBar position="fixed">
<Toolbar className={classes.toolbar}>
<div className={classes.left} />
<Link
variant="h3"
underline="none"
color="inherit"
href="/jchecker"
>
<img src="/assets/logo.png" alt="logo" className={classes.logo} />
</Link>
<div className={classes.right}>
<Button className={classes.langIcon} onClick={() => handleChangeLang('ko')}>
<img src="/assets/kor.svg" alt="kor" />
</Button>
<Button className={classes.langIcon} onClick={() => handleChangeLang('en')}>
<img src="/assets/eng.svg" alt="eng" />
</Button>
</div>
</Toolbar>
</AppBar>
<div className={classes.placeholder} />
</div>
);
}
Toolbar
컴포넌트는 Material-UI에서 기본 제공하는 컴포넌트에 반응형 코드만 조금 첨가해서 고대로 사용했다.
스타일을 주고싶은 컴포넌트에 className
에 대한 값으로 넘겨줬으며,
로고에는 Link
컴포넌트를 이용해 홈으로 이동하도록 만들었다.
메인 페이지 완성하기
이전에 레이아웃을 만들었으니, 이제 이를 이용해서 각 컴포넌트를 조합해 넣어주면 될 것 같다.
내용은 최대한 보기 쉽게, 시각적으로 이해할 수 있도록 목표를 잡았다.
설계대로 일단 3개의 컴포넌트를 각각 따로 만들었다.
첫 번째 페이지부터!
// file: 'SectionMain.tsx'
// 스타일 주는 것은 생략
function SectionMain(props: Props) {
const { classes } = props;
const handleBottom = () => {
window.scrollTo({top: 1800, left: 0, behavior: 'smooth'});
}
return (
<SectionLayout backgroundClassName={classes.background}>
{}
<img style= src={backgroundImage} alt="prioirty" />
<Typographic color="inherit" align="center" variant="h2" marked="center">
JUDGE YOUR ASSIGNMENTS
</Typographic>
<Typographic color="inherit" align="center" variant="h5" className={classes.h5}>
We provide OOP-based Java program scoring service through static analysis.
</Typographic>
<Button
color="secondary"
variant="contained"
size="medium"
className={classes.button}
onClick={handleBottom}
>
{t('start_button')}
</Button>
<Typographic variant="body2" color="inherit" className={classes.more}>
with ISEL, HGU.
</Typographic>
</SectionLayout>
);
}
export default withStyles(styles)(SectionMain);
원래 버튼의 목적은 바로 토큰을 넣는 페이지로 이동시키는 것이었으나,
사용자가 메인 페이지를 스크롤 다운 하면서 서비스가 어떻게 동작하고
어떻게 이용해야 하는지 간단하게 봐 줬으면 좋겠다는 생각에 자동 스크롤로 변경했다.
🔥 근데 window.scrollTo()
를 이용해서 매뉴얼하게 코드를 작성한 것이 아쉬운 부분이다.
저렇게 하면 사용자의 브라우저 크기에 따라 footer
까지 내려가버리기도 해서…
스프링은 되던데, 어떻게 변경할 수 있을지 고민해봐야겠다.
렌더링된 메인 페이지의 첫 번째 컴포넌트가 완성됐다!
다음은 두 번째, 간단하게 동작 방식을 적어놓을 컴포넌트다.
// file: 'SectionDetail.tsx'
// 스타일 주는 것은 생략
function SectionDetail(props: Props) {
const { classes } = props;
return (
<section className={classes.root}>
<Container className={classes.container}>
<img
src="assets/hologram.png"
className={classes.hologram}
alt="back hologram"
/>
<Typographic variant="h4" marked="center" className={classes.title} component="h2">
How the service works
</Typographic>
<div>
<Grid container spacing={5}>
<Grid item xs={12} md={4}>
<div className={classes.item}>
<div className={classes.number}>1.</div>
<img
src="assets/file_add.svg"
alt="file_add"
className={classes.image}
/>
<Typographic variant="h5" align="center">
글 넣는 곳
</Typographic>
</div>
</Grid>
<Grid item xs={12} md={4}>
<div className={classes.item}>
<div className={classes.number}>2.</div>
<img
src="assets/executing.svg"
alt="execute"
className={classes.image}
/>
<Typographic variant="h5" align="center">
글 넣는 곳
</Typographic>
</div>
</Grid>
<Grid item xs={12} md={4}>
<div className={classes.item}>
<div className={classes.number}>3.</div>
<img
src="assets/diagram.svg"
alt="file_add"
className={classes.image}
/>
<Typographic variant="h5" align="center">
글 넣는 곳
</Typographic>
</div>
</Grid>
</Grid>
</div>
</Container>
</section>
)
}
export default withStyles(styles)(SectionDetail);
처음에는 첫 번째 페이지와 동일하게 코드를 작성했으나,
Grid
로 구역을 나눠서 출력하니 위 페이지와 차별화되면서 한 눈에 와닿았다.
이 부분은 별로 어려울 게 없었지만, 구간을 보기 편하게 정렬하느라 여러 번 고친 컴포넌트 되시겠다.
결과물은 이렇다.
목표는 채점 결과를 그래프 / 차트 라이브러리를 사용해 시각적으로 보여주는 것이지만,
아직까지는 유동적이다. (뭐가 더 알아보기 쉬울지 고민 중에 있다🤔)
마지막은 토큰 인증 페이지로 갈 수 있도록 해주는 컴포넌트여야 한다.
// file: 'SectionBegin.tsx'
// 스타일 주는 것은 생략
function SectionBegin(props: Props) {
const { classes } = props;
return (
<SectionLayout backgroundClassName={classes.background}>
<img style= src={backgroundImage} alt="priority" />
<Typographic color="inherit" align="center" variant="h1" marked="center">
{t('begin.getting start')}
</Typographic>
<Typographic color="inherit" align="center" variant="h5" className={classes.h5}>
<Link href="/jchecker/classes" color="secondary">
인증 페이지로 가기
</Link>
글 넣는 곳
</Typographic>
</SectionLayout>
)
}
export default withStyles(styles)(SectionBegin);
버튼을 넣을까 하다가 이미 첫 번째에 넣었으니까 링크로 대체했다. 더 깔끔한 것 같기도 하고.
Link
컴포넌트를 임포트해 사용했으며, 누르면 지정한 링크 /jchecker/classses
로 이동하게 된다.
이로써 Appbar와 메인 페이지, 즉 웹 서비스 시 가장 먼저 보이는 페이지를 완성했다.
아무래도 채점 서비스다 보니, 사용자에게 신뢰성을 줄 수 있게 만드려고 노력했던 것 같다..! 난 노력했다는 이야기
🔥 TroubleShooting & Review
Issue:
- 저렇게 3개의 컴포넌트를 따로 만들어서, Appbar와 3개의 메인 컴포넌트, Footer까지
Home.tsx
에서 합쳤다. 이렇게 만드는 게 효율적인지 잘 모르겠지만 문제가 생겼을 때 파악이 쉬웠다.
Review
- Material-UI를 본격적으로 사용하게 되는 시점인데, 예제 코드를 그대로 갖다 쓰는 게 아니라 코드 리뷰에 꽤 많은 시간을 들였다
- 시간 가는 줄 모르고 코드 작성했던 것 같다. 아무래도 예상한 대로 예쁘게 나오니까 너무 즐겁더라구…🥺
- 구글링을 열심히 하다가
tsx vs. ts
라는 글을 봤다.TSX
방식으로 코드를 작성하는 것이 좋은지,TS + HTML
로 작성하는 것이 좋은지… 성능에 굉장히 관심이 많은 나로서는 정말 궁금한 주제다…!결론이 모호해서 더 궁금하다