📍프로젝트 개요

외부 라이브러리 없이 바닐라 JS만으로 노션 클로닝을 진행하는 프로젝트

기본 요구사항

  • 기본적인 레이아웃은 노션과 같다. (좌) 리스트 / (우) 편집기
  • 편집기는 자동 저장 기능을 이용한다.
  • History API를 이용해 SPA 형태로 만든다.

보너스 요구사항

  • divcontentEditable 속성을 조합하여 리치한 에디터를 만든다.
  • 편집기 최하단에 편집 중인 Document의 하위 Document 링크를 렌더링한다.
  • 편집기 내에 다른 Document 제목을 적은 경우, 해당 Document 편집 페이지로 이동하는 링크를 건다.

기본 요구사항은 모두 구현했지만 보너스 요구사항은 기한 내에 구현하지 못했다.

리치한 에디터를 만들어보려 며칠간 고군분투 했고 결국 성공한 듯 했지만.. 현재 잔버그가 존재하고 구현 방식이 만족스럽지 않다. 😓

지속적으로 발전시켜 가야겠다!


🖥️컴포넌트 구조 & 구현 기능

컴포넌트 구조

Document List

  • 루트 문서, 하위 문서를 트리 형태로 렌더링 (재귀)
  • 하위 문서 토글 기능
  • 루트 문서, 하위 문서 추가/삭제 기능

Editor

  • 디바운스를 적용한 자동 저장 기능
  • 일부 마크다운 문법 적용

notion_cloning_project



🚨이슈

가장 많은 시간을 들였던 부분은 Document content 입력으로 textarea를 사용했던 것에서 divcontenteditable 속성을 활용하는 것으로 고치고 마크다운 문법이 적용되게 하는 것이었다.

처음 구상한 방식은 다음과 같다.

  1. content에 작성한 내용을 innerHTML로 불러와 저장
  2. 마크다운 문법을 정규표현식을 이용하여 html 태그로 변환하고 innerHTML로 저장

수정할 때마다 위 과정이 반복되면서 잘 작동할 줄 알았으나… innerHTML로 작성한 content를 불러오면 줄바꿈을 할 때마다 <div> 태그가 감싸져있었다.
찾아보니 크롬 환경에서 contenteditable 속성이 true로 지정된 요소의 innerHTML을 가져오면 이렇게 된다고 한다.

# h1
## h2
본문 내용
안녕하세요.

innerHTML

갖가지 정규표현식을 써봤지만 줄바꿈과 html 태그가 의도한대로 적용되지 않았다.

innerText

innerHTML 대신 innerText를 쓰면 변환이 훨씬 간단했지만 마크다운 문법이 적용된 content를 다시 편집할 때 텍스트만 가져오기 때문에 마크다운이 풀리는 문제가 발생했다.

고민해보다가 stateoriginalContent를 추가하여 아래와 같은 방식으로 구현했다.

  1. content에 작성한 내용을 innerText로 불러와 저장
  2. 마크다운 문법을 정규표현식을 이용하여 html 태그로 변환하고 innerHTML로 저장
  3. 편집기에 focus 될 때(수정할 때) originalContent에 저장된 값에 html 태그를 씌워 innerHTML로 저장
const textToHtmlWithMarkdown = (text) => {
  if (!text) return text;
  
  const htmlWithTag = text
  .replace(/^# (.+)$/gm, "<h1># $1</h1>")
  .replace(/^## (.+)$/gm, "<h2>## $1</h2>")
  .replace(/^### (.+)$/gm, "<h3>### $1</h3>")
  /* 정규 표현식 replace 중략 */
  .replace(/\n/g, "<br>");

  return htmlWithTag;
};

$contentContainer
  .querySelector(".input-content")
  .addEventListener("focus", (e) => {
  	e.target.innerHTML = textToHtmlWithMarkdown(this.state.originalContent);
  });

사실 위 방법도 수정할 때마다 마크다운이 다시 나타나기 때문에 깔끔하진 않다.

원하던 방식은 아니었지만 좀 더 리치한 편집기를 만들었다. 좀 더 시급한 부분들을 수정한 뒤에 더 나은 방식에 대해 고민해 볼 예정이다.


✏️개선점 및 느낀점

코드 작성 전 도식화하기

프로젝트를 좀 늦게 시작한 편이라 조급한 마음에 바로 실습 코드 기반으로 코드를 작성했다.

파일이 그렇게 많진 않다보니 구조를 이해하는데 어려움은 없었지만, 의존성을 파악하기 어려워 컴포넌트를 잘게 쪼갤 때 시간이 좀 걸렸다.

앞으로는 도식화 단계도 염두에 두고 프로젝트 일정 관리를 해야겠다.

우선순위를 더 명확하게

프로젝트를 시작할 때 요구사항을 잘게 쪼개고, 어떤 요구사항을 우선적으로 구현해야 하는지 정리하지 않았다.

그러다보니 자잘한 기능 구현에 시간을 쏟느라 좀 더 중요한 요구사항을 해내지 못해 아쉬움이 남는다.

보너스 요구사항 중 하위 문서 링크를 상위 문서 최하단에 렌더링하는 것을 구현하지 못했는데, 생각해보니 이 기능이 없다면 노션과 같은 상위/하위 문서 개념의 의미가 약해지는 것 같다..🤔

다음 과제부터는 요구사항을 잘 분석하고 우선순위를 정한 뒤 진행해야겠다.

틈틈이 기록하기

프로젝트를 마치고 거의 일주일 뒤에 회고글을 작성하고 있는데 벌써 기억이 휘발되어 버렸다..😱😱

어떤 에러를 만났고, 어떻게 해결했는지 그때그때 기록하지 않으면 회고 글 작성도 어렵다는 걸 깨달았다.

기한 내에 기능 구현 하는 것도 중요하지만 기록으로 남겨두지 않으면 성장할 수 없다는 것을 기억하자!

구현 & 수정해야 할 것들

  • 디바운스로 서버에 Document 수정 사항이 저장될 때 focus가 풀리는 것 수정
  • 편집기 하단에 하위 Document 제목 + 링크 렌더링
  • 다른 Document 제목 입력 시 링크
  • 하위 문서 hover & 선택 시 전체 너비에 background-color 적용
    Document List
  • 새로고침 시 404 수정
profile
개발 공부중

0개의 댓글