Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>News Feed Hub</title> | |
<style> | |
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; color: #333; } | |
h1 { text-align: center; color: #2c3e50; } | |
.search-container { text-align: center; margin: 20px 0; } | |
.search-bar { width: 50%; padding: 10px; border: 2px solid #3498db; border-radius: 25px; } | |
.category-section { margin: 20px 0; } | |
.category-title { background-color: #3498db; color: white; padding: 10px; border-radius: 5px; } | |
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; } | |
.article-tile { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } | |
.article-tile img, .article-tile svg { width: 100%; height: 150px; object-fit: cover; border-radius: 5px; } | |
.title a { font-size: 1.1em; color: #2c3e50; text-decoration: none; } | |
.title a:hover { color: #3498db; } | |
.description { color: #555; font-size: 0.9em; } | |
.published { font-size: 0.8em; color: #95a5a6; } | |
.no-articles { text-align: center; color: #2c3e50; margin-top: 20px; } | |
.loading-message { text-align: center; color: #3498db; margin: 10px 0; } | |
</style> | |
</head> | |
<body> | |
<h1>News Feed Hub</h1> | |
<div class="search-container"> | |
<form method="POST" action="/search"> | |
<input type="text" name="search" class="search-bar" placeholder="Search news..."> | |
</form> | |
</div> | |
{% if loading %} | |
<div class="loading-message">Fetching new RSS feeds in the background...</div> | |
{% endif %} | |
{% if has_articles %} | |
{% for category, articles in categorized_articles.items() %} | |
<div class="category-section"> | |
<div class="category-title">{{ category }}</div> | |
<div class="tiles" id="category-{{ category }}"> | |
{% for article in articles %} | |
<div class="article-tile" data-published="{{ article.published }}"> | |
{% if article.image != "svg" %} | |
<img src="{{ article.image }}" alt="Article Image"> | |
{% else %} | |
<svg width="100%" height="150" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#e0e0e0"/> | |
<text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="#666">No Image</text> | |
</svg> | |
{% endif %} | |
<div class="title"><a href="{{ article.link }}" target="_blank">{{ article.title }}</a></div> | |
<div class="description">{{ article.description }}</div> | |
<div class="published">Published: {{ article.published }}</div> | |
</div> | |
{% endfor %} | |
</div> | |
</div> | |
{% endfor %} | |
{% else %} | |
<div class="no-articles">No articles available yet. Loading new feeds...</div> | |
{% endif %} | |
{% if loading %} | |
<script> | |
function checkLoadingStatus() { | |
fetch('/check_loading') | |
.then(response => response.json()) | |
.then(data => { | |
if (data.status === "complete") { | |
// Soft refresh: fetch updated articles without full reload | |
fetch('/') | |
.then(response => response.text()) | |
.then(html => { | |
const parser = new DOMParser(); | |
const doc = parser.parseFromString(html, 'text/html'); | |
const newCategories = doc.querySelectorAll('.category-section'); | |
newCategories.forEach(newCat => { | |
const catId = newCat.querySelector('.tiles').id; | |
const existingCat = document.getElementById(catId); | |
if (existingCat) { | |
existingCat.innerHTML = newCat.querySelector('.tiles').innerHTML; | |
} | |
}); | |
document.querySelector('.loading-message').style.display = 'none'; | |
}) | |
.catch(error => console.error('Error updating articles:', error)); | |
} else { | |
setTimeout(checkLoadingStatus, 2000); // Check every 2 seconds | |
} | |
}) | |
.catch(error => { | |
console.error('Error checking loading status:', error); | |
setTimeout(checkLoadingStatus, 2000); // Retry on error | |
}); | |
} | |
document.addEventListener('DOMContentLoaded', () => { | |
checkLoadingStatus(); | |
}); | |
</script> | |
{% endif %} | |
</body> | |
</html> |