feat: window management system with minimize, fullscreen, and AI chat split
- Window manager store (Zustand) for managing open/minimized/fullscreen windows - Window component with header controls: KI-Chat toggle, fullscreen, minimize, close - AI chat panel with streaming chat via existing /ai/sessions API - WindowContainer renders all non-minimized windows - TopBar shows minimized windows as clickable pills - ContactEditForm extracted from ContactEditModal for window rendering - ContactsList and ContactDetailPage use openWindow() instead of modal state - Draggable windows with z-index management
This commit is contained in:
@@ -9,6 +9,7 @@ import { useAIContext } from '@/hooks/useAIContext';
|
||||
import { useAIUIControl } from '@/hooks/useAIUIControl';
|
||||
import { PluginRegistry } from '@/components/plugins/PluginRegistry';
|
||||
import { AIUIControlIndicator } from '@/components/ai-ui-control/AIUIControlIndicator';
|
||||
import { WindowContainer } from '@/components/window/WindowContainer';
|
||||
|
||||
export function AppShell() {
|
||||
const location = useLocation();
|
||||
@@ -44,6 +45,7 @@ export function AppShell() {
|
||||
{/* Message Sidebar — full height, right of TopBar and Toolbar */}
|
||||
{showMessageSidebar && <MessageSidebar />}
|
||||
<AIUIControlIndicator />
|
||||
<WindowContainer />
|
||||
<ToastContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,8 @@ import { useLogout } from '@/api/hooks';
|
||||
import { Avatar } from '@/components/ui/Avatar';
|
||||
import { SearchDropdown } from '@/components/shared/SearchDropdown';
|
||||
import { SuggestionBadge } from '@/components/ai/SuggestionBadge';
|
||||
import { Building, ChevronDown, Menu, Zap, Bot } from 'lucide-react';
|
||||
import { Building, ChevronDown, Menu, Zap, Bot, Layers } from 'lucide-react';
|
||||
import { useWindowStore } from '@/store/windowStore';
|
||||
|
||||
export function TopBar() {
|
||||
const { t } = useTranslation();
|
||||
@@ -17,6 +18,8 @@ export function TopBar() {
|
||||
const tenants = user?.tenants || [];
|
||||
const { toggleSidebar, toggleMessageSidebar } = useUIStore();
|
||||
const logoutMutation = useLogout();
|
||||
const minimizedWindows = useWindowStore((s) => s.windows.filter((w) => w.state === 'minimized'));
|
||||
const restoreWindow = useWindowStore((s) => s.restoreWindow);
|
||||
|
||||
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||
const userRef = useRef<HTMLDivElement>(null);
|
||||
@@ -77,6 +80,22 @@ export function TopBar() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Minimized windows */}
|
||||
{minimizedWindows.length > 0 && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
{minimizedWindows.map((win) => (
|
||||
<button
|
||||
key={win.id}
|
||||
onClick={() => restoreWindow(win.id)}
|
||||
className="flex items-center gap-1.5 bg-secondary-100 text-secondary-700 px-3 py-1 rounded-md text-sm hover:bg-secondary-200"
|
||||
title={win.title}
|
||||
>
|
||||
<Layers className="w-3.5 h-3.5" />
|
||||
<span className="max-w-32 truncate">{win.title}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{/* User menu */}
|
||||
<div ref={userRef} className="relative">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user