first commit

This commit is contained in:
Anton Budylin
2026-04-14 10:12:51 +03:00
commit ea171ed95a
247 changed files with 42642 additions and 0 deletions

398
lastochka-ui/WEB_APP.md Normal file
View File

@@ -0,0 +1,398 @@
# Веб-кабинет Ласточки
## Обзор
Веб-кабинет мессенджера Ласточка предоставляет полный функционал для общения:
- 💬 **Личные чаты** — общение один на один
- 👥 **Группы** — групповые чаты с участниками
- 📢 **Каналы** — публикация контента подписчикам
- 🔍 **Поиск** — поиск пользователей и сообщений
- ⚙️ **Настройки** — управление профилем и настройками
## Структура
```
src/
├── components/
│ ├── layout/
│ │ └── Sidebar.tsx # Боковая панель с навигацией
│ ├── chat/
│ │ ├── ChatHeader.tsx # Шапка чата
│ │ ├── ChatWindow.tsx # Окно чата
│ │ ├── MessagesList.tsx # Список сообщений
│ │ └── MessageInput.tsx # Ввод сообщений
│ ├── sidebar/
│ │ ├── ChatList.tsx # Список чатов
│ │ └── ChatItem.tsx # Элемент чата
│ └── ui/
│ ├── UserSearch.tsx # Поиск пользователей
│ ├── CreateGroupModal.tsx # Создание группы/канала
│ ├── MembersPanel.tsx # Панель участников
│ └── Avatar.tsx # Аватар
├── store/
│ ├── auth.ts # Аутентификация
│ ├── chat.ts # Чаты и сообщения
│ └── groups.ts # Группы и каналы
└── types/
└── index.ts # Типы данных
```
## Компоненты
### Sidebar.tsx
Боковая панель с переключением между чатами, группами и каналами.
**Вкладки:**
- **Чаты** — личные и групповые чаты
- **Группы** — управление группами
- **Каналы** — управление каналами
**Функции:**
- Поиск по чатам
- Счётчики непрочитанных
- Быстрое создание групп/каналов
### ChatHeader.tsx
Шапка чата с информацией о собеседнике/группе.
**Отображение:**
- Аватар и имя
- Статус (онлайн/был недавно)
- Для групп: количество участников
- Для каналов: количество подписчиков
**Действия:**
- Поиск по сообщениям
- Показать/скрыть участников
- Меню действий
### ChatWindow.tsx
Основное окно чата.
**Режимы:**
- Пустое состояние (чат не выбран)
- Активный чат с сообщениями
### UserSearch.tsx
Поиск пользователей для добавления в чат или группу.
**Props:**
```typescript
interface UserSearchProps {
onSelect?: (user: User) => void
onClose?: () => void
showStartChat?: boolean // Показать кнопку "Начать чат"
showAddToGroup?: boolean // Показать кнопку "Добавить в группу"
groupId?: string // ID группы для добавления
}
```
**Функции:**
- Debounced поиск (300ms)
- Отображение статуса онлайн
- Быстрое добавление в группу
### CreateGroupModal.tsx
Модальное окно создания группы или канала.
**Этапы:**
1. **Информация** — название, описание, тип доступа
2. **Участники** — выбор пользователей
**Props:**
```typescript
interface CreateGroupModalProps {
isOpen: boolean
onClose: () => void
mode: 'group' | 'channel'
}
```
**Параметры создания:**
- Название (обязательно)
- Описание (необязательно)
- Тип доступа (приватный/публичный)
- Участники (необязательно)
### MembersPanel.tsx
Выезжающая панель участников группы/канала.
**Props:**
```typescript
interface MembersPanelProps {
isOpen: boolean
onClose: () => void
groupId: string
canAddMembers?: boolean
canRemoveMembers?: boolean
}
```
**Функции:**
- Просмотр списка участников
- Добавление участников (если разрешено)
- Удаление участников (для владельца)
- Выход из группы/канала
## Store
### groups.ts
Управление группами и каналами.
**Состояние:**
```typescript
interface GroupsStore {
groups: Group[] // Список групп
channels: Group[] // Список каналов
selectedGroup: Group | null // Выбранная группа
isLoading: boolean
error: string | null
}
```
**Методы:**
- `loadGroups()` — загрузка списка групп
- `loadChannels()` — загрузка списка каналов
- `createGroup(params)` — создание группы
- `createChannel(params)` — создание канала
- `selectGroup(groupId)` — выбор группы
- `addMember(groupId, userId)` — добавление участника
- `removeMember(groupId, userId)` — удаление участника
- `leaveGroup(groupId)` — выход из группы
- `deleteGroup(groupId)` — удаление группы
- `updateGroupInfo(groupId, name, description)` — обновление информации
- `searchUsersForInvite(query)` — поиск пользователей
## Типы данных
### Group
```typescript
interface Group {
id: string
name: string
description?: string
avatar?: string
owner: string
members: GroupMember[]
created: Date
isChannel: boolean
isPublic: boolean
membersCount: number
}
```
### GroupMember
```typescript
interface GroupMember {
userId: string
name: string
avatar?: string
role: 'owner' | 'admin' | 'member'
joined: Date
online?: boolean
}
```
### CreateGroupParams
```typescript
interface CreateGroupParams {
name: string
description?: string
isChannel: boolean
isPublic: boolean
members: string[] // user IDs
avatar?: string
}
```
## Создание группы
```typescript
import { useGroupsStore } from '@/store/groups'
const { createGroup } = useGroupsStore()
const group = await createGroup({
name: 'Моя группа',
description: 'Описание группы',
isChannel: false,
isPublic: false,
members: ['user1', 'user2'],
})
```
## Создание канала
```typescript
import { useGroupsStore } from '@/store/groups'
const { createChannel } = useGroupsStore()
const channel = await createChannel({
name: 'Мой канал',
description: 'Описание канала',
isPublic: true,
members: [], // Можно без участников
})
```
## Поиск пользователей
```typescript
import { useGroupsStore } from '@/store/groups'
const { searchUsersForInvite } = useGroupsStore()
const users = await searchUsersForInvite('Иван')
// [{ id: 'user1', name: 'Иван', online: true }, ...]
```
## Добавление участника
```typescript
import { useGroupsStore } from '@/store/groups'
const { addMember } = useGroupsStore()
await addMember('group-id', 'user-id')
```
## Отличия групп и каналов
| Параметр | Группа | Канал |
|----------|--------|-------|
| **Цель** | Общение | Публикация контента |
| **Участники** | Могут писать | Только читают (обычно) |
| **Создатель** | Владелец | Администратор |
| **Доступ** | Приватный/Публичный | Приватный/Публичный |
| **Уведомления** | Все сообщения | Только новые посты |
## Типы доступа
### Приватный
- Вход только по приглашению
- Не отображается в поиске
- Участники видны друг другу
### Публичный
- Любой может вступить
- Отображается в поиске
- Можно пригласить ссылку
## Интеграция с Tinode
### Группы
Tinode использует topics с префиксом `grp`:
```typescript
// Создание группы
const groupTopic = tn.getTopic('new')
await groupTopic.save({
desc: {
public: {
fn: 'Название',
note: 'Описание',
type: 'group',
},
},
subs: members.map(userId => ({
user: userId,
mode: 'RW', // Read-Write
})),
})
```
### Каналы
```typescript
// Создание канала
const channelTopic = tn.getTopic('new')
await channelTopic.save({
desc: {
public: {
fn: 'Название',
note: 'Описание',
type: 'channel',
},
},
subs: members.map(userId => ({
user: userId,
mode: 'R', // Read-only
})),
})
```
## Роли участников
### Owner (Владелец)
- Полный доступ
- Может удалять группу
- Назначать администраторов
- Добавлять/удалять участников
### Admin (Администратор)
- Может добавлять участников
- Может удалять участников (не админов)
- Может редактировать информацию
### Member (Участник)
- Может писать сообщения
- Может приглашать других (если разрешено)
- Может покинуть группу
## Примеры использования
### Создание публичного канала
```typescript
const { createChannel } = useGroupsStore()
const channel = await createChannel({
name: 'Новости Ласточки',
description: 'Официальные новости мессенджера',
isPublic: true,
members: [],
})
// Переход в канал
const { setActiveChat } = useChatStore.getState()
await setActiveChat(channel.id)
```
### Добавление участника из поиска
```typescript
<UserSearch
showAddToGroup
groupId="group-id"
onSelect={(user) => {
console.log('Добавлен:', user)
}}
/>
```
### Просмотр участников
```typescript
const { selectGroup, selectedGroup } = useGroupsStore()
await selectGroup('group-id')
console.log(selectedGroup?.members)
// [{ userId: 'user1', name: 'Иван', role: 'owner', ... }]
```
---
**Ласточка** — народный мессенджер с открытым кодом 🕊️