feat(web): профиль с аватаром, панель в углу, настройки сервера, скрытые ID

Правки пользователя:

- в «Профиль → Основной» сверху квадратный аватар слева, справа от него
  настройки имени, «О себе», состояния и эмодзи во всю высоту; смена аватара —
  клик по нему, форматы (JPEG, PNG, WebP, GIF до 8 МБ) — в подсказке;
- убраны дубли: часовой пояс только в «Язык и регион», статус — только в
  мини-профиле панели;
- панель пользователя переехала в нижний левый угол под сайдбар, подсказка о
  выходе из сервера — на её прежнее место; панель ужата под 240 px;
- шестерёнка сервера открывает новый пункт настроек «Сервер» (список серверов,
  общее, участники, роли, опасная зона), а «Профиль → Сервер» оставлен только
  для ника и «Применить ко всем серверам»;
- окно настроек получило статический размер 70% рабочей области со скроллом;
- ID пользователей скрыты везде, кроме раздела «Инстанс» у администратора;
- список друзей свёрнут под кнопкой «Друзья (N)» и раскрывается снизу вверх;
- 249 тестов Vitest (было 239), check/lint/test/build зелёные.
This commit is contained in:
2026-09-20 11:24:09 +03:00
parent bd5f09336b
commit 4c8f888b3e
27 changed files with 1071 additions and 419 deletions
+19 -5
View File
@@ -5,7 +5,9 @@ interface AvatarProps {
/** Стабильный id для оттенка заглушки. */
seed: string;
fileId?: string | undefined;
size?: 'sm' | 'md' | 'lg';
/** Локальный предпросмотр (свежевыбранный файл) вместо `fileId`. */
preview?: string | undefined;
size?: 'sm' | 'md' | 'lg' | 'xl';
/** Квадратная заглушка для серверов, круглая — для пользователей. */
shape?: 'circle' | 'square';
}
@@ -14,13 +16,25 @@ const sizes = {
sm: 'h-7 w-7 text-[11px]',
md: 'h-9 w-9 text-xs',
lg: 'h-14 w-14 text-lg',
/** Крупный аватар в настройках профиля: занимает родителя целиком. */
xl: 'h-full w-full text-4xl',
} as const;
/** Аватар: картинка файлового сервиса либо инициалы на цветной заглушке. */
export function Avatar({ name, seed, fileId, size = 'md', shape = 'circle' }: AvatarProps) {
const src = avatarUrl(fileId);
/**
* Аватар: картинка файлового сервиса либо инициалы на цветной заглушке.
* `preview` перекрывает `fileId` — так выбранный файл видно до ответа сервера.
*/
export function Avatar({
name,
seed,
fileId,
preview,
size = 'md',
shape = 'circle',
}: AvatarProps) {
const src = preview ?? avatarUrl(fileId);
const hue = hueFromId(seed);
const radius = shape === 'circle' ? 'rounded-full' : 'rounded-[var(--radius-md)]';
const radius = shape === 'circle' ? 'rounded-full' : 'rounded-[var(--radius-lg)]';
return (
<span