글쓰기 에디터 문단 처리와 설정 패널 액션 보정
This commit is contained in:
@@ -508,6 +508,37 @@ const updateSlashMenuDirection = (index) => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 텍스트 블록 DOM의 현재 텍스트 반환
|
||||
* @param {number} index - 블록 인덱스
|
||||
* @returns {string} 현재 텍스트
|
||||
*/
|
||||
const getTextBlockDomText = (index) => {
|
||||
const element = blockRefs.value[index]
|
||||
|
||||
return element?.innerText.replace(/\n$/, '') || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 텍스트 블록 DOM 값을 상태에 즉시 반영
|
||||
* @param {number} index - 블록 인덱스
|
||||
* @returns {Object|undefined} 갱신한 블록
|
||||
*/
|
||||
const syncTextBlockFromDom = (index) => {
|
||||
const block = editorBlocks.value[index]
|
||||
|
||||
if (!block || !isTextBlock(block)) {
|
||||
return block
|
||||
}
|
||||
|
||||
block.text = getTextBlockDomText(index)
|
||||
activeBlockId.value = block.id
|
||||
updateSlashQuery(block)
|
||||
updateSlashMenuDirection(index)
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
/**
|
||||
* 블록 타입에 맞는 태그명 반환
|
||||
* @param {Object} block - 에디터 블록
|
||||
@@ -537,15 +568,15 @@ const getBlockTag = (block) => {
|
||||
const getBlockClass = (block) => [
|
||||
'admin-block-editor__block outline-none transition-colors',
|
||||
{
|
||||
'admin-block-editor__paragraph min-h-8 text-[17px] leading-8': block.type === 'paragraph',
|
||||
'admin-block-editor__heading mt-8 min-h-10 font-semibold leading-tight': block.type === 'heading',
|
||||
'admin-block-editor__paragraph min-h-8 whitespace-pre-wrap text-[17px] leading-8': block.type === 'paragraph',
|
||||
'admin-block-editor__heading min-h-10 font-semibold leading-tight': block.type === 'heading',
|
||||
'admin-block-editor__heading--h1 text-5xl': block.type === 'heading' && block.level === 1,
|
||||
'admin-block-editor__heading--h2 text-4xl': block.type === 'heading' && block.level === 2,
|
||||
'admin-block-editor__heading--h3 text-3xl': block.type === 'heading' && block.level === 3,
|
||||
'admin-block-editor__quote my-5 border-l-4 border-ink bg-surface px-5 py-3 text-xl font-medium leading-8': block.type === 'quote',
|
||||
'admin-block-editor__callout my-5 min-h-14 rounded border border-line bg-surface px-5 py-4 text-[16px] leading-7': block.type === 'callout',
|
||||
'admin-block-editor__quote border-l-4 border-ink bg-surface px-5 py-3 text-xl font-medium leading-8': block.type === 'quote',
|
||||
'admin-block-editor__callout min-h-14 rounded border border-line bg-surface px-5 py-4 text-[16px] leading-7': block.type === 'callout',
|
||||
'admin-block-editor__list relative min-h-8 pl-7 text-[17px] leading-8 before:absolute before:left-2 before:top-3 before:h-2 before:w-2 before:rounded-full before:bg-current': block.type === 'list',
|
||||
'admin-block-editor__code my-5 min-h-14 whitespace-pre-wrap rounded bg-[#15171a] px-4 py-3 font-mono text-sm leading-6 text-white': block.type === 'code'
|
||||
'admin-block-editor__code min-h-14 whitespace-pre-wrap rounded bg-[#15171a] px-4 py-3 font-mono text-sm leading-6 text-white': block.type === 'code'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -574,7 +605,7 @@ const getImageWidthClass = (width) => {
|
||||
*/
|
||||
const updateBlockText = (event, index) => {
|
||||
const block = editorBlocks.value[index]
|
||||
const text = event.target.innerText.replace(/\n$/, '')
|
||||
const text = getTextBlockDomText(index)
|
||||
|
||||
block.text = text
|
||||
activeBlockId.value = block.id
|
||||
@@ -608,7 +639,14 @@ const finishTextComposition = (event, index) => {
|
||||
|
||||
nextTick(() => {
|
||||
window.setTimeout(() => {
|
||||
updateBlockText(event, index)
|
||||
const block = syncTextBlockFromDom(index)
|
||||
|
||||
if (!block) {
|
||||
return
|
||||
}
|
||||
|
||||
applyMarkdownShortcut(block, index)
|
||||
emitContent()
|
||||
}, 0)
|
||||
})
|
||||
}
|
||||
@@ -938,6 +976,8 @@ const removeGalleryImage = (block, imageIndex) => {
|
||||
* @returns {void}
|
||||
*/
|
||||
const highlightNextCommand = (event) => {
|
||||
syncTextBlockFromDom(activeBlockIndex.value)
|
||||
|
||||
if (!visibleCommands.value.length) {
|
||||
return
|
||||
}
|
||||
@@ -952,6 +992,8 @@ const highlightNextCommand = (event) => {
|
||||
* @returns {void}
|
||||
*/
|
||||
const highlightPreviousCommand = (event) => {
|
||||
syncTextBlockFromDom(activeBlockIndex.value)
|
||||
|
||||
if (!visibleCommands.value.length) {
|
||||
return
|
||||
}
|
||||
@@ -969,16 +1011,25 @@ const highlightPreviousCommand = (event) => {
|
||||
* @returns {void}
|
||||
*/
|
||||
const handleEnter = (event, index) => {
|
||||
const currentBlock = editorBlocks.value[index]
|
||||
const currentBlock = syncTextBlockFromDom(index)
|
||||
|
||||
if (isComposingText.value || event.isComposing || event.keyCode === 229) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (visibleCommands.value.length && currentBlock.text.startsWith('/')) {
|
||||
if (event.shiftKey && isTextBlock(currentBlock)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (currentBlock.text.startsWith('/')) {
|
||||
event.preventDefault()
|
||||
applyCommand(highlightedCommand.value || visibleCommands.value[0])
|
||||
const command = highlightedCommand.value || visibleCommands.value[0]
|
||||
|
||||
if (command) {
|
||||
applyCommand(command)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1198,15 +1249,17 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="admin-block-editor min-h-[32rem] bg-transparent py-4 text-ink">
|
||||
<div class="admin-block-editor__surface post-prose grid gap-1">
|
||||
<div class="admin-block-editor bg-transparent py-4 text-ink">
|
||||
<div class="admin-block-editor__surface post-prose">
|
||||
<div
|
||||
v-for="(block, index) in editorBlocks"
|
||||
:key="block.id"
|
||||
class="admin-block-editor__row group/block relative rounded transition-colors"
|
||||
:class="{
|
||||
'admin-block-editor__row--selected bg-[#eff1f2] ring-1 ring-[#d8dde1]': selectedBlockId === block.id,
|
||||
'admin-block-editor__row--dragging opacity-50': draggingBlockId === block.id
|
||||
'admin-block-editor__row--dragging opacity-50': draggingBlockId === block.id,
|
||||
'admin-block-editor__row--text': isTextBlock(block),
|
||||
'admin-block-editor__row--structure': !isTextBlock(block)
|
||||
}"
|
||||
:data-editor-block-id="block.id"
|
||||
@dragover.prevent
|
||||
@@ -1226,11 +1279,11 @@ defineExpose({
|
||||
<span aria-hidden="true">⋮⋮</span>
|
||||
</button>
|
||||
|
||||
<hr v-if="block.type === 'divider'" class="admin-block-editor__divider my-6 border-line">
|
||||
<hr v-if="block.type === 'divider'" class="admin-block-editor__divider border-line">
|
||||
|
||||
<figure
|
||||
v-else-if="block.type === 'image'"
|
||||
class="admin-block-editor__media group my-6"
|
||||
class="admin-block-editor__media group"
|
||||
:class="getImageWidthClass(block.width)"
|
||||
tabindex="0"
|
||||
@focus="activateBlock(block)"
|
||||
@@ -1281,7 +1334,7 @@ defineExpose({
|
||||
|
||||
<figure
|
||||
v-else-if="block.type === 'gallery'"
|
||||
class="admin-block-editor__gallery group my-6"
|
||||
class="admin-block-editor__gallery group"
|
||||
tabindex="0"
|
||||
@focus="activateBlock(block)"
|
||||
@click="activateBlock(block)"
|
||||
@@ -1317,7 +1370,7 @@ defineExpose({
|
||||
|
||||
<section
|
||||
v-else-if="block.type === 'toggle'"
|
||||
class="admin-block-editor__toggle my-6 rounded border border-line bg-paper p-5"
|
||||
class="admin-block-editor__toggle rounded border border-line bg-paper p-5"
|
||||
@focusin="activateBlock(block)"
|
||||
@click="activateBlock(block)"
|
||||
@keydown.enter="handleEnter($event, index)"
|
||||
@@ -1341,7 +1394,7 @@ defineExpose({
|
||||
|
||||
<section
|
||||
v-else-if="block.type === 'embed'"
|
||||
class="admin-block-editor__embed my-6 rounded border border-dashed border-line bg-surface p-5"
|
||||
class="admin-block-editor__embed rounded border border-dashed border-line bg-surface p-5"
|
||||
@focusin="activateBlock(block)"
|
||||
@click="activateBlock(block)"
|
||||
@keydown.enter="handleEnter($event, index)"
|
||||
@@ -1460,6 +1513,18 @@ defineExpose({
|
||||
color: #1f2328;
|
||||
}
|
||||
|
||||
.admin-block-editor__row + .admin-block-editor__row--text {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.admin-block-editor__row + .admin-block-editor__row--structure {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.admin-block-editor__row--structure + .admin-block-editor__row--structure {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.admin-block-editor__code {
|
||||
background: #15171a;
|
||||
color: #f8fafc;
|
||||
|
||||
Reference in New Issue
Block a user