web: add jump-to-message navigation from thread panel
Some checks failed
CI / test (push) Has been cancelled
Some checks failed
CI / test (push) Has been cancelled
This commit is contained in:
@@ -16,7 +16,7 @@ Legend:
|
|||||||
7. Chat Creation - `DONE` (private/group/channel)
|
7. Chat Creation - `DONE` (private/group/channel)
|
||||||
8. Messages (base) - `DONE` (send/read/edit/delete/delete for all; 7-day edit window enforced and covered by integration tests; group UI shows sender names over bubbles + sender avatars on incoming message clusters)
|
8. Messages (base) - `DONE` (send/read/edit/delete/delete for all; 7-day edit window enforced and covered by integration tests; group UI shows sender names over bubbles + sender avatars on incoming message clusters)
|
||||||
9. Message Types - `PARTIAL` (text/photo/video/docs/audio/voice/circle; GIF/stickers via dedicated system missing)
|
9. Message Types - `PARTIAL` (text/photo/video/docs/audio/voice/circle; GIF/stickers via dedicated system missing)
|
||||||
10. Reply/Quote/Threads - `PARTIAL` (reply + quote-like UI + thread panel with nested replies, no dedicated full thread navigation yet)
|
10. Reply/Quote/Threads - `PARTIAL` (reply + quote-like UI + thread panel with nested replies; web thread panel now supports direct `Jump in chat` navigation to any thread message; dedicated full standalone thread route is still pending)
|
||||||
11. Forwarding - `DONE` (single + bulk + without author)
|
11. Forwarding - `DONE` (single + bulk + without author)
|
||||||
12. Pinning - `DONE` (message/chat pin-unpin)
|
12. Pinning - `DONE` (message/chat pin-unpin)
|
||||||
13. Reactions - `DONE`
|
13. Reactions - `DONE`
|
||||||
|
|||||||
@@ -310,6 +310,11 @@ export function MessageList() {
|
|||||||
container.scrollTo({ top: container.scrollHeight, behavior: "smooth" });
|
container.scrollTo({ top: container.scrollHeight, behavior: "smooth" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jumpToMessageInChat(messageId: number) {
|
||||||
|
setFocusedMessage(chatId, messageId);
|
||||||
|
setThreadRootId(null);
|
||||||
|
}
|
||||||
|
|
||||||
async function ensureReactionsLoaded(messageId: number) {
|
async function ensureReactionsLoaded(messageId: number) {
|
||||||
if (reactionsByMessage[messageId]) {
|
if (reactionsByMessage[messageId]) {
|
||||||
return;
|
return;
|
||||||
@@ -956,13 +961,26 @@ export function MessageList() {
|
|||||||
const indent = Math.min(6, depth) * 14;
|
const indent = Math.min(6, depth) * 14;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`rounded-xl border px-3 py-2 ${isRoot ? "border-sky-400/60 bg-sky-500/10" : "border-slate-700/70 bg-slate-800/60"}`}
|
className={`cursor-pointer rounded-xl border px-3 py-2 transition-colors ${isRoot ? "border-sky-400/60 bg-sky-500/10" : "border-slate-700/70 bg-slate-800/60 hover:bg-slate-800/80"}`}
|
||||||
key={`thread-${threadMessage.id}`}
|
key={`thread-${threadMessage.id}`}
|
||||||
|
onClick={() => jumpToMessageInChat(threadMessage.id)}
|
||||||
style={{ marginLeft: `${indent}px` }}
|
style={{ marginLeft: `${indent}px` }}
|
||||||
>
|
>
|
||||||
<p className={`mb-1 text-[11px] ${own ? "text-sky-300" : "text-slate-400"}`}>
|
<div className="mb-1 flex items-center justify-between gap-2">
|
||||||
{isRoot ? "Original message" : `Reply • level ${depth}`} • {formatTime(threadMessage.created_at)}
|
<p className={`text-[11px] ${own ? "text-sky-300" : "text-slate-400"}`}>
|
||||||
</p>
|
{isRoot ? "Original message" : `Reply • level ${depth}`} • {formatTime(threadMessage.created_at)}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
className="rounded bg-slate-700/80 px-2 py-1 text-[10px] font-semibold text-slate-200 hover:bg-slate-600"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
jumpToMessageInChat(threadMessage.id);
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Jump in chat
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div className={own ? "text-slate-100" : "text-slate-200"}>
|
<div className={own ? "text-slate-100" : "text-slate-200"}>
|
||||||
{renderMessageContent(threadMessage, {
|
{renderMessageContent(threadMessage, {
|
||||||
attachments: attachmentsByMessage[threadMessage.id] ?? [],
|
attachments: attachmentsByMessage[threadMessage.id] ?? [],
|
||||||
|
|||||||
Reference in New Issue
Block a user