1-3. PostList 페이지 UI 구현

이번에는 PostList 페이지에서 필요한 유저인터페이스를 구현하겠습니다. 이 페이지에서는 포스트 목록에 관련된 컴포넌트들이 사용됩니다. 이전에 우리가 공용되는 컴포넌트들은 common 디렉토리에 넣었던 것 처럼, PostList 에서 보여지는 컴포넌트들은 list 라는 디렉토리에 만들어주겠습니다.

components 디렉토리에 list 디렉토리를 만들고, 내부에 다음 컴포넌트들을 만드세요:

  • ListWrapper: 페이지 내부의 컴포넌트들을 감싸줍니다
  • Pagination: 다음 / 이전 페이지로 이동을 해줍니다
  • PostList: 포스트의 목록을 보여줍니다

ListWrapper 컴포넌트

ListWrapper 컴포넌트는 내용을 페이지의 중앙에 정렬시켜주고, 위 아래에 패딩이 설정되어있으며, 브라우저의 크기에 따라 사이즈가 조정됩니다. 컴포넌트를 감싸는 역할을 하므로, 내부에 children 을 렌더링하세요.

src/components/list/ListWrapper/ListWrapper.js

import React from 'react';
import styles from './ListWrapper.scss';
import classNames from 'classnames/bind';

const cx = classNames.bind(styles);

const ListWrapper = ({children}) => (
  <div className={cx('list-wrapper')}>
    {children}
  </div>
);

export default ListWrapper;

src/components/list/ListWrapper/ListWrapper.scss

@import 'utils';

.list-wrapper {
  width: 1024px;
  margin: 0 auto;

  padding-top: 3rem;
  padding-bottom: 3rem;
  padding-left: 1rem;
  padding-right: 1rem;

  @include media("<wide") {
    width: 768px;
  }
  @include media("<large") {
    width: 512px;
  }
  @include media("<medium") {
    width: 100%;
  }
}

그 다음엔, 이 컴포넌트를 ListPage 에 렌더링 하세요.

src/pages/ListPage.js

import React from 'react';
import PageTemplate from 'components/common/PageTemplate';
import ListWrapper from 'components/list/ListWrapper';

const ListPage = () => {
  return (
    <PageTemplate>
      <ListWrapper>
        리스트
      </ListWrapper>
    </PageTemplate>
  );
};

export default ListPage;

PostList 컴포넌트

이번에는 PostList 컴포넌트를 만들어보겠습니다. 이 컴포넌트는, 블로그 포스트 목록 데이터를 받아온 후, 이를 렌더링 해줍니다.

이 과정에서, 우리는 PostItem 이라는 컴포넌트를 PostList 컴포넌트 내부에 만들어주고, 이를 반복적으로 렌더링해주겠습니다.

지금은, UI 만 만드는 과정이기 때문에, 더미 데이터를 입력하여 보여주세요.

src/components/list/PostList/PostList.js

import React from 'react';
import styles from './PostList.scss';
import classNames from 'classnames/bind';
import { Link } from 'react-router-dom';

const cx = classNames.bind(styles);

const PostItem = () => {
  return (
    <div className={cx('post-item')}>
      <h2><a>타이틀</a></h2>
      <div className={cx('date')}>2017-10-24</div>
      <p>내용</p>
      <div className={cx('tags')}>
        <a>#태그</a>
        <a>#태그</a>
        <a>#태그</a>
      </div>
    </div>
  )
}
const PostList = () => (
  <div className={cx('post-list')}>
    <PostItem/>
    <PostItem/>
    <PostItem/>
    <PostItem/>
  </div>
);

export default PostList;

스타일링도 해볼까요?

src/components/list/PostList/PostList.scss

@import 'utils';

