valley-commons/speakers.js

170 lines
5.5 KiB
JavaScript

// Dynamically load featured speakers
document.addEventListener('DOMContentLoaded', function() {
const speakersContainer = document.getElementById('speakers-container');
if (!speakersContainer) return;
// Define speakers based on folder structure
const speakers = [
{
name: 'Adam Arvidsson',
folder: 'Adam Arvidsson',
image: 'Arvidsson.png'
},
{
name: 'Charlie Fisher',
folder: 'Charlie Fisher',
image: 'charlie.jpeg'
},
{
name: 'Daniel Figueiredo',
folder: 'DANIEL RICHARD DE OLIVIERA FIGUEIREDO',
image: 'daniel.webp'
},
{
name: 'Emil Fritsch',
folder: 'Emil Fritsch',
image: 'emil.webp',
imagePosition: 'top'
},
{
name: 'Felix Fritsch',
folder: 'Felix Fritsch',
image: 'Fritsch.png'
},
{
name: 'Clara Gromaches',
folder: 'Clara Gromaches',
image: 'clara.jpg'
},
{
name: 'Koss',
folder: 'Koss',
image: 'koss.png'
},
{
name: 'Lorenzo Patuzzo',
folder: 'Lorenzo Patuzzo',
image: 'lorenzo.jpg'
},
{
name: 'Michel Bauwens',
folder: 'Michel Bauwens',
image: 'bauwens.jpeg'
},
{
name: 'Rashmi Abbigeri',
folder: 'Rashmi Abbigeri',
image: 'Abbigeri.png'
},
{
name: 'Una Wang',
folder: 'Una Wang',
image: 'una.jpg'
},
{
name: 'Veronica',
folder: 'Veronica',
image: 'veronica.png'
}
];
// Sort by last name; single-name entries go last, sorted by first name
const withLastName = speakers.filter((speaker) => speaker.name.trim().split(/\s+/).length > 1);
const withoutLastName = speakers.filter((speaker) => speaker.name.trim().split(/\s+/).length === 1);
withLastName.sort((a, b) => {
const aParts = a.name.trim().split(/\s+/);
const bParts = b.name.trim().split(/\s+/);
const aLast = aParts[aParts.length - 1];
const bLast = bParts[bParts.length - 1];
const lastCompare = aLast.localeCompare(bLast, 'en', { sensitivity: 'base' });
if (lastCompare !== 0) return lastCompare;
return a.name.localeCompare(b.name, 'en', { sensitivity: 'base' });
});
withoutLastName.sort((a, b) => {
const aFirst = a.name.trim().split(/\s+/)[0];
const bFirst = b.name.trim().split(/\s+/)[0];
return aFirst.localeCompare(bFirst, 'en', { sensitivity: 'base' });
});
const sortedSpeakers = [...withLastName, ...withoutLastName];
// Load each speaker
sortedSpeakers.forEach(speaker => {
loadSpeaker(speaker);
});
async function loadSpeaker(speaker) {
// Create speaker card
const speakerCard = document.createElement('div');
speakerCard.className = 'speaker-card';
// Create image
const img = document.createElement('img');
img.src = `speakers/${speaker.folder}/${speaker.image}`;
img.alt = speaker.name;
img.className = 'speaker-image';
img.loading = 'lazy';
if (speaker.imagePosition) {
img.style.objectPosition = speaker.imagePosition;
}
// Create name
const name = document.createElement('h3');
name.className = 'speaker-name';
name.textContent = speaker.name;
// Create bio (filled after fetch to preserve order)
const bio = document.createElement('p');
bio.className = 'speaker-bio';
// Create toggle text for mobile
const toggleText = document.createElement('span');
toggleText.className = 'speaker-toggle-text';
toggleText.textContent = 'click to read more';
// Create read more indicator for desktop
const readMoreDesktop = document.createElement('span');
readMoreDesktop.className = 'speaker-read-more-desktop';
readMoreDesktop.textContent = 'read more v';
// Assemble card
speakerCard.appendChild(img);
speakerCard.appendChild(name);
speakerCard.appendChild(readMoreDesktop);
speakerCard.appendChild(toggleText);
speakerCard.appendChild(bio);
// Add click handler for mobile
speakerCard.addEventListener('click', function(e) {
if (window.innerWidth < 769) {
e.preventDefault();
speakerCard.classList.toggle('expanded');
// Update toggle text
if (speakerCard.classList.contains('expanded')) {
toggleText.textContent = 'click to collapse';
} else {
toggleText.textContent = 'click to read more';
}
}
});
// Append immediately to preserve sorted order
speakersContainer.appendChild(speakerCard);
try {
// Fetch bio
const bioResponse = await fetch(`speakers/${speaker.folder}/bio.md`);
if (!bioResponse.ok) {
console.error(`Failed to load bio for ${speaker.name}`);
return;
}
const bioText = await bioResponse.text();
bio.textContent = bioText.trim();
} catch (error) {
console.error(`Error loading speaker ${speaker.name}:`, error);
}
}
});