feat(profile): системные бейджи рядом с ником

- участники сервера отдают список бейджей из badges_json (AGENT.md 7.2):
  список расширяемый, назначается только системой
- клиент: каталог бейджей (щит администратора инстанса, корона владельца,
  ранний сторонник, проверенный), неизвестные показываются нейтральной меткой
- бейджи видны в ленте, списке участников и друзьях вместо текстовой плашки
- тесты: Go (бейджи в списке участников) и Vitest (каталог и отрисовка)
This commit is contained in:
2026-09-21 18:10:39 +03:00
parent 0f0060e8a4
commit b43452aa04
19 changed files with 266 additions and 19 deletions
@@ -0,0 +1,48 @@
import { useTranslation } from 'react-i18next';
import { badgesFor, systemBadge } from '@/lib/badges';
interface SystemBadgesProps {
/** Имена бейджей из `badges_json` (AGENT.md 7.2). */
badges?: readonly string[] | undefined;
isOwner?: boolean;
isInstanceAdmin?: boolean;
className?: string;
}
/**
* Системные бейджи рядом с ником: администратор инстанса, владелец сервера и
* другие метки из `badges_json`. Пользователь их не редактирует.
*/
export function SystemBadges({
badges,
isOwner = false,
isInstanceAdmin = false,
className = '',
}: SystemBadgesProps) {
const { t } = useTranslation();
const list = badgesFor(badges, isOwner, isInstanceAdmin);
if (list.length === 0) {
return null;
}
return (
<span className={`inline-flex items-center gap-0.5 ${className}`} data-testid="system-badges">
{list.map((id) => {
const badge = systemBadge(id);
const label = badge.labelKey === '' ? id : t(badge.labelKey);
return (
<span
key={id}
role="img"
aria-label={label}
title={label}
data-testid={`system-badge-${id}`}
className="cursor-help text-xs leading-none"
>
{badge.icon}
</span>
);
})}
</span>
);
}