Compare commits

...

41 commits

Author SHA1 Message Date
Nithin David Thomas
3452a07935
Merge branch 'develop' into chore/chat-list-design 2022-07-01 12:09:44 +05:30
Nithin David
bc14f6d542 Fixes broken styles 2022-06-21 18:07:07 +05:30
Nithin David
52eb4c3183 Merge branch 'develop' of https://github.com/chatwoot/chatwoot into chore/chat-list-design 2022-06-20 16:19:02 +05:30
Nithin David
8e81ef5951 Changes to conversation card 2022-03-30 20:59:39 +05:30
Sivin Varghese
8a57a53e3d
Merge branch 'develop' into design/update-label-theme 2022-03-30 19:02:41 +05:30
Nithin David
b570f3db22 Improves contrast of light colors 2022-03-30 18:48:57 +05:30
Sivin Varghese
4906d5b080
Merge branch 'develop' into design/update-label-theme 2022-03-30 18:11:12 +05:30
Nithin David
7e7f6631b3 Fixes code climate issue 2022-03-29 20:39:18 +05:30
Sivin Varghese
e1d8f32e94
Merge branch 'develop' into design/update-label-theme 2022-03-29 20:17:30 +05:30
Sivin Varghese
5755a3804e
Merge branch 'develop' into design/update-label-theme 2022-03-29 18:21:40 +05:30
Nithin David
fc12580b3e Changes for contact page 2022-03-29 17:01:36 +05:30
Nithin David
08f76206cf enhancement: Changes theme of labels to smooth 2022-03-29 16:52:58 +05:30
Nithin David Thomas
7e8de04448
Merge branch 'develop' into chore/chat-list-design 2022-03-25 11:38:25 +05:30
Pranav Raj S
15950ac8c4
Merge branch 'develop' into chore/chat-list-design 2022-03-21 13:07:23 +05:30
Nithin David Thomas
7c3fcbba2e
Merge branch 'develop' into chore/chat-list-design 2022-03-17 19:07:14 +05:30
Nithin David
12b6a42aa1 Show labels on chat list 2022-03-16 15:32:26 +05:30
Muhsin Keloth
6012b90c78
Merge branch 'develop' into chore/chat-list-design 2022-02-08 14:39:39 +05:30
Muhsin Keloth
f1c61cf306
Merge branch 'develop' into chore/chat-list-design 2022-01-20 20:33:20 +05:30
Nithin David Thomas
00b9803959
Merge branch 'develop' into chore/chat-list-design 2022-01-20 10:45:20 +05:30
Nithin David Thomas
463ac25051
Merge branch 'develop' into chore/chat-list-design 2022-01-14 06:15:42 +05:30
Nithin David
f84bcbfc7c Style changes to card 2022-01-11 11:52:20 +05:30
Nithin David
b900e38022 Improves conversation card design 2022-01-07 16:16:49 +05:30
Muhsin Keloth
1e9fa55bba
Merge branch 'develop' into chore/chat-list-design 2022-01-05 13:19:25 +05:30
Nithin David
8abf171409 Fixes test cases 2022-01-05 13:15:15 +05:30
Nithin David Thomas
50b70093e8
Merge branch 'develop' into chore/chat-list-design 2022-01-05 12:17:55 +05:30
Nithin David
39254be442 Adjusts icon only button size 2022-01-04 17:49:39 +05:30
Nithin David
9793a4d71c Style changes to suit new design 2022-01-03 17:21:04 +05:30
Nithin David
eb9d9ace96 Merge branch 'develop' of https://github.com/chatwoot/chatwoot into chore/chat-list-design 2021-12-30 12:11:30 +05:30
Nithin David
c17b532f95 Fixes issue with labels alignment 2021-12-21 15:03:45 +05:30
Nithin David
c327a7c20e Fixes right spacing for inbox name 2021-12-20 20:40:01 +05:30
Sivin Varghese
fee43711cc
Merge branch 'develop' into chore/chat-list-design 2021-12-20 10:14:37 +05:30
Nithin David
b0a0d08d8d Merge branch 'develop' of https://github.com/chatwoot/chatwoot into chore/chat-list-design 2021-12-15 13:27:58 +05:30
Nithin David
c316c53595 Style changes 2021-12-14 19:29:21 +05:30
Nithin David
b81affbbbf Fuxes inbox name design on chatlist 2021-12-14 18:58:14 +05:30
Nithin David Thomas
aadbc3e0f4
Merge branch 'develop' into chore/chat-list-design 2021-12-10 15:56:45 +05:30
Nithin David
e4f52fb183 Codeclimate fixes 2021-12-06 20:44:16 +05:30
Sivin Varghese
0f2f8a188b
Merge branch 'develop' into chore/chat-list-design 2021-12-06 08:52:29 +05:30
Nithin David
9977884a2c Fixes colors with labels 2021-12-03 21:16:45 +05:30
Sivin Varghese
4aab553567
Merge branch 'develop' into chore/chat-list-design 2021-12-03 21:10:48 +05:30
Muhsin Keloth
034701db8f
Merge branch 'develop' into chore/chat-list-design 2021-12-03 20:53:35 +05:30
Nithin David
2be97cf50a Chore: Updates design of conversation list 2021-12-03 20:46:49 +05:30
31 changed files with 572 additions and 340 deletions

View file

@ -56,10 +56,60 @@ code {
padding-right: var(--space-normal);
}
$badge-size: var(--space-normal);
$label-badge-size: var(--space-slab);
.badge {
border-radius: var(--border-radius-normal);
font-weight: var(--font-weight-bold);
height: min-content;
line-height: 1;
&.small {
font-size: var(--font-size-nano);
min-width: var(--space-slab);
padding: var(--space-micro);
}
&.rounded {
border-radius: var(--space-mega);
}
&.secondary {
background: var(--s-75);
color: var(--s-500);
font-weight: var(--font-weight-bold);
min-width: unset;
}
}
.badge--label,
.badge--icon {
background: var(--s-100);
border-radius: var(--border-radius-small);
display: inline-flex;
margin-right: var(--space-smaller);
}
.badge--icon {
align-items: center;
height: $badge-size;
justify-content: center;
min-width: $badge-size;
.svg-icon {
color: inherit;
}
}
.badge--label {
height: $label-badge-size;
margin-left: var(--space-smaller);
min-width: $label-badge-size;
}
.padding-right-small {
padding-right: var(--space-one);
}

View file

@ -220,10 +220,10 @@ $accordionmenu-arrow-size: 6px;
$badge-background: $primary-color;
$badge-color: $white;
$badge-color-alt: $black;
$badge-color-alt: $color-body;
$badge-palette: $foundation-palette;
$badge-padding: var(--space-smaller);
$badge-minwidth: 2.1em;
$badge-minwidth: var(--space-normal);
$badge-font-size: var(--font-size-nano);
// 10. Breadcrumbs

View file

@ -37,6 +37,10 @@ $default-button-height: 4.0rem;
border-radius: $space-larger;
}
&.not-rounded {
border-radius: 0;
}
// @TODO Use with link
&.compact {

View file

@ -11,138 +11,10 @@
}
.conversation {
@include flex;
@include flex-shrink;
@include padding(0 0 0 $space-normal);
border-bottom: 1px solid transparent;
border-left: $space-micro solid transparent;
border-top: 1px solid transparent;
cursor: pointer;
position: relative;
&.active {
animation: left-shift-animation .25s $swift-ease-out-function;
background: $color-background;
border-bottom-color: $color-border-light;
border-left-color: $color-woot;
border-top-color: $color-border-light;
.conversation--details {
border-top-color: transparent;
}
+.conversation .conversation--details {
border-top-color: transparent;
}
}
&:first-child {
.conversation--details {
border-top-color: transparent;
}
}
&:last-child {
.conversation--details {
border-bottom-color: $color-border-light;
}
}
.conversation--details {
@include margin(0 0 0 $space-one);
@include border-light-bottom;
@include border-light-top;
@include padding($space-slab 0);
border-bottom-color: transparent;
}
.conversation--user {
font-size: $font-size-small;
margin-bottom: 0;
text-transform: capitalize;
.label {
left: $space-micro;
max-width: $space-jumbo;
overflow: hidden;
position: relative;
text-overflow: ellipsis;
top: $space-micro;
white-space: nowrap;
}
}
.conversation--message {
color: $color-body;
font-size: $font-size-small;
font-weight: $font-weight-normal;
height: $space-medium;
line-height: $space-medium;
margin: 0;
max-width: 96%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 27rem;
}
.conversation--meta {
@include flex;
flex-direction: column;
position: absolute;
right: $space-normal;
top: $space-normal;
.unread {
$unread-size: $space-normal;
@include round-corner;
@include light-shadow;
background: darken($success-color, 3%);
color: $color-white;
display: none;
font-size: $font-size-micro;
font-weight: $font-weight-black;
height: $unread-size;
line-height: $unread-size;
margin-left: auto;
margin-top: $space-smaller;
min-width: $unread-size;
padding: 0 $space-smaller;
text-align: center;
}
.timestamp {
color: $dark-gray;
font-size: $font-size-micro;
font-weight: $font-weight-normal;
line-height: $space-normal;
margin-left: auto;
}
}
&.unread-chat {
.unread {
display: inline-block;
}
.conversation--message {
font-weight: $font-weight-bold;
}
.conversation--user {
font-weight: $font-weight-bold;
}
}
&.compact {
padding-left: 0;
.conversation--details {
border-radius: var(--border-radius-small);
margin-left: 0;
padding-left: var(--space-two);
padding-right: var(--space-small);
}
}
}

View file

