feat: Update conversation side panel layout and styling (#12983)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Switch from 'dashboard/components-next/switch/Switch.vue';
|
||||
@@ -19,28 +19,35 @@ const emit = defineEmits(['update', 'delete']);
|
||||
|
||||
const attributeValue = ref(Boolean(props.attribute.value));
|
||||
|
||||
const isAttributePresent = computed(() => {
|
||||
return (
|
||||
props.attribute.value !== undefined &&
|
||||
props.attribute.value !== null &&
|
||||
props.attribute.value !== ''
|
||||
);
|
||||
});
|
||||
|
||||
const handleChange = value => {
|
||||
emit('update', value);
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
attributeValue.value = false;
|
||||
emit('delete');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center w-full gap-2"
|
||||
:class="{
|
||||
'justify-start': isEditingView,
|
||||
'justify-end': !isEditingView,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center w-full gap-2 justify-end">
|
||||
<Switch v-model="attributeValue" @change="handleChange" />
|
||||
<Button
|
||||
v-if="isEditingView"
|
||||
variant="faded"
|
||||
color="ruby"
|
||||
v-if="isEditingView && isAttributePresent"
|
||||
ghost
|
||||
ruby
|
||||
icon="i-lucide-trash"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
@click="emit('delete')"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -75,20 +75,15 @@ const handleInputUpdate = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center w-full min-w-0 gap-2"
|
||||
:class="{
|
||||
'justify-start': isEditingView,
|
||||
'justify-end': !isEditingView,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center w-full min-w-0 gap-1.5 justify-end">
|
||||
<span
|
||||
v-if="!isEditingValue"
|
||||
class="min-w-0 text-sm"
|
||||
:class="{
|
||||
'cursor-pointer text-n-slate-11 hover:text-n-slate-12 py-2 select-none font-medium':
|
||||
!isEditingView,
|
||||
'text-n-slate-12 truncate': isEditingView,
|
||||
'text-n-slate-12 truncate': isEditingView && attribute.value,
|
||||
'text-n-slate-10 truncate': isEditingView && !attribute.value,
|
||||
}"
|
||||
@click="toggleEditValue(!isEditingView)"
|
||||
>
|
||||
@@ -100,19 +95,20 @@ const handleInputUpdate = async () => {
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<Button
|
||||
variant="faded"
|
||||
color="slate"
|
||||
icon="i-lucide-pencil"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
ghost
|
||||
slate
|
||||
icon="i-lucide-pen-line"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="toggleEditValue(true)"
|
||||
/>
|
||||
<Button
|
||||
variant="faded"
|
||||
color="ruby"
|
||||
v-if="attribute.value"
|
||||
ghost
|
||||
ruby
|
||||
icon="i-lucide-trash"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="emit('delete')"
|
||||
/>
|
||||
</div>
|
||||
@@ -125,7 +121,7 @@ const handleInputUpdate = async () => {
|
||||
<Input
|
||||
v-model="defaultDateValue"
|
||||
type="date"
|
||||
class="w-full [&>p]:absolute [&>p]:mt-0.5 [&>p]:top-8 ltr:[&>p]:left-0 rtl:[&>p]:right-0"
|
||||
class="w-full [&>p]:absolute [&>p]:mt-1 [&>p]:top-6 ltr:[&>p]:left-0 rtl:[&>p]:right-0"
|
||||
:message="
|
||||
hasError
|
||||
? t('CONTACTS_LAYOUT.SIDEBAR.ATTRIBUTES.VALIDATIONS.INVALID_DATE')
|
||||
@@ -133,14 +129,15 @@ const handleInputUpdate = async () => {
|
||||
"
|
||||
:message-type="hasError ? 'error' : 'info'"
|
||||
autofocus
|
||||
custom-input-class="h-8 ltr:rounded-r-none rtl:rounded-l-none"
|
||||
@keyup.enter="handleInputUpdate"
|
||||
custom-input-class="h-7 py-1 ltr:rounded-r-none rtl:rounded-l-none"
|
||||
@enter="handleInputUpdate"
|
||||
/>
|
||||
<Button
|
||||
icon="i-lucide-check"
|
||||
:color="hasError ? 'ruby' : 'blue'"
|
||||
size="sm"
|
||||
class="flex-shrink-0 ltr:rounded-l-none rtl:rounded-r-none"
|
||||
type="button"
|
||||
class="flex-shrink-0 ltr:rounded-l-none rtl:rounded-r-none !h-7"
|
||||
@click="handleInputUpdate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
|
||||
const props = defineProps({
|
||||
attribute: {
|
||||
@@ -40,61 +41,55 @@ const handleAttributeAction = async action => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center w-full min-w-0 gap-2"
|
||||
:class="{
|
||||
'justify-start': isEditingView,
|
||||
'justify-end': !isEditingView,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center w-full min-w-0 gap-1.5 justify-end">
|
||||
<div
|
||||
v-on-clickaway="() => toggleAttributeListDropdown(false)"
|
||||
class="relative flex items-center"
|
||||
class="relative flex items-center min-w-0 flex-1 justify-end gap-2 cursor-pointer"
|
||||
@click="toggleAttributeListDropdown()"
|
||||
>
|
||||
<span
|
||||
class="min-w-0 text-sm"
|
||||
v-tooltip.top="{
|
||||
content: attribute.value,
|
||||
delay: { show: 1000, hide: 0 },
|
||||
}"
|
||||
class="min-w-0 text-sm truncate font-420"
|
||||
:class="{
|
||||
'cursor-pointer text-n-slate-11 hover:text-n-slate-12 py-2 select-none font-medium':
|
||||
'text-n-slate-11 hover:text-n-slate-12 py-2 select-none font-medium':
|
||||
!isEditingView,
|
||||
'text-n-slate-12 truncate flex-1': isEditingView,
|
||||
'text-n-slate-12': isEditingView && attribute.value,
|
||||
'text-n-slate-10': isEditingView && !attribute.value,
|
||||
}"
|
||||
@click="toggleAttributeListDropdown(!props.isEditingView)"
|
||||
>
|
||||
{{
|
||||
attribute.value ||
|
||||
t('CONTACTS_LAYOUT.SIDEBAR.ATTRIBUTES.TRIGGER.SELECT')
|
||||
}}
|
||||
</span>
|
||||
<Icon
|
||||
:icon="
|
||||
showAttributeListDropdown
|
||||
? 'i-lucide-chevron-up'
|
||||
: 'i-lucide-chevron-down'
|
||||
"
|
||||
class="text-n-slate-11 flex-shrink-0 size-4"
|
||||
/>
|
||||
<DropdownMenu
|
||||
v-if="showAttributeListDropdown"
|
||||
:menu-items="attributeListMenuItems"
|
||||
show-search
|
||||
class="w-48 mt-2 top-full"
|
||||
:class="{
|
||||
'ltr:right-0 rtl:left-0': !isEditingView,
|
||||
'ltr:left-0 rtl:right-0': isEditingView,
|
||||
}"
|
||||
class="w-48 mt-2 top-full ltr:right-0 rtl:left-0"
|
||||
@action="handleAttributeAction($event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="isEditingView" class="flex items-center gap-1">
|
||||
<Button
|
||||
variant="faded"
|
||||
color="slate"
|
||||
icon="i-lucide-pencil"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
@click="toggleAttributeListDropdown()"
|
||||
/>
|
||||
<Button
|
||||
variant="faded"
|
||||
color="ruby"
|
||||
icon="i-lucide-trash"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
@click="emit('delete')"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
v-if="isEditingView && attribute.value"
|
||||
ghost
|
||||
ruby
|
||||
icon="i-lucide-trash"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="emit('delete')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -114,24 +114,24 @@ const handleInputUpdate = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center w-full min-w-0 gap-2"
|
||||
:class="{
|
||||
'justify-start': isEditingView,
|
||||
'justify-end': !isEditingView,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center w-full min-w-0 gap-1.5 justify-end">
|
||||
<span
|
||||
v-if="!isEditingValue"
|
||||
class="min-w-0 text-sm"
|
||||
:class="{
|
||||
'cursor-pointer text-n-slate-11 hover:text-n-slate-12 py-2 select-none font-medium':
|
||||
!isEditingView,
|
||||
'text-n-slate-12 truncate': isEditingView && !isAttributeTypeLink,
|
||||
'truncate hover:text-n-brand text-n-blue-text':
|
||||
isEditingView && isAttributeTypeLink,
|
||||
v-tooltip.top="{
|
||||
content: !isAttributeTypeLink ? attribute.value : '',
|
||||
delay: { show: 1000, hide: 0 },
|
||||
}"
|
||||
@click="toggleEditValue(!isEditingView)"
|
||||
class="min-w-0 text-sm cursor-pointer font-420"
|
||||
:class="{
|
||||
'text-n-slate-11 hover:text-n-slate-12 py-2 select-none font-medium':
|
||||
!isEditingView,
|
||||
'text-n-slate-12 truncate':
|
||||
isEditingView && !isAttributeTypeLink && attribute.value,
|
||||
'text-n-slate-10 truncate': isEditingView && !attribute.value,
|
||||
'truncate hover:text-n-brand text-n-blue-10':
|
||||
isEditingView && isAttributeTypeLink && attribute.value,
|
||||
}"
|
||||
@click="toggleEditValue(true)"
|
||||
>
|
||||
<a
|
||||
v-if="isAttributeTypeLink && attribute.value && isEditingView"
|
||||
@@ -156,19 +156,20 @@ const handleInputUpdate = async () => {
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<Button
|
||||
variant="faded"
|
||||
color="slate"
|
||||
icon="i-lucide-pencil"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
ghost
|
||||
slate
|
||||
icon="i-lucide-pen-line"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="toggleEditValue(true)"
|
||||
/>
|
||||
<Button
|
||||
variant="faded"
|
||||
color="ruby"
|
||||
v-if="attribute.value"
|
||||
ghost
|
||||
ruby
|
||||
icon="i-lucide-trash"
|
||||
size="xs"
|
||||
class="flex-shrink-0 opacity-0 group-hover/attribute:opacity-100 hover:no-underline"
|
||||
xs
|
||||
class="flex-shrink-0 !size-5 !rounded"
|
||||
@click="emit('delete')"
|
||||
/>
|
||||
</div>
|
||||
@@ -182,18 +183,19 @@ const handleInputUpdate = async () => {
|
||||
v-model="editedValue"
|
||||
:placeholder="t('CONTACTS_LAYOUT.SIDEBAR.ATTRIBUTES.TRIGGER.INPUT')"
|
||||
:type="getInputType"
|
||||
class="w-full [&>p]:absolute [&>p]:mt-0.5 [&>p]:top-8 ltr:[&>p]:left-0 rtl:[&>p]:right-0"
|
||||
class="w-full [&>p]:absolute [&>p]:mt-1 [&>p]:top-6 ltr:[&>p]:left-0 rtl:[&>p]:right-0"
|
||||
autofocus
|
||||
:message="attributeErrorMessage"
|
||||
:message-type="hasError ? 'error' : 'info'"
|
||||
custom-input-class="h-8 ltr:rounded-r-none rtl:rounded-l-none"
|
||||
@keyup.enter="handleInputUpdate"
|
||||
custom-input-class="h-7 py-1 ltr:rounded-r-none rtl:rounded-l-none"
|
||||
@enter="handleInputUpdate"
|
||||
/>
|
||||
<Button
|
||||
icon="i-lucide-check"
|
||||
:color="hasError ? 'ruby' : 'blue'"
|
||||
size="sm"
|
||||
class="flex-shrink-0 ltr:rounded-l-none rtl:rounded-r-none"
|
||||
type="button"
|
||||
class="flex-shrink-0 ltr:rounded-l-none rtl:rounded-r-none !h-7"
|
||||
@click="handleInputUpdate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user