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:
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState, type ReactNode } from 'react';
|
||||
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -14,6 +14,12 @@ interface ModalProps {
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||
/** Дополнительные классы панели (например, ограничение высоты). */
|
||||
panelClassName?: string;
|
||||
/**
|
||||
* Инлайновые размеры панели. Нужны там, где размер считается от окна
|
||||
* браузера (окно настроек занимает фиксированные 70% площади) и не должен
|
||||
* зависеть от содержимого.
|
||||
*/
|
||||
panelStyle?: CSSProperties;
|
||||
/** Дополнительные классы области содержимого (прокрутка длинных форм). */
|
||||
bodyClassName?: string;
|
||||
/**
|
||||
@@ -54,6 +60,7 @@ export function Modal({
|
||||
footer,
|
||||
size = 'md',
|
||||
panelClassName = '',
|
||||
panelStyle,
|
||||
bodyClassName = '',
|
||||
portal = false,
|
||||
}: ModalProps) {
|
||||
@@ -144,6 +151,7 @@ export function Modal({
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label={title}
|
||||
style={panelStyle}
|
||||
className={`w-full ${sizes[size]} rounded-[var(--radius-lg)] border border-border/60 bg-surface-1 shadow-[var(--shadow-3)] ${
|
||||
closing ? 'gl-pop-out' : 'gl-pop-in'
|
||||
} ${panelClassName === '' ? 'p-5' : panelClassName}`}
|
||||
|
||||
Reference in New Issue
Block a user