UI: новый общий стиль, тёмная/светлая тема, настраиваемая палитра

- styles/main.css: роли цветов (по умолчанию «Индиго»), шкала отступов/скруглений/шрифтов,
  цвета отношений для обеих тем; жёсткие цвета в стилях заменены на роли.
- Палитра: пресеты и личные правки, «Оформление» Авто/День/Ночь, долгое нажатие —
  редактор цветов с экспортом/импортом.
- Каналы: пузыри постов автора, плашки дней, строка «Написать в канал…», «О канале»,
  создание канала с адресом из названия; лента открывается на свежих постах.
- Чаты: плоский список, чипы-фильтры, пузыри, плашки дней; нижняя панель скрыта в переписке.
- Корневые разделы — единая шапка; профиль и чужой профиль — общая карточка;
  настройки, кошелёк, сеансы — меню-списки.
- Нижняя панель: иконки без подписей, бейджи на иконках.
- confirmDialog вместо window.confirm/alert; на телефоне диалоги — шторки снизу.
- docs/UI-Design/ISSUES-for-dev.md — найденные ошибки сервера/UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
q
2026-09-26 10:05:26 +03:00
co-authored by Claude Opus 5.5
parent 6e5b57fd7c
commit f8900e531a
94 changed files with 3337 additions and 2432 deletions
+7 -4
View File
@@ -1,3 +1,4 @@
import { iconHtml } from '../components/ui-icon.js';
import { channels as mockChannels } from '../mock-data.js';
import { authService, setChannelsFeed, state } from '../state.js';
import { toUserMessage } from '../services/ui-error-texts.js';
@@ -5,7 +6,7 @@ import { parseMessageAttachments } from '../services/attachment-format.js';
import {
animatePress,
createSkeletonCard,
formatRelativeTime,
formatListTime,
readChannelNotificationsState,
showToast,
softHaptic,
@@ -755,7 +756,7 @@ function mapApiChannelRow(summary, bucketKey, idx, index, notificationsState) {
messagePreview: cleanChannelMessagePreview(lastMessage.text),
messagesCount: Number(summary?.messagesCount || 0),
unreadCount: Number(summary?.unreadCount || 0),
lastMessageAt: Number(lastMessage.createdAtMs || 0),
lastMessageAt: Number(lastMessage.createdAtMs || summary?.channel?.metaUpdatedAtMs || 0),
isOwnChannel: isOwn,
isSubscribed: !isOwn,
notificationsEnabled: notificationsState[rowId] === true,
@@ -964,12 +965,13 @@ function renderChannelMain(channel) {
const time = document.createElement('span');
time.className = 'channel-row-time';
time.textContent = channel.lastMessageAt ? formatRelativeTime(channel.lastMessageAt) : '';
time.textContent = channel.lastMessageAt ? formatListTime(channel.lastMessageAt) : '';
titleLine.append(title, time);
const technical = document.createElement('p');
technical.className = 'channel-row-technical';
technical.textContent = `@${channel.ownerName || 'автор'}`;
technical.hidden = !!channel.isOwnChannel;
if (channel.channelDescription) {
const desc = document.createElement('p');
@@ -984,6 +986,7 @@ function renderChannelMain(channel) {
const preview = document.createElement('p');
preview.className = 'channel-row-message';
preview.textContent = channel.messagePreview || 'Пока нет сообщений';
if (!channel.messagePreview) preview.classList.add('is-empty');
previewLine.append(preview);
@@ -1173,7 +1176,7 @@ export function render({ navigate, route, chrome }) {
controls.className = 'channels-list-controls';
const searchWrap = document.createElement('div');
searchWrap.className = 'channels-inline-search';
searchWrap.innerHTML = '<span aria-hidden="true">⌕</span><span class="sr-only">Поиск каналов</span>';
searchWrap.innerHTML = `<span class="channels-inline-search__icon" aria-hidden="true">${iconHtml('search')}</span><span class="sr-only">Поиск каналов</span>`;
const searchInput = document.createElement('input');
searchInput.type = 'search';
searchInput.value = listState.query;