hhkb.dev

BLOG

2025-12-19 / 블로그 · 06

에디터 기능 개선 및 버그 수정

에디터 안정화: 험난한 기능 개선의 길

지난번 BlockNote 도입으로 큰 틀은 잡혔지만 실제로 써보니 디테일한 부분에서 여전히 문제가 많았다.
오늘은 이 문제들을 하나씩 해결하며 에디터의 완성도를 높이는 데 집중했다.

1. 이미지 로딩과 NBSP의 충돌

가장 골치 아팠던 문제는 에디터에서 이미지가 로드되지 않는 현상이었다.
원인을 파헤쳐보니 마크다운을 BlockNote 블록으로 변환하는 전처리 과정(markdownToBlocks)에 문제가 있었다.
BlockNote가 빈 줄을 제대로 인식하지 못해서 모든 빈 줄을 NBSP(\u00A0)로 변환하도록 처리했었는데
이 과정에서 이미지 문법 바로 앞뒤의 줄바꿈까지 NBSP로 변해버리면서 파서가 이미지를 인식하지 못하게 된 것이다.

결국 전처리 로직을 수정해 '이미지가 아닌 빈 줄'만 선별적으로 변환하려 했지만 정규식 처리가 까다로웠고
근본적으로는 저장 시점에 처리하는 것이 맞다고 판단했다.
불필요한 전처리를 걷어내고 저장 로직(blocksToMarkdown)을 강화하는 방향으로 선회하여 깔끔하게 해결했다.

2. IDE 스타일 저장: 라인별 편집의 로망

보통 웹 에디터는 블록 단위로 생각하고 저장한다. 문단과 문단 사이는 당연히 떨어져 있어야 한다는 식이다.
하지만 나는 VS Code에서 마크다운 파일을 열고 한 줄 한 줄 코드를 짜듯이 글을 쓰는 경험을 웹에서도 원했다.

BlockNote는 기본적으로 모든 블록 사이에 \n\n을 넣어 저장한다.
이게 마크다운 표준에는 맞지만, IDE에서 볼 때는 불필요하게 줄 간격이 넓어 보여 가독성을 해쳤다.
내가 입력한 빈 줄만 저장되고, 나머지는 붙여서 저장되는 진정한 IDE 스타일을 구현하고 싶었다.

이를 위해 마커(Marker) 방식을 도입했다.

  1. 저장 전, 에디터상의 진짜 빈 줄(NBSP 블록)을 __EMPTY_LINE__이라는 마커로 변환한다.
  2. 모든 \n\n을 \n으로 바꿔버린다. (모든 블록을 다닥다닥 붙임)
  3. 마지막으로 __EMPTY_LINE__ 마커를 다시 \n으로 복원한다.

결과는 만족스러웠다. 웹 에디터에서 작성한 글을 VS Code로 열어도 이질감이 거의 없었다.
내가 의도적으로 띄운 줄만 정확히 빈 줄로 남고, 나머지는 깔끔하게 정리되어 있었다.
**'웹에서도 IDE처럼 라인 단위로 편집한다'**는 의도가 기술적으로 구현된 순간이었다.
덤으로, 리스트 아이템 사이나 헤딩과 본문 사이에 강제로 들어가는 공백도 제거하여 훨씬 밀도 있는 문서 작성이 가능해졌다.

3. URL 한글 깨짐과 링크 처리

마크다운으로 저장될 때 한글 URL이 %ED%85%8C...처럼 인코딩돼 저장되는 문제가 있었다. 가독성도 떨어지고 링크 수정도 불편했다.
저장 로직에 decodeURIComponent를 추가하여 한글이 그대로 저장되도록 수정했다.
또 공백이 포함된 파일명이나 URL(예: Program Files)은 마크다운 파싱 오류를 일으킬 수 있어
이런 경우에만 자동으로 < > 기호로 감싸주는([link](<url with space>)) 로직도 추가했다.

4. 다크모드 동기화: 내 맘대로 안 되는 브라우저

앱은 라이트모드인데 에디터만 다크모드로 나오는 기이한 현상이 있었다.
알고 보니 prefers-color-scheme 미디어 쿼리 때문에 브라우저/OS 설정이 강제로 적용되고 있었다.
라이브러리 내장 CSS를 오버라이드하고 테마 감지 로직에서도 브라우저 설정을 무시한 채 **앱의 테마 상태(html.dark 클래스)**만 따르도록 바꿨다.
이제 시스템 설정과 무관하게 웹사이트 설정대로 에디터 테마가 완벽하게 동기화된다.

더 나은 경험을 위한 UI/UX 디테일링

에디터 코어 기능 외에도 글쓰는 경험을 쾌적하게 만들기 위해 놓치고 있던 디테일들을 함께 손봤다.

  • TOC/아웃라인 디자인 통일: 뷰 모드와 에디터의 목차 디자인을 통일했다. 아이콘, 포인트 컬러, 헤딩 카운트 배지까지 맞춰서 일관성을 높였고, 본문 제목(article-title)이 목차에 중복으로 뜨는 문제도 ID 필터링으로 해결했다.
  • 직관적인 태그 관리: 태그를 클릭해야 삭제되는 방식에서, 마우스를 올리면 ✕ 삭제 표시가 뜨도록 변경했다. 또한 무분별한 태그 입력을 막기 위해 최대 5개까지만 입력 가능하도록 제한을 두었다.
  • 날짜 선택 UI: 기존 문자열 입력 방식에서 Date Picker를 도입해 클릭 한 번으로 날짜를 변경할 수 있게 했다. 날짜 포맷도 문서 전체적으로 통일했다.
  • WYSIWYG 강화: 편집기 내 H2 구분선 제거, 불필요한 공백 제거, 그리고 단일 엔터도 줄바꿈으로 인식하도록(remark-breaks) 처리하여 "보이는 대로 저장되고 보이는 대로 출력되는" 경험을 완성했다.