diff --git a/js/app.js b/js/app.js index 2edd7cc0..49b87591 100644 --- a/js/app.js +++ b/js/app.js @@ -3897,20 +3897,147 @@ class Application { } updateProfileInDOM(pubkey, profile) { + const normalizedPubkey = + typeof pubkey === "string" && pubkey.trim() ? pubkey.trim() : ""; + if (!normalizedPubkey) { + return; + } + + const normalizedProfile = + profile && typeof profile === "object" ? profile : {}; + + const pictureUrl = + typeof normalizedProfile.picture === "string" + ? normalizedProfile.picture + : ""; + + const resolveProfileName = () => { + const candidates = [ + normalizedProfile.name, + normalizedProfile.display_name, + normalizedProfile.displayName, + ]; + for (const candidate of candidates) { + if (typeof candidate !== "string") { + continue; + } + const trimmed = candidate.trim(); + if (trimmed) { + return trimmed; + } + } + return ""; + }; + + const resolvedName = resolveProfileName(); + + const explicitNpub = + typeof normalizedProfile.npub === "string" + ? normalizedProfile.npub.trim() + : ""; + + const fallbackNpub = (() => { + if (explicitNpub) { + return explicitNpub; + } + const encoded = this.safeEncodeNpub(normalizedPubkey); + return typeof encoded === "string" ? encoded : ""; + })(); + + const shortNpubLabel = fallbackNpub + ? formatShortNpub(fallbackNpub) || fallbackNpub + : ""; + // For any .author-pic[data-pubkey=...] const picEls = document.querySelectorAll( - `.author-pic[data-pubkey="${pubkey}"]` + `.author-pic[data-pubkey="${normalizedPubkey}"]` ); picEls.forEach((el) => { - el.src = profile.picture; + if (!el) { + return; + } + el.src = pictureUrl; }); + + const nameLabel = resolvedName || shortNpubLabel || fallbackNpub || ""; + // For any .author-name[data-pubkey=...] const nameEls = document.querySelectorAll( - `.author-name[data-pubkey="${pubkey}"]` + `.author-name[data-pubkey="${normalizedPubkey}"]` ); nameEls.forEach((el) => { - el.textContent = profile.name; + if (!el) { + return; + } + el.textContent = nameLabel; }); + + const npubEls = document.querySelectorAll( + `.author-npub[data-pubkey="${normalizedPubkey}"]` + ); + npubEls.forEach((el) => { + if (!el) { + return; + } + + if (shortNpubLabel) { + el.textContent = shortNpubLabel; + el.setAttribute("aria-hidden", "false"); + } else { + el.textContent = ""; + el.setAttribute("aria-hidden", "true"); + } + + if (fallbackNpub) { + el.setAttribute("title", fallbackNpub); + } else { + el.removeAttribute("title"); + } + }); + + if (!nameEls.length && !npubEls.length) { + return; + } + + const cardInstances = new Set(); + const collectCardInstance = (el) => { + if (!el || typeof el.closest !== "function") { + return; + } + const cardRoot = el.closest('[data-component="similar-content-card"]'); + if (!cardRoot) { + return; + } + const instance = cardRoot.__bitvidSimilarContentCard; + if (instance && typeof instance.updateIdentity === "function") { + cardInstances.add(instance); + } + }; + + nameEls.forEach(collectCardInstance); + npubEls.forEach(collectCardInstance); + + if (cardInstances.size) { + const identityPayload = { + name: resolvedName, + npub: fallbackNpub, + shortNpub: shortNpubLabel, + pubkey: normalizedPubkey, + }; + + cardInstances.forEach((card) => { + try { + card.updateIdentity(identityPayload); + } catch (error) { + if (devLogger?.warn) { + devLogger.warn( + "[app] Failed to update similar content card identity", + error + ); + } + } + }); + } } async publishVideoNote(payload, { onSuccess, suppressModalClose } = {}) { diff --git a/js/ui/components/SimilarContentCard.js b/js/ui/components/SimilarContentCard.js index d17dfd67..5a328424 100644 --- a/js/ui/components/SimilarContentCard.js +++ b/js/ui/components/SimilarContentCard.js @@ -1,4 +1,5 @@ import { normalizeDesignSystemContext } from "../../designSystem.js"; +import { formatShortNpub } from "../../utils/formatters.js"; export class SimilarContentCard { constructor({ @@ -85,8 +86,12 @@ export class SimilarContentCard { this.identity = this.normalizeIdentity(nextIdentity, this.identity); if (this.authorNameEl) { - this.authorNameEl.textContent = - this.identity.name || this.identity.shortNpub || this.identity.npub || ""; + const label = + this.identity.name || + this.identity.shortNpub || + this.identity.npub || + ""; + this.authorNameEl.textContent = label; if (this.identity.pubkey) { this.authorNameEl.dataset.pubkey = this.identity.pubkey; } else if (this.authorNameEl.dataset?.pubkey) { @@ -102,6 +107,13 @@ export class SimilarContentCard { } else { this.authorNpubEl.setAttribute("aria-hidden", "false"); } + + if (this.identity.npub) { + this.authorNpubEl.setAttribute("title", this.identity.npub); + } else { + this.authorNpubEl.removeAttribute("title"); + } + if (this.identity.pubkey) { this.authorNpubEl.dataset.pubkey = this.identity.pubkey; } else if (this.authorNpubEl.dataset?.pubkey) { @@ -185,13 +197,27 @@ export class SimilarContentCard { })(); const shortNpub = (() => { - const entries = [candidate.shortNpub, baseline.shortNpub, npub]; + const entries = [candidate.shortNpub, baseline.shortNpub]; + let resolved = ""; for (const entry of entries) { - if (typeof entry === "string" && entry.trim()) { - return entry.trim(); + if (typeof entry !== "string") { + continue; + } + const trimmed = entry.trim(); + if (trimmed) { + resolved = trimmed; + break; } } - return ""; + + if (npub) { + const formatted = formatShortNpub(npub); + if (formatted) { + resolved = formatted; + } + } + + return resolved; })(); if (!name) { @@ -215,6 +241,7 @@ export class SimilarContentCard { } this.root = root; + this.root.__bitvidSimilarContentCard = this; const media = this.buildMediaSection(); const content = this.buildContentSection(); @@ -394,6 +421,9 @@ export class SimilarContentCard { } else { npubEl.setAttribute("aria-hidden", "true"); } + if (this.identity.npub) { + npubEl.setAttribute("title", this.identity.npub); + } if (this.identity.pubkey) { npubEl.dataset.pubkey = this.identity.pubkey; }