From 2b7dfa6e370ea4b46a7ff78cad933bad5fb0c67c Mon Sep 17 00:00:00 2001 From: Eddy Date: Mon, 20 Apr 2026 23:01:27 +0200 Subject: [PATCH] feat: Chat-Panel herausloesbar + Expand-Button Fix [appimage] - Neues Fenster fuer Chat-Panel (auf zweiten Monitor ziehbar) - Expand/Collapse nutzt jetzt $state Array statt Set (Svelte 5 Reaktivitaet) - Kein Collapse waehrend Streaming (verhindert unklickbare Buttons) Co-Authored-By: Claude Opus 4.6 --- src-tauri/src/chat_window.rs | 31 +++++++++++++++++++++++ src-tauri/src/lib.rs | 4 +++ src/lib/components/ChatPanel.svelte | 39 +++++++++++++++++++++++------ src/routes/chat-window/+page.svelte | 26 +++++++++++++++++++ 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 src-tauri/src/chat_window.rs create mode 100644 src/routes/chat-window/+page.svelte diff --git a/src-tauri/src/chat_window.rs b/src-tauri/src/chat_window.rs new file mode 100644 index 0000000..063a869 --- /dev/null +++ b/src-tauri/src/chat_window.rs @@ -0,0 +1,31 @@ +// Claude Desktop — Chat-Fenster herauslösen +// Öffnet den Chat-Panel in einem separaten Fenster + +use tauri::{AppHandle, Manager, WebviewUrl, WebviewWindowBuilder}; + +#[tauri::command] +pub async fn chat_window_open(app: AppHandle) -> Result<(), String> { + if let Some(win) = app.get_webview_window("chat-detached") { + win.show().map_err(|e| e.to_string())?; + win.set_focus().map_err(|e| e.to_string())?; + return Ok(()); + } + + WebviewWindowBuilder::new(&app, "chat-detached", WebviewUrl::App("/chat-window".into())) + .title("Claude \u{2014} Chat") + .inner_size(800.0, 900.0) + .min_inner_size(500.0, 400.0) + .center() + .build() + .map_err(|e| e.to_string())?; + + Ok(()) +} + +#[tauri::command] +pub async fn chat_window_close(app: AppHandle) -> Result<(), String> { + if let Some(win) = app.get_webview_window("chat-detached") { + win.close().map_err(|e| e.to_string())?; + } + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 75a5a37..137f6ba 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -23,6 +23,7 @@ mod session; mod teaching; mod update; mod voice; +mod chat_window; /// Initialisiert die App #[cfg_attr(mobile, tauri::mobile_entry_point)] @@ -145,6 +146,9 @@ pub fn run() { teaching::presentation_close, teaching::presentation_send_slide, teaching::presentation_clear, + // Chat-Fenster (herauslösen) + chat_window::chat_window_open, + chat_window::chat_window_close, // Auto-Update update::check_for_update, update::download_update, diff --git a/src/lib/components/ChatPanel.svelte b/src/lib/components/ChatPanel.svelte index d3e80d0..cc16033 100644 --- a/src/lib/components/ChatPanel.svelte +++ b/src/lib/components/ChatPanel.svelte @@ -7,6 +7,9 @@ import { get } from 'svelte/store'; import CommandPalette from './CommandPalette.svelte'; + // Props + let { detached = false }: { detached?: boolean } = $props(); + // Input-Referenz für Focus-Shortcuts let inputTextarea: HTMLTextAreaElement; @@ -25,15 +28,14 @@ // Collapse: Nachrichten mit > 25 Zeilen werden eingeklappt const COLLAPSE_LINES = 25; - let expandedMessages = new Set(); + let expandedMessages = $state([]); function toggleExpand(msgId: string) { - if (expandedMessages.has(msgId)) { - expandedMessages.delete(msgId); + if (expandedMessages.includes(msgId)) { + expandedMessages = expandedMessages.filter(id => id !== msgId); } else { - expandedMessages.add(msgId); + expandedMessages = [...expandedMessages, msgId]; } - expandedMessages = expandedMessages; } function shouldCollapse(content: string): boolean { @@ -819,6 +821,11 @@ 20000} class:danger={estimatedTokens > TOKEN_WARNING_THRESHOLD}> ~{(estimatedTokens / 1000).toFixed(1)}k Token + {#if !detached} + + {:else} + + {/if} @@ -878,7 +885,7 @@ {:else if message.role === 'assistant'} {#if message.content} - {#if shouldCollapse(message.content) && !expandedMessages.has(message.id)} + {#if shouldCollapse(message.content) && !expandedMessages.includes(message.id) && !($isProcessing && isLastAssistantMessage(index))}
{@html renderMarkdown(message.content.split('\n').slice(0, COLLAPSE_LINES).join('\n') + '\n...')}
@@ -887,7 +894,7 @@ {:else} {@html renderMarkdown(message.content)} - {#if shouldCollapse(message.content)} + {#if shouldCollapse(message.content) && !($isProcessing && isLastAssistantMessage(index))} @@ -1154,6 +1161,24 @@ color: var(--error); } + .detach-btn { + padding: 0.2rem 0.45rem; + background: var(--bg-tertiary, #2a2a3e); + border: 1px solid var(--border, #333); + border-radius: var(--radius-sm, 4px); + color: var(--text-secondary, #aaa); + cursor: pointer; + font-size: 0.85rem; + line-height: 1; + transition: all 0.15s ease; + } + + .detach-btn:hover { + background: var(--accent, #6c8aff); + color: white; + border-color: var(--accent, #6c8aff); + } + .chat-messages { flex: 1; overflow-y: auto; diff --git a/src/routes/chat-window/+page.svelte b/src/routes/chat-window/+page.svelte new file mode 100644 index 0000000..4b23792 --- /dev/null +++ b/src/routes/chat-window/+page.svelte @@ -0,0 +1,26 @@ + + +
+ +
+ +