Comprehensive mobile optimization for KidsAI Explorer

- Added extensive mobile-responsive CSS with proper breakpoints
- Optimized chat interface for mobile devices with better touch targets
- Improved mobile scrolling with hardware acceleration and touch-friendly scrollbars
- Added mobile device detection for enhanced UX on smartphones/tablets
- Prevented iOS zoom on input focus with proper font sizing
- Enhanced textarea auto-resize functionality for mobile
- Added mobile-friendly keyboard handling and focus management
- Improved button sizing to meet iOS 44px minimum touch target requirements
- Optimized conversation container for better mobile viewport handling
- Added landscape orientation support and extra small device breakpoints
- Enhanced visual feedback with proper active states for touch interactions
- Fixed viewport jumping issues when virtual keyboard appears
- Improved mobile-specific JavaScript event handling and scrolling behavior
This commit is contained in:
root
2025-06-29 21:55:23 +02:00
parent 88a03c51a7
commit 0a26fb6b9c
3 changed files with 479 additions and 23 deletions

View File

@@ -43,6 +43,12 @@ class KidsAIExplorer {
console.log('✅ KidsAI constructor completed');
}
// Detect mobile device
isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|| window.innerWidth <= 768;
}
initializeEventListeners() {
console.log('🔗 Setting up event listeners');
@@ -64,6 +70,15 @@ class KidsAIExplorer {
this.handleQuestion();
}
});
// Add mobile-friendly input event for better responsiveness
if (this.isMobileDevice()) {
this.questionInput.addEventListener('input', () => {
// Auto-resize textarea on mobile for better UX
this.questionInput.style.height = 'auto';
this.questionInput.style.height = Math.min(this.questionInput.scrollHeight, 120) + 'px';
});
}
}
// Suggestion cards
@@ -502,7 +517,7 @@ class KidsAIExplorer {
// Show AI response with animation
setTimeout(() => {
responseBubble.classList.add('visible');
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
this.scrollToBottomSmoothly();
}, 100);
// Ask next question
@@ -534,7 +549,7 @@ class KidsAIExplorer {
setTimeout(() => {
responseBubble.classList.add('visible');
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
this.scrollToBottomSmoothly();
}, 100);
setTimeout(() => {
@@ -563,7 +578,7 @@ class KidsAIExplorer {
setTimeout(() => {
revealDiv.classList.add('visible');
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
this.scrollToBottomSmoothly();
}, 500);
return;
}
@@ -611,17 +626,45 @@ class KidsAIExplorer {
questionBubble.classList.add('visible');
inputContainer.classList.add('visible');
// Smooth scroll to bottom of conversation instead of specific element
// Better mobile scrolling
this.scrollToBottomSmoothly();
// Focus on the textarea with mobile-friendly delay and add event listeners
const textarea = document.getElementById(`user-input-${this.currentQuestionIndex}`);
if (textarea) {
// Add Enter key support for chat
textarea.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.submitChatAnswer(this.currentQuestionIndex);
}
});
// Add mobile-friendly auto-resize
if (this.isMobileDevice()) {
textarea.addEventListener('input', () => {
textarea.style.height = 'auto';
textarea.style.height = Math.min(textarea.scrollHeight, 80) + 'px';
});
}
// Delay focus on mobile to prevent keyboard jumping
if (this.isMobileDevice()) {
setTimeout(() => textarea.focus(), 300);
} else {
textarea.focus();
}
}
}, 300);
}
// Helper method for better mobile scrolling
scrollToBottomSmoothly() {
if (this.conversationContainer) {
setTimeout(() => {
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
}, 100);
// Focus on the textarea
const textarea = document.getElementById(`user-input-${this.currentQuestionIndex}`);
if (textarea) {
textarea.focus();
}
}, 300);
}
}
submitChatAnswer(questionIndex) {
@@ -665,6 +708,9 @@ class KidsAIExplorer {
setTimeout(() => {
userBubble.classList.add('visible');
// Better mobile scrolling before generating AI response
this.scrollToBottomSmoothly();
// Generate AI response using server-side AI
this.generateChatAIResponse(answer, questionIndex);

0
html/kidsai/server.js Normal file → Executable file
View File

View File

@@ -5,12 +5,23 @@
box-sizing: border-box;
}
/* Better mobile touch targets and text rendering */
html {
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Open Sans', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
overflow-x: hidden;
/* Prevent horizontal scrolling on mobile */
position: relative;
/* Better text rendering on mobile */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.container {
@@ -980,30 +991,407 @@ body {
animation: answerReveal 0.6s ease-out;
}
/* Mobile responsiveness for answer section */
/* Comprehensive Mobile Responsiveness */
@media (max-width: 768px) {
.answer-reveal-section {
padding: 20px;
margin-top: 20px;
/* Container and Layout */
.container {
padding: 10px;
margin: 0;
}
.reveal-answer-btn {
padding: 12px 25px;
/* Header Optimizations */
.header {
margin-bottom: 20px;
}
.header-top {
margin-bottom: 15px;
}
.logo {
gap: 8px;
margin-bottom: 8px;
}
.logo i,
.logo .brain-icon {
font-size: 2rem;
}
.logo h1 {
font-size: 1.8rem;
text-align: center;
line-height: 1.2;
}
.subtitle {
font-size: 1rem;
padding: 0 10px;
}
/* Language Switcher */
.language-switcher {
gap: 5px;
padding: 3px;
}
.lang-btn {
padding: 6px 10px;
font-size: 0.8rem;
}
/* Main Question Section */
.main-section {
padding: 20px 15px;
margin-bottom: 20px;
}
.main-section h2 {
font-size: 1.5rem;
margin-bottom: 15px;
}
.question-input-container {
flex-direction: column;
gap: 15px;
}
.question-input {
padding: 15px;
font-size: 16px; /* Prevents zoom on iOS */
min-height: 50px;
}
.ask-button {
padding: 15px 25px;
font-size: 1.1rem;
width: 100%;
min-height: 50px;
}
/* Suggestions Grid */
.suggestions-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.suggestion-card {
padding: 15px;
text-align: left;
display: flex;
align-items: center;
gap: 15px;
}
.suggestion-card i,
.suggestion-card .sun-icon,
.suggestion-card .bird-icon,
.suggestion-card .water-icon,
.suggestion-card .computer-icon,
.suggestion-card .moon-icon,
.suggestion-card .rainbow-icon {
font-size: 1.5rem;
margin-bottom: 0;
flex-shrink: 0;
}
.suggestion-card p {
margin: 0;
font-size: 0.95rem;
line-height: 1.3;
}
/* Conversation Container */
.conversation-container {
padding: 15px;
border-radius: 15px;
max-height: 70vh;
margin: 0 -5px;
}
/* Chat Messages */
.chat-message {
max-width: 92%;
margin-bottom: 12px;
}
.chat-message.ai-message {
padding: 12px 15px;
border-radius: 15px 15px 15px 4px;
font-size: 0.95rem;
}
.chat-message.user-message {
padding: 12px 15px;
border-radius: 15px 15px 4px 15px;
font-size: 0.95rem;
}
.message-header {
gap: 6px;
margin-bottom: 6px;
}
.ai-avatar {
font-size: 1rem;
}
.answer-box {
padding: 20px;
.ai-label {
font-size: 0.8rem;
}
.answer-header {
.message-content {
line-height: 1.4;
}
/* Chat Input */
.chat-input-container {
margin: 15px 0;
}
.chat-input-container .input-area {
padding: 8px 12px;
border-radius: 20px;
gap: 8px;
min-height: 50px;
}
.chat-textarea {
padding: 8px 0;
font-size: 16px; /* Prevents zoom on iOS */
min-height: 22px;
max-height: 80px;
}
.chat-input-container .reply-btn {
padding: 10px 12px;
font-size: 12px;
border-radius: 18px;
min-height: 36px;
min-width: 50px;
}
/* Reveal Section */
.reveal-section {
margin-top: 20px;
padding: 20px 15px;
border-radius: 15px;
}
.reveal-prompt p {
font-size: 1rem;
margin-bottom: 12px;
}
.reveal-btn {
padding: 12px 20px;
font-size: 1rem;
border-radius: 20px;
width: 100%;
justify-content: center;
}
/* Final Answer */
.final-answer {
padding: 20px 15px;
border-radius: 12px;
margin: 15px 0;
}
.final-answer .answer-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
gap: 10px;
margin-bottom: 15px;
padding-bottom: 12px;
}
.answer-source {
margin-left: 0;
.final-answer .answer-icon {
font-size: 1.5rem;
padding: 6px;
}
.final-answer h4 {
font-size: 1.2rem;
}
.final-answer .answer-source {
align-self: stretch;
text-align: center;
padding: 8px 12px;
font-size: 0.75rem;
}
.final-answer .answer-text {
font-size: 1rem;
line-height: 1.6;
padding: 15px;
margin-bottom: 15px;
}
.final-answer .answer-footer {
padding: 12px 15px;
}
.final-answer .answer-footer p {
font-size: 1rem;
}
/* Action Buttons */
.action-buttons {
flex-direction: column;
gap: 10px;
margin-top: 15px;
}
.action-btn {
width: 100%;
justify-content: center;
padding: 12px 20px;
font-size: 1rem;
}
/* Encouragement Section */
.encouragement-section {
padding: 15px;
margin-bottom: 20px;
}
.encouragement-text {
font-size: 1.1rem;
line-height: 1.3;
}
/* Footer */
.footer {
padding: 15px 10px;
margin-top: 20px;
}
.footer p {
font-size: 1rem;
}
.safety-note {
font-size: 0.85rem;
flex-direction: column;
gap: 4px;
}
/* Loading Overlay */
.loading-spinner {
width: 80px;
height: 80px;
}
.gear1 {
width: 50px;
height: 50px;
top: 15px;
left: 15px;
}
.gear2 {
width: 35px;
height: 35px;
}
.gear3 {
width: 25px;
height: 25px;
}
/* Touch Improvements */
.suggestion-card:hover {
transform: none; /* Disable hover effects on mobile */
}
.suggestion-card:active {
transform: scale(0.98);
background: linear-gradient(135deg, #e2e8f0, #cbd5e0);
}
.ask-button:active,
.action-btn:active,
.reply-btn:active,
.reveal-btn:active {
transform: scale(0.98);
}
/* Prevent viewport jumping when keyboard appears */
.conversation-container {
/* Use viewport units that don't change with keyboard */
max-height: 70vh;
/* Ensure container stays in place */
position: relative;
}
/* Better handling of focus states on mobile */
.chat-textarea:focus {
outline: none;
border-color: #4299e1;
}
/* Improve button touch targets */
.reply-btn,
.reveal-btn,
.ask-button {
min-height: 44px; /* iOS recommended minimum touch target */
min-width: 44px;
}
}
/* Extra small devices (phones in portrait mode) */
@media (max-width: 480px) {
.container {
padding: 5px;
}
.logo h1 {
font-size: 1.5rem;
}
.main-section {
padding: 15px 10px;
}
.conversation-container {
padding: 10px;
margin: 0 -2px;
}
.chat-message {
max-width: 95%;
}
.chat-message.ai-message,
.chat-message.user-message {
padding: 10px 12px;
font-size: 0.9rem;
}
.final-answer {
padding: 15px 10px;
}
.final-answer .answer-text {
font-size: 0.95rem;
padding: 12px;
}
}
/* Landscape orientation adjustments */
@media (max-width: 768px) and (orientation: landscape) {
.conversation-container {
max-height: 60vh;
}
.logo h1 {
font-size: 1.6rem;
}
.main-section h2 {
font-size: 1.3rem;
}
}
@@ -1202,6 +1590,28 @@ body {
max-height: 600px;
overflow-y: auto;
scroll-behavior: smooth;
/* Better scrolling on mobile */
-webkit-overflow-scrolling: touch;
/* Improve scroll performance */
transform: translateZ(0);
}
/* Better scrollbar styling for mobile */
.conversation-container::-webkit-scrollbar {
width: 4px;
}
.conversation-container::-webkit-scrollbar-track {
background: transparent;
}
.conversation-container::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.2);
border-radius: 2px;
}
.conversation-container::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.3);
}
/* Make reveal section part of the chat flow */