본문 바로가기

프론트엔드

[에디터1] Next.js 블로그에 ToastUI Editor 장착하기

본 블로그를 처음 만들 때는 mdx파일로 포스팅을 하려하였으나, 이전 블로그 때 매번 편집기를 열어 작성하고 배포하는 것이 귀찮았어서 Editor를 달고자 마음먹었다.

여러 에디터들을 비교해보았는데 UI가 제일 내스타일이어서(어차피 나만 볼 페이지지만) ToastUI의 에디터를 선택하였다.

1. 설치

🔗 toast-ui/react-editor

// yarn 설치
yarn add @toast-ui/editor @toast-ui/react-editor

// npm 설치
npm i --save @toast-ui/editor @toast-ui/react-editor

2. 에디터 컴포넌트 생성

1. toolbar 설정

  • 옵션은 아래와 같고, 이 중 쓸 것만 넣어주면 된다.
toolbarItems: [
    ['heading', 'bold', 'italic', 'strike'],
    ['hr', 'quote'],
    ['ul', 'ol', 'task', 'indent', 'outdent'],
    ['table', 'image', 'link'],
    ['code', 'codeblock'],
    ['scrollSync'],
]

2. 플러그인 설정

  • toastUI는 아래와 같은 플러그인을 제공하며, 나는 color-syntax, code-syntax-highlight만 설치해서 사용했다.

플러그인 명패키지 명설명

chart @toast-ui/editor-plugin-chart 차트를 렌더링하기 위한 플러그인
code-syntax-highlight @toast-ui/editor-plugin-code-syntax-highlight 코드 하이라이팅을 위한 플러그인
color-syntax @toast-ui/editor-plugin-color-syntax 컬러피커 사용을 위한 플러그인
table-merged-cell @toast-ui/editor-plugin-table-merged-cell 병합 테이블 셀을 사용하기 위한 플러그인
uml @toast-ui/editor-plugin-uml UML 사용을 위한 플러그인

🎨 code-syntax-highlight 설정

  1. 패키지 설치
  2. // yarn 설치
    yarn add  @toast-ui/editor-plugin-code-syntax-highlight
    
    // npm 설치
    npm i  @toast-ui/editor-plugin-code-syntax-highlight
  3. import혹시나 타입스크립트에서 prismjs를 불러오지 못한다면, 타입을 다운받으면 된다.
  4.  yarn add @types/prismjs      
  5. import 'prismjs/themes/prism.css'
    import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight'
    import '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css'
    import Prism from 'prismjs'
  6. 사용
     <Editor
         ...
          plugins={[colorSyntax, [codeSyntaxHighlight, { highlighter: Prism }]]}
     />
  7. plugins에 아래와 같이 넣어준다.

3. 에디터 컴포넌트

'use client';
import { MutableRefObject, useEffect, useState } from 'react';
import '@toast-ui/editor/dist/toastui-editor.css';
import { Editor } from '@toast-ui/react-editor';
import colorSyntax from '@toast-ui/editor-plugin-color-syntax'
import { PreviewStyle } from '@toast-ui/editor';

const toolbarItems = [
    ['heading', 'bold', 'italic', 'strike'],
    ['hr'],
    ['ul', 'ol', 'task'],
    ['table', 'link'],
    ['image'],
    ['code', 'codeblock'],
    ['scrollSync'],
];

interface Props {
  editorRef: React.RefObject<Editor>
  images?: MutableRefObject<Images[]> // 글수정 시 필요
  initialValue?: string // 글수정 시 필요
}
}

export default function MyEditor({ editorRef, images, initialValue }: Props) {
  return (
    <>
        {
          editorRef && 
            <Editor
              ref={editorRef}
                  initialValue=''
                  initialEditType="markdown"
                  previewStyle='vertical' // tab || vertical
                  hideModeSwitch={true}
                  height="calc(100vh - 380px)"
                  theme={''} // '' & 'dark'
                  usageStatistics={false}
                  toolbarItems={toolbarItems}
                  useCommandShortcut={true}
                  plugins={[colorSyntax, [codeSyntaxHighlight, { highlighter: Prism }]]} 
                  hooks={{ addImageBlobHook: onUploadImage }} // firebase 이미지 업로드
            />
        }
    </>
  )
}

4. Editor 미리보기 반응형으로 만들기

  • previewStyle이 vertical일 경우 에디터 오른편에 미리보기가 바로 나오게 되고, tab일 경우 상단 탭에서 미리보기화면을 선택할 수 있다. 화면이 클 때는 오른쪽에서 바로바로 보이고, 작을 경우에는 탭을 클릭하여 확인하면 좋을 것 같아서 반응형으로 만들었다.
    import { MutableRefObject, useEffect, useState } from 'react';
    import { PreviewStyle } from '@toast-ui/editor';
    
    // 1. 브라우저 사이즈변경에 따른 상태변경을 위해 state작성
    const [ preview, setPreview ] = useState<PreviewStyle>(window.innerWidth > 1000 ? 'vertical' : 'tab')
 
    // 2. 함수 실행시 마다 브라우저 사이즈에 따라 preview 상태 변경
    const handleResize = () => {
        setPreview(window.innerWidth > 1000 ? 'vertical' : 'tab')
    }

    // 3. resize이벤트 구독
    useEffect(() => {
        window.addEventListener('resize', handleResize)

        return () => {
            window.removeEventListener('resize', handleResize)
        }
    }, [])
  
    ...
   
    return (
    <>
        {
          editorRef && 
            <Editor
              ref={editorRef}
              initialValue=''
              initialEditType="markdown"
              previewStyle={preview} // 4. preview state 사용
              ...
            />
        }
    </>
  )

👉🏽 결과