Чат v1.1.1: упростить ввод и стороны по устройству

This commit is contained in:
2026-08-24 12:17:13 +03:00
parent d7624dfade
commit 1a56d2f8a1
17 changed files with 146 additions and 318 deletions
+4 -4
View File
@@ -38,13 +38,13 @@
Шапка: имя (`#general` / `@marta`), по нажатию — участники или карточка контакта. Без темы и «N онлайн».
Лента: поток блоков сверху вниз, одинаковый на десктопе и мобильном; подряд идущие сообщения одного автора — без повтора автора над группой. Свои сообщения выровнены по правому краю ленты, чужие — по левому (ADR-065); свой ник в колонке автора при этом остаётся цветом `mark`. Ширина блока сообщения ограничена — иначе выравнивать нечего, — текст внутри блока выровнен по левому краю независимо от стороны. Разделители дат и «новые» — во всю ширину ленты: линия с датой; «новые» — линия цветом `mark` перед первым непрочитанным, исчезает при следующем открытии чата. Pending — текст цветом `stone`; failed — с пометкой «не отправлено · повторить». Нерасшифрованное — курсивом: «не удалось расшифровать: ключ изменился» / «…: нет ключа комнаты». Время — `ts` в локальной зоне, `ЧЧ:ММ`.
Лента: поток блоков сверху вниз; подряд идущие сообщения одного автора — без повтора автора над группой. На телефоне и планшете свои сообщения выровнены по правому краю, чужие — по левому; на десктопе все сообщения стоят слева (ADR-077). Десктоп определяется точным указателем с наведением, а не шириной окна: широкий планшет остаётся планшетом. Свой ник остаётся цветом `mark`. Ширина блока сообщения ограничена — иначе выравнивать нечего, — текст внутри блока всегда выровнен по левому краю. Разделители дат и «новые» — во всю ширину ленты: линия с датой; «новые» — линия цветом `mark` перед первым непрочитанным, исчезает при следующем открытии чата. Pending — текст цветом `stone`; failed — с пометкой «не отправлено · повторить». Нерасшифрованное — курсивом: «не удалось расшифровать: ключ изменился» / «…: нет ключа комнаты». Время — `ts` в локальной зоне, `ЧЧ:ММ`.
Лента открывается последними 50 сообщениями и стоит в конце. Прокрутка к верхнему краю подгружает следующие 50; то, что человек читает, при этом не двигается. Загруженное остаётся в разметке целиком — виртуализации нет (ADR-053).
Ввод: рамка 1 px ink, слева `>` цветом `mark`, подсказка «сообщение в #general» / «сообщение»; имя комнаты в подсказке обрезается до 12 символов многоточием — «сообщение в #длинноеимя…» (ADR-061), в шапке оно остаётся полным. Enter — отправить, Shift+Enter — перенос; на мобильном Enter — перенос, отправка — кнопка `>` справа. Подсказка «enter — отправить» только на десктопе. Лимит 4000 — счётчик появляется после 3500; лишнее обрезается и при наборе, и при вставке: режется приходящее, набранное остаётся на месте (ADR-071).
Ввод: рамка 1 px ink, слева `>` цветом `mark`, подсказка «сообщение в #general» / «сообщение»; имя комнаты в подсказке обрезается до 12 символов многоточием — «сообщение в #длинноеимя…» (ADR-061), в шапке оно остаётся полным. Enter — отправить, Shift+Enter — перенос; на мобильном Enter — перенос, отправка — кнопка `>` справа. Подсказка «enter — отправить» только на десктопе. Лимит 4000 — счётчик появляется после 3500; нативный `maxLength` не пускает лишнее. Тап по неинтерактивному месту истории снимает фокус со строки и закрывает клавиатуру (ADR-076).
Строка сообщения — редактируемый блок, а не поле формы: над клавиатурой iOS рисует полосу помощника форм, и бывает она только у `input` и `textarea` (ADR-069). Блок принимает и отдаёт только текст: вставка приходит текстом, значение читается и пишется `textContent`, `innerHTML` не появляется. Подсказку рисует правило CSS для пустого блока. Растёт под содержимое, дальше семи строк — прокрутка. Заблокированный ввод перестаёт быть редактируемым. Остальные строки ввода — вход, регистрация, смена пароля, «новый чат», участники — остаются полями формы: там нужны менеджеры паролей, а полоса на разовом экране не мешает.
Строка сообщения — `textarea` (ADR-076): она принимает только текст, сама держит вставку, выделение, отмену, подсказку, предел и состояние `disabled`. Растёт под содержимое, дальше семи строк — прокрутка. Системную панель со стрелками и «готово» iOS рисует поверх клавиатуры и для `textarea`, и для `contenteditable`; у веб-страницы нет поддерживаемого API, чтобы её скрыть. Полное управление этой панелью потребовало бы отдельной нативной iOS-оболочки; собственная экранная клавиатура в веб-клиенте не делается.
Предупреждение о ключе — полоса над вводом цветом `mark`: «ключ @marta изменился. сверьте отпечаток лично. [доверять новому ключу]». Ввод заблокирован до подтверждения. Полоса одна: предупреждение о ключе перебивает отказ отправки и «нет соединения» (ADR-038).
@@ -118,6 +118,6 @@
Семантика: `nav`, `main`, `form`, `button`, `ul/li` для списков; `aria-live="polite"` на ленте; фокус в строку ввода при открытии чата на десктопе; контраст ink/bone и mark/bone не ниже 4.5:1; цели нажатия на мобильном не меньше 44 px.
Строка сообщения — редактируемый блок (ADR-069), и семантику ему задают руками: `role="textbox"`, `aria-multiline="true"`, подпись `aria-label` тем же текстом, что подсказка. Заблокированный ввод перестаёт быть редактируемым и говорит об этом `aria-disabled`.
Строка сообщения — нативная `textarea` (ADR-076): роль многострочного поля и состояние `disabled` сообщает сам браузер; доступное имя повторяет текст видимой подсказки через `aria-label`, кнопка `>` объявляется как «отправить».
Масштабирование запрещено — и щипок, и двойной тап (ADR-075). Это сознательный размен: интерфейс ведёт себя как приложение, а человек, которому нужно увеличить мелкое, средства лишается. Размеры шрифтов от запрета не меняются: поля ввода остаются 14 px, как в `docs/identity/brief.md`. Браузер вправе запрет проигнорировать.