SHA256
UI: обновить экран канала и треда
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
client.version=1.5.8
|
client.version=1.5.9
|
||||||
server.version=1.4.7
|
server.version=1.4.7
|
||||||
|
|||||||
@@ -209,6 +209,24 @@ function resolveChannelDisplayName(channelSelector) {
|
|||||||
return `${found.channel?.ownerLogin || 'неизвестно'}/${found.channel?.channelName || 'канал'}`;
|
return `${found.channel?.ownerLogin || 'неизвестно'}/${found.channel?.channelName || 'канал'}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveChannelHeadingFromNode(node) {
|
||||||
|
const info = node?.channelInfo;
|
||||||
|
const ownerBch = String(info?.ownerBlockchainName || '').trim();
|
||||||
|
const rootBlockNumber = Number(info?.channelRoot?.blockNumber);
|
||||||
|
if (!ownerBch || !Number.isFinite(rootBlockNumber) || rootBlockNumber < 0) return '';
|
||||||
|
if (rootBlockNumber === 0) return 'История пользователя';
|
||||||
|
|
||||||
|
const label = resolveChannelDisplayName({
|
||||||
|
ownerBlockchainName: ownerBch,
|
||||||
|
channelRootBlockNumber: rootBlockNumber,
|
||||||
|
channelRootBlockHash: '0',
|
||||||
|
});
|
||||||
|
const slashIndex = label.indexOf('/');
|
||||||
|
const channelName = slashIndex >= 0 ? label.slice(slashIndex + 1).trim() : label.trim();
|
||||||
|
if (!channelName) return 'Сообщение в канале';
|
||||||
|
return `Сообщение в канале ${channelName}`;
|
||||||
|
}
|
||||||
|
|
||||||
function extractChannelContextFromThreadPayload(payload) {
|
function extractChannelContextFromThreadPayload(payload) {
|
||||||
const focusInfo = payload?.focus?.channelInfo;
|
const focusInfo = payload?.focus?.channelInfo;
|
||||||
if (focusInfo?.ownerBlockchainName && focusInfo?.channelRoot?.blockNumber != null) {
|
if (focusInfo?.ownerBlockchainName && focusInfo?.channelRoot?.blockNumber != null) {
|
||||||
@@ -706,7 +724,7 @@ function renderNodeCard(node, heading, handlers, localNumber) {
|
|||||||
const isOwnMessage = String(node?.authorLogin || '').trim().toLowerCase() === String(state.session.login || '').trim().toLowerCase();
|
const isOwnMessage = String(node?.authorLogin || '').trim().toLowerCase() === String(state.session.login || '').trim().toLowerCase();
|
||||||
const isChannelPost = Number(node?.channelInfo?.channelRoot?.blockNumber) >= 0;
|
const isChannelPost = Number(node?.channelInfo?.channelRoot?.blockNumber) >= 0;
|
||||||
const msgSubType = Number(node?.msgSubType || 0);
|
const msgSubType = Number(node?.msgSubType || 0);
|
||||||
const repostTarget = msgSubType === 30 ? buildRepostTargetFromNode(node) : null;
|
const repostTarget = msgSubType === 50 ? buildRepostTargetFromNode(node) : null;
|
||||||
const parsedText = parseMessageAttachments(text);
|
const parsedText = parseMessageAttachments(text);
|
||||||
|
|
||||||
const headingText = String(heading || '').trim();
|
const headingText = String(heading || '').trim();
|
||||||
@@ -1326,12 +1344,9 @@ export function render({ navigate, route }) {
|
|||||||
if (ancestors.length) {
|
if (ancestors.length) {
|
||||||
ancestorsWrap = document.createElement('div');
|
ancestorsWrap = document.createElement('div');
|
||||||
ancestorsWrap.className = 'stack thread-block thread-block--ancestors';
|
ancestorsWrap.className = 'stack thread-block thread-block--ancestors';
|
||||||
const title = document.createElement('h3');
|
|
||||||
title.className = 'section-title';
|
|
||||||
title.textContent = 'История выше (на что это ответ)';
|
|
||||||
ancestorsWrap.append(title);
|
|
||||||
ancestors.forEach((node, index) => {
|
ancestors.forEach((node, index) => {
|
||||||
ancestorsWrap.append(renderNodeCard(node, `Предок ${index + 1}`, handlers, nextNumber()));
|
const heading = index === 0 ? resolveChannelHeadingFromNode(node) : '';
|
||||||
|
ancestorsWrap.append(renderNodeCard(node, heading, handlers, nextNumber()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { buildArweaveDataUrl } from '../services/arweave-file-service.js';
|
|||||||
export const pageMeta = { id: 'channel-view', title: 'Канал' };
|
export const pageMeta = { id: 'channel-view', title: 'Канал' };
|
||||||
const CHANNEL_TYPE_STORIES = 0;
|
const CHANNEL_TYPE_STORIES = 0;
|
||||||
const CHANNEL_TYPE_PERSONAL = 100;
|
const CHANNEL_TYPE_PERSONAL = 100;
|
||||||
|
const MSG_SUBTYPE_TEXT_REPOST = 50;
|
||||||
|
|
||||||
const pendingReactionActions = new Set();
|
const pendingReactionActions = new Set();
|
||||||
const pendingScrollByRoute = new Map();
|
const pendingScrollByRoute = new Map();
|
||||||
@@ -303,7 +304,19 @@ function createChannelAvatarElement(channel, size = 72) {
|
|||||||
return wrap;
|
return wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openChannelMetaDetailsModal({ title = 'Данные канала', channel = {}, canEdit = false, onEdit = null } = {}) {
|
function openChannelMetaDetailsModal({
|
||||||
|
title = 'Данные канала',
|
||||||
|
channel = {},
|
||||||
|
canEdit = false,
|
||||||
|
onEdit = null,
|
||||||
|
changedAtMs = 0,
|
||||||
|
} = {}) {
|
||||||
|
const avatarState = String(channel.avaAr || '').trim()
|
||||||
|
? 'Установлен'
|
||||||
|
: 'Не установлен';
|
||||||
|
const changedAtLabel = changedAtMs
|
||||||
|
? new Date(Number(changedAtMs)).toLocaleString('ru-RU')
|
||||||
|
: '—';
|
||||||
const root = document.getElementById('modal-root');
|
const root = document.getElementById('modal-root');
|
||||||
root.innerHTML = `
|
root.innerHTML = `
|
||||||
<div class="modal" id="about-channel-modal">
|
<div class="modal" id="about-channel-modal">
|
||||||
@@ -313,9 +326,14 @@ function openChannelMetaDetailsModal({ title = 'Данные канала', chan
|
|||||||
${canEdit ? '<button class="secondary-btn channel-profile-edit-btn" id="about-channel-edit" type="button" title="Изменить">✏️</button>' : ''}
|
${canEdit ? '<button class="secondary-btn channel-profile-edit-btn" id="about-channel-edit" type="button" title="Изменить">✏️</button>' : ''}
|
||||||
</div>
|
</div>
|
||||||
<div id="about-channel-avatar-slot"></div>
|
<div id="about-channel-avatar-slot"></div>
|
||||||
<p><strong>${escapeHtml(channel.displayTitle || channel.displayName || channel.name)}</strong></p>
|
<div class="channel-meta-details-grid">
|
||||||
<p class="meta-muted">${escapeHtml(`${channel.ownerName || 'автор'} / ${channel.name || 'channel'}`)}</p>
|
<span>Дата</span><strong>${escapeHtml(changedAtLabel)}</strong>
|
||||||
<p class="meta-muted">${escapeHtml(channel.description || 'Описание не задано.')}</p>
|
<span>Владелец</span><strong>${escapeHtml(channel.ownerName || 'автор')}</strong>
|
||||||
|
<span>Системное имя</span><code>${escapeHtml(channel.name || 'channel')}</code>
|
||||||
|
<span>Название</span><strong>${escapeHtml(channel.displayTitle || channel.displayName || channel.name || '—')}</strong>
|
||||||
|
<span>Описание</span><span>${escapeHtml(channel.description || 'Описание не задано.')}</span>
|
||||||
|
<span>Аватар</span><span>${escapeHtml(avatarState)}</span>
|
||||||
|
</div>
|
||||||
<button class="secondary-btn" id="about-channel-close" type="button">Закрыть</button>
|
<button class="secondary-btn" id="about-channel-close" type="button">Закрыть</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -337,6 +355,7 @@ function openAboutChannelModal(channel, options = {}) {
|
|||||||
channel,
|
channel,
|
||||||
canEdit: options.canEdit === true,
|
canEdit: options.canEdit === true,
|
||||||
onEdit: options.onEdit,
|
onEdit: options.onEdit,
|
||||||
|
changedAtMs: Number(channel?.metaUpdatedAtMs || 0),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1181,15 +1200,14 @@ function renderChannelMetaEventCard(event) {
|
|||||||
const card = document.createElement('article');
|
const card = document.createElement('article');
|
||||||
card.className = 'card channel-system-event-card';
|
card.className = 'card channel-system-event-card';
|
||||||
const label = event.kind === 'created'
|
const label = event.kind === 'created'
|
||||||
? `Создан канал ${event.title || event.name || ''}`.trim()
|
? 'Создан канал'
|
||||||
: 'Изменён профиль канала';
|
: 'Изменено описание канала';
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<span>${escapeHtml(label)}</span>
|
<span class="channel-system-event-card__label">${escapeHtml(label)}</span>
|
||||||
<small>${escapeHtml(event.timestampMs ? new Date(event.timestampMs).toLocaleString('ru-RU') : '')}</small>
|
|
||||||
`;
|
`;
|
||||||
card.addEventListener('click', () => {
|
card.addEventListener('click', () => {
|
||||||
openChannelMetaDetailsModal({
|
openChannelMetaDetailsModal({
|
||||||
title: event.kind === 'created' ? 'Канал создан' : 'Профиль канала изменён',
|
title: label,
|
||||||
channel: {
|
channel: {
|
||||||
name: event.name,
|
name: event.name,
|
||||||
displayTitle: event.title,
|
displayTitle: event.title,
|
||||||
@@ -1199,6 +1217,7 @@ function renderChannelMetaEventCard(event) {
|
|||||||
avaSize: event.avaSize,
|
avaSize: event.avaSize,
|
||||||
ownerName: event.ownerName,
|
ownerName: event.ownerName,
|
||||||
},
|
},
|
||||||
|
changedAtMs: event.timestampMs,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return card;
|
return card;
|
||||||
@@ -1377,7 +1396,7 @@ function renderPostCard(post, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
actions.append(shareButton);
|
actions.append(shareButton);
|
||||||
if (post.msgSubType === 30 && post.targetRef?.blockchainName && Number.isFinite(post.targetRef?.blockNumber) && post.targetRef?.blockHash) {
|
if (post.msgSubType === MSG_SUBTYPE_TEXT_REPOST && post.targetRef?.blockchainName && Number.isFinite(post.targetRef?.blockNumber) && post.targetRef?.blockHash) {
|
||||||
const originalBtn = document.createElement('button');
|
const originalBtn = document.createElement('button');
|
||||||
originalBtn.type = 'button';
|
originalBtn.type = 'button';
|
||||||
originalBtn.className = 'channel-action-item';
|
originalBtn.className = 'channel-action-item';
|
||||||
@@ -1797,7 +1816,7 @@ export function render({ navigate, route }) {
|
|||||||
channelHeaderButton.onclick = (event) => {
|
channelHeaderButton.onclick = (event) => {
|
||||||
animatePress(event.currentTarget);
|
animatePress(event.currentTarget);
|
||||||
openAboutChannelModal(apiData.channel, {
|
openAboutChannelModal(apiData.channel, {
|
||||||
canEdit: apiData?.isOwnChannel === true,
|
canEdit: apiData?.isOwnChannel === true && !isStoriesChannel(apiData?.channel),
|
||||||
onEdit: () => openEditChannelModal({
|
onEdit: () => openEditChannelModal({
|
||||||
channel: apiData.channel,
|
channel: apiData.channel,
|
||||||
onSave: onEditChannelMeta,
|
onSave: onEditChannelMeta,
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ const MSG_SUBTYPE_TEXT_POST = 10;
|
|||||||
const MSG_SUBTYPE_TEXT_EDIT_POST = 11;
|
const MSG_SUBTYPE_TEXT_EDIT_POST = 11;
|
||||||
const MSG_SUBTYPE_TEXT_REPLY = 20;
|
const MSG_SUBTYPE_TEXT_REPLY = 20;
|
||||||
const MSG_SUBTYPE_TEXT_EDIT_REPLY = 21;
|
const MSG_SUBTYPE_TEXT_EDIT_REPLY = 21;
|
||||||
const MSG_SUBTYPE_TEXT_REPOST = 30;
|
const MSG_SUBTYPE_TEXT_RATING = 30;
|
||||||
const MSG_SUBTYPE_TEXT_CHANNEL_META = 70;
|
const MSG_SUBTYPE_TEXT_REPOST = 50;
|
||||||
|
const MSG_SUBTYPE_TEXT_CHANNEL_META = 90;
|
||||||
const MSG_SUBTYPE_REACTION_LIKE = 1;
|
const MSG_SUBTYPE_REACTION_LIKE = 1;
|
||||||
const MSG_SUBTYPE_REACTION_UNLIKE = 2;
|
const MSG_SUBTYPE_REACTION_UNLIKE = 2;
|
||||||
const MSG_SUBTYPE_CONNECTION_FOLLOW = 30;
|
const MSG_SUBTYPE_CONNECTION_FOLLOW = 30;
|
||||||
|
|||||||
@@ -3939,6 +3939,12 @@ textarea.input {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channels-screen--channel .channel-feed {
|
||||||
|
gap: 2px;
|
||||||
|
margin-left: -7px;
|
||||||
|
margin-right: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
.channels-screen .channel-message-card {
|
.channels-screen .channel-message-card {
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@@ -3950,6 +3956,10 @@ textarea.input {
|
|||||||
box-shadow: 0 0 60px rgba(80, 60, 180, 0.15);
|
box-shadow: 0 0 60px rgba(80, 60, 180, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channels-screen--channel .channel-message-card {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.channel-message-top {
|
.channel-message-top {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -4037,19 +4047,41 @@ textarea.input {
|
|||||||
.channel-system-event-card {
|
.channel-system-event-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 9px 11px;
|
width: fit-content;
|
||||||
|
max-width: min(88%, 460px);
|
||||||
|
margin: 0 auto 4px;
|
||||||
|
padding: 8px 16px;
|
||||||
border-color: rgba(255, 210, 130, 0.22);
|
border-color: rgba(255, 210, 130, 0.22);
|
||||||
background: rgba(89, 67, 31, 0.22);
|
border-radius: 999px;
|
||||||
|
background: rgba(89, 67, 31, 0.26);
|
||||||
color: rgba(255, 235, 188, 0.92);
|
color: rgba(255, 235, 188, 0.92);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-system-event-card small {
|
.channel-system-event-card__label {
|
||||||
flex: 0 0 auto;
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-meta-details-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(96px, 120px) 1fr;
|
||||||
|
gap: 10px 14px;
|
||||||
|
align-items: start;
|
||||||
|
color: rgba(255, 255, 255, 0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-meta-details-grid > span:nth-child(odd) {
|
||||||
color: rgba(255, 255, 255, 0.48);
|
color: rgba(255, 255, 255, 0.48);
|
||||||
font-size: 11px;
|
}
|
||||||
|
|
||||||
|
.channel-meta-details-grid code {
|
||||||
|
color: rgba(255, 214, 117, 0.92);
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-profile-card {
|
.channel-profile-card {
|
||||||
@@ -5331,6 +5363,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal.modal,
|
#about-channel-modal.modal,
|
||||||
|
#edit-channel-modal.modal,
|
||||||
#reply-modal.modal,
|
#reply-modal.modal,
|
||||||
#channel-message-modal.modal,
|
#channel-message-modal.modal,
|
||||||
#channel-edit-description-modal.modal,
|
#channel-edit-description-modal.modal,
|
||||||
@@ -5342,6 +5375,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal .modal-card,
|
#about-channel-modal .modal-card,
|
||||||
|
#edit-channel-modal .modal-card,
|
||||||
#reply-modal .modal-card,
|
#reply-modal .modal-card,
|
||||||
#channel-message-modal .modal-card,
|
#channel-message-modal .modal-card,
|
||||||
#channel-edit-description-modal .modal-card,
|
#channel-edit-description-modal .modal-card,
|
||||||
@@ -5356,6 +5390,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal .modal-title,
|
#about-channel-modal .modal-title,
|
||||||
|
#edit-channel-modal .modal-title,
|
||||||
#reply-modal .modal-title,
|
#reply-modal .modal-title,
|
||||||
#channel-message-modal .modal-title,
|
#channel-message-modal .modal-title,
|
||||||
#channel-edit-description-modal .modal-title,
|
#channel-edit-description-modal .modal-title,
|
||||||
@@ -5368,6 +5403,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal .input,
|
#about-channel-modal .input,
|
||||||
|
#edit-channel-modal .input,
|
||||||
#reply-modal .input,
|
#reply-modal .input,
|
||||||
#channel-message-modal .input,
|
#channel-message-modal .input,
|
||||||
#channel-edit-description-modal .input,
|
#channel-edit-description-modal .input,
|
||||||
@@ -5390,6 +5426,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal .secondary-btn,
|
#about-channel-modal .secondary-btn,
|
||||||
|
#edit-channel-modal .secondary-btn,
|
||||||
#reply-modal .secondary-btn,
|
#reply-modal .secondary-btn,
|
||||||
#channel-message-modal .secondary-btn,
|
#channel-message-modal .secondary-btn,
|
||||||
#channel-edit-description-modal .secondary-btn,
|
#channel-edit-description-modal .secondary-btn,
|
||||||
@@ -5403,6 +5440,7 @@ textarea.input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#about-channel-modal .primary-btn,
|
#about-channel-modal .primary-btn,
|
||||||
|
#edit-channel-modal .primary-btn,
|
||||||
#reply-modal .primary-btn,
|
#reply-modal .primary-btn,
|
||||||
#channel-message-modal .primary-btn,
|
#channel-message-modal .primary-btn,
|
||||||
#channel-edit-description-modal .primary-btn,
|
#channel-edit-description-modal .primary-btn,
|
||||||
|
|||||||
Reference in New Issue
Block a user