feat: Adds the ability to set an emoji for help center category (#8111)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"EMOJI": {
|
||||
"PLACEHOLDER": "Search emojis",
|
||||
"NOT_FOUND": "No emoji match your search"
|
||||
"NOT_FOUND": "No emoji match your search",
|
||||
"REMOVE": "Remove"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
"NAME": {
|
||||
"LABEL": "Name",
|
||||
"PLACEHOLDER": "Category name",
|
||||
"HELP_TEXT": "The category name will be used in the public facing portal to categorize articles.",
|
||||
"HELP_TEXT": "The category name and icon will be used in the public facing portal to categorize articles.",
|
||||
"ERROR": "Name is required"
|
||||
},
|
||||
"SLUG": {
|
||||
@@ -396,7 +396,7 @@
|
||||
"NAME": {
|
||||
"LABEL": "Name",
|
||||
"PLACEHOLDER": "Category name",
|
||||
"HELP_TEXT": "The category name will be used in the public facing portal to categorize articles.",
|
||||
"HELP_TEXT": "The category name and icon will be used in the public facing portal to categorize articles.",
|
||||
"ERROR": "Name is required"
|
||||
},
|
||||
"SLUG": {
|
||||
|
||||
@@ -224,7 +224,9 @@ export default {
|
||||
key: 'category',
|
||||
children: this.categories.map(category => ({
|
||||
id: category.id,
|
||||
label: category.name,
|
||||
label: category.icon
|
||||
? `${category.icon} ${category.name}`
|
||||
: category.name,
|
||||
count: category.meta.articles_count,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
|
||||
@@ -21,15 +21,14 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<woot-input
|
||||
v-model.trim="name"
|
||||
:class="{ error: $v.name.$error }"
|
||||
class="w-full"
|
||||
:error="nameError"
|
||||
<category-name-icon-input
|
||||
:label="$t('HELP_CENTER.CATEGORY.ADD.NAME.LABEL')"
|
||||
:placeholder="$t('HELP_CENTER.CATEGORY.ADD.NAME.PLACEHOLDER')"
|
||||
:help-text="$t('HELP_CENTER.CATEGORY.ADD.NAME.HELP_TEXT')"
|
||||
@input="onNameChange"
|
||||
:has-error="$v.name.$error"
|
||||
:error-message="$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR')"
|
||||
@name-change="onNameChange"
|
||||
@icon-change="onClickInsertEmoji"
|
||||
/>
|
||||
<woot-input
|
||||
v-model.trim="slug"
|
||||
@@ -72,8 +71,10 @@ import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { required, minLength } from 'vuelidate/lib/validators';
|
||||
import { convertToCategorySlug } from 'dashboard/helper/commons.js';
|
||||
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
||||
import CategoryNameIconInput from './NameEmojiInput.vue';
|
||||
|
||||
export default {
|
||||
components: { CategoryNameIconInput },
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
show: {
|
||||
@@ -96,6 +97,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
icon: '',
|
||||
slug: '',
|
||||
description: '',
|
||||
};
|
||||
@@ -115,12 +117,6 @@ export default {
|
||||
? this.$route.params.portalSlug
|
||||
: this.portalSlug;
|
||||
},
|
||||
nameError() {
|
||||
if (this.$v.name.$error) {
|
||||
return this.$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
slugError() {
|
||||
if (this.$v.slug.$error) {
|
||||
return this.$t('HELP_CENTER.CATEGORY.ADD.SLUG.ERROR');
|
||||
@@ -129,7 +125,8 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onNameChange() {
|
||||
onNameChange(name) {
|
||||
this.name = name;
|
||||
this.slug = convertToCategorySlug(this.name);
|
||||
},
|
||||
onCreate() {
|
||||
@@ -138,11 +135,15 @@ export default {
|
||||
onClose() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onClickInsertEmoji(emoji) {
|
||||
this.icon = emoji;
|
||||
},
|
||||
|
||||
async addCategory() {
|
||||
const { name, slug, description, locale } = this;
|
||||
const { name, slug, description, locale, icon } = this;
|
||||
const data = {
|
||||
name,
|
||||
icon,
|
||||
slug,
|
||||
description,
|
||||
locale,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<tbody>
|
||||
<tr v-for="category in categories" :key="category.id">
|
||||
<td>
|
||||
<span>{{ category.name }}</span>
|
||||
<span>{{ category.icon }} {{ category.name }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{ category.description }}</span>
|
||||
|
||||
@@ -21,15 +21,16 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<woot-input
|
||||
v-model.trim="name"
|
||||
:class="{ error: $v.name.$error }"
|
||||
class="w-full"
|
||||
:error="nameError"
|
||||
<category-name-icon-input
|
||||
:label="$t('HELP_CENTER.CATEGORY.EDIT.NAME.LABEL')"
|
||||
:placeholder="$t('HELP_CENTER.CATEGORY.EDIT.NAME.PLACEHOLDER')"
|
||||
:help-text="$t('HELP_CENTER.CATEGORY.EDIT.NAME.HELP_TEXT')"
|
||||
@input="onNameChange"
|
||||
:has-error="$v.name.$error"
|
||||
:error-message="$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR')"
|
||||
:existing-name="category.name"
|
||||
:saved-icon="category.icon"
|
||||
@name-change="changeName"
|
||||
@icon-change="onClickInsertEmoji"
|
||||
/>
|
||||
<woot-input
|
||||
v-model.trim="slug"
|
||||
@@ -72,8 +73,10 @@ import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { required, minLength } from 'vuelidate/lib/validators';
|
||||
import { convertToCategorySlug } from 'dashboard/helper/commons.js';
|
||||
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
||||
import CategoryNameIconInput from './NameEmojiInput.vue';
|
||||
|
||||
export default {
|
||||
components: { CategoryNameIconInput },
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
show: {
|
||||
@@ -101,6 +104,7 @@ export default {
|
||||
return {
|
||||
id: this.category.id,
|
||||
name: '',
|
||||
icon: '',
|
||||
slug: '',
|
||||
description: '',
|
||||
};
|
||||
@@ -115,12 +119,6 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
nameError() {
|
||||
if (this.$v.name.$error) {
|
||||
return this.$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
slugError() {
|
||||
if (this.$v.slug.$error) {
|
||||
return this.$t('HELP_CENTER.CATEGORY.ADD.SLUG.ERROR');
|
||||
@@ -135,12 +133,17 @@ export default {
|
||||
updateDataFromStore() {
|
||||
const { category } = this;
|
||||
this.name = category.name;
|
||||
this.icon = category.icon;
|
||||
this.slug = category.slug;
|
||||
this.description = category.description;
|
||||
},
|
||||
onNameChange() {
|
||||
changeName(name) {
|
||||
this.name = name;
|
||||
this.slug = convertToCategorySlug(this.name);
|
||||
},
|
||||
onClickInsertEmoji(emoji) {
|
||||
this.icon = emoji;
|
||||
},
|
||||
onUpdate() {
|
||||
this.$emit('update');
|
||||
},
|
||||
@@ -148,10 +151,11 @@ export default {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
async editCategory() {
|
||||
const { id, name, slug, description } = this;
|
||||
const { id, name, slug, icon, description } = this;
|
||||
const data = {
|
||||
id,
|
||||
name,
|
||||
icon,
|
||||
slug,
|
||||
description,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="flex items-center relative">
|
||||
<woot-button
|
||||
variant="hollow"
|
||||
class="absolute [&>span]:flex [&>span]:items-center [&>span]:justify-center z-10 top-[25px] h-[2.45rem] w-[2.45rem] !text-slate-400 dark:!text-slate-600 dark:!bg-slate-900 !p-0"
|
||||
color-scheme="secondary"
|
||||
@click="toggleEmojiPicker"
|
||||
>
|
||||
<span v-if="icon" v-dompurify-html="icon" class="text-lg" />
|
||||
<fluent-icon
|
||||
v-else
|
||||
size="18"
|
||||
icon="emoji-add"
|
||||
type="outline"
|
||||
class="text-slate-400 dark:text-slate-600"
|
||||
/>
|
||||
</woot-button>
|
||||
<woot-input
|
||||
v-model="name"
|
||||
:class="{ error: hasError }"
|
||||
class="!mt-0 !mb-4 !mx-0 [&>input]:!mb-0 ltr:[&>input]:ml-12 rtl:[&>input]:mr-12 relative w-[calc(100%-3rem)] [&>p]:w-max"
|
||||
:error="nameErrorMessage"
|
||||
:label="label"
|
||||
:placeholder="placeholder"
|
||||
:help-text="helpText"
|
||||
@input="onNameChange"
|
||||
/>
|
||||
<emoji-input
|
||||
v-if="showEmojiPicker"
|
||||
v-on-clickaway="hideEmojiPicker"
|
||||
class="left-0 top-16"
|
||||
:show-remove-button="true"
|
||||
:on-click="onClickInsertEmoji"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
|
||||
const EmojiInput = () => import('shared/components/emoji/EmojiInput');
|
||||
|
||||
export default {
|
||||
components: { EmojiInput },
|
||||
mixins: [clickaway],
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
helpText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hasError: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
errorMessage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
existingName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
savedIcon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
icon: '',
|
||||
showEmojiPicker: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
nameErrorMessage() {
|
||||
if (this.hasError) {
|
||||
return this.errorMessage;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateDataFromStore();
|
||||
},
|
||||
methods: {
|
||||
updateDataFromStore() {
|
||||
this.name = this.existingName;
|
||||
this.icon = this.savedIcon;
|
||||
},
|
||||
toggleEmojiPicker() {
|
||||
this.showEmojiPicker = !this.showEmojiPicker;
|
||||
},
|
||||
onClickInsertEmoji(emoji = '') {
|
||||
this.icon = emoji;
|
||||
this.$emit('icon-change', emoji);
|
||||
this.showEmojiPicker = false;
|
||||
},
|
||||
onNameChange() {
|
||||
this.$emit('name-change', this.name);
|
||||
},
|
||||
hideEmojiPicker() {
|
||||
if (this.showEmojiPicker) {
|
||||
this.showEmojiPicker = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.emoji-dialog::before {
|
||||
@apply hidden;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user