From b3ed819fd60062f139fe532d1ae40b91834a9285 Mon Sep 17 00:00:00 2001 From: Suk Woo Date: Mon, 26 Aug 2024 12:50:14 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20#63=20=EB=A7=88=ED=81=AC=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=EC=BD=94=EB=93=9C=20=EB=B8=94=EB=A1=9D=20=ED=95=98?= =?UTF-8?q?=EC=9D=B4=EB=9D=BC=EC=9D=B4=ED=8C=85=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#86)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Config: #63 ESLint 설정 추가 (no-cond-assign: off) * Config: #63 @types/react-syntax-highlighter 추가 * Feat: #63 코드 블록 하이라이팅 기능 추가 * Fix: #63 인라인 코드와 코드 블록 분기 처리 수정 * Feat: #63 markdown 개행 처리를 위한 기능 추가 --- .eslintrc.cjs | 1 + package.json | 1 + src/components/common/CustomMarkdown.tsx | 56 +++++-- src/constants/language.ts | 203 +++++++++++++++++++++++ yarn.lock | 7 + 5 files changed, 253 insertions(+), 15 deletions(-) create mode 100644 src/constants/language.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b3474b60..5b41f91e 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -25,6 +25,7 @@ module.exports = { 'no-param-reassign': 'warn', 'no-return-assign': 'warn', 'no-unused-vars': 'warn', + 'no-cond-assign': 'off', 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', 'react/require-default-props': 'off', diff --git a/package.json b/package.json index 46f14412..4231414a 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@types/react": "^18.3.2", "@types/react-big-calendar": "^1.8.9", "@types/react-dom": "^18.3.0", + "@types/react-syntax-highlighter": "^15.5.13", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", "@vitejs/plugin-react-swc": "^3.5.0", diff --git a/src/components/common/CustomMarkdown.tsx b/src/components/common/CustomMarkdown.tsx index 62b8563a..f9373f22 100644 --- a/src/components/common/CustomMarkdown.tsx +++ b/src/components/common/CustomMarkdown.tsx @@ -1,7 +1,10 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; +import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { hybrid } from 'react-syntax-highlighter/dist/esm/styles/hljs'; +import { languageMap } from '@constants/language'; import type { Components } from 'react-markdown'; type CustomMarkdownProps = { @@ -14,29 +17,29 @@ const component: Partial = { return ( <>

{children}

