v0.0.48 Thred형 북마크·회원가입 카드와 X 임베드 보강
북마크·뉴스레터 CTA 마크다운 블록과 컴포넌트를 추가하고, Twitter/X URL은 공식 embed iframe으로 렌더링한다. Callout 강조선과 이미지 캡션 색을 테마 변수에 맞춘다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,8 +6,10 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const { theme } = useThemeMode()
|
||||
|
||||
/**
|
||||
* YouTube 영상 ID를 추출
|
||||
* YouTube 영상 ID를 추출한다.
|
||||
* @param {string} value - 임베드 URL
|
||||
* @returns {string} YouTube 영상 ID
|
||||
*/
|
||||
@@ -29,12 +31,55 @@ const getYouTubeId = (value) => {
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Twitter/X 게시물 ID를 추출한다.
|
||||
* @param {string} value - 트윗 URL
|
||||
* @returns {string} 상태 ID
|
||||
*/
|
||||
const getTweetId = (value) => {
|
||||
try {
|
||||
const trimmed = value.trim()
|
||||
const parsedUrl = new URL(trimmed)
|
||||
const host = parsedUrl.hostname.replace(/^www\./, '')
|
||||
|
||||
if (!['twitter.com', 'x.com', 'mobile.twitter.com'].includes(host)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const parts = parsedUrl.pathname.split('/').filter(Boolean)
|
||||
const statusIdx = parts.indexOf('status')
|
||||
|
||||
if (statusIdx >= 0 && parts[statusIdx + 1]) {
|
||||
return parts[statusIdx + 1].split(/[?#]/)[0] || ''
|
||||
}
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
const youtubeId = computed(() => getYouTubeId(props.url))
|
||||
const youtubeEmbedUrl = computed(() => youtubeId.value ? `https://www.youtube.com/embed/${youtubeId.value}` : '')
|
||||
const tweetId = computed(() => getTweetId(props.url))
|
||||
|
||||
/**
|
||||
* Twitter 공식 embed iframe 주소
|
||||
* @returns {string}
|
||||
*/
|
||||
const tweetEmbedUrl = computed(() => {
|
||||
if (!tweetId.value) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const twitterTheme = theme.value === 'dark' ? 'dark' : 'light'
|
||||
|
||||
return `https://platform.twitter.com/embed/Tweet.html?id=${encodeURIComponent(tweetId.value)}&theme=${twitterTheme}&dnt=true`
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="prose-embed my-8 overflow-hidden rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)]">
|
||||
<div class="prose-embed prose-embed-card my-8 overflow-hidden rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)]">
|
||||
<iframe
|
||||
v-if="youtubeEmbedUrl"
|
||||
class="prose-embed__frame aspect-video w-full"
|
||||
@@ -44,6 +89,14 @@ const youtubeEmbedUrl = computed(() => youtubeId.value ? `https://www.youtube.co
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
/>
|
||||
<iframe
|
||||
v-else-if="tweetEmbedUrl"
|
||||
:key="tweetEmbedUrl"
|
||||
class="prose-embed__tweet min-h-[420px] w-full border-0 sm:min-h-[458px]"
|
||||
:src="tweetEmbedUrl"
|
||||
title="Embedded post"
|
||||
loading="lazy"
|
||||
/>
|
||||
<a
|
||||
v-else
|
||||
class="prose-embed__link block p-5 text-sm font-semibold text-[var(--site-text)] hover:opacity-70"
|
||||
|
||||
Reference in New Issue
Block a user