/** * @fileoverview User Avatar Component for Rantii * @author retoor * @description Displays user avatar with fallback to initials * @keywords avatar, user, profile, image, picture */ import { BaseComponent } from './base-component.js'; import { buildAvatarUrl } from '../utils/url.js'; class UserAvatar extends BaseComponent { static get observedAttributes() { return ['avatar', 'username', 'size', 'user-id']; } init() { this.render(); } render() { const avatarData = this.getAttr('avatar'); const username = this.getAttr('username') || ''; const size = this.getAttr('size') || 'medium'; const userId = this.getAttr('user-id'); this.addClass('avatar', `avatar-${size}`); let avatar = null; if (avatarData) { try { avatar = JSON.parse(avatarData); } catch (e) { avatar = null; } } const bgColor = avatar?.b || '#54556e'; const imageUrl = buildAvatarUrl(avatar); if (imageUrl) { this.setHtml(`
${username}
`); } else { const initials = this.getInitials(username); this.setHtml(`
${initials}
`); } if (userId || username) { this.style.cursor = 'pointer'; this.setAttribute('role', 'button'); this.setAttribute('tabindex', '0'); } } getInitials(username) { if (!username) return '?'; return username.substring(0, 2).toUpperCase(); } onAttributeChanged(name, oldValue, newValue) { this.render(); } onConnected() { this.on(this, 'click', this.handleClick); this.on(this, 'keydown', this.handleKeydown); } handleClick(e) { const username = this.getAttr('username'); if (username) { this.getRouter()?.goToUser(username); } } handleKeydown(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.handleClick(e); } } setAvatar(avatar, username) { if (avatar && typeof avatar === 'object') { this.setAttr('avatar', JSON.stringify(avatar)); } if (username) { this.setAttr('username', username); } this.render(); } } customElements.define('user-avatar', UserAvatar); export { UserAvatar };