feat(nav): add cursor-pointer and tooltip to notification bell
Extract bellLabel as $derived to DRY up aria-label and title. Add cursor-pointer globally to button via @layer base so Tailwind preflight reset doesn't override the browser default. Closes #344 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,12 @@ function handleKeydown(event: KeyboardEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
const bellLabel = $derived(
|
||||
stream.unreadCount > 0
|
||||
? m.notification_bell_unread_label({ count: stream.unreadCount })
|
||||
: m.notification_bell_label()
|
||||
);
|
||||
|
||||
function attachBellButton(node: HTMLButtonElement) {
|
||||
bellButtonEl = node;
|
||||
return () => {
|
||||
@@ -72,12 +78,11 @@ onDestroy(() => {
|
||||
{@attach attachBellButton}
|
||||
type="button"
|
||||
onclick={toggleDropdown}
|
||||
aria-label={stream.unreadCount > 0
|
||||
? m.notification_bell_unread_label({ count: stream.unreadCount })
|
||||
: m.notification_bell_label()}
|
||||
aria-label={bellLabel}
|
||||
title={bellLabel}
|
||||
aria-expanded={open}
|
||||
aria-haspopup="true"
|
||||
class="relative rounded-sm p-2 text-white/65 transition-colors hover:bg-white/10 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
||||
class="relative cursor-pointer rounded-sm p-2 text-white/65 transition-colors hover:bg-white/10 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -55,6 +55,34 @@ async function openDropdownAndClickFirstNotification() {
|
||||
notifButton.click();
|
||||
}
|
||||
|
||||
describe('NotificationBell — cursor and tooltip', () => {
|
||||
it('bell button has cursor-pointer class', async () => {
|
||||
render(NotificationBell);
|
||||
const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
|
||||
expect(btn.classList.contains('cursor-pointer')).toBe(true);
|
||||
});
|
||||
|
||||
it('bell button title equals aria-label when unreadCount is 0', async () => {
|
||||
mockNotificationList.value = [];
|
||||
render(NotificationBell);
|
||||
const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
|
||||
expect(btn.getAttribute('title')).toBe('Benachrichtigungen');
|
||||
expect(btn.getAttribute('aria-label')).toBe(btn.getAttribute('title'));
|
||||
});
|
||||
|
||||
it('bell button title equals aria-label when unreadCount is 3', async () => {
|
||||
mockNotificationList.value = [
|
||||
makeNotification({ id: 'n1' }),
|
||||
makeNotification({ id: 'n2' }),
|
||||
makeNotification({ id: 'n3' })
|
||||
];
|
||||
render(NotificationBell);
|
||||
const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
|
||||
expect(btn.getAttribute('title')).toBe('3 ungelesene Benachrichtigungen');
|
||||
expect(btn.getAttribute('aria-label')).toBe(btn.getAttribute('title'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('NotificationBell', () => {
|
||||
it('handleMarkRead navigates to URL including annotationId when notification has annotationId', async () => {
|
||||
mockNotificationList.value = [makeNotification({ annotationId: 'annot-1' })];
|
||||
|
||||
@@ -365,6 +365,11 @@
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
/* Tailwind preflight resets cursor on *, overriding the browser default for buttons */
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Fallback focus ring for any interactive element not styled with ring-focus-ring */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--c-focus-ring);
|
||||
|
||||
Reference in New Issue
Block a user