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
+28 -2
View File
@@ -25,6 +25,11 @@ const INVALID_SESSION_CODES = new Set([
'SESSION_OF_ANOTHER_USER',
]);
function isLocalPreviewHost() {
const host = String(window.location.hostname || '').toLowerCase();
return host === 'localhost' || host === '127.0.0.1' || host === '::1';
}
function readLocalWsOverrideUrl() {
try {
const params = new URLSearchParams(window.location.search);
@@ -226,6 +231,7 @@ export function clearBrowserClientData() {
function createInitialState({ withStoredSession = true } = {}) {
const storedSession = withStoredSession ? loadStoredSession() : null;
const storedLocalDemo = Boolean(storedSession?.isLocalDemo && isLocalPreviewHost());
const storedReactions = loadStoredReactions();
const storedEntrySettings = loadStoredEntrySettings();
const initialShineServer = LOCAL_WS_OVERRIDE_URL || DEFAULT_SHINE_SERVER;
@@ -240,7 +246,8 @@ function createInitialState({ withStoredSession = true } = {}) {
notificationsTab: 'replies',
pageLabelCollapsed: false,
session: {
isAuthorized: false,
isAuthorized: storedLocalDemo,
isLocalDemo: storedLocalDemo,
login: storedSession?.login || '',
sessionId: storedSession?.sessionId || '',
storagePwdInMemory: '',
@@ -767,13 +774,17 @@ export function authorizeSession({
login = state.session.login,
sessionId = state.session.sessionId,
storagePwd = state.session.storagePwdInMemory,
isLocalDemo = false,
} = {}) {
const localDemo = Boolean(isLocalDemo && isLocalPreviewHost());
state.session.isAuthorized = true;
state.session.isLocalDemo = localDemo;
state.session.login = login;
state.session.sessionId = sessionId;
state.session.storagePwdInMemory = storagePwd;
persistSession({
isAuthorized: true,
isLocalDemo: localDemo,
login,
sessionId,
});
@@ -783,6 +794,21 @@ export function authorizeSession({
}
}
export function isLocalDemoAvailable() {
return isLocalPreviewHost();
}
export function authorizeLocalDemoSession() {
if (!isLocalPreviewHost()) return false;
authorizeSession({
login: 'local-tester',
sessionId: 'local-ui-demo',
storagePwd: '',
isLocalDemo: true,
});
return true;
}
export function setSessionResetHandler(handler) {
onSessionReset = typeof handler === 'function' ? handler : null;
}
@@ -828,7 +854,7 @@ function resetStateForSignedOut() {
async function tryCloseCurrentSessionOnServer() {
const currentSessionId = String(state.session.sessionId || '').trim();
if (!state.session.isAuthorized || !currentSessionId) return;
if (!state.session.isAuthorized || state.session.isLocalDemo || !currentSessionId) return;
try {
await authService.closeSession(currentSessionId);