2025-05-03 14:25:34 +02:00

54 lines
1.4 KiB
Vue

<script setup lang="ts">
import { computedAsync } from '@vueuse/core';
import { fallbackAvatar, gravatar } from '~/src/helpers.ts';
import type { User } from '~/src/user.ts';
interface AvatarUser extends Pick<User, 'username' | 'emailHash'> {
email?: User['email'];
avatar?: string;
avatarSource?: User['avatarSource'];
}
const props = withDefaults(defineProps<{
user: AvatarUser;
src?: string;
size?: number;
dsize?: string;
validate?: boolean;
}>(), {
size: 128,
dsize: '6rem',
});
const failedToLoad = ref(false);
const resolvedSrc = computedAsync(async () => {
return props.src ||
props.user.avatar ||
(props.user.avatarSource === 'gravatar' && props.user.email !== undefined
? await gravatar(props.user as AvatarUser & Required<Pick<AvatarUser, 'email'>>, props.size)
: fallbackAvatar(props.user, props.size));
});
</script>
<template>
<span>
<img
:src="resolvedSrc"
alt=""
class="rounded-circle"
:style="`width: ${dsize};height: ${dsize};`"
@error="failedToLoad = true"
>
<small v-if="validate && failedToLoad" class="failed-to-load small text-danger"><T>user.avatar.failed</T></small>
</span>
</template>
<style lang="scss" scoped>
.failed-to-load {
max-width: 200px;
display: inline-block;
}
</style>