Files
sb-front/src/components/UserAvatar.vue
T

63 lines
1.5 KiB
Vue
Raw Normal View History

<script setup>
import { computed, ref, watch } from 'vue'
// 작성자/추천자 아바타. 우선순위: 커스텀(profileImage) > 구글(googlePicture) > 이니셜.
const props = defineProps({
name: { type: String, default: '' },
googlePicture: { type: String, default: '' },
profileImage: { type: String, default: '' },
size: { type: Number, default: 28 },
})
const broken = ref(false)
const src = computed(() => props.profileImage || props.googlePicture || '')
const initial = computed(() => {
const s = (props.name || '').trim()
return s ? s[0].toUpperCase() : '?'
})
// src 가 바뀌면 깨짐 상태 리셋
watch(src, () => { broken.value = false })
</script>
<template>
<span class="user-avatar" :style="{ width: size + 'px', height: size + 'px' }" :title="name">
<img
v-if="src && !broken"
:src="src"
:alt="name"
referrerpolicy="no-referrer"
@error="broken = true"
/>
<span v-else class="ua-initial" :style="{ fontSize: Math.round(size * 0.45) + 'px' }">{{ initial }}</span>
</span>
</template>
<style scoped>
.user-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
overflow: hidden;
flex: none;
vertical-align: middle;
background: var(--color-background-mute);
}
.user-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.ua-initial {
font-weight: 700;
color: #fff;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: hsla(160, 100%, 37%, 1);
}
</style>