Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Blog with JSON Dataset</title> | |
<style> | |
body { | |
font-family: 'Inter', sans-serif; | |
background: linear-gradient(180deg, #0b1020, #0b1022 30%, #0b1124); | |
color: #e2e8f0; | |
margin: 0; | |
padding: 20px; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
} | |
.controls { | |
display: flex; | |
gap: 1rem; | |
margin: 2rem 0; | |
flex-wrap: wrap; | |
} | |
.search-bar, .category-filter { | |
background: rgba(255, 255, 255, 0.1); | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
border-radius: 25px; | |
padding: 0.75rem 1.5rem; | |
color: #e2e8f0; | |
} | |
.search-bar { | |
flex: 1; | |
min-width: 200px; | |
} | |
.category-filter { | |
min-width: 150px; | |
} | |
.blog-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); | |
gap: 2rem; | |
margin-top: 2rem; | |
} | |
.blog-card { | |
background: rgba(255, 255, 255, 0.05); | |
border-radius: 16px; | |
overflow: hidden; | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
transition: transform 0.3s ease; | |
} | |
.blog-card:hover { | |
transform: translateY(-8px); | |
} | |
.blog-card-image { | |
width: 100%; | |
height: 200px; | |
background-size: cover; | |
background-position: center; | |
} | |
.blog-card-content { | |
padding: 1.5rem; | |
} | |
.blog-card-title { | |
font-size: 1.25rem; | |
font-weight: 600; | |
margin-bottom: 0.5rem; | |
} | |
.blog-card-date { | |
color: #94a3b8; | |
font-size: 0.875rem; | |
margin-bottom: 1rem; | |
} | |
.blog-card-link { | |
color: #8b5cf6; | |
text-decoration: none; | |
font-weight: 600; | |
font-size: 0.875rem; | |
text-transform: uppercase; | |
} | |
.tags { | |
display: flex; | |
gap: 0.5rem; | |
margin-top: 1rem; | |
flex-wrap: wrap; | |
} | |
.tag { | |
background: rgba(139, 92, 246, 0.2); | |
color: #a78bfa; | |
padding: 0.25rem 0.75rem; | |
border-radius: 15px; | |
font-size: 0.75rem; | |
} | |
.loading { | |
text-align: center; | |
padding: 2rem; | |
color: #94a3b8; | |
} | |
.stats { | |
display: flex; | |
gap: 2rem; | |
margin: 1rem 0; | |
color: #94a3b8; | |
font-size: 0.875rem; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Blog with JSON Dataset</h1> | |
<div class="stats" id="stats"> | |
<span>Loading...</span> | |
</div> | |
<div class="controls"> | |
<input type="text" class="search-bar" placeholder="Search articles..." id="searchInput"> | |
<select class="category-filter" id="categoryFilter" aria-label="Filter by category"> | |
<option value="">All Categories</option> | |
</select> | |
</div> | |
<div class="blog-grid" id="blogGrid"> | |
<div class="loading">Loading articles...</div> | |
</div> | |
</div> | |
<script> | |
let allArticles = []; | |
let filteredArticles = []; | |
// Load data from JSON file | |
async function loadDataset() { | |
try { | |
const response = await fetch('data/news.json'); | |
const data = await response.json(); | |
allArticles = data.articles; | |
filteredArticles = [...allArticles]; | |
// Populate category filter | |
populateCategoryFilter(data.categories); | |
// Display articles | |
displayArticles(filteredArticles); | |
// Update stats | |
updateStats(); | |
} catch (error) { | |
console.error('Error loading dataset:', error); | |
document.getElementById('blogGrid').innerHTML = | |
'<div class="loading">Error loading data. Please check if data/news.json exists.</div>'; | |
} | |
} | |
// Populate category filter dropdown | |
function populateCategoryFilter(categories) { | |
const categoryFilter = document.getElementById('categoryFilter'); | |
categories.forEach(category => { | |
const option = document.createElement('option'); | |
option.value = category; | |
option.textContent = category; | |
categoryFilter.appendChild(option); | |
}); | |
} | |
// Create article card | |
function createArticleCard(article) { | |
const tags = article.tags ? article.tags.map(tag => | |
`<span class="tag">${tag}</span>` | |
).join('') : ''; | |
return ` | |
<article class="blog-card"> | |
<div class="blog-card-image" style="background-image: url('${article.image}');"></div> | |
<div class="blog-card-content"> | |
<h3 class="blog-card-title">${article.title}</h3> | |
<p class="blog-card-date">${article.date} • ${article.source} • ${article.category}</p> | |
<p style="color: #94a3b8; font-size: 0.875rem; margin-bottom: 1rem;">${article.description}</p> | |
<div class="tags">${tags}</div> | |
<a href="#" class="blog-card-link">READ MORE</a> | |
</div> | |
</article> | |
`; | |
} | |
// Display articles | |
function displayArticles(articles) { | |
const blogGrid = document.getElementById('blogGrid'); | |
if (articles.length === 0) { | |
blogGrid.innerHTML = '<div class="loading">No articles found.</div>'; | |
} else { | |
blogGrid.innerHTML = articles.map(createArticleCard).join(''); | |
} | |
} | |
// Filter articles | |
function filterArticles() { | |
const searchTerm = document.getElementById('searchInput').value.toLowerCase(); | |
const selectedCategory = document.getElementById('categoryFilter').value; | |
filteredArticles = allArticles.filter(article => { | |
const matchesSearch = | |
article.title.toLowerCase().includes(searchTerm) || | |
article.description.toLowerCase().includes(searchTerm) || | |
article.tags.some(tag => tag.toLowerCase().includes(searchTerm)); | |
const matchesCategory = !selectedCategory || article.category === selectedCategory; | |
return matchesSearch && matchesCategory; | |
}); | |
displayArticles(filteredArticles); | |
updateStats(); | |
} | |
// Update statistics | |
function updateStats() { | |
const stats = document.getElementById('stats'); | |
stats.innerHTML = ` | |
<span>Total Articles: ${allArticles.length}</span> | |
<span>Showing: ${filteredArticles.length}</span> | |
<span>Categories: ${new Set(allArticles.map(a => a.category)).size}</span> | |
`; | |
} | |
// Initialize the page | |
document.addEventListener('DOMContentLoaded', function() { | |
// Load dataset | |
loadDataset(); | |
// Add event listeners | |
document.getElementById('searchInput').addEventListener('input', filterArticles); | |
document.getElementById('categoryFilter').addEventListener('change', filterArticles); | |
}); | |
// Example functions for data manipulation | |
function getArticlesByCategory(category) { | |
return allArticles.filter(article => article.category === category); | |
} | |
function getLatestArticles(count = 3) { | |
return allArticles | |
.sort((a, b) => new Date(b.date) - new Date(a.date)) | |
.slice(0, count); | |
} | |
function searchByTags(tags) { | |
return allArticles.filter(article => | |
tags.some(tag => article.tags.includes(tag)) | |
); | |
} | |
</script> | |
</body> | |
</html> | |