From b6512b2d8c13d8c06862fcea5e19b2fbdd457912 Mon Sep 17 00:00:00 2001 From: Josako Date: Mon, 22 Sep 2025 16:54:39 +0200 Subject: [PATCH 1/4] - Aanpassing layout van de chat-input. Character counter is ook weg op desktop. Scrollbar enkel zichtbaar indien nodig. Meer beschikbare ruimte in mobiele client. kleinere radius in de hoeken. - Gewijzigde logica voor hoogtebepaling chat-input en message history, zodat ook de mobiele client correct functioneert. --- eveai_chat_client/static/assets/css/chat.css | 25 +++++++-- .../static/assets/vue-components/ChatApp.vue | 11 ++-- .../assets/vue-components/ChatInput.vue | 52 ++++++------------- .../assets/vue-components/MessageHistory.vue | 4 +- nginx/frontend_src/js/chat-client.js | 22 +++++++- 5 files changed, 64 insertions(+), 50 deletions(-) diff --git a/eveai_chat_client/static/assets/css/chat.css b/eveai_chat_client/static/assets/css/chat.css index 9449b6d..adf0bea 100644 --- a/eveai_chat_client/static/assets/css/chat.css +++ b/eveai_chat_client/static/assets/css/chat.css @@ -14,7 +14,8 @@ /* App container layout */ .app-container { display: flex; - height: 100vh; + height: 100vh; /* fallback */ + height: 100dvh; /* prefer dynamic viewport unit */ width: 100%; } @@ -80,9 +81,23 @@ .content-area { flex: 1; background: linear-gradient(135deg, var(--gradient-start-color), var(--gradient-end-color)); - overflow-y: auto; + overflow-y: hidden; display: flex; flex-direction: column; + min-height: 0; + height: 100vh; /* fallback for desktop */ + height: 100dvh; /* prefer dynamic viewport on desktop */ +} + +.chat-container { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; /* laat kinderen (ChatApp) krimpen */ +} + +html, body { + height: 100%; } body { @@ -273,10 +288,14 @@ body { width: 100%; } + :root { --mobile-header-height: 60px; } /* default/minimum */ + /* Content area takes remaining space */ .content-area { flex: 1; - height: calc(100vh - 60px); /* Subtract mobile header height */ + height: calc(100vh - var(--mobile-header-height)); /* fallback */ + height: calc(100dvh - var(--mobile-header-height)); /* prefer dynamic viewport */ + min-height: 0; } } diff --git a/eveai_chat_client/static/assets/vue-components/ChatApp.vue b/eveai_chat_client/static/assets/vue-components/ChatApp.vue index 7dc6619..8ab2ddf 100644 --- a/eveai_chat_client/static/assets/vue-components/ChatApp.vue +++ b/eveai_chat_client/static/assets/vue-components/ChatApp.vue @@ -553,7 +553,8 @@ export default { .chat-app-container { display: flex; flex-direction: column; - height: 100vh; + flex: 1; + /* height: 100%; avoided to let flex sizing control height */ width: 100%; min-height: 0; max-width: 1000px; @@ -561,10 +562,12 @@ export default { margin-right: auto; padding: 20px; box-sizing: border-box; + overflow: hidden; } .chat-messages-area { flex: 1; + min-height: 0; /* ensure child can scroll */ overflow: hidden; display: flex; flex-direction: column; @@ -585,10 +588,4 @@ export default { flex: 0 0 auto; } -/* Responsive adjustments */ -@media (max-width: 768px) { - .chat-app-container { - height: 100vh; - } -} \ No newline at end of file diff --git a/eveai_chat_client/static/assets/vue-components/ChatInput.vue b/eveai_chat_client/static/assets/vue-components/ChatInput.vue index 08c470e..cc55a8a 100644 --- a/eveai_chat_client/static/assets/vue-components/ChatInput.vue +++ b/eveai_chat_client/static/assets/vue-components/ChatInput.vue @@ -42,6 +42,7 @@ ref="messageInput" v-model="localMessage" @keydown="handleKeydown" + @focus="autoResize" :placeholder="translatedPlaceholder" rows="1" :disabled="isLoading" @@ -50,10 +51,6 @@ :class="{ 'over-limit': isOverLimit }" > - -
- {{ characterCount }}/{{ maxLength }} -
@@ -142,12 +139,8 @@ export default { }; }, computed: { - characterCount() { - return this.localMessage.length; - }, - isOverLimit() { - return this.characterCount > this.maxLength; + return this.localMessage.length > this.maxLength; }, hasFormData() { @@ -239,12 +232,15 @@ export default { if (this.formData) { console.log('FormData bij mount:', JSON.stringify(this.formData)); } + // Herbereken bij viewport-wijziging (bv. rotatie op mobiel) + window.addEventListener('resize', this.autoResize, { passive: true }); }, beforeUnmount() { // Verwijder event listener bij unmount met de benoemde handler if (this.languageChangeHandler) { document.removeEventListener('language-changed', this.languageChangeHandler); } + window.removeEventListener('resize', this.autoResize); }, methods: { handleLanguageChange(event) { @@ -285,6 +281,8 @@ export default { } finally { // Reset de vertaling vlag this.isTranslating = false; + // Herbereken hoogte na vertaling + this.$nextTick(this.autoResize); } }, @@ -465,9 +463,9 @@ export default { .message-input { width: 100%; min-height: 40px; - padding: 10px 60px 10px 15px; /* Meer rechter padding voor character counter */ + padding: 10px 15px 10px 15px; /* counter verwijderd -> rechter padding omlaag */ border: 1px solid #ddd; - border-radius: 20px; + border-radius: 10px; resize: none; outline: none; transition: border-color 0.2s; @@ -478,35 +476,17 @@ export default { color: var(--human-message-text-color); /* Box-sizing om padding correct te berekenen */ box-sizing: border-box; + /* Laat intern scrollen toe bij >120px, maar verberg scrollbar visueel */ + overflow: auto; + -webkit-overflow-scrolling: touch; /* soepel scrollen op iOS */ + scrollbar-width: none; /* Firefox: verberg scrollbar */ } -/* Character counter */ -.character-counter { - position: absolute; - right: 15px; - bottom: 12px; - font-size: 12px; - color: var(--human-message-text-color); - opacity: 0.7; - pointer-events: none; /* Voorkom dat deze de textarea verstoort */ +/* WebKit/Chromium: scrollbar verbergen */ +.message-input::-webkit-scrollbar { + display: none; } -/* Character counter wordt rood bij overschrijding */ -.character-counter.over-limit { - color: #ff4d4f; - font-weight: bold; -} - -/* Verberg character counter op mobile */ -@media (max-width: 768px) { - .character-counter { - display: none; - } - - .message-input { - padding-right: 15px; /* Verminder van 60px naar 15px omdat counter weg is */ - } -} /* Input actions */ .input-actions { diff --git a/eveai_chat_client/static/assets/vue-components/MessageHistory.vue b/eveai_chat_client/static/assets/vue-components/MessageHistory.vue index 1e3a19a..66b510a 100644 --- a/eveai_chat_client/static/assets/vue-components/MessageHistory.vue +++ b/eveai_chat_client/static/assets/vue-components/MessageHistory.vue @@ -331,9 +331,9 @@ export default { display: flex; flex-direction: column; flex: 1; - height: 100%; + /* height: 100%; avoid forcing parent height */ min-height: 0; /* Laat kinderen scrollen */ - padding: 20px; + padding: 16px; /* iets minder padding om ruimte te besparen */ box-sizing: border-box; width: 100%; max-width: 1000px; diff --git a/nginx/frontend_src/js/chat-client.js b/nginx/frontend_src/js/chat-client.js index 413305e..6917659 100644 --- a/nginx/frontend_src/js/chat-client.js +++ b/nginx/frontend_src/js/chat-client.js @@ -160,20 +160,38 @@ function initializeMobileHeader() { }; const mountedApp = app.mount(container); - + + // Dynamisch de headerhoogte doorgeven aan CSS + const updateHeaderHeightVar = () => { + const isMobile = window.matchMedia('(max-width: 768px)').matches; + if (!isMobile) { + document.documentElement.style.removeProperty('--mobile-header-height'); + return; + } + const h = container.offsetHeight || 60; // fallback + document.documentElement.style.setProperty('--mobile-header-height', `${h}px`); + }; + + // Initieel instellen en bij gebeurtenissen herberekenen + requestAnimationFrame(updateHeaderHeightVar); + window.addEventListener('resize', updateHeaderHeightVar); + // Listen to language change events and update the mobile header's language provider const languageChangeHandler = (event) => { if (event.detail && event.detail.language) { console.log('MobileHeader: Received language change event:', event.detail.language); languageProvider.setLanguage(event.detail.language); + // taalwissel kan headerhoogte veranderen + requestAnimationFrame(updateHeaderHeightVar); } }; document.addEventListener('language-changed', languageChangeHandler); // Store the handler for cleanup if needed mountedApp._languageChangeHandler = languageChangeHandler; + mountedApp._updateHeaderHeightVar = updateHeaderHeightVar; - console.log('✅ MobileHeader component successfully mounted with LanguageProvider'); + console.log('✅ MobileHeader component successfully mounted with LanguageProvider en dynamische headerhoogte'); return mountedApp; } catch (error) { console.error('🚨 [CRITICAL ERROR] Bij initialiseren mobile header:', error); From 61ae9c3174ed60bade1c6ff60170499b5b2f69d9 Mon Sep 17 00:00:00 2001 From: Josako Date: Mon, 22 Sep 2025 22:24:46 +0200 Subject: [PATCH 2/4] - Adaptation of the form message layout, in such a way that labels are shown on top of their values iso left, allowing a decent rendering on mobile devices - refactoring message-content CSS --- .../static/assets/css/chat-components.css | 58 +----------- .../static/assets/css/chat-message.css | 6 +- eveai_chat_client/static/assets/css/chat.css | 10 +- .../static/assets/css/form-message.css | 4 +- .../assets/vue-components/ChatMessage.vue | 91 +++++++++++++++++-- .../assets/vue-components/DynamicForm.vue | 70 ++++++++++++-- .../assets/vue-components/FormMessage.vue | 11 ++- 7 files changed, 164 insertions(+), 86 deletions(-) diff --git a/eveai_chat_client/static/assets/css/chat-components.css b/eveai_chat_client/static/assets/css/chat-components.css index 96ed506..22d0d0f 100644 --- a/eveai_chat_client/static/assets/css/chat-components.css +++ b/eveai_chat_client/static/assets/css/chat-components.css @@ -155,18 +155,7 @@ } /* Zorg dat de progress tracker goed wordt weergegeven in een lege message bubble */ -.message-content:has(.message-text:empty) .message-progress { - margin-bottom: 0; -} - -/* Verberg de message content container als er geen inhoud is en de verwerking bezig is */ -.message-content:has(.message-text:empty):not(:has(.message-progress.completed)):not(:has(.message-progress.error)) { - background: transparent; - box-shadow: none; - border: none; - padding: 0; - margin: 0; -} +/* moved to ChatMessage.vue scoped styles */ /* Focus binnen ChatInput voor toegankelijkheid */ .chat-input:focus-within { @@ -208,33 +197,7 @@ justify-content: flex-start; } -/* Message content wrapper - dit wordt de bubble */ -.message-content { - max-width: 70%; - padding: 12px 16px; - border-radius: 18px; - word-wrap: break-word; - position: relative; - box-shadow: 0 2px 8px rgba(0,0,0,0.1); - transition: all 0.2s ease; - display: inline-block; -} - -/* User message bubble styling */ -.message.user .message-content { - background: var(--human-message-background); - color: var(--human-message-text-color); - border-bottom-right-radius: 4px; -} - -/* AI/Bot message bubble styling */ -.message.ai .message-content, -.message.bot .message-content { - background: var(--ai-message-background); - color: var(--ai-message-text-color); - border-bottom-left-radius: 4px; - margin-right: 60px; -} +/* moved to ChatMessage.vue scoped styles */ /* Message text content */ .message-text { @@ -435,10 +398,7 @@ } /* Hover effects voor message bubbles */ -.message-content:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0,0,0,0.15); -} +/* moved to ChatMessage.vue scoped styles */ /* Bestaande animation en date-separator blijven hetzelfde */ @keyframes messageSlideIn { @@ -483,11 +443,7 @@ padding: 0 15px; } - .message-content { - max-width: 85%; - padding: 10px 14px; - font-size: 14px; - } + /* moved to ChatMessage.vue scoped styles */ .message.user .message-content { margin-left: 40px; @@ -504,11 +460,7 @@ padding: 0 10px; } - .message-content { - max-width: 90%; - margin-left: 20px !important; - margin-right: 20px !important; - } + /* moved to ChatMessage.vue scoped styles */ } /* Progress Tracker Styling */ diff --git a/eveai_chat_client/static/assets/css/chat-message.css b/eveai_chat_client/static/assets/css/chat-message.css index 6fce9ac..a84e026 100644 --- a/eveai_chat_client/static/assets/css/chat-message.css +++ b/eveai_chat_client/static/assets/css/chat-message.css @@ -15,11 +15,7 @@ margin-right: auto; } -.message-content { - width: 100%; - font-family: Arial, sans-serif; - font-size: 14px; -} +/* moved to ChatMessage.vue scoped styles */ /* Tabel styling voor formulieren */ .form-result-table { diff --git a/eveai_chat_client/static/assets/css/chat.css b/eveai_chat_client/static/assets/css/chat.css index adf0bea..ce1cfe5 100644 --- a/eveai_chat_client/static/assets/css/chat.css +++ b/eveai_chat_client/static/assets/css/chat.css @@ -218,15 +218,7 @@ body { /* .message-content wordt nu gedefinieerd in chat-components.css */ -.user-message .message-content { - background-color: var(--message-user-bg); - color: var(--text-color); -} - -.bot-message .message-content { - background-color: var(--message-bot-bg); - color: var(--text-color); -} +/* moved to ChatMessage.vue scoped styles */ /* .chat-input-container wordt nu gedefinieerd in chat-components.css */ diff --git a/eveai_chat_client/static/assets/css/form-message.css b/eveai_chat_client/static/assets/css/form-message.css index a82cbf9..f0a61ae 100644 --- a/eveai_chat_client/static/assets/css/form-message.css +++ b/eveai_chat_client/static/assets/css/form-message.css @@ -54,6 +54,4 @@ word-break: break-word; } -.message-content { - max-width: 100%; -} +/* moved to ChatMessage.vue scoped styles */ diff --git a/eveai_chat_client/static/assets/vue-components/ChatMessage.vue b/eveai_chat_client/static/assets/vue-components/ChatMessage.vue index 4291636..884dc32 100644 --- a/eveai_chat_client/static/assets/vue-components/ChatMessage.vue +++ b/eveai_chat_client/static/assets/vue-components/ChatMessage.vue @@ -383,8 +383,8 @@ export default { /* User messages with forms get fixed width of 90% */ .message.user.has-form { - width: 90%; - max-width: none; + width: auto; /* niet breder maken dan standaard */ + max-width: 100%; } /* Styling for temporarily positioned AI messages */ @@ -421,9 +421,18 @@ export default { padding: 12px; } .message-content { - width: 100%; font-family: Arial, sans-serif; - font-size: 14px; + font-size: 12px; + max-width: 90%; + padding: 8px; + border-radius: 10px; + word-wrap: break-word; + position: relative; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + transition: all 0.2s ease; + display: inline-block; + width: 100%; + box-sizing: border-box; } /* EveAI Logo styling voor AI berichten */ @@ -448,12 +457,26 @@ export default { /* Formulier styling */ .form-display { - margin: 15px 0; color: var(--human-message-text-color); - padding: 15px; font-family: inherit; } +/* Neutraliseer dynamic-form look binnen message bubble voor user-form-values */ +.user-form-values .message-form .dynamic-form { + background: transparent; + box-shadow: none; + padding: 0; + max-width: 100%; + box-sizing: border-box; +} +.user-form-values .message-form .form-readonly, +.user-form-values .message-form .form-field-readonly, +.user-form-values .message-form .field-label, +.user-form-values .message-form .field-value { + max-width: 90%; + box-sizing: border-box; +} + /* Tabel styling voor formulieren */ .form-result-table { width: 100%; @@ -612,13 +635,65 @@ export default { max-width: 95%; } - /* User messages with forms get fixed width of 95% on mobile */ + /* User messages with forms: hou zelfde breedte als gewone tekst */ .message.user.has-form { - width: 95%; + width: auto; + max-width: 100%; } .form-result-table td:first-child { width: 40%; } } +/* migrated from global css: message-content visuals */ +.message.user .message-content { + background: var(--human-message-background); + color: var(--human-message-text-color); + border-bottom-right-radius: 4px; +} + +.message.ai .message-content, +.message.bot .message-content { + background: var(--ai-message-background); + color: var(--ai-message-text-color); + border-bottom-left-radius: 4px; + margin-right: 60px; +} + +/* Hover effects for message bubbles */ +.message-content:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0,0,0,0.15); +} + +/* Handle empty message content during processing */ +.message-content:has(.message-text:empty) .message-progress { + margin-bottom: 0; +} +.message-content:has(.message-text:empty):not(:has(.message-progress.completed)):not(:has(.message-progress.error)) { + background: transparent; + box-shadow: none; + border: none; + padding: 0; + margin: 0; +} + +/* Mobile responsiveness moved from global */ +@media (max-width: 768px) { + .message.user .message-content { + margin-left: 40px; + } + .message.ai .message-content, + .message.bot .message-content { + margin-right: 40px; + } +} + +@media (max-width: 480px) { + .message-content { + max-width: 90%; + margin-left: 20px !important; + margin-right: 20px !important; + } +} \ No newline at end of file diff --git a/eveai_chat_client/static/assets/vue-components/DynamicForm.vue b/eveai_chat_client/static/assets/vue-components/DynamicForm.vue index a51cbd2..4b03516 100644 --- a/eveai_chat_client/static/assets/vue-components/DynamicForm.vue +++ b/eveai_chat_client/static/assets/vue-components/DynamicForm.vue @@ -547,6 +547,8 @@ export default { border-radius: 8px; padding: 15px; box-shadow: 0 2px 15px rgba(0,0,0,0.1); + box-sizing: border-box; + max-width: 100%; } .form-header { @@ -558,7 +560,9 @@ export default { } .dynamic-form.readonly .form-header { - border-bottom: 1px solid #777; + border-bottom: none; /* alle borders weg in readonly */ + padding-bottom: 0; + margin-bottom: 8px; } .form-icon { @@ -722,34 +726,86 @@ export default { /* Read-only form styling */ .form-readonly { - padding: 10px 0; + padding: 8px 0; /* compacter binnen bubble */ + box-sizing: border-box; + max-width: 100%; } .form-field-readonly { display: flex; - margin-bottom: 8px; - padding-bottom: 8px; + align-items: flex-start; + gap: 8px; + margin-bottom: 6px; /* compacter */ + padding-bottom: 6px; + line-height: 1.3; /* iets compacter */ + box-sizing: border-box; + max-width: 100%; } .dynamic-form.readonly .form-field-readonly { - border-bottom: 1px solid #777; + border-bottom: none; /* alle borders weg in readonly */ } .field-label { flex: 0 0 30%; font-weight: 500; - padding-right: 10px; + padding-right: 8px; + box-sizing: border-box; + max-width: 100%; } .field-value { flex: 1; - word-break: break-word; + overflow-wrap: anywhere; /* desktop: meerregelig zonder overflow */ + box-sizing: border-box; + max-width: 100%; } .text-value { white-space: pre-wrap; } +/* Responsive aanpassingen voor read-only binnen message bubbles */ +@media (min-width: 768px) { + /* Desktop en groter: geen ellipsis, laat tekst wrappen */ + .dynamic-form.readonly .field-label, + .dynamic-form.readonly .field-value { + white-space: normal; + overflow: visible; + text-overflow: clip; + } +} + +@media (max-width: 767.98px) { + /* Mobiel: label boven waarde, vet label, ellipsis op één regel */ + .dynamic-form.readonly .form-field-readonly { + display: block; + border-bottom: none; /* alle borders weg in readonly */ + } + .dynamic-form.readonly .field-label { + display: block; + font-weight: 600; + margin-bottom: 3px; /* kleine afstand tussen label en waarde */ + padding-right: 0; + flex: none; + } + .dynamic-form.readonly .field-value { + display: block; + } + .dynamic-form.readonly .field-label, + .dynamic-form.readonly .field-value { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + /* Specifieke override voor text-value die anders pre-wrap afdwingt */ + .dynamic-form.readonly .field-value.text-value { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + /* Boolean icon styling */ .boolean-icon { font-size: 20px; diff --git a/eveai_chat_client/static/assets/vue-components/FormMessage.vue b/eveai_chat_client/static/assets/vue-components/FormMessage.vue index 6db2ec9..a0432d1 100644 --- a/eveai_chat_client/static/assets/vue-components/FormMessage.vue +++ b/eveai_chat_client/static/assets/vue-components/FormMessage.vue @@ -220,7 +220,7 @@ export default { } .message-content { - max-width: 100%; + max-width: 90%; } /* Responsive adjustments */ @@ -294,4 +294,13 @@ export default { border-bottom: 2px solid #000; } } +/* migrated from global css: message-content within form-message */ +.form-message .message-content { + max-width: 90%; + background: white; + border: 1px solid #e9ecef; + border-radius: 12px; + padding: 20px; + box-shadow: 0 4px 12px rgba(0,0,0,0.1); +} \ No newline at end of file From 3b23be0ea44fa220d9544917f51e20f21d6073a4 Mon Sep 17 00:00:00 2001 From: Josako Date: Mon, 22 Sep 2025 22:41:43 +0200 Subject: [PATCH 3/4] - Ensure long messages do not take all available space, rendering the UI unusable. We now have limits built in in the chat-input as well as in the message history. --- .../assets/vue-components/ChatMessage.vue | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/eveai_chat_client/static/assets/vue-components/ChatMessage.vue b/eveai_chat_client/static/assets/vue-components/ChatMessage.vue index 884dc32..5a59c39 100644 --- a/eveai_chat_client/static/assets/vue-components/ChatMessage.vue +++ b/eveai_chat_client/static/assets/vue-components/ChatMessage.vue @@ -2,7 +2,7 @@