@ -86,11 +86,6 @@
align-items: center;
justify-content: space-between;
.page-title {
margin-bottom: $zero;
margin-left: $space-normal;
}
.status--filter {
@include padding($zero null $zero $space-normal);
@include margin($zero);

View file

@ -6,22 +6,7 @@
border-top-width: 0;
}
// Tab chat type
.tab--chat-type {
@include flex;
.tabs-title {
a {
font-size: $font-size-default;
font-weight: $font-weight-medium;
padding-bottom: $space-slab;
padding-top: $space-slab;
}
}
}
.tabs-title {
@include margin($zero $space-slab);
.badge {
background: $color-background;
@ -33,36 +18,19 @@
padding: $space-smaller;
}
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
&:hover,
&:focus {
a {
color: darken($medium-gray, 20%);
}
}
a {
a,
.button {
@include position(relative, 1px null null null);
align-items: center;
border-bottom: 2px solid transparent;
color: $medium-gray;
display: flex;
flex-direction: row;
font-size: $font-size-small;
height: var(--space-large);
transition: border-color .15s $swift-ease-out-function;
}
&.is-active {
a {
a,
.button {
border-bottom-color: $color-woot;
color: $color-woot;
}
.badge {
@ -70,4 +38,26 @@
color: $color-woot;
}
}
// Sleek tabs
&.smooth {
a,
.button {
border-bottom: 0;
top: 0;
.button__content {
align-items: center;
display: inline-flex;
}
}
&.is-active {
.badge {
background: var(--s-100);
color: var(--s-600);
}
}
}
}

View file

@ -5,7 +5,7 @@
class="chat-list__top"
:class="{ filter__applied: hasAppliedFiltersOrActiveFolders }"
>
<h1 class="page-title text-truncate" :title="pageTitle">
<h1 class="page-sub-title text-truncate" :title="pageTitle">
{{ pageTitle }}
</h1>
@ -77,7 +77,6 @@
v-if="!hasAppliedFiltersOrActiveFolders"
:items="assigneeTabItems"
:active-tab="activeAssigneeTab"
class="tab--chat-type"
@chatTabChange="updateAssigneeTab"
/>
@ -658,7 +657,7 @@ export default {
width: 35rem;
}
@include breakpoint(xxlarge up) {
width: 38rem;
width: 36rem;
}
@include breakpoint(xxxlarge up) {
flex-basis: 46rem;
@ -678,6 +677,9 @@ export default {
border-bottom: 1px solid var(--color-border);
}
.page-sub-title {
margin-left: var(--space-normal);
}
.delete-custom-view__button {
margin-right: var(--space-normal);
}

View file

@ -85,9 +85,6 @@ export default {
};
</script>
<style lang="scss" scoped>
$badge-size: var(--space-normal);
$label-badge-size: var(--space-slab);
.button {
margin: var(--space-small) 0;
}
@ -127,6 +124,7 @@ $label-badge-size: var(--space-slab);
font-size: var(--font-size-nano);
}
.badge--label,
.badge--icon {
display: inline-flex;

View file

@ -171,7 +171,7 @@ export default {
}
.secondary-menu--title {
color: var(--s-600);
color: var(--s-700);
display: flex;
font-weight: var(--font-weight-bold);
line-height: var(--space-two);

View file

@ -8,7 +8,7 @@
:style="{ background: color }"
class="label-color-dot"
/>
<span v-if="!href">{{ title }}</span>
<span v-if="!href" class="label__title">{{ title }}</span>
<a v-else :href="href" :style="anchorStyle">{{ title }}</a>
<button
v-if="showClose"
@ -112,16 +112,16 @@ export default {
background: var(--s-50);
color: var(--s-800);
border: 1px solid var(--s-75);
height: var(--space-medium);
height: var(--space-two);
line-height: 1.2;
&.small {
font-size: var(--font-size-micro);
padding: var(--space-micro) var(--space-smaller);
line-height: 1.2;
letter-spacing: 0.15px;
}
.label--icon {
color: inherit;
cursor: pointer;
margin-right: var(--space-smaller);
}
@ -141,16 +141,14 @@ export default {
/* Color Schemes */
&.primary {
background: var(--w-100);
color: var(--w-900);
border: 1px solid var(--w-200);
color: var(--w-700);
a {
color: var(--w-900);
}
}
&.secondary {
background: var(--s-100);
color: var(--s-900);
border: 1px solid var(--s-200);
color: var(--s-700);
a {
color: var(--s-900);
}
@ -158,7 +156,6 @@ export default {
&.success {
background: var(--g-100);
color: var(--g-900);
border: 1px solid var(--g-200);
a {
color: var(--g-900);
}
@ -166,7 +163,7 @@ export default {
&.alert {
background: var(--r-100);
color: var(--r-900);
border: 1px solid var(--r-200);
a {
color: var(--r-900);
}
@ -174,7 +171,6 @@ export default {
&.warning {
background: var(--y-100);
color: var(--y-900);
border: 1px solid var(--y-200);
a {
color: var(--y-900);
}
@ -198,7 +194,15 @@ export default {
}
.label-action--button {
margin-bottom: var(--space-minus-micro);
color: inherit;
display: inline-flex;
align-items: center;
}
.label__title {
max-width: inherit;
overflow: hidden;
text-overflow: ellipsis;
}
.label-color-dot {

View file

@ -3,14 +3,21 @@
:class="{
'tabs-title': true,
'is-active': active,
[variant]: variant,
}"
>
<a @click="onTabClick">
<woot-button
:size="size"
:variant="buttonVariant"
:color-scheme="colorScheme"
:is-rounded="isRounded"
@click="onTabClick"
>
{{ name }}
<span v-if="showBadge" class="badge">
{{ getItemCount }}
</span>
</a>
</woot-button>
</li>
</template>
<script>
@ -37,6 +44,15 @@ export default {
type: Boolean,
default: true,
},
variant: {
type: String,
default: '',
// Available variants: [ '', 'smooth']
},
size: {
type: String,
default: '',
},
},
computed: {
@ -47,6 +63,17 @@ export default {
getItemCount() {
return this.count;
},
colorScheme() {
if (this.variant === 'smooth') return 'secondary';
return this.active ? '' : 'secondary';
},
buttonVariant() {
if (this.variant === 'smooth') return this.active ? 'smooth' : 'clear';
return 'clear';
},
isRounded() {
return this.variant === 'smooth';
},
},
methods: {

View file

@ -60,6 +60,10 @@ export default {
type: Boolean,
default: false,
},
isRounded: {
type: Boolean,
default: true,
},
},
computed: {
variantClasses() {
@ -84,6 +88,7 @@ export default {
this.classNames,
this.isDisabled ? 'disabled' : '',
this.isExpanded ? 'expanded' : '',
this.isRounded ? '' : 'not-rounded',
];
},
iconSize() {

View file

@ -43,12 +43,14 @@ export default {
},
computed: {
style() {
const fontSize = Math.floor(this.size / 2.5);
const lineHeight = this.size + Math.floor(this.size / 20);
let style = {
width: `${this.size}px`,
height: `${this.size}px`,
borderRadius: this.rounded ? '50%' : 0,
lineHeight: `${this.size + Math.floor(this.size / 20)}px`,
fontSize: `${Math.floor(this.size / 2.5)}px`,
lineHeight: `${Math.max(lineHeight, 12)}px`,
fontSize: `${Math.max(fontSize, 8)}px`,
};
if (this.backgroundColor) {

View file

@ -1,10 +1,11 @@
<template>
<woot-tabs :index="activeTabIndex" @change="onTabChange">
<woot-tabs class="smooth" :index="activeTabIndex" @change="onTabChange">
<woot-tabs-item
v-for="item in items"
:key="item.key"
:name="item.name"
:count="item.count"
variant="smooth"
/>
</woot-tabs>
</template>
@ -48,3 +49,12 @@ export default {
},
};
</script>
<style lang="scss" scoped>
.smooth {
padding-bottom: var(--space-small);
&::v-deep .button {
padding: var(--space-smaller) var(--space-small);
}
}
</style>

View file

@ -1,8 +1,10 @@
<template>
<div class="inbox--name">
<fluent-icon class="inbox--icon" :icon="computedInboxClass" size="12" />
{{ inbox.name }}
</div>
<woot-label
:title="inbox.name"
:icon="computedInboxClass"
color-scheme="secondary"
class="inbox--name"
/>
</template>
<script>
import { getInboxClassByType } from 'dashboard/helper/inbox';
@ -23,18 +25,13 @@ export default {
},
};
</script>
<style scoped>
.inbox--name {
display: inline-flex;
padding: var(--space-micro) 0;
line-height: var(--space-slab);
font-weight: var(--font-weight-medium);
<style lang="scss" scoped>
.label.secondary.inbox--name {
background: none;
color: var(--s-500);
font-size: var(--font-size-mini);
}
color: var(--s-600);
.inbox--icon {
margin-right: var(--space-micro);
.label__title {
line-height: 1.2;
}
}
</style>

View file

@ -32,6 +32,7 @@
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
import { mixin as clickaway } from 'vue-clickaway';
import { getBleachBgOfHexColor } from 'shared/helpers/ColorHelper';
export default {
components: {
@ -65,6 +66,7 @@ export default {
},
methods: {
getBleachBgOfHexColor,
addItem(label) {
this.$emit('add', label);
},

View file

@ -11,12 +11,13 @@ describe(`when there are NO errors loading the thumbnail`, () => {
data() {
return {
imgError: false,
hasImageLoaded: true,
};
},
});
expect(wrapper.find('#image').exists()).toBe(true);
const avatarComponent = wrapper.findComponent(Avatar);
expect(avatarComponent.exists()).toBe(false);
expect(avatarComponent.isVisible()).toBe(false);
});
});
@ -29,12 +30,13 @@ describe(`when there ARE errors loading the thumbnail`, () => {
data() {
return {
imgError: true,
hasImageLoaded: true,
};
},
});
expect(wrapper.find('#image').exists()).toBe(false);
expect(wrapper.find('#image').isVisible()).toBe(false);
const avatarComponent = wrapper.findComponent(Avatar);
expect(avatarComponent.exists()).toBe(true);
expect(avatarComponent.isVisible()).toBe(true);
});
});

View file

@ -1,14 +1,15 @@
<template>
<div class="user-thumbnail-box" :style="{ height: size, width: size }">
<img
v-if="!imgError && Boolean(src)"
v-show="shouldShowImage"
id="image"
:src="src"
:class="thumbnailClass"
@load="() => onImgLoad()"
@error="onImgError()"
/>
<Avatar
v-else
v-show="!shouldShowImage"
:username="username"
:class="thumbnailClass"
:size="avatarSize"
@ -123,6 +124,7 @@ export default {
data() {
return {
imgError: false,
hasImageLoaded: false,
};
},
computed: {
@ -147,6 +149,11 @@ export default {
const classname = this.hasBorder ? 'border' : '';
return `user-thumbnail ${classname}`;
},
shouldShowImage() {
if (!this.src) return false;
if (this.hasImageLoaded) return !this.imgError;
return false;
},
},
watch: {
src: {
@ -161,6 +168,9 @@ export default {
onImgError() {
this.imgError = true;
},
onImgLoad() {
this.hasImageLoaded = true;
},
},
};
</script>
@ -177,6 +187,7 @@ export default {
width: 100%;
box-sizing: border-box;
object-fit: cover;
vertical-align: initial;
&.border {
border: 1px solid white;

View file

@ -8,7 +8,7 @@
emoji="😊"
color-scheme="secondary"
variant="smooth"
size="small"
size="tiny"
@click="toggleEmojiPicker"
/>
<!-- ensure the same validations for attachment types are implemented in backend models as well -->
@ -34,7 +34,7 @@
emoji="📎"
color-scheme="secondary"
variant="smooth"
size="small"
size="tiny"
/>
</file-upload>
<woot-button
@ -44,7 +44,7 @@
emoji="🖊️"
color-scheme="secondary"
variant="smooth"
size="small"
size="tiny"
:title="$t('CONVERSATION.REPLYBOX.TIP_FORMAT_ICON')"
@click="toggleFormatMode"
/>

View file

@ -24,71 +24,96 @@
v-if="bulkActionCheck"
:src="currentContact.thumbnail"
:badge="inboxBadge"
class="columns"
:username="currentContact.name"
:status="currentContact.availability_status"
size="40px"
/>
<div class="conversation--details columns">
<div class="conversation--metadata">
<inbox-name v-if="showInboxName" :inbox="inbox" />
<span
v-if="showAssignee && assignee.name"
class="label assignee-label text-truncate"
<div class="message">
<div class="header">
<div
v-if="showAssignee && assignee.name && false"
class="assignee-name-wrap"
>
<fluent-icon icon="person" size="12" />
{{ assignee.name }}
</span>
<thumbnail
v-tooltip.top-end="assignee.name"
class="assignee-avatar"
:src="assignee.thumbnail"
:username="assignee.name"
size="14px"
/>
<fluent-icon size="10" icon="chevron-right" class="assignee-arrow" />
</div>
<h4 class="conversation--user">
<h4 class="user-name text-truncate">
{{ currentContact.name }}
</h4>
<p v-if="lastMessageInChat" class="conversation--message">
<fluent-icon
v-if="isMessagePrivate"
size="16"
class="message--attachment-icon last-message-icon"
icon="lock-closed"
/>
<div class="inbox-name-wrap">
<inbox-name v-if="showInboxName" :inbox="inbox" />
</div>
</div>
<div class="content">
<span v-if="unreadCount" class="unread small badge success">
{{ unreadCount > 9 ? '9+' : unreadCount }}
</span>
<p v-if="lastMessageInChat" class="message__content text-truncate">
<fluent-icon v-if="isMessagePrivate" size="12" icon="lock-closed" />
<fluent-icon
v-else-if="messageByAgent"
size="16"
class="message--attachment-icon last-message-icon"
size="12"
icon="arrow-reply"
/>
<fluent-icon
v-else-if="isMessageAnActivity"
size="16"
class="message--attachment-icon last-message-icon"
icon="info"
/>
<span v-if="lastMessageInChat.content">
<fluent-icon v-else-if="isMessageAnActivity" size="12" icon="info" />
<span
v-if="lastMessageInChat.content"
class="content--text text-truncate"
>
{{ parsedLastMessage }}
</span>
<span v-else-if="lastMessageInChat.attachments">
<fluent-icon
v-if="attachmentIcon"
size="16"
class="message--attachment-icon"
:icon="attachmentIcon"
/>
{{ this.$t(`${attachmentMessageContent}`) }}
<span
v-else-if="lastMessageInChat.attachments"
class="message--with-icon"
>
<fluent-icon size="12" :icon="attachmentIcon" />
{{ $t(`${attachmentMessageContent}`) }}
</span>
<span v-else>
<span v-else class="content--text text-truncate">
{{ $t('CHAT_LIST.NO_CONTENT') }}
</span>
</p>
<p v-else class="conversation--message">
<fluent-icon size="16" class="message--attachment-icon" icon="info" />
<span>
{{ this.$t(`CHAT_LIST.NO_MESSAGES`) }}
<p v-else class="message__content">
<fluent-icon size="12" icon="info" />
<span class="content--text text-truncate">
{{ $t(`CHAT_LIST.NO_MESSAGES`) }}
</span>
</p>
<div class="conversation--meta">
<div class="meta">
<span class="timestamp">
{{ dynamicTime(chat.timestamp) }}
</span>
<span class="unread">{{ unreadCount > 9 ? '9+' : unreadCount }}</span>
</div>
</div>
<div v-if="showAssignee && assignee.name" class="footer">
<div class="assignee-name-wrap">
<fluent-icon size="12" icon="person" class="assignee-arrow" />
<thumbnail
v-if="false"
v-tooltip.top-end="assignee.name"
class="assignee-avatar"
:src="assignee.thumbnail"
:username="assignee.name"
size="14px"
/>
<span class="assignee-name">Nithin David</span>
</div>
<woot-label
v-for="label in activeLabels"
:key="label.id"
:title="label.title"
:description="label.description"
:color="label.color"
variant="smooth"
small
/>
</div>
</div>
</div>
@ -104,6 +129,7 @@ import router from '../../../routes';
import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
import InboxName from '../InboxName';
import inboxMixin from 'shared/mixins/inboxMixin';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
const ATTACHMENT_ICONS = {
image: 'image',
@ -120,7 +146,13 @@ export default {
Thumbnail,
},
mixins: [inboxMixin, timeMixin, conversationMixin, messageFormatterMixin],
mixins: [
inboxMixin,
timeMixin,
conversationMixin,
messageFormatterMixin,
conversationLabelMixin,
],
props: {
activeLabel: {
type: String,
@ -172,6 +204,11 @@ export default {
currentUser: 'getCurrentUser',
accountId: 'getCurrentAccountId',
}),
conversationId() {
return this.chat.id;
},
bulkActionCheck() {
return !this.hideThumbnail && !this.hovered && !this.selected;
},
@ -260,10 +297,6 @@ export default {
this.inboxesList.length > 1
);
},
inboxName() {
const stateInbox = this.inbox;
return stateInbox.name || '';
},
},
methods: {
cardClick(chat) {
@ -297,76 +330,187 @@ export default {
</script>
<style lang="scss" scoped>
.conversation {
align-items: center;
display: flex;
position: relative;
border-radius: var(--border-radius-medium);
cursor: pointer;
margin: var(--space-smaller) var(--space-small);
padding: var(--space-small);
&:hover {
background: var(--color-background-light);
}
&.active {
background: var(--w-25);
}
&.unread-chat {
.message__content {
font-weight: var(--font-weight-medium);
}
.user-name {
font-weight: var(--font-weight-bold);
}
}
&.compact {
padding-left: 0;
margin: var(--space-smaller);
.message {
margin-left: 0;
padding-left: var(--space-small);
}
}
}
.conversation-selected {
background: var(--color-background-light);
}
.has-inbox-name {
&::v-deep .user-thumbnail-box {
margin-top: var(--space-normal);
align-items: flex-start;
.message {
width: 100%;
min-width: 0;
margin-left: var(--space-small);
}
.conversation--meta {
margin-top: var(--space-normal);
.message__content {
display: flex;
align-items: center;
color: var(--color-body);
flex-grow: 0;
font-size: var(--font-size-small);
font-weight: var(--font-weight-normal);
height: var(--font-size-medium);
line-height: var(--font-size-medium);
margin: 0;
max-width: 100%;
width: auto;
.fluent-icon {
flex-shrink: 0;
margin-right: var(--space-micro);
}
}
.conversation--details {
.conversation--user {
padding-top: var(--space-micro);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 60%;
.user-name {
font-size: var(--font-size-small);
line-height: var(--font-size-medium);
margin-bottom: 0;
text-transform: capitalize;
max-width: 60%;
}
.meta {
display: flex;
flex-grow: 1;
flex-shrink: 0;
align-items: center;
justify-content: flex-end;
padding-left: var(--space-medium);
.timestamp {
color: var(--s-500);
font-size: var(--font-size-mini);
font-weight: var(--font-weight-normal);
line-height: var(--font-size-medium);
}
}
.last-message-icon {
color: var(--s-600);
}
.conversation--metadata {
.header {
display: flex;
justify-content: space-between;
padding-right: var(--space-normal);
padding-top: var(--space-micro);
}
.content {
display: flex;
align-items: center;
padding: var(--space-micro) 0 var(--space-micro);
.badge {
color: var(--white);
margin-right: var(--space-smaller);
}
}
.assignee-name-wrap {
display: flex;
align-items: center;
margin-right: var(--space-smaller);
margin-bottom: var(--space-smaller);
}
.assignee-arrow {
color: var(--w-700);
}
.assignee-avatar {
margin-right: var(--space-micro);
}
.message--with-icon {
display: inline-flex;
align-items: center;
}
.inbox-name-wrap {
display: flex;
justify-content: flex-end;
align-items: center;
padding-left: var(--space-normal);
margin-left: auto;
.label {
background: none;
color: var(--s-500);
color: var(--s-600);
margin-bottom: 0;
margin-right: 0;
max-width: 12rem;
}
}
.footer {
display: flex;
align-items: center;
flex-flow: row wrap;
margin-top: var(--space-smaller);
.label {
margin-bottom: var(--space-smaller);
}
}
.assignee-name {
font-size: var(--font-size-mini);
padding-left: var(--space-smaller);
}
.assignee-name-wrap {
border-radius: var(--border-radius-small);
padding: 0 var(--space-smaller) 0 var(--space-smaller);
border: 1px solid var(--w-75);
background: var(--w-25);
color: var(--w-800);
flex-shrink: 0;
font-weight: var(--font-weight-medium);
line-height: var(--space-slab);
padding: var(--space-micro) 0 var(--space-micro) 0;
}
.assignee-label {
display: inline-flex;
max-width: 50%;
}
}
.message--attachment-icon {
margin-top: var(--space-minus-micro);
vertical-align: middle;
}
.checkbox-wrapper {
height: 40px;
width: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 100%;
margin-top: var(--space-normal);
flex: 1 0 auto;
height: var(--space-large);
width: var(--space-large);
border-radius: var(--space-medium);
margin: var(--space-small) var(--space-smaller) 0;
cursor: pointer;
&:hover {
background-color: var(--w-100);
background-color: var(--w-75);
}
input[type='checkbox'] {

View file

@ -20,7 +20,7 @@
/>
</h3>
<div class="conversation--header--actions">
<inbox-name :inbox="inbox" class="margin-right-small" />
<inbox-name :inbox="inbox" class="header__inbox-name" />
<span
v-if="isSnoozed"
class="snoozed--display-text margin-right-small"
@ -164,7 +164,7 @@ export default {
.user--name {
display: inline-block;
font-size: var(--font-size-medium);
line-height: 1.3;
line-height: 1.2;
margin: 0;
text-transform: capitalize;
width: 100%;
@ -174,6 +174,7 @@ export default {
align-items: center;
display: flex;
font-size: var(--font-size-mini);
padding-top: var(--space-smaller);
.user--profile__button {
padding: 0;
@ -185,6 +186,12 @@ export default {
}
}
.header__inbox-name {
margin: 0;
margin-right: var(--space-small);
background: transparent;
}
.hmac-warning__icon {
color: var(--y-600);
}

View file

@ -453,16 +453,15 @@ export default {
background: var(--white);
padding: inherit 0;
border-top-left-radius: calc(
var(--space-medium) + 1px
); /* 100px of height + 10px of border */
border-bottom-left-radius: calc(
var(--space-medium) + 1px
); /* 100px of height + 10px of border */
border-top-left-radius: calc(var(--space-medium) + 1px);
border-bottom-left-radius: calc(var(--space-medium) + 1px);
border: 1px solid var(--color-border-light);
border-right: 0;
box-sizing: border-box;
&:hover {
padding: var(--space-small);
}
}
}
</style>

View file

@ -1,6 +1,6 @@
import fromUnixTime from 'date-fns/fromUnixTime';
import format from 'date-fns/format';
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
import formatDistanceToNowStrict from 'date-fns/formatDistanceToNowStrict';
export default {
methods: {
@ -10,7 +10,7 @@ export default {
},
dynamicTime(time) {
const unixTime = fromUnixTime(time);
return formatDistanceToNow(unixTime, { addSuffix: true });
return formatDistanceToNowStrict(unixTime, { addSuffix: true });
},
},
};

View file

@ -24,7 +24,7 @@
<div class="contact-actions">
<woot-button
class="new-message"
size="small expanded"
size="tiny expanded"
icon="ion-paper-airplane"
@click="onNewMessageClick"
>
@ -32,7 +32,7 @@
</woot-button>
<woot-button
variant="hollow"
size="small expanded"
size="tiny expanded"
icon="edit"
@click="onEditClick"
>

View file

@ -69,7 +69,7 @@
title="$t('CONTACT_PANEL.NEW_MESSAGE')"
class="new-message"
icon="chat"
size="small"
size="tiny"
@click="toggleConversationModal"
/>
<woot-button
@ -78,7 +78,7 @@
class="edit-contact"
icon="edit"
variant="smooth"
size="small"
size="tiny"
@click="toggleEditModal"
/>
<woot-button
@ -88,7 +88,7 @@
class="merge-contact"
icon="merge"
variant="smooth"
size="small"
size="tiny"
color-scheme="secondary"
:disabled="uiFlags.isMerging"
@click="openMergeModal"
@ -100,7 +100,7 @@
class="delete-contact"
icon="delete"
variant="smooth"
size="small"
size="tiny"
color-scheme="alert"
:disabled="uiFlags.isDeleting"
@click="toggleDeleteModal"

View file

@ -48,6 +48,10 @@ import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
import { mixin as clickaway } from 'vue-clickaway';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
import {
getBleachBgOfHexColor,
getTextShadeOfHexColor,
} from 'shared/helpers/ColorHelper';
export default {
components: {
@ -78,6 +82,8 @@ export default {
}),
},
methods: {
getBleachBgOfHexColor,
getTextShadeOfHexColor,
toggleLabels() {
this.showSearchDropdownLabel = !this.showSearchDropdownLabel;
},

View file

@ -10,7 +10,6 @@
--space-normal: 1.6rem;
--space-two: 2rem;
--space-medium: 2.4rem;
--space-three: 3rem;
--space-large: 3.2rem;
--space-larger: 4.8rem;
--space-jumbo: 6.4rem;

View file

@ -5,6 +5,7 @@
fill="none"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
class="fluent-icon"
>
<path
v-for="source in pathSource"

View file

@ -24,5 +24,6 @@ export default {
.label--add {
margin-bottom: var(--space-micro);
margin-right: var(--space-micro);
height: var(--space-two);
}
</style>

View file

@ -0,0 +1,70 @@
export const hexToRGB = H => {
let r = 0;
let g = 0;
let b = 0;
if (H.length === 4) {
r = '0x' + H[1] + H[1];
g = '0x' + H[2] + H[2];
b = '0x' + H[3] + H[3];
} else if (H.length === 7) {
r = '0x' + H[1] + H[2];
g = '0x' + H[3] + H[4];
b = '0x' + H[5] + H[6];
}
return [r, g, b];
};
export const rgbToHSL = (r, g, b) => {
let cmin = Math.min(r, g, b);
let cmax = Math.max(r, g, b);
let delta = cmax - cmin;
let h = 0;
let s = 0;
let l = 0;
if (delta === 0) h = 0;
else if (cmax === r) h = ((g - b) / delta) % 6;
else if (cmax === g) h = (b - r) / delta + 2;
else h = (r - g) / delta + 4;
h = Math.round(h * 60);
if (h < 0) h += 360;
l = (cmax + cmin) / 2;
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return [h, s, l];
};
export const hexToHSLAsArray = H => {
// Convert hex to RGB first
let [r, g, b] = hexToRGB(H);
// Then to HSL
r /= 255;
g /= 255;
b /= 255;
return rgbToHSL(r, g, b);
};
export const hexToHSL = hex => {
const [h, s, l] = hexToHSLAsArray(hex);
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
};
export const getTextShadeOfHexColor = (hex, shade = 24) => {
const [h, s, l] = hexToHSLAsArray(hex);
const newL = Math.min(36, Math.max(l - shade, 40));
return 'hsl(' + h + ',' + s + '%,' + newL + '%)';
};
export const getBleachBgOfHexColor = (hex, bleach = 35) => {
const [h, s, l] = hexToHSLAsArray(hex);
const newL = Math.max(94, Math.min(l + bleach, 96));
return 'hsl(' + h + ',' + s + '%,' + newL + '%)';
};

View file

@ -0,0 +1,34 @@
import {
hexToHSLAsArray,
hexToHSL,
getTextShadeOfHexColor,
getBleachBgOfHexColor,
} from '../ColorHelper';
describe('#hexToHSLAsArray', () => {
it('should return correct color conversion for 6 digit hex', () => {
expect(hexToHSLAsArray('#ffffff')).toEqual([0, 0, 100]);
});
it('should return correct color conversion for 3 digit hex', () => {
expect(hexToHSLAsArray('#fff')).toEqual([0, 0, 100]);
});
});
describe('#hexToHSL', () => {
it('should return correct color conversion for 6 digit hex to hsl string', () => {
expect(hexToHSL('#ffffff')).toEqual('hsl(0,0%,100%)');
});
});
describe('#getTextShadeOfHexColor', () => {
it('should return correct color shade for 6 digit hex to hsl string', () => {
expect(getTextShadeOfHexColor('#ffffff')).toEqual('hsl(0,0%,22%)');
});
});
describe('#getBleachBgOfHexColor', () => {
it('should return correct color shade for 6 digit hex to hsl string', () => {
expect(getBleachBgOfHexColor('#ffffff')).toEqual('hsl(0,0%,96%)');
});
});