Files
live_recorder/frontend/src/components/ui/SafeAvatar.vue
T

70 lines
1.2 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch } from "vue";
const props = withDefaults(defineProps<{
src?: string | null;
alt?: string;
size?: number;
}>(), {
src: "",
alt: "",
size: 48
});
const emit = defineEmits<{
error: [event: Event];
}>();
const failed = ref(false);
const style = computed(() => ({
width: `${props.size}px`,
height: `${props.size}px`
}));
watch(() => props.src, () => {
failed.value = false;
});
function handleError(event: Event) {
failed.value = true;
emit("error", event);
}
</script>
<template>
<span class="safe-avatar" :style="style">
<img
v-if="src && !failed"
:src="src"
:alt="alt"
loading="lazy"
decoding="async"
referrerpolicy="no-referrer"
@error="handleError"
/>
<span v-else class="safe-avatar__fallback"><slot /></span>
</span>
</template>
<style scoped>
.safe-avatar {
display: inline-grid;
flex: 0 0 auto;
place-items: center;
overflow: hidden;
border-radius: 50%;
color: var(--accent-strong);
background: var(--accent-soft);
font-weight: 700;
}
.safe-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.safe-avatar__fallback {
line-height: 1;
}
</style>