- Start met Mobiele versie van de chat client.
This commit is contained in:
@@ -18,6 +18,16 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Mobile header container - hidden on desktop */
|
||||
#mobile-header-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Desktop layout - default */
|
||||
#sidebar-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Sidebar styling */
|
||||
.sidebar {
|
||||
width: 300px;
|
||||
@@ -254,4 +264,29 @@ body {
|
||||
|
||||
/* .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 */
|
||||
|
||||
@@ -225,4 +225,22 @@ export default {
|
||||
color: white;
|
||||
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>
|
||||
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-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>
|
||||
@@ -10,6 +10,8 @@ export { default as ProgressTracker } from './ProgressTracker.vue';
|
||||
export { default as DynamicForm } from './DynamicForm.vue';
|
||||
export { default as FormField } from './FormField.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
|
||||
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>
|
||||
<body>
|
||||
<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>
|
||||
|
||||
<!-- Right content area - contains the chat client -->
|
||||
|
||||
@@ -21,48 +21,77 @@ window.Vue = { createApp };
|
||||
window.marked = marked;
|
||||
|
||||
// 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
|
||||
window.Components = Components;
|
||||
console.log('Components loaded:', Object.keys(Components));
|
||||
|
||||
// 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
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
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 {
|
||||
// Maak de Vue applicatie aan
|
||||
const app = createApp(ChatApp);
|
||||
// Mount SideBar component to sidebar-container
|
||||
const sidebarContainer = document.getElementById('sidebar-container');
|
||||
if (sidebarContainer && Components.SideBar) {
|
||||
const sidebarApp = createApp(Components.SideBar, {
|
||||
tenantMake: window.chatConfig?.tenantMake || { name: 'EveAI', logo_url: '' },
|
||||
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 alle componenten globaal
|
||||
// Registreer componenten voor sidebar app
|
||||
for (const [name, component] of Object.entries(Components)) {
|
||||
app.component(name, component);
|
||||
sidebarApp.component(name, component);
|
||||
}
|
||||
|
||||
// Voeg de IconManagerMixin toe voor alle componenten
|
||||
app.mixin(IconManagerMixin);
|
||||
sidebarApp.mount('#sidebar-container');
|
||||
console.log('SideBar mounted successfully');
|
||||
}
|
||||
|
||||
// Mount de applicatie op #app
|
||||
const mountedApp = app.mount('#app');
|
||||
// Mount MobileHeader component to mobile-header-container
|
||||
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 || ''
|
||||
});
|
||||
|
||||
// Bewaar een referentie naar de app voor debugging
|
||||
window.__vueApp = app;
|
||||
// Registreer componenten voor mobile header app
|
||||
for (const [name, component] of Object.entries(Components)) {
|
||||
mobileHeaderApp.component(name, component);
|
||||
}
|
||||
|
||||
console.log('Vue app mounted successfully');
|
||||
mobileHeaderApp.mount('#mobile-header-container');
|
||||
console.log('MobileHeader mounted successfully');
|
||||
}
|
||||
|
||||
// Mount ChatApp to the chat container
|
||||
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);
|
||||
}
|
||||
|
||||
chatApp.mount('.chat-container');
|
||||
console.log('ChatApp mounted successfully');
|
||||
}
|
||||
|
||||
console.log('All Vue apps mounted successfully');
|
||||
} 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