add metafest page

This commit is contained in:
2024-08-27 10:32:30 +02:00
parent 8b8dbb1b75
commit b13dd41c68
346 changed files with 8840 additions and 659 deletions

View File

@@ -53,7 +53,7 @@ import {
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-4xl sm:text-center">
<h2 className="text-base font-medium font-mono leading-7 text-blue-600">Get Started</h2>
<p className="mt-2 font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">Build Your Own Verse</p>
<p className="mt-2 font-display text-4xl font-medium tracking-tighter text-blue-700 sm:text-5xl">Build Your Own Verse</p>
<p className="mt-6 font-display text-2xl tracking-tight text-blue-900">
Create and customize your virtual world with powerful tools and resources that make building and managing your digital space easy and intuitive.
</p>

View File

@@ -8,10 +8,10 @@ import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
// Example navigation items
const navigationItems = [
{ name: 'Home', href: '#' },
{ name: 'About', href: '#' },
{ name: 'Services', href: '#' },
{ name: 'Contact', href: '#' }
{ name: 'Home', href: '/' },
{ name: 'Features', href: '#' },
{ name: 'Usecases', href: '#' },
{ name: 'Events', href: '#' },
];
export function Header() {

View File

@@ -1,10 +1,11 @@
import { Button } from '@/components/Button';
import { Container } from '@/components/Container';
import { Gradient } from '@/components/Gradient';
import { ChevronRightIcon } from '@heroicons/react/20/solid'
export function Homepage() {
return (
<Gradient className="pt-24 pb-10">
<Gradient className="pt-24 pb-24">
<Container>
{/* Background Video */}
<video
@@ -19,7 +20,18 @@ export function Homepage() {
</video>
<div className="mx-auto max-w-xl lg:max-w-6xl">
<h1 className="font-display lg:max-w-2xl font-bold tracking-tighter text-blue-700 lg:text-7xl text-4xl">
<div className="mt-12 mb-6 lg:mt-16">
<div className="inline-flex space-x-6">
<span className="rounded-full bg-blue-700/10 px-3 py-1 text-sm font-semibold leading-6 text-blue-700 ring-1 ring-inset ring-indigo-600/10">
What's new
</span>
<a href="/events/metafest" className="inline-flex items-center space-x-2 text-sm font-medium leading-6 text-blue-600 hover:text-blue-900">
<span className="underline">Announcing MetaFest 2024</span>
<ChevronRightIcon className="h-5 w-5 text-blue-700" aria-hidden="true" />
</a>
</div>
</div>
<h1 className="font-display lg:max-w-2xl font-bold tracking-tighter text-blue-700 lg:text-7xl text-5xl">
A New, Vibrant Virtual World.
</h1>
<div className="lg:max-w-3xl max-w-2xl my-6 space-y-6 font-display font-medium lg:text-2xl text-xl tracking-tight text-blue-900">

View File

@@ -0,0 +1,89 @@
'use client'
import { useEffect, useState } from 'react'
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
import clsx from 'clsx'
import { BackgroundImage } from '@/components/BackgroundImage'
import { Container } from '@/components/Container'
const products = [
{
id: 1,
name: 'Enhancing Education',
color: 'Transform traditional education with immersive distance learning opportunities',
href: '#',
imageSrc: '/images/education.jpg',
imageAlt: 'classroom',
},
{
id: 2,
name: 'Environmental Awareness',
color: 'Advocate for environmental conservation through virtual eco-tours & initiatives.',
href: '#',
imageSrc: '/images/environment.jpg',
imageAlt: 'environment',
},
{
id: 3,
name: 'Supporting Healthcare',
color: 'Innovate healthcare delivery by integrating virtual consultations & tools.',
href: '#',
imageSrc: '/images/healthcare.jpg',
imageAlt: 'clinic',
},
{
id: 4,
name: 'Empowering Africa',
color: 'Foster cultural and economic growth across Africa through virtual solutions.',
href: '#',
imageSrc: '/images/africa.jpg',
imageAlt: 'africa',
},
]
export function Product() {
return (
<section id="schedule" aria-label="Schedule" className="py-8 lg:py-24 mb-12">
<Container className="relative z-10">
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-4xl lg:pr-24">
<h2 className="text-base font-medium font-mono leading-7 text-blue-600">Usecases</h2>
<h2 className="mt-2 font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">
Transforming Possibilities Across Industries Digitally
</h2>
<p className="mt-4 font-display text-2xl tracking-tight text-blue-900">
Explore diverse scenarios where our platform empowers users to create, collaborate,
and innovate in immersive virtual environments, unlocking new potentials across industries and communities.
</p>
</div>
</Container>
<div className="relative lg:mt-14 mt-16">
<BackgroundImage position="right" className="-bottom-32 -top-40" />
<Container className="relative">
<div className="mt-4 grid grid-cols-1 gap-y-12 sm:grid-cols-2 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8">
{products.map((product) => (
<div key={product.id}>
<div className="relative">
<div className="relative h-full w-full overflow-hidden rounded-sm">
<img
alt={product.imageAlt}
src={product.imageSrc}
className="h-full w-full object-cover object-center"
/>
</div>
<div className="relative mt-4">
<h3 className="lg:text-base text-lg font-medium text-blue-700">{product.name}</h3>
<p className="mt-1 mb-2 lg:text-sm text-base text-blue-900">{product.color}</p>
<a href={product.href} className="lg:text-xs text-sm font-mono text-blue-700 hover:text-blue-900">
Read Usecase <span aria-hidden="true"></span>
</a>
</div>
</div>
</div>
))}
</div>
</Container>
</div>
</section>
)
}

View File

@@ -1,233 +0,0 @@
'use client'
import { useEffect, useState } from 'react'
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
import clsx from 'clsx'
import { BackgroundImage } from '@/components/BackgroundImage'
import { Container } from '@/components/Container'
const schedule = [
{
date: 'Enhancing Education',
summary:
'Transform traditional education with distant learning opportunities.',
timeSlots: [
{
name: 'Virtual Classrooms',
description: 'Create engaging and interactive learning environments where students can collaborate and participate in real-time.',
},
{
name: 'Distance Learning',
description: 'Provide accessible education to students around the world with flexible and remote learning solutions.',
},
{
name: 'Professional Training',
description: 'Equip professionals with advanced skills through immersive, hands-on training experiences.',
},
],
},
{
date: 'Supporting Healthcare',
summary:
' Innovate healthcare by integrating virtual tools for a holistic approach to well-being.',
timeSlots: [
{
name: 'Virtual Health Consultations',
description: 'Offer remote medical consultations in secure and accessible virtual environments.',
},
{
name: 'Mental Health Support',
description: 'Provide confidential and supportive virtual spaces for mental health counseling and therapy.',
},
{
name: 'Promoting Social Good',
description: 'Utilize virtual platforms for fundraising events and community engagement, driving positive change globally.',
},
],
},
{
date: 'Empowering Africa',
summary:
'Foster cultural preservation, economic growth, and educational access across Africa.',
timeSlots: [
{
name: 'Cultural Preservation',
description: 'Protect and celebrate Africas rich cultural heritage through virtual exhibits and experiences.',
},
{
name: 'Economic Development',
description: 'Drive economic growth by creating virtual marketplaces and entrepreneurial opportunities.',
},
{
name: 'Educational Access',
description: ' Expand educational opportunities by delivering learning resources to underserved communities.',
},
],
},
{
date: 'Advocate for environmental conservation through virtual eco-tours, green initiatives',
summary:
'Foster cultural preservation, economic growth, and educational access across Africa.',
timeSlots: [
{
name: 'Cultural Preservation',
description: 'Protect and celebrate Africas rich cultural heritage through virtual exhibits and experiences.',
},
{
name: 'Economic Development',
description: 'Drive economic growth by creating virtual marketplaces and entrepreneurial opportunities.',
},
{
name: 'Educational Access',
description: ' Expand educational opportunities by delivering learning resources to underserved communities.',
},
],
},
]
function ScheduleTabbed() {
let [tabOrientation, setTabOrientation] = useState('horizontal')
useEffect(() => {
let smMediaQuery = window.matchMedia('(min-width: 640px)')
function onMediaQueryChange({ matches }) {
setTabOrientation(matches ? 'vertical' : 'horizontal')
}
onMediaQueryChange(smMediaQuery)
smMediaQuery.addEventListener('change', onMediaQueryChange)
return () => {
smMediaQuery.removeEventListener('change', onMediaQueryChange)
}
}, [])
return (
<TabGroup
className="mx-auto grid max-w-2xl grid-cols-1 gap-y-6 sm:grid-cols-2 lg:hidden"
vertical={tabOrientation === 'vertical'}
>
<TabList className="-mx-4 flex gap-x-4 gap-y-10 overflow-x-auto pb-4 pl-4 sm:mx-0 sm:flex-col sm:pb-0 sm:pl-0 sm:pr-8">
{({ selectedIndex }) => (
<>
{schedule.map((day, dayIndex) => (
<div
key={day.dateTime}
className={clsx(
'relative w-3/4 flex-none pr-4 sm:w-auto sm:pr-0',
dayIndex !== selectedIndex && 'opacity-70',
)}
>
<DaySummary
day={{
...day,
date: (
<Tab className="ui-not-focus-visible:outline-none">
<span className="absolute inset-0" />
{day.date}
</Tab>
),
}}
/>
</div>
))}
</>
)}
</TabList>
<TabPanels>
{schedule.map((day) => (
<TabPanel
key={day.dateTime}
className="ui-not-focus-visible:outline-none"
>
<TimeSlots day={day} />
</TabPanel>
))}
</TabPanels>
</TabGroup>
)
}
function DaySummary({ day }) {
return (
<>
<h3 className="text-2xl font-semibold tracking-tight text-blue-900 mt-16">
<time dateTime={day.dateTime}>{day.date}</time>
</h3>
<p className="mt-1.5 text-base tracking-tight text-blue-900">
{day.summary}
</p>
</>
)
}
function TimeSlots({ day, className }) {
return (
<ol
role="list"
className={clsx(
className,
'space-y-8 bg-white/60 px-10 py-14 text-center shadow-xl shadow-blue-900/5 backdrop-blur',
)}
>
{day.timeSlots.map((timeSlot, timeSlotIndex) => (
<li
key={timeSlot.start}
aria-label={`${timeSlot.name} talking about ${timeSlot.description} at ${timeSlot.start} - ${timeSlot.end} PST`}
>
{timeSlotIndex > 0 && (
<div className="mx-auto mb-8 h-px w-48 bg-indigo-500/10" />
)}
<h4 className="text-lg font-semibold tracking-tight text-blue-900">
{timeSlot.name}
</h4>
{timeSlot.description && (
<p className="mt-1 tracking-tight text-blue-900">
{timeSlot.description}
</p>
)}
</li>
))}
</ol>
)
}
function ScheduleStatic() {
return (
<div className="hidden lg:grid lg:grid-cols-3 lg:gap-x-8">
{schedule.map((day) => (
<section key={day.dateTime}>
<DaySummary day={day} />
<TimeSlots day={day} className="mt-10" />
</section>
))}
</div>
)
}
export function Schedule() {
return (
<section id="schedule" aria-label="Schedule" className="py-20 sm:py-32">
<Container className="relative z-10">
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-4xl lg:pr-24">
<h2 className="font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">
Transforming Possibilities Across Industries Digitally
</h2>
<p className="mt-4 font-display text-2xl tracking-tight text-blue-900">
Explore diverse scenarios where our platform empowers users to create, collaborate,
and innovate in immersive virtual environments, unlocking new potentials across industries and communities.
</p>
</div>
</Container>
<div className="relative mt-14 sm:mt-24">
<BackgroundImage position="right" className="-bottom-32 -top-40" />
<Container className="relative">
<ScheduleTabbed />
<ScheduleStatic />
</Container>
</div>
</section>
)
}

View File

@@ -7,81 +7,311 @@ import clsx from 'clsx'
import { BackgroundImage } from '@/components/BackgroundImage'
import { Container } from '@/components/Container'
const products = [
const schedule = [
{
id: 1,
name: 'Enhancing Education',
color: 'Transform traditional education with immersive distance learning opportunities',
href: '#',
imageSrc: '/images/education.jpg',
imageAlt: 'classroom',
date: 'April 4',
dateTime: '2022-04-04',
summary:
'The first day of the conference is focused on dark patterns for ecommerce.',
timeSlots: [
{
name: 'Steven McHail',
description: 'Not so one-time payments',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Jaquelin Isch',
description: 'The finer print',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Dianne Guilianelli',
description: 'Post-purchase blackmail',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Ronni Cantadore',
description: 'Buy or die',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Erhart Cockrin',
description: 'In-person cancellation',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Parker Johnson',
description: 'The pay/cancel switcheroo',
start: '3:00PM',
end: '4:00PM',
},
],
},
{
id: 2,
name: 'Environmental Awareness',
color: 'Advocate for environmental conservation through virtual eco-tours & initiatives.',
href: '#',
imageSrc: '/images/environment.jpg',
imageAlt: 'environment',
date: 'April 5',
dateTime: '2022-04-05',
summary:
'Next we spend the day talking about deceiving people with technology.',
timeSlots: [
{
name: 'Damaris Kimura',
description: 'The invisible card reader',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Ibrahim Frasch',
description: 'Stealing fingerprints',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Cathlene Burrage',
description: 'Voting machines',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Rinaldo Beynon',
description: 'Blackhat SEO that works',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Waylon Hyden',
description: 'Turning your audience into a botnet',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Giordano Sagucio',
description: 'Fly phishing',
start: '3:00PM',
end: '4:00PM',
},
],
},
{
id: 3,
name: 'Supporting Healthcare',
color: 'Innovate healthcare delivery by integrating virtual consultations & tools.',
href: '#',
imageSrc: '/images/healthcare.jpg',
imageAlt: 'clinic',
},
{
id: 4,
name: 'Empowering Africa',
color: 'Foster cultural and economic growth across Africa through virtual solutions.',
href: '#',
imageSrc: '/images/africa.jpg',
imageAlt: 'africa',
date: 'April 6',
dateTime: '2022-04-06',
summary:
'We close out the event previewing new techniques that are still in development.',
timeSlots: [
{
name: 'Andrew Greene',
description: 'Neuralink dark patterns',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Heather Terry',
description: 'DALL-E for passports',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Piers Wilkins',
description: 'Quantum password cracking',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Gordon Sanderson',
description: 'SkyNet is coming',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Kimberly Parsons',
description: 'Dark patterns for the metaverse',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Richard Astley',
description: 'Knowing the game and playing it',
start: '3:00PM',
end: '4:00PM',
},
],
},
]
function ScheduleTabbed() {
let [tabOrientation, setTabOrientation] = useState('horizontal')
useEffect(() => {
let smMediaQuery = window.matchMedia('(min-width: 640px)')
function onMediaQueryChange({ matches }) {
setTabOrientation(matches ? 'vertical' : 'horizontal')
}
onMediaQueryChange(smMediaQuery)
smMediaQuery.addEventListener('change', onMediaQueryChange)
return () => {
smMediaQuery.removeEventListener('change', onMediaQueryChange)
}
}, [])
return (
<TabGroup
className="mx-auto grid max-w-2xl grid-cols-1 gap-y-6 sm:grid-cols-2 lg:hidden"
vertical={tabOrientation === 'vertical'}
>
<TabList className="-mx-4 flex gap-x-4 gap-y-10 overflow-x-auto pb-4 pl-4 sm:mx-0 sm:flex-col sm:pb-0 sm:pl-0 sm:pr-8">
{({ selectedIndex }) => (
<>
{schedule.map((day, dayIndex) => (
<div
key={day.dateTime}
className={clsx(
'relative w-3/4 flex-none pr-4 sm:w-auto sm:pr-0',
dayIndex !== selectedIndex && 'opacity-70',
)}
>
<DaySummary
day={{
...day,
date: (
<Tab className="ui-not-focus-visible:outline-none">
<span className="absolute inset-0" />
{day.date}
</Tab>
),
}}
/>
</div>
))}
</>
)}
</TabList>
<TabPanels>
{schedule.map((day) => (
<TabPanel
key={day.dateTime}
className="ui-not-focus-visible:outline-none"
>
<TimeSlots day={day} />
</TabPanel>
))}
</TabPanels>
</TabGroup>
)
}
function DaySummary({ day }) {
return (
<>
<h3 className="text-2xl font-semibold tracking-tight text-blue-900">
<time dateTime={day.dateTime}>{day.date}</time>
</h3>
<p className="mt-1.5 text-base tracking-tight text-blue-900">
{day.summary}
</p>
</>
)
}
function TimeSlots({ day, className }) {
return (
<ol
role="list"
className={clsx(
className,
'space-y-8 bg-white/60 px-10 py-14 text-center shadow-xl shadow-blue-900/5 backdrop-blur',
)}
>
{day.timeSlots.map((timeSlot, timeSlotIndex) => (
<li
key={timeSlot.start}
aria-label={`${timeSlot.name} talking about ${timeSlot.description} at ${timeSlot.start} - ${timeSlot.end} PST`}
>
{timeSlotIndex > 0 && (
<div className="mx-auto mb-8 h-px w-48 bg-indigo-500/10" />
)}
<h4 className="text-lg font-semibold tracking-tight text-blue-900">
{timeSlot.name}
</h4>
{timeSlot.description && (
<p className="mt-1 tracking-tight text-blue-900">
{timeSlot.description}
</p>
)}
<p className="mt-1 font-mono text-sm text-slate-500">
<time dateTime={`${day.dateTime}T${timeSlot.start}-08:00`}>
{timeSlot.start}
</time>{' '}
-{' '}
<time dateTime={`${day.dateTime}T${timeSlot.end}-08:00`}>
{timeSlot.end}
</time>{' '}
PST
</p>
</li>
))}
</ol>
)
}
function ScheduleStatic() {
return (
<div className="hidden lg:grid lg:grid-cols-3 lg:gap-x-8">
{schedule.map((day) => (
<section key={day.dateTime}>
<DaySummary day={day} />
<TimeSlots day={day} className="mt-10" />
</section>
))}
</div>
)
}
export function Schedule() {
return (
<section id="schedule" aria-label="Schedule" className="py-8 lg:py-24 mb-12">
<section id="schedule" aria-label="Schedule" className="py-20 sm:py-32">
<Container className="relative z-10">
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-4xl lg:pr-24">
<h2 className="text-base font-medium font-mono leading-7 text-blue-600">Usecases</h2>
<h2 className="mt-2 font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">
Transforming Possibilities Across Industries Digitally
<h2 className="font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">
Our three day schedule is jam-packed with brilliant, creative, evil
geniuses.
</h2>
<p className="mt-4 font-display text-2xl tracking-tight text-blue-900">
Explore diverse scenarios where our platform empowers users to create, collaborate,
and innovate in immersive virtual environments, unlocking new potentials across industries and communities.
The worst people in our industry giving the best talks youve ever
seen. Nothing will be recorded and every attendee has to sign an NDA
to watch the talks.
</p>
</div>
</Container>
<div className="relative lg:mt-14 mt-16">
<div className="relative mt-14 sm:mt-24">
<BackgroundImage position="right" className="-bottom-32 -top-40" />
<Container className="relative">
<div className="mt-4 grid grid-cols-1 gap-y-12 sm:grid-cols-2 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8">
{products.map((product) => (
<div key={product.id}>
<div className="relative">
<div className="relative h-full w-full overflow-hidden rounded-sm">
<img
alt={product.imageAlt}
src={product.imageSrc}
className="h-full w-full object-cover object-center"
/>
</div>
<div className="relative mt-4">
<h3 className="lg:text-base text-lg font-medium text-blue-700">{product.name}</h3>
<p className="mt-1 mb-2 lg:text-sm text-base text-blue-900">{product.color}</p>
<a href={product.href} className="lg:text-xs text-sm font-mono text-blue-700 hover:text-blue-900">
Read Usecase <span aria-hidden="true"></span>
</a>
</div>
</div>
</div>
))}
</div>
<ScheduleTabbed />
<ScheduleStatic />
</Container>
</div>
</section>

View File

@@ -1,319 +0,0 @@
'use client'
import { useEffect, useState } from 'react'
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
import clsx from 'clsx'
import { BackgroundImage } from '@/components/BackgroundImage'
import { Container } from '@/components/Container'
const schedule = [
{
date: 'April 4',
dateTime: '2022-04-04',
summary:
'The first day of the conference is focused on dark patterns for ecommerce.',
timeSlots: [
{
name: 'Steven McHail',
description: 'Not so one-time payments',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Jaquelin Isch',
description: 'The finer print',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Dianne Guilianelli',
description: 'Post-purchase blackmail',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Ronni Cantadore',
description: 'Buy or die',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Erhart Cockrin',
description: 'In-person cancellation',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Parker Johnson',
description: 'The pay/cancel switcheroo',
start: '3:00PM',
end: '4:00PM',
},
],
},
{
date: 'April 5',
dateTime: '2022-04-05',
summary:
'Next we spend the day talking about deceiving people with technology.',
timeSlots: [
{
name: 'Damaris Kimura',
description: 'The invisible card reader',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Ibrahim Frasch',
description: 'Stealing fingerprints',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Cathlene Burrage',
description: 'Voting machines',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Rinaldo Beynon',
description: 'Blackhat SEO that works',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Waylon Hyden',
description: 'Turning your audience into a botnet',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Giordano Sagucio',
description: 'Fly phishing',
start: '3:00PM',
end: '4:00PM',
},
],
},
{
date: 'April 6',
dateTime: '2022-04-06',
summary:
'We close out the event previewing new techniques that are still in development.',
timeSlots: [
{
name: 'Andrew Greene',
description: 'Neuralink dark patterns',
start: '9:00AM',
end: '10:00AM',
},
{
name: 'Heather Terry',
description: 'DALL-E for passports',
start: '10:00AM',
end: '11:00AM',
},
{
name: 'Piers Wilkins',
description: 'Quantum password cracking',
start: '11:00AM',
end: '12:00PM',
},
{
name: 'Lunch',
description: null,
start: '12:00PM',
end: '1:00PM',
},
{
name: 'Gordon Sanderson',
description: 'SkyNet is coming',
start: '1:00PM',
end: '2:00PM',
},
{
name: 'Kimberly Parsons',
description: 'Dark patterns for the metaverse',
start: '2:00PM',
end: '3:00PM',
},
{
name: 'Richard Astley',
description: 'Knowing the game and playing it',
start: '3:00PM',
end: '4:00PM',
},
],
},
]
function ScheduleTabbed() {
let [tabOrientation, setTabOrientation] = useState('horizontal')
useEffect(() => {
let smMediaQuery = window.matchMedia('(min-width: 640px)')
function onMediaQueryChange({ matches }) {
setTabOrientation(matches ? 'vertical' : 'horizontal')
}
onMediaQueryChange(smMediaQuery)
smMediaQuery.addEventListener('change', onMediaQueryChange)
return () => {
smMediaQuery.removeEventListener('change', onMediaQueryChange)
}
}, [])
return (
<TabGroup
className="mx-auto grid max-w-2xl grid-cols-1 gap-y-6 sm:grid-cols-2 lg:hidden"
vertical={tabOrientation === 'vertical'}
>
<TabList className="-mx-4 flex gap-x-4 gap-y-10 overflow-x-auto pb-4 pl-4 sm:mx-0 sm:flex-col sm:pb-0 sm:pl-0 sm:pr-8">
{({ selectedIndex }) => (
<>
{schedule.map((day, dayIndex) => (
<div
key={day.dateTime}
className={clsx(
'relative w-3/4 flex-none pr-4 sm:w-auto sm:pr-0',
dayIndex !== selectedIndex && 'opacity-70',
)}
>
<DaySummary
day={{
...day,
date: (
<Tab className="ui-not-focus-visible:outline-none">
<span className="absolute inset-0" />
{day.date}
</Tab>
),
}}
/>
</div>
))}
</>
)}
</TabList>
<TabPanels>
{schedule.map((day) => (
<TabPanel
key={day.dateTime}
className="ui-not-focus-visible:outline-none"
>
<TimeSlots day={day} />
</TabPanel>
))}
</TabPanels>
</TabGroup>
)
}
function DaySummary({ day }) {
return (
<>
<h3 className="text-2xl font-semibold tracking-tight text-blue-900">
<time dateTime={day.dateTime}>{day.date}</time>
</h3>
<p className="mt-1.5 text-base tracking-tight text-blue-900">
{day.summary}
</p>
</>
)
}
function TimeSlots({ day, className }) {
return (
<ol
role="list"
className={clsx(
className,
'space-y-8 bg-white/60 px-10 py-14 text-center shadow-xl shadow-blue-900/5 backdrop-blur',
)}
>
{day.timeSlots.map((timeSlot, timeSlotIndex) => (
<li
key={timeSlot.start}
aria-label={`${timeSlot.name} talking about ${timeSlot.description} at ${timeSlot.start} - ${timeSlot.end} PST`}
>
{timeSlotIndex > 0 && (
<div className="mx-auto mb-8 h-px w-48 bg-indigo-500/10" />
)}
<h4 className="text-lg font-semibold tracking-tight text-blue-900">
{timeSlot.name}
</h4>
{timeSlot.description && (
<p className="mt-1 tracking-tight text-blue-900">
{timeSlot.description}
</p>
)}
<p className="mt-1 font-mono text-sm text-slate-500">
<time dateTime={`${day.dateTime}T${timeSlot.start}-08:00`}>
{timeSlot.start}
</time>{' '}
-{' '}
<time dateTime={`${day.dateTime}T${timeSlot.end}-08:00`}>
{timeSlot.end}
</time>{' '}
PST
</p>
</li>
))}
</ol>
)
}
function ScheduleStatic() {
return (
<div className="hidden lg:grid lg:grid-cols-3 lg:gap-x-8">
{schedule.map((day) => (
<section key={day.dateTime}>
<DaySummary day={day} />
<TimeSlots day={day} className="mt-10" />
</section>
))}
</div>
)
}
export function Schedule() {
return (
<section id="schedule" aria-label="Schedule" className="py-20 sm:py-32">
<Container className="relative z-10">
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-4xl lg:pr-24">
<h2 className="font-display text-4xl font-medium tracking-tighter text-blue-600 sm:text-5xl">
Our three day schedule is jam-packed with brilliant, creative, evil
geniuses.
</h2>
<p className="mt-4 font-display text-2xl tracking-tight text-blue-900">
The worst people in our industry giving the best talks youve ever
seen. Nothing will be recorded and every attendee has to sign an NDA
to watch the talks.
</p>
</div>
</Container>
<div className="relative mt-14 sm:mt-24">
<BackgroundImage position="right" className="-bottom-32 -top-40" />
<Container className="relative">
<ScheduleTabbed />
<ScheduleStatic />
</Container>
</div>
</section>
)
}