It might not seem very difficult or complicated but getting avatars right can be harder than it first appears. This is usually because there are multiple different locations avatars can come from. In Lemon Squeezy, we try and show a user avatar based on multiple locations in the following order:
To achieve this, let’s assume each user has three pieces of data:
user_name
avatar_url
(uploaded avatar or Gravatar)user_color
(randomly generated)Here’s what our Avatar component looks like in Vue:
<template>
<div class="relative w-full h-full">
<SvgAvatar
:text="user_name"
:bg-color="user_color"
class="absolute inset-0 w-full h-full"
/>
<img
v-if="avatar_url"
:src="avatar_url"
alt=""
class="absolute inset-0 block w-full h-full rounded-full"
/>
</div>
</template>
<script>
export default {
props: {
user_name: {
type: String,
required: true,
},
user_color: {
type: String,
default: '#7047EB',
},
avatar_url: {
type: String,
default: '',
},
},
};
</script>
Data is passed to the component as props. We then use another component called SvgAvatar
which generates the fallback avatar (colored circle with the user’s initials). Finally, we display the image avatar (custom or Gravatar) if it exists.
We absolutely position both of these elements so that the image is on top of the SvgAvatar
. Why? Well, we always want to show the image avatar if one exists. But what if the user has no custom avatar and has no Gravatar image set? The user will still have a Gravatar URL generated for their email address but we don’t just want to show the default blank Gravatar. We want to show our own fallback SvgAvatar
instead. To get around this, we set the Gravatar default image to “blank” so that it serves a transparent PNG which allows the SvgAvatar
positioned behind it to be seen. This is how we generate the Gravatar URL in the backend:
'https://www.gravatar.com/avatar/' . md5($user->email) . '?d=blank';
Note the d=blank
. Technically we could set the default image to be a fallback image URL that we have generated but I wanted to use SVGs for this and Gravatar only supports images.
The SvgAvatar component looks like this:
<template>
<div v-if="svg" class="svg-avatar" v-html="svg" />
</template>
<script>
import UIAvatarSvg from 'ui-avatar-svg';
export default {
props: {
text: {
type: String,
required: true,
},
bgColor: {
type: String,
default: '#ff0000',
},
textColor: {
type: String,
default: '#ffffff',
},
},
data() {
return {
svg: null,
};
},
mounted() {
this.svg = new UIAvatarSvg()
.text(this.text.charAt(0).toUpperCase())
.bgColor(this.bgColor)
.textColor(this.textColor)
.fontSize(0.6)
.fontWeight(600)
.fontFamily(
"system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'"
)
.generate();
},
};
</script>
I use a small library I built called UI Avatar SVG to generate the svgs. Here we simply pass the user_name
and user_color
as the text
and bgColor
props and use this data to generate the svg fallback avatar. The svg is then output to the div
element using Vue’s v-html
directive.
And that’s how our avatars work in Lemon Squeezy.