eleven / messenger Public

web: app avatar no longer shows a prior photo behind its logo (#1025)

appGlyphInto set innerHTML/textContent but never cleared a leftover
inline background-image, so switching from a photo-avatar app-thread
(Eleven, wears the app icon) to a logo app-thread (Admin, ICON_WRENCH)
in the reused header element left Eleven's tile painted BEHIND the
wrench. Clear the background first. Pre-existing (appGlyphInto and
paintHeaderAvatar are unchanged by the modularisation); Paul spotted it.
Regression test added — the boot smoke can't drive an app-to-app switch.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell c7e81f5d083534d06a4ae58b80c69dcd988f7159 parent 6c98cf1
2 files changed, +21 −0
  • test/apps.test.mjs +16 −0
  • web/static/apps.js +5 −0
diff --git a/test/apps.test.mjs b/test/apps.test.mjs
index 1f17c79..4795054 100644
--- a/test/apps.test.mjs
+++ b/test/apps.test.mjs
@@ -47,6 +47,7 @@ import {
groupAppsApp,
groupAppsFor,
groupCapableApps,
+ appGlyphInto,
parseAppMention,
parseHere,
runAppMention,
@@ -2109,5 +2110,20 @@ await test("vault: lock/request/grant surface in previews and the group chat pro
assert.equal(vaultApp.chatMessage({ type: "vault.enroll" }, { group: true }), null);
});
+await test("appGlyphInto clears a leftover photo background before painting the mark", () => {
+ // The header/avatar elements are reused across thread switches: paintAvatar
+ // leaves a photo as an inline background-image (e.g. Eleven's app icon), and
+ // switching to a logo-app (Admin) must not leave it showing behind the mark.
+ const el = { style: { backgroundImage: "url(eleven.png)" }, classList: { add() {} }, innerHTML: "", textContent: "" };
+ appGlyphInto(el, { logo: "<svg><!--wrench--></svg>" });
+ assert.equal(el.style.backgroundImage, "", "logo path must clear the leftover background");
+ assert.match(el.innerHTML, /wrench/);
+ // The glyph fallback path clears it too.
+ const g = { style: { backgroundImage: "url(eleven.png)" }, classList: { add() {} }, innerHTML: "", textContent: "" };
+ appGlyphInto(g, { glyph: "🛠️" });
+ assert.equal(g.style.backgroundImage, "", "glyph path must clear the leftover background");
+ assert.equal(g.textContent, "🛠️");
+});
+
console.log(failures === 0 ? "\nALL PASSED" : `\n${failures} FAILED`);
process.exit(failures === 0 ? 0 : 1);
diff --git a/web/static/apps.js b/web/static/apps.js
index 197b392..bfd34dc 100644
--- a/web/static/apps.js
+++ b/web/static/apps.js
@@ -182,6 +182,11 @@ injectStyles(
// one, else its emoji glyph. The glyph stays the app's cross-surface fallback
// (native palettes and plain-string contexts can't render an SVG).
export function appGlyphInto(el, app) {
+ // These avatar elements are reused across thread switches, and paintAvatar
+ // may have left a photo behind as an inline background-image (e.g. Eleven's
+ // app icon). innerHTML/textContent below replace the children but NOT that
+ // style, so clear it first or the old photo shows through behind the mark.
+ el.style.backgroundImage = "";
if (app && app.logo) {
el.classList.add("app-logo");
el.innerHTML = app.logo; // static in-code SVG, never user content