feat: Add Avatar component
This commit is contained in:
@@ -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>
|
||||
+11
-7
@@ -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"
|
||||
>
|
||||
|
||||
+2
-3
@@ -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>
|
||||
|
||||
+95
@@ -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>
|
||||
Reference in New Issue
Block a user