Componente de Paginación con Scroll Infinito (2026) - Bsale-IO/template-docs GitHub Wiki
Componente reutilizable para colecciones de productos y blog, que permite definir el tipo de paginación desde la configuración general de la tienda.
La opción de paginación se encuentra disponible en el panel de configuración y aplica de forma global tanto para productos como para el blog, sin requerir cambios adicionales en el código una vez habilitada.
Important
Actualización importante: el componente de Paginación ahora es 100% genérico: un único código funciona para todas las plantillas (detecta automáticamente el grid y los items vía JavaScript, sin necesidad de assign wrapper_id / grid_selector por plantilla).
Por lo tanto, ya no se debe duplicar el código de Paginación en cada plantilla. Se implementa una sola vez (ver sección Código unificado de Paginación) y se reutiliza en Blog y en Colección – Buscador – Marca mediante {{ 'paginacion' | get_component }}.
Además, para que el scroll infinito funcione correctamente (que los nuevos productos cargados por AJAX queden disponibles para el JS de carrito/checkout vía window.Bsale.collections), es obligatorio actualizar el componente Coleccion (load collection) con el nuevo script (ver sección Actualización del componente Coleccion).
La activación y selección del modo de paginación se realiza directamente desde la configuración de la tienda, en la sección “Tipo de paginación para productos y blog”.
Desde esta opción es posible seleccionar el comportamiento deseado (paginación tradicional, carga automática o carga con botón), siempre que la configuración esté previamente habilitada para el cliente.
Antes de que la opción “Tipo de paginación para productos y blog” aparezca en la configuración de la tienda, es necesario habilitar previamente la configuración correspondiente a nivel de sistema.
Warning
Importante: Para que las opciones de configuración de paginación aparezcan en la configuración de la tienda y se active el scroll automático,
es obligatorio crear y habilitar previamente la configuración scroll_mode en la base de datos del cliente.
Si esta configuración no existe, las opciones no se mostrarán y el comportamiento de paginación no funcionará, aunque el componente esté correctamente implementado en la plantilla.
INSERT INTO db_bsale_29213.mk_markets_config
(mk_id, mkc_variable, mkc_valor, mkc_es_editable, mkc_es_empresa, mkc_control_html, mkc_orden, mc_id)
VALUES
(1, 'scroll_mode', 'auto', 1, 0, NULL, NULL, NULL);Important
Atención: El nombre de base de datos db_bsale_29213 es solo un ejemplo.
Al implementar en un cliente real, se debe reemplazar por la base de datos correspondiente al cliente, de lo contrario la configuración no se aplicará correctamente.
El mk_id es el número del market.
| Modo | Descripción |
|---|---|
| Carga automática al hacer scroll | Carga nuevos resultados automáticamente al llegar al final de la página |
| Carga con botón | Muestra un botón “Ver más” para cargar más resultados |
| Paginación numérica tradicional | Navegación clásica mediante páginas numeradas |
Modo por defecto: Carga automática al hacer scroll
Este es el único código de Paginación necesario. Reemplaza completamente los bloques de "Paginación" que antes se repetían en cada plantilla (Matías, Facundo, Catalina, Sofía, Trinidad, Ricardo, Nicolás, Rosario, Joaquín, etc).
A diferencia de la versión anterior, ya no requiere que la plantilla calcule wrapper_id / grid_selector vía Liquid ({% assign %} / data-grid): el propio script detecta automáticamente el grid (.bs-collection.grid, .bs-blog-articles, .grid.bs-blog, .grid) y los items (.grid__item, .bs-collection__product, .bs-blog-item, .item) dentro del wrapper correspondiente (products-wrapper para colecciones, content-wrapper para blog).
Componente: paginacion
{% case site.scroll_mode %}
{% when "auto" or "button" %}
{% if collection %}
{% assign wrapper_id = "products-wrapper" %}
{% else %}
{% assign wrapper_id = "content-wrapper" %}
{% endif %}
{% comment %} === SCROLL INFINITO (auto o button) === {% endcomment %}
{% if pagination.next %}
<div id="infinite-scroll-loader"></div>
<!-- Indicador de más contenido (solo modo auto) -->
<div id="scroll-indicator">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
<span>Desliza para ver más</span>
</div>
<button id="load-more-btn" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="7 13 12 18 17 13"></polyline>
<polyline points="7 6 12 11 17 6"></polyline>
</svg>
<span>Ver más</span>
</button>
<div id="scroll-sentinel"
data-next-page="{{ pagination.next }}"
data-mode="{{ site.scroll_mode }}"
data-wrapper="{{ wrapper_id }}">
</div>
{% endif %}
<script>
// Forzar recarga limpia cuando se vuelve desde caché del navegador (bfcache)
window.addEventListener("pageshow", function(event) {
if (event.persisted) location.reload();
});
document.addEventListener("DOMContentLoaded", function() {
// === OBTENER ELEMENTOS DEL DOM ===
const sentinel = document.getElementById("scroll-sentinel");
if (!sentinel) return; // Si no hay sentinel, no hay paginación
// Obtener configuración desde data attributes del sentinel
const wrapperID = sentinel.dataset.wrapper; // ID del contenedor principal
const scrollMode = sentinel.dataset.mode || "auto"; // Modo: auto, button o numbers
// Elementos de la UI
const contentWrapper = document.getElementById(wrapperID);
const loader = document.getElementById("infinite-scroll-loader");
const loadMoreBtn = document.getElementById("load-more-btn");
const scrollIndicator = document.getElementById("scroll-indicator");
const productsShown = document.getElementById("products-shown");
const sortSelect = document.querySelector("[data-bs=\"collection.sort\"]");
// Recargar página al cambiar orden (evita problemas de caché)
if (sortSelect) {
sortSelect.addEventListener("change", function() {
window.location.href = this.value;
});
}
if (!contentWrapper) return;
// === DETECCIÓN AUTOMÁTICA DE GRID ===
// Lista de selectores de grid soportados (en orden de prioridad)
const gridSelectors = [".bs-collection.grid", ".bs-blog-articles", ".grid.bs-blog", ".grid"];
let gridContainer = null;
let gridSelector = null;
// Buscar cuál selector de grid existe en el wrapper
for (const selector of gridSelectors) {
gridContainer = contentWrapper.querySelector(selector);
if (gridContainer) {
gridSelector = selector; // Guardar el selector encontrado
break;
}
}
if (!gridContainer) return; // Si no hay grid, salir
// === DETECCIÓN AUTOMÁTICA DE ITEMS ===
// Lista de selectores de items soportados (en orden de prioridad)
const itemSelectors = [".grid__item", ".bs-collection__product", ".bs-blog-item", ".item"];
let itemSelector = null;
// Buscar cuál selector de items existe en el grid
for (const selector of itemSelectors) {
if (gridContainer.querySelector(":scope > " + selector)) {
itemSelector = selector;
break;
}
}
// Si no encuentra ninguno, usar todos los hijos directos
if (!itemSelector) {
itemSelector = ":scope > *";
}
// === VARIABLES DE ESTADO ===
let isLoading = false; // Indica si está cargando
let nextPageUrl = sentinel.dataset.nextPage; // URL de la siguiente página
// === INICIALIZACIÓN SEGÚN MODO ===
if (scrollMode === "button") {
// Modo botón: mostrar botón y agregar evento click
loadMoreBtn.classList.add("active");
loadMoreBtn.addEventListener("click", loadMoreContent);
} else {
// Modo auto: mostrar indicador y configurar scroll
if (scrollIndicator) scrollIndicator.classList.add("active");
setupAutoScroll();
}
// === FUNCIÓN: Actualizar contador "Mostrando X de Y" ===
function updateCount() {
if (productsShown) {
const items = itemSelector === ":scope > *"
? gridContainer.children.length
: gridContainer.querySelectorAll(":scope > " + itemSelector).length;
productsShown.textContent = items;
}
}
// === FUNCIÓN: Configurar scroll infinito automático ===
function setupAutoScroll() {
// Observer: detecta cuando el sentinel entra en el viewport
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !isLoading && nextPageUrl) loadMoreContent();
});
}, { rootMargin: "500px", threshold: 0 }); // 500px antes de llegar
observer.observe(sentinel);
// Fallback: también detectar scroll manual
window.addEventListener("scroll", function() {
if (isLoading || !nextPageUrl) return;
if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 500) {
loadMoreContent();
}
});
// Verificar si necesita cargar más contenido inicial
checkIfNeedsMoreContent();
}
// === FUNCIÓN PRINCIPAL: Cargar más contenido ===
async function loadMoreContent() {
// Evitar cargas duplicadas
if (isLoading || !nextPageUrl) return;
isLoading = true;
// Ocultar indicador de scroll mientras carga
if (scrollIndicator) scrollIndicator.classList.add("hidden");
// Mostrar loader según el modo
scrollMode === "button" ? loadMoreBtn.classList.add("loading") : loader.classList.add("active");
try {
// Fetch de la siguiente página
const response = await fetch(nextPageUrl);
const doc = new DOMParser().parseFromString(await response.text(), "text/html");
//Se busca el JSON del listado de productos
const collDataBase = doc.getElementById("coll_data_base");
if (collDataBase?.textContent){
const newData = JSON.parse(collDataBase.textContent);
//Se busca el objeto de la coleccion y se añaden los nuevos productos.
const foundColl = window.Bsale.collections.find(coll => coll.name == newData.name);
if (foundColl){foundColl.addItems(newData.items)}
}
// Buscar el grid en la nueva página usando el selector detectado
const newGrid = doc.querySelector("#" + wrapperID + " " + gridSelector);
if (newGrid) {
//Clonar el grid completo.
const clonedGrid = newGrid.cloneNode(true);
//Inicializar eventos de agregar al carro
window.addToCartCollection(clonedGrid);
// Construir selector para los items
const newItemSelector = itemSelector === ":scope > *" ? ":scope > *" : ":scope > " + itemSelector;
const newItems = clonedGrid.querySelectorAll(newItemSelector);
// Agregar cada item al grid actual
gridContainer.append(...newItems);
// Actualizar contador
updateCount();
// Re-inicializar eventos (carrito, etc.)
if (typeof window.BS !== "undefined" && window.BS.init) window.BS.init();
}
// Buscar si hay más páginas
const newSentinel = doc.querySelector("#scroll-sentinel");
if (newSentinel?.dataset.nextPage) {
// Hay más páginas: actualizar URL y mostrar indicador
nextPageUrl = newSentinel.dataset.nextPage;
if (scrollIndicator) scrollIndicator.classList.remove("hidden");
if (scrollMode === "auto") checkIfNeedsMoreContent();
} else {
// No hay más páginas: limpiar elementos
nextPageUrl = null;
loader.remove();
loadMoreBtn.remove();
sentinel.remove();
if (scrollIndicator) scrollIndicator.remove();
}
} catch (error) {
console.error("Error:", error);
} finally {
// Siempre ejecutar: ocultar loaders
isLoading = false;
loader.classList.remove("active");
loadMoreBtn?.classList.remove("loading");
}
}
// === FUNCIÓN: Verificar si la página necesita más contenido ===
// Si la página no tiene scroll, carga más contenido automáticamente
function checkIfNeedsMoreContent() {
setTimeout(() => {
const pageHeight = document.documentElement.scrollHeight;
const viewportHeight = window.innerHeight;
// Si la página es más corta que la ventana y hay más contenido
if (pageHeight <= viewportHeight && nextPageUrl && !isLoading) {
loadMoreContent();
}
}, 300); // Delay para evitar loops
}
});
</script>
{% else %}
{% comment %} === PAGINACIÓN NUMÉRICA (numbers) === {% endcomment %}
{% if pagination.pages %}
<nav>
<ul class="pagination justify-content-center mt-3">
{% if pagination.prev %}
<li class="page-item">
<a class="page-link" tabindex="-1" href="{{ pagination.prev }}"><i class="fas fa-angle-left"></i></a>
</li>
{% endif %}
{% for page in pagination.pages %}
{% if page %}
{% if page.current %}
<li class="page-item active">
<span class="page-link cursor-default">{{ page.number }}</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{{ page.url }}">{{ page.number }}</a>
</li>
{% endif %}
{% else %}
<li class="page-item disabled">
<span class="page-link cursor-default">..</span>
</li>
{% endif %}
{% endfor %}
{% if pagination.next %}
<li class="page-item">
<a class="page-link" href="{{ pagination.next }}"><i class="fas fa-angle-right"></i></a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endcase %}Para que el scroll infinito / botón "Ver más" pueda sincronizar los productos recién cargados por AJAX con window.Bsale.collections (usado por el carrito y otros scripts del sitio), el componente Coleccion debe incluir el siguiente bloque, que expone el JSON de la colección en un <script id="coll_data_base"> que el JS de Paginación busca y parsea en cada carga:
Componente: Coleccion (load collection)
<!--- load collection ----------------------------------------->
<script>
window.INIT.collections.push({
"name": "{{title}}",
"items":{{collection | json_encode }}
});
</script>
<script id="coll_data_base" type="application/json">
{
"name": "{{title}}",
"items":{{collection | json_encode }}
}
</script>
<!----------------------------------------------------------->
Warning
Esta actualización es obligatoria en todas las plantillas para que el scroll infinito funcione correctamente. Sin este bloque, el JS de Paginación no podrá encontrar #coll_data_base y window.Bsale.collections no se actualizará con los nuevos productos, lo que puede afectar funcionalidades como agregar al carro sobre los ítems cargados dinámicamente.
Para implementar el componente correctamente, se debe identificar la versión de la plantilla y reemplazar el código correspondiente en los siguientes componentes:
- Componente Blog
- Componente Colección – Buscador – Marca (orden)
- Componente Colección – Buscador – Marca
- Componente Coleccion (load collection) → aplicar la actualización de la sección anterior
- Componente Paginación → usar una sola vez el código unificado de la sección Código unificado de Paginación (no se repite por plantilla)
Nota: los bloques
Blog,OrdenyColección – Buscador – Marcade cada plantilla se mantienen igual que antes (no cambian entre plantillas en su lógica de paginación, ya que ambos simplemente llaman a{{ 'paginacion' | get_component }}), por lo que a continuación solo se listan por referencia.
TEMPLATE MATIAS
Blog
<main class="bs-blog"> <div class="container"> {{ 'migas de pan' | get_component }} {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE FACUNDO
Blog
<main class="bs-blog"> <div class="container"> {{ 'migas de pan' | get_component }} {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE CATALINA
Blog
<main class="bs-blog"> <div class="container"> {{ 'migas de pan' | get_component }} {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE SOFÍA
Blog
{{ 'migas de pan' | get_component }} <main class="bs-blog"> <div class="container-xxl"> {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container-xxl container-fluid"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE TRINIDAD
Blog
<main class="bs-blog"> <div class="container"> {{ 'migas de pan' | get_component }} {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE RICARDO
Blog
<main class="bs-blog"> <div class="container-xxl container-fluid"> {{ 'migas de pan' | get_component }} {% if articles.size > 0 %} <div class="bs-blog-grid"> <h1>Blog</h1> <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="bs-blog-articles"> {% for art in articles %} <article class="bs-blog-item"> <a href="{{ art.link }}" title="{{ art.title }}" class="bs-blog-image-link"> {% if art.imagen.size > 0 %} <div class="bs-img-square blog bg-secondary cover"> <picture> <source {{ art.imagen | source_tag_attributes: 'X' }}> <source {{ art.imagen | source_tag_attributes: 'L' }}> <source {{ art.imagen | source_tag_attributes: 'M' }}> <source {{ art.imagen | source_tag_attributes: 'S' }}> <img {{ art.imagen | img_tag_attributes: 'S' }} onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </div> {% else %} <div class="bs-img-square blog bg-secondary"></div> {% endif %} </a> <div class="bs-blog-article"> <a href="{{ art.link }}" title="{{ art.title }}"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> </a> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 100, '...' }}</p> <div class="bs-blog-article-more"> <a href="{{ art.link }}" class="bs-blog-article__btn btn btn-link">Ver más</a> </div> </div> </article> {% endfor %} </div> </div> {{ 'paginacion' | get_component }} </div> {% endif %} </div> </main>Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container-xxl container-fluid"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE NICOLAS
Blog
{{'migas de pan' | get_component }} <div class="container-xxl"> <h2><a class="bs-home-title" href="/blog">Blog</a></h2> {% if articles.size > 0 %} <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="grid bs-blog"> {% for art in articles %} <div class="item"> <div class="bs-blog-article"> {% if art.imagen.size > 0 %} <a class="bs-img-square bs-blog-article__img" href="{{art.link}}" title="{{art.title}}"> <picture> <source srcset="{{art.imagen | image_url: 'L'}}" media="(min-width:800px)"> <source srcset="{{art.imagen | image_url: 'M'}}" media="(min-width:400px)"> <source srcset="{{art.imagen | image_url: 'S'}}" media="(min-width:240px)"> <source srcset="{{art.imagen | image_url: 'T'}}" media="(min-width:0px)"> <img loading="lazy" src="{{art.imagen | image_url: 'S'}}" onerror="this.onerror=null;this.src='{{art.imagen}}';" alt="{{art.title}}"> </picture> </a> {% else %} <div class="bs-img-square bs-blog-article__img"> </div> {% endif %} <div class="bs-blog-article__info"> <h4 class="bs-blog-article__title"> {{art.title}}</h4> <p class="bs-blog-article__content"> {{art.content | strip_html | truncate: 120, '...'}}</p> <a class="bs-blog-article__btn btn btn-link" href="{{art.link}}" title="{{art.title}}">ver más</a> </div> </div> </div> {% endfor %} </div> </div> {% endif %} {{'paginacion' | get_component }} </div><!-- container-->Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE ROSARIO
Blog
<!-- Preload de la primera imagen Crítica--> {% if articles.size > 0 and articles[0].imagen.size > 0 %} <link rel="preload" as="image" href="{{ articles[0].imagen | image_url: 'M' }}"> {% endif %} {{ 'migas de pan' | get_component }} <div class="container-xxl"> <h2><a class="bs-home-title" href="/blog">Blog</a></h2> {% if articles.size > 0 %} <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="grid bs-blog"> {% for art in articles %} <div class="item"> <div class="bs-blog-article"> {% if art.imagen.size > 0 %} <a class="bs-img-square bs-blog-article__img" href="{{ art.link }}" title="{{ art.title }}"> <picture> <!-- Pantallas grandes (escritorio) --> <source srcset="{{ art.imagen | image_url: 'L' }} 1x, {{ art.imagen | image_url: 'X' }} 2x" media="(min-width: 1200px)"> <!-- Pantallas medianas (tablets) --> <source srcset="{{ art.imagen | image_url: 'M' }} 1x, {{ art.imagen | image_url: 'L' }} 2x" media="(min-width: 800px)"> <!-- Pantallas pequeñas (smartphones grandes) --> <source srcset="{{ art.imagen | image_url: 'S' }} 1x, {{ art.imagen | image_url: 'M' }} 2x" media="(min-width: 400px)"> <!-- Pantallas móviles (smartphones pequeños) --> <source srcset="{{ art.imagen | image_url: 'M' }} 1x, {{ art.imagen | image_url: 'M' }} 2x" media="(min-width: 0px)"> <img src="{{ art.imagen | image_url: 'M' }}" onerror="this.onerror=null;this.src='{{ art.imagen }}';" alt="{{ art.title }}" loading="{% if forloop.last %}lazy{% endif %}"> </picture> </a> {% else %} <div class="bs-img-square bs-blog-article__img"></div> {% endif %} <div class="bs-blog-article__info"> <h4 class="bs-blog-article__title">{{ art.title }}</h4> <p class="bs-blog-article__content">{{ art.content | strip_html | truncate: 120, '...' }}</p> <a class="bs-blog-article__btn btn btn-link" href="{{ art.link }}" title="{{ art.title }}">ver más</a> </div> </div> </div> {% endfor %} </div> </div> <!-- Paginación dentro del if --> {{ 'paginacion' | get_component }} {% endif %} </div><!-- container -->Colección – Buscador – Marca > Orden
{% assign item_in_page = item_per_page %} {% for i in collection %} {%if forloop.last %} {% if forloop.index < item_per_page %} {% assign item_in_page = forloop.index %} {%endif%} {%endif%} {% endfor %} {%if total_item == 0%} {% assign item_in_page = 0 %} {% endif %} {% unless current_url contains 'search' %} <div class="row pb-3"> <div class="col"> Mostrando <span id="products-shown">{{item_in_page}}</span> de {{total_item}} </div> <div class="col-md-3 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> <option value="">Ordenar por</option> {% for sort in collection.sorting %} <option value="{{sort[1].url}}"{% if current_url contains sort[1].url %} selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div> {% endunless %}Colección – Buscador – Marca
<section class="bs-collection"> {{ 'migas de pan' | get_component }} <div class="container"> <!-- Imagen de la colección --> {% if collection.image %} <div class="d-flex justify-content-center mb-2"> <img class="image-collection img-fluid rounded" src="{{ collection.image }}" alt="{{ title }}"> </div> {% endif %} <div class="row"> <!-- Título y descripción de la colección --> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 mb-4 sidebar-filters"> <div class="sidebar-filters__inner"> {{ 'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> <article class="col-lg-9"> {% if collection.size > 0 %} <!-- Orden de la colección --> <section class="mb-3"> {{ 'Coleccion - Buscador - Marca > orden' | get_component }} </section> <!-- Lista de productos de la colección --> <section class="mb-4"> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> </section> <!-- Paginación --> <nav class="d-flex justify-content-center"> {{ 'paginacion' | get_component }} </nav> {% else %} <!-- Mensaje de error si no hay productos --> {{ 'error > coleccion' | get_component }} {% endif %} </article> </div> </div> </section>
TEMPLATE JOAQUIN
Blog
{{'migas de pan' | get_component }} <div class="container-xxl"> <h2><a class="bs-title" href="/blog">Blog</a></h2> {% if articles.size > 0 %} <!-- Wrapper para scroll infinito --> <div id="content-wrapper"> <div class="grid bs-blog"> {% for art in articles %} <div class="item"> <div class="bs-blog-article"> {% if art.imagen.size > 0 %} <a class="bs-img-square bs-blog-article__img" href="{{art.link}}" title="{{art.title}}"> <picture class='img-bg-blur' style="--img-bg-blur: url('{{art.imagen | image_url: 'S'}}')"> <source srcset="{{art.imagen | image_url: 'X'}}" media="(min-width:800px)"> <source srcset="{{art.imagen | image_url: 'L'}}" media="(min-width:400px)"> <source srcset="{{art.imagen | image_url: 'M'}}" media="(min-width:240px)"> <source srcset="{{art.imagen | image_url: 'S'}}" media="(min-width:0px)"> <img loading="lazy" src="{{art.imagen | image_url: 'L'}}" onerror="this.onerror=null;this.src='{{art.imagen}}';" alt="{{art.title}}"> </picture> </a> {% else %} <div class="bs-img-square bs-blog-article__img"></div> {% endif %} <div class="bs-blog-article__info"> <h4 class="bs-blog-article__title"> {{art.title}}</h4> <p class="bs-blog-article__content"> {{art.content | strip_html | truncate: 120, '...'}}</p> <a class="bs-blog-article__btn btn" href="{{art.link}}" title="{{art.title}}">ver más</a> </div> </div> </div> {% endfor %} </div> </div> {{'paginacion' | get_component }} {% endif %} </div><!-- container-->Colección – Buscador – Marca > Orden
<div class="row bs-collection-order align-items-center"> <div class="col">Mostrando <span id="products-shown">{{ collection.products.size }}</span> de {{collection.size}}</div> <div class="col-lg-4 col-md-5 col-sm-6 "> <select class="custom-select" data-bs="collection.sort"> {% for sort in collection.sorting %} <option value="{{sort[1].url}}" {% if sort[1].selected %}selected{% endif %}>{{sort[1].title}}</option> {% endfor %} </select> </div> </div>Colección – Buscador – Marca
<section class="bs-collection mb-3"> {{'migas de pan'| get_component }} {% if collection.image and pagination.prev == false %} <picture> <source srcset="{{ collection.image | image_url: "X" }}" media="(min-width:1200px)"> <source srcset="{{ collection.image | image_url: "X" }}" media="(min-width:800px)"> <source srcset="{{ collection.image | image_url: "L" }}" media="(min-width:400px)"> <source srcset="{{ collection.image | image_url: "M" }}" media="(min-width:240px)"> <source srcset="{{ collection.image | image_url: "S" }}" media="(min-width:100px)"> <img class="bs-collection__image" src="{{ collection.image | image_url: "M"}}" alt="{{collection.title}}" onerror="this.onerror=null;this.src='{{collection.image}}';"> </picture> {%endif%} <div class="container bs-collection__container" > <div class="row"> <div class="col-12 text-center mb-4"> <h1 class="bs-collection__title"> {% if current_url contains '/search?' %} <div class="bs-collection__subtitle text-muted">Resultado de Búsqueda para:</div> {{ title }} {% else %} {{ title }} {% endif %} </h1> {% if collection.description.size > 0 %} <p class="bs-collection__description text-muted mt-2 mx-auto" style="max-width: 1000px; font-size: 1rem; line-height: 1.5;"> {{ collection.description }} </p> {% endif %} </div> <!-- Filtros sticky --> <aside class="col-lg-3 sidebar-filters"> <div class="sidebar-filters__inner"> {{'Coleccion - Buscador - Marca > filtros' | get_component }} </div> </aside> {% assign search-error1 = site.url | prepend: "https://" | append: "/search" %} {% assign search-error2 = site.url | prepend: "https://" | append: "/search/" %} {% assign search-error3 = site.url | prepend: "https://" | append: "/search?" %} {% if collection.size < 1 or current_url == search-error1 or current_url == search-error2 or current_url == search-error3 %} <div class="col-12 col-lg-9"> {{'error > coleccion' | get_component }} </div> {% else %} <article class="col-lg-9"> {% if collection.size > 0 %} {{ 'Coleccion - Buscador - Marca > orden' | get_component }} <!-- Wrapper para scroll infinito --> <div id="products-wrapper"> {{ 'Coleccion' | get_component }} </div> {{ 'paginacion' | get_component }} {% endif %} </article> {%endif%} </div> </div> </section>
Warning
Incorporar el código al final del style.css o en modificaciones.css
Código CSS
/**********************
paginación 2.0
***********************/
/* Sidebar sticky */
.sidebar-filters {
position: relative;
}
.sidebar-filters__inner {
position: sticky;
top: 70px;
max-height: calc(100vh - 140px);
overflow-y: auto;
padding-bottom: 20px;
}
.sidebar-filters__inner::-webkit-scrollbar {
width: 4px;
}
.sidebar-filters__inner::-webkit-scrollbar-track {
background: transparent;
}
.sidebar-filters__inner::-webkit-scrollbar-thumb {
background: #ddd;
border-radius: 4px;
}
@media (max-width: 991.98px) {
.sidebar-filters__inner {
position: relative;
top: 0;
max-height: none;
overflow-y: visible;
}
}
/* Loader */
#infinite-scroll-loader {
display: none;
width: 20px;
height: 20px;
margin: 2rem auto;
border: 2px solid #e0e0e0;
border-top-color: #999;
border-radius: 50%;
animation: spin 1.5s linear infinite;
}
#infinite-scroll-loader.active {
display: block;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Sentinel */
#scroll-sentinel {
height: 1px;
visibility: hidden;
}
/* Indicador de scroll */
#scroll-indicator {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 1.5rem 0;
color: #999;
font-size: 0.85rem;
}
#scroll-indicator svg {
width: 24px;
height: 24px;
animation: bounceDown 1.5s ease-in-out infinite;
}
#scroll-indicator.active {
display: flex;
}
#scroll-indicator.hidden {
display: none !important;
}
@keyframes bounceDown {
0%, 100% {
transform: translateY(0);
opacity: 0.5;
}
50% {
transform: translateY(8px);
opacity: 1;
}
}
/* Botón cargar más */
#load-more-btn {
display: none;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
max-width: 200px;
margin: 2rem auto;
padding: 12px 24px;
background: transparent;
border: 1px solid #ddd;
border-radius: 30px;
color: #666;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s ease;
}
#load-more-btn:hover {
border-color: #999;
color: #333;
transform: translateY(2px);
}
#load-more-btn svg {
width: 18px;
height: 18px;
transition: transform 0.2s ease;
}
#load-more-btn:hover svg {
transform: translateY(3px);
}
#load-more-btn.active {
display: flex;
}
#load-more-btn.loading {
pointer-events: none;
opacity: 0.6;
}
#load-more-btn.loading svg {
animation: bounce 1s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(5px); }
}