SHA256
Каналы: типы 0/1/100/200, CreateChannel v3, state для chat200, новые API и деплой на prod
This commit is contained in:
@@ -8,6 +8,12 @@ const ITEMS = [
|
||||
{ pageId: 'notifications-view', label: 'Уведомления', icon: '🔔' },
|
||||
{ pageId: 'profile-view', label: 'Профиль', icon: '👤' },
|
||||
];
|
||||
const CHANNEL_HOLD_MS = 260;
|
||||
const CHANNEL_MODES = Object.freeze([
|
||||
{ key: 'feed', label: 'Каналы' },
|
||||
{ key: 'dialogs', label: 'Чаты' },
|
||||
{ key: 'my', label: 'Мои' },
|
||||
]);
|
||||
|
||||
function getTotalUnreadMessages() {
|
||||
const chats = Object.values(state.chats || {});
|
||||
@@ -54,9 +60,99 @@ export function renderToolbar(currentPageId, navigate) {
|
||||
badge.setAttribute('aria-label', `Непрочитанных сообщений: ${badge.textContent}`);
|
||||
btn.append(badge);
|
||||
}
|
||||
btn.addEventListener('click', () => navigate(item.pageId));
|
||||
if (item.pageId === 'channels-list') {
|
||||
installChannelsHoldSwitcher(btn, navigate);
|
||||
} else {
|
||||
btn.addEventListener('click', () => navigate(item.pageId));
|
||||
}
|
||||
root.append(btn);
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
function installChannelsHoldSwitcher(button, navigate) {
|
||||
let holdTimer = 0;
|
||||
let pressed = false;
|
||||
let holdActive = false;
|
||||
let overlay = null;
|
||||
let selectedMode = 'dialogs';
|
||||
|
||||
const clearTimer = () => {
|
||||
if (holdTimer) {
|
||||
window.clearTimeout(holdTimer);
|
||||
holdTimer = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const closeOverlay = () => {
|
||||
if (overlay) overlay.remove();
|
||||
overlay = null;
|
||||
holdActive = false;
|
||||
};
|
||||
|
||||
const setSelectedModeByX = (clientX) => {
|
||||
if (!overlay) return;
|
||||
const rect = overlay.getBoundingClientRect();
|
||||
const part = rect.width / 3;
|
||||
const localX = Math.max(0, Math.min(rect.width - 1, clientX - rect.left));
|
||||
const index = Math.max(0, Math.min(2, Math.floor(localX / Math.max(1, part))));
|
||||
selectedMode = CHANNEL_MODES[index].key;
|
||||
const buttons = overlay.querySelectorAll('.toolbar-channels-hold-item');
|
||||
buttons.forEach((el, idx) => {
|
||||
el.classList.toggle('is-active', idx === index);
|
||||
});
|
||||
};
|
||||
|
||||
const openOverlay = () => {
|
||||
const rect = button.getBoundingClientRect();
|
||||
overlay = document.createElement('div');
|
||||
overlay.className = 'toolbar-channels-hold-overlay';
|
||||
overlay.innerHTML = CHANNEL_MODES.map((mode) => (
|
||||
`<button type="button" class="toolbar-channels-hold-item${mode.key === selectedMode ? ' is-active' : ''}" data-mode="${mode.key}">${mode.label}</button>`
|
||||
)).join('');
|
||||
overlay.style.left = `${Math.round(rect.left + rect.width / 2)}px`;
|
||||
overlay.style.top = `${Math.round(rect.top - 12)}px`;
|
||||
document.body.append(overlay);
|
||||
holdActive = true;
|
||||
};
|
||||
|
||||
button.addEventListener('pointerdown', (event) => {
|
||||
pressed = true;
|
||||
holdActive = false;
|
||||
selectedMode = 'dialogs';
|
||||
clearTimer();
|
||||
holdTimer = window.setTimeout(() => {
|
||||
if (!pressed) return;
|
||||
openOverlay();
|
||||
setSelectedModeByX(event.clientX);
|
||||
}, CHANNEL_HOLD_MS);
|
||||
});
|
||||
|
||||
button.addEventListener('pointermove', (event) => {
|
||||
if (holdActive) setSelectedModeByX(event.clientX);
|
||||
});
|
||||
|
||||
button.addEventListener('pointerup', () => {
|
||||
clearTimer();
|
||||
const wasHold = holdActive;
|
||||
const mode = selectedMode;
|
||||
pressed = false;
|
||||
closeOverlay();
|
||||
if (wasHold) {
|
||||
navigate(`channels-list/${mode}`);
|
||||
return;
|
||||
}
|
||||
navigate('channels-list/dialogs');
|
||||
});
|
||||
|
||||
button.addEventListener('pointercancel', () => {
|
||||
clearTimer();
|
||||
pressed = false;
|
||||
closeOverlay();
|
||||
});
|
||||
|
||||
button.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user