관리자 레이아웃과 네비게이션 정리

This commit is contained in:
2026-05-13 10:23:18 +09:00
parent ec9f9ea57f
commit b490d5b90f
17 changed files with 484 additions and 164 deletions

View File

@@ -53,10 +53,24 @@ const imageSrc = computed(() => props.thumbnail || faviconUrl.value)
* @returns {string}
*/
const displayTitle = computed(() => props.title || displayHost.value || props.url)
/**
* 외부 링크로 열어도 되는 URL인지 확인한다.
* @returns {boolean} 허용 여부
*/
const isSafeBookmarkUrl = computed(() => {
try {
const parsedUrl = new URL(props.url)
return ['http:', 'https:'].includes(parsedUrl.protocol)
} catch {
return false
}
})
</script>
<template>
<a
v-if="isSafeBookmarkUrl"
class="prose-bookmark group prose-bookmark-card my-8 flex max-w-full flex-col overflow-hidden rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] no-underline transition-[background-color,box-shadow] hover:bg-[color-mix(in_srgb,var(--site-panel)_86%,var(--site-text)_14%)] sm:flex-row"
:href="url"
target="_blank"
@@ -92,4 +106,7 @@ const displayTitle = computed(() => props.title || displayHost.value || props.ur
</p>
</div>
</a>
<p v-else class="prose-bookmark prose-bookmark-invalid my-8 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] p-5 text-sm font-semibold text-[var(--site-muted)]">
지원하지 않는 북마크 URL입니다.
</p>
</template>

View File

@@ -63,6 +63,22 @@ const youtubeId = computed(() => getYouTubeId(props.url))
const youtubeEmbedUrl = computed(() => youtubeId.value ? `https://www.youtube.com/embed/${youtubeId.value}` : '')
const tweetId = computed(() => getTweetId(props.url))
/**
* 외부 링크로 열어도 되는 URL인지 확인한다.
* @param {string} value - 검사할 URL
* @returns {boolean} 허용 여부
*/
const isSafeExternalUrl = (value) => {
try {
const parsedUrl = new URL(value)
return ['http:', 'https:'].includes(parsedUrl.protocol)
} catch {
return false
}
}
const safeExternalUrl = computed(() => isSafeExternalUrl(props.url) ? props.url : '')
/**
* Twitter 공식 embed iframe 주소
* @returns {string}
@@ -98,13 +114,16 @@ const tweetEmbedUrl = computed(() => {
loading="lazy"
/>
<a
v-else
v-else-if="safeExternalUrl"
class="prose-embed__link block p-5 text-sm font-semibold text-[var(--site-text)] hover:opacity-70"
:href="url"
:href="safeExternalUrl"
target="_blank"
rel="noreferrer"
>
{{ url }}
</a>
<p v-else class="prose-embed__invalid p-5 text-sm font-semibold text-[var(--site-muted)]">
지원하지 않는 임베드 URL입니다.
</p>
</div>
</template>