import { state } from '../state.js'; import { buildArweaveDataUrl, validateArweaveTxId, validateSha256Hex } 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 === 'node') return 'node-dot'; if (raw === 'xs' || raw === 'xsmall' || raw === 'tiny') return 'avatar-xs'; if (raw === 'sm' || raw === 'small') return 'avatar-sm'; if (raw === 'md' || raw === 'medium' || raw === '') return 'avatar-md'; if (raw === 'lg' || raw === 'big') return 'avatar-lg'; if (raw === 'xl' || raw === 'xlarge' || raw === 'large' || raw === 'very-large') return 'avatar-xl'; 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 renderAvatar({ initials = '?', avatar = null, size = 'xl', className = '', title = '', alt = 'Аватар', glow = false, } = {}) { const wrap = document.createElement('div'); const classes = new Set(['avatar', 'avatar-image', 'avatar-framed']); const sizeClass = pickSizeClass(size); if (sizeClass) classes.add(sizeClass); const extraClass = String(className || '').trim(); if (extraClass) extraClass.split(/\s+/g).filter(Boolean).forEach((value) => classes.add(value)); if (glow) classes.add('avatar-glow'); wrap.className = Array.from(classes).join(' '); if (title) wrap.title = String(title); const fallback = document.createElement('span'); fallback.className = 'avatar-fallback'; fallback.textContent = String(initials || '?').trim().slice(0, 2).toUpperCase() || '?'; wrap.append(fallback); const txId = String(avatar?.ar || '').trim(); if (!validateArweaveTxId(txId)) { return wrap; } const sha256Hex = String(avatar?.sha256Hex || avatar?.sha256 || '').trim().toLowerCase(); const expectedSha256Hex = validateSha256Hex(sha256Hex) ? sha256Hex : ''; const img = document.createElement('img'); img.className = 'avatar-photo'; img.alt = String(alt || 'Аватар'); img.loading = 'lazy'; img.decoding = 'async'; wrap.append(img); const setLoadedState = (loaded) => { wrap.classList.toggle('has-image', Boolean(loaded)); }; setLoadedState(false); const gateway = state?.entrySettings?.arweaveServer; void getCachedAvatarObjectUrl({ gateway, txId, expectedSha256Hex }) .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 = () => { setLoadedState(true); releaseObjectUrl(); }; img.onerror = () => { if (!triedDirectUrl) { if (expectedSha256Hex) { releaseObjectUrl(); img.removeAttribute('src'); setLoadedState(false); return; } triedDirectUrl = true; releaseObjectUrl(); img.src = directUrl; return; } releaseObjectUrl(); img.removeAttribute('src'); setLoadedState(false); }; img.src = objectUrl; }) .catch(() => { if (expectedSha256Hex) { img.removeAttribute('src'); setLoadedState(false); return; } let directUrl = ''; try { directUrl = buildArweaveDataUrl({ gateway, txId }); } catch { directUrl = ''; } if (!directUrl) { img.removeAttribute('src'); setLoadedState(false); return; } img.onload = () => { setLoadedState(true); }; img.onerror = () => { img.removeAttribute('src'); setLoadedState(false); }; img.src = directUrl; }); return wrap; } export function renderUserAvatar({ login, firstName = '', lastName = '', avatar = null, size = 'xl', className = '', title = '', glow = false, } = {}) { return renderAvatar({ initials: buildAvatarInitials({ login, firstName, lastName }), avatar, size, className, title, alt: 'Аватар', glow, }); }