UI: обновить thread/counters, вкладку Каналы и сценарий просмотра+подписки

This commit is contained in:
AidarKC
2026-05-14 12:46:22 +03:00
parent a2954071bd
commit c0b0c99f53
6 changed files with 129 additions and 91 deletions
+39 -26
View File
@@ -17,7 +17,7 @@ const CREATE_CHANNEL_FLASH_KEY = 'shine-channels-create-success';
const MENU_OVERLAY_ID = 'channels-context-menu-overlay';
const CHANNEL_TYPE_STORIES = 0;
const CHANNEL_TYPE_PERSONAL = 100;
const TAB_ORDER = ['feed', 'dialogs', 'my'];
const TAB_ORDER = ['dialogs', 'feed', 'my'];
function isChannelsDemoMode() {
try {
@@ -98,15 +98,6 @@ async function resolveChannelTargetFromInput(rawInput) {
const input = String(rawInput || '').trim();
if (!input) throw new Error('Введите канал.');
const bySelector = input.match(/^([A-Za-z0-9._-]+-\d+)\s*[:/]\s*(\d+)\s*[:/]\s*([A-Fa-f0-9]{1,64})$/);
if (bySelector) {
return {
ownerBlockchainName: bySelector[1],
rootBlockNumber: Number(bySelector[2]),
rootBlockHash: normalizeHash(bySelector[3]),
};
}
const byOwnerAndName = input.match(/^@?([^/#\s]+)\s*\/\s*#?(.+)$/);
if (byOwnerAndName) {
const ownerLogin = normalizeLoginInput(byOwnerAndName[1]);
@@ -242,7 +233,7 @@ function isFollowedChannelVisible(target) {
function openSimpleSubscribeModal({ kind, kindLabel, submitLabel, unfollow = false, onSuccess }) {
const targetHint = kind === 'channel'
? '<p class="meta-muted">Канал: user/channel, имя канала или bch:number:hash.</p>'
? '<p class="meta-muted">Канал: user/channel или имя канала.</p>'
: '<p class="meta-muted">Автор: @login или login.</p>';
const submitText = submitLabel || (unfollow ? 'Отписаться' : 'Подписаться');
const placeholder = kind === 'channel' ? '@owner/channel' : '@login';
@@ -457,6 +448,38 @@ function openChannelFinderModal({ navigate }) {
});
};
const renderChannelRows = (values) => {
channelsEl.innerHTML = '';
if (!values.length) {
channelsEl.style.display = 'none';
return;
}
channelsEl.style.display = '';
values.forEach((item) => {
const row = document.createElement('div');
row.className = 'channel-search-item';
const label = document.createElement('span');
label.textContent = item.label;
const openBtn = document.createElement('button');
openBtn.type = 'button';
openBtn.className = 'secondary-btn small-btn';
openBtn.textContent = 'Просмотреть';
openBtn.addEventListener('click', () => {
close();
navigate(`channel/${encodeRoutePart(item.ownerLogin)}/${encodeRoutePart(item.channelName)}`);
});
row.style.display = 'flex';
row.style.alignItems = 'center';
row.style.justifyContent = 'space-between';
row.style.gap = '8px';
row.append(label, openBtn);
channelsEl.append(row);
});
};
const loadChannelsForLogin = async (login, filterChannel = '') => {
const ownerLogin = normalizeLoginInput(login);
if (!ownerLogin) return;
@@ -469,10 +492,7 @@ function openChannelFinderModal({ navigate }) {
.filter((name) => !needle || name.toLowerCase().includes(needle))
.slice(0, 200)
.map((name) => ({ label: `${ownerLogin}/${name}`, ownerLogin, channelName: name }));
renderButtons(channelsEl, channels, (item) => {
close();
navigate(`channel/${encodeRoutePart(item.ownerLogin)}/${encodeRoutePart(item.channelName)}`);
});
renderChannelRows(channels);
};
const refresh = createDebounced(async () => {
@@ -999,19 +1019,14 @@ function renderListContent({ screen, container, listState, navigate, refreshFeed
container.append(list);
}
function updateBottomCta({ button, listState, navigate, onReload, isTabEmpty = false }) {
function updateBottomCta({ button, listState, navigate, isTabEmpty = false }) {
const tab = listState.activeTab;
const baseClass = `primary-btn channels-bottom-action${isTabEmpty && tab !== 'my' ? ' is-empty-lift' : ''}`;
if (tab === 'feed') {
button.textContent = 'Подписаться на канал';
button.textContent = 'Найти канал';
button.className = baseClass;
button.onclick = () => openSimpleSubscribeModal({
kind: 'channel',
kindLabel: 'Подписка на канал',
submitLabel: 'Подписаться',
onSuccess: onReload,
});
button.onclick = () => openChannelFinderModal({ navigate });
return;
}
@@ -1078,7 +1093,7 @@ export function render({ navigate, route }) {
const listState = {
activeTab: TAB_ORDER.includes(String(route?.params?.mode || '').trim())
? String(route?.params?.mode).trim()
: 'dialogs',
: 'feed',
openMenuId: null,
notificationsState,
revealedCounters: new Set(),
@@ -1140,7 +1155,6 @@ export function render({ navigate, route }) {
button: bottomCta,
listState,
navigate,
onReload: reloadFeed,
isTabEmpty,
});
tabsEl.querySelectorAll('.channels-tab-btn').forEach((btn, idx) => {
@@ -1180,7 +1194,6 @@ export function render({ navigate, route }) {
button: bottomCta,
listState,
navigate,
onReload: reloadFeed,
isTabEmpty: true,
});