24 게시글 페이지 구현하기 - 마크다운 형식의 포스트 출력하기

source: categories/study/gatsby/gatsby_9-15.md

Gatsby에서 마크다운 문서는 어떻게 출력할까?

저렇게 마크다운 문법으로 작성된 글을 화면에 출력하려고 하니 기능이 되게 복잡할 것 같지만, 대부분의 핵심 기능은 모두 Gatsby에서 처리해주기 때문에 저희가 구현할 부분은 많지 않습니다.

예전에 게시글 템플릿 컴포넌트를 구현하며 html 속성을 쿼리했었는데 기억하시나요?

저희가 쿼리한 html 속성에 마크다운 문법으로 작성된 글이 모두 HTML 태그로 변환되어 문자열 형태로 저장되어 있습니다.

따라서 각 태그의 스타일을 지정해준 후, 문자열 형태의 HTML 요소들을 출력해주면 됩니다.

마크다운 게시글 출력 컴포넌트 구현하기

Post 디렉토리에 PostContent.tsx 파일을 생성한 후, 다음과 같이 코드를 추가해주세요.

  • src/components/Post/PostContent.tsx
import React, { FunctionComponent } from 'react'
import styled from '@emotion/styled'

interface PostContentProps {
  html: string
}

const MarkdownRenderer = styled.div`
  // Renderer Style
  display: flex;
  flex-direction: column;
  width: 768px;
  margin: 0 auto;
  padding: 100px 0;
`

const PostContent: FunctionComponent<PostContentProps> = function ({ html }) {
  return <MarkdownRenderer dangerouslySetInnerHTML= />
}

export default PostContent

문자열 형태의 HTML 코드를 출력하는 것도 dangerouslySetInnerHTML 속성을 통해 간단하게 구현이 가능합니다.

그럼 이제 템플릿 컴포넌트에서 이를 불러와 적용해봅시다.

  • src/templates/post_template.tsx
// ...

import PostContent from 'components/Post/PostContent'

// ...

const PostTemplate: FunctionComponent<PostTemplateProps> = function ({
  data: {
    allMarkdownRemark: { edges },
  },
}) {
  const {
    node: {
      html,
      frontmatter: {
        title,
        summary,
        date,
        categories,
        thumbnail: {
          childImageSharp: { gatsbyImageData },
        },
      },
    },
  } = edges[0]

  return (
    <Template>
      <PostHead
        title={title}
        date={date}
        categories={categories}
        thumbnail={gatsbyImageData}
      />
      <PostContent html={html} />
    </Template>
  )
}

// ...

여기까지 한 후, 로컬 서버를 실행해 결과를 확인해보시면 마크다운 데이터가 잘 출력된 것을 볼 수 있습니다.

마크다운 커스텀 스타일 적용하기

여기까지만 하면 마크다운 데이터가 잘 출력되지만, 아무런 스타일도 설정하지 않았기 때문에 깔끔하게 출력되지는 않을 것입니다.

따라서 아래와 같이 마크다운 스타일을 PostContent 컴포넌트에 추가해줍시다.

  • src/components/Post/PostContent.tsx
// ...

const MarkdownRenderer = styled.div`
  // Renderer Style
  display: flex;
  flex-direction: column;
  width: 768px;
  margin: 0 auto;
  padding: 100px 0;
  word-break: break-all;

  // Markdown Style
  line-height: 1.8;
  font-size: 16px;
  font-weight: 400;

  // Apply Padding Attribute to All Elements
  p {
    padding: 3px 0;
  }

  // Adjust Heading Element Style
  h1,
  h2,
  h3 {
    font-weight: 800;
    margin-bottom: 30px;
  }

  * + h1,
  * + h2,
  * + h3 {
    margin-top: 80px;
  }

  hr + h1,
  hr + h2,
  hr + h3 {
    margin-top: 0;
  }

  h1 {
    font-size: 30px;
  }

  h2 {
    font-size: 25px;
  }

  h3 {
    font-size: 20px;
  }

  // Adjust Quotation Element Style
  blockquote {
    margin: 30px 0;
    padding: 5px 15px;
    border-left: 2px solid #000000;
    font-weight: 800;
  }

  // Adjust List Element Style
  ol,
  ul {
    margin-left: 20px;
    padding: 30px 0;
  }

  // Adjust Horizontal Rule style
  hr {
    border: 1px solid #000000;
    margin: 100px 0;
  }

  // Adjust Link Element Style
  a {
    color: #4263eb;
    text-decoration: underline;
  }

  // Adjust Code Style
  pre[class*='language-'] {
    margin: 30px 0;
    padding: 15px;
    font-size: 15px;

    ::-webkit-scrollbar-thumb {
      background: rgba(255, 255, 255, 0.5);
      border-radius: 3px;
    }
  }

  code[class*='language-'],
  pre[class*='language-'] {
    tab-size: 2;
  }
`

// ...

가장 많이 사용되는 태그의 스타일을 위와 같이 지정해주었습니다.

여기까지 한 후, 마크다운 파일에서 여러 문법을 사용해 글을 작성하고 로컬 서버상에서 확인해보세요.