diff --git a/src/components/status.css b/src/components/status.css index 9d5f7560..2c50b04a 100644 --- a/src/components/status.css +++ b/src/components/status.css @@ -149,7 +149,7 @@ margin: 4px 0 0 0; gap: 4px; align-items: center; - color: var(--reply-to-color); + color: var(--reply-to-text-color); background: var(--bg-color); border: 1px solid var(--reply-to-color); border-radius: 4px; diff --git a/src/components/status.jsx b/src/components/status.jsx index a6bb7f3f..2b246b80 100644 --- a/src/components/status.jsx +++ b/src/components/status.jsx @@ -270,30 +270,32 @@ function Status({ </span> ))} </div> - {!!inReplyToId && - !!inReplyToAccountId && - !withinContext && - size !== 's' && ( - <> - {inReplyToAccountId === status.account.id ? ( - <div class="status-thread-badge"> - <Icon icon="thread" size="s" /> - Thread + {!withinContext && size !== 's' && ( + <> + {inReplyToAccountId === status.account?.id || + !!snapStates.statusThreadNumber[id] ? ( + <div class="status-thread-badge"> + <Icon icon="thread" size="s" /> + Thread + {snapStates.statusThreadNumber[id] + ? ` ${snapStates.statusThreadNumber[id]}/X` + : ''} + </div> + ) : ( + !!inReplyToId && + !!inReplyToAccount && + (!!spoilerText || + !mentions.find((mention) => { + return mention.id === inReplyToAccountId; + })) && ( + <div class="status-reply-badge"> + <Icon icon="reply" />{' '} + <NameText account={inReplyToAccount} short /> </div> - ) : ( - !!inReplyToAccount && - (!!spoilerText || - !mentions.find((mention) => { - return mention.id === inReplyToAccountId; - })) && ( - <div class="status-reply-badge"> - <Icon icon="reply" />{' '} - <NameText account={inReplyToAccount} short /> - </div> - ) - )} - </> - )} + ) + )} + </> + )} <div class={`content-container ${ sensitive || spoilerText ? 'has-spoiler' : '' diff --git a/src/index.css b/src/index.css index d8230b9c..e592aef5 100644 --- a/src/index.css +++ b/src/index.css @@ -24,6 +24,7 @@ --reblog-color: var(--purple-color); --reblog-faded-color: #892be220; --reply-to-color: var(--orange-color); + --reply-to-text-color: #b36200; --favourite-color: var(--red-color); --reply-to-faded-color: #ffa6001a; --outline-color: rgba(128, 128, 128, 0.2); diff --git a/src/utils/states.js b/src/utils/states.js index 2c52034c..4c37863c 100644 --- a/src/utils/states.js +++ b/src/utils/states.js @@ -3,6 +3,7 @@ import { proxy } from 'valtio'; const states = proxy({ history: [], statuses: {}, + statusThreadNumber: {}, home: [], homeNew: [], homeLastFetchTime: null, @@ -22,11 +23,57 @@ const states = proxy({ export default states; export function saveStatus(status, opts) { - const { override } = Object.assign({ override: true }, opts); + const { override, skipThreading } = Object.assign( + { override: true, skipThreading: false }, + opts, + ); if (!status) return; if (!override && states.statuses[status.id]) return; states.statuses[status.id] = status; if (status.reblog) { states.statuses[status.reblog.id] = status.reblog; } + + // THREAD TRAVERSER + if (!skipThreading) { + requestAnimationFrame(() => { + threadifyStatus(status); + }); + } +} + +function threadifyStatus(status) { + // Return all statuses in the thread, via inReplyToId, if inReplyToAccountId === account.id + let fetchIndex = 0; + async function traverse(status, index = 0) { + const { inReplyToId, inReplyToAccountId } = status; + if (!inReplyToId || inReplyToAccountId !== status.account.id) { + return [status]; + } + if (inReplyToId && inReplyToAccountId !== status.account.id) { + throw 'Not a thread'; + // Possibly thread of replies by multiple people? + } + let prevStatus = states.statuses[inReplyToId]; + if (!prevStatus) { + if (fetchIndex++ > 3) throw 'Too many fetches for thread'; // Some people revive old threads + await new Promise((r) => setTimeout(r, 500 * fetchIndex)); // Be nice to rate limits + prevStatus = await masto.v1.statuses.fetch(inReplyToId); + saveStatus(prevStatus, { skipThreading: true }); + } + // Prepend so that first status in thread will be index 0 + return [...(await traverse(prevStatus, ++index)), status]; + } + return traverse(status) + .then((statuses) => { + if (statuses.length > 1) { + console.debug('THREAD', statuses); + statuses.forEach((status, index) => { + states.statusThreadNumber[status.id] = index + 1; + }); + } + }) + .catch((e) => { + console.error(e, status); + }); }