feat(v4): Update the help center portal design (#10296)
Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { debounce } from '@chatwoot/utils';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ARTICLE_EDITOR_MENU_OPTIONS } from 'dashboard/constants/editor';
|
||||
|
||||
import HelpCenterLayout from 'dashboard/components-next/HelpCenter/HelpCenterLayout.vue';
|
||||
import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
|
||||
import FullEditor from 'dashboard/components/widgets/WootWriter/FullEditor.vue';
|
||||
import ArticleEditorHeader from 'dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditorHeader.vue';
|
||||
import ArticleEditorControls from 'dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditorControls.vue';
|
||||
|
||||
const props = defineProps({
|
||||
article: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
isUpdating: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isSaved: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
'saveArticle',
|
||||
'goBack',
|
||||
'setAuthor',
|
||||
'setCategory',
|
||||
'previewArticle',
|
||||
]);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const saveArticle = debounce(value => emit('saveArticle', value), 400, false);
|
||||
|
||||
const articleTitle = computed({
|
||||
get: () => props.article.title,
|
||||
set: value => {
|
||||
saveArticle({ title: value });
|
||||
},
|
||||
});
|
||||
|
||||
const articleContent = computed({
|
||||
get: () => props.article.content,
|
||||
set: content => {
|
||||
saveArticle({ content });
|
||||
},
|
||||
});
|
||||
|
||||
const onClickGoBack = () => {
|
||||
emit('goBack');
|
||||
};
|
||||
|
||||
const setAuthorId = authorId => {
|
||||
emit('setAuthor', authorId);
|
||||
};
|
||||
|
||||
const setCategoryId = categoryId => {
|
||||
emit('setCategory', categoryId);
|
||||
};
|
||||
|
||||
const previewArticle = () => {
|
||||
emit('previewArticle');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<HelpCenterLayout :show-header-title="false" :show-pagination-footer="false">
|
||||
<template #header-actions>
|
||||
<ArticleEditorHeader
|
||||
:is-updating="isUpdating"
|
||||
:is-saved="isSaved"
|
||||
:status="article.status"
|
||||
:article-id="article.id"
|
||||
@go-back="onClickGoBack"
|
||||
@preview-article="previewArticle"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="flex flex-col gap-3 pl-4 mb-3 rtl:pr-3 rtl:pl-0">
|
||||
<TextArea
|
||||
v-model="articleTitle"
|
||||
auto-height
|
||||
min-height="4rem"
|
||||
custom-text-area-class="!text-[32px] !leading-[48px] !font-medium !tracking-[0.2px]"
|
||||
custom-text-area-wrapper-class="border-0 !bg-transparent dark:!bg-transparent !py-0 !px-0"
|
||||
placeholder="Title"
|
||||
autofocus
|
||||
/>
|
||||
<ArticleEditorControls
|
||||
:article="article"
|
||||
@save-article="saveArticle"
|
||||
@set-author="setAuthorId"
|
||||
@set-category="setCategoryId"
|
||||
/>
|
||||
</div>
|
||||
<FullEditor
|
||||
v-model="articleContent"
|
||||
class="py-0 pb-10 pl-4 rtl:pr-4 rtl:pl-0 h-fit"
|
||||
:placeholder="
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.EDIT_ARTICLE.EDITOR_PLACEHOLDER')
|
||||
"
|
||||
:enabled-menu-options="ARTICLE_EDITOR_MENU_OPTIONS"
|
||||
:autofocus="false"
|
||||
/>
|
||||
</template>
|
||||
</HelpCenterLayout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep {
|
||||
.ProseMirror .empty-node::before {
|
||||
@apply text-slate-200 dark:text-slate-500 text-base;
|
||||
}
|
||||
|
||||
.ProseMirror-menubar-wrapper {
|
||||
.ProseMirror-woot-style {
|
||||
@apply min-h-[15rem] max-h-full;
|
||||
}
|
||||
}
|
||||
|
||||
.ProseMirror-menubar {
|
||||
display: none; // Hide by default
|
||||
}
|
||||
|
||||
.editor-root .has-selection {
|
||||
.ProseMirror-menubar {
|
||||
@apply h-8 rounded-lg !px-2 z-50 bg-slate-50 dark:bg-slate-800 items-center gap-4 ml-0 mb-0 shadow-md border border-slate-75 dark:border-slate-700/50;
|
||||
display: flex;
|
||||
top: var(--selection-top, auto) !important;
|
||||
left: var(--selection-left, 0) !important;
|
||||
width: fit-content !important;
|
||||
position: absolute !important;
|
||||
|
||||
.ProseMirror-menuitem {
|
||||
@apply mr-0;
|
||||
|
||||
.ProseMirror-icon {
|
||||
@apply p-0 mt-1 !mr-0;
|
||||
|
||||
svg {
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,206 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { OnClickOutside } from '@vueuse/components';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Thumbnail from 'dashboard/components-next/thumbnail/Thumbnail.vue';
|
||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||
import ArticleEditorProperties from 'dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditorProperties.vue';
|
||||
|
||||
const props = defineProps({
|
||||
article: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['saveArticle', 'setAuthor', 'setCategory']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const openAgentsList = ref(false);
|
||||
const openCategoryList = ref(false);
|
||||
const openProperties = ref(false);
|
||||
const selectedAuthorId = ref(null);
|
||||
const selectedCategoryId = ref(null);
|
||||
|
||||
const agents = useMapGetter('agents/getAgents');
|
||||
const categories = useMapGetter('categories/allCategories');
|
||||
const currentUserId = useMapGetter('getCurrentUserID');
|
||||
|
||||
const isNewArticle = computed(() => !props.article?.id);
|
||||
|
||||
const currentUser = computed(() =>
|
||||
agents.value.find(agent => agent.id === currentUserId.value)
|
||||
);
|
||||
|
||||
const author = computed(() => {
|
||||
if (isNewArticle.value) {
|
||||
return selectedAuthorId.value
|
||||
? agents.value.find(agent => agent.id === selectedAuthorId.value)
|
||||
: currentUser.value;
|
||||
}
|
||||
return props.article?.author || currentUser.value;
|
||||
});
|
||||
|
||||
const authorName = computed(
|
||||
() => author.value?.name || author.value?.available_name || '-'
|
||||
);
|
||||
const authorThumbnailSrc = computed(() => author.value?.thumbnail);
|
||||
|
||||
const agentList = computed(() => {
|
||||
return [...agents.value]
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map(agent => ({
|
||||
label: agent.name,
|
||||
value: agent.id,
|
||||
thumbnail: { name: agent.name, src: agent.thumbnail },
|
||||
isSelected: agent.id === props.article?.author?.id,
|
||||
action: 'assignAuthor',
|
||||
}))
|
||||
.sort((a, b) => b.isSelected - a.isSelected);
|
||||
});
|
||||
|
||||
const hasAgentList = computed(() => {
|
||||
return agents.value?.length > 0;
|
||||
});
|
||||
|
||||
const selectedCategory = computed(() => {
|
||||
if (isNewArticle.value) {
|
||||
return selectedCategoryId.value
|
||||
? categories.value.find(
|
||||
category => category.id === selectedCategoryId.value
|
||||
)
|
||||
: categories.value[0] || null;
|
||||
}
|
||||
return categories.value.find(
|
||||
category => category.id === props.article?.category?.id
|
||||
);
|
||||
});
|
||||
|
||||
const categoryList = computed(() => {
|
||||
return categories.value
|
||||
.map(category => ({
|
||||
label: category.name,
|
||||
value: category.id,
|
||||
emoji: category.icon,
|
||||
isSelected: category.id === props.article?.category?.id,
|
||||
action: 'assignCategory',
|
||||
}))
|
||||
.sort((a, b) => b.isSelected - a.isSelected);
|
||||
});
|
||||
|
||||
const hasCategoryMenuItems = computed(() => {
|
||||
return categoryList.value?.length > 0;
|
||||
});
|
||||
|
||||
const handleArticleAction = ({ action, value }) => {
|
||||
const actions = {
|
||||
assignAuthor: () => {
|
||||
if (isNewArticle.value) {
|
||||
selectedAuthorId.value = value;
|
||||
emit('setAuthor', value);
|
||||
} else {
|
||||
emit('saveArticle', { author_id: value });
|
||||
}
|
||||
openAgentsList.value = false;
|
||||
},
|
||||
assignCategory: () => {
|
||||
if (isNewArticle.value) {
|
||||
selectedCategoryId.value = value;
|
||||
emit('setCategory', value);
|
||||
} else {
|
||||
emit('saveArticle', { category_id: value });
|
||||
}
|
||||
openCategoryList.value = false;
|
||||
},
|
||||
};
|
||||
|
||||
actions[action]?.();
|
||||
};
|
||||
|
||||
const updateMeta = meta => {
|
||||
emit('saveArticle', { meta });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<OnClickOutside @trigger="openAgentsList = false">
|
||||
<Button
|
||||
:label="authorName"
|
||||
variant="ghost"
|
||||
class="!px-0 font-normal"
|
||||
text-variant="info"
|
||||
@click="openAgentsList = !openAgentsList"
|
||||
>
|
||||
<template #leftPrefix>
|
||||
<Thumbnail
|
||||
v-if="author"
|
||||
:author="author"
|
||||
:name="authorName"
|
||||
:size="20"
|
||||
:src="authorThumbnailSrc"
|
||||
/>
|
||||
</template>
|
||||
</Button>
|
||||
<DropdownMenu
|
||||
v-if="openAgentsList && hasAgentList"
|
||||
:menu-items="agentList"
|
||||
class="z-[100] w-48 mt-2 overflow-y-auto ltr:left-0 rtl:right-0 top-full max-h-52"
|
||||
@action="handleArticleAction"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
</div>
|
||||
<div class="w-px h-3 bg-slate-50 dark:bg-slate-800" />
|
||||
<div class="relative">
|
||||
<OnClickOutside @trigger="openCategoryList = false">
|
||||
<Button
|
||||
:label="
|
||||
selectedCategory?.name ||
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.EDIT_ARTICLE.UNCATEGORIZED')
|
||||
"
|
||||
:emoji="selectedCategory?.icon || ''"
|
||||
:icon="!selectedCategory?.icon ? 'play-shape' : ''"
|
||||
variant="ghost"
|
||||
class="!px-2 font-normal"
|
||||
text-variant="info"
|
||||
@click="openCategoryList = !openCategoryList"
|
||||
/>
|
||||
<DropdownMenu
|
||||
v-if="openCategoryList && hasCategoryMenuItems"
|
||||
:menu-items="categoryList"
|
||||
class="w-48 mt-2 z-[100] overflow-y-auto left-0 top-full max-h-52"
|
||||
@action="handleArticleAction"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
</div>
|
||||
|
||||
<div class="w-px h-3 bg-slate-50 dark:bg-slate-800" />
|
||||
<div class="relative">
|
||||
<OnClickOutside @trigger="openProperties = false">
|
||||
<Button
|
||||
:label="
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.EDIT_ARTICLE.MORE_PROPERTIES')
|
||||
"
|
||||
icon="add"
|
||||
variant="ghost"
|
||||
:disabled="isNewArticle"
|
||||
text-variant="info"
|
||||
class="!px-2 font-normal"
|
||||
@click="openProperties = !openProperties"
|
||||
/>
|
||||
<ArticleEditorProperties
|
||||
v-if="openProperties"
|
||||
:article="article"
|
||||
class="right-0 z-[100] mt-2 xl:left-0 top-full"
|
||||
@save-article="updateMeta"
|
||||
@close="openProperties = false"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,178 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useStore } from 'dashboard/composables/store.js';
|
||||
import { useAlert, useTrack } from 'dashboard/composables';
|
||||
import { PORTALS_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import { OnClickOutside } from '@vueuse/components';
|
||||
import { getArticleStatus } from 'dashboard/helper/portalHelper.js';
|
||||
import {
|
||||
ARTICLE_EDITOR_STATUS_OPTIONS,
|
||||
ARTICLE_STATUSES,
|
||||
ARTICLE_MENU_ITEMS,
|
||||
} from 'dashboard/helper/portalHelper';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||
|
||||
const props = defineProps({
|
||||
isUpdating: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isSaved: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
articleId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['goBack', 'previewArticle']);
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useStore();
|
||||
const route = useRoute();
|
||||
|
||||
const isArticlePublishing = ref(false);
|
||||
|
||||
const { ARTICLE_STATUS_TYPES } = wootConstants;
|
||||
|
||||
const showArticleActionMenu = ref(false);
|
||||
|
||||
const articleMenuItems = computed(() => {
|
||||
const statusOptions = ARTICLE_EDITOR_STATUS_OPTIONS[props.status] ?? [];
|
||||
return statusOptions.map(option => {
|
||||
const { label, value, icon } = ARTICLE_MENU_ITEMS[option];
|
||||
return {
|
||||
label: t(label),
|
||||
value,
|
||||
action: 'update-status',
|
||||
icon,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const statusText = computed(() =>
|
||||
t(
|
||||
`HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.STATUS.${props.isUpdating ? 'SAVING' : 'SAVED'}`
|
||||
)
|
||||
);
|
||||
|
||||
const onClickGoBack = () => emit('goBack');
|
||||
|
||||
const previewArticle = () => emit('previewArticle');
|
||||
|
||||
const getStatusMessage = (status, isSuccess) => {
|
||||
const messageType = isSuccess ? 'SUCCESS' : 'ERROR';
|
||||
const statusMap = {
|
||||
[ARTICLE_STATUS_TYPES.PUBLISH]: 'PUBLISH_ARTICLE',
|
||||
[ARTICLE_STATUS_TYPES.ARCHIVE]: 'ARCHIVE_ARTICLE',
|
||||
[ARTICLE_STATUS_TYPES.DRAFT]: 'DRAFT_ARTICLE',
|
||||
};
|
||||
|
||||
return statusMap[status]
|
||||
? t(`HELP_CENTER.${statusMap[status]}.API.${messageType}`)
|
||||
: '';
|
||||
};
|
||||
|
||||
const updateArticleStatus = async ({ value }) => {
|
||||
showArticleActionMenu.value = false;
|
||||
const status = getArticleStatus(value);
|
||||
if (status === ARTICLE_STATUS_TYPES.PUBLISH) {
|
||||
isArticlePublishing.value = true;
|
||||
}
|
||||
const { portalSlug } = route.params;
|
||||
|
||||
try {
|
||||
await store.dispatch('articles/update', {
|
||||
portalSlug,
|
||||
articleId: props.articleId,
|
||||
status,
|
||||
});
|
||||
|
||||
useAlert(getStatusMessage(status, true));
|
||||
|
||||
if (status === ARTICLE_STATUS_TYPES.ARCHIVE) {
|
||||
useTrack(PORTALS_EVENTS.ARCHIVE_ARTICLE, { uiFrom: 'header' });
|
||||
} else if (status === ARTICLE_STATUS_TYPES.PUBLISH) {
|
||||
useTrack(PORTALS_EVENTS.PUBLISH_ARTICLE);
|
||||
}
|
||||
isArticlePublishing.value = false;
|
||||
} catch (error) {
|
||||
useAlert(error?.message ?? getStatusMessage(status, false));
|
||||
isArticlePublishing.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between h-20">
|
||||
<Button
|
||||
:label="t('HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.BACK_TO_ARTICLES')"
|
||||
icon="chevron-lucide-left"
|
||||
icon-lib="lucide"
|
||||
variant="link"
|
||||
text-variant="info"
|
||||
size="sm"
|
||||
@click="onClickGoBack"
|
||||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<span
|
||||
v-if="isUpdating || isSaved"
|
||||
class="text-xs font-medium transition-all duration-300 text-slate-500 dark:text-slate-400"
|
||||
>
|
||||
{{ statusText }}
|
||||
</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:label="t('HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.PREVIEW')"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
:disabled="!articleId"
|
||||
@click="previewArticle"
|
||||
/>
|
||||
<div class="flex items-center">
|
||||
<Button
|
||||
:label="t('HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.PUBLISH')"
|
||||
size="sm"
|
||||
class="ltr:rounded-r-none rtl:rounded-l-none"
|
||||
:is-loading="isArticlePublishing"
|
||||
:disabled="
|
||||
status === ARTICLE_STATUSES.PUBLISHED ||
|
||||
!articleId ||
|
||||
isArticlePublishing
|
||||
"
|
||||
@click="updateArticleStatus({ value: ARTICLE_STATUSES.PUBLISHED })"
|
||||
/>
|
||||
<div class="relative">
|
||||
<OnClickOutside @trigger="showArticleActionMenu = false">
|
||||
<Button
|
||||
icon="chevron-lucide-down"
|
||||
icon-lib="lucide"
|
||||
size="sm"
|
||||
:disabled="!articleId"
|
||||
class="ltr:rounded-l-none rtl:rounded-r-none"
|
||||
@click.stop="showArticleActionMenu = !showArticleActionMenu"
|
||||
/>
|
||||
<DropdownMenu
|
||||
v-if="showArticleActionMenu"
|
||||
:menu-items="articleMenuItems"
|
||||
class="mt-2 ltr:right-0 rtl:left-0 top-full"
|
||||
@action="updateArticleStatus($event)"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,134 @@
|
||||
<script setup>
|
||||
import { reactive, watch, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { debounce } from '@chatwoot/utils';
|
||||
|
||||
import InlineInput from 'dashboard/components-next/inline-input/InlineInput.vue';
|
||||
import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
|
||||
import TagInput from 'dashboard/components-next/taginput/TagInput.vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
|
||||
const props = defineProps({
|
||||
article: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['saveArticle', 'close']);
|
||||
|
||||
const saveArticle = debounce(value => emit('saveArticle', value), 400, false);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const state = reactive({
|
||||
title: '',
|
||||
description: '',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const updateState = () => {
|
||||
state.title = props.article.meta?.title || '';
|
||||
state.description = props.article.meta?.description || '';
|
||||
state.tags = props.article.meta?.tags || [];
|
||||
};
|
||||
|
||||
watch(
|
||||
state,
|
||||
newState => {
|
||||
saveArticle({
|
||||
title: newState.title,
|
||||
description: newState.description,
|
||||
tags: newState.tags,
|
||||
});
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
updateState();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col absolute w-[400px] bg-n-alpha-3 backdrop-blur-[100px] shadow-lg gap-6 rounded-xl p-6"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3>
|
||||
{{
|
||||
t(
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.ARTICLE_PROPERTIES'
|
||||
)
|
||||
}}
|
||||
</h3>
|
||||
<Button
|
||||
icon="dismiss"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="w-8 hover:text-n-slate-11"
|
||||
@click="emit('close')"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div>
|
||||
<div class="flex justify-between w-full gap-4 py-2">
|
||||
<label
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[100px] text-slate-900 dark:text-slate-50"
|
||||
>
|
||||
{{
|
||||
t(
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_DESCRIPTION'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
<TextArea
|
||||
v-model="state.description"
|
||||
:placeholder="
|
||||
t(
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_DESCRIPTION_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
class="w-[224px]"
|
||||
custom-text-area-wrapper-class="!p-0 !border-0 !rounded-none !bg-transparent transition-none"
|
||||
custom-text-area-class="max-h-[150px]"
|
||||
auto-height
|
||||
min-height="3rem"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-between w-full gap-2 py-2">
|
||||
<InlineInput
|
||||
v-model="state.title"
|
||||
:placeholder="
|
||||
t(
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TITLE_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
:label="
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TITLE')
|
||||
"
|
||||
custom-label-class="min-w-[120px]"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-between w-full gap-2 py-2">
|
||||
<label
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[120px] text-slate-900 dark:text-slate-50"
|
||||
>
|
||||
{{
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TAGS')
|
||||
}}
|
||||
</label>
|
||||
<TagInput
|
||||
v-model="state.tags"
|
||||
:placeholder="
|
||||
t(
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TAGS_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
class="w-[224px]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user