SHA256
ЛС: редизайн списка (фото-аватары, галочка/значок связи у имени, попап-цепочка→профиль) + demo-чат и lab-маршрут
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// Demo-чат для оффлайн-флоу /messages-list/lab/chat/:id (только demo).
|
||||
// Реальный chat-view.js НЕ трогаем (он завязан на бэкенд/WS); здесь — изолированная мок-страница.
|
||||
// Состояние сообщений берём из dm-lab-store (localStorage). Без сети, без авторизации.
|
||||
import { directMessages } from '../../mock-data.js';
|
||||
import { getThread, appendOut, markRead } from './dm-lab-store.js';
|
||||
|
||||
// showAppChrome:false — у чата свой низ (поле ввода), нижнее меню прячем.
|
||||
export const pageMeta = { id: 'dm-lab-chat', title: 'Чат (demo)', showAppChrome: false };
|
||||
|
||||
function findDialog(id) {
|
||||
return (Array.isArray(directMessages) ? directMessages : []).find((m) => m.id === id) || null;
|
||||
}
|
||||
|
||||
function bubble(m) {
|
||||
const b = document.createElement('div');
|
||||
b.className = `bubble ${m && m.from === 'out' ? 'out' : 'in'}`;
|
||||
b.textContent = m ? m.text : '';
|
||||
return b;
|
||||
}
|
||||
|
||||
export function render({ navigate, route }) {
|
||||
const chatId = String(route?.params?.chatId || '').trim();
|
||||
const dialog = findDialog(chatId);
|
||||
const name = (dialog && dialog.name) || chatId || 'Диалог';
|
||||
|
||||
// Открытие диалога сбрасывает у него непрочитанные (demo).
|
||||
markRead(chatId);
|
||||
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'dm-screen dm-chat-screen';
|
||||
|
||||
// Шапка чата: назад + имя собеседника + demo-метка.
|
||||
const head = document.createElement('header');
|
||||
head.className = 'dm-chat-head';
|
||||
head.innerHTML = `
|
||||
<button type="button" class="dm-chat-back" aria-label="Назад">‹</button>
|
||||
<span class="dm-chat-peer">${name}</span>
|
||||
<span class="dm-chat-demo-tag">demo</span>
|
||||
`;
|
||||
head.querySelector('.dm-chat-back').addEventListener('click', () => navigate('messages-list/lab'));
|
||||
|
||||
const log = document.createElement('div');
|
||||
log.className = 'dm-messages-log';
|
||||
getThread(chatId).forEach((m) => log.append(bubble(m)));
|
||||
|
||||
const inputRow = document.createElement('form');
|
||||
inputRow.className = 'dm-chat-input';
|
||||
inputRow.innerHTML = `
|
||||
<textarea class="dm-input" rows="1" placeholder="Сообщение…" aria-label="Текст сообщения"></textarea>
|
||||
<button type="submit" class="dm-send-btn dm-send-icon-btn" aria-label="Отправить">➤</button>
|
||||
`;
|
||||
const field = inputRow.querySelector('.dm-input');
|
||||
|
||||
const scrollToEnd = () => requestAnimationFrame(() => { log.scrollTop = log.scrollHeight; });
|
||||
const submit = () => {
|
||||
const msg = appendOut(chatId, field.value);
|
||||
if (!msg) return;
|
||||
field.value = '';
|
||||
log.append(bubble(msg));
|
||||
scrollToEnd();
|
||||
};
|
||||
inputRow.addEventListener('submit', (e) => { e.preventDefault(); submit(); });
|
||||
field.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit(); }
|
||||
});
|
||||
|
||||
screen.append(head, log, inputRow);
|
||||
scrollToEnd();
|
||||
return screen;
|
||||
}
|
||||
Reference in New Issue
Block a user