aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js30
1 files changed, 26 insertions, 4 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 030d9fa..a35c0da 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -9309,7 +9309,7 @@ export function messagesFeature(ctx) {
};
return h('div', { class: 'col live-page', style: 'gap:12px' },
ctx.brandHeader(!ui.pubProf && wallet.loaded),
- h('div', { class: 'card col', style: 'gap:10px' },
+ h('div', { class: 'card col live-main', style: 'gap:10px' },
h('div', { class: 'row gap6', style: 'align-items:center' },
mine ? h('button', { class: 'iconbtn chat-back', onClick: () => { if (confirm(t('goLiveEndAsk'))) endBroadcast(); } }, '‹')
: backBtn(() => { ui.liveStream = null; }),
@@ -9361,7 +9361,7 @@ export function messagesFeature(ctx) {
watchersRow(w),
liveSummary(ev) ? h('div', { class: 'small muted', style: 'white-space:pre-wrap;overflow-wrap:anywhere' }, liveSummary(ev).slice(0, 600)) : null,
ui.liveReport && ui.liveReport.a === s.a ? liveReportPanel(ev) : null),
- h('div', { class: 'card col', style: 'gap:8px' },
+ h('div', { class: 'card col live-chat-card', style: 'gap:8px' },
h('div', { class: 'small muted' }, t('liveChat')),
h('div', {
class: 'live-chat', 'data-key': 'live-chat:' + s.a,
@@ -13498,7 +13498,9 @@ export function messagesFeature(ctx) {
const key = mediaIdxKey(feedId);
let r = mediaIdx.get(key);
if (r) return r;
- r = { key, replies: !!(feedDef(feedId) || {}).replies, images: new Map(), videos: new Map(), articles: new Map(), art: { until: 0, end: 0, empty: 0, head: 0 }, checked: new Set(), until: 0, end: false, empty: 0, loaded: false };
+ const order = () => ({ seq: new Map(), top: 0, bottom: 0, newest: 0 });
+ r = { key, replies: !!(feedDef(feedId) || {}).replies, images: new Map(), videos: new Map(), articles: new Map(), art: { until: 0, end: 0, empty: 0, head: 0 }, checked: new Set(), until: 0, end: false, empty: 0, loaded: false,
+ order: { images: order(), videos: order() } };
mediaIdx.set(key, r);
loadMediaIndex(key).then(async (rec) => {
if (rec) {
@@ -14037,7 +14039,27 @@ export function messagesFeature(ctx) {
out.push({ ev, url });
}
}
- return out;
+ return settledOrder(r, kind, out);
+ }
+ // The grid's order holds for the session (Adam, 2026-10-23: clips the
+ // crawl found landed in the middle of the grid, above an older tail the
+ // index had from before, and the tiles already there jumped): what it
+ // shows first is newest first, and whatever turns up after goes under what
+ // is already there, in its own date order. Only a post newer than the top
+ // tile goes above it. Nothing is settled until the kept index is in, so
+ // the first paint is one date order, not two batches.
+ function settledOrder(r, kind, out) {
+ if (!r.loaded) return out;
+ const o = r.order[kind];
+ const key = (it) => it.ev.id + '|' + it.url;
+ const fresh = out.filter((it) => !o.seq.has(key(it)));
+ if (fresh.length) {
+ const above = o.seq.size ? fresh.filter((it) => it.ev.created_at > o.newest) : [];
+ for (const it of above.reverse()) o.seq.set(key(it), --o.top);
+ for (const it of fresh) if (!o.seq.has(key(it))) o.seq.set(key(it), ++o.bottom);
+ for (const it of fresh) if (it.ev.created_at > o.newest) o.newest = it.ev.created_at;
+ }
+ return out.sort((a, b) => o.seq.get(key(a)) - o.seq.get(key(b)));
}
// The feed's pictures (or clips) in reading order — every one of a post
// before the next post's — for the pager opened from one in the feed: the