mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-03 12:37:56 +00:00
feat: Add Help Center layout with portal switcher component (#10272)
This commit is contained in:
@@ -0,0 +1,92 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { OnClickOutside } from '@vueuse/components';
|
||||||
|
|
||||||
|
import PaginationFooter from 'dashboard/components-next/pagination/PaginationFooter.vue';
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import PortalSwitcher from 'dashboard/components-next/HelpCenter/PortalSwitcher/PortalSwitcher.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
header: {
|
||||||
|
type: String,
|
||||||
|
default: 'Chatwoot Help Center',
|
||||||
|
},
|
||||||
|
currentPage: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
totalItems: {
|
||||||
|
type: Number,
|
||||||
|
default: 100,
|
||||||
|
},
|
||||||
|
itemsPerPage: {
|
||||||
|
type: Number,
|
||||||
|
default: 25,
|
||||||
|
},
|
||||||
|
showPaginationFooter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:currentPage']);
|
||||||
|
|
||||||
|
const showPortalSwitcher = ref(false);
|
||||||
|
|
||||||
|
const updateCurrentPage = page => {
|
||||||
|
emit('update:currentPage', page);
|
||||||
|
};
|
||||||
|
const togglePortalSwitcher = () => {
|
||||||
|
showPortalSwitcher.value = !showPortalSwitcher.value;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section
|
||||||
|
class="flex flex-col w-full h-full overflow-hidden bg-white dark:bg-slate-900"
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
class="sticky top-0 z-10 px-6 pb-3 bg-white lg:px-0 dark:bg-slate-900"
|
||||||
|
>
|
||||||
|
<div class="w-full max-w-[900px] mx-auto">
|
||||||
|
<div class="flex items-center justify-start h-20 gap-2">
|
||||||
|
<span class="text-xl font-medium text-slate-900 dark:text-white">
|
||||||
|
{{ header }}
|
||||||
|
</span>
|
||||||
|
<div class="relative group">
|
||||||
|
<Button
|
||||||
|
icon="more-vertical"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
class="group-hover:bg-slate-100 dark:group-hover:bg-slate-800"
|
||||||
|
@click="togglePortalSwitcher"
|
||||||
|
/>
|
||||||
|
<OnClickOutside @trigger="showPortalSwitcher = false">
|
||||||
|
<PortalSwitcher
|
||||||
|
v-if="showPortalSwitcher"
|
||||||
|
class="absolute left-0 top-9"
|
||||||
|
/>
|
||||||
|
</OnClickOutside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<slot name="header-actions" />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="flex-1 px-6 overflow-y-auto lg:px-0">
|
||||||
|
<div class="w-full max-w-[900px] mx-auto py-3">
|
||||||
|
<slot name="content" />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer
|
||||||
|
v-if="showPaginationFooter"
|
||||||
|
class="sticky bottom-0 z-10 px-4 pt-3 pb-4 bg-white dark:bg-slate-900"
|
||||||
|
>
|
||||||
|
<PaginationFooter
|
||||||
|
:current-page="currentPage"
|
||||||
|
:total-items="totalItems"
|
||||||
|
:items-per-page="itemsPerPage"
|
||||||
|
@update:current-page="updateCurrentPage"
|
||||||
|
/>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<script setup>
|
||||||
|
import PortalSwitcher from './PortalSwitcher.vue';
|
||||||
|
|
||||||
|
const portals = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Chatwoot Help Center',
|
||||||
|
articles: 67,
|
||||||
|
domain: 'chatwoot.help',
|
||||||
|
slug: 'help-center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Chatwoot Handbook',
|
||||||
|
articles: 42,
|
||||||
|
domain: 'chatwoot.help',
|
||||||
|
slug: 'handbook',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Developer Documentation',
|
||||||
|
articles: 89,
|
||||||
|
domain: 'dev.chatwoot.com',
|
||||||
|
slug: 'docs',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Story
|
||||||
|
title="Components/HelpCenter/PortalSwitcher"
|
||||||
|
:layout="{ type: 'grid', width: '510px' }"
|
||||||
|
>
|
||||||
|
<Variant title="Portal Switcher">
|
||||||
|
<div class="h-[500px] p-4 bg-slate-100 dark:bg-slate-900">
|
||||||
|
<PortalSwitcher
|
||||||
|
:portals="portals"
|
||||||
|
header="Choose a Portal"
|
||||||
|
description="Select from available help center portals"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
</Story>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
portals: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Chatwoot Help Center',
|
||||||
|
articles: 67,
|
||||||
|
domain: 'chatwoot.help',
|
||||||
|
slug: 'help-center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Chatwoot Handbook',
|
||||||
|
articles: 42,
|
||||||
|
domain: 'chatwoot.help',
|
||||||
|
slug: 'handbook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
type: String,
|
||||||
|
default: 'Portals',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: 'Create and manage multiple portals',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedPortal = ref(1);
|
||||||
|
|
||||||
|
const handlePortalChange = id => {
|
||||||
|
selectedPortal.value = id;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- TODO: Add i18n -->
|
||||||
|
<!-- eslint-disable vue/no-bare-strings-in-template -->
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="pt-5 pb-3 bg-white z-50 dark:bg-slate-800 absolute w-[440px] rounded-xl shadow-md flex flex-col gap-4"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between gap-4 px-6 pb-2">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<h2 class="text-base font-medium text-slate-900 dark:text-slate-50">
|
||||||
|
{{ header }}
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-slate-600 dark:text-slate-300">
|
||||||
|
{{ description }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button label="New portal" variant="secondary" icon="add" size="sm" />
|
||||||
|
</div>
|
||||||
|
<div v-if="portals.length > 0" class="flex flex-col gap-3">
|
||||||
|
<template v-for="(portal, index) in portals" :key="portal.id">
|
||||||
|
<div class="flex flex-col gap-2 px-6 py-2">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input
|
||||||
|
:id="portal.id"
|
||||||
|
v-model="selectedPortal"
|
||||||
|
type="radio"
|
||||||
|
:value="portal.id"
|
||||||
|
class="mr-3"
|
||||||
|
@change="handlePortalChange(portal.id)"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
:for="portal.id"
|
||||||
|
class="text-sm font-medium text-slate-900 dark:text-slate-100"
|
||||||
|
>
|
||||||
|
{{ portal.name }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="w-4 h-4 rounded-full bg-slate-100 dark:bg-slate-700" />
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-center gap-2 py-1 text-sm">
|
||||||
|
<span class="text-slate-600 dark:text-slate-400">
|
||||||
|
articles:
|
||||||
|
<span class="text-slate-800 dark:text-slate-200">
|
||||||
|
{{ portal.articles }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<div class="w-px h-3 bg-slate-50 dark:bg-slate-700" />
|
||||||
|
<span class="text-slate-600 dark:text-slate-400">
|
||||||
|
domain:
|
||||||
|
<span class="text-slate-800 dark:text-slate-200">
|
||||||
|
{{ portal.domain }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<div class="w-px h-3 bg-slate-50 dark:bg-slate-700" />
|
||||||
|
<span class="text-slate-600 dark:text-slate-400">
|
||||||
|
slug:
|
||||||
|
<span class="text-slate-800 dark:text-slate-200">
|
||||||
|
{{ portal.slug }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="index < portals.length - 1 && portals.length > 1"
|
||||||
|
class="w-full h-px bg-slate-50 dark:bg-slate-700/50"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user