feat(cosmetics): оформление профиля — галерея, роли и личные стили

- миграция 00013: guild_cosmetics (рамки и иконки) и user_styles («для друзей»
  и пер-серверные стили) (AGENT.md 7.2, 7.4)
- store: CRUD галереи, личные стили и вычисление оформления поэлементно
  (роль → пер-серверный стиль → «для друзей» → дефолт) с откатом, когда роль
  больше не выдаёт элемент
- API: галерея сервера под MANAGE_ROLES, оформление роли в create/update,
  GET/PUT/DELETE /users/@me/styles с доступными элементами по областям
- клиент: редактор личного стиля с предпросмотром, галерея оформления в
  настройках сервера, оформление роли в разделе «Роли»
- рендер: рамка под аватаром, иконка рядом с ником, цвет и встроенные эффекты
  ника (CSS, при reduced-motion статично) в ленте и списке участников
This commit is contained in:
2026-09-21 01:28:48 +03:00
parent 2e038a1d3f
commit 48e30a1897
25 changed files with 3542 additions and 41 deletions
+20
View File
@@ -53,6 +53,7 @@ export const PERMISSION_MUTE_MEMBERS = 'MUTE_MEMBERS';
export const PERMISSION_DEAFEN_MEMBERS = 'DEAFEN_MEMBERS';
export const PERMISSION_MOVE_MEMBERS = 'MOVE_MEMBERS';
export const PERMISSION_MANAGE_WEBHOOKS = 'MANAGE_WEBHOOKS';
export const PERMISSION_MANAGE_ROLES = 'MANAGE_ROLES';
/** Есть ли у пользователя право с указанным именем. */
export function hasPermission(permissions: readonly string[], name: string): boolean {
@@ -191,6 +192,25 @@ export function canManageEmojis(
);
}
/**
* Может ли пользователь управлять ролями и галереей оформления (AGENT.md 7.4):
* владелец, ADMINISTRATOR, MANAGE_ROLES или администратор инстанса.
*/
export function canManageRoles(
permissions: readonly string[],
ownerId: string,
userId: string | undefined,
isInstanceAdmin = false,
): boolean {
if (isInstanceAdmin || (userId !== undefined && userId === ownerId)) {
return true;
}
return (
hasPermission(permissions, PERMISSION_ADMINISTRATOR) ||
hasPermission(permissions, PERMISSION_MANAGE_ROLES)
);
}
/**
* Может ли пользователь управлять вебхуками комнаты (AGENT.md 7.11):
* владелец, ADMINISTRATOR, MANAGE_WEBHOOKS или администратор инстанса.