clean up UserAvatar a little

This commit is contained in:
Alina Beck 2020-01-21 13:26:14 +03:00
parent c5af2dbfb4
commit d20421cb70
2 changed files with 52 additions and 54 deletions

View File

@ -51,13 +51,13 @@ describe('UserAvatar.vue', () => {
})
it('displays user initials', () => {
expect(wrapper.find('.no-image').text()).toEqual('MR')
expect(wrapper.find('.initials').text()).toEqual('MR')
})
it('displays no more than 3 initials', () => {
propsData = { user: { name: 'Ana Paula Nunes Marques' } }
wrapper = Wrapper()
expect(wrapper.find('.no-image').text()).toEqual('APN')
expect(wrapper.find('.initials').text()).toEqual('APN')
})
})
@ -65,6 +65,7 @@ describe('UserAvatar.vue', () => {
beforeEach(() => {
propsData = {
user: {
name: 'Not Anonymous',
avatar: '/avatar.jpg',
},
}
@ -72,7 +73,7 @@ describe('UserAvatar.vue', () => {
})
it('adds a prefix to load the image from the uploads service', () => {
expect(wrapper.find('img').attributes('src')).toBe('/api/avatar.jpg')
expect(wrapper.find('.image').attributes('src')).toBe('/api/avatar.jpg')
})
})
@ -80,6 +81,7 @@ describe('UserAvatar.vue', () => {
beforeEach(() => {
propsData = {
user: {
name: 'Not Anonymous',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sawalazar/128.jpg',
},
}
@ -88,7 +90,7 @@ describe('UserAvatar.vue', () => {
it('keeps the avatar URL as is', () => {
// e.g. our seeds have absolute image URLs
expect(wrapper.find('img').attributes('src')).toBe(
expect(wrapper.find('.image').attributes('src')).toBe(
'https://s3.amazonaws.com/uifaces/faces/twitter/sawalazar/128.jpg',
)
})

View File

@ -1,8 +1,13 @@
<template>
<div :class="[`--${this.size}`, 'user-avatar', { 'no-image': !hasImage || error }]">
<img v-if="hasImage && !error" :src="user.avatar | proxyApiUrl" @error="onError" />
<base-icon name="eye-slash" v-else-if="isAnonymous" />
<span v-else>{{ userInitials }}</span>
<div :class="['user-avatar', size && `--${this.size}`]">
<span class="initials">{{ userInitials }}</span>
<base-icon v-if="isAnonymous" name="eye-slash" />
<img
v-else
:src="user.avatar | proxyApiUrl"
class="image"
@error="event.target.style.display = 'none'"
/>
</div>
</template>
@ -12,77 +17,68 @@ export default {
props: {
size: {
type: String,
default: 'base',
required: false,
validator: value => {
return value.match(/(small|base|large)/)
return value.match(/(small|large)/)
},
},
user: { type: Object, default: null },
},
data() {
return {
error: false,
}
user: {
type: Object,
default: null,
},
},
computed: {
isAnonymous() {
return !this.user || !this.user.name || this.user.name.toLowerCase() === 'anonymous'
},
hasImage() {
return Boolean(this.user && this.user.avatar)
},
userInitials() {
const { name } = this.user || 'Anonymous'
const namesArray = name.split(/[ -]/)
let initials = ''
for (var i = 0; i < namesArray.length; i++) initials += namesArray[i].charAt(0)
if (initials.length > 3 && /[A-Z]/.test(initials)) initials = initials.replace(/[a-z]+/g, '')
return initials.substr(0, 3).toUpperCase()
},
},
methods: {
onError() {
this.error = true
if (this.isAnonymous) return ''
return this.user.name
.match(/\b\w/g)
.join('')
.substring(0, 3)
.toUpperCase()
},
},
}
</script>
<style lang="scss">
.user-avatar {
img {
width: 100%;
border-radius: 50%;
overflow: hidden;
object-fit: cover;
object-position: center;
}
.base-icon {
margin-top: -0.1em;
}
position: relative;
height: $size-avatar-base;
width: $size-avatar-base;
border-radius: 50%;
overflow: hidden;
background-color: $color-primary-dark;
color: $text-color-primary-inverse;
&.--small {
width: $size-avatar-small;
height: $size-avatar-small;
}
&.--base {
border-width: 1px;
width: $size-avatar-base;
height: $size-avatar-base;
}
&.--large {
width: $size-avatar-large;
height: $size-avatar-large;
font-size: $font-size-xx-large;
}
&.no-image {
display: flex;
flex-wrap: wrap;
border-radius: 50%;
align-items: center;
justify-content: center;
background-color: $background-color-secondary;
color: $text-color-primary-inverse;
> .initials,
> .base-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
> .image {
position: relative;
z-index: 5;
width: 100%;
object-fit: cover;
object-position: center;
}
}
</style>