Доработать UI уведомлений

This commit is contained in:
2026-08-21 14:06:19 +03:00
parent 23bdadab56
commit 19362b950a
7 changed files with 754 additions and 42 deletions
+82 -14
View File
@@ -1,4 +1,4 @@
import { profile } from '../mock-data.js';
import { profile } from '../mock-data.js';
import { state } from '../state.js';
import {
PROFILE_GENDER_FEMALE,
@@ -101,22 +101,90 @@ export function render({ navigate, chrome }) {
const topbar = document.createElement('header');
topbar.className = 'page-header app-topbar-shell app-topbar-shell--profile';
topbar.innerHTML = `
<div class="header-actions profile-top-actions">
<button class="ghost-btn profile-top-action-btn profile-top-icon-btn" type="button" data-top-action="profile" aria-label="Редактировать профиль" title="Редактировать профиль">
<img src="/assets/profile-icon-profile.svg" alt="" aria-hidden="true" />
</button>
<button class="ghost-btn profile-top-action-btn profile-top-icon-btn" type="button" data-top-action="wallet" aria-label="Кошелёк" title="Кошелёк">
<img src="/assets/profile-icon-wallet.svg" alt="" aria-hidden="true" />
</button>
<button class="ghost-btn profile-top-action-btn profile-top-icon-btn" type="button" data-top-action="settings" aria-label="Настройки" title="Настройки">
<img src="/assets/profile-icon-settings.svg" alt="" aria-hidden="true" />
<div class="header-actions profile-head-menu-wrap dm-head-menu-wrap">
<button type="button" class="dm-head-menu-btn profile-head-menu-btn" aria-label="Меню профиля" aria-haspopup="menu" aria-expanded="false">
<span class="dm-head-menu-dots" aria-hidden="true"><i></i><i></i><i></i></span>
</button>
</div>
`;
const topActions = topbar.querySelector('.profile-top-actions');
topActions.querySelector('[data-top-action="profile"]')?.addEventListener('click', () => navigate('profile-edit-view'));
topActions.querySelector('[data-top-action="wallet"]')?.addEventListener('click', () => navigate('wallet-view'));
topActions.querySelector('[data-top-action="settings"]')?.addEventListener('click', () => navigate('settings-view'));
const profileMenuWrap = topbar.querySelector('.profile-head-menu-wrap');
const profileMenuButton = topbar.querySelector('.profile-head-menu-btn');
let profileMenuPortal = null;
const closeProfileMenu = () => {
profileMenuPortal?.remove();
profileMenuPortal = null;
profileMenuButton?.setAttribute('aria-expanded', 'false');
profileMenuWrap?.classList.remove('is-open');
};
const positionProfileMenu = () => {
if (!profileMenuPortal || !profileMenuButton) return;
const rect = profileMenuButton.getBoundingClientRect();
const margin = 10;
const menuWidth = profileMenuPortal.offsetWidth || 224;
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, rect.right - menuWidth));
profileMenuPortal.style.left = `${Math.round(left)}px`;
profileMenuPortal.style.top = `${Math.round(rect.bottom + 7)}px`;
};
const openProfileMenu = () => {
if (!profileMenuButton || profileMenuPortal) return;
const portal = document.createElement('div');
portal.className = 'dm-head-menu dm-head-menu--portal profile-head-menu';
portal.setAttribute('role', 'menu');
portal.innerHTML = `
<button type="button" class="dm-head-menu-item profile-head-menu-item" role="menuitem" data-top-action="profile">
<img src="/assets/profile-icon-profile.svg" alt="" aria-hidden="true" />
<span>Редактировать профиль</span>
</button>
<button type="button" class="dm-head-menu-item profile-head-menu-item" role="menuitem" data-top-action="wallet">
<img src="/assets/profile-icon-wallet.svg" alt="" aria-hidden="true" />
<span>Кошелёк</span>
</button>
<button type="button" class="dm-head-menu-item profile-head-menu-item" role="menuitem" data-top-action="settings">
<img src="/assets/profile-icon-settings.svg" alt="" aria-hidden="true" />
<span>Настройки</span>
</button>
`;
const goTo = (route) => {
closeProfileMenu();
navigate(route);
};
portal.querySelector('[data-top-action="profile"]')?.addEventListener('click', () => goTo('profile-edit-view'));
portal.querySelector('[data-top-action="wallet"]')?.addEventListener('click', () => goTo('wallet-view'));
portal.querySelector('[data-top-action="settings"]')?.addEventListener('click', () => goTo('settings-view'));
portal.addEventListener('click', (event) => event.stopPropagation());
document.body.append(portal);
profileMenuPortal = portal;
profileMenuButton.setAttribute('aria-expanded', 'true');
profileMenuWrap?.classList.add('is-open');
positionProfileMenu();
};
profileMenuButton?.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
if (profileMenuPortal) closeProfileMenu();
else openProfileMenu();
});
document.addEventListener('click', (event) => {
if (!profileMenuPortal) return;
if (profileMenuPortal.contains(event.target) || profileMenuButton?.contains(event.target)) return;
closeProfileMenu();
});
document.addEventListener('keydown', (event) => {
if (event.key !== 'Escape' || !profileMenuPortal) return;
closeProfileMenu();
profileMenuButton?.focus();
});
window.addEventListener('resize', positionProfileMenu, { passive: true });
window.addEventListener('scroll', positionProfileMenu, { passive: true, capture: true });
chrome?.setTopbar(topbar);
const card = document.createElement('div');