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:
@@ -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
0
html/kidsai/server.js
Normal file → Executable 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 */
|
||||
|
||||
Reference in New Issue
Block a user