SHA256
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:
@@ -18,47 +18,44 @@ const EMPTY_PASSWORD_WORDS = Array.from({ length: 12 }, () => '');
|
||||
|
||||
export function render({ navigate }) {
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack';
|
||||
screen.className = 'stack keys-screen';
|
||||
|
||||
const isLoginFlow = state.registrationDraft.flowType === 'login';
|
||||
const normalizedLogin = (state.registrationDraft.login || '').trim();
|
||||
const displayLogin = normalizedLogin || '@new.user';
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card stack';
|
||||
|
||||
const title = document.createElement('p');
|
||||
title.className = 'auth-copy';
|
||||
title.textContent = isLoginFlow
|
||||
? `Вход выполнен для логина ${displayLogin}.`
|
||||
: `Отлично, логин ${displayLogin} зарегистрирован.`;
|
||||
const displayLogin = normalizedLogin ? `@${normalizedLogin.replace(/^@/, '')}` : '@new.user';
|
||||
|
||||
const lead = document.createElement('div');
|
||||
lead.className = 'keys-lead';
|
||||
const title = document.createElement('h1');
|
||||
title.className = 'keys-lead__title';
|
||||
title.textContent = isLoginFlow ? `Вы вошли как ${displayLogin}` : `${displayLogin} зарегистрирован`;
|
||||
const question = document.createElement('p');
|
||||
question.className = 'auth-copy';
|
||||
question.textContent = 'Какие ключи сохранить в зашифрованном контейнере IndexedDB?';
|
||||
|
||||
const nextStep = document.createElement('p');
|
||||
nextStep.className = 'meta-muted';
|
||||
nextStep.textContent = 'После сохранения откроется профиль. Для проверки откройте вкладку «Каналы».';
|
||||
question.className = 'keys-lead__text';
|
||||
question.textContent = 'Какие ключи хранить на этом устройстве?';
|
||||
const questionHint = document.createElement('p');
|
||||
questionHint.className = 'keys-lead__text';
|
||||
questionHint.textContent = 'Они хранятся в зашифрованном виде.';
|
||||
lead.append(title, question, questionHint);
|
||||
|
||||
const status = document.createElement('p');
|
||||
status.className = 'status-line is-unavailable';
|
||||
status.style.display = 'none';
|
||||
|
||||
const createKeyInfo = (toggle, titleText, descriptionText) => {
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'key-storage-option stack';
|
||||
|
||||
const createKeyRow = (toggle, titleText, descriptionText) => {
|
||||
const row = document.createElement('label');
|
||||
row.className = 'checkbox-row';
|
||||
row.append(toggle, document.createTextNode(titleText));
|
||||
|
||||
const description = document.createElement('p');
|
||||
description.className = 'meta-muted key-storage-option__description';
|
||||
row.className = 'keys-row';
|
||||
const text = document.createElement('span');
|
||||
text.className = 'keys-row__text';
|
||||
const name = document.createElement('span');
|
||||
name.className = 'keys-row__title';
|
||||
name.textContent = titleText;
|
||||
const description = document.createElement('span');
|
||||
description.className = 'keys-row__hint';
|
||||
description.textContent = descriptionText;
|
||||
|
||||
wrap.append(row, description);
|
||||
return wrap;
|
||||
text.append(name, description);
|
||||
toggle.className = 'switch';
|
||||
row.append(text, toggle);
|
||||
return row;
|
||||
};
|
||||
|
||||
const rootToggle = document.createElement('input');
|
||||
@@ -74,35 +71,23 @@ export function render({ navigate }) {
|
||||
deviceToggle.checked = true;
|
||||
deviceToggle.disabled = true;
|
||||
|
||||
const rootRow = createKeyInfo(
|
||||
rootToggle,
|
||||
'Ключ root',
|
||||
'Главный ключ аккаунта. Нужен для смены пароля, восстановления доступа и важных основных настроек.',
|
||||
);
|
||||
|
||||
const blockchainRow = createKeyInfo(
|
||||
blockchainToggle,
|
||||
'Ключ blockchain',
|
||||
'Используется для подписи ваших действий и записей в блокчейне Сияния.',
|
||||
);
|
||||
|
||||
const deviceRow = createKeyInfo(
|
||||
deviceToggle,
|
||||
'Client key (всегда)',
|
||||
'Ключ этого устройства. Нужен для обычного входа, авторизации сессии и работы приложения на телефоне.',
|
||||
const list = document.createElement('div');
|
||||
list.className = 'keys-list';
|
||||
list.append(
|
||||
createKeyRow(rootToggle, 'Главный ключ', 'Смена пароля, восстановление доступа, важные настройки'),
|
||||
createKeyRow(blockchainToggle, 'Ключ публикаций', 'Подписывает ваши записи и действия'),
|
||||
createKeyRow(deviceToggle, 'Ключ устройства', 'Вход с этого устройства – нужен всегда'),
|
||||
);
|
||||
|
||||
const simpleNote = document.createElement('p');
|
||||
simpleNote.className = 'key-storage-note key-storage-note--strong';
|
||||
simpleNote.textContent = 'Если вы не особо понимаете, о чём идёт речь, и не хотите особо заморачиваться с ключами, можете просто сохранить все ключи на телефоне.';
|
||||
|
||||
card.append(title, question, nextStep, rootRow, blockchainRow, deviceRow, simpleNote, status);
|
||||
simpleNote.className = 'keys-note';
|
||||
simpleNote.textContent = 'Не уверены – оставьте все включёнными.';
|
||||
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'auth-footer-actions';
|
||||
actions.className = 'keys-actions';
|
||||
|
||||
const cancelButton = document.createElement('button');
|
||||
cancelButton.className = 'ghost-btn';
|
||||
cancelButton.className = 'secondary-btn';
|
||||
cancelButton.type = 'button';
|
||||
cancelButton.textContent = 'Отмена';
|
||||
cancelButton.addEventListener('click', async () => {
|
||||
@@ -118,7 +103,7 @@ export function render({ navigate }) {
|
||||
const okButton = document.createElement('button');
|
||||
okButton.className = 'primary-btn';
|
||||
okButton.type = 'button';
|
||||
okButton.textContent = 'OK';
|
||||
okButton.textContent = 'Готово';
|
||||
okButton.addEventListener('click', async () => {
|
||||
status.style.display = 'none';
|
||||
try {
|
||||
@@ -190,7 +175,7 @@ export function render({ navigate }) {
|
||||
}
|
||||
});
|
||||
|
||||
actions.append(cancelButton, okButton);
|
||||
actions.append(okButton, cancelButton);
|
||||
|
||||
screen.append(
|
||||
createTopBar({
|
||||
@@ -208,7 +193,10 @@ export function render({ navigate }) {
|
||||
},
|
||||
},
|
||||
}),
|
||||
card,
|
||||
lead,
|
||||
list,
|
||||
simpleNote,
|
||||
status,
|
||||
actions,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user