- Start met Mobiele versie van de chat client.
This commit is contained in:
@@ -18,6 +18,16 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile header container - hidden on desktop */
|
||||||
|
#mobile-header-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Desktop layout - default */
|
||||||
|
#sidebar-container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sidebar styling */
|
/* Sidebar styling */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
@@ -254,4 +264,29 @@ body {
|
|||||||
|
|
||||||
/* .btn-primary wordt nu gedefinieerd in chat-components.css */
|
/* .btn-primary wordt nu gedefinieerd in chat-components.css */
|
||||||
|
|
||||||
|
/* Mobile responsive layout */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
/* Switch to vertical layout */
|
||||||
|
.app-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide desktop sidebar on mobile */
|
||||||
|
#sidebar-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show mobile header on mobile */
|
||||||
|
#mobile-header-container {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content area takes remaining space */
|
||||||
|
.content-area {
|
||||||
|
flex: 1;
|
||||||
|
height: calc(100vh - 60px); /* Subtract mobile header height */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsieve design regels worden nu gedefinieerd in chat-components.css */
|
/* Responsieve design regels worden nu gedefinieerd in chat-components.css */
|
||||||
|
|||||||
@@ -225,4 +225,22 @@ export default {
|
|||||||
color: white;
|
color: white;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile-specific styling when used in mobile header */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.language-selector {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-selector label {
|
||||||
|
display: none; /* Hide label in mobile header */
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-select {
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
min-width: 120px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
146
eveai_chat_client/static/assets/vue-components/MobileHeader.vue
Normal file
146
eveai_chat_client/static/assets/vue-components/MobileHeader.vue
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
<!-- MobileHeader.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="mobile-header">
|
||||||
|
<SideBarLogo
|
||||||
|
:logo-url="tenantMake.logo_url"
|
||||||
|
:make-name="tenantMake.name"
|
||||||
|
class="mobile-logo"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<LanguageSelector
|
||||||
|
:initial-language="initialLanguage"
|
||||||
|
:current-language="currentLanguage"
|
||||||
|
:supported-language-details="supportedLanguageDetails"
|
||||||
|
:allowed-languages="allowedLanguages"
|
||||||
|
@language-changed="handleLanguageChange"
|
||||||
|
class="mobile-language-selector"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import SideBarLogo from './SideBarLogo.vue';
|
||||||
|
import LanguageSelector from './LanguageSelector.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
tenantMake: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
name: '',
|
||||||
|
logo_url: '',
|
||||||
|
subtitle: ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initialLanguage: {
|
||||||
|
type: String,
|
||||||
|
default: 'en'
|
||||||
|
},
|
||||||
|
supportedLanguageDetails: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
allowedLanguages: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ['nl', 'en', 'fr', 'de']
|
||||||
|
},
|
||||||
|
apiPrefix: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['language-changed']);
|
||||||
|
|
||||||
|
const currentLanguage = ref(props.initialLanguage);
|
||||||
|
|
||||||
|
const handleLanguageChange = (newLanguage) => {
|
||||||
|
currentLanguage.value = newLanguage;
|
||||||
|
|
||||||
|
// Emit to parent
|
||||||
|
emit('language-changed', newLanguage);
|
||||||
|
|
||||||
|
// Global event for backward compatibility
|
||||||
|
const globalEvent = new CustomEvent('language-changed', {
|
||||||
|
detail: { language: newLanguage }
|
||||||
|
});
|
||||||
|
document.dispatchEvent(globalEvent);
|
||||||
|
|
||||||
|
// Update chatConfig
|
||||||
|
if (window.chatConfig) {
|
||||||
|
window.chatConfig.language = newLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save preference
|
||||||
|
localStorage.setItem('preferredLanguage', newLanguage);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mobile-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 15px;
|
||||||
|
background: var(--sidebar-background);
|
||||||
|
color: var(--sidebar-color);
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile logo styling - compact version */
|
||||||
|
.mobile-header :deep(.mobile-logo) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-logo .sidebar-logo) {
|
||||||
|
padding: 0;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-logo .logo-image) {
|
||||||
|
max-height: 40px;
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-logo .logo-placeholder) {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile language selector styling - compact horizontal version */
|
||||||
|
.mobile-header :deep(.mobile-language-selector) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-language-selector .language-selector) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-language-selector label) {
|
||||||
|
display: none; /* Hide label in mobile header */
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header :deep(.mobile-language-selector .language-select) {
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
min-width: 120px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show mobile header on mobile */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mobile-header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide mobile header on desktop */
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
.mobile-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -69,4 +69,22 @@ const handleImageError = () => {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile-specific styling when used in mobile header */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sidebar-logo {
|
||||||
|
padding: 5px 0; /* Reduce padding for mobile header */
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-image {
|
||||||
|
max-height: 40px; /* Smaller logo for mobile header */
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-placeholder {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -10,6 +10,8 @@ export { default as ProgressTracker } from './ProgressTracker.vue';
|
|||||||
export { default as DynamicForm } from './DynamicForm.vue';
|
export { default as DynamicForm } from './DynamicForm.vue';
|
||||||
export { default as FormField } from './FormField.vue';
|
export { default as FormField } from './FormField.vue';
|
||||||
export { default as FormMessage } from './FormMessage.vue';
|
export { default as FormMessage } from './FormMessage.vue';
|
||||||
|
export { default as SideBar } from './SideBar.vue';
|
||||||
|
export { default as MobileHeader } from './MobileHeader.vue';
|
||||||
|
|
||||||
// Log successful loading
|
// Log successful loading
|
||||||
console.log('Vue components loaded successfully from barrel export');
|
console.log('Vue components loaded successfully from barrel export');
|
||||||
1
eveai_chat_client/static/dist/chat-client.css
vendored
Normal file
1
eveai_chat_client/static/dist/chat-client.css
vendored
Normal file
File diff suppressed because one or more lines are too long
86
eveai_chat_client/static/dist/chat-client.js
vendored
Normal file
86
eveai_chat_client/static/dist/chat-client.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -48,7 +48,10 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app" class="app-container" data-vue-app="true">
|
<div id="app" class="app-container" data-vue-app="true">
|
||||||
<!-- Left sidebar - Vue component container -->
|
<!-- Mobile header - Vue component container (hidden on desktop) -->
|
||||||
|
<div id="mobile-header-container"></div>
|
||||||
|
|
||||||
|
<!-- Left sidebar - Vue component container (hidden on mobile) -->
|
||||||
<div id="sidebar-container"></div>
|
<div id="sidebar-container"></div>
|
||||||
|
|
||||||
<!-- Right content area - contains the chat client -->
|
<!-- Right content area - contains the chat client -->
|
||||||
|
|||||||
@@ -21,48 +21,77 @@ window.Vue = { createApp };
|
|||||||
window.marked = marked;
|
window.marked = marked;
|
||||||
|
|
||||||
// Gebruik barrel export voor componenten
|
// Gebruik barrel export voor componenten
|
||||||
import * as Components from '../../../eveai_chat_client/static/assets/js/components/index.js';
|
import * as Components from '../../../eveai_chat_client/static/assets/vue-components/index.js';
|
||||||
|
|
||||||
// Maak Components globaal beschikbaar voor debugging
|
// Maak Components globaal beschikbaar voor debugging
|
||||||
window.Components = Components;
|
window.Components = Components;
|
||||||
console.log('Components loaded:', Object.keys(Components));
|
console.log('Components loaded:', Object.keys(Components));
|
||||||
|
|
||||||
// Main chat application - moet als laatste worden geladen
|
// Main chat application - moet als laatste worden geladen
|
||||||
import { ChatApp } from '../../../eveai_chat_client/static/assets/js/ChatApp.js';
|
import ChatApp from '../../../eveai_chat_client/static/assets/vue-components/ChatApp.vue';
|
||||||
|
|
||||||
// Wacht tot het document volledig is geladen voordat we Vue initialiseren
|
// Wacht tot het document volledig is geladen voordat we Vue initialiseren
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
console.log('Initializing Chat Application');
|
console.log('Initializing Chat Application');
|
||||||
|
|
||||||
// Check of #app element bestaat
|
|
||||||
const appElement = document.getElementById('app');
|
|
||||||
if (!appElement) {
|
|
||||||
console.error('DOM element #app not found. Cannot initialize Vue application.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('DOM element #app exists:', appElement);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Maak de Vue applicatie aan
|
// Mount SideBar component to sidebar-container
|
||||||
const app = createApp(ChatApp);
|
const sidebarContainer = document.getElementById('sidebar-container');
|
||||||
|
if (sidebarContainer && Components.SideBar) {
|
||||||
// Registreer alle componenten globaal
|
const sidebarApp = createApp(Components.SideBar, {
|
||||||
for (const [name, component] of Object.entries(Components)) {
|
tenantMake: window.chatConfig?.tenantMake || { name: 'EveAI', logo_url: '' },
|
||||||
app.component(name, component);
|
explanationText: window.chatConfig?.explanationText || '',
|
||||||
|
initialLanguage: window.chatConfig?.language || 'en',
|
||||||
|
supportedLanguageDetails: window.chatConfig?.supportedLanguageDetails || {},
|
||||||
|
allowedLanguages: window.chatConfig?.allowedLanguages || ['nl', 'en', 'fr', 'de'],
|
||||||
|
apiPrefix: window.chatConfig?.apiPrefix || ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// Registreer componenten voor sidebar app
|
||||||
|
for (const [name, component] of Object.entries(Components)) {
|
||||||
|
sidebarApp.component(name, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
sidebarApp.mount('#sidebar-container');
|
||||||
|
console.log('SideBar mounted successfully');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Voeg de IconManagerMixin toe voor alle componenten
|
// Mount MobileHeader component to mobile-header-container
|
||||||
app.mixin(IconManagerMixin);
|
const mobileHeaderContainer = document.getElementById('mobile-header-container');
|
||||||
|
if (mobileHeaderContainer && Components.MobileHeader) {
|
||||||
|
const mobileHeaderApp = createApp(Components.MobileHeader, {
|
||||||
|
tenantMake: window.chatConfig?.tenantMake || { name: 'EveAI', logo_url: '' },
|
||||||
|
initialLanguage: window.chatConfig?.language || 'en',
|
||||||
|
supportedLanguageDetails: window.chatConfig?.supportedLanguageDetails || {},
|
||||||
|
allowedLanguages: window.chatConfig?.allowedLanguages || ['nl', 'en', 'fr', 'de'],
|
||||||
|
apiPrefix: window.chatConfig?.apiPrefix || ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// Registreer componenten voor mobile header app
|
||||||
|
for (const [name, component] of Object.entries(Components)) {
|
||||||
|
mobileHeaderApp.component(name, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
mobileHeaderApp.mount('#mobile-header-container');
|
||||||
|
console.log('MobileHeader mounted successfully');
|
||||||
|
}
|
||||||
|
|
||||||
// Mount de applicatie op #app
|
// Mount ChatApp to the chat container
|
||||||
const mountedApp = app.mount('#app');
|
const chatContainer = document.querySelector('.chat-container');
|
||||||
|
if (chatContainer) {
|
||||||
|
const chatApp = createApp(ChatApp);
|
||||||
|
|
||||||
|
// Registreer alle componenten globaal voor chat app
|
||||||
|
for (const [name, component] of Object.entries(Components)) {
|
||||||
|
chatApp.component(name, component);
|
||||||
|
}
|
||||||
|
|
||||||
// Bewaar een referentie naar de app voor debugging
|
chatApp.mount('.chat-container');
|
||||||
window.__vueApp = app;
|
console.log('ChatApp mounted successfully');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Vue app mounted successfully');
|
console.log('All Vue apps mounted successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error initializing Vue application:', error);
|
console.error('Error initializing Vue applications:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
206
test_mobile_header_fix.py
Normal file
206
test_mobile_header_fix.py
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify mobile header visibility fix for eveai_chat_client
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
def test_mobile_header_css_fix():
|
||||||
|
"""Test that MobileHeader component has correct CSS media queries"""
|
||||||
|
print("Testing MobileHeader CSS fix...")
|
||||||
|
|
||||||
|
mobile_header_path = 'eveai_chat_client/static/assets/vue-components/MobileHeader.vue'
|
||||||
|
|
||||||
|
if not os.path.exists(mobile_header_path):
|
||||||
|
print(f"❌ MobileHeader.vue not found at {mobile_header_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open(mobile_header_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for mobile media query (show on mobile)
|
||||||
|
mobile_show_pattern = r'@media\s*\(\s*max-width:\s*768px\s*\)\s*\{[^}]*\.mobile-header\s*\{[^}]*display:\s*flex'
|
||||||
|
mobile_show_match = re.search(mobile_show_pattern, content, re.DOTALL)
|
||||||
|
|
||||||
|
if not mobile_show_match:
|
||||||
|
print("❌ Missing mobile media query to show mobile header")
|
||||||
|
print(" Expected: @media (max-width: 768px) with .mobile-header { display: flex }")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✓ Found mobile media query to show header on mobile devices")
|
||||||
|
|
||||||
|
# Check for desktop media query (hide on desktop)
|
||||||
|
desktop_hide_pattern = r'@media\s*\(\s*min-width:\s*769px\s*\)\s*\{[^}]*\.mobile-header\s*\{[^}]*display:\s*none'
|
||||||
|
desktop_hide_match = re.search(desktop_hide_pattern, content, re.DOTALL)
|
||||||
|
|
||||||
|
if not desktop_hide_match:
|
||||||
|
print("❌ Missing desktop media query to hide mobile header")
|
||||||
|
print(" Expected: @media (min-width: 769px) with .mobile-header { display: none }")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✓ Found desktop media query to hide header on desktop devices")
|
||||||
|
|
||||||
|
# Check that both media queries exist in correct order
|
||||||
|
mobile_pos = content.find('@media (max-width: 768px)')
|
||||||
|
desktop_pos = content.find('@media (min-width: 769px)')
|
||||||
|
|
||||||
|
if mobile_pos == -1 or desktop_pos == -1:
|
||||||
|
print("❌ Media queries not found in expected format")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if mobile_pos > desktop_pos:
|
||||||
|
print("⚠️ Warning: Mobile media query comes after desktop query (may cause specificity issues)")
|
||||||
|
|
||||||
|
print("✅ MobileHeader CSS fix is correctly implemented")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_global_css_rules():
|
||||||
|
"""Test that global CSS rules for mobile-header-container are correct"""
|
||||||
|
print("\nTesting global CSS rules...")
|
||||||
|
|
||||||
|
css_path = 'eveai_chat_client/static/assets/css/chat.css'
|
||||||
|
|
||||||
|
if not os.path.exists(css_path):
|
||||||
|
print(f"❌ chat.css not found at {css_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open(css_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check default hidden state
|
||||||
|
if '#mobile-header-container' not in content or 'display: none' not in content:
|
||||||
|
print("❌ Missing default hidden state for mobile-header-container")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✓ Found default hidden state for mobile-header-container")
|
||||||
|
|
||||||
|
# Check mobile media query shows container
|
||||||
|
# Look for the media query and then check if mobile-header-container is set to display: block within it
|
||||||
|
media_query_start = content.find('@media (max-width: 768px)')
|
||||||
|
if media_query_start == -1:
|
||||||
|
print("❌ Missing @media (max-width: 768px) query")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Find the closing brace of this media query
|
||||||
|
brace_count = 0
|
||||||
|
media_query_end = media_query_start
|
||||||
|
for i, char in enumerate(content[media_query_start:]):
|
||||||
|
if char == '{':
|
||||||
|
brace_count += 1
|
||||||
|
elif char == '}':
|
||||||
|
brace_count -= 1
|
||||||
|
if brace_count == 0:
|
||||||
|
media_query_end = media_query_start + i
|
||||||
|
break
|
||||||
|
|
||||||
|
media_query_content = content[media_query_start:media_query_end + 1]
|
||||||
|
|
||||||
|
if '#mobile-header-container' in media_query_content and 'display: block' in media_query_content:
|
||||||
|
print("✓ Found mobile media query to show mobile-header-container")
|
||||||
|
else:
|
||||||
|
print("❌ Mobile media query doesn't properly show mobile-header-container")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ Global CSS rules are correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_built_assets():
|
||||||
|
"""Test that built assets exist and are recent"""
|
||||||
|
print("\nTesting built assets...")
|
||||||
|
|
||||||
|
assets_to_check = [
|
||||||
|
'eveai_chat_client/static/dist/chat-client.js',
|
||||||
|
'eveai_chat_client/static/dist/chat-client.css'
|
||||||
|
]
|
||||||
|
|
||||||
|
for asset_path in assets_to_check:
|
||||||
|
if not os.path.exists(asset_path):
|
||||||
|
print(f"❌ Built asset not found: {asset_path}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# Check file size to ensure it's not empty
|
||||||
|
size = os.path.getsize(asset_path)
|
||||||
|
if size == 0:
|
||||||
|
print(f"❌ Built asset is empty: {asset_path}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"✓ Built asset exists and has content: {asset_path} ({size} bytes)")
|
||||||
|
|
||||||
|
print("✅ Built assets are present and valid")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_component_structure():
|
||||||
|
"""Test that MobileHeader component structure is intact"""
|
||||||
|
print("\nTesting MobileHeader component structure...")
|
||||||
|
|
||||||
|
mobile_header_path = 'eveai_chat_client/static/assets/vue-components/MobileHeader.vue'
|
||||||
|
|
||||||
|
with open(mobile_header_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
required_elements = [
|
||||||
|
'class="mobile-header"',
|
||||||
|
'SideBarLogo',
|
||||||
|
'LanguageSelector',
|
||||||
|
'justify-content: space-between',
|
||||||
|
'align-items: center'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_elements = []
|
||||||
|
for element in required_elements:
|
||||||
|
if element not in content:
|
||||||
|
missing_elements.append(element)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {element}")
|
||||||
|
|
||||||
|
if missing_elements:
|
||||||
|
print(f"❌ Missing elements in MobileHeader:")
|
||||||
|
for element in missing_elements:
|
||||||
|
print(f" - {element}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ MobileHeader component structure is intact")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run all tests"""
|
||||||
|
print("🔧 Testing Mobile Header Visibility Fix")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
test_mobile_header_css_fix,
|
||||||
|
test_global_css_rules,
|
||||||
|
test_built_assets,
|
||||||
|
test_component_structure
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
failed = 0
|
||||||
|
|
||||||
|
for test in tests:
|
||||||
|
try:
|
||||||
|
if test():
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Test failed with error: {e}")
|
||||||
|
failed += 1
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print(f"📊 Test Results: {passed} passed, {failed} failed")
|
||||||
|
|
||||||
|
if failed == 0:
|
||||||
|
print("🎉 Mobile header visibility fix is complete!")
|
||||||
|
print("📱 The MobileHeader should now be visible when switching to mobile mode.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("⚠️ Some tests failed. Please review the implementation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = main()
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
257
test_mobile_responsive.py
Normal file
257
test_mobile_responsive.py
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify mobile responsive functionality for eveai_chat_client
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def test_files_exist():
|
||||||
|
"""Test that all required files exist"""
|
||||||
|
print("Testing file existence...")
|
||||||
|
|
||||||
|
files_to_check = [
|
||||||
|
# Vue components
|
||||||
|
'eveai_chat_client/static/assets/vue-components/MobileHeader.vue',
|
||||||
|
'eveai_chat_client/static/assets/vue-components/SideBar.vue',
|
||||||
|
'eveai_chat_client/static/assets/vue-components/index.js',
|
||||||
|
|
||||||
|
# Templates
|
||||||
|
'eveai_chat_client/templates/base.html',
|
||||||
|
'eveai_chat_client/templates/scripts.html',
|
||||||
|
|
||||||
|
# CSS
|
||||||
|
'eveai_chat_client/static/assets/css/chat.css',
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
'frontend_src/js/chat-client.js',
|
||||||
|
|
||||||
|
# Built files
|
||||||
|
'eveai_chat_client/static/dist/chat-client.js',
|
||||||
|
'eveai_chat_client/static/dist/chat-client.css',
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_files = []
|
||||||
|
for file_path in files_to_check:
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
missing_files.append(file_path)
|
||||||
|
else:
|
||||||
|
print(f"✓ {file_path}")
|
||||||
|
|
||||||
|
if missing_files:
|
||||||
|
print(f"\n❌ Missing files:")
|
||||||
|
for file_path in missing_files:
|
||||||
|
print(f" - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ All required files exist")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_mobile_header_component():
|
||||||
|
"""Test MobileHeader component structure"""
|
||||||
|
print("\nTesting MobileHeader component...")
|
||||||
|
|
||||||
|
mobile_header_path = 'eveai_chat_client/static/assets/vue-components/MobileHeader.vue'
|
||||||
|
|
||||||
|
with open(mobile_header_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for required elements
|
||||||
|
required_elements = [
|
||||||
|
'class="mobile-header"',
|
||||||
|
'SideBarLogo',
|
||||||
|
'LanguageSelector',
|
||||||
|
'@media (min-width: 769px)',
|
||||||
|
'display: none'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_elements = []
|
||||||
|
for element in required_elements:
|
||||||
|
if element not in content:
|
||||||
|
missing_elements.append(element)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {element}")
|
||||||
|
|
||||||
|
if missing_elements:
|
||||||
|
print(f"❌ Missing elements in MobileHeader:")
|
||||||
|
for element in missing_elements:
|
||||||
|
print(f" - {element}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ MobileHeader component structure is correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_css_responsive_rules():
|
||||||
|
"""Test CSS responsive rules"""
|
||||||
|
print("\nTesting CSS responsive rules...")
|
||||||
|
|
||||||
|
css_path = 'eveai_chat_client/static/assets/css/chat.css'
|
||||||
|
|
||||||
|
with open(css_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for required CSS rules
|
||||||
|
required_rules = [
|
||||||
|
'#mobile-header-container',
|
||||||
|
'#sidebar-container',
|
||||||
|
'@media (max-width: 768px)',
|
||||||
|
'flex-direction: column',
|
||||||
|
'display: none',
|
||||||
|
'display: block'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_rules = []
|
||||||
|
for rule in required_rules:
|
||||||
|
if rule not in content:
|
||||||
|
missing_rules.append(rule)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {rule}")
|
||||||
|
|
||||||
|
if missing_rules:
|
||||||
|
print(f"❌ Missing CSS rules:")
|
||||||
|
for rule in missing_rules:
|
||||||
|
print(f" - {rule}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ CSS responsive rules are correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_base_html_structure():
|
||||||
|
"""Test base.html structure"""
|
||||||
|
print("\nTesting base.html structure...")
|
||||||
|
|
||||||
|
base_html_path = 'eveai_chat_client/templates/base.html'
|
||||||
|
|
||||||
|
with open(base_html_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for required elements
|
||||||
|
required_elements = [
|
||||||
|
'id="mobile-header-container"',
|
||||||
|
'id="sidebar-container"',
|
||||||
|
'class="content-area"'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_elements = []
|
||||||
|
for element in required_elements:
|
||||||
|
if element not in content:
|
||||||
|
missing_elements.append(element)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {element}")
|
||||||
|
|
||||||
|
if missing_elements:
|
||||||
|
print(f"❌ Missing elements in base.html:")
|
||||||
|
for element in missing_elements:
|
||||||
|
print(f" - {element}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ base.html structure is correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_component_exports():
|
||||||
|
"""Test component exports"""
|
||||||
|
print("\nTesting component exports...")
|
||||||
|
|
||||||
|
index_js_path = 'eveai_chat_client/static/assets/vue-components/index.js'
|
||||||
|
|
||||||
|
with open(index_js_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for required exports
|
||||||
|
required_exports = [
|
||||||
|
'export { default as SideBar }',
|
||||||
|
'export { default as MobileHeader }'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_exports = []
|
||||||
|
for export in required_exports:
|
||||||
|
if export not in content:
|
||||||
|
missing_exports.append(export)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {export}")
|
||||||
|
|
||||||
|
if missing_exports:
|
||||||
|
print(f"❌ Missing exports:")
|
||||||
|
for export in missing_exports:
|
||||||
|
print(f" - {export}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ Component exports are correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_chat_client_js():
|
||||||
|
"""Test chat-client.js mounting logic"""
|
||||||
|
print("\nTesting chat-client.js mounting logic...")
|
||||||
|
|
||||||
|
chat_client_path = 'frontend_src/js/chat-client.js'
|
||||||
|
|
||||||
|
with open(chat_client_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Check for required mounting logic
|
||||||
|
required_elements = [
|
||||||
|
'getElementById(\'sidebar-container\')',
|
||||||
|
'getElementById(\'mobile-header-container\')',
|
||||||
|
'Components.SideBar',
|
||||||
|
'Components.MobileHeader',
|
||||||
|
'mount(\'#sidebar-container\')',
|
||||||
|
'mount(\'#mobile-header-container\')'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_elements = []
|
||||||
|
for element in required_elements:
|
||||||
|
if element not in content:
|
||||||
|
missing_elements.append(element)
|
||||||
|
else:
|
||||||
|
print(f"✓ Found: {element}")
|
||||||
|
|
||||||
|
if missing_elements:
|
||||||
|
print(f"❌ Missing elements in chat-client.js:")
|
||||||
|
for element in missing_elements:
|
||||||
|
print(f" - {element}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ chat-client.js mounting logic is correct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run all tests"""
|
||||||
|
print("🧪 Testing Mobile Responsive Implementation")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
test_files_exist,
|
||||||
|
test_mobile_header_component,
|
||||||
|
test_css_responsive_rules,
|
||||||
|
test_base_html_structure,
|
||||||
|
test_component_exports,
|
||||||
|
test_chat_client_js
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
failed = 0
|
||||||
|
|
||||||
|
for test in tests:
|
||||||
|
try:
|
||||||
|
if test():
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Test failed with error: {e}")
|
||||||
|
failed += 1
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print(f"📊 Test Results: {passed} passed, {failed} failed")
|
||||||
|
|
||||||
|
if failed == 0:
|
||||||
|
print("🎉 All tests passed! Mobile responsive implementation is complete.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("⚠️ Some tests failed. Please review the implementation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = main()
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
Reference in New Issue
Block a user