게시물 HTML iframe 블록 추가

This commit is contained in:
2026-06-17 09:52:56 +09:00
parent 6c4064d8b5
commit d41cb71d40
17 changed files with 211 additions and 45 deletions

View File

@@ -132,9 +132,9 @@ const blockCommands = [
},
{
type: 'embed',
label: '임베드',
description: 'YouTube 등 외부 링크 삽입',
keywords: ['embed', 'youtube', 'link', '임베드', '유튜브']
label: 'HTML',
description: 'URL 또는 iframe HTML 삽입',
keywords: ['html', 'iframe', 'embed', 'youtube', 'link', '임베드', '유튜브']
},
{
type: 'quote',
@@ -2281,12 +2281,12 @@ defineExpose({
<input
v-model="block.url"
class="admin-block-editor__embed-url w-full border-0 bg-transparent text-base font-semibold text-ink outline-none placeholder:text-soft"
type="url"
placeholder="https://www.youtube.com/watch?v=..."
type="text"
placeholder="https://www.youtube.com/watch?v=... 또는 iframe HTML"
@input="updateStructuredBlock"
>
<p class="admin-block-editor__embed-help mt-2 text-xs text-muted">
YouTube 링크는 공개 화면에서 영상으로 표시됩니다.
URL 또는 iframe HTML은 공개 화면에서 HTML 블록으로 표시됩니다.
</p>
</section>

View File

@@ -115,7 +115,7 @@ const panelTitle = computed(() => {
}
if (props.panel.kind === 'embed') {
return '임베드'
return 'HTML'
}
if (props.panel.kind === 'quote') {
@@ -155,7 +155,7 @@ const panelMeta = computed(() => {
}
if (props.panel.kind === 'embed') {
return 'YouTube·X 등 URL'
return 'URL·iframe'
}
if (props.panel.kind === 'quote') {
@@ -254,17 +254,16 @@ const onPanelFocusOut = (event) => {
<template v-else-if="panel.kind === 'embed'">
<label class="admin-editor-block-panel__field grid gap-2 text-sm">
<span class="font-semibold text-[#394047]">임베드 URL</span>
<input
class="rounded border border-[#d7dde2] bg-[#eff1f2] px-3 py-2 text-sm text-[#15171a] outline-none transition-colors focus:border-[#8e9cac]"
<span class="font-semibold text-[#394047]">HTML 코드 또는 URL</span>
<textarea
class="min-h-28 resize-y rounded border border-[#d7dde2] bg-[#eff1f2] px-3 py-2 font-mono text-xs leading-5 text-[#15171a] outline-none transition-colors focus:border-[#8e9cac]"
:value="panel.url"
type="url"
placeholder="https://www.youtube.com/watch?v=..."
placeholder="https://www.youtube.com/watch?v=... 또는 <iframe src=&quot;...&quot;></iframe>"
@input="emit('update-embed-url', $event.target.value)"
>
/>
</label>
<p class="admin-editor-block-panel__hint mt-3 text-xs leading-relaxed text-[#8e9cac]">
YouTube·YouTube Shorts, X(트위터) 게시물 URL을 지원합니다. 그 외 URL은 링크 카드로 표시됩니다.
YouTube·YouTube Shorts, X(트위터) 게시물 URL과 외부 서비스 iframe 코드를 지원합니다. iframe은 src 등 허용된 속성만 사용합니다.
</p>
</template>

View File

@@ -1472,18 +1472,39 @@ const getSelectionState = () => {
* @returns {void}
*/
const setTextareaSelection = (start, end = start, options = {}) => {
const previousScrollTop = options.preserveScroll ? textareaRef.value?.scrollTop : null
const scrollContainer = options.preserveScroll && import.meta.client
? getNearestScrollContainer(editorRootRef.value)
: null
const previousScrollState = options.preserveScroll
? {
textareaTop: textareaRef.value?.scrollTop,
containerTop: scrollContainer?.scrollTop,
windowX: import.meta.client ? window.scrollX : 0,
windowY: import.meta.client ? window.scrollY : 0
}
: null
/**
* textarea 스크롤 위치를 복원한다.
* textarea와 에디터 스크롤 위치를 복원한다.
* @param {HTMLTextAreaElement} textarea - 대상 textarea
* @returns {void}
*/
const restoreScroll = (textarea) => {
if (!Number.isFinite(previousScrollTop)) {
if (!previousScrollState) {
return
}
textarea.scrollTop = previousScrollTop
if (Number.isFinite(previousScrollState.textareaTop)) {
textarea.scrollTop = previousScrollState.textareaTop
}
if (scrollContainer && Number.isFinite(previousScrollState.containerTop)) {
scrollContainer.scrollTop = previousScrollState.containerTop
}
if (import.meta.client && Number.isFinite(previousScrollState.windowY)) {
window.scrollTo(previousScrollState.windowX, previousScrollState.windowY)
}
}
nextTick(() => {
@@ -2729,8 +2750,8 @@ const appendImagesToActiveGallery = (images) => {
}
/**
* 현재 임베드 URL을 수정한다.
* @param {string} url - 임베드 URL
* 현재 HTML 블록 값을 수정한다.
* @param {string} url - HTML 블록 값
* @returns {void}
*/
const updateActiveEmbedUrl = (url) => {
@@ -2748,6 +2769,11 @@ const updateActiveEmbedUrl = (url) => {
return
}
if (trimmed.includes('\n') || /^<iframe\b/i.test(trimmed)) {
replaceLineRange(block.startLine, block.endLine, [':::embed', trimmed, ':::'], false)
return
}
replaceLineRange(block.startLine, block.endLine, [trimmed], false)
}

View File

@@ -1154,8 +1154,8 @@ const onBlockPanelAddGalleryImages = () => {
}
/**
* 블록 패널에서 임베드 URL을 수정한다.
* @param {string} url - 임베드 URL
* 블록 패널에서 HTML 임베드 값을 수정한다.
* @param {string} url - HTML 임베드 값
* @returns {void}
*/
const onBlockPanelUpdateEmbedUrl = (url) => {