diff --git a/components/admin/AdminBlockEditor.vue b/components/admin/AdminBlockEditor.vue index f3f28c1..373f8e7 100644 --- a/components/admin/AdminBlockEditor.vue +++ b/components/admin/AdminBlockEditor.vue @@ -12,6 +12,7 @@ const editorBlocks = ref([]) const blockRefs = ref([]) const activeBlockId = ref('') const slashQuery = ref('') +const slashMenuDirection = ref('down') const isApplyingExternalValue = ref(false) let blockIdSeed = 0 @@ -211,6 +212,10 @@ const emitContent = () => { const setBlockRef = (element, index) => { if (element) { blockRefs.value[index] = element + + if (element.innerText !== editorBlocks.value[index]?.text) { + element.innerText = editorBlocks.value[index]?.text || '' + } } } @@ -237,6 +242,28 @@ const focusBlock = (index) => { }) } +/** + * 슬래시 메뉴 표시 방향 갱신 + * @param {number} index - 블록 인덱스 + * @returns {void} + */ +const updateSlashMenuDirection = (index) => { + nextTick(() => { + const element = blockRefs.value[index] + + if (!element) { + slashMenuDirection.value = 'down' + return + } + + const rect = element.getBoundingClientRect() + const menuHeight = 280 + slashMenuDirection.value = window.innerHeight - rect.bottom < menuHeight && rect.top > menuHeight + ? 'up' + : 'down' + }) +} + /** * 블록 타입에 맞는 태그명 반환 * @param {Object} block - 에디터 블록 @@ -291,6 +318,7 @@ const updateBlockText = (event, index) => { activeBlockId.value = block.id applyMarkdownShortcut(block, index) updateSlashQuery(block) + updateSlashMenuDirection(index) emitContent() } @@ -378,6 +406,12 @@ const applyCommand = (command) => { block.type = command.type block.level = command.level || null block.text = '' + const element = blockRefs.value[index] + + if (element) { + element.innerText = '' + } + slashQuery.value = '' if (command.type === 'divider') { @@ -406,6 +440,10 @@ const handleEnter = (event, index) => { event.preventDefault() + if (!currentBlock.text.trim() && currentBlock.type === 'paragraph') { + return + } + if (currentBlock.type === 'divider') { editorBlocks.value.splice(index + 1, 0, createEditorBlock()) emitContent() @@ -452,10 +490,23 @@ const handleBackspace = (event, index) => { * @returns {void} */ const activateBlock = (block) => { + const index = editorBlocks.value.findIndex((item) => item.id === block.id) activeBlockId.value = block.id updateSlashQuery(block) + updateSlashMenuDirection(index) } +/** + * 블록 placeholder 표시 여부 반환 + * @param {Object} block - 에디터 블록 + * @param {number} index - 블록 인덱스 + * @returns {boolean} placeholder 표시 여부 + */ +const shouldShowPlaceholder = (block, index) => !block.text && ( + activeBlockId.value === block.id || + (index === 0 && editorBlocks.value.length === 1) +) + watch(() => props.modelValue, (value) => { if (isApplyingExternalValue.value) { return @@ -479,7 +530,7 @@ watch(editorBlocks, () => {