diff --git a/static/css/assistant.css b/static/css/assistant.css index 22e9eea..20ac518 100644 --- a/static/css/assistant.css +++ b/static/css/assistant.css @@ -1,6 +1,7 @@ /* ChatGPT Assistent Styles - Verbesserte Version */ #chatgpt-assistant { font-family: 'Inter', sans-serif; + bottom: 4.5rem; } #assistant-chat { @@ -10,6 +11,7 @@ border-radius: 0.75rem; overflow: hidden; max-width: calc(100vw - 2rem); + max-height: 80vh !important; } #assistant-toggle { @@ -142,14 +144,21 @@ .typing-indicator span { height: 8px; width: 8px; - background-color: #888; border-radius: 50%; display: inline-block; margin: 0 2px; - opacity: 0.4; + opacity: 0.6; animation: bounce 1.4s infinite ease-in-out; } +body.dark .typing-indicator span { + background-color: rgba(255, 255, 255, 0.7); +} + +body:not(.dark) .typing-indicator span { + background-color: rgba(107, 114, 128, 0.8); +} + .typing-indicator span:nth-child(1) { animation-delay: 0s; } .typing-indicator span:nth-child(2) { animation-delay: 0.2s; } .typing-indicator span:nth-child(3) { animation-delay: 0.4s; } @@ -173,11 +182,12 @@ @media (max-width: 640px) { #assistant-chat { width: calc(100vw - 2rem) !important; + max-height: 70vh !important; } #chatgpt-assistant { right: 1rem; - bottom: 1rem; + bottom: 5rem; } } @@ -200,4 +210,27 @@ main { footer { flex-shrink: 0; +} + +/* Verbesserte Farbkontraste für Nachrichtenblasen */ +.user-message { + background-color: rgba(124, 58, 237, 0.1) !important; + color: #4B5563 !important; +} + +body.dark .user-message { + background-color: rgba(124, 58, 237, 0.2) !important; + color: #F9FAFB !important; +} + +.assistant-message { + background-color: #F3F4F6 !important; + color: #1F2937 !important; + border-left: 3px solid #8B5CF6; +} + +body.dark .assistant-message { + background-color: rgba(31, 41, 55, 0.5) !important; + color: #F9FAFB !important; + border-left: 3px solid #8B5CF6; } \ No newline at end of file diff --git a/static/js/modules/chatgpt-assistant.js b/static/js/modules/chatgpt-assistant.js index 0da90a2..0a7819c 100644 --- a/static/js/modules/chatgpt-assistant.js +++ b/static/js/modules/chatgpt-assistant.js @@ -247,130 +247,63 @@ class ChatGPTAssistant { const bubble = document.createElement('div'); bubble.className = sender === 'user' - ? 'bg-primary-100 dark:bg-primary-900 text-gray-800 dark:text-white rounded-lg py-2 px-3 max-w-[85%]' - : 'bg-gray-100 dark:bg-dark-700 text-gray-800 dark:text-white rounded-lg py-2 px-3 max-w-[85%]'; - - // Formatierung des Texts (mit Markdown für Assistent-Nachrichten) - let formattedText = ''; - - if (sender === 'assistant' && this.markdownParser) { - // Für Assistentnachrichten Markdown verwenden - try { - formattedText = this.markdownParser.parse(text); - - // CSS für Markdown-Formatierung hinzufügen - const markdownStyles = ` - .markdown-bubble h1, .markdown-bubble h2, .markdown-bubble h3, - .markdown-bubble h4, .markdown-bubble h5, .markdown-bubble h6 { - font-weight: bold; - margin-top: 0.5rem; - margin-bottom: 0.5rem; - } - .markdown-bubble h1 { font-size: 1.4rem; } - .markdown-bubble h2 { font-size: 1.3rem; } - .markdown-bubble h3 { font-size: 1.2rem; } - .markdown-bubble h4 { font-size: 1.1rem; } - .markdown-bubble ul, .markdown-bubble ol { - padding-left: 1.5rem; - margin: 0.5rem 0; - } - .markdown-bubble ul { list-style-type: disc; } - .markdown-bubble ol { list-style-type: decimal; } - .markdown-bubble p { margin: 0.5rem 0; } - .markdown-bubble code { - font-family: monospace; - background-color: rgba(0, 0, 0, 0.1); - padding: 1px 4px; - border-radius: 3px; - } - .markdown-bubble pre { - background-color: rgba(0, 0, 0, 0.1); - padding: 0.5rem; - border-radius: 4px; - overflow-x: auto; - margin: 0.5rem 0; - } - .markdown-bubble pre code { - background-color: transparent; - padding: 0; - } - .markdown-bubble blockquote { - border-left: 3px solid rgba(0, 0, 0, 0.2); - padding-left: 0.8rem; - margin: 0.5rem 0; - font-style: italic; - } - .dark .markdown-bubble code { - background-color: rgba(255, 255, 255, 0.1); - } - .dark .markdown-bubble pre { - background-color: rgba(255, 255, 255, 0.1); - } - .dark .markdown-bubble blockquote { - border-left-color: rgba(255, 255, 255, 0.2); - } - `; - - // Füge die Styles hinzu, wenn sie noch nicht vorhanden sind - if (!document.querySelector('#markdown-chat-styles')) { - const style = document.createElement('style'); - style.id = 'markdown-chat-styles'; - style.textContent = markdownStyles; - document.head.appendChild(style); - } - - // Klasse für Markdown-Formatierung hinzufügen - bubble.classList.add('markdown-bubble'); - } catch (error) { - console.error('Fehler bei der Markdown-Formatierung:', error); - // Fallback zur einfachen Formatierung - formattedText = text.split('\n').map(line => { - if (line.trim() === '') return '
'; - return `

