fix(communications): compact mobile messenger workspace
This commit is contained in:
parent
f2ac97a841
commit
3425be1b8a
10 changed files with 70 additions and 73 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"generatedAt": "2026-09-12T05:25:45.504Z",
|
||||
"generatedAt": "2026-09-12T06:26:42.753Z",
|
||||
"module": "communications",
|
||||
"version": "v3.0",
|
||||
"referenceMockups": [
|
||||
|
|
@ -128,19 +128,19 @@
|
|||
"filename": "mobile-chat.png",
|
||||
"theme": "state-capture",
|
||||
"viewport": "mobile-chat",
|
||||
"capturedAt": "2026-09-12T05:25:36.209Z"
|
||||
"capturedAt": "2026-09-12T06:26:42.411Z"
|
||||
},
|
||||
{
|
||||
"filename": "mobile-contact.png",
|
||||
"theme": "state-capture",
|
||||
"viewport": "mobile-contact",
|
||||
"capturedAt": "2026-09-12T05:25:36.390Z"
|
||||
"capturedAt": "2026-09-12T06:26:42.582Z"
|
||||
},
|
||||
{
|
||||
"filename": "mobile-list.png",
|
||||
"theme": "state-capture",
|
||||
"viewport": "mobile-list",
|
||||
"capturedAt": "2026-09-12T05:25:35.998Z"
|
||||
"capturedAt": "2026-09-12T06:26:42.215Z"
|
||||
},
|
||||
{
|
||||
"filename": "noble-green-desktop-1280.png",
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 78 KiB |
|
|
@ -134,7 +134,7 @@ test.describe('Scenario 13: Communications Visual & Responsive Design System V3
|
|||
await expect(backToListBtn).toBeVisible();
|
||||
|
||||
// Check bottom contact teaser button
|
||||
const profileTeaserBtn = activeChat.locator('button[aria-label="Открыть карточку контакта"]');
|
||||
const profileTeaserBtn = activeChat.getByRole('button', { name: /Открыть.*контакт/i });
|
||||
await expect(profileTeaserBtn).toBeVisible();
|
||||
|
||||
// Check message composer is positioned within viewport
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { QuickActionsModal } from '../shell/QuickActionsModal';
|
|||
import { NotificationsDrawer } from '../shell/NotificationsDrawer';
|
||||
import { Drawer } from '../../shared/ui';
|
||||
import { useResponsive } from '../../shared/lib/useResponsive';
|
||||
import { useCommunicationsStore } from '../../features/communications/services/communicationsService';
|
||||
|
||||
export const AppShell: React.FC = () => {
|
||||
const {
|
||||
|
|
@ -25,6 +26,7 @@ export const AppShell: React.FC = () => {
|
|||
const profile = getActiveProfile();
|
||||
const location = useLocation();
|
||||
const isCommunicationsPage = location.pathname.startsWith('/communications');
|
||||
const isMobileChatOpen = useCommunicationsStore((state) => state.isMobileChatOpen);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
|
|
@ -80,13 +82,13 @@ export const AppShell: React.FC = () => {
|
|||
|
||||
{/* Center Work Area */}
|
||||
<div className="flex-1 flex flex-col min-w-0 overflow-hidden bg-krona-workspace">
|
||||
<Topbar />
|
||||
{!(isEffectiveMobile && isCommunicationsPage && isMobileChatOpen) && <Topbar />}
|
||||
|
||||
{/* Main Content Router Outlet */}
|
||||
<main
|
||||
className={`flex-1 min-h-0 ${
|
||||
isCommunicationsPage
|
||||
? `overflow-hidden flex flex-col pt-0 px-0 ${isEffectiveMobile ? 'pb-20' : 'pb-0'}`
|
||||
? `overflow-hidden flex flex-col pt-0 px-0 ${isEffectiveMobile ? 'pb-14' : 'pb-0'}`
|
||||
: `overflow-y-auto ${isEffectiveMobile ? 'pb-24' : 'pb-8'} p-3 sm:p-4 md:p-6`
|
||||
}`}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ export const BottomNav: React.FC = () => {
|
|||
<nav
|
||||
aria-label="Мобильная навигация"
|
||||
data-testid="bottom-nav"
|
||||
className="fixed bottom-0 inset-x-0 bg-krona-surface text-krona-secondary border-t border-krona-border flex items-center justify-around z-40 px-1 pt-1 pb-[max(0.5rem,env(safe-area-inset-bottom))] shadow-lg backdrop-blur-md"
|
||||
className="fixed bottom-0 inset-x-0 bg-krona-surface text-krona-secondary border-t border-krona-border flex items-center justify-around z-40 px-1 pt-0.5 pb-[max(0.25rem,env(safe-area-inset-bottom))] shadow-lg backdrop-blur-md"
|
||||
>
|
||||
{/* 1. Главная (KPI Сводка) */}
|
||||
<button
|
||||
onClick={() => navigate('/?tab=dashboard')}
|
||||
className={`flex-1 min-h-[48px] min-w-[44px] flex flex-col items-center justify-center gap-1 p-1 rounded-xl transition-colors select-none ${
|
||||
className={`flex-1 min-h-[44px] min-w-[44px] flex flex-col items-center justify-center gap-0.5 p-0.5 rounded-lg transition-colors select-none ${
|
||||
isDashboardActive
|
||||
? 'text-krona-gold font-bold bg-krona-gold/10'
|
||||
: 'text-krona-secondary hover:text-krona-primary active:bg-krona-workspace'
|
||||
|
|
@ -41,7 +41,7 @@ export const BottomNav: React.FC = () => {
|
|||
{/* 2. Модули (Единый каталог) */}
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className={`flex-1 min-h-[48px] min-w-[44px] flex flex-col items-center justify-center gap-1 p-1 rounded-xl transition-colors select-none ${
|
||||
className={`flex-1 min-h-[44px] min-w-[44px] flex flex-col items-center justify-center gap-0.5 p-0.5 rounded-lg transition-colors select-none ${
|
||||
isCatalogActive
|
||||
? 'text-krona-gold font-bold bg-krona-gold/10'
|
||||
: 'text-krona-secondary hover:text-krona-primary active:bg-krona-workspace'
|
||||
|
|
@ -56,7 +56,7 @@ export const BottomNav: React.FC = () => {
|
|||
<NavLink
|
||||
to="/tasks"
|
||||
className={({ isActive }) =>
|
||||
`flex-1 min-h-[48px] min-w-[44px] flex flex-col items-center justify-center gap-1 p-1 rounded-xl transition-colors select-none ${
|
||||
`flex-1 min-h-[44px] min-w-[44px] flex flex-col items-center justify-center gap-0.5 p-0.5 rounded-lg transition-colors select-none ${
|
||||
isActive
|
||||
? 'text-krona-gold font-bold bg-krona-gold/10'
|
||||
: 'text-krona-secondary hover:text-krona-primary active:bg-krona-workspace'
|
||||
|
|
@ -72,7 +72,7 @@ export const BottomNav: React.FC = () => {
|
|||
<NavLink
|
||||
to="/communications"
|
||||
className={({ isActive }) =>
|
||||
`flex-1 min-h-[48px] min-w-[44px] flex flex-col items-center justify-center gap-1 p-1 rounded-xl transition-colors select-none ${
|
||||
`flex-1 min-h-[44px] min-w-[44px] flex flex-col items-center justify-center gap-0.5 p-0.5 rounded-lg transition-colors select-none ${
|
||||
isActive
|
||||
? 'text-krona-gold font-bold bg-krona-gold/10'
|
||||
: 'text-krona-secondary hover:text-krona-primary active:bg-krona-workspace'
|
||||
|
|
@ -87,7 +87,7 @@ export const BottomNav: React.FC = () => {
|
|||
{/* 5. Ещё */}
|
||||
<button
|
||||
onClick={() => setIsDrawerOpen(true)}
|
||||
className={`flex-1 min-h-[48px] min-w-[44px] flex flex-col items-center justify-center gap-1 p-1 rounded-xl transition-colors select-none ${
|
||||
className={`flex-1 min-h-[44px] min-w-[44px] flex flex-col items-center justify-center gap-0.5 p-0.5 rounded-lg transition-colors select-none ${
|
||||
isDrawerOpen
|
||||
? 'text-krona-gold font-bold bg-krona-gold/10'
|
||||
: 'text-krona-secondary hover:text-krona-primary active:bg-krona-workspace'
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ export const Topbar: React.FC = () => {
|
|||
return (
|
||||
<header className="sticky top-0 z-30 bg-krona-surface/95 backdrop-blur-md border-b border-krona-border text-krona-primary shadow-xs">
|
||||
{/* Mobile Topbar (< 768px): Minimal, clean, zero overflow */}
|
||||
<div className="flex md:hidden h-14 px-3 items-center justify-between gap-2">
|
||||
<div className="flex md:hidden h-12 px-2.5 items-center justify-between gap-2">
|
||||
{/* Left: Logo & Current Section Title */}
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<div
|
||||
|
|
@ -99,7 +99,7 @@ export const Topbar: React.FC = () => {
|
|||
{/* AI Trigger */}
|
||||
<button
|
||||
onClick={() => setIsAiDrawerOpen(true)}
|
||||
className="w-11 h-11 min-w-[44px] min-h-[44px] rounded-xl bg-krona-workspace text-krona-gold hover:text-krona-gold-text border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
className="w-10 h-10 min-w-10 min-h-10 rounded-xl bg-krona-workspace text-krona-gold hover:text-krona-gold-text border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
title="Krona AI"
|
||||
aria-label="Krona AI"
|
||||
>
|
||||
|
|
@ -109,7 +109,7 @@ export const Topbar: React.FC = () => {
|
|||
{/* Notifications Trigger */}
|
||||
<button
|
||||
onClick={() => setIsNotificationsOpen(true)}
|
||||
className="relative w-11 h-11 min-w-[44px] min-h-[44px] rounded-xl bg-krona-workspace text-krona-secondary hover:text-krona-primary border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
className="relative w-10 h-10 min-w-10 min-h-10 rounded-xl bg-krona-workspace text-krona-secondary hover:text-krona-primary border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
title="Уведомления"
|
||||
aria-label="Уведомления"
|
||||
data-testid="mobile-notifications-btn"
|
||||
|
|
@ -123,7 +123,7 @@ export const Topbar: React.FC = () => {
|
|||
{/* Profile / Menu Drawer Trigger */}
|
||||
<button
|
||||
onClick={() => setIsMobileDrawerOpen(true)}
|
||||
className="w-11 h-11 min-w-[44px] min-h-[44px] rounded-xl bg-krona-workspace text-krona-primary border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
className="w-10 h-10 min-w-10 min-h-10 rounded-xl bg-krona-workspace text-krona-primary border border-krona-border flex items-center justify-center active:scale-95 transition-all"
|
||||
title="Меню управления"
|
||||
aria-label="Открыть меню управления"
|
||||
data-testid="mobile-menu-btn"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
|
||||
export function CommunicationsModule() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const { activeTab, setActiveTab } = useCommunicationsStore();
|
||||
const { activeTab, setActiveTab, isMobileChatOpen } = useCommunicationsStore();
|
||||
|
||||
const [isComposeEmailOpen, setIsComposeEmailOpen] = useState(false);
|
||||
const [isCreateChannelOpen, setIsCreateChannelOpen] = useState(false);
|
||||
|
|
@ -38,13 +38,15 @@ export function CommunicationsModule() {
|
|||
return (
|
||||
<div className="h-full min-h-0 flex flex-col bg-[var(--krona-bg-workspace)] overflow-hidden">
|
||||
{/* Header */}
|
||||
<CommunicationsHeader
|
||||
activeTab={currentTab}
|
||||
onTabChange={handleTabChange}
|
||||
unreadChats={48}
|
||||
unreadEmails={10}
|
||||
unreadChannels={4}
|
||||
/>
|
||||
<div className={currentTab === 'messengers' && isMobileChatOpen ? 'hidden sm:block' : ''}>
|
||||
<CommunicationsHeader
|
||||
activeTab={currentTab}
|
||||
onTabChange={handleTabChange}
|
||||
unreadChats={48}
|
||||
unreadEmails={10}
|
||||
unreadChannels={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Body Views */}
|
||||
<main className="flex-1 min-h-0 flex flex-col overflow-hidden">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect, type FormEvent } from 'react';
|
|||
import {
|
||||
Search, ArrowUpDown, Star, Phone, Video, UserPlus,
|
||||
MoreVertical, Paperclip, Sparkles, Smile, Mic, Send, Download, FileText,
|
||||
ArrowLeft, ChevronRight, CheckCheck, Plus,
|
||||
ArrowLeft, CheckCheck, Plus,
|
||||
Briefcase, CheckSquare, ShieldCheck
|
||||
} from 'lucide-react';
|
||||
import { useCommunicationsStore } from '../services/communicationsService';
|
||||
|
|
@ -171,11 +171,15 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
// Dialogs list section
|
||||
const dialogListSection = (
|
||||
<section
|
||||
className="w-full h-full bg-[var(--krona-surface-raised)] rounded-2xl border border-[var(--krona-border-subtle)] shadow-[var(--krona-shadow-soft)] flex flex-col min-h-0 overflow-hidden"
|
||||
className={`w-full h-full bg-[var(--krona-surface-raised)] flex flex-col min-h-0 overflow-hidden ${
|
||||
layoutMode === 'compact'
|
||||
? 'rounded-none border-0 shadow-none'
|
||||
: 'rounded-2xl border border-[var(--krona-border-subtle)] shadow-[var(--krona-shadow-soft)]'
|
||||
}`}
|
||||
aria-label="Список диалогов"
|
||||
>
|
||||
{/* Search and filters header */}
|
||||
<div className="p-3.5 border-b border-[var(--krona-border-subtle)] space-y-2.5 shrink-0">
|
||||
<div className={`${layoutMode === 'compact' ? 'p-2 space-y-1.5' : 'p-3.5 space-y-2.5'} border-b border-[var(--krona-border-subtle)] shrink-0`}>
|
||||
<div className="relative">
|
||||
<Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-[var(--krona-text-muted)]" />
|
||||
<input
|
||||
|
|
@ -255,7 +259,9 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
setIsMobileChatOpen(true);
|
||||
setIsContactDrawerOpen(false);
|
||||
}}
|
||||
className={`w-full p-3.5 text-left flex items-start gap-3 transition-colors border-l-4 min-h-[76px] ${
|
||||
className={`w-full text-left flex items-start transition-colors border-l-4 ${
|
||||
layoutMode === 'compact' ? 'px-3 py-2.5 gap-2.5 min-h-[64px]' : 'p-3.5 gap-3 min-h-[76px]'
|
||||
} ${
|
||||
isActive
|
||||
? 'bg-[var(--krona-surface-selected)] border-l-[var(--krona-primary)]'
|
||||
: 'border-l-transparent hover:bg-[var(--krona-surface-hover)]'
|
||||
|
|
@ -316,17 +322,21 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
// Active chat section
|
||||
const activeChatSection = (
|
||||
<section
|
||||
className="w-full h-full bg-[var(--krona-surface-raised)] rounded-2xl border border-[var(--krona-border-subtle)] shadow-[var(--krona-shadow-soft)] flex flex-col min-h-0 overflow-hidden"
|
||||
className={`w-full h-full bg-[var(--krona-surface-raised)] flex flex-col min-h-0 overflow-hidden ${
|
||||
layoutMode === 'compact'
|
||||
? 'rounded-none border-0 shadow-none'
|
||||
: 'rounded-2xl border border-[var(--krona-border-subtle)] shadow-[var(--krona-shadow-soft)]'
|
||||
}`}
|
||||
aria-label="Активный диалог"
|
||||
>
|
||||
{/* Chat Header */}
|
||||
<div className="h-16 px-4 bg-[var(--krona-surface)] border-b border-[var(--krona-border-subtle)] flex items-center justify-between gap-3 shrink-0">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<div className={`${layoutMode === 'compact' ? 'h-12 px-2' : 'h-16 px-4'} bg-[var(--krona-surface)] border-b border-[var(--krona-border-subtle)] flex items-center justify-between gap-2 shrink-0`}>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
{layoutMode === 'compact' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsMobileChatOpen(false)}
|
||||
className="w-9 h-9 -ml-1 rounded-lg flex items-center justify-center text-[var(--krona-text-secondary)] hover:bg-[var(--krona-surface-hover)]"
|
||||
className="w-9 h-9 -ml-1 rounded-full flex items-center justify-center text-[var(--krona-text-secondary)] hover:bg-[var(--krona-surface-hover)]"
|
||||
aria-label="Назад к списку чатов"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
|
|
@ -379,7 +389,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
type: 'info',
|
||||
})
|
||||
}
|
||||
className="w-9 h-9 rounded-lg hover:bg-[var(--krona-surface-hover)] flex items-center justify-center transition-colors"
|
||||
className="hidden sm:flex w-9 h-9 rounded-lg hover:bg-[var(--krona-surface-hover)] items-center justify-center transition-colors"
|
||||
title="Аудиозвонок"
|
||||
aria-label="Аудиозвонок"
|
||||
>
|
||||
|
|
@ -394,7 +404,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
type: 'info',
|
||||
})
|
||||
}
|
||||
className="w-9 h-9 rounded-lg hover:bg-[var(--krona-surface-hover)] flex items-center justify-center transition-colors"
|
||||
className="hidden sm:flex w-9 h-9 rounded-lg hover:bg-[var(--krona-surface-hover)] items-center justify-center transition-colors"
|
||||
title="Видеозвонок"
|
||||
aria-label="Видеозвонок"
|
||||
>
|
||||
|
|
@ -414,6 +424,18 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
</button>
|
||||
)}
|
||||
|
||||
{layoutMode === 'compact' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsContactDrawerOpen(true)}
|
||||
className="w-9 h-9 rounded-full flex items-center justify-center text-[var(--krona-text-secondary)] hover:bg-[var(--krona-surface-hover)]"
|
||||
title="Карточка контакта"
|
||||
aria-label="Открыть карточку контакта"
|
||||
>
|
||||
<UserPlus className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="w-9 h-9 rounded-lg hover:bg-[var(--krona-surface-hover)] flex items-center justify-center transition-colors"
|
||||
|
|
@ -428,7 +450,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
{/* Messages Feed */}
|
||||
<div
|
||||
ref={messagesContainerRef}
|
||||
className="flex-1 min-h-0 overflow-y-auto p-4 space-y-3 bg-[var(--krona-bg-workspace)]/40"
|
||||
className={`flex-1 min-h-0 overflow-y-auto bg-[var(--krona-bg-workspace)]/40 ${layoutMode === 'compact' ? 'px-2.5 py-2 space-y-2' : 'p-4 space-y-3'}`}
|
||||
>
|
||||
<div className="text-center my-2">
|
||||
<span className="px-3 py-1 rounded-full text-[11px] font-medium bg-[var(--krona-surface)] text-[var(--krona-text-muted)] border border-[var(--krona-border-subtle)] shadow-2xs">
|
||||
|
|
@ -439,7 +461,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
{activeChat.messages.map((msg) => (
|
||||
<div
|
||||
key={msg.id}
|
||||
className={`flex gap-3 ${
|
||||
className={`flex ${layoutMode === 'compact' ? 'gap-2' : 'gap-3'} ${
|
||||
msg.direction === 'outgoing' ? 'justify-end' : 'justify-start'
|
||||
}`}
|
||||
>
|
||||
|
|
@ -455,7 +477,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
)}
|
||||
|
||||
<div
|
||||
className={`max-w-[85%] sm:max-w-[75%] rounded-2xl p-3.5 shadow-xs text-sm transition-colors ${
|
||||
className={`max-w-[88%] sm:max-w-[75%] rounded-2xl shadow-xs text-sm transition-colors ${layoutMode === 'compact' ? 'px-3 py-2' : 'p-3.5'} ${
|
||||
msg.direction === 'outgoing'
|
||||
? 'bg-[var(--krona-primary-soft)] border border-[var(--krona-border-subtle)] text-[var(--krona-text-primary)] rounded-tr-xs'
|
||||
: 'bg-[var(--krona-surface)] border border-[var(--krona-border-subtle)] text-[var(--krona-text-primary)] rounded-tl-xs'
|
||||
|
|
@ -515,7 +537,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
</div>
|
||||
|
||||
{/* Quick Replies Bar */}
|
||||
<div className="px-4 py-2 bg-[var(--krona-surface)]/60 border-t border-[var(--krona-border-subtle)] flex items-center gap-2 overflow-x-auto scrollbar-none shrink-0">
|
||||
{layoutMode !== 'compact' && <div className="px-4 py-2 bg-[var(--krona-surface)]/60 border-t border-[var(--krona-border-subtle)] flex items-center gap-2 overflow-x-auto scrollbar-none shrink-0">
|
||||
<span className="text-[11px] text-[var(--krona-text-muted)] font-medium shrink-0 flex items-center gap-1">
|
||||
<Sparkles className="w-3 h-3 text-[var(--krona-gold)]" /> Быстрые:
|
||||
</span>
|
||||
|
|
@ -529,12 +551,12 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
{qrText}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* Message Composer */}
|
||||
<form
|
||||
onSubmit={handleSend}
|
||||
className="p-3 sm:p-4 bg-[var(--krona-surface)] border-t border-[var(--krona-border-subtle)] shrink-0"
|
||||
className="p-1.5 sm:p-4 bg-[var(--krona-surface)] border-t border-[var(--krona-border-subtle)] shrink-0"
|
||||
>
|
||||
<div className="flex items-end gap-2 bg-[var(--krona-bg-workspace)] border border-[var(--krona-border)] rounded-xl p-1.5 focus-within:border-[var(--krona-primary)] transition-colors">
|
||||
<button
|
||||
|
|
@ -613,35 +635,6 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
</div>
|
||||
</form>
|
||||
|
||||
{/* Mobile Bottom Contact Teaser Bar (Level 2 -> Level 3 drilldown) */}
|
||||
{layoutMode === 'compact' && (
|
||||
<div className="p-3 bg-[var(--krona-surface)] border-t border-[var(--krona-border-subtle)] flex items-center justify-between gap-3 shrink-0">
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
<Avatar
|
||||
src={activeChat.contact.avatarUrl}
|
||||
alt={activeChat.contact.name}
|
||||
initials={activeChat.contact.initials}
|
||||
size="sm"
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<span className="font-semibold text-xs text-[var(--krona-text-primary)] truncate block">
|
||||
{activeChat.contact.name}
|
||||
</span>
|
||||
<span className="text-[11px] text-[var(--krona-text-secondary)] truncate block">
|
||||
{activeChat.contact.company}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsContactDrawerOpen(true)}
|
||||
className="p-1.5 rounded-lg text-[var(--krona-primary)] hover:bg-[var(--krona-surface-hover)]"
|
||||
aria-label="Открыть карточку контакта"
|
||||
>
|
||||
<ChevronRight className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
|
||||
|
|
@ -652,7 +645,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
className="flex-1 min-h-0 flex flex-col bg-[var(--krona-bg-workspace)] overflow-hidden"
|
||||
>
|
||||
{/* 1. Channel Switcher Row (# 17. Channel Switcher) */}
|
||||
<div className="bg-[var(--krona-surface)]/80 backdrop-blur-xs border-b border-[var(--krona-border-subtle)] px-3 sm:px-6 py-2 flex items-center justify-between gap-3 min-w-0 shrink-0">
|
||||
{!(layoutMode === 'compact' && isMobileChatOpen) && <div className="bg-[var(--krona-surface)]/80 backdrop-blur-xs border-b border-[var(--krona-border-subtle)] px-2 sm:px-6 py-1.5 sm:py-2 flex items-center justify-between gap-2 sm:gap-3 min-w-0 shrink-0">
|
||||
<div className="relative flex-1 min-w-0 flex items-center overflow-x-auto scrollbar-none py-0.5">
|
||||
<div className="flex items-center gap-2 shrink-0 pr-6">
|
||||
<ConnectorPill
|
||||
|
|
@ -722,10 +715,10 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
|
|||
<Plus className="w-4 h-4 text-[var(--krona-primary)]" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* 2. Main Workspace Canvas */}
|
||||
<div className="flex-1 min-h-0 p-3 sm:p-4 lg:p-5 flex gap-4 overflow-hidden">
|
||||
<div className={`flex-1 min-h-0 flex gap-4 overflow-hidden ${layoutMode === 'compact' ? 'p-0' : 'p-3 sm:p-4 lg:p-5'}`}>
|
||||
{/* COMPACT MODE (<600px): strictly 1 level at a time */}
|
||||
{layoutMode === 'compact' && (
|
||||
<>
|
||||
|
|
|
|||
Loading…
Reference in a new issue