mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 20:18:08 +00:00
chore: Replace darkmode mixin with useDarkMode composable [CW-3474] (#9949)
# Pull Request Template ## Description Replaces darkModeMixin with the new useDarkMode composable and replaces wll usages of mixin the the composable in components and pages Fixes https://linear.app/chatwoot/issue/CW-3474/rewrite-darkmodemixin-mixin-to-a-composable ## Type of change Please delete options that are not relevant. - [x] New feature (non-breaking change which adds functionality) --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import CardButton from 'shared/components/CardButton.vue';
|
import CardButton from 'shared/components/CardButton.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
CardButton,
|
CardButton,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -25,21 +24,30 @@ export default {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {},
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="card-message chat-bubble agent"
|
class="card-message chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700')"
|
||||||
>
|
>
|
||||||
<img class="media" :src="mediaUrl" />
|
<img class="media" :src="mediaUrl" />
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="title" :class="$dm('text-black-900', 'dark:text-slate-50')">
|
<h4
|
||||||
|
class="title"
|
||||||
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h4>
|
</h4>
|
||||||
<p class="body" :class="$dm('text-black-700', 'dark:text-slate-100')">
|
<p
|
||||||
|
class="body"
|
||||||
|
:class="getThemeClass('text-black-700', 'dark:text-slate-100')"
|
||||||
|
>
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</p>
|
</p>
|
||||||
<CardButton v-for="action in actions" :key="action.id" :action="action" />
|
<CardButton v-for="action in actions" :key="action.id" :action="action" />
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { getContrastingTextColor } from '@chatwoot/utils';
|
import { getContrastingTextColor } from '@chatwoot/utils';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
buttonLabel: {
|
buttonLabel: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -19,6 +18,10 @@ export default {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
formValues: {},
|
formValues: {},
|
||||||
@@ -33,8 +36,8 @@ export default {
|
|||||||
return getContrastingTextColor(this.widgetColor);
|
return getContrastingTextColor(this.widgetColor);
|
||||||
},
|
},
|
||||||
inputColor() {
|
inputColor() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')}
|
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
|
||||||
${this.$dm('text-black-900', 'dark:text-slate-50')}`;
|
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
isFormValid() {
|
isFormValid() {
|
||||||
return this.items.reduce((acc, { name }) => {
|
return this.items.reduce((acc, { name }) => {
|
||||||
@@ -80,7 +83,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="form chat-bubble agent"
|
class="form chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700')"
|
||||||
>
|
>
|
||||||
<form @submit.prevent="onSubmit">
|
<form @submit.prevent="onSubmit">
|
||||||
<div
|
<div
|
||||||
@@ -91,7 +94,7 @@ export default {
|
|||||||
'has-submitted': hasSubmitted,
|
'has-submitted': hasSubmitted,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<label :class="$dm('text-black-900', 'dark:text-slate-50')">{{
|
<label :class="getThemeClass('text-black-900', 'dark:text-slate-50')">{{
|
||||||
item.label
|
item.label
|
||||||
}}</label>
|
}}</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
import { CSAT_RATINGS } from 'shared/constants/messages';
|
import { CSAT_RATINGS } from 'shared/constants/messages';
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import { getContrastingTextColor } from '@chatwoot/utils';
|
import { getContrastingTextColor } from '@chatwoot/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -11,7 +11,6 @@ export default {
|
|||||||
Spinner,
|
Spinner,
|
||||||
FluentIcon,
|
FluentIcon,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
messageContentAttributes: {
|
messageContentAttributes: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -22,6 +21,10 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
email: '',
|
email: '',
|
||||||
@@ -44,8 +47,8 @@ export default {
|
|||||||
return !(this.selectedRating && this.feedback);
|
return !(this.selectedRating && this.feedback);
|
||||||
},
|
},
|
||||||
inputColor() {
|
inputColor() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')}
|
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
|
||||||
${this.$dm('text-black-900', 'dark:text-slate-50')}`;
|
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
textColor() {
|
textColor() {
|
||||||
return getContrastingTextColor(this.widgetColor);
|
return getContrastingTextColor(this.widgetColor);
|
||||||
@@ -105,10 +108,13 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="customer-satisfaction"
|
class="customer-satisfaction"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700')"
|
||||||
:style="{ borderColor: widgetColor }"
|
:style="{ borderColor: widgetColor }"
|
||||||
>
|
>
|
||||||
<h6 class="title" :class="$dm('text-slate-900', 'dark:text-slate-50')">
|
<h6
|
||||||
|
class="title"
|
||||||
|
:class="getThemeClass('text-slate-900', 'dark:text-slate-50')"
|
||||||
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h6>
|
</h6>
|
||||||
<div class="ratings">
|
<div class="ratings">
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDate } from 'shared/helpers/DateHelper';
|
import { formatDate } from 'shared/helpers/DateHelper';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
date: {
|
date: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formattedDate() {
|
formattedDate() {
|
||||||
return formatDate({
|
return formatDate({
|
||||||
@@ -25,7 +28,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="date--separator"
|
class="date--separator"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-200')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-200')"
|
||||||
>
|
>
|
||||||
{{ formattedDate }}
|
{{ formattedDate }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import DateSeparator from '../DateSeparator.vue';
|
|||||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
import VueI18n from 'vue-i18n';
|
import VueI18n from 'vue-i18n';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
|
||||||
const localVue = createLocalVue();
|
const localVue = createLocalVue();
|
||||||
import i18n from 'dashboard/i18n';
|
import i18n from 'dashboard/i18n';
|
||||||
localVue.use(Vuex);
|
localVue.use(Vuex);
|
||||||
@@ -40,7 +39,6 @@ describe('dateSeparator', () => {
|
|||||||
propsData: { date: 'Nov 18, 2019' },
|
propsData: { date: 'Nov 18, 2019' },
|
||||||
mocks: { $t: msg => msg },
|
mocks: { $t: msg => msg },
|
||||||
i18n: i18nConfig,
|
i18n: i18nConfig,
|
||||||
mixins: [darkModeMixin],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ON_CAMPAIGN_MESSAGE_CLICK,
|
ON_CAMPAIGN_MESSAGE_CLICK,
|
||||||
ON_UNREAD_MESSAGE_CLICK,
|
ON_UNREAD_MESSAGE_CLICK,
|
||||||
} from './constants/widgetBusEvents';
|
} from './constants/widgetBusEvents';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import { SDK_SET_BUBBLE_VISIBILITY } from '../shared/constants/sharedFrameEvents';
|
import { SDK_SET_BUBBLE_VISIBILITY } from '../shared/constants/sharedFrameEvents';
|
||||||
import { emitter } from 'shared/helpers/mitt';
|
import { emitter } from 'shared/helpers/mitt';
|
||||||
|
|
||||||
@@ -27,7 +27,11 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
mixins: [availabilityMixin, configMixin, routerMixin, darkModeMixin],
|
mixins: [availabilityMixin, configMixin, routerMixin],
|
||||||
|
setup() {
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
return { prefersDarkMode };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { MESSAGE_TYPE } from 'widget/helpers/constants';
|
|||||||
import configMixin from '../mixins/configMixin';
|
import configMixin from '../mixins/configMixin';
|
||||||
import messageMixin from '../mixins/messageMixin';
|
import messageMixin from '../mixins/messageMixin';
|
||||||
import { isASubmittedFormMessage } from 'shared/helpers/MessageTypeHelper';
|
import { isASubmittedFormMessage } from 'shared/helpers/MessageTypeHelper';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import ReplyToChip from 'widget/components/ReplyToChip.vue';
|
import ReplyToChip from 'widget/components/ReplyToChip.vue';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { emitter } from 'shared/helpers/mitt';
|
import { emitter } from 'shared/helpers/mitt';
|
||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
MessageReplyButton,
|
MessageReplyButton,
|
||||||
ReplyToChip,
|
ReplyToChip,
|
||||||
},
|
},
|
||||||
mixins: [configMixin, messageMixin, darkModeMixin],
|
mixins: [configMixin, messageMixin],
|
||||||
props: {
|
props: {
|
||||||
message: {
|
message: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -39,6 +39,12 @@ export default {
|
|||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return {
|
||||||
|
getThemeClass,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasImageError: false,
|
hasImageError: false,
|
||||||
@@ -192,7 +198,9 @@ export default {
|
|||||||
<div
|
<div
|
||||||
v-if="hasAttachments"
|
v-if="hasAttachments"
|
||||||
class="space-y-2 chat-bubble has-attachment agent"
|
class="space-y-2 chat-bubble has-attachment agent"
|
||||||
:class="(wrapClass, $dm('bg-white', 'dark:bg-slate-700'))"
|
:class="
|
||||||
|
(wrapClass, getThemeClass('bg-white', 'dark:bg-slate-700'))
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="attachment in message.attachments"
|
v-for="attachment in message.attachments"
|
||||||
@@ -231,7 +239,7 @@ export default {
|
|||||||
v-if="message.showAvatar || hasRecordedResponse"
|
v-if="message.showAvatar || hasRecordedResponse"
|
||||||
v-dompurify-html="agentName"
|
v-dompurify-html="agentName"
|
||||||
class="agent-name"
|
class="agent-name"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-200')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-200')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ChatOptions from 'shared/components/ChatOptions.vue';
|
|||||||
import ChatArticle from './template/Article.vue';
|
import ChatArticle from './template/Article.vue';
|
||||||
import EmailInput from './template/EmailInput.vue';
|
import EmailInput from './template/EmailInput.vue';
|
||||||
import CustomerSatisfaction from 'shared/components/CustomerSatisfaction.vue';
|
import CustomerSatisfaction from 'shared/components/CustomerSatisfaction.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import IntegrationCard from './template/IntegrationCard.vue';
|
import IntegrationCard from './template/IntegrationCard.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -20,7 +20,6 @@ export default {
|
|||||||
CustomerSatisfaction,
|
CustomerSatisfaction,
|
||||||
IntegrationCard,
|
IntegrationCard,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
message: { type: String, default: null },
|
message: { type: String, default: null },
|
||||||
contentType: { type: String, default: null },
|
contentType: { type: String, default: null },
|
||||||
@@ -34,11 +33,13 @@ export default {
|
|||||||
setup() {
|
setup() {
|
||||||
const { formatMessage, getPlainText, truncateMessage, highlightContent } =
|
const { formatMessage, getPlainText, truncateMessage, highlightContent } =
|
||||||
useMessageFormatter();
|
useMessageFormatter();
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
return {
|
return {
|
||||||
formatMessage,
|
formatMessage,
|
||||||
getPlainText,
|
getPlainText,
|
||||||
truncateMessage,
|
truncateMessage,
|
||||||
highlightContent,
|
highlightContent,
|
||||||
|
getThemeClass,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -98,7 +99,7 @@ export default {
|
|||||||
!isCards && !isOptions && !isForm && !isArticle && !isCards && !isCSAT
|
!isCards && !isOptions && !isForm && !isArticle && !isCards && !isCSAT
|
||||||
"
|
"
|
||||||
class="chat-bubble agent"
|
class="chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700 has-dark-mode')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700 has-dark-mode')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-dompurify-html="formatMessage(message, false)"
|
v-dompurify-html="formatMessage(message, false)"
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import darkModeMixing from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
export default {
|
export default {
|
||||||
name: 'AgentTypingBubble',
|
name: 'AgentTypingBubble',
|
||||||
mixins: [darkModeMixing],
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -13,7 +16,7 @@ export default {
|
|||||||
<div class="message-wrap mt-2">
|
<div class="message-wrap mt-2">
|
||||||
<div
|
<div
|
||||||
class="typing-bubble chat-bubble agent"
|
class="typing-bubble chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700')"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="~widget/assets/images/typing.gif"
|
src="~widget/assets/images/typing.gif"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import nextAvailabilityTime from 'widget/mixins/nextAvailabilityTime';
|
|||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import HeaderActions from './HeaderActions.vue';
|
import HeaderActions from './HeaderActions.vue';
|
||||||
import routerMixin from 'widget/mixins/routerMixin';
|
import routerMixin from 'widget/mixins/routerMixin';
|
||||||
import darkMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatHeader',
|
name: 'ChatHeader',
|
||||||
@@ -12,7 +12,7 @@ export default {
|
|||||||
FluentIcon,
|
FluentIcon,
|
||||||
HeaderActions,
|
HeaderActions,
|
||||||
},
|
},
|
||||||
mixins: [nextAvailabilityTime, availabilityMixin, routerMixin, darkMixin],
|
mixins: [nextAvailabilityTime, availabilityMixin, routerMixin],
|
||||||
props: {
|
props: {
|
||||||
avatarUrl: {
|
avatarUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -35,6 +35,10 @@ export default {
|
|||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isOnline() {
|
isOnline() {
|
||||||
const { workingHoursEnabled } = this.channelConfig;
|
const { workingHoursEnabled } = this.channelConfig;
|
||||||
@@ -57,7 +61,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<header
|
<header
|
||||||
class="flex justify-between w-full p-5"
|
class="flex justify-between w-full p-5"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-900')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-900')"
|
||||||
>
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<button
|
<button
|
||||||
@@ -68,7 +72,7 @@ export default {
|
|||||||
<FluentIcon
|
<FluentIcon
|
||||||
icon="chevron-left"
|
icon="chevron-left"
|
||||||
size="24"
|
size="24"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<img
|
<img
|
||||||
@@ -80,7 +84,7 @@ export default {
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="flex items-center text-base font-medium leading-4"
|
class="flex items-center text-base font-medium leading-4"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
>
|
>
|
||||||
<span v-dompurify-html="title" class="mr-1" />
|
<span v-dompurify-html="title" class="mr-1" />
|
||||||
<div
|
<div
|
||||||
@@ -90,7 +94,7 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mt-1 text-xs leading-3"
|
class="mt-1 text-xs leading-3"
|
||||||
:class="$dm('text-black-700', 'dark:text-slate-400')"
|
:class="getThemeClass('text-black-700', 'dark:text-slate-400')"
|
||||||
>
|
>
|
||||||
{{ replyWaitMessage }}
|
{{ replyWaitMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import HeaderActions from './HeaderActions.vue';
|
import HeaderActions from './HeaderActions.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatHeaderExpanded',
|
name: 'ChatHeaderExpanded',
|
||||||
components: {
|
components: {
|
||||||
HeaderActions,
|
HeaderActions,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
avatarUrl: {
|
avatarUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -26,6 +25,10 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -51,12 +54,12 @@ export default {
|
|||||||
<h2
|
<h2
|
||||||
v-dompurify-html="introHeading"
|
v-dompurify-html="introHeading"
|
||||||
class="mt-4 text-2xl mb-1.5 font-medium"
|
class="mt-4 text-2xl mb-1.5 font-medium"
|
||||||
:class="$dm('text-slate-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-slate-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
v-dompurify-html="introBody"
|
v-dompurify-html="introBody"
|
||||||
class="text-base leading-normal"
|
class="text-base leading-normal"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-200')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-200')"
|
||||||
/>
|
/>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ChatSendButton from 'widget/components/ChatSendButton.vue';
|
|||||||
import configMixin from '../mixins/configMixin';
|
import configMixin from '../mixins/configMixin';
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
|
import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
const EmojiInput = () => import('shared/components/emoji/EmojiInput.vue');
|
const EmojiInput = () => import('shared/components/emoji/EmojiInput.vue');
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export default {
|
|||||||
FluentIcon,
|
FluentIcon,
|
||||||
ResizableTextArea,
|
ResizableTextArea,
|
||||||
},
|
},
|
||||||
mixins: [configMixin, darkModeMixin],
|
mixins: [configMixin],
|
||||||
props: {
|
props: {
|
||||||
onSendMessage: {
|
onSendMessage: {
|
||||||
type: Function,
|
type: Function,
|
||||||
@@ -30,7 +30,10 @@ export default {
|
|||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userInput: '',
|
userInput: '',
|
||||||
@@ -51,13 +54,16 @@ export default {
|
|||||||
return this.userInput.length > 0;
|
return this.userInput.length > 0;
|
||||||
},
|
},
|
||||||
inputColor() {
|
inputColor() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')}
|
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
|
||||||
${this.$dm('text-black-900', 'dark:text-slate-50')}`;
|
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
emojiIconColor() {
|
emojiIconColor() {
|
||||||
return this.showEmojiPicker
|
return this.showEmojiPicker
|
||||||
? `text-woot-500 ${this.$dm('text-black-900', 'dark:text-slate-100')}`
|
? `text-woot-500 ${this.getThemeClass(
|
||||||
: `${this.$dm('text-black-900', 'dark:text-slate-100')}`;
|
'text-black-900',
|
||||||
|
'dark:text-slate-100'
|
||||||
|
)}`
|
||||||
|
: `${this.getThemeClass('text-black-900', 'dark:text-slate-100')}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -128,7 +134,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="chat-message--input is-focused"
|
class="chat-message--input is-focused"
|
||||||
:class="$dm('bg-white ', 'dark:bg-slate-600')"
|
:class="getThemeClass('bg-white ', 'dark:bg-slate-600')"
|
||||||
@keydown.esc="hideEmojiPicker"
|
@keydown.esc="hideEmojiPicker"
|
||||||
>
|
>
|
||||||
<ResizableTextArea
|
<ResizableTextArea
|
||||||
@@ -148,7 +154,7 @@ export default {
|
|||||||
<div class="button-wrap">
|
<div class="button-wrap">
|
||||||
<ChatAttachmentButton
|
<ChatAttachmentButton
|
||||||
v-if="showAttachment"
|
v-if="showAttachment"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-100')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-100')"
|
||||||
:on-attach="onSendAttachment"
|
:on-attach="onSendAttachment"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import ChatMessage from 'widget/components/ChatMessage.vue';
|
|||||||
import AgentTypingBubble from 'widget/components/AgentTypingBubble.vue';
|
import AgentTypingBubble from 'widget/components/AgentTypingBubble.vue';
|
||||||
import DateSeparator from 'shared/components/DateSeparator.vue';
|
import DateSeparator from 'shared/components/DateSeparator.vue';
|
||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
||||||
import { mapActions, mapGetters } from 'vuex';
|
import { mapActions, mapGetters } from 'vuex';
|
||||||
|
|
||||||
@@ -15,13 +15,16 @@ export default {
|
|||||||
DateSeparator,
|
DateSeparator,
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
groupedMessages: {
|
groupedMessages: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { darkMode } = useDarkMode();
|
||||||
|
return { darkMode };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
previousScrollHeight: 0,
|
previousScrollHeight: 0,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import { getContrastingTextColor } from '@chatwoot/utils';
|
import { getContrastingTextColor } from '@chatwoot/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FluentIcon,
|
FluentIcon,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
url: {
|
url: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -26,6 +25,10 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
title() {
|
title() {
|
||||||
return this.isInProgress
|
return this.isInProgress
|
||||||
@@ -45,7 +48,7 @@ export default {
|
|||||||
},
|
},
|
||||||
titleColor() {
|
titleColor() {
|
||||||
return !this.isUserBubble
|
return !this.isUserBubble
|
||||||
? this.$dm('text-black-900', 'dark:text-slate-50')
|
? this.getThemeClass('text-black-900', 'dark:text-slate-50')
|
||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
export default {
|
export default {
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -28,20 +27,33 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
labelClass() {
|
labelClass() {
|
||||||
return this.error
|
return this.error
|
||||||
? `text-red-400 ${this.$dm('text-black-800', 'dark:text-slate-50')}`
|
? `text-red-400 ${this.getThemeClass(
|
||||||
: `text-black-800 ${this.$dm('text-black-800', 'dark:text-slate-50')}`;
|
'text-black-800',
|
||||||
|
'dark:text-slate-50'
|
||||||
|
)}`
|
||||||
|
: `text-black-800 ${this.getThemeClass(
|
||||||
|
'text-black-800',
|
||||||
|
'dark:text-slate-50'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
isInputDarkOrLightMode() {
|
isInputDarkOrLightMode() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-white',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-600'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
inputBorderColor() {
|
inputBorderColor() {
|
||||||
return `${this.$dm('border-black-200', 'dark:border-black-500')}`;
|
return `${this.getThemeClass(
|
||||||
|
'border-black-200',
|
||||||
|
'dark:border-black-500'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
inputHasError() {
|
inputHasError() {
|
||||||
return this.error
|
return this.error
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
import countries from 'shared/constants/countries.js';
|
import countries from 'shared/constants/countries.js';
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import FormulateInputMixin from '@braid/vue-formulate/src/FormulateInputMixin';
|
import FormulateInputMixin from '@braid/vue-formulate/src/FormulateInputMixin';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FluentIcon,
|
FluentIcon,
|
||||||
},
|
},
|
||||||
mixins: [FormulateInputMixin, darkModeMixin],
|
mixins: [FormulateInputMixin],
|
||||||
props: {
|
props: {
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -19,6 +19,10 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedIndex: -1,
|
selectedIndex: -1,
|
||||||
@@ -45,28 +49,31 @@ export default {
|
|||||||
return this.activeCountryCode ? 'Clear selection' : 'Select Country';
|
return this.activeCountryCode ? 'Clear selection' : 'Select Country';
|
||||||
},
|
},
|
||||||
dropdownClass() {
|
dropdownClass() {
|
||||||
return `${this.$dm('bg-slate-100', 'dark:bg-slate-700')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-slate-100',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-700'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
dropdownBackgroundClass() {
|
dropdownBackgroundClass() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-700')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-white',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-700'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
dropdownItemClass() {
|
dropdownItemClass() {
|
||||||
return `${this.$dm('text-slate-700', 'dark:text-slate-50')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'hover:bg-slate-50',
|
'text-slate-700',
|
||||||
'dark:hover:bg-slate-600'
|
'dark:text-slate-50'
|
||||||
)}`;
|
)} ${this.getThemeClass('hover:bg-slate-50', 'dark:hover:bg-slate-600')}`;
|
||||||
},
|
},
|
||||||
activeDropdownItemClass() {
|
activeDropdownItemClass() {
|
||||||
return `active ${this.$dm('bg-slate-100', 'dark:bg-slate-800')}`;
|
return `active ${this.getThemeClass(
|
||||||
|
'bg-slate-100',
|
||||||
|
'dark:bg-slate-800'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
focusedDropdownItemClass() {
|
focusedDropdownItemClass() {
|
||||||
return `focus ${this.$dm('bg-slate-50', 'dark:bg-slate-600')}`;
|
return `focus ${this.getThemeClass('bg-slate-50', 'dark:bg-slate-600')}`;
|
||||||
},
|
},
|
||||||
inputHasError() {
|
inputHasError() {
|
||||||
return this.hasErrorInPhoneInput
|
return this.hasErrorInPhoneInput
|
||||||
@@ -74,13 +81,16 @@ export default {
|
|||||||
: `hover:border-black-300 focus:border-black-300 ${this.inputLightAndDarkModeColor} ${this.inputBorderColor}`;
|
: `hover:border-black-300 focus:border-black-300 ${this.inputLightAndDarkModeColor} ${this.inputBorderColor}`;
|
||||||
},
|
},
|
||||||
inputBorderColor() {
|
inputBorderColor() {
|
||||||
return `${this.$dm('border-black-200', 'dark:border-black-500')}`;
|
return `${this.getThemeClass(
|
||||||
|
'border-black-200',
|
||||||
|
'dark:border-black-500'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
inputLightAndDarkModeColor() {
|
inputLightAndDarkModeColor() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-white',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-600'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
items() {
|
items() {
|
||||||
return this.countries.filter(country => {
|
return this.countries.filter(country => {
|
||||||
@@ -241,7 +251,7 @@ export default {
|
|||||||
<span
|
<span
|
||||||
v-if="activeDialCode"
|
v-if="activeDialCode"
|
||||||
class="py-2 pl-2 pr-0 text-base"
|
class="py-2 pl-2 pr-0 text-base"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-50')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-50')"
|
||||||
>
|
>
|
||||||
{{ activeDialCode }}
|
{{ activeDialCode }}
|
||||||
</span>
|
</span>
|
||||||
@@ -273,7 +283,10 @@ export default {
|
|||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.DROPDOWN_SEARCH')"
|
:placeholder="$t('PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.DROPDOWN_SEARCH')"
|
||||||
class="w-full h-8 px-3 py-2 mt-1 mb-1 text-sm border border-solid rounded outline-none dropdown-search"
|
class="w-full h-8 px-3 py-2 mt-1 mb-1 text-sm border border-solid rounded outline-none dropdown-search"
|
||||||
:class="[$dm('bg-slate-50', 'dark:bg-slate-600'), inputBorderColor]"
|
:class="[
|
||||||
|
getThemeClass('bg-slate-50', 'dark:bg-slate-600'),
|
||||||
|
inputBorderColor,
|
||||||
|
]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -298,7 +311,7 @@ export default {
|
|||||||
<div v-if="items.length === 0">
|
<div v-if="items.length === 0">
|
||||||
<span
|
<span
|
||||||
class="flex justify-center mt-4 text-sm text-center"
|
class="flex justify-center mt-4 text-sm text-center"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-50')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-50')"
|
||||||
>
|
>
|
||||||
{{ $t('PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.DROPDOWN_EMPTY') }}
|
{{ $t('PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.DROPDOWN_EMPTY') }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
export default {
|
export default {
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -20,20 +19,33 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
labelClass() {
|
labelClass() {
|
||||||
return this.error
|
return this.error
|
||||||
? `text-red-400 ${this.$dm('text-black-800', 'dark:text-slate-50')}`
|
? `text-red-400 ${this.getThemeClass(
|
||||||
: `text-black-800 ${this.$dm('text-black-800', 'dark:text-slate-50')}`;
|
'text-black-800',
|
||||||
|
'dark:text-slate-50'
|
||||||
|
)}`
|
||||||
|
: `text-black-800 ${this.getThemeClass(
|
||||||
|
'text-black-800',
|
||||||
|
'dark:text-slate-50'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
isTextAreaDarkOrLightMode() {
|
isTextAreaDarkOrLightMode() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-white',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-600'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
textAreaBorderColor() {
|
textAreaBorderColor() {
|
||||||
return `${this.$dm('border-black-200', 'dark:border-black-500')}`;
|
return `${this.getThemeClass(
|
||||||
|
'border-black-200',
|
||||||
|
'dark:border-black-500'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
isTextAreaHasError() {
|
isTextAreaHasError() {
|
||||||
return this.error
|
return this.error
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import { mapGetters } from 'vuex';
|
|||||||
import { IFrameHelper, RNHelper } from 'widget/helpers/utils';
|
import { IFrameHelper, RNHelper } from 'widget/helpers/utils';
|
||||||
import { popoutChatWindow } from '../helpers/popoutHelper';
|
import { popoutChatWindow } from '../helpers/popoutHelper';
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import configMixin from 'widget/mixins/configMixin';
|
import configMixin from 'widget/mixins/configMixin';
|
||||||
import { CONVERSATION_STATUS } from 'shared/constants/messages';
|
import { CONVERSATION_STATUS } from 'shared/constants/messages';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HeaderActions',
|
name: 'HeaderActions',
|
||||||
components: { FluentIcon },
|
components: { FluentIcon },
|
||||||
mixins: [configMixin, darkModeMixin],
|
mixins: [configMixin],
|
||||||
props: {
|
props: {
|
||||||
showPopoutButton: {
|
showPopoutButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -21,6 +21,10 @@ export default {
|
|||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { getThemeClass };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
conversationAttributes: 'conversationAttributes/getConversationParams',
|
conversationAttributes: 'conversationAttributes/getConversationParams',
|
||||||
@@ -92,7 +96,7 @@ export default {
|
|||||||
<FluentIcon
|
<FluentIcon
|
||||||
icon="sign-out"
|
icon="sign-out"
|
||||||
size="22"
|
size="22"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -103,7 +107,7 @@ export default {
|
|||||||
<FluentIcon
|
<FluentIcon
|
||||||
icon="open"
|
icon="open"
|
||||||
size="22"
|
size="22"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -116,7 +120,7 @@ export default {
|
|||||||
<FluentIcon
|
<FluentIcon
|
||||||
icon="dismiss"
|
icon="dismiss"
|
||||||
size="24"
|
size="24"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { isEmptyObject } from 'widget/helpers/utils';
|
|||||||
import { getRegexp } from 'shared/helpers/Validators';
|
import { getRegexp } from 'shared/helpers/Validators';
|
||||||
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
||||||
import routerMixin from 'widget/mixins/routerMixin';
|
import routerMixin from 'widget/mixins/routerMixin';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import configMixin from 'widget/mixins/configMixin';
|
import configMixin from 'widget/mixins/configMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -15,7 +15,7 @@ export default {
|
|||||||
CustomButton,
|
CustomButton,
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
mixins: [routerMixin, darkModeMixin, configMixin],
|
mixins: [routerMixin, configMixin],
|
||||||
props: {
|
props: {
|
||||||
options: {
|
options: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -24,9 +24,8 @@ export default {
|
|||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { formatMessage } = useMessageFormatter();
|
const { formatMessage } = useMessageFormatter();
|
||||||
return {
|
const { getThemeClass } = useDarkMode();
|
||||||
formatMessage,
|
return { formatMessage, getThemeClass };
|
||||||
};
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -131,25 +130,28 @@ export default {
|
|||||||
return `mt-1 border rounded w-full py-2 px-3 text-slate-700 outline-none`;
|
return `mt-1 border rounded w-full py-2 px-3 text-slate-700 outline-none`;
|
||||||
},
|
},
|
||||||
isInputDarkOrLightMode() {
|
isInputDarkOrLightMode() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')} ${this.$dm(
|
return `${this.getThemeClass(
|
||||||
'text-slate-700',
|
'bg-white',
|
||||||
'dark:text-slate-50'
|
'dark:bg-slate-600'
|
||||||
)}`;
|
)} ${this.getThemeClass('text-slate-700', 'dark:text-slate-50')}`;
|
||||||
},
|
},
|
||||||
inputBorderColor() {
|
inputBorderColor() {
|
||||||
return `${this.$dm('border-black-200', 'dark:border-black-500')}`;
|
return `${this.getThemeClass(
|
||||||
|
'border-black-200',
|
||||||
|
'dark:border-black-500'
|
||||||
|
)}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
labelClass(context) {
|
labelClass(context) {
|
||||||
const { hasErrors } = context;
|
const { hasErrors } = context;
|
||||||
if (!hasErrors) {
|
if (!hasErrors) {
|
||||||
return `text-xs font-medium ${this.$dm(
|
return `text-xs font-medium ${this.getThemeClass(
|
||||||
'text-black-800',
|
'text-black-800',
|
||||||
'dark:text-slate-50'
|
'dark:text-slate-50'
|
||||||
)}`;
|
)}`;
|
||||||
}
|
}
|
||||||
return `text-xs font-medium ${this.$dm(
|
return `text-xs font-medium ${this.getThemeClass(
|
||||||
'text-red-400',
|
'text-red-400',
|
||||||
'dark:text-red-400'
|
'dark:text-red-400'
|
||||||
)}`;
|
)}`;
|
||||||
@@ -264,7 +266,7 @@ export default {
|
|||||||
v-if="shouldShowHeaderMessage"
|
v-if="shouldShowHeaderMessage"
|
||||||
v-dompurify-html="formatMessage(headerMessage, false)"
|
v-dompurify-html="formatMessage(headerMessage, false)"
|
||||||
class="mb-4 text-sm leading-5 pre-chat-header-message"
|
class="mb-4 text-sm leading-5 pre-chat-header-message"
|
||||||
:class="$dm('text-black-800', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-800', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
<FormulateInput
|
<FormulateInput
|
||||||
v-for="item in enabledPreChatFields"
|
v-for="item in enabledPreChatFields"
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
ON_CAMPAIGN_MESSAGE_CLICK,
|
ON_CAMPAIGN_MESSAGE_CLICK,
|
||||||
ON_UNREAD_MESSAGE_CLICK,
|
ON_UNREAD_MESSAGE_CLICK,
|
||||||
} from '../constants/widgetBusEvents';
|
} from '../constants/widgetBusEvents';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
export default {
|
export default {
|
||||||
name: 'UnreadMessage',
|
name: 'UnreadMessage',
|
||||||
components: { Thumbnail },
|
components: { Thumbnail },
|
||||||
mixins: [configMixin, darkModeMixin],
|
mixins: [configMixin],
|
||||||
props: {
|
props: {
|
||||||
message: {
|
message: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -31,9 +31,15 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { formatMessage } = useMessageFormatter();
|
const { formatMessage, getPlainText, truncateMessage, highlightContent } =
|
||||||
|
useMessageFormatter();
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
return {
|
return {
|
||||||
formatMessage,
|
formatMessage,
|
||||||
|
getPlainText,
|
||||||
|
truncateMessage,
|
||||||
|
highlightContent,
|
||||||
|
getThemeClass,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -91,7 +97,7 @@ export default {
|
|||||||
<div class="chat-bubble-wrap">
|
<div class="chat-bubble-wrap">
|
||||||
<button
|
<button
|
||||||
class="chat-bubble agent"
|
class="chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-50')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-50')"
|
||||||
@click="onClickMessage"
|
@click="onClickMessage"
|
||||||
>
|
>
|
||||||
<div v-if="showSender" class="row--agent-block">
|
<div v-if="showSender" class="row--agent-block">
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FluentIcon,
|
FluentIcon,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
items: {
|
items: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -16,9 +15,8 @@ export default {
|
|||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { truncateMessage } = useMessageFormatter();
|
const { truncateMessage } = useMessageFormatter();
|
||||||
return {
|
const { getThemeClass } = useDarkMode();
|
||||||
truncateMessage,
|
return { getThemeClass, truncateMessage };
|
||||||
};
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -27,7 +25,7 @@ export default {
|
|||||||
<div
|
<div
|
||||||
v-if="!!items.length"
|
v-if="!!items.length"
|
||||||
class="chat-bubble agent"
|
class="chat-bubble agent"
|
||||||
:class="$dm('bg-white', 'dark:bg-slate-700')"
|
:class="getThemeClass('bg-white', 'dark:bg-slate-700')"
|
||||||
>
|
>
|
||||||
<div v-for="item in items" :key="item.link" class="article-item">
|
<div v-for="item in items" :key="item.link" class="article-item">
|
||||||
<a :href="item.link" target="_blank" rel="noopener noreferrer nofollow">
|
<a :href="item.link" target="_blank" rel="noopener noreferrer nofollow">
|
||||||
@@ -35,15 +33,16 @@ export default {
|
|||||||
<FluentIcon
|
<FluentIcon
|
||||||
icon="link"
|
icon="link"
|
||||||
class="mr-1"
|
class="mr-1"
|
||||||
:class="$dm('text-black-900', 'dark:text-slate-50')"
|
:class="getThemeClass('text-black-900', 'dark:text-slate-50')"
|
||||||
/>
|
/>
|
||||||
<span :class="$dm('text-slate-900', 'dark:text-slate-50')">{{
|
<span
|
||||||
item.title
|
:class="getThemeClass('text-slate-900', 'dark:text-slate-50')"
|
||||||
}}</span>
|
>{{ item.title }}</span
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="description"
|
class="description"
|
||||||
:class="$dm('text-slate-700', 'dark:text-slate-200')"
|
:class="getThemeClass('text-slate-700', 'dark:text-slate-200')"
|
||||||
>
|
>
|
||||||
{{ truncateMessage(item.description) }}
|
{{ truncateMessage(item.description) }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import { getContrastingTextColor } from '@chatwoot/utils';
|
|||||||
|
|
||||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FluentIcon,
|
FluentIcon,
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
mixins: [darkModeMixin],
|
|
||||||
props: {
|
props: {
|
||||||
messageId: {
|
messageId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -25,7 +24,8 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
return { v$: useVuelidate() };
|
const { getThemeClass } = useDarkMode();
|
||||||
|
return { v$: useVuelidate(), getThemeClass };
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -47,9 +47,9 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
inputColor() {
|
inputColor() {
|
||||||
return `${this.$dm('bg-white', 'dark:bg-slate-600')}
|
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
|
||||||
${this.$dm('text-black-900', 'dark:text-slate-50')}
|
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}
|
||||||
${this.$dm('border-black-200', 'dark:border-black-500')}`;
|
${this.getThemeClass('border-black-200', 'dark:border-black-500')}`;
|
||||||
},
|
},
|
||||||
inputHasError() {
|
inputHasError() {
|
||||||
return this.v$.email.$error
|
return this.v$.email.$error
|
||||||
|
|||||||
71
app/javascript/widget/composables/specs/useDarkMode.spec.js
Normal file
71
app/javascript/widget/composables/specs/useDarkMode.spec.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { useDarkMode } from '../useDarkMode';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
|
||||||
|
vi.mock('dashboard/composables/store', () => ({
|
||||||
|
useMapGetter: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('useDarkMode', () => {
|
||||||
|
let mockDarkMode;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDarkMode = { value: 'light' };
|
||||||
|
vi.mocked(useMapGetter).mockReturnValue(mockDarkMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns darkMode, prefersDarkMode, and getThemeClass', () => {
|
||||||
|
const result = useDarkMode();
|
||||||
|
expect(result).toHaveProperty('darkMode');
|
||||||
|
expect(result).toHaveProperty('prefersDarkMode');
|
||||||
|
expect(result).toHaveProperty('getThemeClass');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('prefersDarkMode', () => {
|
||||||
|
it('returns false when darkMode is light', () => {
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
expect(prefersDarkMode.value).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when darkMode is dark', () => {
|
||||||
|
mockDarkMode.value = 'dark';
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
expect(prefersDarkMode.value).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when darkMode is auto and OS prefers dark mode', () => {
|
||||||
|
mockDarkMode.value = 'auto';
|
||||||
|
vi.spyOn(window, 'matchMedia').mockReturnValue({ matches: true });
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
expect(prefersDarkMode.value).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when darkMode is auto and OS prefers light mode', () => {
|
||||||
|
mockDarkMode.value = 'auto';
|
||||||
|
vi.spyOn(window, 'matchMedia').mockReturnValue({ matches: false });
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
expect(prefersDarkMode.value).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getThemeClass', () => {
|
||||||
|
it('returns light class when darkMode is light', () => {
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
expect(getThemeClass('light-class', 'dark-class')).toBe('light-class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns dark class when darkMode is dark', () => {
|
||||||
|
mockDarkMode.value = 'dark';
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
expect(getThemeClass('light-class', 'dark-class')).toBe('dark-class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns both classes when darkMode is auto', () => {
|
||||||
|
mockDarkMode.value = 'auto';
|
||||||
|
const { getThemeClass } = useDarkMode();
|
||||||
|
expect(getThemeClass('light-class', 'dark-class')).toBe(
|
||||||
|
'light-class dark-class'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
39
app/javascript/widget/composables/useDarkMode.js
Normal file
39
app/javascript/widget/composables/useDarkMode.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { computed } from 'vue';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
|
||||||
|
const isDarkModeAuto = mode => mode === 'auto';
|
||||||
|
const isDarkMode = mode => mode === 'dark';
|
||||||
|
|
||||||
|
const getSystemPreference = () =>
|
||||||
|
window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
|
||||||
|
|
||||||
|
const calculatePrefersDarkMode = (mode, systemPreference) =>
|
||||||
|
isDarkModeAuto(mode) ? systemPreference : isDarkMode(mode);
|
||||||
|
|
||||||
|
const calculateThemeClass = (mode, light, dark) => {
|
||||||
|
if (isDarkModeAuto(mode)) return `${light} ${dark}`;
|
||||||
|
return isDarkMode(mode) ? dark : light;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable for handling dark mode.
|
||||||
|
* @returns {Object} An object containing computed properties and methods for dark mode.
|
||||||
|
*/
|
||||||
|
export function useDarkMode() {
|
||||||
|
const darkMode = useMapGetter('appConfig/darkMode');
|
||||||
|
|
||||||
|
const systemPreference = computed(getSystemPreference);
|
||||||
|
|
||||||
|
const prefersDarkMode = computed(() =>
|
||||||
|
calculatePrefersDarkMode(darkMode.value, systemPreference.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
const getThemeClass = (light, dark) =>
|
||||||
|
calculateThemeClass(darkMode.value, light, dark);
|
||||||
|
|
||||||
|
return {
|
||||||
|
darkMode,
|
||||||
|
prefersDarkMode,
|
||||||
|
getThemeClass,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { mapGetters } from 'vuex';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
...mapGetters({ darkMode: 'appConfig/darkMode' }),
|
|
||||||
prefersDarkMode() {
|
|
||||||
const isOSOnDarkMode =
|
|
||||||
this.darkMode === 'auto' &&
|
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
||||||
return isOSOnDarkMode || this.darkMode === 'dark';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
$dm(light, dark) {
|
|
||||||
if (this.darkMode === 'light') {
|
|
||||||
return light;
|
|
||||||
}
|
|
||||||
if (this.darkMode === 'dark') {
|
|
||||||
return dark;
|
|
||||||
}
|
|
||||||
return light + ' ' + dark;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
|
||||||
import darkModeMixin from '../darkModeMixin';
|
|
||||||
import Vuex from 'vuex';
|
|
||||||
const localVue = createLocalVue();
|
|
||||||
localVue.use(Vuex);
|
|
||||||
|
|
||||||
const darkModeValues = ['light', 'auto'];
|
|
||||||
|
|
||||||
describe('darkModeMixin', () => {
|
|
||||||
let getters;
|
|
||||||
let store;
|
|
||||||
beforeEach(() => {
|
|
||||||
getters = {
|
|
||||||
'appConfig/darkMode': () => darkModeValues[0],
|
|
||||||
};
|
|
||||||
store = new Vuex.Store({ getters });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('if light theme', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
mixins: [darkModeMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.$dm('bg-100', 'bg-600')).toBe('bg-100');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('if auto theme', () => {
|
|
||||||
getters = {
|
|
||||||
'appConfig/darkMode': () => darkModeValues[2],
|
|
||||||
};
|
|
||||||
store = new Vuex.Store({ getters });
|
|
||||||
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
mixins: [darkModeMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.$dm('bg-100', 'bg-600')).toBe('bg-100 bg-600');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -4,7 +4,7 @@ import ArticleHero from 'widget/components/ArticleHero.vue';
|
|||||||
import ArticleCardSkeletonLoader from 'widget/components/ArticleCardSkeletonLoader.vue';
|
import ArticleCardSkeletonLoader from 'widget/components/ArticleCardSkeletonLoader.vue';
|
||||||
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import darkModeMixin from 'widget/mixins/darkModeMixin';
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||||
import routerMixin from 'widget/mixins/routerMixin';
|
import routerMixin from 'widget/mixins/routerMixin';
|
||||||
import configMixin from 'widget/mixins/configMixin';
|
import configMixin from 'widget/mixins/configMixin';
|
||||||
|
|
||||||
@@ -15,7 +15,11 @@ export default {
|
|||||||
TeamAvailability,
|
TeamAvailability,
|
||||||
ArticleCardSkeletonLoader,
|
ArticleCardSkeletonLoader,
|
||||||
},
|
},
|
||||||
mixins: [configMixin, routerMixin, darkModeMixin],
|
mixins: [configMixin, routerMixin],
|
||||||
|
setup() {
|
||||||
|
const { prefersDarkMode } = useDarkMode();
|
||||||
|
return { prefersDarkMode };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
availableAgents: 'agent/availableAgents',
|
availableAgents: 'agent/availableAgents',
|
||||||
|
|||||||
Reference in New Issue
Block a user