Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/article list #92

Merged
merged 15 commits into from
Jan 22, 2024
55 changes: 54 additions & 1 deletion cigaradvisor/blocks/article-list/article-list.css
Original file line number Diff line number Diff line change
@@ -1 +1,54 @@
/** Dummy File for now **/
@import url('../article-teaser/article-teaser.css');
bstopp marked this conversation as resolved.
Show resolved Hide resolved

.article-list.block .pagination-container {
display: flex;
justify-content: center;
align-items: center;
padding-top: 30px;

}

.article-list.block .pagination {
display: flex;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}

.article-list.block .pagination li {
display: inline;
}

.article-list.block .pagination a {
border: .5px solid var(--tan);
margin: auto 2px;
font-size: var(--body-font-size-s);
min-width: 40px;
display: flex;
justify-content: center;
align-items: center;
min-height: 40px;
font-weight: var(--font-weight-normal);
position: relative;
float: left;
padding: 6px 12px;
line-height: var(--line-height-m);
text-decoration: none;
background-color: var(--clr-white);

}

.article-list.block .pagination a:hover {
background-color: var(--tan);
border-color: var(--tan);
color: var(--clr-white);
}

.article-list.block .pagination .gap:hover {
background-color: var(--neutral-grey);
}

.article-list.block .pagination a.active {
background-color: var(--tan);
color: var(--clr-white);;
}
143 changes: 142 additions & 1 deletion cigaradvisor/blocks/article-list/article-list.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,144 @@
import { readBlockConfig } from '../../scripts/aem.js';
import { fetchAuthorInfo, fetchCategoryInfo, fetchPostsInfo } from '../../scripts/scripts.js';
import { buildArticleTeaser } from '../article-teaser/article-teaser.js';

// Function to create ellipsis
function createEllipsis() {
const listItem = document.createElement('li');
const a = document.createElement('a');
const span = document.createElement('span');
a.className = 'gap';
span.textContent = '...';
a.appendChild(span);
listItem.appendChild(a);
return listItem;
}

// Function to create a page link
function createPageLink(pageNumber, text, className) {
const listItem = document.createElement('li');
const link = document.createElement('a');
const currentPagePath = window.location.pathname;
link.href = `${currentPagePath}?page=${pageNumber}`;
link.textContent = text;

if (className) {
link.classList.add(className);
}

listItem.appendChild(link);
return listItem;
}

function generatePagination(currentPage, totalPages) {
const displayPages = 7;
const paginationList = document.createElement('ol');
paginationList.className = 'pagination';

// Previous page link
if (currentPage > 1) {
paginationList.appendChild(createPageLink(currentPage - 1, '«', 'prev'));
}

// Page links
const startPage = Math.max(1, currentPage - Math.floor(displayPages / 2));
const endPage = Math.min(totalPages, startPage + displayPages - 1);

if (startPage > 1) {
paginationList.appendChild(createPageLink(1, '1'));
if (startPage > 2) {
paginationList.appendChild(createEllipsis());
}
}

for (let i = startPage; i <= endPage; i += 1) {
if (i === currentPage) {
paginationList.appendChild(createPageLink(i, i, 'active'));
} else {
paginationList.appendChild(createPageLink(i, i));
}
}

if (endPage < totalPages) {
if (endPage < totalPages - 1) {
paginationList.appendChild(createEllipsis());
}
paginationList.appendChild(createPageLink(totalPages, totalPages));
}

// Next page link
if (currentPage < totalPages) {
paginationList.appendChild(createPageLink(currentPage + 1, '»', 'next'));
}
return paginationList;
}

