diff --git a/blocks/filter-cards/filter-cards.css b/blocks/filter-cards/filter-cards.css index d77b451..98576f6 100644 --- a/blocks/filter-cards/filter-cards.css +++ b/blocks/filter-cards/filter-cards.css @@ -1,60 +1,99 @@ -.filter-cards > ul { - box-sizing: border-box; +.filter-cards .filter-cards-list { list-style: none; margin: 0; padding: 0; display: grid; - grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); - gap: 1.5rem; - width: 100%; + grid-template-columns: 1fr; + gap: 24px; +} + +@media (width >= 600px) { + .filter-cards .filter-cards-list { + grid-template-columns: repeat(2, 1fr); + } } -.filter-cards > ul > li { - box-sizing: border-box; - display: flex; - flex-direction: column; - min-width: 0; - overflow: hidden; - border: 1px solid var(--dark-color, #333); - border-radius: 4px; - background-color: var(--background-color); +@media (width >= 900px) { + .filter-cards .filter-cards-list { + grid-template-columns: repeat(3, 1fr); + } } -.filter-cards .filter-cards-card-image { - flex: 0 0 auto; +.filter-cards-card { + background: transparent; +} + +.filter-cards-card-image { line-height: 0; - overflow: hidden; + margin-bottom: 12px; } -.filter-cards .filter-cards-card-image picture, -.filter-cards > ul > li img { +.filter-cards-card-image a { display: block; +} + +.filter-cards-card-image img { width: 100%; - height: auto; + aspect-ratio: 16 / 9; object-fit: cover; + border-radius: 0; } -.filter-cards .filter-cards-card-body { - flex: 1 1 auto; - min-height: 0; - margin: 0; - padding: 1rem; - overflow: auto; - text-align: left; +.filter-cards-card-body h3 { + font-family: var(--body-font-family-semibold); + font-size: 18px; + font-weight: 600; + line-height: 1.3; + text-transform: uppercase; + margin: 0 0 8px; +} + +.filter-cards-card-body h3 a { + color: #000; + text-decoration: none; +} + +.filter-cards-card-body h3 a:hover { + text-decoration: underline; +} + +.filter-cards-card-body p { + font-size: 16px; + line-height: 1.4; + color: #333; + margin: 0 0 8px; } -.filter-cards .filter-cards-card-body :is(h3, h4) { - margin: 0 0 0.5rem; +.filter-cards-card-body .filter-cards-read-more { font-family: var(--body-font-family-semibold); - font-size: var(--body-font-size-s); + font-size: 14px; font-weight: 600; - line-height: 1.25; - color: var(--text-color); + text-transform: uppercase; + text-decoration: underline; + color: #0357b8; } -.filter-cards .filter-cards-card-body p { - margin: 0; - font-size: var(--body-font-size-xs); - line-height: 1.4; - color: var(--text-color); +.filter-cards-card-body .filter-cards-read-more:hover { + color: #024a9e; +} + +.filter-cards .filter-cards-more { + display: block; + margin: 32px auto 0; + padding: 14px 40px; + font-family: var(--body-font-family-semibold); + font-size: 14px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1.5px; + background-color: #000; + color: #fff; + border: none; + border-radius: 50px; + cursor: pointer; + transition: background-color 0.2s; +} + +.filter-cards .filter-cards-more:hover { + background-color: #333; } diff --git a/blocks/filter-cards/filter-cards.js b/blocks/filter-cards/filter-cards.js index cf3ab31..1a6bbfc 100644 --- a/blocks/filter-cards/filter-cards.js +++ b/blocks/filter-cards/filter-cards.js @@ -1,26 +1,139 @@ -import { createOptimizedPicture } from '../../scripts/aem.js'; - -export default function decorate(block) { - const ul = document.createElement('ul'); - [...block.children].forEach((row) => { - const li = document.createElement('li'); - while (row.firstElementChild) li.append(row.firstElementChild); - [...li.children].forEach((div) => { - if (div.children.length === 1 && div.querySelector('picture')) { - div.className = 'filter-cards-card-image'; - } else { - div.className = 'filter-cards-card-body'; - } - }); - ul.append(li); +const INDEX_URL = '/en/home/improve/query-index.json'; +const PAGE_SIZE = 6; + +let allArticles = []; +let filteredArticles = []; +let currentPage = 0; + +async function fetchIndex() { + const resp = await fetch(INDEX_URL); + const json = await resp.json(); + return json.data || []; +} + +function createCard(article) { + const card = document.createElement('li'); + card.className = 'filter-cards-card'; + + if (article.image) { + const imageDiv = document.createElement('div'); + imageDiv.className = 'filter-cards-card-image'; + const a = document.createElement('a'); + a.href = article.path; + const img = document.createElement('img'); + img.src = article.image; + img.alt = article.title; + img.loading = 'lazy'; + a.appendChild(img); + imageDiv.appendChild(a); + card.appendChild(imageDiv); + } + + const body = document.createElement('div'); + body.className = 'filter-cards-card-body'; + + const title = document.createElement('h3'); + const titleLink = document.createElement('a'); + titleLink.href = article.path; + titleLink.textContent = article.title; + title.appendChild(titleLink); + body.appendChild(title); + + if (article.description) { + const desc = document.createElement('p'); + desc.textContent = article.description; + body.appendChild(desc); + } + + const readMore = document.createElement('p'); + const readMoreLink = document.createElement('a'); + readMoreLink.href = article.path; + readMoreLink.textContent = 'Read More'; + readMoreLink.className = 'filter-cards-read-more'; + readMore.appendChild(readMoreLink); + body.appendChild(readMore); + + card.appendChild(body); + return card; +} + +function renderCards(block, articles, append = false) { + let list = block.querySelector('.filter-cards-list'); + if (!list || !append) { + list = document.createElement('ul'); + list.className = 'filter-cards-list'; + const existing = block.querySelector('.filter-cards-list'); + if (existing) existing.remove(); + block.insertBefore(list, block.querySelector('.filter-cards-more')); + } + + articles.forEach((article) => { + list.appendChild(createCard(article)); }); +} + +function getPageArticles() { + const start = currentPage * PAGE_SIZE; + return filteredArticles.slice(start, start + PAGE_SIZE); +} + +function updateMoreButton(block) { + const btn = block.querySelector('.filter-cards-more'); + const totalShown = (currentPage + 1) * PAGE_SIZE; + if (totalShown >= filteredArticles.length) { + btn.style.display = 'none'; + } else { + btn.style.display = ''; + } +} + +function filterArticles(filter) { + if (!filter) { + filteredArticles = [...allArticles]; + } else { + const lowerFilter = filter.toLowerCase(); + filteredArticles = allArticles.filter((a) => { + const content = (a.content || '').toLowerCase(); + const title = (a.title || '').toLowerCase(); + const tags = (a.tags || '').toLowerCase(); + return content.includes(lowerFilter) + || title.includes(lowerFilter) + || tags.includes(lowerFilter); + }); + } +} + +export default async function decorate(block) { + block.textContent = ''; + + const moreBtn = document.createElement('button'); + moreBtn.className = 'filter-cards-more'; + moreBtn.textContent = 'MORE'; + block.appendChild(moreBtn); + + const data = await fetchIndex(); + allArticles = data + .filter((a) => a.path && a.title && a.path !== window.location.pathname) + .sort((a, b) => (b.lastModified || 0) - (a.lastModified || 0)); - ul.querySelectorAll('picture > img').forEach((img) => { - const pic = img.closest('picture'); - if (pic) { - pic.replaceWith(createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }])); - } + filteredArticles = [...allArticles]; + currentPage = 0; + + renderCards(block, getPageArticles()); + updateMoreButton(block); + + moreBtn.addEventListener('click', () => { + currentPage += 1; + renderCards(block, getPageArticles(), true); + updateMoreButton(block); }); - block.replaceChildren(ul); + // Listen for filter events from filter-bubble block + document.addEventListener('filter-change', (e) => { + const filter = e.detail?.filter || ''; + filterArticles(filter); + currentPage = 0; + renderCards(block, getPageArticles()); + updateMoreButton(block); + }); }