104 lines
2.8 KiB
JavaScript
104 lines
2.8 KiB
JavaScript
|
|
/**
|
||
|
|
* @fileoverview User Avatar Component for Rantii
|
||
|
|
* @author retoor <retoor@molodetz.nl>
|
||
|
|
* @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(`
|
||
|
|
<div class="avatar-wrapper" style="background-color: ${bgColor}">
|
||
|
|
<img class="avatar-image" src="${imageUrl}" alt="${username}" loading="lazy">
|
||
|
|
</div>
|
||
|
|
`);
|
||
|
|
} else {
|
||
|
|
const initials = this.getInitials(username);
|
||
|
|
this.setHtml(`
|
||
|
|
<div class="avatar-wrapper avatar-initials" style="background-color: ${bgColor}">
|
||
|
|
<span>${initials}</span>
|
||
|
|
</div>
|
||
|
|
`);
|
||
|
|
}
|
||
|
|
|
||
|
|
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 };
|