diff --git a/shine-UI/assets/demo-avatars/u1.jpg b/shine-UI/assets/demo-avatars/u1.jpg deleted file mode 100644 index f5dfb5a..0000000 Binary files a/shine-UI/assets/demo-avatars/u1.jpg and /dev/null differ diff --git a/shine-UI/assets/demo-avatars/u2.jpg b/shine-UI/assets/demo-avatars/u2.jpg deleted file mode 100644 index 3f8d8f1..0000000 Binary files a/shine-UI/assets/demo-avatars/u2.jpg and /dev/null differ diff --git a/shine-UI/assets/demo-avatars/u3.jpg b/shine-UI/assets/demo-avatars/u3.jpg deleted file mode 100644 index b706e9e..0000000 Binary files a/shine-UI/assets/demo-avatars/u3.jpg and /dev/null differ diff --git a/shine-UI/assets/demo-avatars/u4.jpg b/shine-UI/assets/demo-avatars/u4.jpg deleted file mode 100644 index 9688fb2..0000000 Binary files a/shine-UI/assets/demo-avatars/u4.jpg and /dev/null differ diff --git a/shine-UI/assets/demo-avatars/u6.jpg b/shine-UI/assets/demo-avatars/u6.jpg deleted file mode 100644 index 970a9fe..0000000 Binary files a/shine-UI/assets/demo-avatars/u6.jpg and /dev/null differ diff --git a/shine-UI/assets/demo-avatars/u7.jpg b/shine-UI/assets/demo-avatars/u7.jpg deleted file mode 100644 index b530fdb..0000000 Binary files a/shine-UI/assets/demo-avatars/u7.jpg and /dev/null differ diff --git a/shine-UI/js/app.js b/shine-UI/js/app.js index af12a85..1d0eba7 100644 --- a/shine-UI/js/app.js +++ b/shine-UI/js/app.js @@ -63,7 +63,6 @@ import * as appLogView from './pages/app-log-view.js'; import * as pwaDiagnosticsView from './pages/pwa-diagnostics-view.js'; import * as solanaUsersInitView from './pages/solana-users-init-view.js'; import * as messagesList from './pages/messages-list.js'; -import * as dmLabChat from './pages/messages/dm-lab-chat.js'; import * as contactSearchView from './pages/contact-search-view.js'; import * as chatView from './pages/chat-view.js'; import * as userProfileView from './pages/user-profile-view.js'; @@ -106,7 +105,6 @@ const routes = { 'pwa-diagnostics-view': pwaDiagnosticsView, 'solana-users-init-view': solanaUsersInitView, 'messages-list': messagesList, - 'dm-lab-chat': dmLabChat, 'contact-search-view': contactSearchView, 'chat-view': chatView, user: userProfileView, @@ -153,7 +151,6 @@ const GUEST_ALLOWED_PAGES = new Set([ 'channel-thread-view', 'user', 'contact-search-view', - 'dm-lab-chat', // demo-чат лаборатории ЛС (мок, без сессии) ]); setClientErrorTransport((payload) => authService.reportClientUiError(payload)); @@ -690,10 +687,7 @@ function renderApp() { const route = getRoute(); const pageId = route.pageId || (state.session.isAuthorized ? 'messages-list' : 'start-view'); - // Гостю доступен ТОЛЬКО demo-маршрут ЛС (/messages-list/lab) — для оффлайн-проверки редизайна без сессии. - // Реальный /messages-list остаётся защищённым (mode пустой → редирект на start-view). - const isDmDemo = pageId === 'messages-list' && route.params?.mode === 'lab'; - if (!state.session.isAuthorized && !PRE_AUTH_PAGES.includes(pageId) && !GUEST_ALLOWED_PAGES.has(pageId) && !isDmDemo) { + if (!state.session.isAuthorized && !PRE_AUTH_PAGES.includes(pageId) && !GUEST_ALLOWED_PAGES.has(pageId)) { navigate('start-view'); return; } diff --git a/shine-UI/js/pages/messages-list.js b/shine-UI/js/pages/messages-list.js index b8f0df3..12edefb 100644 --- a/shine-UI/js/pages/messages-list.js +++ b/shine-UI/js/pages/messages-list.js @@ -3,7 +3,6 @@ import { state } from '../state.js'; import { renderUserAvatar } from '../components/avatar-image.js'; import { loadProfileSnapshot } from '../services/user-profile-params.js'; import { resolveDmVisualState } from './messages/dm-visual-resolver.js'; -import { getPreview, getUnread } from './messages/dm-lab-store.js'; import { makeProfileRoute } from '../services/shine-routes.js'; export const pageMeta = { id: 'messages-list', title: 'Личные сообщения' }; @@ -80,14 +79,8 @@ export function render({ navigate, route }) { const screen = document.createElement('section'); screen.className = 'dm-screen dm-list-screen'; - // demo/lab: гость без сессии (маршрут /messages-list/lab или ?demo=1). В demo НЕ ходим в сеть за фото - // профиля — иначе висящие listUserParams не дают сети уйти в idle и ломают скриншоты (остаются initials). - const isDemo = route?.params?.mode === 'lab' - || (typeof window !== 'undefined' && /[?&]demo=1(?:&|$)/.test(window.location.search || '')); - - // Слева сверху — имя владельца аккаунта (на проде реальный логин; в demo — заглушка, НЕ «shine», - // чтобы не дублировать центральный бренд «Shine»). - const login = String(state.session.login || '').trim() || 'Aidar007'; + // Слева сверху — имя владельца аккаунта (реальный логин из сессии). + const login = String(state.session.login || '').trim(); // DM-шапка: grid 1fr auto 1fr (бренд слева, title строго по центру, «+» справа). const head = document.createElement('header'); @@ -111,12 +104,10 @@ export function render({ navigate, route }) { list.className = 'dm-list'; function renderRow(item) { - // В demo превью/непрочитанные берём из dm-lab-store (обновляются после отправки/открытия чата). - const resolverItem = isDemo ? { ...item, unreadCount: getUnread(item.id) } : item; - const v = resolveDmVisualState(resolverItem); // { tone, shining, confirmed, via, unread } + const v = resolveDmVisualState(item); // { tone, shining, confirmed, via, unread } const cardVariant = v.tone === 'family' ? ' dm-card--family' : (v.tone === 'shining' ? ' dm-card--shining' : ''); const name = item.name || item.id; - const preview = (isDemo ? getPreview(item.id, item.preview || item.lastMessage || '') : (item.preview || item.lastMessage || '')) || 'Диалог пока пуст.'; + const preview = (item.preview || item.lastMessage || '') || 'Диалог пока пуст.'; const row = document.createElement('article'); row.className = `dm-dialog-card${cardVariant}`; @@ -199,14 +190,12 @@ export function render({ navigate, route }) { // Аватар: фото/инициалы без кольца; у сияющего — свечение (класс is-shine). const avWrap = document.createElement('div'); avWrap.className = `dm-av dm-av--${v.tone}${v.shining ? ' is-shine' : ''}`; - const avatarEl = createDmAvatar(item.id, { upgrade: !isDemo, name, photo: isDemo ? item.photo : '' }); + const avatarEl = createDmAvatar(item.id, { upgrade: true, name }); avatarEl.classList.add('avatar'); avWrap.appendChild(avatarEl); row.prepend(avWrap); - const go = () => navigate(isDemo - ? `messages-list/lab/chat/${encodeURIComponent(item.id)}` - : `chat-view/${encodeURIComponent(item.id)}`); + const go = () => navigate(`chat-view/${encodeURIComponent(item.id)}`); row.addEventListener('click', go); row.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); go(); } @@ -214,9 +203,8 @@ export function render({ navigate, route }) { return row; } - // Оффлайн-демо: список из мока directMessages (с семантическими полями). - // На проде источник заменяется на реальные relations (relationFlagsForTarget/shineConfirmed/shine) — - // карточки и резолвер не меняются. + // Источник списка — мок directMessages (плейсхолдер). На проде заменяется реальными + // relations/chats (relationFlagsForTarget/shineConfirmed/shine) — карточки и резолвер не меняются. const items = Array.isArray(directMessages) ? directMessages : []; if (!items.length) { const empty = document.createElement('div'); diff --git a/shine-UI/js/pages/messages/dm-lab-chat.js b/shine-UI/js/pages/messages/dm-lab-chat.js deleted file mode 100644 index fd7fbe8..0000000 --- a/shine-UI/js/pages/messages/dm-lab-chat.js +++ /dev/null @@ -1,70 +0,0 @@ -// 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 = ` - - ${name} - demo - `; - 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 = ` - - - `; - 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; -} diff --git a/shine-UI/js/pages/messages/dm-lab-store.js b/shine-UI/js/pages/messages/dm-lab-store.js deleted file mode 100644 index 3c2d81d..0000000 --- a/shine-UI/js/pages/messages/dm-lab-store.js +++ /dev/null @@ -1,89 +0,0 @@ -// Demo-состояние ЛС для оффлайн-флоу /messages-list/lab (только demo, на проде НЕ используется). -// Хранится в localStorage, поэтому переживает навигацию список ↔ чат и перезагрузку. -// Источник стартовых тредов — мок directMessages: последнее сообщение = preview карточки. -import { directMessages } from '../../mock-data.js'; - -const KEY = 'dm-lab-demo-v1'; - -function nowLabel() { - try { - const d = new Date(); - return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; - } catch { - return ''; - } -} - -// Стартовый набор тредов: пара входящих, последнее = preview карточки (чтобы список совпал с моком). -function seed() { - const store = {}; - (Array.isArray(directMessages) ? directMessages : []).forEach((m) => { - const last = m.preview || m.lastMessage || 'Сообщение'; - store[m.id] = { - unread: Math.max(0, Math.trunc(Number(m.unreadCount) || 0)), - messages: [ - { from: 'in', text: 'Привет! Это тестовый диалог demo-режима.', time: m.time || '' }, - { from: 'in', text: last, time: m.time || '' }, - ], - }; - }); - return store; -} - -function readAll() { - try { - const raw = localStorage.getItem(KEY); - if (raw) { - const parsed = JSON.parse(raw); - if (parsed && typeof parsed === 'object') return parsed; - } - } catch {} - const fresh = seed(); - writeAll(fresh); - return fresh; -} - -function writeAll(store) { - try { localStorage.setItem(KEY, JSON.stringify(store)); } catch {} -} - -export function getThread(id) { - const all = readAll(); - const t = all[id]; - return t && Array.isArray(t.messages) ? t.messages : []; -} - -export function getUnread(id) { - const all = readAll(); - return all[id] ? Math.max(0, Math.trunc(Number(all[id].unread) || 0)) : 0; -} - -// Превью для списка = текст последнего сообщения треда (или fallback из мока). -export function getPreview(id, fallback = '') { - const msgs = getThread(id); - const last = msgs[msgs.length - 1]; - return last && last.text ? last.text : fallback; -} - -// Добавить исходящее сообщение; вернуть его (или null, если текст пуст). -export function appendOut(id, text) { - const clean = String(text || '').trim(); - if (!id || !clean) return null; - const all = readAll(); - if (!all[id]) all[id] = { unread: 0, messages: [] }; - const msg = { from: 'out', text: clean, time: nowLabel() }; - all[id].messages.push(msg); - writeAll(all); - return msg; -} - -// Открытие диалога сбрасывает непрочитанные у него. -export function markRead(id) { - const all = readAll(); - if (all[id]) { all[id].unread = 0; writeAll(all); } -} - -// На случай отладки: сбросить demo-состояние к стартовому. -export function resetDemo() { - writeAll(seed()); -} diff --git a/shine-UI/js/router.js b/shine-UI/js/router.js index 80f9c99..9bc56d2 100644 --- a/shine-UI/js/router.js +++ b/shine-UI/js/router.js @@ -150,15 +150,6 @@ export function getRoute() { return { pageId, params: { mode: segments[1] ? decodePart(segments[1]) : '' } }; } - // messages-list/: ловим второй сегмент как mode (нужно для demo-маршрута /messages-list/lab). - if (pageId === 'messages-list') { - // demo-чат под лабораторным префиксом: /messages-list/lab/chat/:id → отдельная demo-страница. - if (segments[1] === 'lab' && segments[2] === 'chat' && segments[3]) { - return { pageId: 'dm-lab-chat', params: { chatId: decodePart(segments[3]) } }; - } - return { pageId, params: { mode: segments[1] ? decodePart(segments[1]) : '' } }; - } - return { pageId, params: {} }; } diff --git a/shine-UI/styles/components.css b/shine-UI/styles/components.css index 3398dc5..4b5e272 100644 --- a/shine-UI/styles/components.css +++ b/shine-UI/styles/components.css @@ -3730,33 +3730,6 @@ button.dm-via-node:hover { border-color: rgba(25, 229, 138, 0.5); } даёт лишний скролл. Фон НЕ меняем — клиппим overflow на уровне страницы (как просит ТЗ, п.4). */ html, body { overflow-x: hidden; } -/* ===== Demo-чат лаборатории ЛС (dm-lab-chat) — только demo, прод chat-view не затрагивает ===== */ -.dm-chat-screen { display: flex; flex-direction: column; min-height: 100%; } -.dm-chat-head { - position: sticky; top: 0; z-index: 12; display: flex; align-items: center; gap: 12px; - padding: 14px; border-bottom: 1px solid rgba(240, 184, 46, 0.22); - background: linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.55)); - backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); -} -.dm-chat-back { - flex: 0 0 auto; width: 40px; height: 40px; border-radius: 12px; - display: grid; place-items: center; font-size: 26px; line-height: 1; - color: var(--rel-family); border: 1px solid rgba(240, 184, 46, 0.4); - background: rgba(10, 12, 18, 0.6); cursor: pointer; -} -.dm-chat-peer { flex: 1 1 auto; min-width: 0; font-size: 17px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.dm-chat-demo-tag { - flex: 0 0 auto; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; - color: rgba(244, 246, 255, 0.55); padding: 3px 8px; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.12); -} -.dm-chat-screen .dm-messages-log { - flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; - padding: 14px; padding-bottom: 16px; -} -.dm-chat-screen .bubble.in { align-self: flex-start; } -.dm-chat-screen .bubble.out { align-self: flex-end; } -.dm-chat-screen .dm-chat-input { display: grid; } - .dm-chat-wrap { gap: 12px; }