All checks were successful
Build AppImage / build (push) Successful in 6m56s
ToolDrawer ist jetzt 3. Spalte im Flex-Layout (Sidebar | Chat | Panel). Kein position:fixed, kein Backdrop, kein Overlay. Panel bleibt fest offen bis X-Button, Esc oder erneuter Sidebar-Klick. Chat wird schmaler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
4.4 KiB
Svelte
154 lines
4.4 KiB
Svelte
<script lang="ts">
|
|
// Hauptfenster-Layout (Phase 9.2 — 3-spaltig mit festem Panel)
|
|
//
|
|
// ┌─────────────────────────────────────────────────────┐
|
|
// │ Sidebar (240px) │ Chat (flex) │ Panel (420px) │
|
|
// │ - Suche │ ChatPanel │ ToolDrawer │
|
|
// │ - Sessions │ │ (optional) │
|
|
// │ - Nav-Rail │ │ │
|
|
// └─────────────────────────────────────────────────────┘
|
|
// Panel ist fester Teil des Flex-Layouts, kein Overlay.
|
|
// Schließt nur per X-Button, Esc oder erneuten Sidebar-Klick.
|
|
|
|
import { invoke } from '@tauri-apps/api/core';
|
|
import { listen } from '@tauri-apps/api/event';
|
|
import { onMount } from 'svelte';
|
|
import { chatDetached } from '$lib/stores/app';
|
|
import ChatPanel from '$lib/components/ChatPanel.svelte';
|
|
import Sidebar, { type DrawerSection } from '$lib/components/Sidebar.svelte';
|
|
import ToolDrawer from '$lib/components/ToolDrawer.svelte';
|
|
import QuickActions from '$lib/components/QuickActions.svelte';
|
|
|
|
let activeDrawer = $state<DrawerSection | null>(null);
|
|
let showQuickActions = $state(false);
|
|
|
|
function toggleDrawer(section: DrawerSection) {
|
|
activeDrawer = activeDrawer === section ? null : section;
|
|
}
|
|
|
|
function openSearch() {
|
|
showQuickActions = true;
|
|
}
|
|
|
|
onMount(async () => {
|
|
// Detach/Reattach
|
|
await listen('chat-reattached', () => { $chatDetached = false; });
|
|
await listen('chat-detached', () => { $chatDetached = true; });
|
|
|
|
// Globaler Cmd/Ctrl+K Listener fuer Quick-Actions
|
|
const handler = (e: KeyboardEvent) => {
|
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
|
|
e.preventDefault();
|
|
showQuickActions = !showQuickActions;
|
|
}
|
|
// Esc schliesst Panel
|
|
if (e.key === 'Escape' && activeDrawer) {
|
|
activeDrawer = null;
|
|
}
|
|
};
|
|
window.addEventListener('keydown', handler);
|
|
|
|
// Quick-Actions Navigation: Panel-Sektion bei Sub-Tab-Wahl oeffnen
|
|
await listen<{ panel: string; tab: string }>('navigate-tab', (event) => {
|
|
const t = event.payload.tab;
|
|
if (['activity', 'monitor', 'perf'].includes(t)) activeDrawer = 'activity';
|
|
else if (['memory', 'knowledge', 'context'].includes(t)) activeDrawer = 'memory';
|
|
else if (['programs', 'voice', 'agents', 'guards', 'hooks'].includes(t)) activeDrawer = 'tools';
|
|
else if (['settings', 'audit'].includes(t)) activeDrawer = 'settings';
|
|
});
|
|
|
|
return () => window.removeEventListener('keydown', handler);
|
|
});
|
|
|
|
function handleQuickAction(action: any) {
|
|
showQuickActions = false;
|
|
if (action?.invoke) {
|
|
invoke(action.invoke, action.invokeArgs ?? {}).catch((e) =>
|
|
console.error('Quick-Action invoke failed:', e)
|
|
);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="layout">
|
|
<Sidebar
|
|
{activeDrawer}
|
|
onSearchOpen={openSearch}
|
|
onDrawerToggle={toggleDrawer}
|
|
/>
|
|
|
|
<div class="main">
|
|
{#if !$chatDetached}
|
|
<ChatPanel />
|
|
{:else}
|
|
<div class="detached">
|
|
<p>Chat ist in einem eigenen Fenster.</p>
|
|
<button class="reattach" onclick={() => invoke('chat_window_close')}>
|
|
Zurückholen
|
|
</button>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
{#if activeDrawer}
|
|
<div class="panel">
|
|
<ToolDrawer
|
|
section={activeDrawer}
|
|
onClose={() => (activeDrawer = null)}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<QuickActions bind:visible={showQuickActions} onExecute={handleQuickAction} />
|
|
|
|
<style>
|
|
.layout {
|
|
display: flex;
|
|
height: 100%;
|
|
min-height: 0;
|
|
background: var(--bg-primary);
|
|
}
|
|
|
|
.main {
|
|
flex: 1;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--bg-primary);
|
|
}
|
|
|
|
.panel {
|
|
width: 420px;
|
|
flex-shrink: 0;
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
border-left: 1px solid var(--border);
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
.detached {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: var(--sp-3);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.reattach {
|
|
padding: var(--sp-2) var(--sp-4);
|
|
background: var(--accent);
|
|
color: var(--accent-fg);
|
|
border: 0;
|
|
border-radius: var(--r-sm);
|
|
font-size: var(--fs-md);
|
|
cursor: pointer;
|
|
}
|
|
.reattach:hover {
|
|
background: var(--accent-hover);
|
|
}
|
|
</style>
|