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

Career testimonials: create testimonials carousel block #71

Merged
merged 10 commits into from
Sep 29, 2023
148 changes: 148 additions & 0 deletions blocks/career-carousel/career-carousel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
.career-carousel {
--card-width: 16rem;
}

.career-slider {
display: flex;
flex-direction: column;
margin-left: -1rem;
width: calc((var(--card-width) + 3rem) * 4);
overflow: hidden;
}

.career-slides {
display: flex;
overflow-x: scroll;
scroll-behavior: smooth;

/* We want to hide the scroll bar */
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* for Firefox */
}

/* Hide the scroll bar */
.career-slides::-webkit-scrollbar {
/* for Chrome, Safari and Opera */
display: none;
}

.career-carousel .career-card {
flex-shrink: 0;
box-shadow: #3c465040 0 2px 12px 0;
margin: 0.5rem;
padding: 1rem;
width: var(--card-width);
transition: all 0.15s ease-in-out;
}

.career-carousel .career-card:hover {
box-shadow: #3c465066 0 4px 16px 0;
}

.career-carousel .career-card a {
display: inline-flex;
flex-direction: column;
text-decoration: none;
}

.career-carousel .career-card picture {
align-self: center;
width: 14.375rem;
margin: 0 0 1.375rem;
}

.career-carousel .career-card picture img {
height: 16rem;
width: 14.375rem;
}

.career-carousel .career-card blockquote {
color: var(--primary);
font-size: var(--body-font-size-l);
font-style: normal;
line-height: 29px;
margin: 0 0 19px;
max-height: 9.375rem;
overflow: hidden;
text-indent: 0;

/* Show ellipsis on multiline text */
display: -webkit-box;
-webkit-line-clamp: 5; /* number of lines to show */
-webkit-box-orient: vertical;
}

.career-carousel .career-card .career-card-bqc {
height: 9.375rem;
margin-bottom: 0.75rem;
}

.career-carousel .career-card h6 {
color: var(--light-black);
font-size: var( --heading-font-size-mxs);
text-transform: none;
margin-bottom: 6px;
}

.career-carousel .career-card p {
color: var(--light-black);
font-size: var(--body-font-size-s);
height: 2.5rem;
line-height: 21.6px;
margin-bottom: 0.75rem;
overflow: hidden;
text-overflow: ellipsis;
}

.career-carousel .career-card button {
background-color: unset;
color: var(--secondary);
font-family: var(--body-font-family);
font-size: var(--body-font-size-m);
font-weight: var(--font-weight-medium);
justify-content: left;
height: auto;
padding: 0;
margin-block: 1rem;
}

.career-carousel .career-card button:hover {
text-decoration: underline;
}

.career-carousel .career-card button .icon-angle-right-blue {
height: 14px;
width: 10px;
margin-left: 6px;
margin-top: 2px;
}

.career-carousel .career-slides-navbar {
display: flex;
}

.career-carousel .career-slides-nav {
display: inline-flex;
align-items: center;
margin-top: 3.125rem;
margin-bottom: 2.5rem;
margin-inline: auto;
}

.career-carousel .career-slides-nav span {
width: 6px;
height: 6px;
margin: 0 3px;
border-radius: 50%;
background: #0003;
}

.career-carousel .career-slides-nav span.active-nav {
background: var(--link-color);
}

.career-carousel .career-slides-nav .btn-angle {
height: 1.5rem;
width: 1rem;
margin-inline: 0.5rem;
}
144 changes: 144 additions & 0 deletions blocks/career-carousel/career-carousel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { createOptimizedPicture } from '../../scripts/lib-franklin.js';
import { fetchIndex } from '../../scripts/scripts.js';

export function filterIncompleteEntries(json) {
return json.data.filter((e) => e.image !== '' && e['career-quote'] !== '0' && e['career-jobtitle'] !== '0');
jindaliiita marked this conversation as resolved.
Show resolved Hide resolved
}

export function scrollToCard(idx, card, precedingCard, slides, span, doc) {
const rect = card.getBoundingClientRect();

// set the style on the active button
const buttons = doc.querySelectorAll('.career-slides-nav span.active-nav');
buttons.forEach((b) => b.classList.remove('active-nav'));
span.classList.add('active-nav');

// Compute the gap to add to the location
let gap = 0;
if (precedingCard) {
const prevRect = precedingCard.getBoundingClientRect();
gap = rect.x - (prevRect.x + prevRect.width);
}

slides.scrollTo(idx * (rect.width + gap), slides.scrollHeight);
}

export function scrollToAdjacent(spans, slideDivs, slides, next, doc) {
const curActive = spans.findIndex((s) => s.classList.contains('active-nav'));
if (curActive === -1) {
return;
}

// compute the next active element, wrapping around on over- or underflow.
const newActive = (curActive + (next ? 1 : -1) + spans.length) % spans.length;
if (slideDivs.length <= newActive) {
return;
}

scrollToCard(
newActive,
slideDivs[newActive],
newActive > 0 ? slideDivs[newActive - 1] : null,
slides,
spans[newActive],
doc,
);
}

export default async function decorate(block) {
const json = await fetchIndex('query-index', 'career-testimonials');
const data = filterIncompleteEntries(json);

const careerSlider = document.createElement('div');
careerSlider.classList.add('career-slider');

const careerSlides = document.createElement('div');
careerSlides.classList.add('career-slides');

const slideDivs = [];
for (let i = 0; i < data.length; i += 1) {
const div = document.createElement('div');
div.classList.add('career-card');
const a = document.createElement('a');
a.href = data[i].path;
const pic = createOptimizedPicture(data[i].image, data[i].pagename);
a.append(pic);

const bqc = document.createElement('div');
bqc.classList.add('career-card-bqc');
const bq = document.createElement('blockquote');
bq.textContent = data[i]['career-quote'];
bqc.append(bq);
a.append(bqc);

const nm = document.createElement('h6');
nm.textContent = data[i].pagename;
a.append(nm);

const role = document.createElement('p');
role.textContent = data[i]['career-jobtitle'];
a.append(role);

const link = document.createElement('button');
link.textContent = 'Read More '; // TODO
jindaliiita marked this conversation as resolved.
Show resolved Hide resolved
const arrow = document.createElement('img');
arrow.src = '/icons/angle-right-blue.svg';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why its needed here, can it be in css

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it can be but then it has to be changed to a background image, these arrows arent really background images...

arrow.alt = 'Go to testimonial';
jindaliiita marked this conversation as resolved.
Show resolved Hide resolved
arrow.classList.add('icon-angle-right-blue');
link.append(arrow);
a.append(link);
div.append(a);

careerSlides.append(div);
slideDivs.push(div);
}
careerSlider.append(careerSlides);

const navBar = document.createElement('div');
navBar.classList.add('career-slides-navbar');
const navButtons = document.createElement('div');
navButtons.classList.add('career-slides-nav');

const buttons = [];
for (let i = 0; i < data.length; i += 1) {
const prevDiv = i > 0 ? slideDivs[i - 1] : null;

const s = document.createElement('span');
s.classList.toggle('active-nav', i === 0);
s.tabIndex = '-1';
s.onclick = () => scrollToCard(i, slideDivs[i], prevDiv, careerSlides, s, document);
navButtons.append(s);

buttons.push(s);
}
const la = document.createElement('img');
la.src = '/icons/angle-left-blue.svg';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be in css

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it can be but then it has to be changed to a background image, these arrows aren't really background images... AFAIK there is no portable way to set the img src tag in CSS yet.

la.alt = 'Previous person card';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Should this be localized?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we need i18n. I will create an issue to track.

la.classList.add('btn-angle');
la.onclick = () => scrollToAdjacent(buttons, slideDivs, careerSlides, false, document);
navButtons.prepend(la);

const ra = document.createElement('img');
ra.src = '/icons/angle-right-blue.svg';
ra.alt = 'Next person card';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Should this be localized?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we need i18n. I will create an issue to track.

ra.classList.add('btn-angle');
ra.onclick = () => scrollToAdjacent(buttons, slideDivs, careerSlides, true, document);
navButtons.append(ra);
navBar.append(navButtons);

block.append(careerSlider);
block.append(navBar);

document.onkeydown = (e) => {
switch (e.keyCode) {
case 37:
la.onclick();
break;
case 39:
ra.onclick();
break;
default:
// do nothing
}
};
}
1 change: 1 addition & 0 deletions icons/angle-left-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion icons/angle-right-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions test/blocks/career-carousel/career-carousel.plain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div>
<div class="breadcrumb"></div>
</div>
<div>
<div class="career-carousel"></div>
</div>
Loading