Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions blocks/resource-showcase/resource-showcase.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
.resource-showcase {
--resource-showcase-radius: 16px;
--resource-showcase-max-width: 1200px;

position: relative;
padding: var(--spacing-xl) var(--spacing-xs);
background-image:
radial-gradient(circle at 0% 0%, rgb(216 130 80 / 45%), transparent 45%),
linear-gradient(135deg, #6b5a4e 0%, #4a4846 30%, #33343a 60%, #1c1d22 100%);
overflow: hidden;
}

.resource-showcase .resource-showcase-heading {
max-width: var(--resource-showcase-max-width);
margin: 0 auto var(--spacing-m);
color: var(--color-white);
font-size: 32px;
line-height: 32px;
letter-spacing: -0.96px;
font-weight: 900;
}

.resource-showcase .resource-showcase-content {
display: grid;
max-width: var(--resource-showcase-max-width);
margin: 0 auto;
grid-template-columns: 1fr;
gap: var(--spacing-l);
}

/* CTA link, shared by featured card and secondary items */
.resource-showcase .resource-showcase-cta {
display: inline-flex;
align-items: center;
gap: var(--spacing-xxs);
font-size: 14px;
font-weight: 700;
line-height: 18px;
letter-spacing: 0;
text-align: center;
text-decoration: none;
}

.resource-showcase .resource-showcase-cta:hover {
text-decoration: underline;
}

.resource-showcase .resource-showcase-cta:focus-visible {
outline: 2px solid var(--color-accent-focus-ring);
outline-offset: 2px;
}

.resource-showcase .resource-showcase-chevron {
flex-shrink: 0;
}

/* Featured card */
.resource-showcase .resource-showcase-featured {
display: flex;
flex-direction: column;
border-radius: var(--resource-showcase-radius);
overflow: hidden;
background-color: var(--color-white);
color: inherit;
text-decoration: none;
}

.resource-showcase .resource-showcase-featured:focus-visible {
outline: 2px solid var(--color-accent-focus-ring);
outline-offset: 2px;
}

.resource-showcase .resource-showcase-featured-image {
width: 100%;
aspect-ratio: 16 / 9;
background-color: var(--color-gray-300);
border-radius: 16px;
overflow: hidden;
}

.resource-showcase .resource-showcase-featured-image picture,
.resource-showcase .resource-showcase-featured-image img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

.resource-showcase .resource-showcase-featured-image img {
transition: transform 0.3s ease;
}

.resource-showcase .resource-showcase-featured:hover .resource-showcase-featured-image img,
.resource-showcase .resource-showcase-featured:focus-visible .resource-showcase-featured-image img {
transform: scale(1.2);
}

@media (prefers-reduced-motion: reduce) {
.resource-showcase .resource-showcase-featured-image img {
transition: none;
}
}

.resource-showcase .resource-showcase-featured-body {
display: flex;
flex-direction: column;
gap: var(--spacing-xxs);
padding: var(--spacing-s);
}

.resource-showcase .resource-showcase-featured-title {
margin: 0;
color: var(--color-black);
font-size: 24px;
line-height: 24px;
letter-spacing: -0.2px;
font-weight: 900;
}

.resource-showcase .resource-showcase-featured-description {
margin: 0;
color: rgb(0 0 0 / 60%);
font-family: var(--body-font-family);
font-size: 16px;
font-weight: 400;
line-height: 20.8px;
letter-spacing: 0.16px;
}

.resource-showcase .resource-showcase-featured .resource-showcase-cta {
color: var(--color-black);
}

/* Secondary list */
.resource-showcase .resource-showcase-list {
display: flex;
flex-direction: column;
gap: var(--spacing-m);
margin: 0;
padding: 0;
min-width: 0;
list-style: none;
}

.resource-showcase .resource-showcase-item-body {
display: flex;
flex-direction: column;
}

.resource-showcase .resource-showcase-item-title {
margin: 0 0 var(--spacing-xxs);
color: var(--color-white);
font-size: 24px;
line-height: 24px;
letter-spacing: -0.48px;
font-weight: 900;
}

.resource-showcase .resource-showcase-item-description {
margin: 0 0 var(--spacing-s);
color: var(--color-white);
font-family: var(--body-font-family);
font-size: 16px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0;
}

.resource-showcase .resource-showcase-item .resource-showcase-cta {
color: var(--color-white);
}

@media (min-width: 769px) {
.resource-showcase .resource-showcase-content {
grid-template-columns: 1fr 1fr;
align-items: start;
}

.resource-showcase .resource-showcase-heading {
font-size: 48px;
line-height: 48px;
letter-spacing: -1.44px;
}

.resource-showcase .resource-showcase-item-title {
font-size: 20px;
line-height: 20px;
}

.resource-showcase .resource-showcase-item-description {
font-size: 14px;
line-height: 18px;
}
}

@media (min-width: 1280px) {
.resource-showcase {
padding: var(--spacing-xxl) var(--spacing-m);
}

.resource-showcase .resource-showcase-heading {
font-size: 56px;
line-height: 56px;
letter-spacing: -1.68px;
}

.resource-showcase .resource-showcase-item-title {
font-size: 24px;
line-height: 24px;
}

.resource-showcase .resource-showcase-item-description {
font-size: 16px;
line-height: 20px;
}

.resource-showcase .resource-showcase-content {
grid-template-columns: 635px 1fr;
}
}
119 changes: 119 additions & 0 deletions blocks/resource-showcase/resource-showcase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { LIBS } from '../../scripts/scripts.js';

const LANA_OPTIONS = { tags: 'resource-showcase', errorType: 'i' };

const CHEVRON_ICON = `<svg class="resource-showcase-chevron" xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true" focusable="false">
<path d="M2.5 1L7.5 5L2.5 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`;

function decorateCTA(link) {
if (!link) return null;
link.classList.add('resource-showcase-cta');
link.insertAdjacentHTML('beforeend', CHEVRON_ICON);
return link;
}

function buildItemBody(contentCell, ctaCell, { headingClass, descriptionClass }) {
const heading = contentCell?.querySelector('h1, h2, h3, h4, h5, h6');
const paragraphs = [...contentCell?.querySelectorAll('p') ?? []]
.filter((p) => p.textContent.trim());

const title = document.createElement('h3');
title.className = headingClass;
title.innerHTML = heading ? heading.innerHTML : '';

const body = document.createElement('div');
body.append(title);

paragraphs.forEach((p) => {
p.className = descriptionClass;
body.append(p);
});

const cta = decorateCTA(ctaCell?.querySelector('a'));
if (cta) body.append(cta);

return body;
}

function buildFeatured(row) {
const [contentCell, ctaCell] = row.querySelectorAll(':scope > div');
const picture = contentCell?.querySelector('picture');

const image = document.createElement('div');
image.className = 'resource-showcase-featured-image';
if (picture) image.append(picture);

const body = buildItemBody(contentCell, ctaCell, {
headingClass: 'resource-showcase-featured-title',
descriptionClass: 'resource-showcase-featured-description',
});
body.className = 'resource-showcase-featured-body';

const link = body.querySelector('a.resource-showcase-cta');
const href = link?.getAttribute('href');

const featured = document.createElement(href ? 'a' : 'div');
featured.className = 'resource-showcase-featured';
if (href) {
Comment thread
jsandland marked this conversation as resolved.
featured.href = href;
const label = document.createElement('span');
label.className = link.className;
label.innerHTML = link.innerHTML;
link.replaceWith(label);

const title = body.querySelector('.resource-showcase-featured-title');
featured.setAttribute('aria-label', title?.textContent.trim() ?? '');
image.setAttribute('aria-hidden', 'true');
body.setAttribute('aria-hidden', 'true');
}
featured.append(image, body);
return featured;
}

function buildSecondaryList(rows) {
const list = document.createElement('ul');
list.className = 'resource-showcase-list';

rows.forEach((row) => {
const [contentCell, ctaCell] = row.querySelectorAll(':scope > div');
const body = buildItemBody(contentCell, ctaCell, {
headingClass: 'resource-showcase-item-title',
descriptionClass: 'resource-showcase-item-description',
});
body.className = 'resource-showcase-item-body';

const item = document.createElement('li');
item.className = 'resource-showcase-item';
item.append(body);
list.append(item);
});

return list;
}

export default async function init(el) {
try {
const { decorateBlockAnalytics } = await import(`${LIBS}/martech/attributes.js`);
decorateBlockAnalytics(el);

const rows = [...el.querySelectorAll(':scope > div')];
const [headingRow, featuredRow, ...secondaryRows] = rows;
if (!headingRow || !featuredRow) return;

const headingSrc = headingRow.querySelector('h1, h2, h3, h4, h5, h6');
const heading = document.createElement('h2');
heading.className = 'resource-showcase-heading';
heading.innerHTML = headingSrc ? headingSrc.innerHTML : headingRow.innerHTML;

const content = document.createElement('div');
content.className = 'resource-showcase-content';
content.append(buildFeatured(featuredRow));
if (secondaryRows.length) content.append(buildSecondaryList(secondaryRows));

el.innerHTML = '';
el.append(heading, content);
} catch (err) {
window.lana?.log(`Resource Showcase: ${err}`, LANA_OPTIONS);
}
}
Loading
Loading