grok_test / templates /index.html
broadfield-dev's picture
Update templates/index.html
5d4d8d0 verified
raw
history blame
7.23 kB
<!DOCTYPE html>
<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 }}" data-last-update="0">
{% for article in articles %}
<div class="article-tile" data-published="{{ article.published }}" data-id="{{ loop.index }}">
{% 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>
let lastUpdate = 0;
function updateArticles() {
fetch('/get_updates')
.then(response => response.json())
.then(data => {
if (data.articles && data.last_update > lastUpdate) {
lastUpdate = data.last_update;
const newArticles = data.articles;
for (const [category, articles] of Object.entries(newArticles)) {
const tilesDiv = document.getElementById(`category-${category}`);
if (tilesDiv) {
const existingArticles = Array.from(tilesDiv.querySelectorAll('.article-tile'));
let currentIds = new Set(existingArticles.map(a => a.dataset.id));
let newHtml = '';
// Sort new articles by published date
articles.sort((a, b) => new Date(b.published) - new Date(a.published));
// Add new articles (up to 10 total, keeping most recent)
articles.forEach((article, index) => {
if (index < 10 && !currentIds.has(index.toString())) {
newHtml += `
<div class="article-tile" data-published="${article.published}" data-id="${index}">
${article.image !== "svg" ? `<img src="${article.image}" alt="Article Image">` : `
<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>
`}
<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>
`;
}
});
// Append new articles, maintaining limit of 10
if (newHtml) {
tilesDiv.innerHTML += newHtml;
const allArticles = Array.from(tilesDiv.querySelectorAll('.article-tile'));
allArticles.sort((a, b) => new Date(b.dataset.published) - new Date(a.dataset.published));
tilesDiv.innerHTML = allArticles.slice(0, 10).map(a => a.outerHTML).join('');
}
}
}
document.querySelector('.loading-message').style.display = 'none';
}
setTimeout(updateArticles, 2000); // Check every 2 seconds
})
.catch(error => {
console.error('Error updating articles:', error);
setTimeout(updateArticles, 2000); // Retry on error
});
}
document.addEventListener('DOMContentLoaded', () => {
const tiles = document.querySelectorAll('.tiles');
tiles.forEach(tile => {
lastUpdate = Math.max(lastUpdate, parseFloat(tile.dataset.lastUpdate) || 0);
});
updateArticles();
});
</script>
{% endif %}
</body>
</html>