-
+
); }, h2(props) { const { children } = props; - return

{children}

; + return

{children}

; }, h3(props) { const { children } = props; - return

{children}

; + return

{children}

; }, h4(props) { const { children } = props; - return

{children}

; + return

{children}

; }, h5(props) { const { children } = props; - return

{children}

; + return

{children}

; }, h6(props) { const { children } = props; - return

{children}

; + return

{children}

; }, hr() { return
; @@ -51,15 +54,15 @@ const component: Partial = { }, img(props) { const { src, alt } = props; - return {alt}; + return {alt}; }, blockquote(props) { const { children } = props; - return
{children}
; + return
{children}
; }, table(props) { const { children } = props; - return {children}
; + return {children}
; }, th(props) { const { children, style } = props; @@ -118,17 +121,40 @@ const component: Partial = { return
{children}
; }, code(props) { - const { children, className } = props; - return {children}; + const { children, className, node } = props; + const language = className?.split('-')[1] || ''; + const mappedLanguage = languageMap[language] || 'plaintext'; + + if (!language && node?.position?.start.line === node?.position?.end.line) { + return {children}; + } + return ( + + {children as string} + + ); }, }; +function getChangedMarkdownForLineBreak(markdown: string) { + return markdown + .split('\n') + .map((sentence) => (sentence === '' ? '\n
\n' : sentence)) + .join('\n'); +} + export default function CustomMarkdown({ markdown }: CustomMarkdownProps) { + const changedMarkdown = useMemo(() => getChangedMarkdownForLineBreak(markdown), [markdown]); + return (
- - {markdown} - + {markdown.trim().length === 0 ? ( +
입력된 내용이 없습니다.
+ ) : ( + + {changedMarkdown} + + )}
); } diff --git a/src/constants/language.ts b/src/constants/language.ts new file mode 100644 index 00000000..60890ce9 --- /dev/null +++ b/src/constants/language.ts @@ -0,0 +1,203 @@ +export const languageMap: { [key: string]: string } = { + oneC: '1c', + '1c': '1c', + abnf: 'abnf', + accesslog: 'accesslog', + actionscript: 'actionscript', + ada: 'ada', + angelscript: 'angelscript', + apache: 'apache', + applescript: 'applescript', + arcade: 'arcade', + arduino: 'arduino', + armasm: 'armasm', + asciidoc: 'asciidoc', + aspectj: 'aspectj', + autohotkey: 'autohotkey', + autoit: 'autoit', + avrasm: 'avrasm', + awk: 'awk', + axapta: 'axapta', + bash: 'bash', + basic: 'basic', + bnf: 'bnf', + brainfuck: 'brainfuck', + cLike: 'c-like', + 'c-like': 'c-like', + c: 'c', + cal: 'cal', + capnproto: 'capnproto', + ceylon: 'ceylon', + clean: 'clean', + clojureRepl: 'clojure-repl', + 'clojure-repl': 'clojure-repl', + clojure: 'clojure', + cmake: 'cmake', + coffeescript: 'coffeescript', + coq: 'coq', + cos: 'cos', + cpp: 'cpp', + crmsh: 'crmsh', + crystal: 'crystal', + csharp: 'csharp', + csp: 'csp', + css: 'css', + d: 'd', + dart: 'dart', + delphi: 'delphi', + diff: 'diff', + django: 'django', + dns: 'dns', + dockerfile: 'dockerfile', + dos: 'dos', + dsconfig: 'dsconfig', + dts: 'dts', + dust: 'dust', + ebnf: 'ebnf', + elixir: 'elixir', + elm: 'elm', + erb: 'erb', + erlangRepl: 'erlang-repl', + 'erlang-repl': 'erlang-repl', + erlang: 'erlang', + excel: 'excel', + fix: 'fix', + flix: 'flix', + fortran: 'fortran', + fsharp: 'fsharp', + gams: 'gams', + gauss: 'gauss', + gcode: 'gcode', + gherkin: 'gherkin', + glsl: 'glsl', + gml: 'gml', + go: 'go', + golo: 'golo', + gradle: 'gradle', + groovy: 'groovy', + haml: 'haml', + handlebars: 'handlebars', + haskell: 'haskell', + haxe: 'haxe', + hsp: 'hsp', + htmlbars: 'htmlbars', + http: 'http', + hy: 'hy', + inform7: 'inform7', + ini: 'ini', + irpf90: 'irpf90', + isbl: 'isbl', + java: 'java', + js: 'javascript', + javascript: 'javascript', + jbossCli: 'jboss-cli', + 'jboss-cli': 'jboss-cli', + json: 'json', + juliaRepl: 'julia-repl', + 'julia-repl': 'julia-repl', + julia: 'julia', + kotlin: 'kotlin', + lasso: 'lasso', + latex: 'latex', + ldif: 'ldif', + leaf: 'leaf', + less: 'less', + lisp: 'lisp', + livecodeserver: 'livecodeserver', + livescript: 'livescript', + llvm: 'llvm', + lsl: 'lsl', + lua: 'lua', + makefile: 'makefile', + markdown: 'markdown', + mathematica: 'mathematica', + matlab: 'matlab', + maxima: 'maxima', + mel: 'mel', + mercury: 'mercury', + mipsasm: 'mipsasm', + mizar: 'mizar', + mojolicious: 'mojolicious', + monkey: 'monkey', + moonscript: 'moonscript', + n1ql: 'n1ql', + nginx: 'nginx', + nim: 'nim', + nix: 'nix', + nodeRepl: 'node-repl', + 'node-repl': 'node-repl', + nsis: 'nsis', + objectivec: 'objectivec', + ocaml: 'ocaml', + openscad: 'openscad', + oxygene: 'oxygene', + parser3: 'parser3', + perl: 'perl', + pf: 'pf', + pgsql: 'pgsql', + phpTemplate: 'php-template', + 'php-template': 'php-template', + php: 'php', + plaintext: 'plaintext', + pony: 'pony', + powershell: 'powershell', + processing: 'processing', + profile: 'profile', + prolog: 'prolog', + properties: 'properties', + protobuf: 'protobuf', + puppet: 'puppet', + purebasic: 'purebasic', + pythonRepl: 'python-repl', + 'python-repl': 'python-repl', + python: 'python', + q: 'q', + qml: 'qml', + r: 'r', + reasonml: 'reasonml', + rib: 'rib', + roboconf: 'roboconf', + routeros: 'routeros', + rsl: 'rsl', + ruby: 'ruby', + ruleslanguage: 'ruleslanguage', + rust: 'rust', + sas: 'sas', + scala: 'scala', + scheme: 'scheme', + scilab: 'scilab', + scss: 'scss', + shell: 'shell', + smali: 'smali', + smalltalk: 'smalltalk', + sml: 'sml', + sqf: 'sqf', + sql: 'sql', + stan: 'stan', + stata: 'stata', + step21: 'step21', + stylus: 'stylus', + subunit: 'subunit', + swift: 'swift', + taggerscript: 'taggerscript', + tap: 'tap', + tcl: 'tcl', + thrift: 'thrift', + tp: 'tp', + twig: 'twig', + typescript: 'typescript', + vala: 'vala', + vbnet: 'vbnet', + vbscriptHtml: 'vbscript-html', + 'vbscript-html': 'vbscript-html', + vbscript: 'vbscript', + verilog: 'verilog', + vhdl: 'vhdl', + vim: 'vim', + x86asm: 'x86asm', + xl: 'xl', + xml: 'xml', + xquery: 'xquery', + yaml: 'yaml', + zephir: 'zephir', +}; diff --git a/yarn.lock b/yarn.lock index 15d1e8d7..81c2b3fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -765,6 +765,13 @@ dependencies: "@types/react" "*" +"@types/react-syntax-highlighter@^15.5.13": + version "15.5.13" + resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz#c5baf62a3219b3bf28d39cfea55d0a49a263d1f2" + integrity sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@>=16.9.11", "@types/react@^18.3.2": version "18.3.2" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz"