Skip to content

Commit

Permalink
fix: add mobile sidebar component
Browse files Browse the repository at this point in the history
  • Loading branch information
RitvikSardana committed Aug 30, 2024
1 parent f6dbec5 commit 36d0352
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 10 deletions.
3 changes: 2 additions & 1 deletion desk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"copy-html-entry": "cp ../helpdesk/public/desk/index.html ../helpdesk/www/helpdesk/index.html"
},
"dependencies": {
"@headlessui/vue": "^1.7.22",
"@iconify-json/lucide": "^1.1.99",
"@iconify-json/ph": "^1.1.5",
"@iconify/tools": "^2.2.6",
Expand Down Expand Up @@ -37,7 +38,7 @@
"unplugin-vue-components": "^0.25.2",
"vee-validate": "^4.8.2",
"vite": "^4.4.9",
"vue": "^3.4.12",
"vue": "^3.4.12",
"vue-echarts": "^6.5.4",
"vue-router": "^4.2.2",
"vuedraggable": "^4.1.0",
Expand Down
6 changes: 2 additions & 4 deletions desk/src/components/layouts/DesktopLayout.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<template>
<div class="flex h-screen w-screen">
<div class="h-full border-r bg-gray-50">
<SideBar />
</div>
<Sidebar />
<div class="flex-1 flex flex-col h-full overflow-auto">
<slot />
</div>
</div>
</template>
<script setup>
import SideBar from "./SideBar.vue";
import Sidebar from "./Sidebar.vue";
</script>
14 changes: 14 additions & 0 deletions desk/src/components/layouts/MobileAppHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div class="flex border-b pr-3 h-12">
<div class="z-20 -mr-4 ml-1 flex items-center justify-center">
<Button variant="ghosted" @click="sidebarOpened = !sidebarOpened">
<FeatherIcon name="menu" class="size-4" />
</Button>
</div>
<div id="app-header" class="flex-1"></div>
</div>
</template>

<script setup>
import { mobileSidebarOpened as sidebarOpened } from "@/composables/mobile";
</script>
8 changes: 5 additions & 3 deletions desk/src/components/layouts/MobileLayout.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<template>
<div class="flex h-screen w-screen">
<SideBar />
<div class="flex h-full flex-1 flex-col overflow-auto">
<MobileSidebar />
<div class="flex h-full flex-col flex-1 overflow-auto">
<MobileAppHeader />
<slot />
</div>
</div>
</template>
<script setup>
import SideBar from "./SideBar.vue";
import MobileSidebar from "./MobileSidebar.vue";
import MobileAppHeader from "./MobileAppHeader.vue";
</script>
172 changes: 172 additions & 0 deletions desk/src/components/layouts/MobileSidebar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<template>
<TransitionRoot :show="sidebarOpened">
<Dialog as="div" @close="sidebarOpened = false" class="fixed inset-0 z-40">
<TransitionChild
as="template"
enter="transition ease-in-out duration-200 transform"
enter-from="-translate-x-full"
enter-to="translate-x-0"
leave="transition ease-in-out duration-200 transform"
leave-from="translate-x-0"
leave-to="-translate-x-full"
>
<div
class="relative z-10 flex h-full w-[260px] flex-col border-r bg-gray-50 transition-all duration-300 ease-in-out"
>
<!-- user dropwdown -->
<UserMenu class="p-2 mb-2 ml-0.5" :options="profileSettings" />
<!-- notifications -->
<div class="overflow-y-auto px-2">
<div class="mb-3 flex flex-col">
<SidebarLink
class="relative"
label="Notifications"
:icon="LucideInbox"
:on-click="() => notificationStore.toggle()"
:is-expanded="true"
>
<template #right>
<Badge
v-if="notificationStore.unread"
:label="notificationStore.unread"
theme="gray"
variant="subtle"
/>
</template>
</SidebarLink>
</div>
</div>

<div class="mb-4 flex flex-col gap-1 px-2">
<SidebarLink
v-for="option in menuOptions"
v-bind="option"
:key="option.label"
:is-expanded="true"
:is-active="isActiveTab(option.to)"
/>
</div>
</div>
</TransitionChild>
<TransitionChild
as="template"
enter="transition-opacity ease-linear duration-200"
enter-from="opacity-0"
enter-to="opacity-100"
leave="transition-opacity ease-linear duration-200"
leave-from="opacity-100"
leave-to="opacity-0"
>
<DialogOverlay class="fixed inset-0 bg-gray-600 bg-opacity-50" />
</TransitionChild>
</Dialog>
</TransitionRoot>
</template>

<script setup lang="ts">
import { computed, markRaw } from "vue";
import {
TransitionRoot,
TransitionChild,
Dialog,
DialogOverlay,
} from "@headlessui/vue";
import { useRouter, useRoute } from "vue-router";
import UserMenu from "@/components/UserMenu.vue";
import SidebarLink from "@/components/SidebarLink.vue";
import { useNotificationStore } from "@/stores/notification";
import { mobileSidebarOpened as sidebarOpened } from "@/composables/mobile";
import LucideBookOpen from "~icons/lucide/book-open";
import LucideCloudLightning from "~icons/lucide/cloud-lightning";
import LucideContact2 from "~icons/lucide/contact-2";
import LucideTicket from "~icons/lucide/ticket";
import LucideUser from "~icons/lucide/user";
import LucideUserCircle2 from "~icons/lucide/user-circle-2";
import LucideUsers from "~icons/lucide/users";
import LucideInbox from "~icons/lucide/inbox";
import {
AGENT_PORTAL_AGENT_LIST,
AGENT_PORTAL_CONTACT_LIST,
AGENT_PORTAL_CUSTOMER_LIST,
AGENT_PORTAL_TEAM_LIST,
AGENT_PORTAL_TICKET_LIST,
CUSTOMER_PORTAL_LANDING,
} from "@/router";
import Apps from "../Apps.vue";
const notificationStore = useNotificationStore();
const route = useRoute();
const router = useRouter();
const menuOptions = computed(() => [
{
label: "Tickets",
icon: LucideTicket,
to: AGENT_PORTAL_TICKET_LIST,
},
{
label: "Agents",
icon: LucideUser,
to: AGENT_PORTAL_AGENT_LIST,
},
{
label: "Knowledge base",
icon: LucideBookOpen,
to: "DeskKBHome",
},
{
label: "Teams",
icon: LucideUsers,
to: AGENT_PORTAL_TEAM_LIST,
},
{
label: "Canned responses",
icon: LucideCloudLightning,
to: "CannedResponses",
},
{
label: "Customers",
icon: LucideUserCircle2,
to: AGENT_PORTAL_CUSTOMER_LIST,
},
{
label: "Contacts",
icon: LucideContact2,
to: AGENT_PORTAL_CONTACT_LIST,
},
]);
const profileSettings = [
{
component: markRaw(Apps),
},
{
label: "Customer portal",
icon: "users",
onClick: () => {
const path = router.resolve({ name: CUSTOMER_PORTAL_LANDING });
window.open(path.href);
},
},
{
icon: "life-buoy",
label: "Support",
onClick: () => window.open("https://t.me/frappedesk"),
},
{
icon: "book-open",
label: "Docs",
onClick: () => window.open("https://docs.frappe.io/helpdesk"),
},
];
function isActiveTab(to: string) {
return route.name === to;
}
</script>

<style scoped></style>
3 changes: 3 additions & 0 deletions desk/src/composables/mobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ref } from "vue";

