SHA256
Обновить UI для меню и языка
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
client.version=1.7.5
|
client.version=1.7.6
|
||||||
server.version=1.6.2
|
server.version=1.6.2
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="32" cy="24.5" r="10.5" stroke="#F2F5FB" stroke-width="3"/>
|
<circle cx="32" cy="23.5" r="10.5" stroke="#65B7FF" stroke-width="3.2"/>
|
||||||
<path d="M15.5 48C17.8 38.9 24.2 34.5 32 34.5C39.8 34.5 46.2 38.9 48.5 48" stroke="#F2F5FB" stroke-width="3" stroke-linecap="round"/>
|
<path d="M14.5 49C17.1 39.2 23.9 34.5 32 34.5C40.1 34.5 46.9 39.2 49.5 49" stroke="#65B7FF" stroke-width="3.2" stroke-linecap="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 316 B |
@@ -1,4 +1,4 @@
|
|||||||
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M12 15.25A3.25 3.25 0 1 0 12 8.75a3.25 3.25 0 0 0 0 6.5Z" stroke="#F2F5FB" stroke-width="1.65"/>
|
<path d="M27.1 11.5h9.8l1.4 6.1c1.5.6 2.9 1.4 4.2 2.4l6-1.9 4.9 8.5-4.6 4.2c.1.8.2 1.6.2 2.4s-.1 1.6-.2 2.4l4.6 4.2-4.9 8.5-6-1.9c-1.3 1-2.7 1.8-4.2 2.4l-1.4 6.1h-9.8l-1.4-6.1c-1.5-.6-2.9-1.4-4.2-2.4l-6 1.9-4.9-8.5 4.6-4.2a16 16 0 0 1 0-4.8l-4.6-4.2 4.9-8.5 6 1.9c1.3-1 2.7-1.8 4.2-2.4l1.4-6.1Z" stroke="#65B7FF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M19.15 13.15c.04-.38.04-.77 0-1.15l1.55-1.2-1.75-3.02-1.82.74a7.4 7.4 0 0 0-1-.58L15.86 6h-3.5l-.27 1.94c-.35.16-.68.35-1 .58l-1.82-.74-1.75 3.02L9.07 12a6 6 0 0 0 0 1.15l-1.55 1.2 1.75 3.03 1.82-.75c.32.23.65.42 1 .58l.27 1.94h3.5l.27-1.94c.35-.16.68-.35 1-.58l1.82.75 1.75-3.03-1.55-1.2Z" stroke="#F2F5FB" stroke-width="1.55" stroke-linecap="round" stroke-linejoin="round"/>
|
<circle cx="32" cy="33.2" r="8.2" stroke="#65B7FF" stroke-width="3.2"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 599 B After Width: | Height: | Size: 558 B |
@@ -1,6 +1,5 @@
|
|||||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M13.5 24.5C13.5 20.9101 16.4101 18 20 18H41.5C45.0899 18 48 20.9101 48 24.5V26H23.5C21.0147 26 19 28.0147 19 30.5C19 32.9853 21.0147 35 23.5 35H48V39.5C48 43.0899 45.0899 46 41.5 46H20C16.4101 46 13.5 43.0899 13.5 39.5V24.5Z" stroke="#F2F5FB" stroke-width="3" stroke-linejoin="round"/>
|
<path d="M13 23.5C13 19.9 15.9 17 19.5 17H42C45.6 17 48.5 19.9 48.5 23.5V27H24C21.2 27 19 29.2 19 32C19 34.8 21.2 37 24 37H48.5V40.5C48.5 44.1 45.6 47 42 47H19.5C15.9 47 13 44.1 13 40.5V23.5Z" stroke="#65B7FF" stroke-width="3.2" stroke-linejoin="round"/>
|
||||||
<path d="M19 30.5C19 28.0147 21.0147 26 23.5 26H50.5V35H23.5C21.0147 35 19 32.9853 19 30.5Z" stroke="#F2F5FB" stroke-width="3" stroke-linejoin="round"/>
|
<path d="M19 32C19 29.2 21.2 27 24 27H51V37H24C21.2 37 19 34.8 19 32Z" stroke="#65B7FF" stroke-width="3.2" stroke-linejoin="round"/>
|
||||||
<circle cx="42.5" cy="30.5" r="2.4" fill="#F2F5FB"/>
|
<circle cx="42.5" cy="32" r="2.5" fill="#65B7FF"/>
|
||||||
<path d="M18.5 22H38" stroke="#F2F5FB" stroke-width="3" stroke-linecap="round" opacity="0.9"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 548 B |
+21
-2
@@ -229,9 +229,17 @@ window.__SHINE_BUILD_HASH__ = '20260826145335';
|
|||||||
document.getElementById(menuId)?.remove();
|
document.getElementById(menuId)?.remove();
|
||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
const dismissError = () => {
|
||||||
|
removeMenu();
|
||||||
|
try {
|
||||||
|
document.getElementById('boot-error-overlay')?.remove();
|
||||||
|
setState(null);
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
const openMenu = () => {
|
const openMenu = () => {
|
||||||
try {
|
try {
|
||||||
removeMenu();
|
removeMenu();
|
||||||
|
document.dispatchEvent(new CustomEvent('shine:dropdown-open', { detail: { owner: 'boot-error' } }));
|
||||||
const report = buildReport();
|
const report = buildReport();
|
||||||
const root = document.getElementById('modal-root') || document.body;
|
const root = document.getElementById('modal-root') || document.body;
|
||||||
const shell = document.createElement('div');
|
const shell = document.createElement('div');
|
||||||
@@ -246,7 +254,7 @@ window.__SHINE_BUILD_HASH__ = '20260826145335';
|
|||||||
<button type="button" class="secondary-btn" data-action="copy">Скопировать текст ошибки</button>
|
<button type="button" class="secondary-btn" data-action="copy">Скопировать текст ошибки</button>
|
||||||
<button type="button" class="secondary-btn" data-action="share">Отправить текст ошибки</button>
|
<button type="button" class="secondary-btn" data-action="share">Отправить текст ошибки</button>
|
||||||
<button type="button" class="secondary-btn" data-action="send"${typeof window.__SHINE_SEND_CLIENT_ERROR_TO_SERVER__ === 'function' ? '' : ' disabled'}>Отправить в лог на сервере</button>
|
<button type="button" class="secondary-btn" data-action="send"${typeof window.__SHINE_SEND_CLIENT_ERROR_TO_SERVER__ === 'function' ? '' : ' disabled'}>Отправить в лог на сервере</button>
|
||||||
<button type="button" class="ghost-btn" data-action="close">Закрыть</button>
|
<button type="button" class="secondary-btn" data-action="dismiss">Закрыть</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -308,7 +316,18 @@ window.__SHINE_BUILD_HASH__ = '20260826145335';
|
|||||||
close();
|
close();
|
||||||
});
|
});
|
||||||
|
|
||||||
shell.querySelector('[data-action="close"]')?.addEventListener('click', close);
|
shell.querySelector('[data-action="dismiss"]')?.addEventListener('click', () => {
|
||||||
|
close();
|
||||||
|
try {
|
||||||
|
document.getElementById('boot-error-overlay')?.remove();
|
||||||
|
setState(null);
|
||||||
|
} catch {}
|
||||||
|
});
|
||||||
|
const onPeerDropdownOpen = (event) => {
|
||||||
|
if (event?.detail?.owner === 'boot-error') return;
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
document.addEventListener('shine:dropdown-open', onPeerDropdownOpen, { once: true });
|
||||||
dialog?.focus?.();
|
dialog?.focus?.();
|
||||||
window.addEventListener('keydown', onKeyDown);
|
window.addEventListener('keydown', onKeyDown);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export function createDropdownMenu({
|
|||||||
minWidth = 210,
|
minWidth = 210,
|
||||||
offset = 7,
|
offset = 7,
|
||||||
align = 'right',
|
align = 'right',
|
||||||
|
leftShift = 0,
|
||||||
onOpen = null,
|
onOpen = null,
|
||||||
onClose = null,
|
onClose = null,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@@ -23,7 +24,8 @@ export function createDropdownMenu({
|
|||||||
const rect = anchorEl.getBoundingClientRect();
|
const rect = anchorEl.getBoundingClientRect();
|
||||||
const margin = 10;
|
const margin = 10;
|
||||||
const menuWidth = portal.offsetWidth || minWidth;
|
const menuWidth = portal.offsetWidth || minWidth;
|
||||||
const desiredLeft = align === 'left' ? rect.left : rect.right - menuWidth;
|
const baseLeft = align === 'left' ? rect.left : rect.right - menuWidth;
|
||||||
|
const desiredLeft = baseLeft - Number(leftShift || 0);
|
||||||
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, desiredLeft));
|
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, desiredLeft));
|
||||||
let top = rect.bottom + offset;
|
let top = rect.bottom + offset;
|
||||||
const menuHeight = portal.offsetHeight || 180;
|
const menuHeight = portal.offsetHeight || 180;
|
||||||
@@ -36,6 +38,7 @@ export function createDropdownMenu({
|
|||||||
|
|
||||||
const open = () => {
|
const open = () => {
|
||||||
if (!anchorEl || portal) return;
|
if (!anchorEl || portal) return;
|
||||||
|
document.dispatchEvent(new CustomEvent('shine:dropdown-open', { detail: { owner: anchorEl } }));
|
||||||
const menu = document.createElement('div');
|
const menu = document.createElement('div');
|
||||||
menu.className = `dm-head-menu dm-head-menu--portal shared-dropdown-menu ${className}`.trim();
|
menu.className = `dm-head-menu dm-head-menu--portal shared-dropdown-menu ${className}`.trim();
|
||||||
menu.setAttribute('role', 'menu');
|
menu.setAttribute('role', 'menu');
|
||||||
@@ -99,6 +102,10 @@ export function createDropdownMenu({
|
|||||||
if (portal.contains(event.target) || anchorEl?.contains(event.target)) return;
|
if (portal.contains(event.target) || anchorEl?.contains(event.target)) return;
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
const onPeerDropdownOpen = (event) => {
|
||||||
|
if (!portal || event?.detail?.owner === anchorEl) return;
|
||||||
|
close();
|
||||||
|
};
|
||||||
const onKeydown = (event) => {
|
const onKeydown = (event) => {
|
||||||
if (event.key !== 'Escape' || !portal) return;
|
if (event.key !== 'Escape' || !portal) return;
|
||||||
close();
|
close();
|
||||||
@@ -110,6 +117,7 @@ export function createDropdownMenu({
|
|||||||
anchorEl?.addEventListener('click', onAnchorClick);
|
anchorEl?.addEventListener('click', onAnchorClick);
|
||||||
document.addEventListener('click', onOutsideClick);
|
document.addEventListener('click', onOutsideClick);
|
||||||
document.addEventListener('keydown', onKeydown);
|
document.addEventListener('keydown', onKeydown);
|
||||||
|
document.addEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
window.addEventListener('resize', position, { passive: true });
|
window.addEventListener('resize', position, { passive: true });
|
||||||
window.addEventListener('scroll', position, { passive: true, capture: true });
|
window.addEventListener('scroll', position, { passive: true, capture: true });
|
||||||
|
|
||||||
@@ -123,6 +131,7 @@ export function createDropdownMenu({
|
|||||||
anchorEl?.removeEventListener('click', onAnchorClick);
|
anchorEl?.removeEventListener('click', onAnchorClick);
|
||||||
document.removeEventListener('click', onOutsideClick);
|
document.removeEventListener('click', onOutsideClick);
|
||||||
document.removeEventListener('keydown', onKeydown);
|
document.removeEventListener('keydown', onKeydown);
|
||||||
|
document.removeEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
window.removeEventListener('resize', position);
|
window.removeEventListener('resize', position);
|
||||||
window.removeEventListener('scroll', position, true);
|
window.removeEventListener('scroll', position, true);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function renderToolbar(currentPageId, navigate) {
|
|||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
} else if (isNetwork) {
|
} else if (isNetwork) {
|
||||||
btn.innerHTML = iconHtml(item);
|
btn.innerHTML = `${iconHtml(item)}<span>${item.label}</span>`;
|
||||||
btn.setAttribute('aria-label', item.label);
|
btn.setAttribute('aria-label', item.label);
|
||||||
btn.title = item.label;
|
btn.title = item.label;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -966,6 +966,7 @@ function openTopChannelsMenu({
|
|||||||
onFindChannel,
|
onFindChannel,
|
||||||
}) {
|
}) {
|
||||||
closeTopChannelsMenu(listState);
|
closeTopChannelsMenu(listState);
|
||||||
|
document.dispatchEvent(new CustomEvent('shine:dropdown-open', { detail: { owner: anchorEl } }));
|
||||||
const root = document.getElementById('modal-root');
|
const root = document.getElementById('modal-root');
|
||||||
if (!root || !anchorEl) return;
|
if (!root || !anchorEl) return;
|
||||||
|
|
||||||
@@ -975,7 +976,9 @@ function openTopChannelsMenu({
|
|||||||
left = Math.max(12, Math.min(left, window.innerWidth - menuWidth - 12));
|
left = Math.max(12, Math.min(left, window.innerWidth - menuWidth - 12));
|
||||||
|
|
||||||
const estimatedHeight = 250;
|
const estimatedHeight = 250;
|
||||||
let top = rect.bottom + 8;
|
const titleAnchor = document.querySelector('.channels-filter-title');
|
||||||
|
const titleRect = titleAnchor?.getBoundingClientRect?.();
|
||||||
|
let top = (titleRect?.bottom || rect.bottom) + 7;
|
||||||
if (top + estimatedHeight > window.innerHeight - 10) {
|
if (top + estimatedHeight > window.innerHeight - 10) {
|
||||||
top = Math.max(12, rect.top - estimatedHeight - 8);
|
top = Math.max(12, rect.top - estimatedHeight - 8);
|
||||||
}
|
}
|
||||||
@@ -1022,13 +1025,19 @@ function openTopChannelsMenu({
|
|||||||
const onOverlayClick = (event) => {
|
const onOverlayClick = (event) => {
|
||||||
if (event.target === overlay) closeTopChannelsMenu(listState);
|
if (event.target === overlay) closeTopChannelsMenu(listState);
|
||||||
};
|
};
|
||||||
|
const onPeerDropdownOpen = (event) => {
|
||||||
|
if (event?.detail?.owner === anchorEl) return;
|
||||||
|
closeTopChannelsMenu(listState);
|
||||||
|
};
|
||||||
const onWindowResize = () => closeTopChannelsMenu(listState);
|
const onWindowResize = () => closeTopChannelsMenu(listState);
|
||||||
|
|
||||||
overlay.addEventListener('click', onOverlayClick);
|
overlay.addEventListener('click', onOverlayClick);
|
||||||
window.addEventListener('resize', onWindowResize);
|
window.addEventListener('resize', onWindowResize);
|
||||||
|
document.addEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
listState.topMenuCleanup = () => {
|
listState.topMenuCleanup = () => {
|
||||||
overlay.removeEventListener('click', onOverlayClick);
|
overlay.removeEventListener('click', onOverlayClick);
|
||||||
window.removeEventListener('resize', onWindowResize);
|
window.removeEventListener('resize', onWindowResize);
|
||||||
|
document.removeEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1368,6 +1377,7 @@ export function render({ navigate, route, chrome }) {
|
|||||||
const channelsFilterMenu = createDropdownMenu({
|
const channelsFilterMenu = createDropdownMenu({
|
||||||
anchorEl: topTitle,
|
anchorEl: topTitle,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
leftShift: 72,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Все каналы', iconHtml: channelMenuIcon('all'), action: () => navigate(buildChannelsViewRoute(CHANNELS_VIEW_ALL)) },
|
{ label: 'Все каналы', iconHtml: channelMenuIcon('all'), action: () => navigate(buildChannelsViewRoute(CHANNELS_VIEW_ALL)) },
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function render({ navigate }) {
|
|||||||
controls.className = 'row wrap-row';
|
controls.className = 'row wrap-row';
|
||||||
|
|
||||||
const checkButton = document.createElement('button');
|
const checkButton = document.createElement('button');
|
||||||
checkButton.className = 'ghost-btn server-check-btn';
|
checkButton.className = 'shine-btn shine-btn--settings server-check-btn';
|
||||||
checkButton.type = 'button';
|
checkButton.type = 'button';
|
||||||
checkButton.textContent = 'Проверить';
|
checkButton.textContent = 'Проверить';
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ export function render({ navigate }) {
|
|||||||
|
|
||||||
if (isLocalDemoAvailable()) {
|
if (isLocalDemoAvailable()) {
|
||||||
const localDemoButton = document.createElement('button');
|
const localDemoButton = document.createElement('button');
|
||||||
localDemoButton.className = 'ghost-btn preauth-local-demo-btn';
|
localDemoButton.className = 'shine-btn shine-btn--settings preauth-local-demo-btn';
|
||||||
localDemoButton.type = 'button';
|
localDemoButton.type = 'button';
|
||||||
localDemoButton.textContent = 'Открыть локальный тестовый режим';
|
localDemoButton.textContent = 'Открыть локальный тестовый режим';
|
||||||
localDemoButton.addEventListener('click', () => {
|
localDemoButton.addEventListener('click', () => {
|
||||||
@@ -143,7 +143,7 @@ export function render({ navigate }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const serverUiButton = document.createElement('button');
|
const serverUiButton = document.createElement('button');
|
||||||
serverUiButton.className = 'ghost-btn';
|
serverUiButton.className = 'shine-btn shine-btn--settings';
|
||||||
serverUiButton.type = 'button';
|
serverUiButton.type = 'button';
|
||||||
serverUiButton.textContent = 'Настроить свой сервер';
|
serverUiButton.textContent = 'Настроить свой сервер';
|
||||||
serverUiButton.addEventListener('click', () => {
|
serverUiButton.addEventListener('click', () => {
|
||||||
@@ -152,13 +152,13 @@ export function render({ navigate }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const cancelButton = document.createElement('button');
|
const cancelButton = document.createElement('button');
|
||||||
cancelButton.className = 'ghost-btn';
|
cancelButton.className = 'shine-btn shine-btn--settings';
|
||||||
cancelButton.type = 'button';
|
cancelButton.type = 'button';
|
||||||
cancelButton.textContent = 'Отмена';
|
cancelButton.textContent = 'Отмена';
|
||||||
cancelButton.addEventListener('click', () => navigate('start-view'));
|
cancelButton.addEventListener('click', () => navigate('start-view'));
|
||||||
|
|
||||||
const saveButton = document.createElement('button');
|
const saveButton = document.createElement('button');
|
||||||
saveButton.className = 'primary-btn';
|
saveButton.className = 'shine-btn shine-btn--primary';
|
||||||
saveButton.type = 'button';
|
saveButton.type = 'button';
|
||||||
saveButton.textContent = 'Сохранить';
|
saveButton.textContent = 'Сохранить';
|
||||||
saveButton.addEventListener('click', async () => {
|
saveButton.addEventListener('click', async () => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export function render({ navigate }) {
|
|||||||
const screen = document.createElement('section');
|
const screen = document.createElement('section');
|
||||||
screen.className = 'stack language-screen';
|
screen.className = 'stack language-screen';
|
||||||
const returnPage = resolveReturnPage();
|
const returnPage = resolveReturnPage();
|
||||||
|
let pendingLanguage = state.entrySettings.language === 'en' ? 'en' : 'ru';
|
||||||
|
|
||||||
screen.append(
|
screen.append(
|
||||||
renderHeader({
|
renderHeader({
|
||||||
@@ -27,31 +28,42 @@ export function render({ navigate }) {
|
|||||||
card.className = 'card stack language-choice-card';
|
card.className = 'card stack language-choice-card';
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<p class="meta-muted language-choice-hint">Выберите язык интерфейса</p>
|
<p class="meta-muted language-choice-hint">Выберите язык интерфейса</p>
|
||||||
<div class="language-choice-grid" role="radiogroup" aria-label="Язык интерфейса">
|
<div class="language-segmented-control" role="radiogroup" aria-label="Язык интерфейса">
|
||||||
<button class="language-choice-option${state.entrySettings.language === 'ru' ? ' is-selected' : ''}" type="button" data-language="ru" role="radio" aria-checked="${state.entrySettings.language === 'ru'}">
|
<button class="language-segment${pendingLanguage === 'ru' ? ' is-selected' : ''}" type="button" data-language="ru" role="radio" aria-checked="${pendingLanguage === 'ru'}">Русский</button>
|
||||||
<span class="language-choice-name">Русский</span>
|
<button class="language-segment${pendingLanguage === 'en' ? ' is-selected' : ''}" type="button" data-language="en" role="radio" aria-checked="${pendingLanguage === 'en'}">English</button>
|
||||||
<span class="language-choice-code">RU</span>
|
<span class="language-segmented-thumb" aria-hidden="true"></span>
|
||||||
</button>
|
</div>
|
||||||
<button class="language-choice-option${state.entrySettings.language === 'en' ? ' is-selected' : ''}" type="button" data-language="en" role="radio" aria-checked="${state.entrySettings.language === 'en'}">
|
<div class="language-choice-actions">
|
||||||
<span class="language-choice-name">English</span>
|
<button class="shine-btn shine-btn--settings" type="button" data-action="cancel">Отмена</button>
|
||||||
<span class="language-choice-code">EN</span>
|
<button class="shine-btn shine-btn--primary" type="button" data-action="ok">OK</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const syncSelection = () => {
|
||||||
|
card.dataset.language = pendingLanguage;
|
||||||
|
card.querySelectorAll('[data-language]').forEach((item) => {
|
||||||
|
const selected = item.dataset.language === pendingLanguage;
|
||||||
|
item.classList.toggle('is-selected', selected);
|
||||||
|
item.setAttribute('aria-checked', String(selected));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
syncSelection();
|
||||||
|
|
||||||
card.querySelectorAll('[data-language]').forEach((button) => {
|
card.querySelectorAll('[data-language]').forEach((button) => {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
const language = String(button.dataset.language || 'ru');
|
pendingLanguage = button.dataset.language === 'en' ? 'en' : 'ru';
|
||||||
saveEntryLanguage(language);
|
syncSelection();
|
||||||
card.querySelectorAll('[data-language]').forEach((item) => {
|
|
||||||
const selected = item === button;
|
|
||||||
item.classList.toggle('is-selected', selected);
|
|
||||||
item.setAttribute('aria-checked', String(selected));
|
|
||||||
});
|
|
||||||
sessionStorage.removeItem('shine-language-return-page');
|
|
||||||
navigate(returnPage);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
card.querySelector('[data-action="cancel"]')?.addEventListener('click', () => {
|
||||||
|
sessionStorage.removeItem('shine-language-return-page');
|
||||||
|
navigate(returnPage);
|
||||||
|
});
|
||||||
|
card.querySelector('[data-action="ok"]')?.addEventListener('click', () => {
|
||||||
|
saveEntryLanguage(pendingLanguage);
|
||||||
|
sessionStorage.removeItem('shine-language-return-page');
|
||||||
|
navigate(returnPage);
|
||||||
|
});
|
||||||
|
|
||||||
screen.append(card);
|
screen.append(card);
|
||||||
return screen;
|
return screen;
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ export function render({ navigate, chrome }) {
|
|||||||
const chatFilterMenu = createDropdownMenu({
|
const chatFilterMenu = createDropdownMenu({
|
||||||
anchorEl: filterTitle,
|
anchorEl: filterTitle,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
leftShift: 72,
|
||||||
minWidth: 225,
|
minWidth: 225,
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Все чаты', action: () => { currentChatFilter = 'all'; filterTitle.textContent = filterLabels.all; reloadForFilter(); } },
|
{ label: 'Все чаты', action: () => { currentChatFilter = 'all'; filterTitle.textContent = filterLabels.all; reloadForFilter(); } },
|
||||||
@@ -259,11 +260,13 @@ export function render({ navigate, chrome }) {
|
|||||||
const menuWidth = menuPortal.offsetWidth || 206;
|
const menuWidth = menuPortal.offsetWidth || 206;
|
||||||
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, rect.right - menuWidth));
|
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, rect.right - menuWidth));
|
||||||
menuPortal.style.left = `${Math.round(left)}px`;
|
menuPortal.style.left = `${Math.round(left)}px`;
|
||||||
menuPortal.style.top = `${Math.round(rect.bottom + 7)}px`;
|
const titleRect = filterTitle?.getBoundingClientRect?.();
|
||||||
|
menuPortal.style.top = `${Math.round((titleRect?.bottom || rect.bottom) + 7)}px`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const openHeadMenu = () => {
|
const openHeadMenu = () => {
|
||||||
if (!menuButton || menuPortal) return;
|
if (!menuButton || menuPortal) return;
|
||||||
|
document.dispatchEvent(new CustomEvent('shine:dropdown-open', { detail: { owner: menuButton } }));
|
||||||
const portal = document.createElement('div');
|
const portal = document.createElement('div');
|
||||||
portal.className = 'dm-head-menu dm-head-menu--portal';
|
portal.className = 'dm-head-menu dm-head-menu--portal';
|
||||||
portal.setAttribute('role', 'menu');
|
portal.setAttribute('role', 'menu');
|
||||||
@@ -304,6 +307,10 @@ export function render({ navigate, chrome }) {
|
|||||||
if (menuPortal.contains(event.target) || menuButton?.contains(event.target)) return;
|
if (menuPortal.contains(event.target) || menuButton?.contains(event.target)) return;
|
||||||
closeHeadMenu();
|
closeHeadMenu();
|
||||||
};
|
};
|
||||||
|
const onPeerDropdownOpen = (event) => {
|
||||||
|
if (!menuPortal || event?.detail?.owner === menuButton) return;
|
||||||
|
closeHeadMenu();
|
||||||
|
};
|
||||||
const onMenuKeydown = (event) => {
|
const onMenuKeydown = (event) => {
|
||||||
if (event.key !== 'Escape' || !menuPortal) return;
|
if (event.key !== 'Escape' || !menuPortal) return;
|
||||||
closeHeadMenu();
|
closeHeadMenu();
|
||||||
@@ -312,6 +319,7 @@ export function render({ navigate, chrome }) {
|
|||||||
const onMenuViewportChange = () => positionHeadMenu();
|
const onMenuViewportChange = () => positionHeadMenu();
|
||||||
document.addEventListener('click', onOutsideClick);
|
document.addEventListener('click', onOutsideClick);
|
||||||
document.addEventListener('keydown', onMenuKeydown);
|
document.addEventListener('keydown', onMenuKeydown);
|
||||||
|
document.addEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
window.addEventListener('resize', onMenuViewportChange, { passive: true });
|
window.addEventListener('resize', onMenuViewportChange, { passive: true });
|
||||||
window.addEventListener('scroll', onMenuViewportChange, { passive: true, capture: true });
|
window.addEventListener('scroll', onMenuViewportChange, { passive: true, capture: true });
|
||||||
|
|
||||||
@@ -487,6 +495,7 @@ function renderRow(item) {
|
|||||||
chatFilterMenu.destroy();
|
chatFilterMenu.destroy();
|
||||||
document.removeEventListener('click', onOutsideClick);
|
document.removeEventListener('click', onOutsideClick);
|
||||||
document.removeEventListener('keydown', onMenuKeydown);
|
document.removeEventListener('keydown', onMenuKeydown);
|
||||||
|
document.removeEventListener('shine:dropdown-open', onPeerDropdownOpen);
|
||||||
window.removeEventListener('resize', onMenuViewportChange);
|
window.removeEventListener('resize', onMenuViewportChange);
|
||||||
window.removeEventListener('scroll', onMenuViewportChange, true);
|
window.removeEventListener('scroll', onMenuViewportChange, true);
|
||||||
};
|
};
|
||||||
|
|||||||
+185
-14
@@ -10040,10 +10040,11 @@ body.chat-topbar-overlay .composer-slot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profile-head-menu .shared-dropdown-menu__item > img {
|
.profile-head-menu .shared-dropdown-menu__item > img {
|
||||||
width: 23px;
|
width: 27px;
|
||||||
height: 23px;
|
height: 27px;
|
||||||
min-width: 23px;
|
min-width: 27px;
|
||||||
flex-basis: 23px;
|
flex-basis: 27px;
|
||||||
|
filter: drop-shadow(0 0 6px rgba(101, 183, 255, 0.36));
|
||||||
}
|
}
|
||||||
|
|
||||||
.dm-head-filter-title,
|
.dm-head-filter-title,
|
||||||
@@ -10235,20 +10236,20 @@ body.chat-topbar-overlay .composer-slot {
|
|||||||
|
|
||||||
.channels-screen--list .channel-row {
|
.channels-screen--list .channel-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100% - 8px);
|
width: calc(100% - 2px);
|
||||||
grid-template-columns: 58px minmax(0, 1fr);
|
grid-template-columns: 46px minmax(0, 1fr);
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
min-height: 64px;
|
min-height: 44px;
|
||||||
margin: 2px 4px;
|
margin: 1px 1px;
|
||||||
padding: 5px 8px 5px 5px;
|
padding: 3px 6px 3px 3px;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channels-screen--list .channel-row .avatar {
|
.channels-screen--list .channel-row .avatar {
|
||||||
width: 52px;
|
width: 42px;
|
||||||
height: 52px;
|
height: 42px;
|
||||||
min-width: 52px;
|
min-width: 42px;
|
||||||
min-height: 52px;
|
min-height: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channels-screen--list .channel-row-main {
|
.channels-screen--list .channel-row-main {
|
||||||
@@ -10314,3 +10315,173 @@ body.chat-topbar-overlay .composer-slot {
|
|||||||
linear-gradient(180deg, rgba(255,255,255,.075), transparent 30%),
|
linear-gradient(180deg, rgba(255,255,255,.075), transparent 30%),
|
||||||
rgba(10, 24, 52, .68) !important;
|
rgba(10, 24, 52, .68) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ===== UX refinements 2026-08-29 ===== */
|
||||||
|
/* Start: larger breathing room between brand and actions. */
|
||||||
|
.auth-screen--welcome .auth-brand {
|
||||||
|
margin-bottom: clamp(34px, 6vh, 58px) !important;
|
||||||
|
}
|
||||||
|
.auth-screen--welcome .shine-actions {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language selector: actual two-position switch with explicit confirmation. */
|
||||||
|
.language-segmented-control {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0;
|
||||||
|
padding: 4px;
|
||||||
|
min-height: 58px;
|
||||||
|
border: 1px solid rgba(190, 210, 238, .18);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(12, 22, 40, .72);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.language-segmented-thumb {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
top: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
left: 4px;
|
||||||
|
width: calc(50% - 4px);
|
||||||
|
border: 1px solid rgba(99, 190, 255, .52);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: linear-gradient(180deg, rgba(76, 166, 255, .28), rgba(30, 105, 204, .20));
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255,255,255,.10), 0 0 18px rgba(63,160,255,.14);
|
||||||
|
transition: transform 180ms ease;
|
||||||
|
}
|
||||||
|
.language-choice-card[data-language="en"] .language-segmented-thumb { transform: translateX(100%); }
|
||||||
|
.language-segment {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
min-height: 50px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
color: rgba(231,239,255,.64);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
.language-segment.is-selected { color: #eef8ff; }
|
||||||
|
.language-choice-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.language-choice-actions .shine-btn { height: 50px; }
|
||||||
|
|
||||||
|
/* Entry settings actions use the existing Start button visual language without huge width side effects. */
|
||||||
|
.screen-content.preauth-flow .server-check-btn.shine-btn {
|
||||||
|
width: auto;
|
||||||
|
height: 44px;
|
||||||
|
min-height: 44px;
|
||||||
|
padding-inline: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.screen-content.preauth-flow .auth-footer-actions .shine-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Channels: much wider, substantially shorter rows. */
|
||||||
|
.channels-screen--list .channels-list-content,
|
||||||
|
.channels-screen--list .channels-groups,
|
||||||
|
.channels-screen--list .stack:has(> .channel-row) {
|
||||||
|
width: calc(100% + 16px) !important;
|
||||||
|
margin-left: -8px !important;
|
||||||
|
margin-right: -8px !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row {
|
||||||
|
width: 100% !important;
|
||||||
|
min-height: 54px !important;
|
||||||
|
margin: 1px 0 !important;
|
||||||
|
padding: 5px 6px 5px 4px !important;
|
||||||
|
grid-template-columns: 50px minmax(0, 1fr) !important;
|
||||||
|
gap: 8px !important;
|
||||||
|
border-radius: 15px !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row .avatar {
|
||||||
|
width: 48px !important;
|
||||||
|
height: 48px !important;
|
||||||
|
min-width: 48px !important;
|
||||||
|
min-height: 48px !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-main {
|
||||||
|
gap: 0 !important;
|
||||||
|
padding-right: 3px !important;
|
||||||
|
align-self: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-title,
|
||||||
|
.channels-screen--list .channel-row-technical,
|
||||||
|
.channels-screen--list .channel-row-description,
|
||||||
|
.channels-screen--list .channel-row-owner {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
line-height: 1.12 !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-preview-line {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: baseline !important;
|
||||||
|
gap: 7px !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
line-height: 1.15 !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-preview-line .channel-row-message {
|
||||||
|
flex: 1 1 auto !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
line-height: 1.15 !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-preview-line .channel-row-time {
|
||||||
|
flex: 0 0 auto !important;
|
||||||
|
position: static !important;
|
||||||
|
align-self: baseline !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
line-height: 1.15 !important;
|
||||||
|
transform: none !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
.channels-screen--list .channel-row-controls { top: 3px !important; right: 5px !important; }
|
||||||
|
|
||||||
|
/* Toolbar: reserve enough vertical room for the Connections label and safe area. */
|
||||||
|
:root { --toolbar-height: 88px; }
|
||||||
|
.toolbar-slot {
|
||||||
|
min-height: calc(88px + env(safe-area-inset-bottom)) !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom) !important;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
min-height: 82px !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding-bottom: 6px !important;
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
.toolbar-btn-network {
|
||||||
|
min-height: 72px !important;
|
||||||
|
align-content: end !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
.toolbar-btn-network .toolbar-icon-img {
|
||||||
|
transform: translateY(-4px) !important;
|
||||||
|
}
|
||||||
|
.toolbar-btn-network > span:last-child {
|
||||||
|
display: block !important;
|
||||||
|
transform: translateY(-2px) !important;
|
||||||
|
line-height: 1.05 !important;
|
||||||
|
padding-bottom: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels-screen--list .channel-row-technical,
|
||||||
|
.channels-screen--list .channel-row-description,
|
||||||
|
.channels-screen--list .channel-row-owner {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user