feat(web): друзья, личные беседы и вход только по приглашению
Раздел «Друзья» по запросу пользователя: - первая иконка рейки — «Друзья», серверы ниже за разделителем; личные беседы не засоряют список серверов; - сайдбар друзей: беседы с точками статуса и бейджами непрочитанного, список друзей с кликом на беседу; - контент: пустое состояние «Добавь друзей для общения» с поиском, поиск по логину (debounce), добавление в друзья, входящие и исходящие заявки, меню «…» (удалить/заблокировать), поповер последнего входа в часовом поясе пользователя (по умолчанию МСК), блок «Присоединиться по приглашению» с предпросмотром сервера; - личный чат на существующих компонентах: права по can_send канала, заголовок с именем и статусом собеседника, поиск, пины, ack и typing работают; - realtime: READY dm_channels, события DM_CHANNEL_CREATE, RELATIONSHIP_UPDATE, PRESENCE_UPDATE и MESSAGE_CREATE в беседах; - новый пользователь: «У вас пока нет серверов», создание сервера и вход по приглашению (автовступления нет); - 239 тестов Vitest (было 219), тест паритета ключей i18n (527 ключей).
This commit is contained in:
@@ -137,7 +137,9 @@ export function FriendsSidebar({ channelId }: { channelId: string | null }) {
|
||||
{t('friends.dmSection')}
|
||||
</h2>
|
||||
{direct.length === 0 ? (
|
||||
<p className="px-2 text-xs text-fg-muted">{t('friends.dmEmpty')}</p>
|
||||
<p className="px-2 text-xs text-fg-muted" data-testid="dm-sidebar-empty">
|
||||
{t('friends.dmEmpty')}
|
||||
</p>
|
||||
) : (
|
||||
<ul className="gl-stagger flex flex-col gap-0.5" data-testid="dm-list">
|
||||
{direct.map((channel) => (
|
||||
|
||||
@@ -52,7 +52,7 @@ export function GuildRail({ guilds, selectedGuildId, canCreate, onCreate }: Guil
|
||||
</svg>
|
||||
</NavLink>
|
||||
|
||||
<div role="separator" aria-hidden="true" className="my-0.5 h-px w-8 bg-border/60" />
|
||||
<div role="separator" className="my-0.5 h-px w-8 bg-border/60" />
|
||||
|
||||
<ul className="gl-stagger flex flex-col items-center gap-2" data-testid="guild-rail">
|
||||
{guilds.map((guild) => {
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function NoGuildView() {
|
||||
<p className="mt-2 text-sm text-fg-muted">{t('guilds.empty.body')}</p>
|
||||
|
||||
<Button className="mt-4" onClick={openGuildCreate}>
|
||||
{t('guilds.add')}
|
||||
{t('guilds.empty.create')}
|
||||
</Button>
|
||||
|
||||
<InviteJoin className="mt-6 border-t border-border/60 pt-4" />
|
||||
|
||||
Reference in New Issue
Block a user