feat: Add Avatar component

This commit is contained in:
Muhsin Keloth
2024-03-31 13:02:55 +05:30
parent 1935d45a42
commit de982f2c9f
4 changed files with 163 additions and 10 deletions
@@ -0,0 +1,55 @@
<template>
<div class="avatar-container" :style="style" aria-hidden="true">
<slot>{{ userInitial }}</slot>
</div>
</template>
<script>
export default {
name: 'Avatar',
props: {
username: {
type: String,
default: '',
},
size: {
type: Number,
default: 40,
},
},
computed: {
style() {
return {
fontSize: `${Math.floor(this.size / 2.5)}px`,
};
},
userInitial() {
const parts = this.username.split(/[ -]/);
let initials = parts.reduce((acc, curr) => acc + curr.charAt(0), '');
if (initials.length > 2 && initials.search(/[A-Z]/) !== -1) {
initials = initials.replace(/[a-z]+/g, '');
}
initials = initials.substring(0, 2).toUpperCase();
return initials;
},
},
};
</script>
<style scoped>
@tailwind components;
@layer components {
.avatar-color {
background-image: linear-gradient(to top, #c2e1ff 0%, #d6ebff 100%);
}
.dark-avatar-color {
background-image: linear-gradient(to top, #135899 0%, #135899 100%);
}
}
.avatar-container {
@apply flex leading-[100%] font-medium items-center justify-center text-center cursor-default avatar-color dark:dark-avatar-color text-woot-600 dark:text-woot-200;
}
</style>
@@ -1,5 +1,6 @@
<script setup>
import CardLabels from 'dashboard/components/widgets/conversation/conversationCardComponents/CardLabels.vue';
import UserAvatar from './UserAvatar.vue';
defineProps({
slaName: {
type: String,
@@ -18,7 +19,7 @@ defineProps({
<template>
<div
class="grid content-center h-16 grid-cols-12 gap-4 px-6 py-0 bg-white border-b border-slate-75 dark:border-slate-800/50 dark:bg-slate-900"
class="grid content-center items-center h-16 grid-cols-12 gap-4 px-6 py-0 w-full bg-white border-b border-slate-75 dark:border-slate-800/50 dark:bg-slate-900"
>
<div
class="flex items-center capitalize py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 text-left rtl:text-right col-span-2"
@@ -26,25 +27,28 @@ defineProps({
{{ slaName }}
</div>
<div
class="flex items-center col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-100">
{{ `#${conversationId} ` }}
</span>
<span class="text-slate-600 dark:text-slate-100">with </span>
<span class="text-slate-700 dark:text-slate-100 capitalize">{{
<span class="text-slate-700 dark:text-slate-100 capitalize truncate">{{
conversation.contact.name
}}</span>
<card-labels
class="w-[80%]"
:conversation-id="conversationId"
:conversation-labels="conversation.labels"
/>
</div>
<div
class="flex items-center col-span-2 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
Elijah
<div class="flex items-center gap-2 col-span-2">
<user-avatar user-name="Muhsin" src="" />
<span class="text-slate-600 dark:text-slate-200 capitalize truncate">
Muhsin Keloth
</span>
</div>
<div
class="flex items-center col-span-2 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
@@ -1,7 +1,7 @@
<template>
<div>
<div
class="min-w-full border rounded-xl border-slate-75 dark:border-slate-800/50"
class="min-w-full border-t border-x rounded-xl border-slate-75 dark:border-slate-800/50"
>
<!-- Header -->
<div
@@ -35,11 +35,10 @@
/>
</div>
<table-footer
v-if="shouldShowFooter"
:current-page="currentPage"
:total-count="totalCount"
:page-size="pageSize"
class="dark:bg-slate-900 sticky bottom-0"
class="dark:bg-slate-900 sticky bottom-0 border-none"
@page-change="onPageChange"
/>
</div>
@@ -0,0 +1,95 @@
<template>
<div
:style="{ height: size, width: size }"
class="rounded-full flex items-center justify-center bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-100"
:title="username"
>
<slot>
<img
v-if="shouldShowImage"
:src="src"
draggable="false"
@load="onImgLoad"
@error="onImgError"
/>
<div
v-else
:style="{ height: size, width: size }"
class="flex justify-center items-center rounded-full"
aria-hidden="true"
>
<span :style="{ fontSize: fontSize }" class="font-semibold">{{
userInitial
}}</span>
</div>
</slot>
</div>
</template>
<script>
import { removeEmoji } from 'shared/helpers/emoji';
export default {
props: {
src: {
type: String,
default: '',
},
size: {
type: String,
default: '24px',
},
username: {
type: String,
default: '',
},
},
data() {
return {
hasImageLoaded: false,
imgError: false,
};
},
computed: {
userNameWithoutEmoji() {
return removeEmoji(this.username);
},
showStatusIndicator() {
if (this.shouldShowStatusAlways) return true;
return this.status === 'online' || this.status === 'busy';
},
avatarSize() {
return Number(this.size.replace(/\D+/g, ''));
},
shouldShowImage() {
if (!this.src) {
return false;
}
if (this.hasImageLoaded) {
return !this.imgError;
}
return false;
},
userInitial() {
return 'M';
},
fontSize() {
return `${Math.floor(this.avatarSize / 2.5)}px`;
},
},
watch: {
src(value, oldValue) {
if (value !== oldValue && this.imgError) {
this.imgError = false;
}
},
},
methods: {
onImgError() {
this.imgError = true;
},
onImgLoad() {
this.hasImageLoaded = true;
},
},
};
</script>