feat: paginación de noticias (app.py + templates)
This commit is contained in:
parent
db6fa3d2c3
commit
8109dbf274
3 changed files with 233 additions and 104 deletions
|
|
@ -3,27 +3,28 @@
|
|||
<li class="noticia-item">
|
||||
{% if noticia.imagen_url %}
|
||||
<div class="noticia-imagen">
|
||||
<a href="{{ noticia.url }}" target="_blank" rel="noopener noreferrer"><img src="{{ noticia.imagen_url }}" alt="Imagen para {{ noticia.titulo }}" loading="lazy"></a>
|
||||
<a href="{{ noticia.url }}" target="_blank" rel="noopener noreferrer">
|
||||
<img src="{{ noticia.imagen_url }}" alt="Imagen para {{ noticia.titulo }}" loading="lazy">
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="noticia-texto">
|
||||
<h3><a href="{{ noticia.url }}" target="_blank" rel="noopener noreferrer">{{ noticia.titulo }}</a></h3>
|
||||
<div class="noticia-meta">
|
||||
<span><i class="far fa-calendar-alt"></i> {{ noticia.fecha.strftime('%d-%m-%Y %H:%M') if noticia.fecha else 'N/D' }}</span>
|
||||
|
||||
<span><i class="far fa-calendar-alt"></i>
|
||||
{{ noticia.fecha.strftime('%d-%m-%Y %H:%M') if noticia.fecha else 'N/D' }}
|
||||
</span>
|
||||
{% if noticia.fuente_nombre %}
|
||||
| <span><i class="fas fa-newspaper"></i> <strong>{{ noticia.fuente_nombre }}</strong></span>
|
||||
{% endif %}
|
||||
|
||||
{% if noticia.categoria %}
|
||||
| <span><i class="fas fa-tag"></i> {{ noticia.categoria }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if noticia.pais %}
|
||||
| <span><i class="fas fa-globe-americas"></i> {{ noticia.pais }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="resumen-container">
|
||||
<div class="resumen-corto">
|
||||
{{ noticia.resumen | safe_html | truncate(280, True) }}
|
||||
|
|
@ -31,11 +32,11 @@
|
|||
<div class="resumen-completo" style="display: none;">
|
||||
{{ noticia.resumen | safe_html }}
|
||||
</div>
|
||||
{% if noticia.resumen|length > 280 %}
|
||||
{% if noticia.resumen and noticia.resumen|length > 280 %}
|
||||
<button class="ver-mas-btn">Ver más</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="text-center p-4">
|
||||
|
|
@ -43,3 +44,50 @@
|
|||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{# Resumen y paginación #}
|
||||
{% if total_results and total_results > 0 %}
|
||||
<div style="text-align:center; margin-top: 10px; color: var(--text-color-light);">
|
||||
{% set start_i = (page - 1) * per_page + 1 %}
|
||||
{% set end_i = (page - 1) * per_page + (noticias|length) %}
|
||||
Mostrando {{ start_i }}–{{ end_i }} de {{ total_results }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if total_pages and total_pages > 1 %}
|
||||
<nav class="pagination" aria-label="Paginación de noticias" style="margin-top: 15px;">
|
||||
{% set current = page %}
|
||||
{# Anterior #}
|
||||
{% if current > 1 %}
|
||||
<a href="#" class="page-link" data-page="{{ current - 1 }}">« Anterior</a>
|
||||
{% endif %}
|
||||
|
||||
{# Ventana de páginas (máx 5 alrededor) #}
|
||||
{% set start = 1 if current - 2 < 1 else current - 2 %}
|
||||
{% set end = total_pages if current + 2 > total_pages else current + 2 %}
|
||||
|
||||
{% if start > 1 %}
|
||||
<a href="#" class="page-link" data-page="1">1</a>
|
||||
{% if start > 2 %}<span class="page-link">…</span>{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% for p in range(start, end + 1) %}
|
||||
{% if p == current %}
|
||||
<span class="page-link active">{{ p }}</span>
|
||||
{% else %}
|
||||
<a href="#" class="page-link" data-page="{{ p }}">{{ p }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if end < total_pages %}
|
||||
{% if end < total_pages - 1 %}<span class="page-link">…</span>{% endif %}
|
||||
<a href="#" class="page-link" data-page="{{ total_pages }}">{{ total_pages }}</a>
|
||||
{% endif %}
|
||||
|
||||
{# Siguiente #}
|
||||
{% if current < total_pages %}
|
||||
<a href="#" class="page-link" data-page="{{ current + 1 }}">Siguiente »</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Últimas Noticias RSS{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<h2><i class="fas fa-filter" style="color: var(--secondary-color); margin-right: 10px;"></i>Filtrar Noticias</h2>
|
||||
|
||||
<form method="get" action="{{ url_for('home') }}" id="filter-form">
|
||||
<!-- Campos ocultos para paginación -->
|
||||
<input type="hidden" name="page" id="page" value="{{ page or 1 }}">
|
||||
<input type="hidden" name="per_page" id="per_page" value="{{ per_page or 20 }}">
|
||||
|
||||
<div class="filter-main-row">
|
||||
|
||||
<div class="filter-search-box">
|
||||
<label for="q">Buscar por palabra clave</label>
|
||||
<input type="search" name="q" id="q" placeholder="Ej: Trump, California, IA..." value="{{ q or '' }}">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="filter-actions">
|
||||
<button type="submit" class="btn"><i class="fas fa-search"></i> Filtrar</button>
|
||||
<a href="{{ url_for('home') }}" class="btn btn-secondary"><i class="fas fa-eraser"></i> Limpiar</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 15px; align-items: flex-end; border-top: 1px solid var(--border-color); padding-top: 20px;">
|
||||
<div>
|
||||
<label for="categoria_id">Categoría</label>
|
||||
|
|
@ -59,6 +61,7 @@
|
|||
</div>
|
||||
|
||||
<div id="noticias-container">
|
||||
{# El parcial incluye la lista + la paginación #}
|
||||
{% include '_noticias_list.html' %}
|
||||
</div>
|
||||
|
||||
|
|
@ -67,8 +70,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
const form = document.getElementById('filter-form');
|
||||
const continenteSelect = document.getElementById('continente_id');
|
||||
const paisSelect = document.getElementById('pais_id');
|
||||
const pageInput = document.getElementById('page');
|
||||
|
||||
// Lógica para filtrar países al cambiar el continente
|
||||
function filtrarPaises() {
|
||||
const continenteId = continenteSelect.value;
|
||||
for (let i = 1; i < paisSelect.options.length; i++) {
|
||||
|
|
@ -82,19 +85,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Lógica para enviar el formulario con AJAX
|
||||
async function actualizarNoticias(event) {
|
||||
if (event) event.preventDefault();
|
||||
async function cargarNoticias(keepPage) {
|
||||
// Si cambiamos filtros manualmente, reiniciamos a página 1
|
||||
if (!keepPage) pageInput.value = 1;
|
||||
|
||||
const formData = new FormData(form);
|
||||
const params = new URLSearchParams(formData);
|
||||
const newUrl = `${form.action}?${params.toString()}`;
|
||||
|
||||
const container = document.getElementById('noticias-container');
|
||||
container.style.opacity = '0.5';
|
||||
container.innerHTML = '<div style="text-align:center; padding: 40px;"><i class="fas fa-spinner fa-spin fa-2x"></i></div>';
|
||||
|
||||
try {
|
||||
const response = await fetch(newUrl, {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||
});
|
||||
const response = await fetch(newUrl, { headers: { 'X-Requested-With': 'XMLHttpRequest' } });
|
||||
const html = await response.text();
|
||||
container.innerHTML = html;
|
||||
window.history.pushState({path: newUrl}, '', newUrl);
|
||||
|
|
@ -106,10 +110,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Asignar los eventos
|
||||
continenteSelect.addEventListener('change', filtrarPaises);
|
||||
form.addEventListener('submit', actualizarNoticias);
|
||||
// Envío del formulario (filtrar) -> page = 1
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
cargarNoticias(false);
|
||||
});
|
||||
|
||||
// Clic en enlaces de paginación (delegación)
|
||||
document.addEventListener('click', function(e) {
|
||||
const link = e.target.closest('a.page-link');
|
||||
if (link && link.dataset.page) {
|
||||
e.preventDefault();
|
||||
pageInput.value = link.dataset.page;
|
||||
cargarNoticias(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializaciones
|
||||
continenteSelect.addEventListener('change', function() {
|
||||
filtrarPaises();
|
||||
// al cambiar continente, forzamos recarga desde página 1
|
||||
cargarNoticias(false);
|
||||
});
|
||||
|
||||
filtrarPaises(); // Ejecutar al inicio
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue