Fix notification dropdown accessibility

This commit is contained in:
Chocobozzz 2024-09-20 10:45:16 +02:00
parent 8ce037b0c0
commit fff5a323fd
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 108 additions and 109 deletions

View File

@ -79,7 +79,7 @@
</div>
@defer (when isLoggedIn) {
<my-notification (navigate)="onActiveLinkScrollToAnchor($event)"></my-notification>
<my-notification-dropdown (navigate)="onActiveLinkScrollToAnchor($event)"></my-notification-dropdown>
}
</div>

View File

@ -116,7 +116,7 @@ nav {
}
}
my-notification {
my-notification-dropdown {
@include margin-left(auto);
@include margin-right(15px);
}

View File

@ -27,7 +27,7 @@ import debug from 'debug'
import { forkJoin, Subscription } from 'rxjs'
import { first, switchMap } from 'rxjs/operators'
import { LanguageChooserComponent } from './language-chooser.component'
import { NotificationComponent } from './notification.component'
import { NotificationDropdownComponent } from './notification-dropdown.component'
import { QuickSettingsModalComponent } from './quick-settings-modal.component'
const debugLogger = debug('peertube:menu:MenuComponent')
@ -39,7 +39,7 @@ const debugLogger = debug('peertube:menu:MenuComponent')
standalone: true,
imports: [
CommonModule,
NotificationComponent,
NotificationDropdownComponent,
ActorAvatarComponent,
InputSwitchComponent,
SignupLabelComponent,

View File

@ -0,0 +1,70 @@
<ng-template #notificationNumber>
<div *ngIf="unreadNotifications > 0 && unreadNotifications < 100" class="unread-notifications">{{ unreadNotifications }}</div>
<div *ngIf="unreadNotifications >= 100" class="unread-notifications">99+</div>
</ng-template>
@if (isInMobileView) {
<div i18n-title title="View your notifications" class="notification-inbox-link">
<ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
<a routerLink="/my-account/notifications" routerLinkActive="active" #link (click)="onNavigate(link)">
<my-global-icon iconName="bell"></my-global-icon>
</a>
</div>
} @else {
<div
ngbDropdown autoClose="outside" placement="bottom" container="body" dropdownClass="dropdown-notifications"
#dropdown="ngbDropdown" (shown)="onDropdownShown()" (hidden)="onDropdownHidden()"
>
<button
i18n-title title="View your notifications"
class="border-0 text-start disable-dropdown-caret" [ngClass]="{ 'notification-inbox-dropdown': true, 'shown': opened, 'hidden': isInMobileView }"
ngbDropdownToggle
>
<ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
<my-global-icon iconName="bell"></my-global-icon>
</button>
<div ngbDropdownMenu>
<div class="content" [ngClass]="{ loaded: loaded }">
<div class="notifications-header">
<div i18n>Notifications</div>
<div>
<button
*ngIf="unreadNotifications"
i18n-title title="Mark all as read" class="me-2"
(click)="markAllAsRead()"
>
<my-global-icon iconName="tick"></my-global-icon>
</button>
<a
i18n-title title="Update your notification preferences"
routerLink="/my-account/settings" fragment="notifications"
#settingsNotifications (click)="onNavigate(settingsNotifications)"
>
<my-global-icon iconName="cog"></my-global-icon>
</a>
</div>
</div>
<div *ngIf="!loaded" class="loader mt-4">
<my-loader size="xl" [loading]="!loaded"></my-loader>
</div>
<my-user-notifications
[ignoreLoadingBar]="true" [infiniteScroll]="false" [itemsPerPage]="10"
[markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
></my-user-notifications>
<a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)">
<my-global-icon class="me-1" iconName="bell" aria-hidden="true"></my-global-icon>
<span i18n>See all your notifications</span>
</a>
</div>
</div>
</div>
}

View File

@ -5,7 +5,7 @@
scrollbar-color: auto;
}
.notification-inbox-popover {
.notification-inbox-dropdown {
padding: 10px;
}
@ -13,7 +13,7 @@
padding: 13px 10px;
}
.notification-inbox-popover,
.notification-inbox-dropdown,
.notification-inbox-link a {
transition: all .1s ease-in-out;
border-radius: 25px;
@ -33,7 +33,7 @@
}
}
.notification-inbox-popover.shown,
.notification-inbox-dropdown.shown,
.notification-inbox-link a.active {
background-color: rgba(255, 255, 255, 0.28);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .325);
@ -41,21 +41,17 @@
@include apply-svg-color(#fff);
}
.notification-inbox-popover.hidden {
.notification-inbox-dropdown.hidden {
display: none;
}
::ng-deep {
.popover-notifications.popover {
.dropdown-notifications {
max-width: none;
top: -6px !important;
left: 7px !important;
.arrow {
display: none;
}
.popover-body {
.dropdown-menu {
padding: 0;
font-size: 14px;
font-family: $main-fonts;
@ -130,20 +126,23 @@
}
.all-notifications {
display: flex;
align-items: center;
justify-content: center;
border-top: 1px solid rgba(0, 0, 0, 0.1);
margin-top: -1px; // To not have 2 borders with the last notification
text-align: center;
font-weight: $font-semibold;
color: pvar(--mainForegroundColor);
padding: 7px 0;
margin-top: auto;
text-decoration: none;
padding: 0.75rem 0;
text-decoration: underline !important;
&:hover {
opacity: 0.85;
}
}
}
}
}
.notification-inbox-popover,
.notification-inbox-dropdown,
.notification-inbox-link {
cursor: pointer;
position: relative;

View File

@ -6,14 +6,14 @@ import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.compon
import { LoaderComponent } from '@app/shared/shared-main/loaders/loader.component'
import { UserNotificationService } from '@app/shared/shared-main/users/user-notification.service'
import { UserNotificationsComponent } from '@app/shared/standalone-notifications/user-notifications.component'
import { NgbPopover, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { NgbDropdown, NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { Subject, Subscription } from 'rxjs'
import { filter } from 'rxjs/operators'
@Component({
selector: 'my-notification',
templateUrl: './notification.component.html',
styleUrls: [ './notification.component.scss' ],
selector: 'my-notification-dropdown',
templateUrl: './notification-dropdown.component.html',
styleUrls: [ './notification-dropdown.component.scss' ],
standalone: true,
imports: [
CommonModule,
@ -22,11 +22,12 @@ import { filter } from 'rxjs/operators'
GlobalIconComponent,
LoaderComponent,
RouterLink,
RouterLinkActive
RouterLinkActive,
NgbDropdownModule
]
})
export class NotificationComponent implements OnInit, OnDestroy {
@ViewChild('popover', { static: true }) popover: NgbPopover
export class NotificationDropdownComponent implements OnInit, OnDestroy {
@ViewChild('dropdown', { static: false }) dropdown: NgbDropdown
@Output() navigate = new EventEmitter<HTMLAnchorElement>()
@ -61,7 +62,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
this.routeSub = this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(() => this.closePopover())
.subscribe(() => this.closeDropdown())
}
ngOnDestroy () {
@ -73,29 +74,17 @@ export class NotificationComponent implements OnInit, OnDestroy {
return this.screenService.isInMobileView()
}
closePopover () {
this.popover.close()
closeDropdown () {
if (this.dropdown) this.dropdown.close()
}
onPopoverShown () {
onDropdownShown () {
this.opened = true
document.querySelector('nav').scrollTo(0, 0) // Reset menu scroll to easy lock
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').addEventListener('scroll', this.onMenuScrollEvent)
}
onPopoverHidden () {
onDropdownHidden () {
this.loaded = false
this.opened = false
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent)
}
// Lock menu scroll when menu scroll to avoid fleeing / detached dropdown
onMenuScrollEvent () {
document.querySelector('nav').scrollTo(0, 0)
}
onNotificationLoaded () {
@ -103,7 +92,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
}
onNavigate (link: HTMLAnchorElement) {
this.closePopover()
this.closeDropdown()
this.navigate.emit(link)
}

View File

@ -1,63 +0,0 @@
<ng-template #notificationNumber>
<div *ngIf="unreadNotifications > 0 && unreadNotifications < 100" class="unread-notifications">{{ unreadNotifications }}</div>
<div *ngIf="unreadNotifications >= 100" class="unread-notifications">99+</div>
</ng-template>
<button
[ngbPopover]="popContent" autoClose="outside" placement="bottom" container="body" popoverClass="popover-notifications"
i18n-title title="View your notifications"
class="border-0 text-start" [ngClass]="{ 'notification-inbox-popover': true, 'shown': opened, 'hidden': isInMobileView }"
#popover="ngbPopover" (shown)="onPopoverShown()" (hidden)="onPopoverHidden()"
>
<ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
<my-global-icon iconName="bell"></my-global-icon>
</button>
<div *ngIf="isInMobileView" i18n-title title="View your notifications" class="notification-inbox-link">
<ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
<a routerLink="/my-account/notifications" routerLinkActive="active" #link (click)="onNavigate(link)">
<my-global-icon iconName="bell"></my-global-icon>
</a>
</div>
<ng-template #popContent>
<div class="content" [ngClass]="{ loaded: loaded }">
<div class="notifications-header">
<div i18n>Notifications</div>
<div>
<button
*ngIf="unreadNotifications"
i18n-title title="Mark all as read" class="me-2"
(click)="markAllAsRead()"
>
<my-global-icon iconName="tick"></my-global-icon>
</button>
<a
i18n-title title="Update your notification preferences"
routerLink="/my-account/settings" fragment="notifications"
#settingsNotifications (click)="onNavigate(settingsNotifications)"
>
<my-global-icon iconName="cog"></my-global-icon>
</a>
</div>
</div>
<div *ngIf="!loaded" class="loader mt-4">
<my-loader size="xl" [loading]="!loaded"></my-loader>
</div>
<my-user-notifications
[ignoreLoadingBar]="true" [infiniteScroll]="false" [itemsPerPage]="10"
[markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
></my-user-notifications>
<a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)">
<my-global-icon class="me-1" iconName="bell" aria-hidden="true"></my-global-icon>
<span i18n>See all your notifications</span>
</a>
</div>
</ng-template>

View File

@ -102,6 +102,10 @@ body {
margin: 0.3rem 0;
}
.disable-dropdown-caret::after {
display: none;
}
// ---------------------------------------------------------------------------
// Alert
// ---------------------------------------------------------------------------