- Replace incorrect semantic token names with correct ones: • $semantic-border-width-thin → $semantic-border-width-1 • $semantic-color-border-default → $semantic-color-border-primary • $semantic-spacing-content-* → $semantic-spacing-component-* • $semantic-typography-body-* → $semantic-typography-font-size-* • $semantic-typography-caption-* → $semantic-typography-font-size-* • $semantic-motion-easing-standard → $semantic-easing-standard • $semantic-color-surface-tertiary → $semantic-color-surface-secondary • Various hover color tokens → base color tokens - Fix typography map usage errors: • Replace heading map tokens with individual size tokens • $semantic-typography-heading-h* → $semantic-typography-heading-h*-size - Update affected components: • tooltip, divider, progress-circle, range-slider components • Related demo components and SCSS files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
502 lines
19 KiB
TypeScript
502 lines
19 KiB
TypeScript
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { AvatarComponent } from '../../../../../ui-essentials/src/lib/components/data-display/avatar/avatar.component';
|
|
|
|
interface Activity {
|
|
user: string;
|
|
action: string;
|
|
time: string;
|
|
status?: 'online' | 'offline' | 'away' | 'busy';
|
|
}
|
|
|
|
@Component({
|
|
selector: 'ui-avatar-demo',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
AvatarComponent
|
|
],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
template: `
|
|
<div style="padding: 2rem;">
|
|
<h2>Avatar Component Showcase</h2>
|
|
|
|
<!-- Size Variants -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Size Variants</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="xs" name="Extra Small"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">XS (24px)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="sm" name="Small Avatar"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">SM (32px)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="md" name="Medium Avatar"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">MD (40px)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Large Avatar"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">LG (48px)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="xl" name="Extra Large"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">XL (64px)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="xxl" name="XX Large"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">XXL (80px)</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- With Images -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>With Images</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar
|
|
size="lg"
|
|
imageUrl="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face"
|
|
name="John Doe"
|
|
altText="John Doe's profile picture">
|
|
</ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">John Doe</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar
|
|
size="lg"
|
|
imageUrl="https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face"
|
|
name="Jane Smith"
|
|
altText="Jane Smith's profile picture">
|
|
</ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Jane Smith</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar
|
|
size="lg"
|
|
imageUrl="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face"
|
|
name="Alex Rodriguez"
|
|
altText="Alex Rodriguez's profile picture">
|
|
</ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Alex Rodriguez</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar
|
|
size="lg"
|
|
imageUrl="broken-url"
|
|
name="Fallback Test"
|
|
altText="This should show initials">
|
|
</ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Fallback (Broken URL)</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- With Status -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Status Indicators</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Online User" status="online"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Online</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Offline User" status="offline"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Offline</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Away User" status="away"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Away</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Busy User" status="busy"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Busy</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- With Badges -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Notification Badges</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Badge User" badge="3"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">3 notifications</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Badge User" badge="99+"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">99+ notifications</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Badge User" badge="5" status="online"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Online + Badge</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar
|
|
size="lg"
|
|
name="Premium User"
|
|
badge="⭐"
|
|
imageUrl="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face">
|
|
</ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Premium User</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Shape Variants -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Shape Variants</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Circle User" shape="circle"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Circle (Default)</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Square User" shape="square"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Square</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Rounded User" shape="rounded"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Rounded Square</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Color Variants -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Color Variants</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Primary User" color="primary"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Primary</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Secondary User" color="secondary"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Secondary</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Success User" color="success"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Success</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Warning User" color="warning"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Warning</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Danger User" color="danger"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Danger</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Activity List Example -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Activity List Example</h3>
|
|
<div style="background: #f8f9fa; border-radius: 12px; padding: 1.5rem; max-width: 600px;">
|
|
<h4 style="margin: 0 0 1rem 0; font-size: 1.125rem;">Recent Activity</h4>
|
|
@for (activity of activities; track activity.user) {
|
|
<div style="display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0; border-bottom: 1px solid #e9ecef;">
|
|
<ui-avatar
|
|
size="sm"
|
|
[name]="activity.user"
|
|
[status]="activity.status">
|
|
</ui-avatar>
|
|
<div style="flex: 1; min-width: 0;">
|
|
<div style="font-weight: 500; font-size: 14px; margin-bottom: 2px;">{{ activity.user }}</div>
|
|
<div style="color: #666; font-size: 12px; line-height: 1.3;">{{ activity.action }}</div>
|
|
</div>
|
|
<div style="color: #999; font-size: 11px; white-space: nowrap;">{{ activity.time }}</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- User List Example -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>User List Example</h3>
|
|
<div style="background: #f8f9fa; border-radius: 12px; padding: 1.5rem; max-width: 800px;">
|
|
<div style="display: grid; gap: 1rem;">
|
|
@for (user of userProfiles; track user.id) {
|
|
<div style="display: flex; align-items: center; gap: 1rem; padding: 1rem; background: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
|
|
<ui-avatar
|
|
size="lg"
|
|
[name]="user.name"
|
|
[imageUrl]="user.avatar"
|
|
[status]="user.status"
|
|
[badge]="user.notifications > 0 ? user.notifications.toString() : ''">
|
|
</ui-avatar>
|
|
<div style="flex: 1; min-width: 0;">
|
|
<h4 style="margin: 0; font-size: 16px; font-weight: 600;">{{ user.name }}</h4>
|
|
<p style="margin: 2px 0; color: #666; font-size: 14px;">{{ user.role }}</p>
|
|
<p style="margin: 0; color: #999; font-size: 12px;">{{ user.email }}</p>
|
|
</div>
|
|
<div style="text-align: right;">
|
|
<div style="font-size: 12px; color: #999;">Last seen</div>
|
|
<div style="font-size: 12px; font-weight: 500;">{{ user.lastSeen }}</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Loading and Error States -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Special States</h3>
|
|
<div style="display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" [loading]="true"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Loading</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="" altText="Empty name fallback"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Empty Name</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" name="Single" altText="Single character name"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">Single Character</p>
|
|
</div>
|
|
<div style="text-align: center;">
|
|
<ui-avatar size="lg" altText="No name provided"></ui-avatar>
|
|
<p style="font-size: 12px; margin: 0.5rem 0;">No Name</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Avatar Group Example -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Avatar Group Example</h3>
|
|
<div style="display: flex; align-items: center; gap: -0.5rem;">
|
|
@for (member of teamMembers; track member.name; let i = $index) {
|
|
<ui-avatar
|
|
size="md"
|
|
[name]="member.name"
|
|
[imageUrl]="member.avatar"
|
|
[status]="member.status"
|
|
[style.z-index]="teamMembers.length - i"
|
|
[style.margin-left]="i > 0 ? '-8px' : '0'">
|
|
</ui-avatar>
|
|
}
|
|
<div style="margin-left: 1rem; padding: 0.5rem 1rem; background: #e3f2fd; border-radius: 20px; font-size: 12px; font-weight: 500;">
|
|
+{{ teamMembers.length }} members
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Usage Examples -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Usage Examples</h3>
|
|
<div style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; border-left: 4px solid #007bff;">
|
|
<h4>Basic Avatar:</h4>
|
|
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code><ui-avatar
|
|
size="md"
|
|
name="Current User"
|
|
status="online">
|
|
</ui-avatar></code></pre>
|
|
|
|
<h4>Avatar with Image:</h4>
|
|
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code><ui-avatar
|
|
size="lg"
|
|
name="John Doe"
|
|
imageUrl="https://example.com/avatar.jpg"
|
|
altText="John's profile picture"
|
|
status="away"
|
|
badge="5">
|
|
</ui-avatar></code></pre>
|
|
|
|
<h4>Custom Styled Avatar:</h4>
|
|
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code><ui-avatar
|
|
size="xl"
|
|
name="Admin User"
|
|
color="primary"
|
|
shape="rounded"
|
|
badge="⭐"
|
|
[loading]="false">
|
|
</ui-avatar></code></pre>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Interactive Example -->
|
|
<section style="margin-bottom: 3rem;">
|
|
<h3>Interactive Example</h3>
|
|
<div style="display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin-bottom: 1rem;">
|
|
<button
|
|
(click)="cycleStatus()"
|
|
style="padding: 0.5rem 1rem; border: 1px solid #007bff; background: #007bff; color: white; border-radius: 4px; cursor: pointer;">
|
|
Toggle Status
|
|
</button>
|
|
<button
|
|
(click)="toggleBadge()"
|
|
style="padding: 0.5rem 1rem; border: 1px solid #28a745; background: #28a745; color: white; border-radius: 4px; cursor: pointer;">
|
|
Toggle Badge
|
|
</button>
|
|
<button
|
|
(click)="cycleSize()"
|
|
style="padding: 0.5rem 1rem; border: 1px solid #6c757d; background: #6c757d; color: white; border-radius: 4px; cursor: pointer;">
|
|
Cycle Size
|
|
</button>
|
|
</div>
|
|
|
|
<div style="display: flex; align-items: center; gap: 1rem;">
|
|
<ui-avatar
|
|
[size]="interactiveSize"
|
|
name="Interactive User"
|
|
[status]="interactiveStatus"
|
|
[badge]="interactiveBadge"
|
|
imageUrl="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150&h=150&fit=crop&crop=face">
|
|
</ui-avatar>
|
|
<div>
|
|
<div><strong>Size:</strong> {{ interactiveSize }}</div>
|
|
<div><strong>Status:</strong> {{ interactiveStatus || 'none' }}</div>
|
|
<div><strong>Badge:</strong> {{ interactiveBadge || 'none' }}</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
h2 {
|
|
color: hsl(279, 14%, 11%);
|
|
font-size: 2rem;
|
|
margin-bottom: 2rem;
|
|
border-bottom: 2px solid hsl(258, 100%, 47%);
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
h3 {
|
|
color: hsl(279, 14%, 25%);
|
|
font-size: 1.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
h4 {
|
|
color: hsl(287, 12%, 35%);
|
|
font-size: 1.125rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
section {
|
|
border: 1px solid hsl(289, 14%, 90%);
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
background: hsl(286, 20%, 99%);
|
|
}
|
|
|
|
pre {
|
|
font-size: 0.875rem;
|
|
line-height: 1.5;
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
code {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
color: #d63384;
|
|
}
|
|
`]
|
|
})
|
|
export class AvatarDemoComponent {
|
|
activities: Activity[] = [
|
|
{
|
|
user: 'Alice Johnson',
|
|
action: 'Updated the project documentation and added new API endpoints',
|
|
time: '2 min ago',
|
|
status: 'online'
|
|
},
|
|
{
|
|
user: 'Bob Smith',
|
|
action: 'Completed code review for the authentication module',
|
|
time: '15 min ago',
|
|
status: 'away'
|
|
},
|
|
{
|
|
user: 'Carol Williams',
|
|
action: 'Created new user interface mockups for the dashboard',
|
|
time: '1 hour ago',
|
|
status: 'online'
|
|
},
|
|
{
|
|
user: 'David Brown',
|
|
action: 'Fixed critical bug in the payment processing system',
|
|
time: '2 hours ago',
|
|
status: 'busy'
|
|
},
|
|
{
|
|
user: 'Eve Davis',
|
|
action: 'Deployed version 2.1.0 to production environment',
|
|
time: '3 hours ago',
|
|
status: 'offline'
|
|
}
|
|
];
|
|
|
|
userProfiles = [
|
|
{
|
|
id: 1,
|
|
name: 'Alice Johnson',
|
|
role: 'Senior Developer',
|
|
email: 'alice@company.com',
|
|
status: 'online' as const,
|
|
notifications: 3,
|
|
lastSeen: '2 min ago',
|
|
avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face'
|
|
},
|
|
{
|
|
id: 2,
|
|
name: 'Bob Smith',
|
|
role: 'Product Manager',
|
|
email: 'bob@company.com',
|
|
status: 'away' as const,
|
|
notifications: 0,
|
|
lastSeen: '15 min ago',
|
|
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face'
|
|
},
|
|
{
|
|
id: 3,
|
|
name: 'Carol Williams',
|
|
role: 'UX Designer',
|
|
email: 'carol@company.com',
|
|
status: 'online' as const,
|
|
notifications: 12,
|
|
lastSeen: 'Just now',
|
|
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face'
|
|
}
|
|
];
|
|
|
|
teamMembers = [
|
|
{ name: 'Alex Chen', status: 'online' as const, avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face' },
|
|
{ name: 'Maria Garcia', status: 'away' as const, avatar: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?w=150&h=150&fit=crop&crop=face' },
|
|
{ name: 'James Wilson', status: 'busy' as const, avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=150&h=150&fit=crop&crop=face' },
|
|
{ name: 'Sarah Kim', status: 'online' as const, avatar: 'https://images.unsplash.com/photo-1534751516642-a1af1ef26a56?w=150&h=150&fit=crop&crop=face' },
|
|
];
|
|
|
|
// Interactive demo properties
|
|
interactiveSize: any = 'lg';
|
|
interactiveStatus: any = 'online';
|
|
interactiveBadge = '3';
|
|
|
|
private statusCycle: any[] = ['online', 'away', 'busy', 'offline', null];
|
|
private statusIndex = 0;
|
|
|
|
private sizeCycle: any[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
|
|
private sizeIndex = 3; // Start with 'lg'
|
|
|
|
cycleStatus(): void {
|
|
this.statusIndex = (this.statusIndex + 1) % this.statusCycle.length;
|
|
this.interactiveStatus = this.statusCycle[this.statusIndex];
|
|
}
|
|
|
|
toggleBadge(): void {
|
|
if (this.interactiveBadge) {
|
|
this.interactiveBadge = '';
|
|
} else {
|
|
this.interactiveBadge = Math.floor(Math.random() * 99 + 1).toString();
|
|
}
|
|
}
|
|
|
|
cycleSize(): void {
|
|
this.sizeIndex = (this.sizeIndex + 1) % this.sizeCycle.length;
|
|
this.interactiveSize = this.sizeCycle[this.sizeIndex];
|
|
}
|
|
} |