SHA256
- 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>
103 lines
4.0 KiB
JavaScript
103 lines
4.0 KiB
JavaScript
import { profile } from '../mock-data.js';
|
|
import { state } from '../state.js';
|
|
import { renderUserAvatar } from '../components/avatar-image.js';
|
|
import { createTopBar } from '../components/topbar.js';
|
|
import { loadUserProfileCard } from '../services/user-connections.js';
|
|
import { profileCardHtml, profileTileHtml } from '../components/profile-card.js';
|
|
|
|
export const pageMeta = { id: 'profile-view', title: 'Профиль' };
|
|
|
|
export function render({ navigate, chrome }) {
|
|
const login = String(state.session.login || profile.login || '').trim();
|
|
const screen = document.createElement('section');
|
|
screen.className = 'stack user-profile-screen';
|
|
|
|
const topbar = createTopBar({
|
|
title: 'Профиль',
|
|
className: 'topbar--root user-profile-header',
|
|
});
|
|
chrome?.setTopbar(topbar);
|
|
|
|
const status = document.createElement('div');
|
|
status.className = 'status-line user-profile-status';
|
|
status.textContent = 'Загрузка профиля...';
|
|
|
|
const body = document.createElement('div');
|
|
body.className = 'user-profile-body';
|
|
screen.append(status, body);
|
|
|
|
let card = null;
|
|
|
|
function renderProfile() {
|
|
if (!card) return;
|
|
const official = card.accountRole === 'primary';
|
|
const shining = card.shineStatus === 'shining';
|
|
body.innerHTML = profileCardHtml({
|
|
card,
|
|
login,
|
|
tilesHtml: [
|
|
profileTileHtml({ icon: 'edit', label: 'Редактировать', attrs: 'data-self-profile-action="edit"' }),
|
|
profileTileHtml({ icon: 'wallet', label: 'Кошелёк', attrs: 'data-self-profile-action="wallet"' }),
|
|
profileTileHtml({ icon: 'settings', label: 'Настройки', attrs: 'data-self-profile-action="settings"' }),
|
|
].join(''),
|
|
}) + `
|
|
<div class="nav-list profile-more-list">
|
|
<button class="nav-row" type="button" data-profile-list="primary_given"><span class="nav-row__label">Подтверждённые мной аккаунты</span><span class="nav-row__hint">Аккаунты, за которые вы поручились</span></button>
|
|
<button class="nav-row" type="button" data-profile-list="shine_given"><span class="nav-row__label">Отмеченные мной как сияющие</span></button>
|
|
<button class="nav-row" type="button" data-self-profile-action="profiles"><span class="nav-row__label">Сменить профиль</span><span class="nav-row__hint">Другие аккаунты на этом устройстве</span></button>
|
|
</div>`;
|
|
|
|
const avatarSlot = body.querySelector('.user-profile-avatar-slot');
|
|
avatarSlot?.append(renderUserAvatar({
|
|
login: card.login,
|
|
firstName: card.firstName,
|
|
lastName: card.lastName,
|
|
avatar: card.avatar,
|
|
size: 'xl',
|
|
className: 'user-profile-hero-avatar',
|
|
glow: shining,
|
|
official,
|
|
}));
|
|
|
|
status.textContent = '';
|
|
}
|
|
|
|
body.addEventListener('click', (event) => {
|
|
if (!card) return;
|
|
|
|
const listButton = event.target.closest('[data-profile-list]');
|
|
if (listButton) {
|
|
const kind = listButton.dataset.profileList;
|
|
if (kind) navigate(`SHiNE/${encodeURIComponent(card.login)}/list/${encodeURIComponent(kind)}`);
|
|
return;
|
|
}
|
|
|
|
const actionButton = event.target.closest('[data-self-profile-action]');
|
|
if (actionButton) {
|
|
const action = actionButton.dataset.selfProfileAction;
|
|
if (action === 'edit') navigate('profile-edit-view');
|
|
if (action === 'wallet') navigate('wallet-view');
|
|
if (action === 'settings') navigate('settings-view');
|
|
if (action === 'profiles') navigate('profiles-view');
|
|
return;
|
|
}
|
|
|
|
});
|
|
|
|
async function refresh() {
|
|
if (state.session.isLocalDemo) {
|
|
status.textContent = 'Локальный тестовый режим.';
|
|
return;
|
|
}
|
|
card = await loadUserProfileCard(login);
|
|
renderProfile();
|
|
}
|
|
|
|
refresh().catch((error) => {
|
|
status.className = 'status-line user-profile-status is-unavailable';
|
|
status.textContent = `Ошибка: ${error?.message || 'unknown'}`;
|
|
});
|
|
|
|
return screen;
|
|
}
|