SHA256
UI: новый общий стиль, тёмная/светлая тема, настраиваемая палитра
- styles/main.css: роли цветов (по умолчанию «Индиго»), шкала отступов/скруглений/шрифтов, цвета отношений для обеих тем; жёсткие цвета в стилях заменены на роли. - Палитра: пресеты и личные правки, «Оформление» Авто/День/Ночь, долгое нажатие — редактор цветов с экспортом/импортом. - Каналы: пузыри постов автора, плашки дней, строка «Написать в канал…», «О канале», создание канала с адресом из названия; лента открывается на свежих постах. - Чаты: плоский список, чипы-фильтры, пузыри, плашки дней; нижняя панель скрыта в переписке. - Корневые разделы — единая шапка; профиль и чужой профиль — общая карточка; настройки, кошелёк, сеансы — меню-списки. - Нижняя панель: иконки без подписей, бейджи на иконках. - confirmDialog вместо window.confirm/alert; на телефоне диалоги — шторки снизу. - docs/UI-Design/ISSUES-for-dev.md — найденные ошибки сервера/UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,55 +14,38 @@ export function render({navigate, chrome}) {
|
||||
const returnPage = resolveReturnPage();
|
||||
let pendingLanguage = state.entrySettings.language === 'en' ? 'en' : 'ru';
|
||||
|
||||
chrome?.setTopbar(createTopBar({
|
||||
const topbar = createTopBar({
|
||||
title: 'Язык / Language',
|
||||
back: { label: '←', onClick: () => {
|
||||
sessionStorage.removeItem('shine-language-return-page');
|
||||
navigate(returnPage);
|
||||
} },
|
||||
}));
|
||||
});
|
||||
const embedTopbar = !state.session.isAuthorized;
|
||||
if (!embedTopbar) chrome?.setTopbar(topbar);
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card stack language-choice-card';
|
||||
card.innerHTML = `
|
||||
<p class="meta-muted language-choice-hint">Выберите язык интерфейса</p>
|
||||
<div class="language-segmented-control" role="radiogroup" aria-label="Язык интерфейса">
|
||||
<button class="language-segment${pendingLanguage === 'ru' ? ' is-selected' : ''}" type="button" data-language="ru" role="radio" aria-checked="${pendingLanguage === 'ru'}">Русский</button>
|
||||
<button class="language-segment${pendingLanguage === 'en' ? ' is-selected' : ''}" type="button" data-language="en" role="radio" aria-checked="${pendingLanguage === 'en'}">English</button>
|
||||
<span class="language-segmented-thumb" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div class="language-choice-actions">
|
||||
<button class="shine-btn shine-btn--settings" type="button" data-action="cancel">Отмена</button>
|
||||
<button class="shine-btn shine-btn--primary" type="button" data-action="ok">OK</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const syncSelection = () => {
|
||||
card.dataset.language = pendingLanguage;
|
||||
card.querySelectorAll('[data-language]').forEach((item) => {
|
||||
const selected = item.dataset.language === pendingLanguage;
|
||||
item.classList.toggle('is-selected', selected);
|
||||
item.setAttribute('aria-checked', String(selected));
|
||||
card.className = 'nav-list language-list';
|
||||
card.setAttribute('role', 'radiogroup');
|
||||
card.setAttribute('aria-label', 'Язык интерфейса / Interface language');
|
||||
[['ru', 'Русский'], ['en', 'English']].forEach(([code, label]) => {
|
||||
const row = document.createElement('button');
|
||||
row.type = 'button';
|
||||
row.className = 'nav-row language-row';
|
||||
row.setAttribute('role', 'radio');
|
||||
row.setAttribute('aria-checked', String(pendingLanguage === code));
|
||||
row.innerHTML = `<span class="nav-row__label"></span>`;
|
||||
row.querySelector('.nav-row__label').textContent = label;
|
||||
row.addEventListener('click', () => {
|
||||
pendingLanguage = code;
|
||||
saveEntryLanguage(code);
|
||||
sessionStorage.removeItem('shine-language-return-page');
|
||||
navigate(returnPage);
|
||||
});
|
||||
};
|
||||
syncSelection();
|
||||
|
||||
card.querySelectorAll('[data-language]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
pendingLanguage = button.dataset.language === 'en' ? 'en' : 'ru';
|
||||
syncSelection();
|
||||
});
|
||||
});
|
||||
card.querySelector('[data-action="cancel"]')?.addEventListener('click', () => {
|
||||
sessionStorage.removeItem('shine-language-return-page');
|
||||
navigate(returnPage);
|
||||
});
|
||||
card.querySelector('[data-action="ok"]')?.addEventListener('click', () => {
|
||||
saveEntryLanguage(pendingLanguage);
|
||||
sessionStorage.removeItem('shine-language-return-page');
|
||||
navigate(returnPage);
|
||||
card.append(row);
|
||||
});
|
||||
|
||||
if (embedTopbar) screen.append(topbar);
|
||||
screen.append(card);
|
||||
return screen;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user