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
+121
View File
@@ -422,3 +422,124 @@ body {
scroll-behavior: auto !important;
}
}
/*
* Эффекты ника (AGENT.md 7.4): встроенный набор CSS-анимаций. При
* `prefers-reduced-motion: reduce` анимации гасятся общим правилом выше,
* поэтому эффект остаётся статичным градиентом или свечением.
*/
.gl-nick {
font-weight: 600;
}
.gl-nick-gradient {
background-image: linear-gradient(90deg, #5865f2, #eb459e, #faa61a, #5865f2);
background-size: 300% 100%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: gl-nick-gradient 6s linear infinite;
}
@keyframes gl-nick-gradient {
from {
background-position: 0% 50%;
}
to {
background-position: 300% 50%;
}
}
.gl-nick-glow {
animation: gl-nick-glow 2.4s ease-in-out infinite;
}
@keyframes gl-nick-glow {
0%,
100% {
text-shadow: 0 0 4px currentColor;
}
50% {
text-shadow:
0 0 10px currentColor,
0 0 18px currentColor;
}
}
.gl-nick-fire {
background-image: linear-gradient(180deg, #ffd166, #ff7b00, #d62828);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: gl-nick-fire 1.6s ease-in-out infinite;
}
@keyframes gl-nick-fire {
0%,
100% {
filter: brightness(1);
}
50% {
filter: brightness(1.25);
}
}
.gl-nick-shimmer {
background-image: linear-gradient(100deg, currentColor 20%, #ffffff 40%, currentColor 60%);
background-size: 250% 100%;
-webkit-background-clip: text;
background-clip: text;
animation: gl-nick-shimmer 3.2s linear infinite;
}
@keyframes gl-nick-shimmer {
from {
background-position: 150% 50%;
}
to {
background-position: -50% 50%;
}
}
.gl-nick-glitch {
animation: gl-nick-glitch 2.2s steps(2, end) infinite;
}
@keyframes gl-nick-glitch {
0%,
92%,
100% {
text-shadow: none;
}
93% {
text-shadow: -2px 0 #eb459e;
}
95% {
text-shadow: 2px 0 #00b0f4;
}
97% {
text-shadow: -1px 0 #faa61a;
}
}
/* Рамка вокруг аватара: подложка под аватаром, как в AGENT.md 7.4. */
.gl-frame {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
}
.gl-frame-image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: contain;
pointer-events: none;
}
.gl-frame-inner {
position: relative;
z-index: 1;
}