import { state } from '../state.js'; import { buildArweaveDataUrl, validateArweaveTxId } from '../services/arweave-file-service.js'; import { getCachedAvatarObjectUrl } from '../services/arweave-avatar-cache-service.js'; function normalizeLogin(value) { return String(value || '').trim(); } function pickSizeClass(size) { const raw = String(size || '').trim().toLowerCase(); if (raw === 'large') return 'large'; if (raw === 'node') return 'node-dot'; if (raw === 'small') return ''; return raw || ''; } export function buildAvatarInitials({ login, firstName = '', lastName = '' } = {}) { const first = String(firstName || '').trim(); const last = String(lastName || '').trim(); if (first || last) { const initials = `${(first[0] || '').toUpperCase()}${(last[0] || '').toUpperCase()}`.trim(); if (initials) return initials; } const cleanLogin = normalizeLogin(login); return (cleanLogin[0] || '?').toUpperCase(); } export function renderUserAvatar({ login, firstName = '', lastName = '', avatar = null, size = 'large', className = '', title = '', } = {}) { const wrap = document.createElement('div'); const classes = ['avatar', 'avatar-image']; const sizeClass = pickSizeClass(size); if (sizeClass) classes.push(sizeClass); const extraClass = String(className || '').trim(); if (extraClass) classes.push(...extraClass.split(/\s+/g)); wrap.className = classes.join(' '); if (title) wrap.title = String(title); const fallback = document.createElement('span'); fallback.className = 'avatar-fallback'; fallback.textContent = buildAvatarInitials({ login, firstName, lastName }); wrap.append(fallback); const txId = String(avatar?.ar || '').trim(); if (!validateArweaveTxId(txId)) { return wrap; } fallback.hidden = true; const img = document.createElement('img'); img.alt = 'Аватар'; img.loading = 'lazy'; img.decoding = 'async'; img.hidden = true; wrap.append(img); const gateway = state?.entrySettings?.arweaveServer; void getCachedAvatarObjectUrl({ gateway, txId }) .then((objectUrl) => { const directUrl = buildArweaveDataUrl({ gateway, txId }); let triedDirectUrl = false; let objectUrlReleased = false; const releaseObjectUrl = () => { if (objectUrlReleased) return; objectUrlReleased = true; if (objectUrl.startsWith('blob:')) { URL.revokeObjectURL(objectUrl); } }; img.onload = () => { fallback.hidden = true; img.hidden = false; releaseObjectUrl(); }; img.onerror = () => { if (!triedDirectUrl) { triedDirectUrl = true; releaseObjectUrl(); img.src = directUrl; return; } releaseObjectUrl(); img.hidden = true; fallback.hidden = false; }; img.src = objectUrl; }) .catch(() => { let directUrl = ''; try { directUrl = buildArweaveDataUrl({ gateway, txId }); } catch { directUrl = ''; } if (!directUrl) { img.hidden = true; fallback.hidden = false; return; } img.onload = () => { fallback.hidden = true; img.hidden = false; }; img.onerror = () => { img.hidden = true; fallback.hidden = false; }; img.src = directUrl; }); return wrap; }