mirror of https://github.com/rancher/dashboard.git
113 lines
3.0 KiB
Vue
113 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import { useStore } from 'vuex';
|
|
import { computed, inject, ref } from 'vue';
|
|
import { DropdownContext, defaultContext } from '@components/RcDropdown/types';
|
|
|
|
const { dropdownItems } = inject<DropdownContext>('dropdownContext') || defaultContext;
|
|
const store = useStore();
|
|
const unreadCount = computed<number>(() => store.getters['notifications/unreadCount']);
|
|
const markAllReadButton = ref<HTMLElement>();
|
|
|
|
const markAllRead = (keyboard: boolean) => {
|
|
store.dispatch('notifications/markAllRead');
|
|
|
|
// If we have focus, then move to the next item if activated by the keyboard
|
|
if (keyboard && document.activeElement === markAllReadButton?.value) {
|
|
moveFocus(true);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handles keydown events to navigate between dropdown items.
|
|
* @param {KeyboardEvent} e - The keydown event.
|
|
*/
|
|
const handleKeydown = (e: KeyboardEvent) => {
|
|
const shouldAdvance = e.key === 'ArrowDown';
|
|
|
|
moveFocus(shouldAdvance);
|
|
};
|
|
|
|
// User pressed up/down - move focus to the correct notification item
|
|
// Header should always be the first item
|
|
const moveFocus = (shouldAdvance: Boolean) => {
|
|
if (dropdownItems.value.length > 1) {
|
|
const newIndex = shouldAdvance ? 1 : dropdownItems.value.length - 1;
|
|
|
|
if (dropdownItems.value[newIndex] instanceof HTMLElement) {
|
|
dropdownItems.value[newIndex].focus();
|
|
}
|
|
}
|
|
};
|
|
|
|
const gotFocus = (e: Event) => {
|
|
// If no unread items, then there is no button to focus, so move to the next item
|
|
if (unreadCount.value === 0) {
|
|
moveFocus(true);
|
|
}
|
|
|
|
// When the header gets focus, pass the focus onto the 'mark all read' button
|
|
markAllReadButton?.value?.focus();
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
dropdown-menu-item
|
|
tabindex="-1"
|
|
role="menuitem"
|
|
class="notification-header"
|
|
@click.stop
|
|
@keydown.up.down.stop.prevent="handleKeydown"
|
|
@focus="gotFocus"
|
|
>
|
|
<div class="notification-header">
|
|
<div class="notification-title">
|
|
{{ t('notificationCenter.title') }}
|
|
</div>
|
|
<div v-if="unreadCount !== 0">
|
|
<a
|
|
ref="markAllReadButton"
|
|
role="button"
|
|
tabindex="-1"
|
|
href="#"
|
|
data-testid="notifications-center-markall-read"
|
|
@keydown.up.down.stop.prevent="handleKeydown"
|
|
@keydown.enter.space.stop="markAllRead(true)"
|
|
@click="markAllRead(false)"
|
|
>
|
|
{{ t('notificationCenter.markAllRead') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="notification-border" />
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
[dropdown-menu-item] {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.notification-border {
|
|
border-bottom: 1px solid var(--border);
|
|
margin-left: -16px;
|
|
width: calc(100% + 32px);
|
|
}
|
|
|
|
.notification-header {
|
|
display: flex;
|
|
flex: 1;
|
|
padding: 6px 16px 16px 16px; // already 10px at the top of the dropdown
|
|
|
|
.notification-title {
|
|
font-weight: bold;
|
|
flex: 1;
|
|
}
|
|
|
|
A {
|
|
color: var(--link);
|
|
}
|
|
}
|
|
}
|
|
</style>
|