요약

Key Changes

  • src/utils/create-crepe.ts

    • BlockEdit 설정을 CMS용 config 함수로 분리한다.

    • blockHandle.getOffset/getPlacement를 반응형으로 조정하되 Crepe 기본 tall-block 정렬 로직은 유지한다.

    • 메뉴 라벨을 한국어화하고 H1/H4-H6/수식은 계속 비활성화한다.

    • buildMenu로 CMS 그룹을 추가하고 미디어 라이브러리 항목을 만든다.

    • 메뉴 실행 시 editorViewCtx의 selection bookmark를 담아 cms:open-media CustomEvent를 dispatch한다.

  • src/utils/editor-init.ts

    • cms:open-media 이벤트를 AbortController로 등록/정리한다.

    • openMediaModal(mode, selectionBookmark?) 헬퍼를 추가해 썸네일 모드와 본문 삽입 모드를 분리한다.

    • 본문 삽입은 parserCtx로 Markdown 조각을 ProseMirror slice로 파싱해 selection bookmark 위치에 삽입한다.

    • 파싱/selection 복원 실패 시 기존 동작처럼 현재 Markdown 끝에 append하고 Crepe를 재생성한다.

    • 모달 취소, editor 재생성, 저장 불가 상태에서는 pending bookmark를 반드시 제거한다.

  • src/pages/admin/editor.astro

    • .milkdown-block-handle, .milkdown-slash-menu 스타일을 admin token 기반으로 정돈한다.

    • 데스크톱 hover 환경에서는 핸들/plus 버튼이 문서 여백과 겹치지 않게 하고, hover: none 또는 좁은 화면에서는 핸들 노출을 억제한다.

    • prefers-reduced-motion에서 transition을 제거한다.

Edge Cases

  • bodyLoadError 또는 readonly 상태에서는 이벤트와 삽입 로직이 no-op 처리된다.

  • 모달이 여러 번 열리면 가장 최근 bookmark만 사용하고 이전 값은 폐기한다.

  • 미디어 URL이 비어 있거나 선택이 없으면 삽입하지 않는다.

  • 이미지 삽입은 raw text를 ProseMirror에 넣지 않고 Milkdown parser를 거쳐 Markdown 의미를 유지한다.

  • 기존 썸네일 적용, URL 복사, AI 재작성, dirty tracking, SEO 분석 흐름은 유지한다.

Test Plan

  • pnpm build로 Astro/Vite 번들 검증.

  • 수동 확인: /admin/editor에서 문단, H2/H3, 목록, 코드, 이미지, 표 근처 handle 위치와 drag reorder 확인.

  • plus 버튼과 / slash 메뉴 모두에서 한국어 메뉴, 키보드 이동, Enter 실행 확인.

  • 미디어 라이브러리 메뉴로 모달을 열고 선택 위치에 이미지가 들어가는지 확인.

  • 썸네일 모드에서 기존 썸네일 적용 동작이 변하지 않는지 확인.

  • 모바일 폭과 coarse pointer 환경에서 handle이 UI를 가리지 않는지 확인.

  • 참고: 현재 astro check는 @astrojs/check 미설치로 바로 실행할 수 없으므로, 의존성 추가 요청이 있을 때만 별도 검증에 포함한다.

Assumptions

  • v1에서는 Crepe 기본 BlockHandle 컴포넌트를 교체하지 않는다.

  • 삭제/복제/AI 블록 재작성 같은 handle 자체 액션은 이번 범위에서 제외한다.

  • 새 패키지는 추가하지 않고 현재 @milkdown/crepe@7.20.0, @milkdown/kit@7.20.0 기준으로 구현한다.