${line}

`; - }).join(''); - } + ? 'user-message rounded-lg py-2 px-3 max-w-[85%]' + : 'assistant-message rounded-lg py-2 px-3 max-w-[85%]'; + + // Nachrichtentext einfügen, falls Markdown-Parser verfügbar, nutzen + if (this.markdownParser) { + bubble.innerHTML = this.markdownParser.parse(text); } else { - // Für Benutzernachrichten einfache Formatierung - formattedText = text.split('\n').map(line => { - if (line.trim() === '') return '
'; - return `

${line}

`; - }).join(''); + bubble.textContent = text; } - bubble.innerHTML = formattedText; + // Links in der Nachricht klickbar machen + const links = bubble.querySelectorAll('a'); + links.forEach(link => { + link.target = '_blank'; + link.rel = 'noopener noreferrer'; + link.className = 'text-primary-600 dark:text-primary-400 underline'; + }); + + // Code-Blöcke stylen + const codeBlocks = bubble.querySelectorAll('pre'); + codeBlocks.forEach(block => { + block.className = 'bg-gray-100 dark:bg-dark-900 p-2 rounded my-2 overflow-x-auto'; + }); + + const inlineCode = bubble.querySelectorAll('code:not(pre code)'); + inlineCode.forEach(code => { + code.className = 'bg-gray-100 dark:bg-dark-900 px-1 rounded font-mono text-sm'; + }); messageEl.appendChild(bubble); + this.chatHistory.appendChild(messageEl); - if (this.chatHistory) { - this.chatHistory.appendChild(messageEl); - - // Scroll zum Ende des Verlaufs - this.chatHistory.scrollTop = this.chatHistory.scrollHeight; - } + // Scrolle zum Ende des Chat-Verlaufs + this.chatHistory.scrollTop = this.chatHistory.scrollHeight; } /** - * Zeigt Vorschläge als klickbare Pills an - * @param {string[]} suggestions - Liste von Vorschlägen + * Zeigt Vorschläge für mögliche Fragen an + * @param {Array} suggestions - Array von Vorschlägen */ showSuggestions(suggestions) { - if (!this.suggestionArea) return; + if (!this.suggestionArea || !suggestions || !suggestions.length) return; // Vorherige Vorschläge entfernen this.suggestionArea.innerHTML = ''; - if (suggestions && suggestions.length > 0) { - suggestions.forEach(suggestion => { - const pill = document.createElement('button'); - pill.className = 'suggestion-pill text-sm bg-gray-200 dark:bg-dark-600 hover:bg-gray-300 dark:hover:bg-dark-500 text-gray-800 dark:text-gray-200 rounded-full px-3 py-1 mb-2 transition-colors'; - pill.textContent = suggestion; - this.suggestionArea.appendChild(pill); - }); - - this.suggestionArea.classList.remove('hidden'); - } else { - this.suggestionArea.classList.add('hidden'); - } + // Neue Vorschläge hinzufügen + suggestions.forEach((text, index) => { + const pill = document.createElement('button'); + pill.className = 'suggestion-pill text-sm px-3 py-1.5 rounded-full bg-primary-100 dark:bg-primary-900 text-primary-800 dark:text-primary-200 hover:bg-primary-200 dark:hover:bg-primary-800 transition-all duration-200'; + pill.style.animationDelay = `${index * 0.1}s`; + pill.textContent = text; + this.suggestionArea.appendChild(pill); + }); + + // Vorschlagsbereich anzeigen + this.suggestionArea.classList.remove('hidden'); } /** @@ -512,26 +445,33 @@ class ChatGPTAssistant { } /** - * Zeigt einen Ladeindikator im Chat an + * Zeigt eine Ladeanimation an */ showLoadingIndicator() { if (!this.chatHistory) return; - // Entferne vorhandenen Ladeindikator (falls vorhanden) - this.removeLoadingIndicator(); + // Prüfen, ob bereits ein Ladeindikator angezeigt wird + if (document.getElementById('assistant-loading-indicator')) return; const loadingEl = document.createElement('div'); - loadingEl.id = 'assistant-loading'; loadingEl.className = 'flex justify-start'; + loadingEl.id = 'assistant-loading-indicator'; const bubble = document.createElement('div'); - bubble.className = 'bg-gray-100 dark:bg-dark-700 text-gray-800 dark:text-white rounded-lg py-2 px-3'; - bubble.innerHTML = '
'; + bubble.className = 'assistant-message rounded-lg py-3 px-4 max-w-[85%] flex items-center'; + const typingIndicator = document.createElement('div'); + typingIndicator.className = 'typing-indicator'; + typingIndicator.innerHTML = ` + + + + `; + + bubble.appendChild(typingIndicator); loadingEl.appendChild(bubble); - this.chatHistory.appendChild(loadingEl); - // Scroll zum Ende des Verlaufs + this.chatHistory.appendChild(loadingEl); this.chatHistory.scrollTop = this.chatHistory.scrollHeight; } @@ -539,7 +479,7 @@ class ChatGPTAssistant { * Entfernt den Ladeindikator aus dem Chat */ removeLoadingIndicator() { - const loadingIndicator = document.getElementById('assistant-loading'); + const loadingIndicator = document.getElementById('assistant-loading-indicator'); if (loadingIndicator) { loadingIndicator.remove(); } diff --git a/templates/base.html b/templates/base.html index 353c47c..ef43f58 100644 --- a/templates/base.html +++ b/templates/base.html @@ -307,7 +307,7 @@ class="nav-link flex items-center" x-bind:class="darkMode ? 'bg-gradient-to-r from-purple-900/90 to-indigo-800/90 text-white font-medium px-4 py-2 rounded-xl hover:shadow-lg hover:shadow-purple-800/30 transition-all duration-300' - : 'bg-gradient-to-r from-purple-600/30 to-indigo-500/30 text-gray-800 font-medium px-4 py-2 rounded-xl hover:shadow-md transition-all duration-300'"> + : 'bg-gradient-to-r from-purple-600 to-indigo-500 text-white font-medium px-4 py-2 rounded-xl hover:shadow-md transition-all duration-300'"> KI-Chat {% if current_user.is_authenticated %} @@ -467,7 +467,7 @@ class="block w-full text-left py-3.5 px-4 rounded-xl transition-all duration-200 flex items-center" x-bind:class="darkMode ? 'bg-gradient-to-r from-purple-600/30 to-blue-500/30 text-white hover:from-purple-600/40 hover:to-blue-500/40' - : 'bg-gradient-to-r from-purple-500/10 to-blue-400/10 text-gray-900 hover:from-purple-500/20 hover:to-blue-400/20'"> + : 'bg-gradient-to-r from-purple-600 to-blue-500 text-white hover:from-purple-600/90 hover:to-blue-500/90'"> KI-Chat {% if current_user.is_authenticated %}