lvwerra HF Staff commited on
Commit
9ac475c
·
verified ·
1 Parent(s): 9cf5b99

Deploy msgboard

Browse files
Files changed (1) hide show
  1. src/msgboard/dashboard.html +24 -7
src/msgboard/dashboard.html CHANGED
@@ -1150,24 +1150,41 @@ const avatar = (s, cls = "", link = true) => {
1150
  (s.identity_type === "system" ? dashedBorderSvg(S) : "") + `</div>`;
1151
  };
1152
  const pictures = new Map();
 
 
 
 
 
 
 
 
 
1153
  function hydrateBoardImages(root) {
1154
  root.querySelectorAll(".board-img[data-file]:not([data-done])").forEach(async (el) => {
1155
  el.dataset.done = "1";
1156
  const id = el.dataset.file;
 
1157
  try {
1158
  const info = await getInfo(id), blob = await getBlob(id, info);
1159
  if (!info || kindOf(info.filename, info.content_type) !== "image") throw new Error("not an image");
1160
- const img = document.createElement("img"); img.alt = el.title || info.filename; img.src = URL.createObjectURL(typed(blob, info));
1161
- img.onclick = () => openViewer([id], 0);
1162
- el.replaceChildren(img); el.classList.add("ready");
1163
- } catch { el.innerHTML = `<a href="#" data-board-file="${esc(id)}">📎 ${esc(id.split("/").pop())}</a>`; }
 
 
 
 
 
 
 
1164
  });
1165
  }
1166
  // Safari (macOS overlay scrollbars) draws a code block's sideways scrollbar over its last line;
1167
- // blocks that actually scroll get room below the text for it
 
1168
  function markScrollingCode(root) {
1169
- requestAnimationFrame(() => root.querySelectorAll(".body pre").forEach((pre) =>
1170
- pre.classList.toggle("hscroll", pre.scrollWidth > pre.clientWidth + 1)));
1171
  }
1172
  let codeResizeTimer = null;
1173
  window.addEventListener("resize", () => { clearTimeout(codeResizeTimer); codeResizeTimer = setTimeout(() => markScrollingCode(document), 150); });
 
1150
  (s.identity_type === "system" ? dashedBorderSvg(S) : "") + `</div>`;
1151
  };
1152
  const pictures = new Map();
1153
+ // Inline images, once loaded, are remembered with their size: every re-render of a feed puts them back at full
1154
+ // size right away instead of a placeholder that grows later and pushes the messages around.
1155
+ const boardImgs = new Map(); // file id -> { url, w, h, alt }
1156
+ function boardImgEl(id, r) {
1157
+ const img = document.createElement("img"); img.alt = r.alt; img.src = r.url;
1158
+ img.style.cssText = `aspect-ratio: ${r.w} / ${r.h}; width: min(100%, 640px, ${r.w}px, ${Math.floor(420 * r.w / r.h)}px); height: auto;`;
1159
+ img.onclick = () => openViewer([id], 0);
1160
+ return img;
1161
+ }
1162
  function hydrateBoardImages(root) {
1163
  root.querySelectorAll(".board-img[data-file]:not([data-done])").forEach(async (el) => {
1164
  el.dataset.done = "1";
1165
  const id = el.dataset.file;
1166
+ if (boardImgs.has(id)) { el.replaceChildren(boardImgEl(id, boardImgs.get(id))); el.classList.add("ready"); return; }
1167
  try {
1168
  const info = await getInfo(id), blob = await getBlob(id, info);
1169
  if (!info || kindOf(info.filename, info.content_type) !== "image") throw new Error("not an image");
1170
+ const url = URL.createObjectURL(typed(blob, info)), probe = new Image();
1171
+ probe.src = url; await probe.decode();
1172
+ const r = { url, w: probe.naturalWidth || 1, h: probe.naturalHeight || 1, alt: el.title || info.filename };
1173
+ boardImgs.set(id, r);
1174
+ if (!el.isConnected) return;
1175
+ // first load: the placeholder grows into the image, so keep the reader's place (or the bottom) by hand;
1176
+ // Safari has no built-in scroll anchoring
1177
+ const sc = el.closest(".scroll"), atBottom = sc && nearBottom(sc), restore = sc && !atBottom ? keepAnchor(sc) : null;
1178
+ el.replaceChildren(boardImgEl(id, r)); el.classList.add("ready");
1179
+ if (atBottom) sc.scrollTop = sc.scrollHeight; else if (restore) restore();
1180
+ } catch { if (el.isConnected) el.innerHTML = `<a href="#" data-board-file="${esc(id)}">📎 ${esc(id.split("/").pop())}</a>`; }
1181
  });
1182
  }
1183
  // Safari (macOS overlay scrollbars) draws a code block's sideways scrollbar over its last line;
1184
+ // blocks that actually scroll get room below the text for it. Done right away, not on the next frame, so a
1185
+ // re-render has its final height before the scroll position is restored.
1186
  function markScrollingCode(root) {
1187
+ root.querySelectorAll(".body pre").forEach((pre) => pre.classList.toggle("hscroll", pre.scrollWidth > pre.clientWidth + 1));
 
1188
  }
1189
  let codeResizeTimer = null;
1190
  window.addEventListener("resize", () => { clearTimeout(codeResizeTimer); codeResizeTimer = setTimeout(() => markScrollingCode(document), 150); });