본문 이미지 최적화·라이트박스·번호형 페이지네이션 반영 (v1.10.3)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fallbackSrc: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
alt: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -18,15 +22,22 @@ const props = defineProps({
|
||||
variant: {
|
||||
type: String,
|
||||
default: 'regular'
|
||||
},
|
||||
expandable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const loadFailed = ref(false)
|
||||
const emit = defineEmits(['activate'])
|
||||
|
||||
const hasRenderableSrc = computed(() => String(props.src || '').trim().length > 0)
|
||||
const loadFailed = ref(false)
|
||||
const currentSrc = ref(props.src)
|
||||
|
||||
const hasRenderableSrc = computed(() => String(currentSrc.value || '').trim().length > 0)
|
||||
|
||||
const errorLabel = computed(() => {
|
||||
const trimmed = String(props.src || '').trim()
|
||||
const trimmed = String(props.fallbackSrc || props.src || '').trim()
|
||||
|
||||
if (!trimmed) {
|
||||
return '이미지 URL이 비어 있습니다'
|
||||
@@ -38,6 +49,7 @@ const errorLabel = computed(() => {
|
||||
})
|
||||
|
||||
watch(() => props.src, () => {
|
||||
currentSrc.value = props.src
|
||||
loadFailed.value = false
|
||||
})
|
||||
|
||||
@@ -46,6 +58,11 @@ watch(() => props.src, () => {
|
||||
* @returns {void}
|
||||
*/
|
||||
const onImageError = () => {
|
||||
if (props.fallbackSrc && currentSrc.value !== props.fallbackSrc) {
|
||||
currentSrc.value = props.fallbackSrc
|
||||
return
|
||||
}
|
||||
|
||||
loadFailed.value = true
|
||||
}
|
||||
|
||||
@@ -56,6 +73,18 @@ const onImageError = () => {
|
||||
const onImageLoad = () => {
|
||||
loadFailed.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 이미지 확대 요청을 전달한다.
|
||||
* @returns {void}
|
||||
*/
|
||||
const activateImage = () => {
|
||||
if (!props.expandable || !hasRenderableSrc.value || loadFailed.value) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('activate')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -66,18 +95,25 @@ const onImageLoad = () => {
|
||||
'prose-image--full lg:-mx-20 lg:max-w-none': variant === 'full'
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="prose-image__frame overflow-hidden rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)]"
|
||||
<component
|
||||
:is="expandable && hasRenderableSrc && !loadFailed ? 'button' : 'div'"
|
||||
class="prose-image__frame block w-full overflow-hidden rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] p-0 text-left text-inherit"
|
||||
:class="{
|
||||
'prose-image__frame--empty': !hasRenderableSrc || loadFailed,
|
||||
'prose-image__frame--broken': loadFailed
|
||||
'prose-image__frame--broken': loadFailed,
|
||||
'prose-image__frame--expandable cursor-zoom-in': expandable && hasRenderableSrc && !loadFailed
|
||||
}"
|
||||
:type="expandable && hasRenderableSrc && !loadFailed ? 'button' : undefined"
|
||||
:aria-label="expandable && hasRenderableSrc && !loadFailed ? '이미지 크게 보기' : undefined"
|
||||
@click="activateImage"
|
||||
>
|
||||
<img
|
||||
v-if="hasRenderableSrc && !loadFailed"
|
||||
class="prose-image__media w-full object-cover"
|
||||
:src="src"
|
||||
:src="currentSrc"
|
||||
:alt="alt"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
@load="onImageLoad"
|
||||
@error="onImageError"
|
||||
>
|
||||
@@ -92,7 +128,7 @@ const onImageLoad = () => {
|
||||
{{ errorLabel }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
<figcaption
|
||||
v-if="caption"
|
||||
class="prose-image__caption mt-1.5 text-center text-sm text-[var(--site-muted)]"
|
||||
|
||||
Reference in New Issue
Block a user