export default async function decorate(block) {
block.innerHTML = '';
const configs = readBlockConfig(block);
const { category } = configs;
const { author } = configs;
const { limit } = configs;
const parentDiv = document.createElement('div');
parentDiv.classList.add('section');
parentDiv.dataset.layout = '50/50';
const leftDiv = document.createElement('div');
leftDiv.classList.add('left-grid');
const rightDiv = document.createElement('div');
rightDiv.classList.add('right-grid');
let current = rightDiv;
let currentPage = 1;
if (category || author) {
let articles;
if (category) {
articles = await fetchPostsInfo(category, 'category');
} else if (author) {
articles = await fetchPostsInfo(author, 'author');
}
const totalArticles = articles.length;
const totalPages = Math.ceil(totalArticles / limit);
let categoryInfo;
let authorInfo;
if (category) {
categoryInfo = await fetchCategoryInfo(category);
}
if (author) {
authorInfo = await fetchAuthorInfo(author);
}
if (!articles || articles.length === 0) {
return;
}
const urlParams = new URLSearchParams(window.location.search);
currentPage = urlParams.get('page') ? parseInt(urlParams.get('page'), 10) : 1;
// eslint-disable-next-line max-len
const articlePromises = [...articles].slice((currentPage - 1) * limit, currentPage * limit).map(async (article) => {
const articletTeaserWrapper = document.createElement('div');
articletTeaserWrapper.classList.add('article-teaser-wrapper');
const articleTeaser = document.createElement('div');
articleTeaser.classList.add('article-teaser');
articleTeaser.classList.add('block');
articletTeaserWrapper.append(articleTeaser);
current = (current === leftDiv) ? rightDiv : leftDiv;
current.append(articletTeaserWrapper);
if (categoryInfo) {
authorInfo = await fetchAuthorInfo(article.author);
[article.author] = authorInfo;
[article.category] = categoryInfo;
buildArticleTeaser(articleTeaser, article);
} else if (authorInfo) {
categoryInfo = await fetchCategoryInfo(article.category);
[article.author] = authorInfo;
[article.category] = categoryInfo;
buildArticleTeaser(articleTeaser, article);
}
});
await Promise.all(articlePromises);

parentDiv.append(leftDiv);
parentDiv.append(rightDiv);
block.replaceChildren(parentDiv);
const pageinationContainer = document.createElement('div');
pageinationContainer.classList.add('pagination-container');
pageinationContainer.appendChild(generatePagination(currentPage, totalPages));
block.append(pageinationContainer);
}
}
47 changes: 27 additions & 20 deletions cigaradvisor/blocks/article-teaser/article-teaser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createOptimizedPicture } from '../../scripts/aem.js';
import { fetchData, getRelativePath } from '../../scripts/scripts.js';
import { fetchPostsInfo, fetchAuthorInfo, fetchCategoryInfo } from '../../scripts/scripts.js';

