SHA256
UI: обновить thread/counters, вкладку Каналы и сценарий просмотра+подписки
This commit is contained in:
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user