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:
@@ -0,0 +1,48 @@
|
||||
// Возвращает Promise<boolean>: true — подтвердили, false — отмена, Escape или тап мимо.
|
||||
export function confirmDialog({
|
||||
title = 'Подтвердите действие',
|
||||
text = '',
|
||||
confirmLabel = 'Да',
|
||||
cancelLabel = 'Отмена',
|
||||
danger = false,
|
||||
} = {}) {
|
||||
return new Promise((resolve) => {
|
||||
const opener = document.activeElement;
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal confirm-dialog';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-card confirm-dialog__card" role="alertdialog" aria-modal="true" aria-labelledby="confirm-dialog-title">
|
||||
<h2 class="modal-title" id="confirm-dialog-title"></h2>
|
||||
<p class="confirm-dialog__text"></p>
|
||||
<div class="form-actions-grid">
|
||||
<button type="button" class="secondary-btn" data-answer="no"></button>
|
||||
<button type="button" class="${danger ? 'destructive-btn confirm-dialog__danger' : 'primary-btn'}" data-answer="yes"></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
modal.querySelector('.modal-title').textContent = title;
|
||||
const textEl = modal.querySelector('.confirm-dialog__text');
|
||||
textEl.textContent = text;
|
||||
textEl.hidden = !text;
|
||||
modal.querySelector('[data-answer="no"]').textContent = cancelLabel;
|
||||
modal.querySelector('[data-answer="yes"]').textContent = confirmLabel;
|
||||
|
||||
const finish = (answer) => {
|
||||
document.removeEventListener('keydown', onKeydown, true);
|
||||
modal.remove();
|
||||
opener?.focus?.();
|
||||
resolve(answer);
|
||||
};
|
||||
const onKeydown = (event) => {
|
||||
if (event.key === 'Escape') { event.stopPropagation(); finish(false); }
|
||||
};
|
||||
modal.addEventListener('click', (event) => {
|
||||
if (event.target === modal) { finish(false); return; }
|
||||
const answer = event.target.closest('[data-answer]')?.dataset.answer;
|
||||
if (answer) finish(answer === 'yes');
|
||||
});
|
||||
document.addEventListener('keydown', onKeydown, true);
|
||||
document.body.append(modal);
|
||||
modal.querySelector('[data-answer="no"]').focus();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user