SHA256
Compare commits
2
Commits
ui-artem
...
f0b8fac598
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
f0b8fac598 | ||
|
|
3ae9d9175f |
@@ -1,3 +1,5 @@
|
||||
import org.bouncycastle.util.Properties
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'application'
|
||||
|
||||
@@ -952,6 +952,9 @@ function closeTopChannelsMenu(listState) {
|
||||
listState.topMenuCleanup();
|
||||
}
|
||||
listState.topMenuCleanup = null;
|
||||
listState.topMenuAnchor?.setAttribute('aria-expanded', 'false');
|
||||
listState.topMenuAnchor?.classList.remove('menu-open-pressed');
|
||||
listState.topMenuAnchor = null;
|
||||
const root = document.getElementById('modal-root');
|
||||
if (root) {
|
||||
const overlay = root.querySelector(`#${TOP_MENU_OVERLAY_ID}`);
|
||||
@@ -1002,9 +1005,6 @@ function openTopChannelsMenu({
|
||||
if (item.divider) {
|
||||
const divider = document.createElement('div');
|
||||
divider.className = 'channel-menu-divider';
|
||||
divider.style.height = '1px';
|
||||
divider.style.background = 'rgba(255,255,255,0.08)';
|
||||
divider.style.margin = '6px 0';
|
||||
menu.append(divider);
|
||||
return;
|
||||
}
|
||||
@@ -1021,6 +1021,9 @@ function openTopChannelsMenu({
|
||||
|
||||
overlay.append(menu);
|
||||
root.append(overlay);
|
||||
anchorEl.setAttribute('aria-expanded', 'true');
|
||||
anchorEl.classList.add('menu-open-pressed');
|
||||
listState.topMenuAnchor = anchorEl;
|
||||
|
||||
const onOverlayClick = (event) => {
|
||||
if (event.target === overlay) closeTopChannelsMenu(listState);
|
||||
@@ -1354,6 +1357,7 @@ export function render({ navigate, route, chrome }) {
|
||||
const listState = {
|
||||
openMenuId: null,
|
||||
topMenuCleanup: null,
|
||||
topMenuAnchor: null,
|
||||
notificationsState,
|
||||
revealedCounters: new Set(),
|
||||
channels: [],
|
||||
@@ -1393,11 +1397,16 @@ export function render({ navigate, route, chrome }) {
|
||||
topMenuBtn.type = 'button';
|
||||
topMenuBtn.className = 'icon-btn channels-top-more-btn';
|
||||
topMenuBtn.setAttribute('aria-label', 'Ещё действия');
|
||||
topMenuBtn.setAttribute('aria-haspopup', 'menu');
|
||||
topMenuBtn.setAttribute('aria-expanded', 'false');
|
||||
topMenuBtn.title = 'Ещё действия';
|
||||
topMenuBtn.append(createOverflowDots());
|
||||
topMenuBtn.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
animatePress(topMenuBtn);
|
||||
if (listState.topMenuAnchor === topMenuBtn) {
|
||||
closeTopChannelsMenu(listState);
|
||||
return;
|
||||
}
|
||||
openTopChannelsMenu({
|
||||
listState,
|
||||
anchorEl: topMenuBtn,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { renderHeader } from '../components/header.js';
|
||||
import { createOverflowDots } from '../components/overflow-dots.js';
|
||||
import { authService, state } from '../state.js';
|
||||
import { makeProfileRoute } from '../services/shine-routes.js';
|
||||
import { makeProfileLinksRoute } from '../services/shine-routes.js';
|
||||
@@ -457,18 +458,113 @@ export function render({ navigate, route, chrome } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
let topMenuPortal = null;
|
||||
let topMenuBackdrop = null;
|
||||
let topMenuButton = null;
|
||||
|
||||
const closeTopMenu = () => {
|
||||
topMenuPortal?.remove();
|
||||
topMenuBackdrop?.remove();
|
||||
topMenuPortal = null;
|
||||
topMenuBackdrop = null;
|
||||
topMenuButton?.setAttribute('aria-expanded', 'false');
|
||||
topMenuButton?.classList.remove('menu-open-pressed');
|
||||
};
|
||||
|
||||
const positionTopMenu = () => {
|
||||
if (!topMenuPortal || !topMenuButton) return;
|
||||
const rect = topMenuButton.getBoundingClientRect();
|
||||
const margin = 10;
|
||||
const menuRect = topMenuPortal.getBoundingClientRect();
|
||||
const menuWidth = menuRect.width || topMenuPortal.offsetWidth || 190;
|
||||
const menuHeight = menuRect.height || topMenuPortal.offsetHeight || 56;
|
||||
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, rect.right - menuWidth));
|
||||
const below = rect.bottom + 7;
|
||||
const top = below + menuHeight <= window.innerHeight - margin
|
||||
? below
|
||||
: Math.max(margin, rect.top - menuHeight - 7);
|
||||
topMenuPortal.style.left = `${Math.round(left)}px`;
|
||||
topMenuPortal.style.top = `${Math.round(top)}px`;
|
||||
};
|
||||
|
||||
const openTopMenu = () => {
|
||||
if (!topMenuButton || topMenuPortal) return;
|
||||
const portal = document.createElement('div');
|
||||
portal.className = 'dm-head-menu dm-head-menu--portal network-head-menu';
|
||||
portal.setAttribute('role', 'menu');
|
||||
portal.innerHTML = `
|
||||
<button type="button" class="dm-head-menu-item network-head-menu-item" role="menuitem" data-action="find-person">
|
||||
<span>Найти человека</span>
|
||||
</button>
|
||||
`;
|
||||
portal.querySelector('[data-action="find-person"]')?.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
closeTopMenu();
|
||||
openSearchModal();
|
||||
});
|
||||
portal.addEventListener('click', (event) => event.stopPropagation());
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.className = 'ui-menu-dim-layer';
|
||||
backdrop.addEventListener('click', closeTopMenu);
|
||||
document.body.append(backdrop, portal);
|
||||
topMenuBackdrop = backdrop;
|
||||
topMenuPortal = portal;
|
||||
topMenuButton.setAttribute('aria-expanded', 'true');
|
||||
topMenuButton.classList.add('menu-open-pressed');
|
||||
positionTopMenu();
|
||||
requestAnimationFrame(positionTopMenu);
|
||||
};
|
||||
|
||||
const toggleTopMenu = (event) => {
|
||||
event?.preventDefault?.();
|
||||
event?.stopPropagation?.();
|
||||
if (topMenuPortal) closeTopMenu();
|
||||
else openTopMenu();
|
||||
};
|
||||
|
||||
const header = renderHeader({
|
||||
title: 'Связи',
|
||||
rightActions: [
|
||||
{ label: 'Найти', onClick: openSearchModal },
|
||||
{
|
||||
iconNode: createOverflowDots(),
|
||||
className: 'network-top-more-btn',
|
||||
title: 'Ещё действия',
|
||||
ariaLabel: 'Меню связей',
|
||||
onClick: toggleTopMenu,
|
||||
},
|
||||
],
|
||||
});
|
||||
// «Связи» используют тот же общий topbar, что и остальные страницы.
|
||||
// Отдельный класс нужен только для page-specific fade графа, не для геометрии header.
|
||||
header.classList.add('network-topbar');
|
||||
topMenuButton = header.querySelector('.network-top-more-btn');
|
||||
topMenuButton?.setAttribute('aria-haspopup', 'menu');
|
||||
topMenuButton?.setAttribute('aria-expanded', 'false');
|
||||
|
||||
const onTopMenuOutsideClick = (event) => {
|
||||
if (!topMenuPortal) return;
|
||||
if (topMenuPortal.contains(event.target) || topMenuButton?.contains(event.target)) return;
|
||||
closeTopMenu();
|
||||
};
|
||||
const onTopMenuKeydown = (event) => {
|
||||
if (event.key !== 'Escape' || !topMenuPortal) return;
|
||||
closeTopMenu();
|
||||
topMenuButton?.focus();
|
||||
};
|
||||
const onTopMenuViewportChange = () => positionTopMenu();
|
||||
document.addEventListener('click', onTopMenuOutsideClick);
|
||||
document.addEventListener('keydown', onTopMenuKeydown);
|
||||
window.addEventListener('resize', onTopMenuViewportChange, { passive: true });
|
||||
window.addEventListener('scroll', onTopMenuViewportChange, { passive: true, capture: true });
|
||||
|
||||
// Ресайз и перерисовку рёбер движок обрабатывает сам (window resize + ResizeObserver внутри).
|
||||
screen.cleanup = () => {
|
||||
closeTopMenu();
|
||||
document.removeEventListener('click', onTopMenuOutsideClick);
|
||||
document.removeEventListener('keydown', onTopMenuKeydown);
|
||||
window.removeEventListener('resize', onTopMenuViewportChange);
|
||||
window.removeEventListener('scroll', onTopMenuViewportChange, true);
|
||||
if (engine) engine.destroy();
|
||||
engine = null;
|
||||
appScreenEl?.classList.remove('network-scroll-lock');
|
||||
|
||||
@@ -34,8 +34,8 @@ body::before {
|
||||
--toolbar-height: 78px;
|
||||
--keyboard-offset: 0px;
|
||||
background: transparent;
|
||||
border-left: 1px solid rgba(211, 170, 86, 0.2);
|
||||
border-right: 1px solid rgba(211, 170, 86, 0.2);
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
box-shadow: var(--shadow);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user