elearning/Frontend-Learner/components/user/UserAvatar.vue
2026-01-13 10:48:02 +07:00

100 lines
2.1 KiB
Vue

<script setup lang="ts">
const props = defineProps<{
size?: number | string
photoURL?: string
firstName?: string
lastName?: string
}>()
const imageError = ref(false)
const avatarSize = computed(() => {
const s = props.size || 32
if (typeof s === 'number') return `${s}px`
// If it's a string consisting only of digits, append px
if (/^\d+$/.test(s)) return `${s}px`
return s
})
const initials = computed(() => {
const getFirstChar = (name?: string) => {
if (!name) return ''
// For Thai names, if the first char is a leading vowel (เ แ โ ใ ไ), skip it to get the consonant
const leadingVowels = ['เ', 'แ', 'โ', 'ใ', 'ไ']
if (leadingVowels.includes(name.charAt(0)) && name.length > 1) {
return name.charAt(1)
}
return name.charAt(0)
}
const f = getFirstChar(props.firstName)
const l = getFirstChar(props.lastName)
return (f + l).toUpperCase()
})
const handleImageError = () => {
imageError.value = true
}
// Watch for photoURL changes to reset error state
watch(() => props.photoURL, () => {
imageError.value = false
})
</script>
<template>
<div
class="user-avatar"
:style="{ width: avatarSize, height: avatarSize }"
>
<img
v-if="photoURL && !imageError"
:src="photoURL"
class="avatar-img"
@error="handleImageError"
>
<div v-else class="avatar-initials">
{{ initials }}
</div>
</div>
</template>
<style scoped>
.user-avatar {
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--neutral-200);
color: var(--neutral-600);
font-weight: 700;
font-size: 13px;
flex-shrink: 0;
border: 1px solid var(--border-color);
}
.avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.avatar-initials {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #3b82f6; /* Blue-500 to match theme */
color: #ffffff;
user-select: none;
font-size: 13px;
letter-spacing: 0.05em;
}
/* Specific styling for AppHeader integration */
:deep(.avatar-initials) {
text-transform: uppercase;
}
</style>