1<template>
2 <span
3 v-if="notificationStore.visible"
4 ref="target"
5 class="fixed z-10 h-screen overflow-auto bg-surface-base notifications-panel"
6 :style="{
7 'box-shadow': '8px 0px 8px rgba(0, 0, 0, 0.1)',
8 'max-width': '350px',
9 'min-width': '350px',
10 'inset-inline-start': sidebarStore.width,
11 }"
12 >
13 <NotificationPanel
14 v-bind="controller"
15 @mark-as-read="handleNotificationClick"
16 @mark-all-as-read="controller.markAllAsRead"
17 @load-more="controller.loadMore"
18 @close="notificationStore.toggle()"
19 >
20 <template #header="{ markAllAsRead, close }">
21 <div class="flex items-center gap-2 px-4 py-2 pt-4">
22 <span class="text-md font-medium mr-auto">
23 {{ __("Notifications") }}
24 </span>
25 <Button
26 variant="ghost"
27 size="sm"
28 :tooltip="__('Mark all as read')"
29 :aria-label="__('Mark all as read')"
30 :icon="LucideCheckCheck"
31 @click="markAllAsRead"
32 />
33 <Button
34 variant="ghost"
35 size="sm"
36 :tooltip="__('Close')"
37 :aria-label="__('Close')"
38 :icon="LucideX"
39 @click="close"
40 />
41 </div>
42 <NotificationFilters />
43 </template>
44 </NotificationPanel>
45 </span>
46</template>
47
48<script setup lang="ts">
49import { useNotificationStore } from "@/stores/notification";
50import { useSidebarStore } from "@/stores/sidebar";
51import { __ } from "@/translation";
52import { NotificationLog, NotificationPanel } from "@framework/ui";
53import { onClickOutside, useEventListener } from "@vueuse/core";
54import { Button } from "frappe-ui";
55import { ref } from "vue";
56import { useRouter } from "vue-router";
57import LucideCheckCheck from "~icons/lucide/check-check";
58import LucideX from "~icons/lucide/x";
59import NotificationFilters from "./NotificationFilters.vue";
60
61const notificationStore = useNotificationStore();
62const controller = notificationStore.controller;
63const sidebarStore = useSidebarStore();
64const router = useRouter();
65const target = ref(null);
66
67// An open menu makes the page inert, so its dismiss click lands outside the
68// panel; the menu is gone by click time, so note it on pointerdown.
69let menuWasOpen = false;
70useEventListener(
71 window,
72 "pointerdown",
73 () => (menuWasOpen = !!document.querySelector("[role='menu']")),
74 { capture: true }
75);
76
77onClickOutside(
78 target,
79 () => {
80 if (menuWasOpen) return;
81 if (notificationStore.visible) {
82 notificationStore.toggle();
83 }
84 },
85 {
86 ignore: ["#notifications-btn"],
87 }
88);
89
90function handleNotificationClick(n: NotificationLog) {
91 controller.markAsRead(n.name);
92 const route = notificationStore.routeFor(n);
93 notificationStore.toggle();
94 if (route) router.push(route);
95}
96</script>
97<style lang="css">
98[dir="rtl"] .notifications-panel {
99 box-shadow: -8px 0px 8px rgba(0, 0, 0, 0.1) !important;
100}
101</style>
102