iOS: запрет масштабирования, версия в подвале, самообновление, строка ввода
Отзыв с iPhone после первого живого прогона. Масштабирование запрещено (ADR-066): viewport как в соседнем sixlines плюс viewport-fit=cover, мета-теги установленного приложения, touch-action против двойного тапа и страховка на JS — гашение жестов iOS, потому что мета-строку Safari вправе проигнорировать. Размеры шрифтов не тронуты: 14 px из брифа остаются, поднимать поля до 16 px владелец отклонил. Цена — доступность для тех, кому зум нужен — записана в ADR и в ui.md честно. Версия в подвале (ADR-065, 067): GET /api/config отдаёт короткую ревизию и время коммита. Именно коммита, а не сборки: штамп компиляции в бинаре means каждая пересборка даёт новый хеш, и обещание ADR-022 «бинарь собирается из тега байт в байт» перестаёт проверяться. Самообновление PWA (ADR-068, 070): в режиме приложения на iPhone перезагрузки нет, и старая версия жила бы вечно. Проверка при возврате в приложение, включение ждущей оболочки, перезагрузка — но не тогда, когда в строке набран текст. Замок от петли сравнивает версию оболочки, а не считает перезагрузки: счётчик отменял саму фичу, долгоживущая вкладка переставала обновляться. Замерено: было 30, 60, 120, 240 секунд между релизами, стало ровно 30. Строка ввода — редактируемый блок (ADR-069): iOS рисует над клавиатурой полосу со стрелками и «готово» для полей формы, и убрать её со страницы нельзя. Для contenteditable не рисует. Режим plaintext-only с проверкой, что он применился, и запасным путём с разбором вставки: невалидное значение атрибута в части браузеров делает блок нередактируемым вовсе. Чтение и запись только через textContent, innerHTML в клиенте по-прежнему нет. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DbCjVfTFq4ZFG8juD45YJ
This commit is contained in:
+30
-2
@@ -5,6 +5,12 @@ import * as pwa from "../pwa.js";
|
||||
import { INSTALL_IOS, clear, el, mark } from "./dom.js";
|
||||
import { mount } from "./chats.js";
|
||||
|
||||
// Время коммита — в местной зоне и коротко: день с месяцем и часы
|
||||
// с минутами (ADR-067). Год не показывается: версия отвечает на вопрос
|
||||
// «что сейчас работает», а не ведёт летопись.
|
||||
const BUILD_DAY = new Intl.DateTimeFormat("ru-RU", { day: "2-digit", month: "2-digit" });
|
||||
const BUILD_TIME = new Intl.DateTimeFormat("ru-RU", { hour: "2-digit", minute: "2-digit" });
|
||||
|
||||
// frame отдаёт корень, место под экран и отписку списка чатов.
|
||||
// screen — что показывать на мобильном, где виден один экран за раз:
|
||||
// "list" или "screen". active — чат, который сейчас открыт.
|
||||
@@ -38,17 +44,39 @@ function side(ctx, active) {
|
||||
list.append(add, items);
|
||||
nav.append(list);
|
||||
|
||||
const foot = el("div", "foot");
|
||||
const me = el("button", "me");
|
||||
me.type = "button";
|
||||
const dot = el("i");
|
||||
dot.setAttribute("aria-hidden", "true");
|
||||
me.append(dot, el("span", null, `ты: @${ctx.me.nick}`));
|
||||
me.append(dot, el("span", "me__nick", `ты: @${ctx.me.nick}`));
|
||||
me.addEventListener("click", () => ctx.go("#/settings"));
|
||||
nav.append(me);
|
||||
foot.append(me);
|
||||
const version = build(ctx.config);
|
||||
if (version !== null) {
|
||||
foot.append(el("span", "build", version));
|
||||
}
|
||||
nav.append(foot);
|
||||
|
||||
return { nav, dispose: mount(items, ctx, active) };
|
||||
}
|
||||
|
||||
// build — версия и время коммита из GET /api/config (ADR-065, ADR-067).
|
||||
// Конфигурации нет — офлайн-старт до первого ответа сервера — значит,
|
||||
// и строки нет: выдумывать версию не из чего. Время без версии не бывает:
|
||||
// её сервер отдаёт всегда, хотя бы как «unknown».
|
||||
function build(config) {
|
||||
const version = config?.version;
|
||||
if (typeof version !== "string" || version === "") {
|
||||
return null;
|
||||
}
|
||||
const at = config?.commitAt;
|
||||
if (!Number.isFinite(at) || at <= 0) {
|
||||
return version;
|
||||
}
|
||||
return `${version} · ${BUILD_DAY.format(at)} ${BUILD_TIME.format(at)}`;
|
||||
}
|
||||
|
||||
// banner — баннер установки на iOS: пуши там работают только
|
||||
// у установленного приложения (ADR-011). Крестик закрывает его насовсем.
|
||||
async function banner(place) {
|
||||
|
||||
Reference in New Issue
Block a user