11{% capture speakers_content %}
2- < div class ="grid sm:grid-cols-2 lg:grid-cols-3 gap-8 ">
3- {% for speaker in site.data.speakers %}
4- < div class ="my-card rounded-lg overflow-hidden shadow-md transition duration-300 ">
5- < div class ="relative " data-aos ="fade-zoom ">
6- < img src ="{{ speaker.avatar | relative_url }} " alt ="{{ speaker.full_name }} "
7- class ="w-full h-64 object-cover ">
8- < div class ="absolute inset-0 bg-gradient-to-t from-black to-transparent opacity-70 "> </ div >
9- < div class ="absolute bottom-4 left-4 ">
10- < h3 class ="text-white text-2xl font-bold "> {{ speaker.full_name }}</ h3 >
11- < p class ="text-red-200 "> {{ speaker.role }}</ p >
12- </ div >
13- </ div >
14- < div class ="p-6 " data-aos ="fade-zoom ">
15- < div class ="text-gray-600 mb-4 "> {{ speaker.description | markdownify }}</ div >
16- < div class ="flex space-x-2 ">
17- {% for label in speaker.labels %}
18- < span class ="bg-red-100 text-red-800 text-xs px-3 py-1 rounded-full "> {{ label }}</ span >
19- {% endfor %}
2+ < div id ="speakers-wrapper " class ="overflow-hidden relative ">
3+ < div class ="flex speakers-track ">
4+ {% for speaker in site.data.speakers %}
5+ < div class ="my-card mx-3 rounded-lg overflow-hidden shadow-md transition duration-300 ">
6+ < div class ="relative ">
7+ < img src ="{{ speaker.avatar | relative_url }} " alt ="{{ speaker.full_name }} " class ="w-full h-64 object-cover ">
8+ < div class ="absolute inset-0 bg-gradient-to-t from-black to-transparent opacity-70 "> </ div >
9+ < div class ="absolute bottom-4 left-4 ">
10+ < h3 class ="text-white text-2xl font-bold "> {{ speaker.full_name }}</ h3 >
11+ < p class ="text-red-200 "> {{ speaker.role }}</ p >
12+ </ div >
13+ </ div >
14+ < div class ="p-6 ">
15+ < div class ="text-gray-600 mb-4 "> {{ speaker.description | markdownify }}</ div >
16+ < div class ="flex space-x-2 ">
17+ {% for label in speaker.labels %}
18+ < span class ="bg-red-100 text-red-800 text-xs px-3 py-1 rounded-full "> {{ label }}</ span >
19+ {% endfor %}
20+ </ div >
21+ </ div >
2022 </ div >
23+ {% endfor %}
2124 </ div >
2225 </ div >
23- {% endfor %}
2426</ div>
2527{% endcapture %}
2628
2729{% include section.html
28- id="speakers"
29- title="II. Featured speakers"
30- description="We are humbled by the huge response to our CFP: over 40 submissions! We are currently evaluating them and
31- will announce the speakers soon."
32- content=speakers_content
33- %}
30+ id="speakers"
31+ title="II. Featured speakers"
32+ description="We are humbled by the huge response to our CFP: over 40 submissions! We are currently evaluating them and
33+ will announce the speakers soon."
34+ content=speakers_content
35+ %}
36+
37+ < script >
38+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
39+ gsap . registerPlugin ( Draggable ) ;
40+
41+ const track = document . querySelector ( '.speakers-track' ) ;
42+ track . innerHTML += track . innerHTML ; //temporary cause few speakers
43+
44+ const contentWidth = track . scrollWidth / 2 ;
45+
46+ let x = 0 ;
47+ const speed = 0.8 ;
48+ let isPaused = false ;
49+
50+ function animate ( ) {
51+ if ( ! isPaused ) {
52+ x -= speed ;
53+ }
54+
55+ // wrap infinito
56+ if ( x <= - contentWidth ) x += contentWidth ;
57+ if ( x >= 0 ) x -= contentWidth ;
58+
59+ gsap . set ( track , { x } ) ;
60+
61+ requestAnimationFrame ( animate ) ;
62+ }
63+
64+ animate ( ) ;
65+
66+ // DRAG (mouse + touch)
67+ Draggable . create ( track , {
68+ type : "x" ,
69+ allowNativeTouchScrolling : false ,
70+
71+ onPress ( ) {
72+ isPaused = true ;
73+ } ,
74+
75+ onDrag ( ) {
76+ x += this . deltaX ;
77+ } ,
78+
79+ onRelease ( ) {
80+ isPaused = false ;
81+ }
82+ } ) ;
83+
84+ // DESKTOP hover
85+ track . addEventListener ( "pointerenter" , ( ) => isPaused = true ) ;
86+ track . addEventListener ( "pointerleave" , ( ) => isPaused = false ) ;
87+ } )
88+ </ script >
89+
0 commit comments