306 lines
11 KiB
JavaScript
306 lines
11 KiB
JavaScript
'use client'
|
|
|
|
import { useEffect, useId, useState } from 'react'
|
|
import Image from 'next/image'
|
|
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
|
|
import clsx from 'clsx'
|
|
|
|
import { Container } from '@/components/Container'
|
|
import { DiamondIcon } from '@/components/DiamondIcon'
|
|
import andrewGreeneImage from '@/images/avatars/andrew-greene.jpg'
|
|
import cathleneBurrageImage from '@/images/avatars/cathlene-burrage.jpg'
|
|
import damarisKimuraImage from '@/images/avatars/damaris-kimura.jpg'
|
|
import dianneGuilianelliImage from '@/images/avatars/dianne-guilianelli.jpg'
|
|
import erhartCockrinImage from '@/images/avatars/erhart-cockrin.jpg'
|
|
import giordanoSagucioImage from '@/images/avatars/giordano-sagucio.jpg'
|
|
import gordonSandersonImage from '@/images/avatars/gordon-sanderson.jpg'
|
|
import heatherTerryImage from '@/images/avatars/heather-terry.jpg'
|
|
import ibrahimFraschImage from '@/images/avatars/ibrahim-frasch.jpg'
|
|
import jaquelinIschImage from '@/images/avatars/jaquelin-isch.jpg'
|
|
import kimberlyParsonsImage from '@/images/avatars/kimberly-parsons.jpg'
|
|
import parkerJohnsonImage from '@/images/avatars/parker-johnson.jpg'
|
|
import piersWilkinsImage from '@/images/avatars/piers-wilkins.jpg'
|
|
import richardAstley from '@/images/avatars/richard-astley.jpg'
|
|
import rinaldoBeynonImage from '@/images/avatars/rinaldo-beynon.jpg'
|
|
import ronniCantadoreImage from '@/images/avatars/ronni-cantadore.jpg'
|
|
import stevenMchailImage from '@/images/avatars/steven-mchail.jpg'
|
|
import waylonHydenImage from '@/images/avatars/waylon-hyden.jpg'
|
|
import kristofdespiegeleerImage from '@/images/avatars/kristof_de_spiegeleer.jpeg'
|
|
import adnanfatayerjiImage from '@/images/avatars/adnan_fatayerji.jpg'
|
|
import florianfournierImage from '@/images/avatars/florian_fournier.jpeg'
|
|
import matthewschutteImage from '@/images/avatars/matthew_schutte.jpeg'
|
|
import omreiabumadiImage from '@/images/avatars/omrei_abumadi.jpeg'
|
|
import victormuhagachiImage from '@/images/avatars/victor_muhagachi.jpeg'
|
|
import sashaastiadiImage from '@/images/avatars/sasha_astiadi.jpeg'
|
|
|
|
const days = [
|
|
{
|
|
name: 'Opening Day',
|
|
date: 'Oct 24',
|
|
dateTime: '2022-04-04',
|
|
speakers: [
|
|
{
|
|
name: 'Kristof de Spielegeer',
|
|
role: 'CEO at ThreeFold',
|
|
image: kristofdespiegeleerImage,
|
|
},
|
|
{
|
|
name: 'Adnan Fatayerji',
|
|
role: 'CEO at Habari',
|
|
image: adnanfatayerjiImage,
|
|
},
|
|
{
|
|
name: 'Matthew Schutte',
|
|
role: 'CEO at Holochain',
|
|
image: matthewschutteImage,
|
|
},
|
|
{
|
|
name: 'Florian Fournier',
|
|
role: 'Co-founder at OurWorld',
|
|
image: florianfournierImage,
|
|
},
|
|
{
|
|
name: 'Omrei Abumadi',
|
|
role: 'Founder at Vindo',
|
|
image: omreiabumadiImage,
|
|
},
|
|
{
|
|
name: 'Sasha Astiadi',
|
|
role: 'Event Host, PO at OurVerse',
|
|
image: sashaastiadiImage
|
|
},
|
|
{
|
|
name: 'Victor Muhagachi',
|
|
role: 'Co-founder at Dunia Yetu',
|
|
image: victormuhagachiImage,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Speakers & Workshops',
|
|
date: 'Oct 25',
|
|
dateTime: '2022-04-05',
|
|
speakers: [
|
|
{
|
|
name: 'Damaris Kimura',
|
|
role: 'Senior Engineer at OCP',
|
|
image: damarisKimuraImage,
|
|
},
|
|
{
|
|
name: 'Ibrahim Frasch',
|
|
role: 'Programmer at Umbrella Corp',
|
|
image: ibrahimFraschImage,
|
|
},
|
|
{
|
|
name: 'Cathlene Burrage',
|
|
role: 'Frontend Developer at Buy n Large',
|
|
image: cathleneBurrageImage,
|
|
},
|
|
{
|
|
name: 'Rinaldo Beynon',
|
|
role: 'Data Scientist at Rekall',
|
|
image: rinaldoBeynonImage,
|
|
},
|
|
{
|
|
name: 'Waylon Hyden',
|
|
role: 'DevOps at RDA Corporation',
|
|
image: waylonHydenImage,
|
|
},
|
|
{
|
|
name: 'Giordano Sagucio',
|
|
role: 'Game Developer at Soylent Corp',
|
|
image: giordanoSagucioImage,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Interviews',
|
|
date: 'Oct 26',
|
|
dateTime: '2022-04-06',
|
|
speakers: [
|
|
{
|
|
name: 'Andrew Greene',
|
|
role: 'Frontend Developer at Ultratech',
|
|
image: andrewGreeneImage,
|
|
},
|
|
{
|
|
name: 'Heather Terry',
|
|
role: 'Backend Developer at Xanatos Enterprises',
|
|
image: heatherTerryImage,
|
|
},
|
|
{
|
|
name: 'Piers Wilkins',
|
|
role: 'Full stack Developer at BiffCo',
|
|
image: piersWilkinsImage,
|
|
},
|
|
{
|
|
name: 'Gordon Sanderson',
|
|
role: 'Mobile Developer at Cobra Industries',
|
|
image: gordonSandersonImage,
|
|
},
|
|
{
|
|
name: 'Kimberly Parsons',
|
|
role: 'Game Developer at Tyrell Corporation',
|
|
image: kimberlyParsonsImage,
|
|
},
|
|
{
|
|
name: 'Richard Astley',
|
|
role: 'CEO at Roll Out',
|
|
image: richardAstley,
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
function ImageClipPaths({ id, ...props }) {
|
|
return (
|
|
<svg aria-hidden="true" width={0} height={0} {...props}>
|
|
<defs>
|
|
<clipPath id={`${id}-0`} clipPathUnits="objectBoundingBox">
|
|
<path d="M0,0 h0.729 v0.129 h0.121 l-0.016,0.032 C0.815,0.198,0.843,0.243,0.885,0.243 H1 v0.757 H0.271 v-0.086 l-0.121,0.057 v-0.214 c0,-0.032,-0.026,-0.057,-0.057,-0.057 H0 V0" />
|
|
</clipPath>
|
|
<clipPath id={`${id}-1`} clipPathUnits="objectBoundingBox">
|
|
<path d="M1,1 H0.271 v-0.129 H0.15 l0.016,-0.032 C0.185,0.802,0.157,0.757,0.115,0.757 H0 V0 h0.729 v0.086 l0.121,-0.057 v0.214 c0,0.032,0.026,0.057,0.057,0.057 h0.093 v0.7" />
|
|
</clipPath>
|
|
<clipPath id={`${id}-2`} clipPathUnits="objectBoundingBox">
|
|
<path d="M1,0 H0.271 v0.129 H0.15 l0.016,0.032 C0.185,0.198,0.157,0.243,0.115,0.243 H0 v0.757 h0.729 v-0.086 l0.121,0.057 v-0.214 c0,-0.032,0.026,-0.057,0.057,-0.057 h0.093 V0" />
|
|
</clipPath>
|
|
</defs>
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
export function Speakers() {
|
|
let id = useId()
|
|
let [tabOrientation, setTabOrientation] = useState('horizontal')
|
|
|
|
useEffect(() => {
|
|
let lgMediaQuery = window.matchMedia('(min-width: 1024px)')
|
|
|
|
function onMediaQueryChange({ matches }) {
|
|
setTabOrientation(matches ? 'vertical' : 'horizontal')
|
|
}
|
|
|
|
onMediaQueryChange(lgMediaQuery)
|
|
lgMediaQuery.addEventListener('change', onMediaQueryChange)
|
|
|
|
return () => {
|
|
lgMediaQuery.removeEventListener('change', onMediaQueryChange)
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<section
|
|
id="speakers"
|
|
aria-labelledby="speakers-title"
|
|
className="py-20 lg:py-12"
|
|
>
|
|
<ImageClipPaths id={id} />
|
|
<Container>
|
|
<div className="mx-auto max-w-2xl lg:mx-0">
|
|
<h2
|
|
id="speakers-title"
|
|
className="font-display text-4xl font-medium tracking-tighter text-purple-700 sm:text-5xl"
|
|
>
|
|
Speakers
|
|
</h2>
|
|
<p className="mt-4 font-display text-2xl tracking-tight text-purple-900">
|
|
Get ready to be inspired by some of the industry leaders and innovators who are shaping the future of the metaverse, Web3, AI, and more.
|
|
</p>
|
|
</div>
|
|
<TabGroup
|
|
className="mt-14 grid grid-cols-1 items-start gap-x-8 gap-y-8 sm:mt-16 sm:gap-y-16 lg:mt-24 lg:grid-cols-4"
|
|
vertical={tabOrientation === 'vertical'}
|
|
>
|
|
<div className="relative -mx-4 flex overflow-x-auto pb-4 sm:mx-0 sm:block sm:overflow-visible sm:pb-0">
|
|
<div className="absolute bottom-0 left-0.5 top-2 hidden w-px bg-slate-200 lg:block" />
|
|
<TabList className="grid auto-cols-auto grid-flow-col justify-start gap-x-8 gap-y-10 whitespace-nowrap px-4 sm:mx-auto sm:max-w-2xl sm:grid-cols-3 sm:px-0 sm:text-center lg:grid-flow-row lg:grid-cols-1 lg:text-left">
|
|
{({ selectedIndex }) => (
|
|
<>
|
|
{days.map((day, dayIndex) => (
|
|
<div key={day.dateTime} className="relative lg:pl-8">
|
|
<DiamondIcon
|
|
className={clsx(
|
|
'absolute left-[-0.5px] top-[0.5625rem] hidden h-1.5 w-1.5 overflow-visible lg:block',
|
|
dayIndex === selectedIndex
|
|
? 'fill-purple-500 stroke-purple-500'
|
|
: 'fill-transparent stroke-slate-400',
|
|
)}
|
|
/>
|
|
<div className="relative">
|
|
<div
|
|
className={clsx(
|
|
'font-mono text-sm',
|
|
dayIndex === selectedIndex
|
|
? 'text-purple-500'
|
|
: 'text-slate-500',
|
|
)}
|
|
>
|
|
<Tab className="ui-not-focus-visible:outline-none">
|
|
<span className="absolute inset-0" />
|
|
{day.name}
|
|
</Tab>
|
|
</div>
|
|
<time
|
|
dateTime={day.dateTime}
|
|
className="mt-1.5 block text-2xl font-semibold tracking-tight text-purple-900"
|
|
>
|
|
{day.date}
|
|
</time>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</>
|
|
)}
|
|
</TabList>
|
|
</div>
|
|
<TabPanels className="lg:col-span-3">
|
|
{days.map((day) => (
|
|
<TabPanel
|
|
key={day.dateTime}
|
|
className="grid grid-cols-1 gap-x-8 gap-y-10 ui-not-focus-visible:outline-none sm:grid-cols-2 sm:gap-y-16 md:grid-cols-3"
|
|
unmount={false}
|
|
>
|
|
{day.speakers.map((speaker, speakerIndex) => (
|
|
<div key={speakerIndex}>
|
|
<div className="group relative h-[17.5rem] transform overflow-hidden rounded-4xl">
|
|
<div
|
|
className={clsx(
|
|
'absolute bottom-6 left-0 right-4 top-0 rounded-4xl border transition duration-300 group-hover:scale-95 xl:right-6',
|
|
[
|
|
'border-purple-300',
|
|
'border-indigo-300',
|
|
'border-sky-300',
|
|
][speakerIndex % 3],
|
|
)}
|
|
/>
|
|
<div
|
|
className="absolute inset-0 bg-indigo-50"
|
|
style={{ clipPath: `url(#${id}-${speakerIndex % 3})` }}
|
|
>
|
|
<Image
|
|
className="absolute inset-0 h-full w-full object-cover transition duration-300 group-hover:scale-110"
|
|
src={speaker.image}
|
|
alt=""
|
|
priority
|
|
sizes="(min-width: 1280px) 17.5rem, (min-width: 1024px) 25vw, (min-width: 768px) 33vw, (min-width: 640px) 50vw, 100vw"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<h3 className="mt-8 font-display text-xl font-bold tracking-tight text-slate-900">
|
|
{speaker.name}
|
|
</h3>
|
|
<p className="mt-1 text-base tracking-tight text-slate-500">
|
|
{speaker.role}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</TabPanel>
|
|
))}
|
|
</TabPanels>
|
|
</TabGroup>
|
|
</Container>
|
|
</section>
|
|
)
|
|
}
|