From eb0d7a3b78735cd63d95ad54b698212b4a31fdf3 Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 17 Apr 2025 14:41:50 +0200 Subject: [PATCH 01/11] Update speakers page look. --- src/pages/speakers.astro | 173 ++++++++++++++++++++++++--------------- 1 file changed, 108 insertions(+), 65 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index f72dc19e6..9a56a6ad4 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -1,42 +1,66 @@ --- -import { getCollection } from "astro:content"; +import { getCollection, type CollectionEntry } from "astro:content"; import Layout from "../layouts/Layout.astro"; import Prose from "../components/prose/prose.astro"; import { Separator } from "../components/separator/separator"; +import { Image } from "astro:assets"; + +type Speaker = CollectionEntry<"speakers">; -// Fetch all speaker entries const speakersCollection = await getCollection("speakers"); -// Define the type for the groups object -type Speaker = { - id: string; - data: { - name: string; - }; -}; - -type Groups = { - [key: string]: Speaker[]; -}; - -// Group speakers by the first letter of their name -const groups: Groups = speakersCollection - .filter((speaker: Speaker) => !!speaker.data.name) - .reduce((acc: Groups, speaker: Speaker) => { - const letter = speaker.data.name[0].toUpperCase(); - if (!acc[letter]) { - acc[letter] = []; +const speakersWithNames = speakersCollection.filter((speaker) => + !!speaker.data?.name +); + +const getFirstLetter = (name: string): string => name.charAt(0).toUpperCase(); + +function createOptimalGroups(speakers: Speaker[]): Record { + const sortedSpeakers = [...speakers].sort((a, b) => + a.data.name.localeCompare(b.data.name) + ); + + const groups: Record = {}; + let currentGroup: Speaker[] = []; + let currentLetter = ''; + let groupKey = ''; + + sortedSpeakers.forEach((speaker) => { + const letter = getFirstLetter(speaker.data.name); + + if (currentGroup.length === 0) { + currentLetter = letter; + groupKey = letter; + currentGroup.push(speaker); + } + else if (letter === currentLetter && currentGroup.length < 15) { + currentGroup.push(speaker); } - acc[letter].push(speaker); - return acc; - }, {} as Groups); + else { + if (currentGroup.length < 10 && currentGroup.length + 1 <= 15) { + currentGroup.push(speaker); + groupKey = `${currentLetter}-${letter}`; + } else { + groups[groupKey] = currentGroup; + currentLetter = letter; + groupKey = letter; + currentGroup = [speaker]; + } + } + }); -const letters = Object.keys(groups).sort((a, b) => a.localeCompare(b)); + if (currentGroup.length > 0) { + groups[groupKey] = currentGroup; + } -const title = "Speakers"; + return groups; +} -const description = - "Alphabetical list of all confirmed speakers for the conference"; +const speakerGroups = createOptimalGroups(speakersWithNames); +const groupKeys = Object.keys(speakerGroups); + +const title = "Speakers"; +const description = "Our conference speakers organized alphabetically"; --- @@ -45,49 +69,68 @@ const description =

Speakers

