feat(thread): переход в тред ответа и явная история сверху
This commit is contained in:
parent
49ebf1605a
commit
580bd6fbeb
@ -0,0 +1,19 @@
|
|||||||
|
# Навигация по тредам и история сообщения
|
||||||
|
|
||||||
|
Статус: `pending`
|
||||||
|
|
||||||
|
## Краткое описание
|
||||||
|
В экране треда добавлен явный переход `🧵 В тред` для каждого сообщения (включая ответы), чтобы можно было углубляться в любую ветку обсуждения.
|
||||||
|
Также уточнены заголовки блоков: сверху история сообщений, отдельно текущее сообщение.
|
||||||
|
|
||||||
|
## Что проверять
|
||||||
|
1. Открыть любой канал и перейти в тред сообщения.
|
||||||
|
2. Нажать `🧵 В тред` у одного из ответов.
|
||||||
|
3. Убедиться, что открывается тред выбранного ответа, а не исходного сообщения.
|
||||||
|
4. Проверить, что в новом треде сверху показывается блок истории (`История выше...`), затем блок `Текущее сообщение`, затем `Ответы`.
|
||||||
|
5. Проверить на мобильной ширине, что кнопки действий в карточке не ломают верстку.
|
||||||
|
|
||||||
|
## Ожидаемый результат
|
||||||
|
- Переход в тред ответа работает стабильно для всех узлов дерева.
|
||||||
|
- Пользователь видит структуру треда в логичном порядке: предки → текущее сообщение → потомки.
|
||||||
|
- UI остаётся читаемым на мобильных экранах.
|
||||||
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.62
|
client.version=1.2.63
|
||||||
server.version=1.2.56
|
server.version=1.2.57
|
||||||
|
|||||||
@ -391,7 +391,17 @@ function renderNodeCard(node, heading, handlers, localNumber) {
|
|||||||
await handlers.onShare(target);
|
await handlers.onShare(target);
|
||||||
});
|
});
|
||||||
|
|
||||||
actions.append(likeButton, replyButton, changedButton, shareButton);
|
const openThreadButton = document.createElement('button');
|
||||||
|
openThreadButton.type = 'button';
|
||||||
|
openThreadButton.className = 'secondary-btn thread-open-btn';
|
||||||
|
openThreadButton.textContent = '🧵 В тред';
|
||||||
|
openThreadButton.addEventListener('click', (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
animatePress(event.currentTarget);
|
||||||
|
handlers.onOpenThread(target);
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.append(likeButton, replyButton, changedButton, shareButton, openThreadButton);
|
||||||
card.append(actions);
|
card.append(actions);
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
@ -559,6 +569,14 @@ export function render({ navigate, route }) {
|
|||||||
showStatus(toUserMessage(error, 'Не удалось транслировать ссылку.'));
|
showStatus(toUserMessage(error, 'Не удалось транслировать ссылку.'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onOpenThread: (target) => {
|
||||||
|
const routePath = buildThreadRouteFromTarget(target, selector);
|
||||||
|
if (!routePath) {
|
||||||
|
showStatus('Не удалось определить путь до треда.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigate(routePath);
|
||||||
|
},
|
||||||
onActionError: (error, action) => {
|
onActionError: (error, action) => {
|
||||||
const fallback = action === 'unlike'
|
const fallback = action === 'unlike'
|
||||||
? 'Не удалось убрать лайк.'
|
? 'Не удалось убрать лайк.'
|
||||||
@ -683,7 +701,7 @@ export function render({ navigate, route }) {
|
|||||||
ancestorsWrap.className = 'stack thread-block thread-block--ancestors';
|
ancestorsWrap.className = 'stack thread-block thread-block--ancestors';
|
||||||
const title = document.createElement('h3');
|
const title = document.createElement('h3');
|
||||||
title.className = 'section-title';
|
title.className = 'section-title';
|
||||||
title.textContent = 'Предыдущие сообщения';
|
title.textContent = 'История выше (на что это ответ)';
|
||||||
ancestorsWrap.append(title);
|
ancestorsWrap.append(title);
|
||||||
ancestors.forEach((node, index) => {
|
ancestors.forEach((node, index) => {
|
||||||
ancestorsWrap.append(renderNodeCard(node, `Предок ${index + 1}`, handlers, nextNumber()));
|
ancestorsWrap.append(renderNodeCard(node, `Предок ${index + 1}`, handlers, nextNumber()));
|
||||||
@ -694,6 +712,10 @@ export function render({ navigate, route }) {
|
|||||||
if (focus) {
|
if (focus) {
|
||||||
const focusWrap = document.createElement('div');
|
const focusWrap = document.createElement('div');
|
||||||
focusWrap.className = 'stack thread-block thread-block--focus';
|
focusWrap.className = 'stack thread-block thread-block--focus';
|
||||||
|
const focusTitle = document.createElement('h3');
|
||||||
|
focusTitle.className = 'section-title';
|
||||||
|
focusTitle.textContent = 'Текущее сообщение';
|
||||||
|
focusWrap.append(focusTitle);
|
||||||
focusWrap.append(renderNodeCard(focus, '', handlers, nextNumber()));
|
focusWrap.append(renderNodeCard(focus, '', handlers, nextNumber()));
|
||||||
screen.append(focusWrap);
|
screen.append(focusWrap);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2356,7 +2356,7 @@ textarea.input {
|
|||||||
|
|
||||||
.thread-node-actions {
|
.thread-node-actions {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2439,6 +2439,10 @@ textarea.input {
|
|||||||
color: rgba(255, 255, 255, 0.55);
|
color: rgba(255, 255, 255, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thread-open-btn {
|
||||||
|
color: rgba(255, 255, 255, 0.62);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 430px) {
|
@media (max-width: 430px) {
|
||||||
.channels-screen .page-title {
|
.channels-screen .page-title {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user