게시물 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

@@ -35,6 +35,7 @@ import {
parseCalloutOptions
} from '../../lib/markdown-callout.js'
import { createHeadingIdFactory } from '../../lib/markdown-toc.js'
import { isIframeEmbedMarkup } from '../../lib/markdown-iframe-embed.js'
import ContentMarkdownCodeBlockEditor from './ContentMarkdownCodeBlockEditor.vue'
import ProseCodeBlock from './ProseCodeBlock.vue'
import ContentMarkdownCalloutEditor from './ContentMarkdownCalloutEditor.vue'
@@ -259,6 +260,7 @@ const isMarkdownBlockStart = (line) => {
trimmedLine.startsWith('```') ||
trimmedLine === '---' ||
isStandaloneUrlLine(trimmedLine) ||
isIframeEmbedMarkup(trimmedLine) ||
/^(#{1,6})\s+(.+)$/.test(trimmedLine) ||
trimmedLine.startsWith('> ') ||
/^- /.test(trimmedLine) ||
@@ -721,6 +723,17 @@ const parseMarkdownBlocks = (markdown) => {
continue
}
if (isIframeEmbedMarkup(trimmedLine)) {
const startLine = index
blocks.push(attachSourceRange(
createBlock('embed', '', null, `block-${blocks.length}`, { url: trimmedLine }),
startLine,
startLine
))
index += 1
continue
}
const image = parseImageLine(trimmedLine)
if (image) {
@@ -3311,14 +3324,14 @@ onBeforeUnmount(() => {
data-preview-card-block="true"
tabindex="0"
role="group"
aria-label="임베드 블록"
aria-label="HTML 블록"
@mousedown.capture="focusPreviewCardBlock"
@keydown="onPreviewCardKeydown($event, block)"
>
<button
class="content-markdown-renderer__embed-delete content-markdown-renderer__preview-card-action absolute right-2 top-2 z-10 rounded bg-[#15171a]/85 px-2.5 py-1 text-xs font-semibold text-white opacity-0 shadow transition-opacity hover:bg-[#15171a] focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-[var(--site-accent)] group-hover:opacity-100 group-focus-within:opacity-100"
type="button"
aria-label="임베드 삭제"
aria-label="HTML 블록 삭제"
@click.stop="deletePreviewCardBlock(block)"
>
삭제

View File

@@ -1,4 +1,6 @@
<script setup>
import { parseIframeEmbedMarkup } from '../../lib/markdown-iframe-embed.js'
const props = defineProps({
url: {
type: String,
@@ -98,6 +100,7 @@ const youtubeId = computed(() => getYouTubeId(props.url))
const youtubeEmbedUrl = computed(() => youtubeId.value ? `https://www.youtube.com/embed/${youtubeId.value}` : '')
const tweetId = computed(() => getTweetId(props.url))
const mastodonEmbedUrl = computed(() => getMastodonEmbedUrl(props.url))
const customIframe = computed(() => parseIframeEmbedMarkup(props.url))
const mastodonIframeRef = ref(null)
const mastodonEmbedHeight = ref(640)
const mastodonEmbedId = ref(0)
@@ -230,6 +233,18 @@ watch(mastodonEmbedUrl, () => {
scrolling="no"
@load="requestMastodonEmbedHeight"
/>
<iframe
v-else-if="customIframe"
class="prose-embed__custom block w-full border-0"
:src="customIframe.src"
:title="customIframe.title"
:allow="customIframe.allow"
:height="customIframe.height || 480"
:width="customIframe.width || undefined"
:allowfullscreen="customIframe.allowFullscreen"
loading="lazy"
sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-presentation"
/>
<a
v-else-if="safeExternalUrl"
class="prose-embed__link block p-5 text-sm font-semibold text-[var(--site-text)] hover:opacity-70"