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
+52
View File
@@ -0,0 +1,52 @@
/**
* Системные бейджи (AGENT.md 7.2): метки рядом с ником, которые назначает
* только система. Список расширяемый (`badges_json`), поэтому неизвестные
* бейджи показываются нейтральной меткой, а не пропадают.
*/
export interface SystemBadge {
/** Имя бейджа из `badges_json`. */
id: string;
/** Значок: эмодзи, чтобы не тащить в бандл отдельные картинки. */
icon: string;
/** Ключ подписи в локалях. */
labelKey: string;
}
/** Известные системные бейджи. */
export const SYSTEM_BADGES: SystemBadge[] = [
{ id: 'instance_admin', icon: '🛡', labelKey: 'badges.instanceAdmin' },
{ id: 'guild_owner', icon: '👑', labelKey: 'badges.guildOwner' },
{ id: 'early_supporter', icon: '💎', labelKey: 'badges.earlySupporter' },
{ id: 'verified', icon: '✔', labelKey: 'badges.verified' },
];
/** Бейдж владельца сервера: система его не хранит, он вычисляется на клиенте. */
export const GUILD_OWNER_BADGE = 'guild_owner';
/** Описание бейджа: известные — из каталога, остальные — нейтральные. */
export function systemBadge(id: string): SystemBadge {
const known = SYSTEM_BADGES.find((badge) => badge.id === id);
if (known !== undefined) {
return known;
}
return { id, icon: '•', labelKey: '' };
}
/** Список бейджей участника: системные плюс вычисленный бейдж владельца. */
export function badgesFor(
badges: readonly string[] | undefined,
isOwner: boolean,
isInstanceAdmin = false,
): string[] {
const result = new Set<string>(badges ?? []);
// Администратор инстанса всегда помечен, даже если `badges_json` пуст
// (бейдж назначается системой при выдаче прав).
if (isInstanceAdmin) {
result.add('instance_admin');
}
if (isOwner) {
result.add(GUILD_OWNER_BADGE);
}
return [...result];
}