UI: адаптация шапки «Связи», кнопка поиска каналов, локальный тестовый вход

- Связи: верхняя панель не выходит за границы экрана — кнопки назад/Найти/«?»
  не обрезаются на узких устройствах; заголовок сокращается вместо сдвига кнопок.
- Каналы: emoji-иконка поиска заменена на контурную кнопку-лупу в стиле панели
  (подсказка «Найти канал»); окно поиска без изменений.
- Локальный тестовый вход: на localhost/127.0.0.1/::1 — кнопка демо-входа
  (сеанс local-tester, автономные локальные состояния ЛС/каналов/профиля, без
  сервера и пароля); на shineup.me и тестовых доменах кнопка отсутствует.
- Заметки на ручную проверку добавлены в Dev_Docs/Pending_Features.
- VERSION: client 1.2.262.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pixel
2026-07-15 12:40:16 +03:00
co-authored by Claude Opus 4.8
parent 127c561a41
commit 8c4997ee2e
19 changed files with 1066 additions and 143 deletions
+27 -12
View File
@@ -754,22 +754,25 @@ function renderErrorState(container, error, onRetry) {
container.append(errCard);
}
function renderDemoFallback(container, navigate, error, onRetry) {
function renderDemoFallback(container, navigate, error, onRetry, { localOnly = false } = {}) {
const info = document.createElement('div');
info.className = 'card stack';
info.innerHTML = `
<strong>Включен демо-режим</strong>
<p class="meta-muted">Данные сервера недоступны. Показаны мок-каналы, потому что включен channelsDemo.</p>
<p class="meta-muted">${toUserMessage(error, 'Ошибка API/WS')}</p>
<strong>${localOnly ? 'Локальный тестовый режим' : 'Включен демо-режим'}</strong>
<p class="meta-muted">${localOnly
? 'Показаны мок-каналы. Подключение к серверу отключено.'
: 'Данные сервера недоступны. Показаны мок-каналы, потому что включен channelsDemo.'}</p>
${localOnly ? '' : `<p class="meta-muted">${toUserMessage(error, 'Ошибка API/WS')}</p>`}
`;
const retry = document.createElement('button');
retry.className = 'secondary-btn';
retry.type = 'button';
retry.textContent = 'Повторить запрос к серверу';
retry.addEventListener('click', onRetry);
info.append(retry);
if (!localOnly && typeof onRetry === 'function') {
const retry = document.createElement('button');
retry.className = 'secondary-btn';
retry.type = 'button';
retry.textContent = 'Повторить запрос к серверу';
retry.addEventListener('click', onRetry);
info.append(retry);
}
container.append(info);
const groups = mapMockGroups();
@@ -1090,6 +1093,14 @@ async function loadFeedAndRender({ screen, listState, contentEl, navigate }) {
return;
}
if (state.session.isLocalDemo) {
setChannelsFeed(null, {});
listState.channels = [];
contentEl.innerHTML = '';
renderDemoFallback(contentEl, navigate, null, null, { localOnly: true });
return;
}
try {
const feed = await authService.listSubscriptionsFeed(state.session.login, 200);
const groups = mapApiFeed(feed, listState.notificationsState);
@@ -1160,8 +1171,12 @@ export function render({ navigate, route }) {
const findChannelBtn = document.createElement('button');
findChannelBtn.type = 'button';
findChannelBtn.className = 'icon-btn channels-top-search-btn';
findChannelBtn.textContent = '🔎';
findChannelBtn.setAttribute('aria-label', 'Найти канал');
findChannelBtn.title = 'Найти канал';
const findChannelIcon = document.createElement('span');
findChannelIcon.className = 'channels-search-icon';
findChannelIcon.setAttribute('aria-hidden', 'true');
findChannelBtn.append(findChannelIcon);
findChannelBtn.addEventListener('click', () => openChannelFinderModal({ navigate }));
const createInMyBtn = document.createElement('button');