mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-03 12:37:56 +00:00
feat: Add the new Category card component (#10271)
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
<script setup>
|
||||||
|
import CategoryCard from './CategoryCard.vue';
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
id: 'getting-started',
|
||||||
|
title: '🚀 Getting started',
|
||||||
|
description:
|
||||||
|
'Learn how to use Chatwoot effectively and make the most of its features to enhance customer support and engagement.',
|
||||||
|
articlesCount: '5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'marketing',
|
||||||
|
title: '📈 Marketing',
|
||||||
|
description: '',
|
||||||
|
articlesCount: '4',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- eslint-disable vue/no-bare-strings-in-template -->
|
||||||
|
<!-- eslint-disable vue/no-undef-components -->
|
||||||
|
<template>
|
||||||
|
<Story
|
||||||
|
title="Components/HelpCenter/CategoryCard"
|
||||||
|
:layout="{ type: 'grid', width: '800px' }"
|
||||||
|
>
|
||||||
|
<Variant title="Category Card">
|
||||||
|
<div
|
||||||
|
v-for="(category, index) in categories"
|
||||||
|
:key="index"
|
||||||
|
class="px-20 py-4 bg-white dark:bg-slate-900"
|
||||||
|
>
|
||||||
|
<CategoryCard
|
||||||
|
:title="category.title"
|
||||||
|
:description="category.description"
|
||||||
|
:articles-count="category.articlesCount"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
</Story>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { OnClickOutside } from '@vueuse/components';
|
||||||
|
|
||||||
|
import CardLayout from 'dashboard/components-next/CardLayout.vue';
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
articlesCount: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['click']);
|
||||||
|
|
||||||
|
const isOpen = ref(false);
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{
|
||||||
|
label: 'Edit',
|
||||||
|
action: 'edit',
|
||||||
|
icon: 'edit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Delete',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'delete',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const description = computed(() => {
|
||||||
|
return props.description ? props.description : 'No description added';
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasDescription = computed(() => {
|
||||||
|
return props.description.length > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClick = id => {
|
||||||
|
emit('click', id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const handleAction = action => {
|
||||||
|
// TODO: Implement action
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- TODO: Add i18n -->
|
||||||
|
<!-- eslint-disable vue/no-bare-strings-in-template -->
|
||||||
|
<template>
|
||||||
|
<CardLayout @click="handleClick(id)">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div class="flex justify-between w-full">
|
||||||
|
<div class="flex items-center justify-start gap-2">
|
||||||
|
<span
|
||||||
|
class="text-base cursor-pointer group-hover/cardLayout:underline text-slate-900 dark:text-slate-50 line-clamp-1"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center justify-center h-6 px-2 py-1 text-xs text-center border rounded-lg text-slate-500 w-fit border-slate-200 dark:border-slate-800 dark:text-slate-400"
|
||||||
|
>
|
||||||
|
{{ articlesCount }} articles
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="relative group" @click.stop>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
icon="more-vertical"
|
||||||
|
class="w-8 z-60 group-hover:bg-slate-100 dark:group-hover:bg-slate-800"
|
||||||
|
@click="isOpen = !isOpen"
|
||||||
|
/>
|
||||||
|
<OnClickOutside @trigger="isOpen = false">
|
||||||
|
<DropdownMenu
|
||||||
|
v-if="isOpen"
|
||||||
|
:menu-items="menuItems"
|
||||||
|
class="right-0 mt-1 xl:left-0 top-full z-60"
|
||||||
|
@action="handleAction"
|
||||||
|
/>
|
||||||
|
</OnClickOutside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<span
|
||||||
|
class="text-sm line-clamp-3"
|
||||||
|
:class="
|
||||||
|
hasDescription
|
||||||
|
? 'text-slate-500 dark:text-slate-400'
|
||||||
|
: 'text-slate-400 dark:text-slate-700'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ description }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</CardLayout>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user