Compare commits
41 commits
develop
...
chore/chat
Author | SHA1 | Date | |
---|---|---|---|
|
3452a07935 | ||
|
bc14f6d542 | ||
|
52eb4c3183 | ||
|
8e81ef5951 | ||
|
8a57a53e3d | ||
|
b570f3db22 | ||
|
4906d5b080 | ||
|
7e7f6631b3 | ||
|
e1d8f32e94 | ||
|
5755a3804e | ||
|
fc12580b3e | ||
|
08f76206cf | ||
|
7e8de04448 | ||
|
15950ac8c4 | ||
|
7c3fcbba2e | ||
|
12b6a42aa1 | ||
|
6012b90c78 | ||
|
f1c61cf306 | ||
|
00b9803959 | ||
|
463ac25051 | ||
|
f84bcbfc7c | ||
|
b900e38022 | ||
|
1e9fa55bba | ||
|
8abf171409 | ||
|
50b70093e8 | ||
|
39254be442 | ||
|
9793a4d71c | ||
|
eb9d9ace96 | ||
|
c17b532f95 | ||
|
c327a7c20e | ||
|
fee43711cc | ||
|
b0a0d08d8d | ||
|
c316c53595 | ||
|
b81affbbbf | ||
|
aadbc3e0f4 | ||
|
e4f52fb183 | ||
|
0f2f8a188b | ||
|
9977884a2c | ||
|
4aab553567 | ||
|
034701db8f | ||
|
2be97cf50a |
31 changed files with 572 additions and 340 deletions
|
@ -56,10 +56,60 @@ code {
|
||||||
padding-right: var(--space-normal);
|
padding-right: var(--space-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$badge-size: var(--space-normal);
|
||||||
|
$label-badge-size: var(--space-slab);
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
border-radius: var(--border-radius-normal);
|
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-small {
|
||||||
padding-right: var(--space-one);
|
padding-right: var(--space-one);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,10 +220,10 @@ $accordionmenu-arrow-size: 6px;
|
||||||
|
|
||||||
$badge-background: $primary-color;
|
$badge-background: $primary-color;
|
||||||
$badge-color: $white;
|
$badge-color: $white;
|
||||||
$badge-color-alt: $black;
|
$badge-color-alt: $color-body;
|
||||||
$badge-palette: $foundation-palette;
|
$badge-palette: $foundation-palette;
|
||||||
$badge-padding: var(--space-smaller);
|
$badge-padding: var(--space-smaller);
|
||||||
$badge-minwidth: 2.1em;
|
$badge-minwidth: var(--space-normal);
|
||||||
$badge-font-size: var(--font-size-nano);
|
$badge-font-size: var(--font-size-nano);
|
||||||
|
|
||||||
// 10. Breadcrumbs
|
// 10. Breadcrumbs
|
||||||
|
|
|
@ -37,6 +37,10 @@ $default-button-height: 4.0rem;
|
||||||
border-radius: $space-larger;
|
border-radius: $space-larger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.not-rounded {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
// @TODO Use with link
|
// @TODO Use with link
|
||||||
|
|
||||||
&.compact {
|
&.compact {
|
||||||
|
|
|
@ -11,138 +11,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation {
|
.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 {
|
&.active {
|
||||||
animation: left-shift-animation .25s $swift-ease-out-function;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,11 +86,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.page-title {
|
|
||||||
margin-bottom: $zero;
|
|
||||||
margin-left: $space-normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status--filter {
|
.status--filter {
|
||||||
@include padding($zero null $zero $space-normal);
|
@include padding($zero null $zero $space-normal);
|
||||||
@include margin($zero);
|
@include margin($zero);
|
||||||
|
|
|
@ -6,22 +6,7 @@
|
||||||
border-top-width: 0;
|
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 {
|
.tabs-title {
|
||||||
@include margin($zero $space-slab);
|
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
background: $color-background;
|
background: $color-background;
|
||||||
|
@ -33,36 +18,19 @@
|
||||||
padding: $space-smaller;
|
padding: $space-smaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:first-child {
|
a,
|
||||||
margin-left: 0;
|
.button {
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
a {
|
|
||||||
color: darken($medium-gray, 20%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
@include position(relative, 1px null null null);
|
@include position(relative, 1px null null null);
|
||||||
align-items: center;
|
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
color: $medium-gray;
|
height: var(--space-large);
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
font-size: $font-size-small;
|
|
||||||
transition: border-color .15s $swift-ease-out-function;
|
transition: border-color .15s $swift-ease-out-function;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
a {
|
|
||||||
|
a,
|
||||||
|
.button {
|
||||||
border-bottom-color: $color-woot;
|
border-bottom-color: $color-woot;
|
||||||
color: $color-woot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
|
@ -70,4 +38,26 @@
|
||||||
color: $color-woot;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
class="chat-list__top"
|
class="chat-list__top"
|
||||||
:class="{ filter__applied: hasAppliedFiltersOrActiveFolders }"
|
:class="{ filter__applied: hasAppliedFiltersOrActiveFolders }"
|
||||||
>
|
>
|
||||||
<h1 class="page-title text-truncate" :title="pageTitle">
|
<h1 class="page-sub-title text-truncate" :title="pageTitle">
|
||||||
{{ pageTitle }}
|
{{ pageTitle }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
@ -77,7 +77,6 @@
|
||||||
v-if="!hasAppliedFiltersOrActiveFolders"
|
v-if="!hasAppliedFiltersOrActiveFolders"
|
||||||
:items="assigneeTabItems"
|
:items="assigneeTabItems"
|
||||||
:active-tab="activeAssigneeTab"
|
:active-tab="activeAssigneeTab"
|
||||||
class="tab--chat-type"
|
|
||||||
@chatTabChange="updateAssigneeTab"
|
@chatTabChange="updateAssigneeTab"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -658,7 +657,7 @@ export default {
|
||||||
width: 35rem;
|
width: 35rem;
|
||||||
}
|
}
|
||||||
@include breakpoint(xxlarge up) {
|
@include breakpoint(xxlarge up) {
|
||||||
width: 38rem;
|
width: 36rem;
|
||||||
}
|
}
|
||||||
@include breakpoint(xxxlarge up) {
|
@include breakpoint(xxxlarge up) {
|
||||||
flex-basis: 46rem;
|
flex-basis: 46rem;
|
||||||
|
@ -678,6 +677,9 @@ export default {
|
||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-sub-title {
|
||||||
|
margin-left: var(--space-normal);
|
||||||
|
}
|
||||||
.delete-custom-view__button {
|
.delete-custom-view__button {
|
||||||
margin-right: var(--space-normal);
|
margin-right: var(--space-normal);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,6 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$badge-size: var(--space-normal);
|
|
||||||
$label-badge-size: var(--space-slab);
|
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
margin: var(--space-small) 0;
|
margin: var(--space-small) 0;
|
||||||
}
|
}
|
||||||
|
@ -127,6 +124,7 @@ $label-badge-size: var(--space-slab);
|
||||||
font-size: var(--font-size-nano);
|
font-size: var(--font-size-nano);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.badge--label,
|
.badge--label,
|
||||||
.badge--icon {
|
.badge--icon {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
|
@ -171,7 +171,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.secondary-menu--title {
|
.secondary-menu--title {
|
||||||
color: var(--s-600);
|
color: var(--s-700);
|
||||||
display: flex;
|
display: flex;
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
line-height: var(--space-two);
|
line-height: var(--space-two);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
:style="{ background: color }"
|
:style="{ background: color }"
|
||||||
class="label-color-dot"
|
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>
|
<a v-else :href="href" :style="anchorStyle">{{ title }}</a>
|
||||||
<button
|
<button
|
||||||
v-if="showClose"
|
v-if="showClose"
|
||||||
|
@ -112,16 +112,16 @@ export default {
|
||||||
background: var(--s-50);
|
background: var(--s-50);
|
||||||
color: var(--s-800);
|
color: var(--s-800);
|
||||||
border: 1px solid var(--s-75);
|
border: 1px solid var(--s-75);
|
||||||
height: var(--space-medium);
|
height: var(--space-two);
|
||||||
|
line-height: 1.2;
|
||||||
|
|
||||||
&.small {
|
&.small {
|
||||||
font-size: var(--font-size-micro);
|
font-size: var(--font-size-micro);
|
||||||
padding: var(--space-micro) var(--space-smaller);
|
padding: var(--space-micro) var(--space-smaller);
|
||||||
line-height: 1.2;
|
|
||||||
letter-spacing: 0.15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.label--icon {
|
.label--icon {
|
||||||
|
color: inherit;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-right: var(--space-smaller);
|
margin-right: var(--space-smaller);
|
||||||
}
|
}
|
||||||
|
@ -141,16 +141,14 @@ export default {
|
||||||
/* Color Schemes */
|
/* Color Schemes */
|
||||||
&.primary {
|
&.primary {
|
||||||
background: var(--w-100);
|
background: var(--w-100);
|
||||||
color: var(--w-900);
|
color: var(--w-700);
|
||||||
border: 1px solid var(--w-200);
|
|
||||||
a {
|
a {
|
||||||
color: var(--w-900);
|
color: var(--w-900);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.secondary {
|
&.secondary {
|
||||||
background: var(--s-100);
|
background: var(--s-100);
|
||||||
color: var(--s-900);
|
color: var(--s-700);
|
||||||
border: 1px solid var(--s-200);
|
|
||||||
a {
|
a {
|
||||||
color: var(--s-900);
|
color: var(--s-900);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +156,6 @@ export default {
|
||||||
&.success {
|
&.success {
|
||||||
background: var(--g-100);
|
background: var(--g-100);
|
||||||
color: var(--g-900);
|
color: var(--g-900);
|
||||||
border: 1px solid var(--g-200);
|
|
||||||
a {
|
a {
|
||||||
color: var(--g-900);
|
color: var(--g-900);
|
||||||
}
|
}
|
||||||
|
@ -166,7 +163,7 @@ export default {
|
||||||
&.alert {
|
&.alert {
|
||||||
background: var(--r-100);
|
background: var(--r-100);
|
||||||
color: var(--r-900);
|
color: var(--r-900);
|
||||||
border: 1px solid var(--r-200);
|
|
||||||
a {
|
a {
|
||||||
color: var(--r-900);
|
color: var(--r-900);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +171,6 @@ export default {
|
||||||
&.warning {
|
&.warning {
|
||||||
background: var(--y-100);
|
background: var(--y-100);
|
||||||
color: var(--y-900);
|
color: var(--y-900);
|
||||||
border: 1px solid var(--y-200);
|
|
||||||
a {
|
a {
|
||||||
color: var(--y-900);
|
color: var(--y-900);
|
||||||
}
|
}
|
||||||
|
@ -198,7 +194,15 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-action--button {
|
.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 {
|
.label-color-dot {
|
||||||
|
|
|
@ -3,14 +3,21 @@
|
||||||
:class="{
|
:class="{
|
||||||
'tabs-title': true,
|
'tabs-title': true,
|
||||||
'is-active': active,
|
'is-active': active,
|
||||||
|
[variant]: variant,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<a @click="onTabClick">
|
<woot-button
|
||||||
|
:size="size"
|
||||||
|
:variant="buttonVariant"
|
||||||
|
:color-scheme="colorScheme"
|
||||||
|
:is-rounded="isRounded"
|
||||||
|
@click="onTabClick"
|
||||||
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
<span v-if="showBadge" class="badge">
|
<span v-if="showBadge" class="badge">
|
||||||
{{ getItemCount }}
|
{{ getItemCount }}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</woot-button>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -37,6 +44,15 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
variant: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
// Available variants: [ '', 'smooth']
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -47,6 +63,17 @@ export default {
|
||||||
getItemCount() {
|
getItemCount() {
|
||||||
return this.count;
|
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: {
|
methods: {
|
||||||
|
|
|
@ -60,6 +60,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
isRounded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
variantClasses() {
|
variantClasses() {
|
||||||
|
@ -84,6 +88,7 @@ export default {
|
||||||
this.classNames,
|
this.classNames,
|
||||||
this.isDisabled ? 'disabled' : '',
|
this.isDisabled ? 'disabled' : '',
|
||||||
this.isExpanded ? 'expanded' : '',
|
this.isExpanded ? 'expanded' : '',
|
||||||
|
this.isRounded ? '' : 'not-rounded',
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
iconSize() {
|
iconSize() {
|
||||||
|
|
|
@ -43,12 +43,14 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
const fontSize = Math.floor(this.size / 2.5);
|
||||||
|
const lineHeight = this.size + Math.floor(this.size / 20);
|
||||||
let style = {
|
let style = {
|
||||||
width: `${this.size}px`,
|
width: `${this.size}px`,
|
||||||
height: `${this.size}px`,
|
height: `${this.size}px`,
|
||||||
borderRadius: this.rounded ? '50%' : 0,
|
borderRadius: this.rounded ? '50%' : 0,
|
||||||
lineHeight: `${this.size + Math.floor(this.size / 20)}px`,
|
lineHeight: `${Math.max(lineHeight, 12)}px`,
|
||||||
fontSize: `${Math.floor(this.size / 2.5)}px`,
|
fontSize: `${Math.max(fontSize, 8)}px`,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.backgroundColor) {
|
if (this.backgroundColor) {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<woot-tabs :index="activeTabIndex" @change="onTabChange">
|
<woot-tabs class="smooth" :index="activeTabIndex" @change="onTabChange">
|
||||||
<woot-tabs-item
|
<woot-tabs-item
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
:name="item.name"
|
:name="item.name"
|
||||||
:count="item.count"
|
:count="item.count"
|
||||||
|
variant="smooth"
|
||||||
/>
|
/>
|
||||||
</woot-tabs>
|
</woot-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
@ -48,3 +49,12 @@ export default {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.smooth {
|
||||||
|
padding-bottom: var(--space-small);
|
||||||
|
|
||||||
|
&::v-deep .button {
|
||||||
|
padding: var(--space-smaller) var(--space-small);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="inbox--name">
|
<woot-label
|
||||||
<fluent-icon class="inbox--icon" :icon="computedInboxClass" size="12" />
|
:title="inbox.name"
|
||||||
{{ inbox.name }}
|
:icon="computedInboxClass"
|
||||||
</div>
|
color-scheme="secondary"
|
||||||
|
class="inbox--name"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
||||||
|
@ -23,18 +25,13 @@ export default {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.inbox--name {
|
.label.secondary.inbox--name {
|
||||||
display: inline-flex;
|
|
||||||
padding: var(--space-micro) 0;
|
|
||||||
line-height: var(--space-slab);
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--s-500);
|
color: var(--s-600);
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inbox--icon {
|
.label__title {
|
||||||
margin-right: var(--space-micro);
|
line-height: 1.2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
|
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
|
||||||
import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
|
import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
|
||||||
import { mixin as clickaway } from 'vue-clickaway';
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
import { getBleachBgOfHexColor } from 'shared/helpers/ColorHelper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -65,6 +66,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
getBleachBgOfHexColor,
|
||||||
addItem(label) {
|
addItem(label) {
|
||||||
this.$emit('add', label);
|
this.$emit('add', label);
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,12 +11,13 @@ describe(`when there are NO errors loading the thumbnail`, () => {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
imgError: false,
|
imgError: false,
|
||||||
|
hasImageLoaded: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(wrapper.find('#image').exists()).toBe(true);
|
expect(wrapper.find('#image').exists()).toBe(true);
|
||||||
const avatarComponent = wrapper.findComponent(Avatar);
|
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() {
|
data() {
|
||||||
return {
|
return {
|
||||||
imgError: true,
|
imgError: true,
|
||||||
|
hasImageLoaded: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(wrapper.find('#image').exists()).toBe(false);
|
expect(wrapper.find('#image').isVisible()).toBe(false);
|
||||||
const avatarComponent = wrapper.findComponent(Avatar);
|
const avatarComponent = wrapper.findComponent(Avatar);
|
||||||
expect(avatarComponent.exists()).toBe(true);
|
expect(avatarComponent.isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="user-thumbnail-box" :style="{ height: size, width: size }">
|
<div class="user-thumbnail-box" :style="{ height: size, width: size }">
|
||||||
<img
|
<img
|
||||||
v-if="!imgError && Boolean(src)"
|
v-show="shouldShowImage"
|
||||||
id="image"
|
id="image"
|
||||||
:src="src"
|
:src="src"
|
||||||
:class="thumbnailClass"
|
:class="thumbnailClass"
|
||||||
|
@load="() => onImgLoad()"
|
||||||
@error="onImgError()"
|
@error="onImgError()"
|
||||||
/>
|
/>
|
||||||
<Avatar
|
<Avatar
|
||||||
v-else
|
v-show="!shouldShowImage"
|
||||||
:username="username"
|
:username="username"
|
||||||
:class="thumbnailClass"
|
:class="thumbnailClass"
|
||||||
:size="avatarSize"
|
:size="avatarSize"
|
||||||
|
@ -123,6 +124,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
imgError: false,
|
imgError: false,
|
||||||
|
hasImageLoaded: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -147,6 +149,11 @@ export default {
|
||||||
const classname = this.hasBorder ? 'border' : '';
|
const classname = this.hasBorder ? 'border' : '';
|
||||||
return `user-thumbnail ${classname}`;
|
return `user-thumbnail ${classname}`;
|
||||||
},
|
},
|
||||||
|
shouldShowImage() {
|
||||||
|
if (!this.src) return false;
|
||||||
|
if (this.hasImageLoaded) return !this.imgError;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
src: {
|
src: {
|
||||||
|
@ -161,6 +168,9 @@ export default {
|
||||||
onImgError() {
|
onImgError() {
|
||||||
this.imgError = true;
|
this.imgError = true;
|
||||||
},
|
},
|
||||||
|
onImgLoad() {
|
||||||
|
this.hasImageLoaded = true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -177,6 +187,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
vertical-align: initial;
|
||||||
|
|
||||||
&.border {
|
&.border {
|
||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
emoji="😊"
|
emoji="😊"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
@click="toggleEmojiPicker"
|
@click="toggleEmojiPicker"
|
||||||
/>
|
/>
|
||||||
<!-- ensure the same validations for attachment types are implemented in backend models as well -->
|
<!-- ensure the same validations for attachment types are implemented in backend models as well -->
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
emoji="📎"
|
emoji="📎"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
/>
|
/>
|
||||||
</file-upload>
|
</file-upload>
|
||||||
<woot-button
|
<woot-button
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
emoji="🖊️"
|
emoji="🖊️"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
:title="$t('CONVERSATION.REPLYBOX.TIP_FORMAT_ICON')"
|
:title="$t('CONVERSATION.REPLYBOX.TIP_FORMAT_ICON')"
|
||||||
@click="toggleFormatMode"
|
@click="toggleFormatMode"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,71 +24,96 @@
|
||||||
v-if="bulkActionCheck"
|
v-if="bulkActionCheck"
|
||||||
:src="currentContact.thumbnail"
|
:src="currentContact.thumbnail"
|
||||||
:badge="inboxBadge"
|
:badge="inboxBadge"
|
||||||
class="columns"
|
|
||||||
:username="currentContact.name"
|
:username="currentContact.name"
|
||||||
:status="currentContact.availability_status"
|
:status="currentContact.availability_status"
|
||||||
size="40px"
|
size="40px"
|
||||||
/>
|
/>
|
||||||
<div class="conversation--details columns">
|
<div class="message">
|
||||||
<div class="conversation--metadata">
|
<div class="header">
|
||||||
<inbox-name v-if="showInboxName" :inbox="inbox" />
|
<div
|
||||||
<span
|
v-if="showAssignee && assignee.name && false"
|
||||||
v-if="showAssignee && assignee.name"
|
class="assignee-name-wrap"
|
||||||
class="label assignee-label text-truncate"
|
|
||||||
>
|
>
|
||||||
<fluent-icon icon="person" size="12" />
|
<thumbnail
|
||||||
{{ assignee.name }}
|
v-tooltip.top-end="assignee.name"
|
||||||
</span>
|
class="assignee-avatar"
|
||||||
</div>
|
:src="assignee.thumbnail"
|
||||||
<h4 class="conversation--user">
|
:username="assignee.name"
|
||||||
{{ currentContact.name }}
|
size="14px"
|
||||||
</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"
|
|
||||||
/>
|
|
||||||
<fluent-icon
|
|
||||||
v-else-if="messageByAgent"
|
|
||||||
size="16"
|
|
||||||
class="message--attachment-icon last-message-icon"
|
|
||||||
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">
|
|
||||||
{{ parsedLastMessage }}
|
|
||||||
</span>
|
|
||||||
<span v-else-if="lastMessageInChat.attachments">
|
|
||||||
<fluent-icon
|
|
||||||
v-if="attachmentIcon"
|
|
||||||
size="16"
|
|
||||||
class="message--attachment-icon"
|
|
||||||
:icon="attachmentIcon"
|
|
||||||
/>
|
/>
|
||||||
{{ this.$t(`${attachmentMessageContent}`) }}
|
<fluent-icon size="10" icon="chevron-right" class="assignee-arrow" />
|
||||||
|
</div>
|
||||||
|
<h4 class="user-name text-truncate">
|
||||||
|
{{ currentContact.name }}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<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>
|
</span>
|
||||||
<span v-else>
|
<p v-if="lastMessageInChat" class="message__content text-truncate">
|
||||||
{{ $t('CHAT_LIST.NO_CONTENT') }}
|
<fluent-icon v-if="isMessagePrivate" size="12" icon="lock-closed" />
|
||||||
</span>
|
<fluent-icon
|
||||||
</p>
|
v-else-if="messageByAgent"
|
||||||
<p v-else class="conversation--message">
|
size="12"
|
||||||
<fluent-icon size="16" class="message--attachment-icon" icon="info" />
|
icon="arrow-reply"
|
||||||
<span>
|
/>
|
||||||
{{ this.$t(`CHAT_LIST.NO_MESSAGES`) }}
|
<fluent-icon v-else-if="isMessageAnActivity" size="12" icon="info" />
|
||||||
</span>
|
<span
|
||||||
</p>
|
v-if="lastMessageInChat.content"
|
||||||
<div class="conversation--meta">
|
class="content--text text-truncate"
|
||||||
<span class="timestamp">
|
>
|
||||||
{{ dynamicTime(chat.timestamp) }}
|
{{ parsedLastMessage }}
|
||||||
</span>
|
</span>
|
||||||
<span class="unread">{{ unreadCount > 9 ? '9+' : unreadCount }}</span>
|
<span
|
||||||
|
v-else-if="lastMessageInChat.attachments"
|
||||||
|
class="message--with-icon"
|
||||||
|
>
|
||||||
|
<fluent-icon size="12" :icon="attachmentIcon" />
|
||||||
|
{{ $t(`${attachmentMessageContent}`) }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="content--text text-truncate">
|
||||||
|
{{ $t('CHAT_LIST.NO_CONTENT') }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<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="meta">
|
||||||
|
<span class="timestamp">
|
||||||
|
{{ dynamicTime(chat.timestamp) }}
|
||||||
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,6 +129,7 @@ import router from '../../../routes';
|
||||||
import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
|
import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
|
||||||
import InboxName from '../InboxName';
|
import InboxName from '../InboxName';
|
||||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
|
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
|
||||||
|
|
||||||
const ATTACHMENT_ICONS = {
|
const ATTACHMENT_ICONS = {
|
||||||
image: 'image',
|
image: 'image',
|
||||||
|
@ -120,7 +146,13 @@ export default {
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [inboxMixin, timeMixin, conversationMixin, messageFormatterMixin],
|
mixins: [
|
||||||
|
inboxMixin,
|
||||||
|
timeMixin,
|
||||||
|
conversationMixin,
|
||||||
|
messageFormatterMixin,
|
||||||
|
conversationLabelMixin,
|
||||||
|
],
|
||||||
props: {
|
props: {
|
||||||
activeLabel: {
|
activeLabel: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -172,6 +204,11 @@ export default {
|
||||||
currentUser: 'getCurrentUser',
|
currentUser: 'getCurrentUser',
|
||||||
accountId: 'getCurrentAccountId',
|
accountId: 'getCurrentAccountId',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
conversationId() {
|
||||||
|
return this.chat.id;
|
||||||
|
},
|
||||||
|
|
||||||
bulkActionCheck() {
|
bulkActionCheck() {
|
||||||
return !this.hideThumbnail && !this.hovered && !this.selected;
|
return !this.hideThumbnail && !this.hovered && !this.selected;
|
||||||
},
|
},
|
||||||
|
@ -260,10 +297,6 @@ export default {
|
||||||
this.inboxesList.length > 1
|
this.inboxesList.length > 1
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
inboxName() {
|
|
||||||
const stateInbox = this.inbox;
|
|
||||||
return stateInbox.name || '';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
cardClick(chat) {
|
cardClick(chat) {
|
||||||
|
@ -297,76 +330,187 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.conversation {
|
.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 {
|
&:hover {
|
||||||
background: var(--color-background-light);
|
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 {
|
.conversation-selected {
|
||||||
background: var(--color-background-light);
|
background: var(--color-background-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-inbox-name {
|
.message {
|
||||||
&::v-deep .user-thumbnail-box {
|
width: 100%;
|
||||||
margin-top: var(--space-normal);
|
min-width: 0;
|
||||||
align-items: flex-start;
|
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 {
|
.user-name {
|
||||||
.conversation--user {
|
font-size: var(--font-size-small);
|
||||||
padding-top: var(--space-micro);
|
line-height: var(--font-size-medium);
|
||||||
text-overflow: ellipsis;
|
margin-bottom: 0;
|
||||||
overflow: hidden;
|
text-transform: capitalize;
|
||||||
white-space: nowrap;
|
max-width: 60%;
|
||||||
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 {
|
.header {
|
||||||
color: var(--s-600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation--metadata {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
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 {
|
.label {
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--s-500);
|
color: var(--s-600);
|
||||||
font-size: var(--font-size-mini);
|
margin-bottom: 0;
|
||||||
font-weight: var(--font-weight-medium);
|
margin-right: 0;
|
||||||
line-height: var(--space-slab);
|
max-width: 12rem;
|
||||||
padding: var(--space-micro) 0 var(--space-micro) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignee-label {
|
|
||||||
display: inline-flex;
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message--attachment-icon {
|
.footer {
|
||||||
margin-top: var(--space-minus-micro);
|
display: flex;
|
||||||
vertical-align: middle;
|
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);
|
||||||
}
|
}
|
||||||
.checkbox-wrapper {
|
.checkbox-wrapper {
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 100%;
|
flex: 1 0 auto;
|
||||||
margin-top: var(--space-normal);
|
|
||||||
|
height: var(--space-large);
|
||||||
|
width: var(--space-large);
|
||||||
|
border-radius: var(--space-medium);
|
||||||
|
|
||||||
|
margin: var(--space-small) var(--space-smaller) 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--w-100);
|
background-color: var(--w-75);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='checkbox'] {
|
input[type='checkbox'] {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
/>
|
/>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="conversation--header--actions">
|
<div class="conversation--header--actions">
|
||||||
<inbox-name :inbox="inbox" class="margin-right-small" />
|
<inbox-name :inbox="inbox" class="header__inbox-name" />
|
||||||
<span
|
<span
|
||||||
v-if="isSnoozed"
|
v-if="isSnoozed"
|
||||||
class="snoozed--display-text margin-right-small"
|
class="snoozed--display-text margin-right-small"
|
||||||
|
@ -164,7 +164,7 @@ export default {
|
||||||
.user--name {
|
.user--name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: var(--font-size-medium);
|
font-size: var(--font-size-medium);
|
||||||
line-height: 1.3;
|
line-height: 1.2;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -174,6 +174,7 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: var(--font-size-mini);
|
font-size: var(--font-size-mini);
|
||||||
|
padding-top: var(--space-smaller);
|
||||||
|
|
||||||
.user--profile__button {
|
.user--profile__button {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -185,6 +186,12 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header__inbox-name {
|
||||||
|
margin: 0;
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.hmac-warning__icon {
|
.hmac-warning__icon {
|
||||||
color: var(--y-600);
|
color: var(--y-600);
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,16 +453,15 @@ export default {
|
||||||
|
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
|
|
||||||
padding: inherit 0;
|
border-top-left-radius: calc(var(--space-medium) + 1px);
|
||||||
border-top-left-radius: calc(
|
border-bottom-left-radius: calc(var(--space-medium) + 1px);
|
||||||
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: 1px solid var(--color-border-light);
|
border: 1px solid var(--color-border-light);
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
padding: var(--space-small);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||||
import format from 'date-fns/format';
|
import format from 'date-fns/format';
|
||||||
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
|
import formatDistanceToNowStrict from 'date-fns/formatDistanceToNowStrict';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -10,7 +10,7 @@ export default {
|
||||||
},
|
},
|
||||||
dynamicTime(time) {
|
dynamicTime(time) {
|
||||||
const unixTime = fromUnixTime(time);
|
const unixTime = fromUnixTime(time);
|
||||||
return formatDistanceToNow(unixTime, { addSuffix: true });
|
return formatDistanceToNowStrict(unixTime, { addSuffix: true });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<div class="contact-actions">
|
<div class="contact-actions">
|
||||||
<woot-button
|
<woot-button
|
||||||
class="new-message"
|
class="new-message"
|
||||||
size="small expanded"
|
size="tiny expanded"
|
||||||
icon="ion-paper-airplane"
|
icon="ion-paper-airplane"
|
||||||
@click="onNewMessageClick"
|
@click="onNewMessageClick"
|
||||||
>
|
>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
</woot-button>
|
</woot-button>
|
||||||
<woot-button
|
<woot-button
|
||||||
variant="hollow"
|
variant="hollow"
|
||||||
size="small expanded"
|
size="tiny expanded"
|
||||||
icon="edit"
|
icon="edit"
|
||||||
@click="onEditClick"
|
@click="onEditClick"
|
||||||
>
|
>
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
title="$t('CONTACT_PANEL.NEW_MESSAGE')"
|
title="$t('CONTACT_PANEL.NEW_MESSAGE')"
|
||||||
class="new-message"
|
class="new-message"
|
||||||
icon="chat"
|
icon="chat"
|
||||||
size="small"
|
size="tiny"
|
||||||
@click="toggleConversationModal"
|
@click="toggleConversationModal"
|
||||||
/>
|
/>
|
||||||
<woot-button
|
<woot-button
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
class="edit-contact"
|
class="edit-contact"
|
||||||
icon="edit"
|
icon="edit"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
@click="toggleEditModal"
|
@click="toggleEditModal"
|
||||||
/>
|
/>
|
||||||
<woot-button
|
<woot-button
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
class="merge-contact"
|
class="merge-contact"
|
||||||
icon="merge"
|
icon="merge"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
:disabled="uiFlags.isMerging"
|
:disabled="uiFlags.isMerging"
|
||||||
@click="openMergeModal"
|
@click="openMergeModal"
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
class="delete-contact"
|
class="delete-contact"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
variant="smooth"
|
variant="smooth"
|
||||||
size="small"
|
size="tiny"
|
||||||
color-scheme="alert"
|
color-scheme="alert"
|
||||||
:disabled="uiFlags.isDeleting"
|
:disabled="uiFlags.isDeleting"
|
||||||
@click="toggleDeleteModal"
|
@click="toggleDeleteModal"
|
||||||
|
|
|
@ -48,6 +48,10 @@ import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
|
||||||
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
|
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
|
||||||
import { mixin as clickaway } from 'vue-clickaway';
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
|
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
|
||||||
|
import {
|
||||||
|
getBleachBgOfHexColor,
|
||||||
|
getTextShadeOfHexColor,
|
||||||
|
} from 'shared/helpers/ColorHelper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -78,6 +82,8 @@ export default {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getBleachBgOfHexColor,
|
||||||
|
getTextShadeOfHexColor,
|
||||||
toggleLabels() {
|
toggleLabels() {
|
||||||
this.showSearchDropdownLabel = !this.showSearchDropdownLabel;
|
this.showSearchDropdownLabel = !this.showSearchDropdownLabel;
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
--space-normal: 1.6rem;
|
--space-normal: 1.6rem;
|
||||||
--space-two: 2rem;
|
--space-two: 2rem;
|
||||||
--space-medium: 2.4rem;
|
--space-medium: 2.4rem;
|
||||||
--space-three: 3rem;
|
|
||||||
--space-large: 3.2rem;
|
--space-large: 3.2rem;
|
||||||
--space-larger: 4.8rem;
|
--space-larger: 4.8rem;
|
||||||
--space-jumbo: 6.4rem;
|
--space-jumbo: 6.4rem;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="fluent-icon"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
v-for="source in pathSource"
|
v-for="source in pathSource"
|
||||||
|
|
|
@ -24,5 +24,6 @@ export default {
|
||||||
.label--add {
|
.label--add {
|
||||||
margin-bottom: var(--space-micro);
|
margin-bottom: var(--space-micro);
|
||||||
margin-right: var(--space-micro);
|
margin-right: var(--space-micro);
|
||||||
|
height: var(--space-two);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
70
app/javascript/shared/helpers/ColorHelper.js
Normal file
70
app/javascript/shared/helpers/ColorHelper.js
Normal 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 + '%)';
|
||||||
|
};
|
34
app/javascript/shared/helpers/specs/ColorHelper.spec.js
Normal file
34
app/javascript/shared/helpers/specs/ColorHelper.spec.js
Normal 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%)');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue