UI v4: новый стиль по макету V3/V4 и доводка экранов

Палитра «Сияние» по умолчанию, новые роли цветов. Лента канала: плоские записи, ряд действий
с равным шагом иконок, дата у записи. Обсуждение со строкой ввода, личный чат, шторки.
Вход и регистрация: стартовый экран (надпись «СИЯНИЕ», сияние мандалы), настройки входа
со статусами серверов, статус логина в одну строку, вход с другого устройства (код, таймер, шаги),
сохранение ключей с переключателями. Корневые разделы – заголовок по центру; фильтр чатов –
переключатель; уведомления – список как в чатах; фото – просмотр на весь экран.
Общее: один зазор под шапкой (--page-top-gap), переключатели высотой с поле ввода,
второстепенные кнопки по одной роли (в том числе на экранах устройств и серверов),
иконки только из ui-icon.js, полоса прокрутки скрыта, среднее тире в текстах интерфейса.

Что нужно от сервера и разработчика – docs/UI-Design/UI-v4-for-dev.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
q
2026-09-29 01:36:52 +03:00
co-authored by Claude Opus 5.5
parent 13693a0a53
commit 2e62616b46
84 changed files with 2507 additions and 1583 deletions
+25 -15
View File
@@ -208,23 +208,33 @@ export function render({ navigate, chrome }) {
];
let reloadForFilter = () => {};
const filterRow = document.createElement('div');
filterRow.className = 'chip-row chip-row--bleed dm-filter-row';
filterRow.setAttribute('role', 'toolbar');
filterRow.className = 'tabs tabs--auto tabs--dense dm-filter-row';
filterRow.setAttribute('role', 'radiogroup');
filterRow.setAttribute('aria-label', 'Фильтр чатов');
const selectFilter = (value) => {
if (currentChatFilter === value) return;
currentChatFilter = value;
filterRow.querySelectorAll('.tab-btn').forEach((el) => el.setAttribute('aria-checked', String(el.dataset.filter === value)));
reloadForFilter();
};
CHAT_FILTERS.forEach(([value, label]) => {
const chip = document.createElement('button');
chip.type = 'button';
chip.className = 'chip';
chip.dataset.filter = value;
chip.textContent = label;
chip.setAttribute('aria-pressed', String(value === currentChatFilter));
chip.addEventListener('click', () => {
if (currentChatFilter === value) return;
currentChatFilter = value;
filterRow.querySelectorAll('.chip').forEach((el) => el.setAttribute('aria-pressed', String(el.dataset.filter === value)));
reloadForFilter();
});
filterRow.append(chip);
const button = document.createElement('button');
button.type = 'button';
button.className = 'tab-btn';
button.dataset.filter = value;
button.textContent = label;
button.setAttribute('role', 'radio');
button.setAttribute('aria-checked', String(value === currentChatFilter));
button.addEventListener('click', () => selectFilter(value));
filterRow.append(button);
});
filterRow.addEventListener('keydown', (event) => {
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
const index = CHAT_FILTERS.findIndex(([value]) => value === currentChatFilter);
const next = CHAT_FILTERS[(index + (event.key === 'ArrowRight' ? 1 : -1) + CHAT_FILTERS.length) % CHAT_FILTERS.length][0];
selectFilter(next);
filterRow.querySelector(`[data-filter="${next}"]`)?.focus();
event.preventDefault();
});
const head = createTopBar({