diff --git a/blocks/author-box/author-box.css b/blocks/author-box/author-box.css new file mode 100644 index 00000000..530ee56b --- /dev/null +++ b/blocks/author-box/author-box.css @@ -0,0 +1,122 @@ +/* author box */ + +main .author-box-container { + padding-top: 0; +} + +main .author-box-container > div { + max-width: unset; + padding: 0; + margin: 0 auto; + } + + main .author-box { + visibility: unset; + max-width: unset; + } + + main .author-box-info { + display: flex; + flex-wrap: wrap; + align-items: center; + margin-top: 40px; + margin-bottom: 40px; + padding: 0 2rem; + } + + main .author-box-info .sharing-details { + margin-left: auto; + } + + main .author-box-info .blog-author-image, + main .author-box-info .blog-author-image img { + flex: 0 0 64px; + margin: 0; + margin-right: 16px; + height: 64px; + width: 64px; + border-radius: 50%; + object-fit: cover; + } + + main .author-box-info .blog-author-name { + margin-bottom: 0; + } + + main .author-box-info a { + text-decoration: none; + cursor: pointer; + } + + main .author-box-info p, + main .author-box-info p a { + margin: 0; + } + + main .author-box-info .sharing-details svg { + width: 40px; + height: 40px; + } + + main .author-box-info .blog-author-blurb { + font-style: italic; + color: grey; + padding-left: 15px; + display: none; + } + + main .author-box-info .publication-date-invalid { + display: none; + } + + @media (min-width: 600px) { + main .author-box { + margin-left: auto; + margin-right: auto; + padding-left: 0; + padding-right: 0; + } + + main .author-box .author-box-info { + max-width: 900px; + margin-left: auto; + margin-right: auto; + } + + main .author-box-info .blog-author-blurb { + max-width: 300px; + margin-left: 10px; + border-left: 1px solid grey; + display: block; + font-size: 15px; + } + + main .author-box-info .blog-author-details { + font-size: 16px; + } + } + + @media (min-width: 768px) { + main .author-box-info .blog-author-blurb { + max-width: 380px; + margin-left: 20px; + font-size: 18px; + } + + main .author-box-info .blog-author-details { + font-size: 18px; + } + } + + @media (min-width: 900px) { + main .author-box-info .blog-author-blurb { + max-width: 450px; + font-size: 20px; + margin-left: 30px; + padding-left: 30px; + } + + main .author-box-info .blog-author-details { + font-size: 20px; + } + } diff --git a/blocks/author-box/author-box.js b/blocks/author-box/author-box.js new file mode 100644 index 00000000..b6ca4af6 --- /dev/null +++ b/blocks/author-box/author-box.js @@ -0,0 +1,86 @@ +import { + getMetadata, +} from '../../scripts/lib-franklin.js'; + +function openPopup(e) { + const target = e.target.closest('a'); + const href = target.getAttribute('data-href'); + const type = target.getAttribute('data-type'); + window.open( + href, + type, + 'popup,top=233,left=233,width=700,height=467', + ); +} + +async function buildSharing(githubId) { + const authorName = getMetadata('author'); + const sharing = document.createElement('div'); + sharing.classList.add('sharing-details'); + const scriptUrl = new URL(import.meta.url); + const iconsPath = new URL('../../icons/icon-github.svg', scriptUrl).href; + // Fetch SVG content + const response = await fetch(iconsPath); + const svgContent = await response.text(); + sharing.innerHTML = ` + + ${svgContent} + + `; + sharing.querySelectorAll('[data-href]').forEach((link) => { + link.addEventListener('click', openPopup); + }); + return sharing; +} + +async function addProfileLinkToImage(authorImage, githubId) { + const authorLink = document.createElement('a'); + authorLink.classList.add('blog-author-link'); + authorLink.setAttribute('data-href', githubId); + authorLink.append(authorImage); + authorLink.addEventListener('click', openPopup); + return authorLink; +} + +async function createAuthorBlurb(blurb) { + const authorBlurb = document.createElement('div'); + authorBlurb.classList.add('blog-author-blurb'); + authorBlurb.append(blurb); + return authorBlurb; +} + +function validateDate(dateTag, dateString) { + const regex = /^[A-Z][a-z]+\s\d{1,2}(st|nd|rd|th),?\s\d{4}$/; + if (!regex.test(dateString)) { + dateTag.classList.add('publication-date-invalid'); + dateTag.setAttribute('title', 'invalid-date'); + console.error('Invalid publication date format. Please use a format like Month DDth, YYYY (e.g., January 30th, 2024)'); + } +} + +export default async function decorateAuthorBox(blockEl) { + const githubId = getMetadata('github'); + const childrenEls = Array.from(blockEl.children); + const bylineContainer = childrenEls[0]; + bylineContainer.classList.add('author-box-info'); + // author image + const authorImage = bylineContainer.firstElementChild; + authorImage.classList.add('blog-author-image'); + const addAuthorLink = await addProfileLinkToImage(authorImage, githubId); + bylineContainer.prepend(addAuthorLink); + // author name + bylineContainer.lastElementChild.classList.add('blog-author-details'); + const authorDetails = bylineContainer.lastElementChild; + authorDetails.firstElementChild.classList.add('blog-author-name'); + // publication date + const date = authorDetails.lastElementChild; + date.classList.add('blog-publication-date'); + validateDate(date, date.textContent.trim()); + // author blurb + const blurb = getMetadata('author-blurb'); + const authorBlurb = await createAuthorBlurb(blurb); + bylineContainer.append(authorBlurb); + // sharing + const shareBlock = await buildSharing(githubId); + bylineContainer.append(shareBlock); +} diff --git a/icons/icon-github.svg b/icons/icon-github.svg new file mode 100644 index 00000000..95992ac8 --- /dev/null +++ b/icons/icon-github.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/scripts/scripts.js b/scripts/scripts.js index b9361542..044297c9 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -425,7 +425,7 @@ function addBlockLevelInViewAnimation(main) { } function decorateBreadcrumb(main) { - if (!document.body.classList.contains('guides-template')) { + if (!document.body.classList.contains('guides-template') && !document.body.classList.contains('blog-template')) { return; } @@ -448,6 +448,7 @@ function decorateBreadcrumb(main) { main.prepend(wrapper); const isDocumentationLanding = window.location.pathname === '/docs/'; + const blogTemplate = document.body.classList.contains('blog-template'); const list = createTag('ul'); const home = createTag('li', {}, 'Home'); @@ -458,6 +459,7 @@ function decorateBreadcrumb(main) { const category = getMetadata('category'); const title = getMetadata('og:title'); + const template = getMetadata('template'); if (category) { const section = createTag( @@ -468,17 +470,28 @@ function decorateBreadcrumb(main) { list.append(section); } + if (template) { + const section = createTag( + 'li', + {}, + `${template}`, + ); + list.append(section); + } + if (!isDocumentationLanding) { const article = createTag('li', {}, `${title}`); list.append(article); - const backBtn = createTag('div', { class: 'guides-back-btn desktop' }, ` - - - Back - - `); - document.querySelector('.default-content-wrapper').prepend(backBtn); + if (!blogTemplate) { + const backBtn = createTag('div', { class: 'guides-back-btn desktop' }, ` + + + Back + + `); + document.querySelector('.default-content-wrapper').prepend(backBtn); + } } // make the last item to be unclickable as already on the page @@ -533,6 +546,21 @@ function decorateSVGs(main) { }); } +function buildAuthorBox(main) { + const div = document.createElement('div'); + const author = getMetadata('author'); + const publicationDate = getMetadata('publication-date'); + const authorImage = getMetadata('author-image'); + + const authorBoxBlockEl = buildBlock('author-box', [ + [`${author}`, + `

${author}

+

${publicationDate}

`], + ]); + div.append(authorBoxBlockEl); + main.append(div); +} + // --------------- Main functions here ---------------- // /** @@ -541,6 +569,9 @@ function decorateSVGs(main) { */ export function buildAutoBlocks(main) { try { + if (getMetadata('author') && !main.querySelector('.author-box')) { + buildAuthorBox(main); + } buildEmbeds(main); } catch (error) { // eslint-disable-next-line no-console diff --git a/styles/styles.css b/styles/styles.css index 594e3d8b..c302bd8e 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -312,6 +312,10 @@ aside { padding-left: var(--side-navigation-bar-gap); margin-right: 0; } + + .blog-template .default-content-wrapper { + max-width: 70%; + } } @media screen and (min-width: 1250px) { @@ -323,6 +327,11 @@ aside { .franklin .gnav .submenu-content { max-width: var(--grid-desktop-container-width); } + + .blog-template .default-content-wrapper { + max-width: 60%; + height: 50%; + } } [class$="-"], @@ -1801,6 +1810,10 @@ body.guides-template .guides-back-btn span.icon { body.guides-template main.without-full-width-hero .doc-detail-hero-image { border-radius: var(--image-border-radius-xxl); } + + body.blog-template img { + max-width: 90%; + } } @media screen and (min-width: 900px) { @@ -1878,6 +1891,10 @@ body.guides-template .guides-back-btn .icon-icon-arrow { brightness(94%) contrast(92%); } +body.blog-template aside { + display: none; +} + /* bumper template */ body.bumper-template { text-align: center;