feat: Add mobile support and testing utilities
- Add mobile keyboard handler for better mobile experience - Create mobile test page for responsive testing - Add chat test utilities for development and debugging - Improve overall mobile usability and testing capabilities
This commit is contained in:
388
html/kidsai/mobile-keyboard-handler.js
Normal file
388
html/kidsai/mobile-keyboard-handler.js
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
// Mobile Keyboard Overlay Handler
|
||||||
|
// This script dynamically adjusts the layout when the virtual keyboard appears
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Only run on mobile devices
|
||||||
|
if (!/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialViewportHeight = window.innerHeight;
|
||||||
|
let isKeyboardOpen = false;
|
||||||
|
let activeInputContainer = null; // Track which input container is currently active
|
||||||
|
let focusedInput = null; // Track the currently focused input element
|
||||||
|
|
||||||
|
// Function to handle viewport changes (keyboard show/hide)
|
||||||
|
function handleViewportChange() {
|
||||||
|
const currentHeight = window.innerHeight;
|
||||||
|
const heightDifference = initialViewportHeight - currentHeight;
|
||||||
|
const threshold = 150; // Minimum height change to consider keyboard open
|
||||||
|
|
||||||
|
const conversationContainer = document.querySelector('.conversation-container');
|
||||||
|
const allChatInputContainers = document.querySelectorAll('.chat-input-container');
|
||||||
|
const body = document.body;
|
||||||
|
|
||||||
|
// Update debug counter
|
||||||
|
const visibleInputs = Array.from(allChatInputContainers).filter(
|
||||||
|
container => container.style.display !== 'none'
|
||||||
|
).length;
|
||||||
|
body.setAttribute('data-visible-inputs', visibleInputs);
|
||||||
|
|
||||||
|
if (heightDifference > threshold && !isKeyboardOpen) {
|
||||||
|
// Keyboard opened
|
||||||
|
isKeyboardOpen = true;
|
||||||
|
console.log('Keyboard opened, adjusting layout. Found', allChatInputContainers.length, 'input containers');
|
||||||
|
|
||||||
|
if (conversationContainer) {
|
||||||
|
conversationContainer.classList.add('keyboard-open');
|
||||||
|
conversationContainer.style.height = `${currentHeight * 0.4}px`;
|
||||||
|
conversationContainer.style.maxHeight = `${currentHeight * 0.4}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply keyboard positioning to ALL chat input containers
|
||||||
|
allChatInputContainers.forEach((chatInputContainer, index) => {
|
||||||
|
if (chatInputContainer) {
|
||||||
|
console.log(`Processing input container ${index + 1}/${allChatInputContainers.length}`);
|
||||||
|
chatInputContainer.style.position = 'fixed';
|
||||||
|
chatInputContainer.style.bottom = '0';
|
||||||
|
chatInputContainer.style.left = '0';
|
||||||
|
chatInputContainer.style.right = '0';
|
||||||
|
chatInputContainer.style.zIndex = '1000';
|
||||||
|
chatInputContainer.style.background = 'white';
|
||||||
|
chatInputContainer.style.borderTop = '1px solid #e2e8f0';
|
||||||
|
chatInputContainer.style.padding = '15px';
|
||||||
|
chatInputContainer.style.paddingBottom = '20px';
|
||||||
|
chatInputContainer.style.boxShadow = '0 -2px 10px rgba(0, 0, 0, 0.1)';
|
||||||
|
chatInputContainer.style.margin = '0';
|
||||||
|
chatInputContainer.style.borderRadius = '0';
|
||||||
|
chatInputContainer.classList.add('keyboard-fixed');
|
||||||
|
|
||||||
|
// Ensure the input area is properly styled
|
||||||
|
const inputArea = chatInputContainer.querySelector('.input-area');
|
||||||
|
if (inputArea) {
|
||||||
|
inputArea.style.margin = '0';
|
||||||
|
inputArea.style.borderRadius = '20px';
|
||||||
|
inputArea.style.background = '#f8f9fa';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide non-active input containers
|
||||||
|
if (activeInputContainer) {
|
||||||
|
allChatInputContainers.forEach(container => {
|
||||||
|
if (container !== activeInputContainer) {
|
||||||
|
container.style.display = 'none';
|
||||||
|
console.log('Hiding non-active input container');
|
||||||
|
} else {
|
||||||
|
console.log('Keeping active input container visible');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
body.classList.add('keyboard-open');
|
||||||
|
|
||||||
|
// Update debug counter after hiding
|
||||||
|
const visibleAfter = Array.from(allChatInputContainers).filter(
|
||||||
|
container => container.style.display !== 'none'
|
||||||
|
).length;
|
||||||
|
body.setAttribute('data-visible-inputs', visibleAfter);
|
||||||
|
|
||||||
|
} else if (heightDifference <= threshold && isKeyboardOpen) {
|
||||||
|
// Keyboard closed
|
||||||
|
isKeyboardOpen = false;
|
||||||
|
console.log('Keyboard closed, restoring layout for', allChatInputContainers.length, 'input containers');
|
||||||
|
|
||||||
|
if (conversationContainer) {
|
||||||
|
conversationContainer.classList.remove('keyboard-open');
|
||||||
|
conversationContainer.style.removeProperty('height');
|
||||||
|
conversationContainer.style.removeProperty('max-height');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset ALL chat input containers
|
||||||
|
allChatInputContainers.forEach((chatInputContainer, index) => {
|
||||||
|
if (chatInputContainer) {
|
||||||
|
console.log(`Restoring input container ${index + 1}/${allChatInputContainers.length}`);
|
||||||
|
chatInputContainer.style.removeProperty('position');
|
||||||
|
chatInputContainer.style.removeProperty('bottom');
|
||||||
|
chatInputContainer.style.removeProperty('left');
|
||||||
|
chatInputContainer.style.removeProperty('right');
|
||||||
|
chatInputContainer.style.removeProperty('z-index');
|
||||||
|
chatInputContainer.style.removeProperty('background');
|
||||||
|
chatInputContainer.style.removeProperty('border-top');
|
||||||
|
chatInputContainer.style.removeProperty('padding');
|
||||||
|
chatInputContainer.style.removeProperty('padding-bottom');
|
||||||
|
chatInputContainer.style.removeProperty('box-shadow');
|
||||||
|
chatInputContainer.style.removeProperty('margin');
|
||||||
|
chatInputContainer.style.removeProperty('border-radius');
|
||||||
|
chatInputContainer.style.removeProperty('display');
|
||||||
|
chatInputContainer.classList.remove('keyboard-fixed');
|
||||||
|
|
||||||
|
// Reset input area styles
|
||||||
|
const inputArea = chatInputContainer.querySelector('.input-area');
|
||||||
|
if (inputArea) {
|
||||||
|
inputArea.style.removeProperty('margin');
|
||||||
|
inputArea.style.removeProperty('border-radius');
|
||||||
|
inputArea.style.removeProperty('background');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
activeInputContainer = null;
|
||||||
|
body.classList.remove('keyboard-open');
|
||||||
|
body.removeAttribute('data-visible-inputs');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to scroll input into view when focused
|
||||||
|
function scrollInputIntoView(inputElement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// Always ensure input is visible when focused
|
||||||
|
const elementRect = inputElement.getBoundingClientRect();
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
const keyboardHeight = initialViewportHeight - viewportHeight;
|
||||||
|
|
||||||
|
// If there's likely a keyboard (height reduced by significant amount)
|
||||||
|
if (keyboardHeight > 150) {
|
||||||
|
const availableHeight = viewportHeight;
|
||||||
|
const inputBottom = elementRect.bottom;
|
||||||
|
|
||||||
|
// If input is in bottom 40% of available viewport, scroll it up
|
||||||
|
if (inputBottom > availableHeight * 0.6) {
|
||||||
|
// Scroll the input container's parent into view
|
||||||
|
const container = inputElement.closest('.conversation-container') ||
|
||||||
|
inputElement.closest('.thinking-section');
|
||||||
|
|
||||||
|
if (container) {
|
||||||
|
container.scrollTop = container.scrollHeight - availableHeight * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also try scrolling the window
|
||||||
|
window.scrollTo({
|
||||||
|
top: window.scrollY + (inputBottom - availableHeight * 0.4),
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100); // Shorter delay for more responsive feel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced focus handler for chat textarea
|
||||||
|
function handleChatInputFocus(event) {
|
||||||
|
const chatTextarea = event.target;
|
||||||
|
focusedInput = chatTextarea;
|
||||||
|
|
||||||
|
// Add focused class for styling
|
||||||
|
chatTextarea.classList.add('focused');
|
||||||
|
|
||||||
|
// Immediately apply keyboard-friendly positioning
|
||||||
|
const chatInputContainer = chatTextarea.closest('.chat-input-container');
|
||||||
|
if (chatInputContainer && window.innerWidth <= 768) {
|
||||||
|
// Set this as the active input container
|
||||||
|
activeInputContainer = chatInputContainer;
|
||||||
|
|
||||||
|
// Hide all other input containers immediately
|
||||||
|
const allInputContainers = document.querySelectorAll('.chat-input-container');
|
||||||
|
allInputContainers.forEach(container => {
|
||||||
|
if (container !== chatInputContainer) {
|
||||||
|
container.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply keyboard positioning immediately on focus
|
||||||
|
setTimeout(() => {
|
||||||
|
chatInputContainer.style.position = 'fixed';
|
||||||
|
chatInputContainer.style.bottom = '0';
|
||||||
|
chatInputContainer.style.left = '0';
|
||||||
|
chatInputContainer.style.right = '0';
|
||||||
|
chatInputContainer.style.zIndex = '1001';
|
||||||
|
chatInputContainer.style.background = 'white';
|
||||||
|
chatInputContainer.style.borderTop = '1px solid #e2e8f0';
|
||||||
|
chatInputContainer.style.padding = '15px';
|
||||||
|
chatInputContainer.style.paddingBottom = '25px';
|
||||||
|
chatInputContainer.style.boxShadow = '0 -2px 10px rgba(0, 0, 0, 0.1)';
|
||||||
|
chatInputContainer.style.margin = '0';
|
||||||
|
chatInputContainer.style.display = 'block'; // Ensure this one is visible
|
||||||
|
chatInputContainer.classList.add('input-focused');
|
||||||
|
|
||||||
|
// Add class to body for CSS targeting (fallback for :has() selector)
|
||||||
|
document.body.classList.add('input-focused-active');
|
||||||
|
|
||||||
|
// Adjust conversation container
|
||||||
|
const conversationContainer = document.querySelector('.conversation-container');
|
||||||
|
if (conversationContainer) {
|
||||||
|
conversationContainer.style.paddingBottom = '80px';
|
||||||
|
conversationContainer.style.marginBottom = '0';
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll into view if keyboard is likely to appear
|
||||||
|
scrollInputIntoView(chatTextarea);
|
||||||
|
|
||||||
|
// For iOS, prevent zoom by ensuring font-size is 16px
|
||||||
|
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
||||||
|
chatTextarea.style.fontSize = '16px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChatInputBlur(event) {
|
||||||
|
event.target.classList.remove('focused');
|
||||||
|
|
||||||
|
// Clear focused input reference
|
||||||
|
if (focusedInput === event.target) {
|
||||||
|
focusedInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up keyboard positioning when input loses focus
|
||||||
|
const chatInputContainer = event.target.closest('.chat-input-container');
|
||||||
|
if (chatInputContainer && chatInputContainer.classList.contains('input-focused')) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// Only remove if keyboard is not detected as open
|
||||||
|
if (!isKeyboardOpen) {
|
||||||
|
// Show all input containers again
|
||||||
|
const allInputContainers = document.querySelectorAll('.chat-input-container');
|
||||||
|
allInputContainers.forEach(container => {
|
||||||
|
container.style.removeProperty('display');
|
||||||
|
});
|
||||||
|
|
||||||
|
chatInputContainer.style.removeProperty('position');
|
||||||
|
chatInputContainer.style.removeProperty('bottom');
|
||||||
|
chatInputContainer.style.removeProperty('left');
|
||||||
|
chatInputContainer.style.removeProperty('right');
|
||||||
|
chatInputContainer.style.removeProperty('z-index');
|
||||||
|
chatInputContainer.style.removeProperty('background');
|
||||||
|
chatInputContainer.style.removeProperty('border-top');
|
||||||
|
chatInputContainer.style.removeProperty('padding');
|
||||||
|
chatInputContainer.style.removeProperty('padding-bottom');
|
||||||
|
chatInputContainer.style.removeProperty('box-shadow');
|
||||||
|
chatInputContainer.style.removeProperty('margin');
|
||||||
|
chatInputContainer.classList.remove('input-focused');
|
||||||
|
|
||||||
|
// Remove body class
|
||||||
|
document.body.classList.remove('input-focused-active');
|
||||||
|
|
||||||
|
// Reset conversation container
|
||||||
|
const conversationContainer = document.querySelector('.conversation-container');
|
||||||
|
if (conversationContainer) {
|
||||||
|
conversationContainer.style.removeProperty('padding-bottom');
|
||||||
|
conversationContainer.style.removeProperty('margin-bottom');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear active input container
|
||||||
|
if (activeInputContainer === chatInputContainer) {
|
||||||
|
activeInputContainer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300); // Delay to avoid flicker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounced resize handler
|
||||||
|
let resizeTimeout;
|
||||||
|
function debouncedViewportChange() {
|
||||||
|
clearTimeout(resizeTimeout);
|
||||||
|
resizeTimeout = setTimeout(handleViewportChange, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize when DOM is ready
|
||||||
|
function initialize() {
|
||||||
|
console.log('Initializing mobile keyboard handler');
|
||||||
|
|
||||||
|
// Store initial viewport height
|
||||||
|
initialViewportHeight = window.innerHeight;
|
||||||
|
|
||||||
|
// Listen for viewport changes
|
||||||
|
window.addEventListener('resize', debouncedViewportChange);
|
||||||
|
|
||||||
|
// Listen for orientation changes
|
||||||
|
window.addEventListener('orientationchange', () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
initialViewportHeight = window.innerHeight;
|
||||||
|
handleViewportChange();
|
||||||
|
}, 500); // Wait for orientation change to complete
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add focus/blur handlers for chat inputs (using event delegation for dynamic content)
|
||||||
|
document.addEventListener('focus', (event) => {
|
||||||
|
if (event.target.matches('.chat-textarea, #question-input, .step-thinking-space textarea')) {
|
||||||
|
handleChatInputFocus(event);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
document.addEventListener('blur', (event) => {
|
||||||
|
if (event.target.matches('.chat-textarea, #question-input, .step-thinking-space textarea')) {
|
||||||
|
handleChatInputBlur(event);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
// Listen for new chat input containers being added to the DOM
|
||||||
|
if (window.MutationObserver) {
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
mutation.addedNodes.forEach((node) => {
|
||||||
|
if (node.nodeType === 1) { // Element node
|
||||||
|
// Check if the added node contains chat input containers
|
||||||
|
const newInputContainers = node.querySelectorAll ?
|
||||||
|
node.querySelectorAll('.chat-input-container') : [];
|
||||||
|
|
||||||
|
if (newInputContainers.length > 0) {
|
||||||
|
console.log('New chat input containers detected:', newInputContainers.length);
|
||||||
|
// If keyboard is currently open and we have an active input, hide the new ones
|
||||||
|
if (isKeyboardOpen && activeInputContainer) {
|
||||||
|
newInputContainers.forEach(container => {
|
||||||
|
if (container !== activeInputContainer) {
|
||||||
|
container.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Observe the conversation container for new additions
|
||||||
|
const conversationContainer = document.querySelector('.conversation-container');
|
||||||
|
if (conversationContainer) {
|
||||||
|
observer.observe(conversationContainer, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also observe the main content area
|
||||||
|
const mainContent = document.querySelector('.main-content, .thinking-steps');
|
||||||
|
if (mainContent) {
|
||||||
|
observer.observe(mainContent, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visual Viewport API support (newer browsers)
|
||||||
|
if (window.visualViewport) {
|
||||||
|
window.visualViewport.addEventListener('resize', () => {
|
||||||
|
const heightDifference = window.innerHeight - window.visualViewport.height;
|
||||||
|
if (heightDifference > 150 && !isKeyboardOpen) {
|
||||||
|
handleViewportChange();
|
||||||
|
} else if (heightDifference <= 150 && isKeyboardOpen) {
|
||||||
|
handleViewportChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for DOM to be ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', initialize);
|
||||||
|
} else {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add utility class for JavaScript
|
||||||
|
document.documentElement.classList.add('js-mobile-keyboard-handler');
|
||||||
|
|
||||||
|
})();
|
||||||
203
html/kidsai/mobile-test.html
Normal file
203
html/kidsai/mobile-test.html
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>KidsAI Mobile Test</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<!-- Mobile keyboard handler -->
|
||||||
|
<script src="mobile-keyboard-handler.js"></script>
|
||||||
|
<style>
|
||||||
|
/* Add mobile simulator styling for testing */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
body::before {
|
||||||
|
content: "MOBILE VIEW ACTIVE";
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #48bb78;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin-top: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-info {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
|
color: white;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
z-index: 10001;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="debug-info">
|
||||||
|
Screen: <span id="screen-size"></span><br>
|
||||||
|
Viewport: <span id="viewport-size"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<!-- Header -->
|
||||||
|
<header class="header">
|
||||||
|
<div class="header-top">
|
||||||
|
<div class="language-switcher">
|
||||||
|
<button class="lang-btn active">
|
||||||
|
<span class="flag-icon">🇺🇸</span> English
|
||||||
|
</button>
|
||||||
|
<button class="lang-btn">
|
||||||
|
<span class="flag-icon">🇩🇪</span> Deutsch
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="logo">
|
||||||
|
<span class="brain-icon">🧠</span>
|
||||||
|
<h1>KidsAI Explorer</h1>
|
||||||
|
</div>
|
||||||
|
<p class="tagline">Think, Learn, Discover Together!</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="main-content">
|
||||||
|
<!-- Welcome Section -->
|
||||||
|
<section class="welcome-section">
|
||||||
|
<h2>Hi there, young explorer! 🚀</h2>
|
||||||
|
<p>Testing mobile responsiveness! This should look great on all screen sizes.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Question Input Section -->
|
||||||
|
<section class="question-section">
|
||||||
|
<div class="input-container">
|
||||||
|
<label for="question-input">What would you like to explore today?</label>
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<textarea id="question-input" placeholder="Ask me anything!" rows="3"></textarea>
|
||||||
|
<button class="ask-btn">
|
||||||
|
<span class="rocket-icon">🚀</span>
|
||||||
|
<span>Let's Explore!</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Thinking Process Section (with conversation container test) -->
|
||||||
|
<section class="thinking-section chat-mode">
|
||||||
|
<div class="thinking-header">
|
||||||
|
<h3><span class="lightbulb-icon">💡</span> Mobile Conversation Test</h3>
|
||||||
|
</div>
|
||||||
|
<div class="thinking-steps">
|
||||||
|
<div class="conversation-container">
|
||||||
|
<div class="chat-message ai-message visible">
|
||||||
|
<div class="message-header">
|
||||||
|
<span class="ai-avatar">🤖</span>
|
||||||
|
<span class="ai-label">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>This is a test message to see how the conversation container looks on mobile. It should be scrollable and properly sized.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-message user-message visible">
|
||||||
|
<div class="message-content">
|
||||||
|
<p>This is a user message. On mobile, it should take up most of the width and be easy to read.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-message ai-message visible">
|
||||||
|
<div class="message-header">
|
||||||
|
<span class="ai-avatar">🤖</span>
|
||||||
|
<span class="ai-label">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>Here's another message to test scrolling. The container should maintain its height and allow smooth scrolling on mobile devices.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- More messages to test scrolling -->
|
||||||
|
<div class="chat-message user-message visible">
|
||||||
|
<div class="message-content">
|
||||||
|
<p>Testing more content...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-message ai-message visible">
|
||||||
|
<div class="message-header">
|
||||||
|
<span class="ai-avatar">🤖</span>
|
||||||
|
<span class="ai-label">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>And even more content to ensure we can scroll properly on mobile devices.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-input-container visible">
|
||||||
|
<div class="input-area">
|
||||||
|
<textarea class="chat-textarea" placeholder="Type your thoughts here..."></textarea>
|
||||||
|
<button class="reply-btn">
|
||||||
|
<span class="rocket-icon">🚀</span>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Action Buttons Test -->
|
||||||
|
<section class="welcome-section">
|
||||||
|
<h2>Button Test</h2>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="action-btn research">
|
||||||
|
<span class="research-icon">🔍</span>
|
||||||
|
Research Ideas
|
||||||
|
</button>
|
||||||
|
<button class="action-btn experiment">
|
||||||
|
<span class="experiment-icon">🧪</span>
|
||||||
|
Try Experiments
|
||||||
|
</button>
|
||||||
|
<button class="action-btn discuss">
|
||||||
|
<span class="discuss-icon">💬</span>
|
||||||
|
Discuss Together
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Answer Reveal Test -->
|
||||||
|
<section class="answer-reveal-section">
|
||||||
|
<div class="reveal-prompt">
|
||||||
|
<h4>Ready to see the answer?</h4>
|
||||||
|
<p>You've done great thinking! Now let's see what the experts say.</p>
|
||||||
|
</div>
|
||||||
|
<button class="reveal-answer-btn">
|
||||||
|
<span class="btn-icon">🎉</span>
|
||||||
|
Reveal Answer
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Debug script to show screen dimensions
|
||||||
|
function updateDebugInfo() {
|
||||||
|
document.getElementById('screen-size').textContent =
|
||||||
|
`${window.screen.width}x${window.screen.height}`;
|
||||||
|
document.getElementById('viewport-size').textContent =
|
||||||
|
`${window.innerWidth}x${window.innerHeight}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDebugInfo();
|
||||||
|
window.addEventListener('resize', updateDebugInfo);
|
||||||
|
window.addEventListener('orientationchange', updateDebugInfo);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
0
html/kidsai/test-chat.html
Normal file
0
html/kidsai/test-chat.html
Normal file
Reference in New Issue
Block a user