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
@@ -1789,12 +1789,12 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
function updateSummary(data) {
if (!data) {
summaryFields.login.textContent = '—';
summaryFields.pda.textContent = '—';
summaryFields.recordNumber.textContent = '—';
summaryFields.blockchainName.textContent = '—';
summaryFields.arweave.textContent = '—';
summaryFields.lastBlock.textContent = '—';
summaryFields.login.textContent = '–';
summaryFields.pda.textContent = '–';
summaryFields.recordNumber.textContent = '–';
summaryFields.blockchainName.textContent = '–';
summaryFields.arweave.textContent = '–';
summaryFields.lastBlock.textContent = '–';
setLinkState(solanaAccountLink, '', 'Открыть PDA в Solana explorer');
setLinkState(arweaveLink, '', 'Открыть Arweave запись');
return;
@@ -2297,27 +2297,27 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
<div id="summary-grid" class="summary-grid">
<div class="summary-item">
<span class="summary-item__label">Логин</span>
<strong id="summary-login">—</strong>
<strong id="summary-login">–</strong>
</div>
<div class="summary-item">
<span class="summary-item__label">PDA</span>
<strong id="summary-pda">—</strong>
<strong id="summary-pda">–</strong>
</div>
<div class="summary-item">
<span class="summary-item__label">Версия записи</span>
<strong id="summary-record-number">—</strong>
<strong id="summary-record-number">–</strong>
</div>
<div class="summary-item">
<span class="summary-item__label">Блокчейн</span>
<strong id="summary-blockchain-name">—</strong>
<strong id="summary-blockchain-name">–</strong>
</div>
<div class="summary-item">
<span class="summary-item__label">Arweave TX</span>
<strong id="summary-arweave">—</strong>
<strong id="summary-arweave">–</strong>
</div>
<div class="summary-item">
<span class="summary-item__label">Последний блок</span>
<strong id="summary-last-block">—</strong>
<strong id="summary-last-block">–</strong>
</div>
</div>
</section>
@@ -2660,12 +2660,12 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
function updateSummary(data) {
if (!data) {
summaryFields.login.textContent = '—';
summaryFields.pda.textContent = '—';
summaryFields.recordNumber.textContent = '—';
summaryFields.blockchainName.textContent = '—';
summaryFields.arweave.textContent = '—';
summaryFields.lastBlock.textContent = '—';
summaryFields.login.textContent = '–';
summaryFields.pda.textContent = '–';
summaryFields.recordNumber.textContent = '–';
summaryFields.blockchainName.textContent = '–';
summaryFields.arweave.textContent = '–';
summaryFields.lastBlock.textContent = '–';
setLinkState(solanaAccountLink, '', 'Открыть PDA в Solana explorer');
setLinkState(arweaveLink, '', 'Открыть Arweave запись');
updateToolbarState();
@@ -3309,7 +3309,7 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
clearBlockchainBrowser();
setContentStatus('ok', 'Viewer читает новый формат Arweave: ?login=...&channel=... или ?key=...&channel=...');
renderResult({
info: 'Передайте ?login=...&channel=... — ключ будет взят из Solana PDA. Или ?key=<blockchainKey>&channel=... — прямое чтение Arweave без Solana.',
info: 'Передайте ?login=...&channel=... – ключ будет взят из Solana PDA. Или ?key=<blockchainKey>&channel=... – прямое чтение Arweave без Solana.',
});
showEmptyState('Укажите логин пользователя SHiNE и откройте его блокчейн.');
updateToolbarState();
@@ -3,19 +3,19 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SHiNE — четыре направления UI</title>
<title>SHiNE – четыре направления UI</title>
<link rel="stylesheet" href="mockups.css">
<script src="mockups.js" defer></script>
</head>
<body>
<header class="studio-header">
<a class="brand" href="index.html" aria-label="SHiNE — все варианты"><span class="brand-spark">✳</span> SHiNE<span class="brand-caption">DESIGN STUDY / 01</span></a>
<a class="brand" href="index.html" aria-label="SHiNE – все варианты"><span class="brand-spark">✳</span> SHiNE<span class="brand-caption">DESIGN STUDY / 01</span></a>
<span class="draft-label">Концепции · сентябрь 2026</span>
</header>
<main>
<section class="intro">
<div><div class="eyebrow">КАНАЛЫ / СООБЩЕНИЯ / ОТВЕТЫ</div><h1>Ближе к разговору.</h1><p>Четыре характера. Один привычный путь от канала к ответу.<br>Выберите экран и сравните — или нажмите на элементы внутри макета.</p></div>
<div class="intro-note"><span>01—04</span><p>Меньше визуального шума.<br>Больше места людям и мыслям.</p></div>
<div><div class="eyebrow">КАНАЛЫ / СООБЩЕНИЯ / ОТВЕТЫ</div><h1>Ближе к разговору.</h1><p>Четыре характера. Один привычный путь от канала к ответу.<br>Выберите экран и сравните – или нажмите на элементы внутри макета.</p></div>
<div class="intro-note"><span>01–04</span><p>Меньше визуального шума.<br>Больше места людям и мыслям.</p></div>
</section>
<section class="review-bar" aria-label="Управление просмотром">
<div class="screen-switch" role="group" aria-label="Экран для всех вариантов">
@@ -43,7 +43,7 @@ const channels = [
let role = 'reader';
let showKeyboard = false;
const states = new Map();
const mainText = 'Иногда лучший маршрут — чуть длиннее обычного. Сегодня свернула к реке и нашла это место. А где вы перезагружаетесь после рабочего дня?';
const mainText = 'Иногда лучший маршрут – чуть длиннее обычного. Сегодня свернула к реке и нашла это место. А где вы перезагружаетесь после рабочего дня?';
const secondText = 'Собрала наши любимые места в один список. Добавляйте свои находки в ответах!';
const landscape = () => `<div class="landscape" role="img" aria-label="Иллюстрация: тихая река, холмы и солнце"><svg viewBox="0 0 400 180" preserveAspectRatio="xMidYMid slice"><rect width="400" height="180" fill="#cad8d0"/><circle cx="290" cy="46" r="24" fill="#f5e7b5"/><path d="M0 87Q65 35 136 79T270 70T400 61V180H0" fill="#8faaa0"/><path d="M0 125Q73 67 155 102T310 86T400 101V180H0" fill="#527b70"/><path d="M0 153Q98 104 184 130T400 110V180H0" fill="#31594f"/><path d="M216 100Q105 130 236 145T201 180H311Q347 151 239 137T242 101Z" fill="#c2d2ba"/><path d="M32 138V59m0 4-15 30h30ZM361 129V47m0 4-18 34h36Z" fill="#30534a" stroke="#30534a" stroke-width="4"/></svg><span class="media-caption">У реки / 18:42</span></div>`;
function header(s) {
@@ -198,8 +198,8 @@ function handle(s, event) {
else if (action==='details') menu(s,'Данные записи','<p>Здесь доступны номер записи, цепочка автора, хэш и подпись. В мокапе технические данные не генерируются.</p>',el);
else if (action==='about') menu(s,'О канале','<p>Замечаем красоту рядом. Делимся местами, историями и маленькими открытиями.</p><p>Автор: @'+escapeText(s.channel.owner)+'</p>',el);
else if (action==='close-menu') { removeOverlay(s); if(s.returnFocus?.isConnected)s.returnFocus.focus({preventScroll:true}); }
else if (action==='new-channel') toast(s,'Создание канала — следующий этап проектирования');
else if (action==='edit-demo') toast(s,'Редактор существующего сообщения — следующий этап');
else if (action==='new-channel') toast(s,'Создание канала – следующий этап проектирования');
else if (action==='edit-demo') toast(s,'Редактор существующего сообщения – следующий этап');
else if (action==='outside') toast(s,'Сейчас проектируем каналы. Этот раздел пока вне макета.');
}
function attachEvents(s) {