Spaces:
Running
Running
File size: 4,653 Bytes
f909bae 7c2bec2 f909bae 0be9c61 abcf498 31300e6 abcf498 31300e6 d547a7b abcf498 d547a7b 31300e6 b366eeb 7c2bec2 31300e6 b366eeb d547a7b 7c2bec2 31300e6 7c2bec2 d547a7b b366eeb 31300e6 d547a7b 31300e6 d547a7b 31300e6 d547a7b 31300e6 d547a7b f909bae d547a7b 31300e6 b366eeb abcf498 31300e6 e06118d 31300e6 d547a7b 31300e6 abcf498 e06118d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
// scripts/ui.js -- Corrected and Final Version
// --- Configuration ---
const BACKEND_URL = 'https://streamai-backend-v2.smplushypermedia.workers.dev';
// --- Helper Functions ---
const getElement = (id) => document.getElementById(id);
function showNotification(message, isError = false) {
const container = getElement('notification');
if (!container) return;
const bgColor = isError ? 'bg-red-500' : 'bg-green-500';
container.innerHTML = `<div class="flex items-center text-white p-4 rounded-lg shadow-lg ${bgColor}"><i class="fas fa-check-circle mr-3"></i><p>${message}</p></div>`;
container.classList.add('show');
setTimeout(() => { container.classList.remove('show'); }, 4000);
}
// --- Card Rendering ---
function createListingCard(item) {
const card = document.createElement('div');
const pinnedClass = item.is_pinned ? 'border-2 border-indigo-400' : 'shadow-md';
card.className = `stream-card bg-white rounded-lg overflow-hidden hover:shadow-xl transition duration-300 p-4 relative ${pinnedClass}`;
card.innerHTML = `
${item.is_pinned ? '<div class="absolute top-2 right-2 text-xs bg-indigo-500 text-white px-2 py-1 rounded-full animate-pulse"><i class="fas fa-thumbtack mr-1"></i> Pinned</div>' : ''}
<div class="mb-3"><h3 class="font-bold text-base">${item.title}</h3><div class="text-xs text-gray-500 mb-2 mt-1">From: <span class="font-semibold text-indigo-600">${item.source_name}</span></div></div>
<p class="text-gray-700 text-sm mb-4">${item.description || ''}</p>
<div class="flex justify-between items-center mt-auto"><span class="text-xs font-bold uppercase text-gray-400">${(item.category || '').replace('_', ' ')}</span><a href="${item.url}" target="_blank" rel="noopener noreferrer" class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded-full text-xs font-medium transition">Visit Site</a></div>
`;
return card;
}
// --- Core Logic ---
async function loadRecommendations() {
const container = getElement('recommendations-container');
if (!container) return;
try {
const response = await fetch(`${BACKEND_URL}/api/recommendations`);
if (!response.ok) throw new Error(`Network Error: ${response.statusText}`);
const listings = await response.json();
container.innerHTML = '';
if (listings.length === 0) {
container.innerHTML = `<p class="text-center col-span-full text-gray-500">No recommendations available yet.</p>`;
return;
}
listings.forEach(item => container.appendChild(createListingCard(item)));
} catch (error) {
container.innerHTML = `<p class="text-center col-span-full text-red-500">Could not load recommendations.</p>`;
}
}
async function handleFormSubmit(event) {
event.preventDefault();
const form = event.target;
const submitButton = getElement('submit-listing-btn');
submitButton.disabled = true;
submitButton.textContent = 'Submitting...';
const listingData = Object.fromEntries(new FormData(form).entries());
try {
const response = await fetch(`${BACKEND_URL}/api/add-listing`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(listingData),
});
const result = await response.json();
if (!response.ok) throw new Error(result.details || 'Submission failed.');
showNotification('Success! Your recommendation has been added.');
const newCard = createListingCard(listingData);
getElement('recommendations-container').prepend(newCard);
getElement('form-container').classList.add('hidden');
getElement('form-chevron').classList.remove('rotate-180');
form.reset();
} catch (error) {
showNotification(`Error: ${error.message}`, true);
} finally {
submitButton.disabled = false;
submitButton.textContent = 'Submit Listing';
}
}
// --- Initialization ---
export function initUI() {
const addListingForm = getElement('add-listing-form');
const toggleBtn = getElement('toggle-form-btn');
const formContainer = getElement('form-container');
const chevron = getElement('form-chevron');
if (toggleBtn && formContainer && chevron) {
toggleBtn.addEventListener('click', () => {
formContainer.classList.toggle('hidden');
chevron.classList.toggle('rotate-180');
});
}
if (addListingForm) {
addListingForm.addEventListener('submit', handleFormSubmit);
}
loadRecommendations();
} |