function formatDate(originalDateString) {
const utcDateString = new Date(originalDateString * 1000);
Expand All @@ -13,41 +13,48 @@ function formatDate(originalDateString) {
return `${formattedDate}|${dateTimeAttribute}`;
}

export default async function decorate(block) {
const filterPath = block.querySelector('a').getAttribute('href');
block.classList.add('article-teaser');
const articleInfo = await fetchData(getRelativePath(filterPath), '/cigaradvisor/posts/query-index.json');
if (!articleInfo) {
return;
}
const articleCategoryLink = articleInfo.category;
const articleCategoryInfo = await fetchData(getRelativePath(articleCategoryLink));
const [formattedDate, datetimeAttr] = formatDate(articleInfo.published).split('|');
const articleAuthorLink = articleInfo.author;
const articleAuthorInfo = await fetchData(getRelativePath(articleAuthorLink), '/cigaradvisor/author/query-index.json');
block.innerHTML = `
// eslint-disable-next-line max-len
export function buildArticleTeaser(parentElement, article) {
const [formattedDate, datetimeAttr] = formatDate(article.published).split('|');
parentElement.innerHTML += `
<article class="article article-thumbnail">
<a class="article-category" href="${articleCategoryLink}" data-category="${(articleCategoryInfo && articleCategoryInfo.title) ? articleCategoryInfo.title : ''}" title="${(articleCategoryInfo && articleCategoryInfo.title) ? articleCategoryInfo.title : ''}">${(articleCategoryInfo && articleCategoryInfo.title) ? articleCategoryInfo.title : ''}</a>
<a class="article-category" href="${article.category ? article.category.path : ''}" data-category="${(article.category && article.category.title) ? article.category.title : ''}" title="${(article.category && article.category.title) ? article.category.title : ''}">${(article.category && article.category.title) ? article.category.title : ''}</a>
<div class="article-image">
${createOptimizedPicture(articleInfo.image).outerHTML}
${createOptimizedPicture(article.image).outerHTML}
</div>
<div class="article-content">
<articleheader class="article-header">
<h2 class="article-title">
<a class="article-title-link" href="${articleInfo.path}" title="${articleInfo.title}">${articleInfo.title}</a>
<a class="article-title-link" href="${article.path}" title="${article.title}">${article.title}</a>
</h2>
<div class="article-meta">
<a class="article-authorLink" href="${articleAuthorLink}" title="By ${(articleAuthorInfo && articleAuthorInfo.name) ? articleAuthorInfo.name : ''}">By ${(articleAuthorInfo && articleAuthorInfo.name) ? articleAuthorInfo.name : ''}</a>
<a class="article-authorLink" href="${article.author ? article.author.path : ''}" title="By ${(article.author && article.author.name) ? article.author.name : ''}">By ${(article.author && article.author.name) ? article.author.name : ''}</a>
<time class="article-pubdate" datetime="${datetimeAttr}">${formattedDate}</time>
</div>
</articleheader>
<div class="article-preview">
<div class="article-excerpt">
<p><span class="rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time">${articleInfo.readingTime}</span></span> ${articleInfo.description}</p>
<p><span class="rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time">${article.readingTime}</span></span> ${article.description}</p>
</div>
<a class="article-read-more read-more" href="${articleInfo.path}" title="Read More">Read More</a>
<a class="article-read-more read-more" href="${article.path}" title="Read More">Read More</a>
</div>
</div>
</article>
`;
}

export default async function decorate(block) {
const filterPath = block.querySelector('a').getAttribute('href');
block.classList.add('article-teaser');
const articleInfo = await fetchPostsInfo(filterPath);
if (!articleInfo || articleInfo.length === 0) {
return;
}
block.innerHTML = '';
const article = articleInfo[0];
const categoryInfo = await fetchCategoryInfo(article.category);
const authorInfo = await fetchAuthorInfo(article.author);
article.category = categoryInfo;
article.author = authorInfo;
buildArticleTeaser(block, article);
}
14 changes: 7 additions & 7 deletions cigaradvisor/blocks/articleheader/articleheader.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchData, getRelativePath } from '../../scripts/scripts.js';
import { fetchCategoryInfo, fetchAuthorInfo } from '../../scripts/scripts.js';

export default async function decorate(block) {
const section = document.createElement('section');
Expand All @@ -9,20 +9,20 @@ export default async function decorate(block) {
const articleInfo = document.createElement('div');
articleInfo.classList.add('article-info');
const categoryLink = block.querySelector('p.category').innerText;
const category = await fetchData(getRelativePath(categoryLink));
if (category) {
const category = await fetchCategoryInfo(categoryLink);
if (category[0]) {
const categoryLinkEl = document.createElement('div');
categoryLinkEl.classList.add('article-category');
categoryLinkEl.innerHTML = `<a href="${categoryLink}">${category.title}</a>`;
categoryLinkEl.innerHTML = `<a href="${categoryLink}">${category[0].title}</a>`;
articleInfo.append(categoryLinkEl);
}
articleInfo.append(block.querySelector('h1'));
const authorLink = block.querySelector('p.author').innerText;
const author = await fetchData(getRelativePath(authorLink));
const author = await fetchAuthorInfo(authorLink);
const authorLinkEl = document.createElement('div');
authorLinkEl.classList.add('article-author');
if (author) {
authorLinkEl.innerHTML = `<a href="${authorLink}">By ${author.title}</a>`;
if (author[0]) {
authorLinkEl.innerHTML = `<a href="${authorLink}">By ${author[0].title}</a>`;
articleInfo.append(authorLinkEl);
}
const publishedDate = block.querySelector('p.published-date').innerText;
Expand Down
10 changes: 5 additions & 5 deletions cigaradvisor/blocks/author-card/author-card.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readBlockConfig, createOptimizedPicture } from '../../scripts/aem.js';
import { isExternal, fetchData, getRelativePath } from '../../scripts/scripts.js';
import { isExternal, fetchAuthorInfo } from '../../scripts/scripts.js';

export default async function decorate(block) {
const configs = readBlockConfig(block);
Expand Down Expand Up @@ -34,13 +34,13 @@ export default async function decorate(block) {
authorWrapperSection.classList.add('author-wrapper');
authorWrapperSection.innerHTML = '';
const authorPromises = [...authors].map(async (authorPage) => {
const authorInfo = await fetchData(getRelativePath(authorPage), '/cigaradvisor/author/query-index.json');
if (authorInfo) {
const authorInfo = await fetchAuthorInfo(authorPage);
if (authorInfo[0]) {
return `<div class="author-content">
<div class="overlay-image">
${createOptimizedPicture(authorInfo.image).outerHTML}
${createOptimizedPicture(authorInfo[0].image).outerHTML}
<div class="overlay-content">
<p class="align-center"><a href="${authorInfo.page}">${authorInfo.name}</a></p>
<p class="align-center"><a href="${authorInfo[0].path}">${authorInfo[0].name}</a></p>
</div>
</div>
</div>`;
Expand Down
Loading