# Avatar: Руководства

## Паттерны

### Строка с идентичностью пользователя

Когда использовать:

- Списку или экрану настроек нужен быстрый визуальный контекст идентичности.

Заметки о композиции:

- Сочетайте аватар с видимым текстом имени.
- Делайте инициалы короткими и стабильными.

Компромиссы:

- Людей и сущности легко находить взглядом.
- Плохо подходит, когда идентичность неважна для задачи.

```tsx
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const members = [
  { name: 'Maria Chen', email: 'maria@northwind.io', initials: 'MC', photo: portrait(210), active: true },
  { name: 'Omar Haddad', email: 'omar@northwind.io', initials: 'OH', photo: portrait(28), active: true },
  { name: 'Lena Fischer', email: 'lena@northwind.io', initials: 'LF', photo: '', active: true },
  { name: 'Tom Becker', email: 'tom@northwind.io', initials: 'TB', photo: '', active: false },
];

export default function MemberList() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-8)', width: '100%', maxWidth: 360 }}>
      {members.map((member) => (
        <li key={member.email} style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)' }}>
          <Avatar size='sm' variant={member.active ? 'primary' : 'secondary'} aria-hidden='true'>
            {member.photo && <AvatarImage src={member.photo} alt='' />}
            <AvatarFallback>{member.initials}</AvatarFallback>
          </Avatar>
          <div style={{ display: 'grid', minWidth: 0 }}>
            <Text size={2} fontWeight={500}>{member.name}</Text>
            <Text size={1} style={{ color: 'var(--label-secondary)' }}>
              {member.active ? member.email : 'Deactivated'}
            </Text>
          </div>
        </li>
      ))}
    </ul>
  );
}
```

### Аватар с изображением и надёжным запасным вариантом

Когда использовать:

- Фото профиля доступно, но при сбое должно безопасно заменяться.

Заметки о композиции:

- Всегда сочетайте `AvatarImage` с запасным содержимым.
- Делайте запасной текст кратким для выбранного размера.

Компромиссы:

- Высокая устойчивость к сбоям изображений.
- Требует продуманных `alt` и запасного варианта.

```tsx
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const photo = portrait(150);
const placeholder = portrait(220);
const broken = 'data:image/png;base64,broken';

const cases = [
  { label: 'Image loads', name: 'Priya Nair', initials: 'PN', src: photo, fallbackSrc: undefined },
  { label: 'Image fails → initials', name: 'Diego Alvarez', initials: 'DA', src: broken, fallbackSrc: undefined },
  { label: 'Image fails → fallbackSrc', name: 'Sara Lindqvist', initials: 'SL', src: broken, fallbackSrc: placeholder },
];

export default function ImageFallbacks() {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 'var(--spacing-8)', width: '100%' }}>
      {cases.map((item) => (
        <figure key={item.label} style={{ margin: 0, display: 'grid', gap: 'var(--spacing-4)', justifyItems: 'center', alignContent: 'start', textAlign: 'center' }}>
          <Avatar size='lg' role='img' aria-label={item.name}>
            <AvatarImage src={item.src} fallbackSrc={item.fallbackSrc} alt='' />
            <AvatarFallback>{item.initials}</AvatarFallback>
          </Avatar>
          <figcaption><Text size={1} style={{ color: 'var(--label-secondary)' }}>{item.label}</Text></figcaption>
        </figure>
      ))}
    </div>
  );
}
```

### Аватар обобщённой сущности

Когда использовать:

- Представленный элемент — не конкретный человек и не сущность с изображением.

Заметки о композиции:

- Используйте `AvatarIcon`, когда инициалы или изображение вводили бы в заблуждение.
- Окружающие подписи должны явно называть представленную сущность.

Компромиссы:

- Понятное обобщённое представление.
- Менее персонально, чем изображение или инициалы.

```tsx
import { Avatar, AvatarIcon, Text } from '@vega-ui/react';
import { Bot, Building2, Users } from '@vega-ui/icons';

export default function GenericEntities() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-6)', width: '100%' }}>
      <li style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)' }}>
        <Avatar size='sm' variant='secondary' aria-hidden='true'>
          <AvatarIcon><Bot /></AvatarIcon>
        </Avatar>
        <Text size={3}>Release bot merged 3 pull requests</Text>
      </li>
      <li style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)' }}>
        <Avatar size='sm' variant='secondary' aria-hidden='true'>
          <AvatarIcon><Users /></AvatarIcon>
        </Avatar>
        <Text size={3}>Design team was mentioned in “Q4 roadmap”</Text>
      </li>
      <li style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)' }}>
        <Avatar size='sm' variant='secondary' aria-hidden='true'>
          <AvatarIcon><Building2 /></AvatarIcon>
        </Avatar>
        <Text size={3}>Northwind Traders</Text>
      </li>
    </ul>
  );
}
```

## Сравнение

### Быстрое правило выбора

Используйте `Avatar`, когда интерфейсу нужно компактное представление человека или сущности.

### `Avatar` или `Badge`

Используйте `Avatar`, когда:

- элемент представляет идентичность человека или сущности

Используйте `Badge`, когда:

- элемент — компактная метка статуса или категории

Главный компромисс: аватар представляет идентичность, а бейдж — метаданные.

### `Avatar` или `Icon`

Используйте `Avatar`, когда:

- интерфейсу нужна поверхность идентичности с размером, формой и обработкой запасного варианта

Используйте `Icon`, когда:

- нужен только глиф без семантики аватара

Главный компромисс: аватар — контейнер идентичности, а иконка — просто глиф.

### `Avatar` или `AvatarStack`

Используйте `Avatar`, когда:

- представлен один человек или одна сущность

Используйте `AvatarStack`, когда:

- несколько идентичностей нужно сжать в одно групповое отображение

### Выбирайте этот компонент, когда

- Важно представление идентичности.
- Нужно поведение запасного варианта.
- Интерфейсу полезна ограниченная поверхность аватара.
- Главное, что показывается, — одна сущность, а не группа.

### Не выбирайте этот компонент, когда

- Элемент — просто метка статуса.
- Нужна только обычная иконка.
- Представленную сущность незачем показывать визуально.

## Решение проблем

### Аватар ломается при сбое изображения

#### Симптом

Аватар становится пустым или визуально сломанным, когда изображение недоступно.

#### Вероятная причина

Не передано запасное содержимое.

#### Как проверить

- Сымитируйте отсутствующее или медленное изображение.
- Проверьте, есть ли `AvatarFallback` или `AvatarIcon`.

#### Исправление

- Сочетайте `AvatarImage` с запасным содержимым.

### Инициалы выходят за границы

#### Симптом

В маленьких размерах аватара инициалы выглядят сжатыми или обрезанными.

#### Вероятная причина

Запасной текст слишком длинный для выбранного размера.

#### Как проверить

- Проверьте аватар в самых маленьких поддерживаемых размерах.
- Сравните запасной текст из одного и двух символов.

#### Исправление

- Сократите запасной текст.
- Увеличьте размер аватара, если содержимое должно оставаться крупнее.