export const mobileSidebarOpened = ref(false);
23 changes: 23 additions & 0 deletions desk/src/composables/screen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { onMounted, onUnmounted, reactive } from "vue";

export function useScreenSize() {
const size = reactive({
width: window.innerWidth,
height: window.innerHeight,
});

const onResize = () => {
size.width = window.innerWidth;
size.height = window.innerHeight;
};

onMounted(() => {
window.addEventListener("resize", onResize);
});

onUnmounted(() => {
window.removeEventListener("resize", onResize);
});

return size;
}
6 changes: 4 additions & 2 deletions desk/src/pages/desk/AgentRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ import { useAuthStore } from "@/stores/auth";
import { useConfigStore } from "@/stores/config";
import { CUSTOMER_PORTAL_LANDING, ONBOARDING_PAGE } from "@/router";
import { CommandPalette, Notifications } from "@/components";
import { useScreenSize } from "@/composables/screen";
const router = useRouter();
const authStore = useAuthStore();
const configStore = useConfigStore();
const screenSize = useScreenSize();
const MobileLayout = defineAsyncComponent(
() => import("@/components/Layouts/MobileLayout.vue")
);
const DesktopLayout = defineAsyncComponent(
() => import("@/components/Layouts/DesktopLayout.vue")
);
const Layout = computed(() => {
if (window.innerWidth < 640) {
if (screenSize.width < 640) {
return MobileLayout;
} else {
return DesktopLayout;
Expand Down

0 comments on commit 36d0352

Please sign in to comment.