-
+
{ - letters.map((letter) => ( -

- {letter} -

+ groupKeys.map((key) => ( + + {key} + )) }
-
    - { - letters.map((letter, index) => ( - <> -
    -

    - {letter} -

    - -
      - {groups[letter] - .sort((a, b) => a.data.name.localeCompare(b.data.name)) - .map((speaker) => ( -
    • - - {speaker.data.name} - -
    • - ))} -
    + { + groupKeys.map((key, index) => ( + <> + - {index !== letters.length - 1 ? ( - - ) : ( -
    - )} - - )) - } -
+ {index !== groupKeys.length - 1 && } + + )) + }
+ + From 8f76e48c4d7459b00cbcc88f3aafadc37c106186 Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 17 Apr 2025 14:47:13 +0200 Subject: [PATCH 02/11] Update avatar. --- src/pages/speakers.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index 9a56a6ad4..86ad33e59 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -100,8 +100,8 @@ const description = "Our conference speakers organized alphabetically"; {`${speaker.data.name}'s ) : ( From 7727c6ef54739a509239e68fd51cd6249e3b08c2 Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 17 Apr 2025 14:48:38 +0200 Subject: [PATCH 03/11] Update imports. --- src/pages/speakers.astro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index 86ad33e59..e05d1319e 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -1,8 +1,8 @@ --- import { getCollection, type CollectionEntry } from "astro:content"; -import Layout from "../layouts/Layout.astro"; -import Prose from "../components/prose/prose.astro"; -import { Separator } from "../components/separator/separator"; +import Layout from "@layouts/Layout.astro"; +import Prose from "@components/prose/prose.astro"; +import { Separator } from "@components/separator/separator"; import { Image } from "astro:assets"; type Speaker = CollectionEntry<"speakers">; From 52cdb9b1acb02486033096b09e87df2226ef5818 Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 17 Apr 2025 15:12:18 +0200 Subject: [PATCH 04/11] Example home page section with random speakers. --- src/components/sections/speakers.astro | 160 +++++++++++++++++++++++++ src/pages/index.astro | 2 + 2 files changed, 162 insertions(+) create mode 100644 src/components/sections/speakers.astro diff --git a/src/components/sections/speakers.astro b/src/components/sections/speakers.astro new file mode 100644 index 000000000..4c9a45d03 --- /dev/null +++ b/src/components/sections/speakers.astro @@ -0,0 +1,160 @@ +--- +import { getCollection } from "astro:content"; +import type { CollectionEntry } from "astro:content"; + +const allSpeakers = await getCollection("speakers"); + +const validSpeakers = allSpeakers.filter(speaker => + !!speaker.data?.name && !!speaker.data?.avatar +); + +function getRandomSpeakers(speakers: CollectionEntry<"speakers">[], count: number) { + const shuffled = [...speakers].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, Math.min(count, speakers.length)); +} + +const featuredSpeakers = getRandomSpeakers(validSpeakers, 15); + +const sectionTitle = "Featured Speakers"; +const sectionSubtitle = "Meet some of our amazing speakers"; +--- + +
+
+
+

{sectionTitle}

+

{sectionSubtitle}

+
+ + + + +
+
+ + + + diff --git a/src/pages/index.astro b/src/pages/index.astro index c1c8b74b3..dc881ad84 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -8,6 +8,7 @@ import Updates from "@sections/updates.astro"; import Prague from "@sections/prague.astro"; import Sponsors from "@components/sponsors/sponsors.astro"; import Subscribe from "@sections/subscribe.astro"; +import Speakers from "@sections/speakers.astro"; let deadlines = await getCollection("deadlines"); deadlines = deadlines @@ -23,6 +24,7 @@ deadlines = deadlines + From 0f11c61796f3384bd56fab8fa188da4fa1ee759f Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 17 Apr 2025 15:35:17 +0200 Subject: [PATCH 05/11] Update spekers style. --- src/components/sections/speakers.astro | 11 +++++++---- src/pages/speakers.astro | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/sections/speakers.astro b/src/components/sections/speakers.astro index 4c9a45d03..de1873899 100644 --- a/src/components/sections/speakers.astro +++ b/src/components/sections/speakers.astro @@ -1,6 +1,7 @@ --- import { getCollection } from "astro:content"; import type { CollectionEntry } from "astro:content"; +import { Image } from "astro:assets"; const allSpeakers = await getCollection("speakers"); @@ -33,10 +34,12 @@ const sectionSubtitle = "Meet some of our amazing speakers";
- {`${speaker.data.name}'s
@@ -88,7 +91,7 @@ const sectionSubtitle = "Meet some of our amazing speakers"; function moveCarousel() { currentPosition += slideWidth; - track.style.transition = 'transform 2000ms linear'; + track.style.transition = 'transform 1000ms linear'; track.style.transform = `translateX(-${currentPosition}%)`; if (currentPosition >= slideWidth * totalOriginalSlides) { @@ -98,9 +101,9 @@ const sectionSubtitle = "Meet some of our amazing speakers"; track.style.transform = `translateX(0)`; setTimeout(() => { - track.style.transition = 'transform 2000ms linear'; + track.style.transition = 'transform 1000ms linear'; }, 20); - }, 1000); + }, 4000); } } diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index e05d1319e..5d7d116c0 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -37,7 +37,7 @@ function createOptimalGroups(speakers: Speaker[]): Record { currentGroup.push(speaker); } else { - if (currentGroup.length < 10 && currentGroup.length + 1 <= 15) { + if (currentGroup.length < 1 && currentGroup.length + 1 <= 15) { currentGroup.push(speaker); groupKey = `${currentLetter}-${letter}`; } else { @@ -100,8 +100,8 @@ const description = "Our conference speakers organized alphabetically"; {`${speaker.data.name}'s ) : ( From 68fabc7072f0413593b996783fc922e18a03800b Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 19 Apr 2025 21:45:35 +0200 Subject: [PATCH 06/11] Update speakers. --- src/pages/speakers.astro | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index 5d7d116c0..5daf3a671 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -2,7 +2,6 @@ import { getCollection, type CollectionEntry } from "astro:content"; import Layout from "@layouts/Layout.astro"; import Prose from "@components/prose/prose.astro"; -import { Separator } from "@components/separator/separator"; import { Image } from "astro:assets"; type Speaker = CollectionEntry<"speakers">; @@ -37,7 +36,7 @@ function createOptimalGroups(speakers: Speaker[]): Record { currentGroup.push(speaker); } else { - if (currentGroup.length < 1 && currentGroup.length + 1 <= 15) { + if (currentGroup.length < 10 && currentGroup.length + 1 <= 15) { currentGroup.push(speaker); groupKey = `${currentLetter}-${letter}`; } else { @@ -69,32 +68,17 @@ const description = "Our conference speakers organized alphabetically";

Speakers

-
- { groupKeys.map((key, index) => ( <>
-

{key}

-
{speakerGroups[key].map((speaker) => ( -
+
{speaker.data.avatar ? (
- {index !== groupKeys.length - 1 && } )) } From 3645fb4b823eed7a4f5d115a7de1ada90e625531 Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 19 Apr 2025 21:51:42 +0200 Subject: [PATCH 07/11] Add image borders. --- src/pages/speakers.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index 5daf3a671..3185b545d 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -78,7 +78,7 @@ const description = "Our conference speakers organized alphabetically"; href={`/speaker/${speaker.id}`} class="flex flex-col items-center group" > -
+
{speaker.data.avatar ? ( {`${speaker.data.name}'s ) : (
From a4972c6e2370494b1c4b2adc724019146e6a2a0b Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 19 Apr 2025 23:31:42 +0200 Subject: [PATCH 08/11] Clean up html structure. --- src/pages/speakers.astro | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/speakers.astro b/src/pages/speakers.astro index 3185b545d..d6e419208 100644 --- a/src/pages/speakers.astro +++ b/src/pages/speakers.astro @@ -78,7 +78,6 @@ const description = "Our conference speakers organized alphabetically"; href={`/speaker/${speaker.id}`} class="flex flex-col items-center group" > -
{speaker.data.avatar ? ( {`${speaker.data.name}'s ) : ( -
+
{speaker.data.name.charAt(0)}
)} -

{speaker.data.name}

From 960ac6de3d56c35d3897f3395e4d14dd704a5a7e Mon Sep 17 00:00:00 2001 From: Niko Date: Wed, 23 Apr 2025 16:37:48 +0200 Subject: [PATCH 09/11] Update mobile view. --- src/components/sections/speakers.astro | 119 ++++++++++++++++++++----- 1 file changed, 95 insertions(+), 24 deletions(-) diff --git a/src/components/sections/speakers.astro b/src/components/sections/speakers.astro index de1873899..a4b580bd8 100644 --- a/src/components/sections/speakers.astro +++ b/src/components/sections/speakers.astro @@ -18,6 +18,15 @@ const featuredSpeakers = getRandomSpeakers(validSpeakers, 15); const sectionTitle = "Featured Speakers"; const sectionSubtitle = "Meet some of our amazing speakers"; + +// Helper function to truncate names if needed +function formatSpeakerName(name: string) { + // Option: You could truncate very long names + // if (name.length > 20) { + // return name.substring(0, 18) + '...'; + // } + return name; +} ---
@@ -43,10 +52,18 @@ const sectionSubtitle = "Meet some of our amazing speakers"; loading="eager" />
-
-

- {speaker.data.name} +
+ +

+ {formatSpeakerName(speaker.data.name)}

+ + + {speaker.data.title && ( +

+ {speaker.data.title} +

+ )}

@@ -70,23 +87,44 @@ const sectionSubtitle = "Meet some of our amazing speakers"; document.addEventListener('DOMContentLoaded', () => { const track = document.querySelector('.speakers-track') as HTMLElement; const slides = document.querySelectorAll('.speaker-slide'); + const totalOriginalSlides = slides.length / 2; if (!track || slides.length === 0) return; - const slideWidth = 100 / 5; - const totalOriginalSlides = slides.length / 2; let currentPosition = 0; const scrollSpeed = 4000; + let slidingInterval: ReturnType | null = null; + + // Function to determine slides per view based on window width + function getSlidesPerView() { + const width = window.innerWidth; + if (width <= 480) return 1; + if (width <= 640) return 2; + if (width <= 768) return 3; + if (width <= 1024) return 4; + return 5; + } - slides.forEach((slide) => { - (slide as HTMLElement).style.flexBasis = `${slideWidth}%`; - }); + function updateCarouselSettings() { + const slidesPerView = getSlidesPerView(); + const slideWidth = 100 / slidesPerView; - startAnimation(); + // Reset position when breakpoint changes + currentPosition = 0; + track.style.transition = 'none'; + track.style.transform = `translateX(0)`; - function startAnimation() { + // Clear and restart animation + if (slidingInterval !== null) { + clearInterval(slidingInterval); + } + startAnimation(slideWidth); + } + + function startAnimation(slideWidth: number) { + // Initial setup moveCarousel(); - let slidingInterval = setInterval(moveCarousel, scrollSpeed); + slidingInterval = setInterval(moveCarousel, scrollSpeed); function moveCarousel() { currentPosition += slideWidth; @@ -94,6 +132,7 @@ const sectionSubtitle = "Meet some of our amazing speakers"; track.style.transition = 'transform 1000ms linear'; track.style.transform = `translateX(-${currentPosition}%)`; + // Reset when we've scrolled through the original set of slides if (currentPosition >= slideWidth * totalOriginalSlides) { setTimeout(() => { track.style.transition = 'none'; @@ -103,27 +142,43 @@ const sectionSubtitle = "Meet some of our amazing speakers"; setTimeout(() => { track.style.transition = 'transform 1000ms linear'; }, 20); - }, 4000); + }, 1000); } } + } + + // Start the carousel + updateCarouselSettings(); - const carouselContainer = document.querySelector('.speakers-carousel-container'); - carouselContainer?.addEventListener('mouseenter', () => { + // Update on window resize + window.addEventListener('resize', () => { + updateCarouselSettings(); + }); + + // Pause on hover + const carouselContainer = document.querySelector('.speakers-carousel-container'); + carouselContainer?.addEventListener('mouseenter', () => { + if (slidingInterval !== null) { clearInterval(slidingInterval); - }); + slidingInterval = null; + } + }); - carouselContainer?.addEventListener('mouseleave', () => { - slidingInterval = setInterval(moveCarousel, scrollSpeed); - }); + carouselContainer?.addEventListener('mouseleave', () => { + updateCarouselSettings(); + }); - document.addEventListener('visibilitychange', () => { - if (document.hidden) { + // Pause when tab is not visible + document.addEventListener('visibilitychange', () => { + if (document.hidden) { + if (slidingInterval !== null) { clearInterval(slidingInterval); - } else { - slidingInterval = setInterval(moveCarousel, scrollSpeed); + slidingInterval = null; } - }); - } + } else { + updateCarouselSettings(); + } + }); }); @@ -137,6 +192,22 @@ const sectionSubtitle = "Meet some of our amazing speakers"; will-change: transform; } + /* Line clamping for text overflow */ + .line-clamp-1 { + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + overflow: hidden; + } + + .line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + } + + /* These styles match the responsive classes used in the HTML */ @media (max-width: 1024px) { .speaker-slide { width: 25%; From 56387299e4b0742e5863aa9493cb21eeabd54d4f Mon Sep 17 00:00:00 2001 From: Niko Date: Wed, 23 Apr 2025 16:44:32 +0200 Subject: [PATCH 10/11] Update mobile view. --- src/components/sections/speakers.astro | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/components/sections/speakers.astro b/src/components/sections/speakers.astro index a4b580bd8..718db0441 100644 --- a/src/components/sections/speakers.astro +++ b/src/components/sections/speakers.astro @@ -19,14 +19,6 @@ const featuredSpeakers = getRandomSpeakers(validSpeakers, 15); const sectionTitle = "Featured Speakers"; const sectionSubtitle = "Meet some of our amazing speakers"; -// Helper function to truncate names if needed -function formatSpeakerName(name: string) { - // Option: You could truncate very long names - // if (name.length > 20) { - // return name.substring(0, 18) + '...'; - // } - return name; -} ---
@@ -55,15 +47,8 @@ function formatSpeakerName(name: string) {

- {formatSpeakerName(speaker.data.name)} + {speaker.data.name}

- - - {speaker.data.title && ( -

- {speaker.data.title} -

- )}
From a5fa458e34a752204e01b206d3f5b6f1736a225e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mia=20Baji=C4=87?= <38294198+clytaemnestra@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:59:03 +0200 Subject: [PATCH 11/11] Update src/components/sections/speakers.astro --- src/components/sections/speakers.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sections/speakers.astro b/src/components/sections/speakers.astro index 718db0441..5903ce5b4 100644 --- a/src/components/sections/speakers.astro +++ b/src/components/sections/speakers.astro @@ -62,7 +62,7 @@ const sectionSubtitle = "Meet some of our amazing speakers"; href="/speakers" class="inline-block px-6 py-3 bg-primary hover:bg-primary-dark text-white font-medium rounded-md transition-colors" > - View All Speakers + See all speakers