미리보기 액션 적용 분리

This commit is contained in:
2026-07-29 10:30:24 +09:00
parent 980ef92a68
commit d8cfa77080
10 changed files with 456 additions and 228 deletions

View File

@@ -37,18 +37,7 @@ import {
resolveImageUploadInsertTarget,
resolveUploadFetchErrorMessage
} from '../../lib/markdown-editor-media.js'
import {
createPreviewAppendParagraphValue,
createPreviewDeleteLineValue,
createPreviewExtractGalleryImageValue,
createPreviewGalleryReorderValue,
createPreviewImagesMergeValue,
createPreviewInsertAfterLineResult,
createPreviewInsertImageToGalleryValue,
createPreviewMergeWithPreviousLineValue,
createPreviewRemoveGalleryImageResult,
parseEditorImageLine
} from '../../lib/markdown-editor-preview-blocks.js'
import { parseEditorImageLine } from '../../lib/markdown-editor-preview-blocks.js'
import {
createSlashCommandApplyPlan,
createSlashCommandEditorEffectPlan,
@@ -59,8 +48,7 @@ import {
insertMarkdownLinesAtSlashTarget,
parseSlashInput,
resolveSlashCommand,
shouldCaptureSlashMenuKeyboardAction,
shouldIgnorePendingMediaSlashCommit
shouldCaptureSlashMenuKeyboardAction
} from '../../lib/markdown-slash-commands.js'
import {
calculateSlashMenuPosition,
@@ -77,6 +65,7 @@ import { useAdminMarkdownPreviewFocus } from '../../composables/useAdminMarkdown
import { useAdminMarkdownTextareaFocus } from '../../composables/useAdminMarkdownTextareaFocus.js'
import { useAdminMarkdownBlockPanel } from '../../composables/useAdminMarkdownBlockPanel.js'
import { useAdminMarkdownBlockActions } from '../../composables/useAdminMarkdownBlockActions.js'
import { useAdminMarkdownPreviewActions } from '../../composables/useAdminMarkdownPreviewActions.js'
import {
buildDefaultUploadSizeLimits,
DEFAULT_UPLOAD_MAX_FILE_COUNT,
@@ -1167,197 +1156,27 @@ const resolveCurrentFencedBlockEndLine = (startLine, fallbackEndLine) => {
return fallbackEndLine
}
/**
* 미리보기에서 갤러리 순서 변경
* @param {{ startLine: number, endLine: number, images: Array<Object> }} payload - 갤러리 줄 범위·이미지 목록
* @returns {void}
*/
const onPreviewGalleryReorder = ({ startLine, endLine, images }) => {
const nextValue = createPreviewGalleryReorderValue({
value: markdownValue.value,
startLine,
endLine,
images
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
/**
* 라이브 모드에서 두 이미지 블록을 갤러리 fenced block으로 병합한다.
* @param {{ sourceLine: number, targetLine: number }} payload - 원본·대상 줄(0-based)
* @returns {void}
*/
const onPreviewMergeImagesToGallery = ({ sourceLine, targetLine }) => {
const nextValue = createPreviewImagesMergeValue({
value: markdownValue.value,
sourceLine,
targetLine
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
/**
* 라이브 모드에서 단일 이미지 블록을 기존 갤러리에 추가한다.
* @param {{ sourceLine: number, startLine: number, endLine: number, targetIndex: number, image?: Object }} payload - 이미지 줄·갤러리 범위·삽입 위치
* @returns {void}
*/
const onPreviewInsertImageToGallery = ({
sourceLine,
startLine,
endLine,
targetIndex,
image
}) => {
const nextValue = createPreviewInsertImageToGalleryValue({
value: markdownValue.value,
sourceLine,
startLine,
endLine,
targetIndex,
image
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
/**
* 라이브 모드 갤러리에서 특정 이미지를 삭제한다.
* @param {{ startLine: number, endLine: number, imageIndex: number }} payload - 갤러리 범위·이미지 인덱스
* @returns {void}
*/
const onPreviewRemoveGalleryImage = ({ startLine, endLine, imageIndex }) => {
const result = createPreviewRemoveGalleryImageResult({
value: markdownValue.value,
startLine,
endLine,
imageIndex
})
if (!result) {
return
}
markdownValue.value = result.value
activeLogicalLineIndex.value = result.focusLine
}
/**
* 라이브 모드에서 갤러리 이미지를 블록 사이에 단일 이미지 줄로 분리한다.
* @param {{ startLine: number, endLine: number, imageIndex: number, insertBeforeLine: number, image?: Object }} payload - 갤러리 범위·삽입 위치
* @returns {void}
*/
const onPreviewExtractGalleryImage = ({
startLine,
endLine,
imageIndex,
insertBeforeLine,
image
}) => {
const nextValue = createPreviewExtractGalleryImageValue({
value: markdownValue.value,
startLine,
endLine,
imageIndex,
insertBeforeLine,
image
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
/**
* 미리보기 인라인 편집 결과를 마크다운 본문에 반영한다.
* @param {{ startLine: number, endLine: number, replacementLines: string[] }} payload - 줄 범위·대체 줄
* @returns {void}
*/
const onPreviewBlockContentChange = ({ startLine, endLine, replacementLines }) => {
if (typeof startLine !== 'number' || typeof endLine !== 'number' || !Array.isArray(replacementLines)) {
return
}
if (shouldIgnorePendingMediaSlashCommit({
pendingInsertLine: liveSlashInsertLine.value,
startLine,
replacementLines
})) {
return
}
replaceLineRange(startLine, resolveCurrentFencedBlockEndLine(startLine, endLine), replacementLines, false)
}
/**
* 라이브 모드 교차 선택 삭제 결과를 본문에 반영한다.
* @param {{ value: string }} payload - 갱신된 마크다운
* @returns {void}
*/
const onPreviewContentReplace = ({ value }) => {
if (typeof value !== 'string') {
return
}
markdownValue.value = value
}
/**
* 라이브 모드 하단에서 새 문단 줄을 추가한다.
* @returns {void}
*/
const onPreviewAppendParagraph = () => {
markdownValue.value = createPreviewAppendParagraphValue(markdownValue.value)
}
/**
* 라이브 모드에서 지정 줄 아래에 마크다운 줄을 삽입한다.
* @param {{ afterLine: number, lines: string[], focusLine?: number }} payload - 삽입 위치·줄
* @returns {void}
*/
const onPreviewInsertAfterLine = ({ afterLine, lines, focusLine }) => {
const result = createPreviewInsertAfterLineResult({
value: markdownValue.value,
afterLine,
lines,
focusLine
})
if (!result) {
return
}
markdownValue.value = result.value
activeLogicalLineIndex.value = result.focusLine
resetBlockPanelContext()
nextTick(() => {
focusPreviewEditableAtLine(result.focusLine, 0, 'start')
})
}
/**
* 라이브 모드에서 현재 줄을 삭제한다.
* @param {number} lineIndex - 줄 번호(0-based)
* @returns {void}
*/
const onPreviewDeleteLine = (lineIndex) => {
const nextValue = createPreviewDeleteLineValue({
value: markdownValue.value,
lineIndex
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
const {
onPreviewAppendParagraph,
onPreviewBlockContentChange,
onPreviewContentReplace,
onPreviewDeleteLine,
onPreviewExtractGalleryImage,
onPreviewGalleryReorder,
onPreviewInsertAfterLine,
onPreviewInsertImageToGallery,
onPreviewMergeImagesToGallery,
onPreviewMergeWithPreviousLine,
onPreviewRemoveGalleryImage
} = useAdminMarkdownPreviewActions({
value: markdownValue,
activeLogicalLineIndex,
liveSlashInsertLine,
replaceLineRange,
resolveCurrentFencedBlockEndLine,
resetBlockPanelContext,
focusPreviewEditableAtLine
})
/**
* 라이브 모드 미리보기 루트 단축키를 처리한다.
@@ -1786,23 +1605,6 @@ const insertMarkdownAtLine = (lineIndex, insertLines) => {
markdownValue.value = insertMarkdownLinesAtSlashTarget(markdownValue.value, lineIndex, insertLines)
}
/**
* 라이브 모드에서 현재 줄을 이전 줄 끝에 병합한다.
* @param {{ lineIndex: number, mergedLine: string }} payload - 병합 위치·결과 줄
* @returns {void}
*/
const onPreviewMergeWithPreviousLine = ({ lineIndex, mergedLine }) => {
const nextValue = createPreviewMergeWithPreviousLineValue({
value: markdownValue.value,
lineIndex,
mergedLine
})
if (nextValue !== null) {
markdownValue.value = nextValue
}
}
/**
* 이미지 마크다운을 삽입한다.
* @param {{ url: string, alt?: string, width?: string }} image - 이미지 정보