mitlist/fe/src/components/valerie/VAvatar.vue

93 lines
2.6 KiB
Vue

<template>
<div class="avatar">
<img v-if="src" :src="src" :alt="alt" class="avatar-img" @error="handleImageError" />
<span v-else-if="initials" class="avatar-initials">{{ initials }}</span>
<slot v-else></slot>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, watch } from 'vue';
export default defineComponent({
name: 'VAvatar',
props: {
src: {
type: String,
default: null,
},
initials: {
type: String,
default: null,
},
alt: {
type: String,
default: 'Avatar',
},
},
setup(props, { slots }) {
// Optional: Handle image loading errors, e.g., to show initials or slot content as a fallback
const imageError = ref(false);
const handleImageError = () => {
imageError.value = true;
};
watch(() => props.src, (newSrc) => {
if (newSrc) {
imageError.value = false; // Reset error state when src changes
}
});
// This computed prop is not strictly necessary for the template logic above,
// but can be useful if template logic becomes more complex or for debugging.
const showImage = computed(() => props.src && !imageError.value);
const showInitials = computed(() => !showImage.value && props.initials);
const showSlot = computed(() => !showImage.value && !showInitials.value && slots.default);
return {
handleImageError,
// expose computed if needed by a more complex template
// showImage,
// showInitials,
// showSlot,
};
},
});
</script>
<style lang="scss" scoped>
.avatar {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px; // Default size, can be made a prop or customized via CSS
height: 40px; // Default size
border-radius: 50%;
background-color: #E9ECEF; // Placeholder background, customize as needed (e.g., Gray-200)
color: #495057; // Placeholder text color (e.g., Gray-700)
font-weight: 500;
overflow: hidden; // Ensure content (like images) is clipped to the circle
vertical-align: middle; // Better alignment with surrounding text/elements
.avatar-img {
width: 100%;
height: 100%;
object-fit: cover; // Ensures the image covers the area without distortion
}
.avatar-initials {
font-size: 0.9em; // Adjust based on avatar size and desired text appearance
line-height: 1; // Ensure initials are centered vertically
text-transform: uppercase;
}
// If using an icon via slot, you might want to style it too
// Example:
// ::v-deep(svg), ::v-deep(.icon) { // if slot contains an icon component or raw svg
// width: 60%;
// height: 60%;
// }
}
</style>