-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* New : QuillEditor, Quill-mention, Dompurify 추가 * New : Quill에디터 구현 * New : Quill에디터 구현 * Refactor : 사용하지 않는 모듈 제거 * New : Quill에디터 적용 * Minor : 브라우저 기본스타일 제거 * New : 태그 리스트를 검색하는 쿼리 추가
- Loading branch information
1 parent
ad23935
commit f22ee31
Showing
9 changed files
with
785 additions
and
151 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
"use client"; | ||
import React, { useCallback, useState, memo, useEffect } from "react"; | ||
import ReactQuill from "react-quill"; | ||
import "./quill.core.css"; | ||
import "quill-mention"; | ||
import "./quill.mention.css"; | ||
import { Typography } from "@mui/material"; | ||
import { sanitize } from "isomorphic-dompurify"; | ||
|
||
interface NewPostTextEditorInterface { | ||
onContentChange: (props: { content: string; tagList: string[] }) => void; | ||
} | ||
|
||
const NewPostTextEditor = ({ onContentChange }: NewPostTextEditorInterface) => { | ||
const [mentioningValue, setMentioningValue] = useState(""); | ||
|
||
const [tagList, setTagList] = useState<string[]>([]); | ||
|
||
const [content, setContent] = useState(""); | ||
const [textLength, setTextLength] = useState(0); | ||
|
||
useEffect(() => { | ||
onContentChange({ content: sanitize(content), tagList }); | ||
}, [content]); | ||
|
||
const modules = { | ||
toolbar: false, | ||
mention: { | ||
allowedChars: /^[A-Za-z가-힣\sÅÄÖåäö]*$/, | ||
mentionDenotationChars: ["#"], | ||
source: useCallback( | ||
async ( | ||
searchTerm: string, | ||
renderItem: ( | ||
arg0: { id: number | string; value: string }[] | undefined, | ||
arg1: any | ||
) => void, | ||
mentionChar: string | ||
) => { | ||
if (mentionChar === "#") { | ||
// 검색중인 태그를 설정 | ||
setMentioningValue(searchTerm); | ||
} | ||
if (searchTerm.length === 0 || searchTerm.includes(" ")) { | ||
renderItem([], searchTerm); | ||
} else { | ||
renderItem([{ id: searchTerm, value: searchTerm }], searchTerm); | ||
} | ||
}, | ||
[] | ||
), | ||
}, | ||
}; | ||
|
||
return ( | ||
<> | ||
<ReactQuill | ||
style={{ height: 300 }} | ||
modules={modules} | ||
placeholder="입력해주세요" | ||
onChange={(content, _d, _s, editor) => { | ||
const parsedTags = editor | ||
.getContents() | ||
.filter((op) => op.insert?.mention?.value) | ||
.reduce( | ||
(acc: string[], op) => [...acc, op.insert?.mention?.value], | ||
[] | ||
); | ||
setTagList(parsedTags); | ||
setContent(content); | ||
setTextLength(editor.getLength() - 1); | ||
}} | ||
value={content} | ||
/> | ||
<Typography | ||
variant="label" | ||
color={"text.secondary"} | ||
sx={{ textAlign: "right" }} | ||
> | ||
<Typography | ||
variant="label" | ||
color="primary.main" | ||
fontWeight={"bold"} | ||
component="span" | ||
> | ||
{textLength} | ||
</Typography>{" "} | ||
/ 200자 | ||
</Typography> | ||
</> | ||
); | ||
}; | ||
|
||
export default memo(NewPostTextEditor); |
Oops, something went wrong.