feat: Add more files

This commit is contained in:
Muhsin Keloth
2024-04-12 08:34:43 +05:30
parent e8fe3c7c05
commit ca44d6b7a2
14 changed files with 367 additions and 0 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>
@@ -0,0 +1,62 @@
<template>
<div
class="flex flex-1 h-full justify-between flex-col m-0 bg-white dark:bg-slate-900 overflow-auto"
>
<div class="flex p-5 pt-16 mx-auto my-0">
<div class="flex flex-col gap-8 min-w-[335px] sm:w-[720px]">
<span class="font-medium dark:text-white text-slate-900 text-[24px]">
Profile Settings
</span>
<div>
<span
class="text-slate-900 dark:text-slate-25 text-normal font-medium"
>
Profile picture
</span>
<!-- <thumbnail src="" username="John Doe" size="72px" /> -->
</div>
<div>
<span class="text-slate-900 dark:text-slate-25 text-lg font-medium">
Personal message signature
</span>
<div class="w-full h-[1px] bg-slate-200 dark:bg-slate-700 my-2" />
<p class="text-slate-600 dark:text-slate-400 text-sm font-normal">
Create a unique message signature to appear at the end of every
message you send from any inbox. You can also include an inline
image, which is supported in live-chat, email, and API inboxes.
</p>
</div>
<div>
<span class="text-slate-900 dark:text-slate-25 text-lg font-medium">
Hot key to send messages
</span>
<div class="w-full h-[1px] bg-slate-200 dark:bg-slate-700 my-2" />
<p class="text-slate-600 dark:text-slate-400 text-sm font-normal">
You can select a hotkey (either Enter or Cmd/Ctrl+Enter) based on
your preference of writing.
</p>
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1 p-4 border">
<div class="flex flex-row justify-between">
<div class="text-sm">Enter ()</div>
<input type="radio" name="hotkey" value="enter" />
</div>
<div class="text-xs pt-2">
Send messages by pressing Enter key instead of clicking send
button.
</div>
<img class="pt-4" src="/hot-key-enter.png" alt="Enter key" />
</div>
<div class="flex-1 p-4 border">BOX 2</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
// import Thumbnail from './Thumbnail.vue';
</script>
@@ -0,0 +1,228 @@
<template>
<div
:class="thumbnailBoxClass"
:style="{ height: size, width: size }"
:title="title"
>
<!-- Using v-show instead of v-if to avoid flickering as v-if removes dom elements. -->
<slot>
<img
v-show="shouldShowImage"
:src="src"
draggable="false"
:class="thumbnailClass"
@load="onImgLoad"
@error="onImgError"
/>
<Avatar
v-show="!shouldShowImage"
:username="userNameWithoutEmoji"
:class="thumbnailClass"
:size="avatarSize"
/>
<!-- Show image on hover -->
<img
v-show="!shouldShowImage"
src="/upload.png"
draggable="false"
:class="thumbnailClass"
@load="onImgLoad"
@error="onImgError"
/>
</slot>
<img
v-if="badgeSrc"
class="source-badge"
:style="badgeStyle"
:src="uploadImage"
alt="Badge"
/>
<div
v-if="showStatusIndicator"
:class="`source-badge user-online-status user-online-status--${status}`"
:style="statusStyle"
/>
</div>
</template>
<script>
/**
* Thumbnail Component
* Src - source for round image
* Size - Size of the thumbnail
* Badge - Chat source indication { fb / telegram }
* Username - Username for avatar
*/
import Avatar from './Avatar.vue';
import { removeEmoji } from 'shared/helpers/emoji';
export default {
components: {
Avatar,
},
props: {
src: {
type: String,
default: '',
},
size: {
type: String,
default: '40px',
},
badge: {
type: String,
default: '',
},
username: {
type: String,
default: '',
},
status: {
type: String,
default: '',
},
hasBorder: {
type: Boolean,
default: false,
},
shouldShowStatusAlways: {
type: Boolean,
default: false,
},
title: {
type: String,
default: '',
},
variant: {
type: String,
default: 'circle',
},
},
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, ''));
},
badgeSrc() {
return {
instagram_direct_message: 'instagram-dm',
facebook: 'messenger',
'twitter-tweet': 'twitter-tweet',
'twitter-dm': 'twitter-dm',
whatsapp: 'whatsapp',
sms: 'sms',
'Channel::Line': 'line',
'Channel::Telegram': 'telegram',
'Channel::WebWidget': '',
}[this.badge];
},
badgeStyle() {
const size = Math.floor(this.avatarSize / 3);
const badgeSize = `${size + 2}px`;
const borderRadius = `${size / 2}px`;
return { width: badgeSize, height: badgeSize, borderRadius };
},
statusStyle() {
const statusSize = `${this.avatarSize / 4}px`;
return { width: statusSize, height: statusSize };
},
thumbnailClass() {
const className = this.hasBorder
? 'border border-solid border-white dark:border-slate-700/50'
: '';
const variant =
this.variant === 'circle' ? 'thumbnail-rounded' : 'thumbnail-square';
return `user-thumbnail ${className} ${variant}`;
},
thumbnailBoxClass() {
const boxClass = this.variant === 'circle' ? 'is-rounded' : '';
return `user-thumbnail-box ${boxClass}`;
},
shouldShowImage() {
if (!this.src) {
return false;
}
if (this.hasImageLoaded) {
return !this.imgError;
}
return false;
},
},
watch: {
src(value, oldValue) {
if (value !== oldValue && this.imgError) {
this.imgError = false;
}
},
},
methods: {
onImgError() {
this.imgError = true;
},
onImgLoad() {
this.hasImageLoaded = true;
},
},
};
</script>
<style lang="scss" scoped>
.user-thumbnail-box {
flex: 0 0 auto;
max-width: 100%;
position: relative;
.user-thumbnail {
height: 100%;
width: 100%;
box-sizing: border-box;
object-fit: cover;
vertical-align: initial;
}
.source-badge {
border-radius: var(--border-radius-small);
bottom: var(--space-minus-micro);
box-shadow: var(--shadow-small);
height: var(--space-slab);
padding: var(--space-micro);
position: absolute;
right: 0;
width: var(--space-slab);
@apply bg-white dark:bg-slate-900;
}
.user-online-status {
border-radius: 50%;
bottom: var(--space-micro);
&:after {
content: ' ';
}
}
.user-online-status--online {
@apply bg-green-400 dark:bg-green-400;
}
.user-online-status--busy {
@apply bg-yellow-500 dark:bg-yellow-500;
}
.user-online-status--offline {
@apply bg-slate-500 dark:bg-slate-500;
}
}
</style>
@@ -0,0 +1,20 @@
import { frontendURL } from '../../../../helper/URLHelper';
const Index = () => import('./Index.vue');
export default {
routes: [
{
path: frontendURL('accounts/:accountId/personal'),
name: 'personal_settings',
roles: ['administrator', 'agent'],
component: Index,
props: {
headerTitle: 'PROFILE_SETTINGS.TITLE',
icon: 'edit',
showNewButton: false,
showSidemenuIcon: false,
},
},
],
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

@@ -18,6 +18,7 @@ import reports from './reports/reports.routes';
import store from '../../../store';
import sla from './sla/sla.routes';
import teams from './teams/teams.routes';
import personal from './personal/personal.routes';
export default {
routes: [
@@ -39,6 +40,7 @@ export default {
...automation.routes,
...auditlogs.routes,
...billing.routes,
...personal.routes,
...campaigns.routes,
...canned.routes,
...inbox.routes,