Slide_mover / index.html
humza7656's picture
Update index.html
51583ad verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content Carousel</title>
<!-- Load Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Configure Tailwind for custom classes and Inter font -->
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
colors: {
'primary-dark': '#1e293b',
'secondary-dark': '#0f172a',
'next-start': '#3b82f6', // Blue-500
'next-end': '#1d4ed8', // Blue-700
'prev-start': '#10b981', // Emerald-500
'prev-end': '#059669', // Emerald-700
}
}
}
}
</script>
<style>
/* Custom styles for the button effect */
.btn-base {
transition: all 0.3s ease;
transform: translateY(0);
}
.btn-base:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
transform: translateY(-2px);
}
.btn-base:active {
transform: translateY(0);
box-shadow: none;
}
</style>
</head>
<body class="bg-secondary-dark text-white font-sans min-h-screen flex flex-col items-center justify-center p-4">
<div class="w-full max-w-lg bg-primary-dark p-8 md:p-12 rounded-2xl shadow-2xl space-y-8">
<h1 class="text-4xl font-extrabold text-center text-gray-100 mb-6">
Content Carousel
</h1>
<p class="text-center text-gray-400 mb-8">
Move the content by clicking Next or Previous.
</p>
<!-- Button Container -->
<div class="flex flex-col sm:flex-row gap-6 justify-center">
<!-- Previous Button -->
<button id="prev-btn" data-endpoint="/prev"
class="btn-base flex-1 flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-xl
bg-gradient-to-r from-prev-start to-prev-end hover:from-prev-end hover:to-prev-start
shadow-lg shadow-emerald-700/50">
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7"></path></svg>
Previous Slide
</button>
<!-- Next Button -->
<button id="next-btn" data-endpoint="/next"
class="btn-base flex-1 flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-xl
bg-gradient-to-r from-next-start to-next-end hover:from-next-end hover:to-next-start
shadow-lg shadow-blue-700/50">
Next Slide
<svg class="w-5 h-5 ml-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7"></path></svg>
</button>
</div>
<!-- Response Display Area -->
<div id="response-display" class="pt-8 text-center min-h-[4rem] text-lg font-medium text-gray-400">
<!-- Messages will appear here -->
</div>
</div>
<script>
const BASE_URL = 'https://32d5c4f4e919.ngrok-free.app';
const prevBtn = document.getElementById('prev-btn');
const nextBtn = document.getElementById('next-btn');
const responseDisplay = document.getElementById('response-display');
/**
* Updates the UI display with the given message and style.
* @param {string} message - The text to display.
* @param {string} type - 'success' or 'error'.
*/
function updateDisplay(message, type) {
responseDisplay.textContent = message;
responseDisplay.classList.remove('text-green-400', 'text-red-400', 'text-gray-400');
if (type === 'success') {
responseDisplay.classList.add('text-green-400');
} else if (type === 'error') {
responseDisplay.classList.add('text-red-400');
} else {
responseDisplay.classList.add('text-gray-400');
}
}
/**
* Handles the API call with exponential backoff for resilience.
*/
async function safeFetch(fullUrl, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(fullUrl);
const contentType = response.headers.get("content-type");
if (!response.ok) {
const responseText = await response.text();
throw new Error(`HTTP error ${response.status}: ${responseText.substring(0, 100)}...`);
}
if (!contentType || !contentType.includes("application/json")) {
const responseText = await response.text();
throw new Error(`Content-Type error! Expected 'application/json' but received: ${contentType || 'None'}. Server body starts with: ${responseText.substring(0, 50)}...`);
}
return await response.json();
} catch (error) {
console.error(`Attempt ${i + 1} failed for ${fullUrl}:`, error.message);
if (i < retries - 1) {
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2;
} else {
throw new Error(`Failed to complete request to ${fullUrl} after ${retries} attempts. Reason: ${error.message}`);
}
}
}
}
/**
* Main function to handle button click and send request.
*/
async function sendRequest(endpoint) {
const fullUrl = `${BASE_URL}${endpoint}`;
// Disable buttons and show loading state
prevBtn.disabled = true;
nextBtn.disabled = true;
updateDisplay("Connecting to backend...", 'loading');
console.log(`Sending request to: ${fullUrl}`);
try {
const result = await safeFetch(fullUrl);
// Extract and display the "Statement" from your JSON response
updateDisplay(result.Statement || "Success! JSON received.", 'success');
console.log(`SUCCESS: Response from ${endpoint}`, result);
} catch (error) {
// Display the detailed error on the screen
updateDisplay(`Connection Error: ${error.message}`, 'error');
console.error(`ERROR: Failed request to ${endpoint}`, error.message);
} finally {
// Enable buttons regardless of success or failure
prevBtn.disabled = false;
nextBtn.disabled = false;
}
}
// Event listeners for the buttons
prevBtn.addEventListener('click', () => sendRequest(prevBtn.dataset.endpoint));
nextBtn.addEventListener('click', () => sendRequest(nextBtn.dataset.endpoint));
// Set initial message
updateDisplay("Ready. Please ensure your FastAPI server is running.", 'loading');
</script>
</body>
</html>