인용 블록 색상과 라이브 설정 패널 정리

This commit is contained in:
2026-06-04 10:28:43 +09:00
parent 2cb1ff4651
commit b38fc9f154
15 changed files with 222 additions and 221 deletions

View File

@@ -20,7 +20,7 @@ import {
} from '../../lib/markdown-live-edit.js'
import { buildCodeBlockLines, parseCodeFenceLine } from '../../lib/markdown-code-block.js'
import { buildToggleBlockLines, parseToggleOpenerLine } from '../../lib/markdown-toggle.js'
import { CALLOUT_BACKGROUND_OPTIONS, parseCalloutOptions } from '../../lib/markdown-callout.js'
import { CALLOUT_BACKGROUND_OPTIONS, QUOTE_BACKGROUND_OPTIONS, parseCalloutOptions } from '../../lib/markdown-callout.js'
import { createHeadingIdFactory } from '../../lib/markdown-toc.js'
import ContentMarkdownCodeBlockEditor from './ContentMarkdownCodeBlockEditor.vue'
import ProseCodeBlock from './ProseCodeBlock.vue'
@@ -61,6 +61,8 @@ const emit = defineEmits([
'delete-line',
'merge-with-previous-line',
'edit-image',
'line-focus',
'line-blur',
'slash-update',
'slash-end',
'slash-apply'
@@ -141,7 +143,7 @@ const createBlock = (type = 'paragraph', text = '', level = null, id = '', optio
calloutEmojiEnabled: options.calloutEmojiEnabled ?? true,
calloutEmoji: options.calloutEmoji || '💡',
calloutBackground: options.calloutBackground || 'blue',
quoteBackground: options.quoteBackground || 'pink',
quoteBackground: options.quoteBackground || 'gray',
codeLanguage: options.codeLanguage || '',
codeShowLineNumbers: options.codeShowLineNumbers !== false
})
@@ -192,7 +194,7 @@ const parseQuoteOptions = (value) => {
const [key, rawOptionValue] = token.split('=')
const optionValue = String(rawOptionValue || '').trim()
if (key?.toLowerCase() === 'bg' && CALLOUT_BACKGROUND_OPTIONS.includes(optionValue)) {
if (key?.toLowerCase() === 'bg' && QUOTE_BACKGROUND_OPTIONS.includes(optionValue)) {
quoteBackground = optionValue
}
})
@@ -1181,6 +1183,51 @@ const commitInlineBlockLines = (block, replacementLines) => {
})
}
/**
* 라이브 편집 포커스/클릭 위치의 원본 줄을 상위에 알린다.
* @param {Event} event - 포커스 또는 포인터 이벤트
* @returns {void}
*/
const emitLiveLineFocus = (event) => {
if (!props.interactive) {
return
}
const target = event.target
if (!(target instanceof Element)) {
return
}
const sourceElement = target.closest('[data-source-line]')
const sourceLine = Number(sourceElement?.getAttribute('data-source-line'))
if (!Number.isInteger(sourceLine) || sourceLine < 0) {
return
}
emit('line-focus', sourceLine)
}
/**
* 라이브 편집 영역을 벗어난 포커스를 상위에 알린다.
* @param {FocusEvent} event - 포커스 이탈 이벤트
* @returns {void}
*/
const emitLiveLineBlur = (event) => {
if (!props.interactive || !rendererRootRef.value) {
return
}
const nextTarget = event.relatedTarget
if (nextTarget instanceof Node && rendererRootRef.value.contains(nextTarget)) {
return
}
emit('line-blur')
}
/**
* 문단 인라인 편집 반영
* @param {Object} block - 블록
@@ -2297,7 +2344,13 @@ onBeforeUnmount(() => {
</script>
<template>
<div ref="rendererRootRef" class="content-markdown-renderer">
<div
ref="rendererRootRef"
class="content-markdown-renderer"
@mousedown.capture="emitLiveLineFocus"
@focusin.capture="emitLiveLineFocus"
@focusout.capture="emitLiveLineBlur"
>
<template v-for="block in blocks" :key="block.id">
<div
v-if="interactive && getBlockInsertBeforeLine(block) !== null"
@@ -2350,6 +2403,7 @@ onBeforeUnmount(() => {
v-else-if="block.type === 'quote' && interactive && block.variant !== 'alt'"
:variant="block.variant || 'default'"
:background="block.quoteBackground"
:data-source-line="block.meta.startLine"
>
<ContentMarkdownEditableInline
v-for="quoteLine in getQuoteLineEntries(block)"
@@ -2497,6 +2551,7 @@ onBeforeUnmount(() => {
:callout-emoji-enabled="block.calloutEmojiEnabled"
:callout-emoji="block.calloutEmoji"
:callout-background="block.calloutBackground"
:block-source-line="block.meta.startLine"
:body-source-line="block.meta.startLine + 1"
:model-value="block.text"
@commit="onCalloutBlockCommit(block, $event)"