Files
ui-essentials/src/lib/components/data-display/avatar/avatar.component.ts
Jules 0a0cade343 Initial commit - Angular library: ui-essentials
🎯 Implementation Complete!

This library has been extracted from the monorepo and is ready for Git submodule distribution.

Features:
- Standardized SCSS imports (no relative paths)
- Optimized public-api.ts exports
- Independent Angular library structure
- Ready for consumer integration as submodule

🚀 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 21:12:46 +10:00

108 lines
3.2 KiB
TypeScript

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faUser } from '@fortawesome/free-solid-svg-icons';
import { BadgeComponent } from '../badge/badge.component';
export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
@Component({
selector: 'ui-avatar',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, FontAwesomeModule, BadgeComponent],
template: `
<div class="skyui-avatar"
[class]="'skyui-avatar--size-' + size"
[class.skyui-avatar--loading]="loading"
[attr.aria-label]="ariaLabel || (name ? name + ' avatar' : 'User avatar')">
@if (loading) {
<div class="skyui-avatar__loading">
<div class="loading-spinner" aria-hidden="true"></div>
</div>
} @else {
@if (imageUrl && !imageError) {
<img
[src]="imageUrl"
[alt]="altText || (name ? name + ' avatar' : 'User avatar')"
class="skyui-avatar__image"
(error)="onImageError()"
(load)="onImageLoad()">
} @else {
<div class="skyui-avatar__fallback">
@if (computedInitials) {
<span class="skyui-avatar__initials" aria-hidden="true">{{ computedInitials }}</span>
} @else {
<fa-icon
[icon]="faUser"
class="skyui-avatar__icon"
aria-hidden="true">
</fa-icon>
}
</div>
}
}
@if (status) {
<div class="skyui-avatar__status"
[class]="'skyui-avatar__status--' + status"
[attr.aria-label]="statusLabel || status + ' status'">
</div>
}
@if (badge !== undefined && badge !== null) {
<ui-badge
class="skyui-avatar__badge"
variant="danger"
size="xs"
[ariaLabel]="badgeLabel || 'Badge: ' + badge">
{{ badge }}
</ui-badge>
}
</div>
`,
styleUrl: './avatar.component.scss'
})
export class AvatarComponent {
@Input() imageUrl?: string;
@Input() name?: string;
@Input() initials?: string;
@Input() size: AvatarSize = 'md';
@Input() altText?: string;
@Input() ariaLabel?: string;
@Input() loading: boolean = false;
@Input() status?: 'online' | 'offline' | 'away' | 'busy';
@Input() statusLabel?: string;
@Input() badge?: string | number;
@Input() badgeLabel?: string;
faUser = faUser;
imageError = false;
onImageError(): void {
this.imageError = true;
}
onImageLoad(): void {
this.imageError = false;
}
// Auto-generate initials from name if not provided
get computedInitials(): string {
if (this.initials) {
return this.initials.slice(0, 2).toUpperCase();
}
if (this.name) {
const nameParts = this.name.trim().split(/\s+/);
if (nameParts.length >= 2) {
return (nameParts[0][0] + nameParts[nameParts.length - 1][0]).toUpperCase();
} else if (nameParts[0]) {
return nameParts[0].slice(0, 2).toUpperCase();
}
}
return '';
}
}