fix(web): show notification count as menu badge and mark read on open
ci / ts / ts (packages + web) (push) Successful in 2m52s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Sonnet 5.5 committed 2026-10-28 13:56:05 +03:00
1 parent 139dd226fa
commit f77148df2c
4 files changed
+19 -3

No files matched your search

@@ -29,7 +29,7 @@ export function NotificationsDialog({ onClose, onOpen }: { onClose: () => void;
{shown.map(event => {
const date = new Date(event.created_at);
return <article key={event.id} className={`${s.row} ${!event.read ? s.unread : ''}`}>
<button type="button" className={s.open} aria-label={t('social.open_notification', { name: event.actor_name })} onClick={() => onOpen(event.actor_id)}>
<button type="button" className={s.open} aria-label={t('social.open_notification', { name: event.actor_name })} onClick={() => { if (!event.read) read.mutate(event.id); onOpen(event.actor_id); }}>
<span className={s.avatar} aria-hidden>{event.actor_name.slice(0, 1).toUpperCase()}</span>
<span className={s.content}><strong>{event.actor_name}</strong><span>{t(`social.kind_${event.kind}`)}</span>
<time dateTime={event.created_at} title={date.toLocaleString(i18n.language)}>{date.toLocaleString(i18n.language, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })}</time>
+1 -1
View File
@@ -86,7 +86,7 @@ export function useSocialProfileMenu() {
return {
items: [
{ label: t(currentVisibility === 'nobody' ? 'social.status_hidden' : 'social.privacy_settings'), icon: currentVisibility === 'nobody' ? visibilityOffIcon : shieldIcon, onSelect: () => setDialog('privacy') },
{ label: `${t('social.notifications')}${inbox.data?.unread ? ` ${inbox.data.unread}` : ''}`, icon: inboxIcon, onSelect: () => setDialog('notifications') },
{ label: t('social.notifications'), badge: inbox.data?.unread, icon: inboxIcon, onSelect: () => setDialog('notifications') },
],
dialogs: <>
{dialog === 'privacy' && <Dialog title={t('social.privacy_settings')} onClose={closeDialog} className={s.preferencesDialog}>
+15
View File
@@ -420,6 +420,21 @@
background: var(--hover);
}
.menuBadge {
margin-left: auto;
min-width: 20px;
height: 20px;
padding: 0 6px;
border-radius: 10px;
background: var(--accent-fill);
color: var(--on-accent, #fff);
font-size: 11px;
font-weight: 600;
line-height: 20px;
text-align: center;
font-variant-numeric: tabular-nums;
}
.menuDanger {
color: var(--danger);
}
+2 -1
View File
@@ -204,7 +204,7 @@ export function Dialog({
);
}
export type MenuItem = { label: string; icon?: string; danger?: boolean; onSelect: () => void };
export type MenuItem = { label: string; icon?: string; danger?: boolean; badge?: number; onSelect: () => void };
/** Выпадающее меню: открывается кнопкой-триггером, закрывается кликом снаружи и Esc. */
export function Menu({
@@ -268,6 +268,7 @@ export function Menu({
>
{it.icon && <Icon src={it.icon} size={18} />}
{it.label}
{it.badge ? <span className={s.menuBadge}>{it.badge > 99 ? '99+' : it.badge}</span> : null}
</button>
))}
</div>