공개 본문 블록 계산 분리

This commit is contained in:
2026-07-27 12:38:21 +09:00
parent b15282f41f
commit 8c4ad90f91
10 changed files with 214 additions and 83 deletions

View File

@@ -40,11 +40,9 @@ import {
getQuoteLineEntries,
normalizeQuoteEditableValue
} from '../../lib/markdown-quote.js'
import { getInArticleAdAfterBlockIds } from '../../lib/content-in-article-ad.js'
import { getContentLightboxImages, getGalleryRows } from '../../lib/content-gallery-images.js'
import { parseMarkdownBlocks } from '../../lib/markdown-block-parser.js'
import { createHeadingIdFactory } from '../../lib/markdown-toc.js'
import { getGalleryRows } from '../../lib/content-gallery-images.js'
import { useContentMarkdownLightbox } from '../../composables/useContentMarkdownLightbox.js'
import { useContentMarkdownBlocks } from '../../composables/useContentMarkdownBlocks.js'
import ContentMarkdownCodeBlockEditor from './ContentMarkdownCodeBlockEditor.vue'
import ProseCodeBlock from './ProseCodeBlock.vue'
import ProseHtml from './ProseHtml.vue'
@@ -132,6 +130,19 @@ const {
showNextImage
} = useContentMarkdownLightbox()
const {
blocks,
normalizedInArticleAdCode,
headingIdsByBlock,
renderBlocks,
tailInsertBeforeLine,
contentLightboxImages
} = useContentMarkdownBlocks({
content: computed(() => props.content),
interactive: computed(() => props.interactive),
inArticleAdCode: computed(() => props.inArticleAdCode)
})
/**
* 빈 줄 공백 블록 높이를 반환한다.
* @param {Object} block - 렌더링 블록
@@ -139,79 +150,6 @@ const {
*/
const getSpacerHeightClass = (block) => block.meta?.legacy ? 'h-6' : 'h-8'
const blocks = computed(() => parseMarkdownBlocks(props.content))
const normalizedInArticleAdCode = computed(() => String(props.inArticleAdCode || '').trim())
/**
* 본문 인아티클 광고를 삽입할 블록 ID 목록을 반환한다.
* @returns {string[]} 삽입 기준 블록 ID 목록
*/
const inArticleAdAfterBlockIds = computed(() => {
if (props.interactive || !normalizedInArticleAdCode.value) {
return []
}
return getInArticleAdAfterBlockIds(blocks.value)
})
const headingIdsByBlock = computed(() => {
const createHeadingId = createHeadingIdFactory()
const ids = {}
for (const block of blocks.value) {
if (block.type === 'heading' && block.level >= 1 && block.level <= 3) {
ids[block.id] = createHeadingId(block.text)
}
}
return ids
})
/**
* 공개 본문 렌더링용 블록 목록을 반환한다.
* 인아티클 광고는 별도 v-if 대신 블록으로 삽입해 fragment 주석을 줄인다.
* @returns {Array<Object>} 렌더링 블록 목록
*/
const renderBlocks = computed(() => {
const sourceBlocks = blocks.value
const adAfterBlockIds = inArticleAdAfterBlockIds.value
if (props.interactive || !adAfterBlockIds.length) {
return sourceBlocks
}
const adAfterIdSet = new Set(adAfterBlockIds)
const result = []
for (const block of sourceBlocks) {
result.push(block)
if (adAfterIdSet.has(block.id)) {
result.push({
id: `in-article-ad-after-${block.id}`,
type: 'in-article-ad',
meta: {
afterBlockId: block.id
}
})
}
}
return result
})
/** @type {import('vue').ComputedRef<number>} 문서 맨 아래 단일 이미지 삽입 줄 */
const tailInsertBeforeLine = computed(() => {
const lastBlock = blocks.value[blocks.value.length - 1]
if (typeof lastBlock?.meta?.endLine === 'number') {
return lastBlock.meta.endLine + 1
}
return (props.content || '').split('\n').length
})
const contentLightboxImages = computed(() => getContentLightboxImages(blocks.value))
/**
* 갤러리 이미지 비율 저장 키를 만든다.
* @param {string} blockId - 블록 ID