.post-list {
  .post-item {
    padding: 1.5rem;
    transition: all .15s ease-in;
    h2 {
      font-size: 2rem;
      font-weight: 400;
      margin: 0;
      color: $oc-gray-8;
      a {
        transition: all .15s ease-in; // 스타일 바뀔 때 애니메이션 효과
        border-bottom: 1px solid transparent;
      }
      a:hover {
        color: $oc-blue-6;
        // 마우스 호버시 밑줄 (밑줄과 글자 사이 여백, 얇은 밑줄을 위해 border-bottom 사용)
        border-bottom: 1px solid $oc-blue-6; 
      }
    }
    .date {
      font-size: 0.85rem;
      color: $oc-gray-5;
    }
    p {
      font-weight: 300;
      color: $oc-gray-7;
    }
    .tags {
      font-size: 0.85rem;
      color: $oc-blue-6;
      a {
        &:hover {
          color: $oc-blue-5;
          text-decoration: underline;
        }
      }
      a + a { // 태그 사이 여백
        margin-left: 0.25rem;
      }
    }
    &:hover {
      // 호버시 배경색 변경
      background: rgba($oc-blue-6, 0.05);
    }
  }
  .post-item + .post-item { // 아이템 사이 여백
    border-top: 1px solid $oc-gray-3;
  }
}

이제 이 컴포넌트를 ListPage 에 불러와서 ListWrapper 내부에 렌더링하세요.

src/pages/ListPage.js

import React from 'react';
import PageTemplate from 'components/common/PageTemplate';
import ListWrapper from 'components/list/ListWrapper';
import PostList from 'components/list/PostList';

const ListPage = () => {
  return (
    <PageTemplate>
      <ListWrapper>
        <PostList/>
      </ListWrapper>
    </PageTemplate>
  );
};

export default ListPage;

아까 봤던 PostList 미리보기와 동일하게 나타났나요?

Pagination 컴포넌트

이번엔, ListPage 가 지니고있는 마지막 컴포넌트인 Pagination 을 만들어보겠습니다.

이 컴포넌트에는 양쪽에 두개의 버튼이 있고, 중간에는 페이지가 있습니다. 첫번째 페이지를 보고있을 때는, 왼쪽의 버튼이 비활성화 되며, 마지막 페이지를 보고있을 때는 오른쪽 버튼이 비활성화됩니다.

src/components/list/Pagination/Pagination.js

import React from 'react';
import styles from './Pagination.scss';
import classNames from 'classnames/bind';
import Button from 'components/common/Button';

const cx = classNames.bind(styles);

const Pagination = () => (
  <div className={cx('pagination')}>
    <Button disabled>
      이전 페이지
    </Button>
    <div className={cx('number')}>
      페이지 1
    </div>
    <Button>
      다음 페이지
    </Button>
  </div>
);

export default Pagination;

우리가 이전에, 버튼의 theme 값을 지정해주지 않으면, 파란색으로 나타나게 했고, disabled 값이 true 가 되면 버튼을 비활성화시켜서 회색으로 나타나게 했습니다.

첫번째 버튼에 disabled 를 넣으세요. JSX 에서 따로 값을 설정하지 않고 props 명만 넣어주면 자동으로 disabled={true} 로 설정 됩니다.

그 다음엔 이 컴포넌트를 스타일링해주겠씁니다. Flex 를 사용하여 엘리먼트들을 세로 중앙 정렬을 하고, 페이지가 나타나는 부분에 flex:1 을 설정하여 양옆 버튼 사이즈를 제외한 사이즈를 꽉 채워서 버튼이 페이지의 양 끝에 보여지게 하겠습니다.

src/list/Pagination/Pagination.scss

@import 'utils';
.pagination {
  margin-top: 2rem;

  // 세로 중앙 정렬
  display: flex;
  align-items: center;

  .number {
    font-size: 0.85rem;
    text-align: center;
    color: $oc-gray-6;
    flex: 1; // 남은 공간을 다 차지
  }
}

이제 이 컴포넌트를 ListPage 에서 PostList 하단에 렌더링하겠습니다.

src/pages/ListPage.js

import React from 'react';
import PageTemplate from 'components/common/PageTemplate';
import ListWrapper from 'components/list/ListWrapper';
import PostList from 'components/list/PostList';
import Pagination from 'components/list/Pagination';

const ListPage = () => {
  return (
    <PageTemplate>
      <ListWrapper>
        <PostList/>
        <Pagination/>
      </ListWrapper>
    </PageTemplate>
  );
};

export default ListPage;

ListPage 를 저장하고, 컴포넌트들이 모두 제대로 나타나는지 확인하세요.

이제 List 페이지에서 필요한 컴포넌트들의 모양새를 갖추었습니다. 이어서, Post 페이지와 Editor 페이지에서 사용하는 컴포넌트들의 유저인터페이스를 만들고 그 다음에 실제 기능들을 붙여봅시다.

results matching ""

    No results matching ""