feat: Update conversation side panel layout and styling (#12983)
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import Avatar from 'next/avatar/Avatar.vue';
|
||||
|
||||
const props = defineProps({
|
||||
usersList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 24,
|
||||
},
|
||||
showMoreThumbnailsCount: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
moreThumbnailsText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
gap: {
|
||||
type: String,
|
||||
default: 'normal',
|
||||
validator(value) {
|
||||
// The value must match one of these strings
|
||||
return ['normal', 'tight'].includes(value);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const gapClass = computed(() => {
|
||||
if (props.gap === 'tight') {
|
||||
return 'ltr:[&:not(:first-child)]:-ml-2 rtl:[&:not(:first-child)]:-mr-2';
|
||||
}
|
||||
return 'ltr:[&:not(:first-child)]:-ml-1 rtl:[&:not(:first-child)]:-mr-1';
|
||||
});
|
||||
|
||||
const moreThumbnailsClass = computed(() => {
|
||||
if (props.gap === 'tight') {
|
||||
return 'ltr:-ml-2 rtl:-mr-2';
|
||||
}
|
||||
return 'ltr:-ml-1 rtl:-mr-1';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex">
|
||||
<Avatar
|
||||
v-for="user in usersList"
|
||||
:key="user.id"
|
||||
v-tooltip="user.name"
|
||||
:title="user.name"
|
||||
:src="user.thumbnail"
|
||||
:name="user.name"
|
||||
:size="size"
|
||||
class="[&>span]:outline [&>span]:outline-1 [&>span]:outline-n-background [&>span]:shadow"
|
||||
:class="gapClass"
|
||||
rounded-full
|
||||
/>
|
||||
<span
|
||||
v-if="showMoreThumbnailsCount"
|
||||
class="text-n-slate-11 bg-n-slate-4 outline outline-1 outline-n-background text-xs font-medium rounded-full px-2 inline-flex items-center shadow relative"
|
||||
:class="moreThumbnailsClass"
|
||||
>
|
||||
{{ moreThumbnailsText }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -92,6 +92,7 @@ onMounted(() => {
|
||||
:chat="currentChat"
|
||||
:is-on-expanded-view="isOnExpandedLayout"
|
||||
:show-back-button="isOnExpandedLayout && !isInboxView"
|
||||
:class="{ 'border-b border-n-weak !pb-3': !dashboardApps.length }"
|
||||
/>
|
||||
<woot-tabs
|
||||
v-if="dashboardApps.length && currentChat.id"
|
||||
|
||||
@@ -12,6 +12,7 @@ import { conversationListPageURL } from 'dashboard/helper/URLHelper';
|
||||
import { snoozedReopenTime } from 'dashboard/helper/snoozeHelpers';
|
||||
import { useInbox } from 'dashboard/composables/useInbox';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
|
||||
const props = defineProps({
|
||||
chat: {
|
||||
@@ -35,6 +36,15 @@ const conversationHeader = ref(null);
|
||||
const { width } = useElementSize(conversationHeader);
|
||||
const { isAWebWidgetInbox } = useInbox();
|
||||
|
||||
const { uiSettings } = useUISettings();
|
||||
|
||||
const isSidepanelOpen = computed(
|
||||
() =>
|
||||
uiSettings.value.is_contact_sidebar_open ||
|
||||
uiSettings.value.is_copilot_panel_open ||
|
||||
false
|
||||
);
|
||||
|
||||
const currentChat = computed(() => store.getters.getSelectedChat);
|
||||
const accountId = computed(() => store.getters.getCurrentAccountId);
|
||||
|
||||
@@ -91,20 +101,24 @@ const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);
|
||||
ref="conversationHeader"
|
||||
class="flex flex-col items-start gap-x-6 gap-y-2 w-full min-w-0 pt-3 pb-2 ltr:pl-4 rtl:pr-4 ltr:pr-1 rtl:pl-1"
|
||||
:class="{
|
||||
'md:flex-row md:items-center': isOnExpandedView,
|
||||
'lg:flex-row lg:items-center': !isOnExpandedView,
|
||||
'md:flex-row md:items-center': isOnExpandedView && !isSidepanelOpen,
|
||||
'lg:flex-row lg:items-center': isOnExpandedView && isSidepanelOpen,
|
||||
'lg:flex-row lg:items-center': !isOnExpandedView && !isSidepanelOpen,
|
||||
'xl:flex-row xl:items-center': !isOnExpandedView && isSidepanelOpen,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="flex items-center gap-2 min-w-0 w-full"
|
||||
:class="{
|
||||
'md:flex-1 md:basis-0': isOnExpandedView,
|
||||
'lg:flex-1 lg:basis-0': !isOnExpandedView,
|
||||
'md:flex-1 md:basis-0': isOnExpandedView && !isSidepanelOpen,
|
||||
'lg:flex-1 lg:basis-0': isOnExpandedView && isSidepanelOpen,
|
||||
'lg:flex-1 lg:basis-0': !isOnExpandedView && !isSidepanelOpen,
|
||||
'xl:flex-1 xl:basis-0': !isOnExpandedView && isSidepanelOpen,
|
||||
}"
|
||||
>
|
||||
<BackButton v-if="showBackButton" :back-url="backButtonUrl" />
|
||||
|
||||
<div class="flex items-center gap-1 min-w-0 flex-1">
|
||||
<div class="flex items-center gap-1 min-w-0 ltr:mr-2 rtl:ml-2">
|
||||
<span class="text-base font-medium text-n-slate-12 truncate min-w-0">
|
||||
{{ currentContact.name }}
|
||||
</span>
|
||||
@@ -120,8 +134,14 @@ const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);
|
||||
<div
|
||||
class="flex items-center gap-2 min-w-0 w-full"
|
||||
:class="{
|
||||
'md:flex-1 md:basis-0 md:justify-end': isOnExpandedView,
|
||||
'lg:flex-1 lg:basis-0 lg:justify-end': !isOnExpandedView,
|
||||
'md:flex-1 md:basis-0 md:justify-end':
|
||||
isOnExpandedView && !isSidepanelOpen,
|
||||
'lg:flex-1 lg:basis-0 lg:justify-end':
|
||||
isOnExpandedView && isSidepanelOpen,
|
||||
'lg:flex-1 lg:basis-0 lg:justify-end':
|
||||
!isOnExpandedView && !isSidepanelOpen,
|
||||
'xl:flex-1 xl:basis-0 xl:justify-end':
|
||||
!isOnExpandedView && isSidepanelOpen,
|
||||
}"
|
||||
>
|
||||
<div v-if="isSnoozed" class="flex items-center gap-1 min-w-0 shrink">
|
||||
|
||||
@@ -42,7 +42,7 @@ const closeContactPanel = () => {
|
||||
<template>
|
||||
<div
|
||||
v-on-click-outside="() => closeContactPanel()"
|
||||
class="bg-n-surface-2 h-full overflow-hidden flex flex-col fixed top-0 z-40 w-full max-w-sm transition-transform duration-300 ease-in-out ltr:right-0 rtl:left-0 md:static md:w-[320px] md:min-w-[320px] ltr:border-l rtl:border-r border-n-weak 2xl:min-w-[360px] 2xl:w-[360px] shadow-lg md:shadow-none"
|
||||
class="bg-n-surface-2 h-full overflow-hidden flex flex-col fixed top-0 z-40 w-full max-w-sm transition-transform duration-300 ease-in-out ltr:right-0 rtl:left-0 md:static ltr:border-l rtl:border-r border-n-weak md:min-w-[360px] md:w-[360px] shadow-lg md:shadow-none"
|
||||
:class="[
|
||||
{
|
||||
'md:flex': activeTab === 0,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useFunctionGetter } from 'dashboard/composables/store';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
import ShopifyAPI from '../../../api/integrations/shopify';
|
||||
import ShopifyOrderItem from './ShopifyOrderItem.vue';
|
||||
import SidePanelEmptyState from 'dashboard/routes/dashboard/conversation/SidePanelEmptyState.vue';
|
||||
|
||||
const props = defineProps({
|
||||
contactId: {
|
||||
@@ -47,7 +48,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="px-4 py-2 text-n-slate-12">
|
||||
<div class="py-2 px-3 text-n-slate-12">
|
||||
<div v-if="!hasSearchableInfo" class="text-center text-n-slate-12">
|
||||
{{ $t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS') }}
|
||||
</div>
|
||||
@@ -57,8 +58,10 @@ watch(
|
||||
<div v-else-if="error" class="text-center text-n-ruby-12">
|
||||
{{ error }}
|
||||
</div>
|
||||
<div v-else-if="!orders.length" class="text-center text-n-slate-12">
|
||||
{{ $t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS') }}
|
||||
<div v-else-if="!orders.length" class="mt-2">
|
||||
<SidePanelEmptyState
|
||||
:message="$t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS')"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<ShopifyOrderItem
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ const handleCancel = () => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
store.dispatch('teams/fetch');
|
||||
store.dispatch('teams/get');
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import CreateOrLinkIssue from './CreateOrLinkIssue.vue';
|
||||
import LinearIssueItem from './LinearIssueItem.vue';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
import SidePanelEmptyState from 'dashboard/routes/dashboard/conversation/SidePanelEmptyState.vue';
|
||||
import { LINEAR_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import { parseLinearAPIErrorResponse } from 'dashboard/store/utils/api';
|
||||
|
||||
@@ -86,10 +87,10 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="px-4 pt-3 pb-2">
|
||||
<div class="pt-3 px-3 pb-2">
|
||||
<NextButton
|
||||
ghost
|
||||
xs
|
||||
sm
|
||||
slate
|
||||
icon="i-lucide-plus"
|
||||
:label="$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK_BUTTON')"
|
||||
@click="openCreateModal"
|
||||
@@ -100,17 +101,17 @@ onMounted(() => {
|
||||
<Spinner />
|
||||
</div>
|
||||
|
||||
<div v-else-if="!hasIssues" class="flex justify-center p-4">
|
||||
<p class="text-sm text-n-slate-11">
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.NO_LINKED_ISSUES') }}
|
||||
</p>
|
||||
<div v-else-if="!hasIssues" class="mt-2">
|
||||
<SidePanelEmptyState
|
||||
:message="$t('INTEGRATION_SETTINGS.LINEAR.NO_LINKED_ISSUES')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else class="max-h-[300px] overflow-y-auto">
|
||||
<div v-else class="max-h-[300px] overflow-y-auto px-2">
|
||||
<LinearIssueItem
|
||||
v-for="linkedIssue in linkedIssues"
|
||||
:key="linkedIssue.id"
|
||||
class="px-4 pt-3 pb-4 border-b border-n-weak last:border-b-0"
|
||||
class="px-1 pt-3 pb-4 border-b border-n-weak last:border-b-0"
|
||||
:linked-issue="linkedIssue"
|
||||
@unlink-issue="unlinkIssue"
|
||||
/>
|
||||
|
||||
@@ -73,11 +73,11 @@ const variableKey = (item = {}) => {
|
||||
class="bg-n-solid-1 p-1 rounded-xl overflow-auto absolute w-full z-20 shadow-md left-0 bottom-full max-h-[9.75rem] border border-solid border-n-strong mention--box"
|
||||
>
|
||||
<ul class="mb-0 vertical dropdown menu">
|
||||
<woot-dropdown-item
|
||||
<li
|
||||
v-for="(item, index) in items"
|
||||
:id="`mention-item-${index}`"
|
||||
:key="item.key"
|
||||
class="!mb-1"
|
||||
class="mb-1 list-none"
|
||||
@mouseover="onHover(index)"
|
||||
>
|
||||
<button
|
||||
@@ -106,7 +106,7 @@ const variableKey = (item = {}) => {
|
||||
</p>
|
||||
</slot>
|
||||
</button>
|
||||
</woot-dropdown-item>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user