Compare commits

...

2 Commits

Author SHA1 Message Date
9b8934fef7 toggoe 2025-08-27 13:47:14 +02:00
296545ed3a edit 2025-08-27 13:42:03 +02:00
6 changed files with 131 additions and 360 deletions

View File

@@ -1,3 +1,6 @@
'use client'
import { useState } from 'react'
import { CallToAction3 } from '@/components/CallToAction3' import { CallToAction3 } from '@/components/CallToAction3'
import { Footer } from '@/components/Footer' import { Footer } from '@/components/Footer'
import { Header } from '@/components/Header' import { Header } from '@/components/Header'
@@ -10,22 +13,34 @@ import { Experience } from '@/components/Exp2'
import FFVid from '@/components/FreeflowVideo' import FFVid from '@/components/FreeflowVideo'
import { Experiences } from '@/components/Experiences' import { Experiences } from '@/components/Experiences'
export default function ExperiencesPage() { export default function ExperiencesPage() {
const [selectedExperience, setSelectedExperience] = useState('community')
const renderSelectedComponent = () => {
switch (selectedExperience) {
case 'community':
return <Community />
case 'events':
return <Events />
case 'nomads':
return <Nomads />
case 'retreats':
return <Retreats />
default:
return <Community />
}
}
return ( return (
<> <>
<Header /> <Header />
<main> <main>
<Experiences/> <Experiences onExperienceSelect={setSelectedExperience} />
<Experience /> {renderSelectedComponent()}
<Community />
<Retreats />
<Events />
<Nomads />
<FFVid/> <FFVid/>
<Exp/> <Exp/>
</main> </main>
<Footer /> <Footer />
</> </>
) )
} }

View File

@@ -1,4 +1,3 @@
import { P, H3, H4, PXS, PXXS } from '@/components/text'
import { import {
Tab, Tab,
TabGroup, TabGroup,
@@ -8,7 +7,6 @@ import {
} from '@headlessui/react' } from '@headlessui/react'
import { H2, PS } from '@/components/text' import { H2, PS } from '@/components/text'
const product = { const product = {
name: 'Community Buildings', name: 'Community Buildings',
images: [ images: [
@@ -37,11 +35,6 @@ const product = {
alt: 'Community building exterior and surroundings', alt: 'Community building exterior and surroundings',
}, },
], ],
colors: [
{ id: 'washed-black', name: 'Washed Black', classes: 'bg-gray-700 checked:outline-gray-700' },
{ id: 'white', name: 'White', classes: 'bg-white checked:outline-gray-400' },
{ id: 'washed-gray', name: 'Washed Gray', classes: 'bg-gray-500 checked:outline-gray-500' },
],
description: 'Community building holds significant value by fostering a sense of belonging, providing social and emotional support, and promoting collective action. It enhances social capital, encourages collaboration. Human to human connection become more and more important as new technological times require us to collaborate more on a peer to peer level and connect on different levels with each other.', description: 'Community building holds significant value by fostering a sense of belonging, providing social and emotional support, and promoting collective action. It enhances social capital, encourages collaboration. Human to human connection become more and more important as new technological times require us to collaborate more on a peer to peer level and connect on different levels with each other.',
details: [ details: [
{ {
@@ -54,54 +47,11 @@ const product = {
}, },
], ],
} }
const relatedProducts = [
{
id: 1,
name: 'Zip Tote Basket',
color: 'White and black',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-01.jpg',
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.',
price: '$140',
},
{
id: 2,
name: 'Zip High Wall Tote',
color: 'White and blue',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-02.jpg',
imageAlt: 'Front of zip tote bag with white canvas, blue canvas straps and handle, and front zipper pocket.',
price: '$150',
},
{
id: 3,
name: 'Halfsize Tote',
color: 'Clay',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-03.jpg',
imageAlt: 'Front of tote with monochrome natural canvas body, straps, roll top, and handles.',
price: '$210',
},
{
id: 4,
name: 'High Wall Tote',
color: 'Black and orange',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-04.jpg',
imageAlt: 'Front of zip tote bag with black canvas, black handles, and orange drawstring top.',
price: '$210',
},
]
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export function Community() { export function Community() {
return ( return (
<div className="pb-24"> <div className="pb-24">
<main className="mx-auto max-w-7xl sm:px-6 sm:pt-12 lg:px-8"> <main className="mx-auto max-w-7xl sm:px-6 sm:pt-24 lg:px-0">
<div className="mx-auto max-w-2xl lg:max-w-none"> <div className="mx-auto max-w-2xl lg:max-w-none">
{/* Product */} {/* Product */}
<div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8"> <div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8">
@@ -139,22 +89,16 @@ export function Community() {
{/* Product info */} {/* Product info */}
<div className="mt-6 px-6 sm:mt-16 sm:px-0 lg:mt-0"> <div className="mt-6 px-6 sm:mt-16 sm:px-0 lg:mt-0">
<H2 className="">{product.name}</H2> <H2>{product.name}</H2>
<div className="mt-4"> <div className="mt-4">
<h3 className="sr-only">Description</h3> <h3 className="sr-only">Description</h3>
<div className="space-y-2 text-base text-gray-700"> <div className="space-y-2 text-base text-gray-700">
<PS>{product.description}</PS> <PS>{product.description}</PS>
</div> </div>
</div> </div>
<section aria-labelledby="details-heading" className="mt-8"> <section aria-labelledby="details-heading" className="mt-8">
<div className="space-y-4 border-t border-gray-300 pt-4"> <div className="space-y-4 border-t border-gray-300 pt-4">
{product.details.map((detail) => ( {product.details.map((detail) => (
<div key={detail.name}> <div key={detail.name}>

View File

@@ -1,35 +1,11 @@
'use client'
import { Fragment, useState } from 'react'
import { import {
Dialog,
DialogBackdrop,
DialogPanel,
Disclosure,
DisclosureButton,
DisclosurePanel,
Popover,
PopoverButton,
PopoverGroup,
PopoverPanel,
Tab, Tab,
TabGroup, TabGroup,
TabList, TabList,
TabPanel, TabPanel,
TabPanels, TabPanels,
} from '@headlessui/react' } from '@headlessui/react'
import { import { H2, PS } from '@/components/text'
Bars3Icon,
HeartIcon,
MagnifyingGlassIcon,
MinusIcon,
PlusIcon,
ShoppingBagIcon,
UserIcon,
XMarkIcon,
} from '@heroicons/react/24/outline'
import { StarIcon } from '@heroicons/react/20/solid'
const product = { const product = {
name: 'Events & Conferences', name: 'Events & Conferences',
@@ -59,17 +35,10 @@ const product = {
alt: 'Outdoor event setting by the Nile', alt: 'Outdoor event setting by the Nile',
}, },
], ],
colors: [ description: "VEDA's facilities are suited for hosting events, a unique venue that combines professional functionality with the tranquility of the Nile. An innovative setting that stands apart from traditional conference venues, promising an impactful event.",
{ id: 'washed-black', name: 'Washed Black', classes: 'bg-gray-700 checked:outline-gray-700' },
{ id: 'white', name: 'White', classes: 'bg-white checked:outline-gray-400' },
{ id: 'washed-gray', name: 'Washed Gray', classes: 'bg-gray-500 checked:outline-gray-500' },
],
description: `
<p>VEDA's facilities are suited for hosting events, a unique venue that combines professional functionality with the tranquility of the Nile. An innovative setting that stands apart from traditional conference venues, promising an impactful event.</p>
`,
details: [ details: [
{ {
name: 'Unique Features', name: 'Features',
items: [ items: [
'Four Air-Conditioned Meeting Spaces equipped with modern amenities to host up to 50/100 participants, perfect for workshops, seminars, and more.', 'Four Air-Conditioned Meeting Spaces equipped with modern amenities to host up to 50/100 participants, perfect for workshops, seminars, and more.',
'From indoor workshops to outdoor receptions and gala dinners, the settings are as versatile as the events themselves.', 'From indoor workshops to outdoor receptions and gala dinners, the settings are as versatile as the events themselves.',
@@ -78,69 +47,13 @@ const product = {
'Flexible Event Locations Across the Nile: Offering the freedom to choose unique meeting locations for an unparalleled experience.', 'Flexible Event Locations Across the Nile: Offering the freedom to choose unique meeting locations for an unparalleled experience.',
], ],
}, },
{
name: 'Benefits',
items: [
'Unique venue: The natural and historical backdrop of the Nile serves as a source of inspiration and tranquility.',
'Modern Conveniences: Internet, flexible meeting locations, and comprehensive support services facilitate a productive and engaging environment.',
],
},
], ],
} }
const relatedProducts = [
{
id: 1,
name: 'Zip Tote Basket',
color: 'White and black',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-01.jpg',
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.',
price: '$140',
},
{
id: 2,
name: 'Zip High Wall Tote',
color: 'White and blue',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-02.jpg',
imageAlt: 'Front of zip tote bag with white canvas, blue canvas straps and handle, and front zipper pocket.',
price: '$150',
},
{
id: 3,
name: 'Halfsize Tote',
color: 'Clay',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-03.jpg',
imageAlt: 'Front of tote with monochrome natural canvas body, straps, roll top, and handles.',
price: '$210',
},
{
id: 4,
name: 'High Wall Tote',
color: 'Black and orange',
href: '#',
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-03-related-product-04.jpg',
imageAlt: 'Front of zip tote bag with black canvas, black handles, and orange drawstring top.',
price: '$210',
},
]
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export function Events() { export function Events() {
const [open, setOpen] = useState(false)
return ( return (
<div className="pb-24"> <div className="pb-24">
<main className="mx-auto max-w-7xl sm:px-6 sm:pt-24 lg:px-0">
<main className="mx-auto max-w-7xl sm:px-6 sm:pt-16 lg:px-8">
<div className="mx-auto max-w-2xl lg:max-w-none"> <div className="mx-auto max-w-2xl lg:max-w-none">
{/* Product */} {/* Product */}
<div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8"> <div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8">
@@ -152,15 +65,15 @@ export function Events() {
{product.images.map((image) => ( {product.images.map((image) => (
<Tab <Tab
key={image.id} key={image.id}
className="group relative flex h-24 cursor-pointer items-center justify-center rounded-md bg-white text-sm font-medium text-gray-900 uppercase hover:bg-gray-50 focus:ring-3 focus:ring-indigo-500/50 focus:ring-offset-4 focus:outline-hidden" className="group relative flex h-24 cursor-pointer items-center justify-center rounded-md bg-transparent text-sm font-medium text-gray-900 uppercase hover:bg-gray-50 focus:ring-3 focus:ring-indigo-500/50 focus:ring-offset-4 focus:outline-hidden"
> >
<span className="sr-only">{image.name}</span> <span className="sr-only">{image.name}</span>
<span className="absolute inset-0 overflow-hidden rounded-md"> <span className="absolute inset-0 overflow-hidden ">
<img alt="" src={image.src} className="size-full object-cover" /> <img alt="" src={image.src} className="size-full object-cover" />
</span> </span>
<span <span
aria-hidden="true" aria-hidden="true"
className="pointer-events-none absolute inset-0 rounded-md ring-2 ring-transparent ring-offset-2 group-data-selected:ring-indigo-500" className="pointer-events-none absolute inset-0 ring-1 ring-transparent ring-offset-2 group-data-selected:ring-indigo-500"
/> />
</Tab> </Tab>
))} ))}
@@ -170,84 +83,50 @@ export function Events() {
<TabPanels> <TabPanels>
{product.images.map((image) => ( {product.images.map((image) => (
<TabPanel key={image.id}> <TabPanel key={image.id}>
<img alt={image.alt} src={image.src} className="aspect-square w-full object-cover sm:rounded-lg" /> <img alt={image.alt} src={image.src} className="aspect-square w-full object-cover" />
</TabPanel> </TabPanel>
))} ))}
</TabPanels> </TabPanels>
</TabGroup> </TabGroup>
{/* Product info */} {/* Product info */}
<div className="mt-10 px-6 sm:mt-16 sm:px-0 lg:mt-0"> <div className="mt-6 px-6 sm:mt-16 sm:px-0 lg:mt-0">
<h1 className="text-3xl font-bold tracking-tight text-gray-900">{product.name}</h1> <H2>{product.name}</H2>
<div className="mt-3"> <div className="mt-4">
<h2 className="sr-only">Product information</h2>
</div>
{/* Reviews */}
<div className="mt-3">
<h3 className="sr-only">Reviews</h3>
</div>
<div className="mt-6">
<h3 className="sr-only">Description</h3> <h3 className="sr-only">Description</h3>
<div className="space-y-2 text-base text-gray-700">
<div <PS>{product.description}</PS>
dangerouslySetInnerHTML={{ __html: product.description }} </div>
className="space-y-6 text-base text-gray-700"
/>
</div> </div>
<section aria-labelledby="details-heading" className="mt-8">
<div className="space-y-4 border-t border-gray-300 pt-4">
<section aria-labelledby="details-heading" className="mt-12">
<h2 id="details-heading" className="sr-only">
Additional details
</h2>
<div className="divide-y divide-gray-200 border-t border-gray-200">
{product.details.map((detail) => ( {product.details.map((detail) => (
<Disclosure key={detail.name} as="div"> <div key={detail.name}>
<h3> <h3>
<DisclosureButton className="group relative flex w-full items-center justify-between py-6 text-left"> <PS className="font-medium text-gray-900 mb-4">
<span className="text-sm font-medium text-gray-900 group-data-open:text-indigo-600"> {detail.name}
{detail.name} </PS>
</span>
<span className="ml-6 flex items-center">
<PlusIcon
aria-hidden="true"
className="block size-6 text-gray-400 group-hover:text-gray-500 group-data-open:hidden"
/>
<MinusIcon
aria-hidden="true"
className="hidden size-6 text-indigo-400 group-hover:text-indigo-500 group-data-open:block"
/>
</span>
</DisclosureButton>
</h3> </h3>
<DisclosurePanel className="pb-6"> <ul
<ul role="list"
role="list" className="list-disc space-y-2 pl-5 text-sm/6 text-gray-700 marker:text-gray-300"
className="list-disc space-y-1 pl-5 text-sm/6 text-gray-700 marker:text-gray-300" >
> {detail.items.map((item) => (
{detail.items.map((item) => ( <li key={item} className="pl-2 font-light">
<li key={item} className="pl-2"> {item}
{item} </li>
</li> ))}
))} </ul>
</ul> </div>
</DisclosurePanel>
</Disclosure>
))} ))}
</div> </div>
</section> </section>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
</div> </div>
) )
} }

View File

@@ -1,7 +1,7 @@
import { H2, P , PS, PXS, H3, H4 } from "@/components/text"; import { H1, H2, P , PS, PXS, H3, H4 } from "@/components/text";
export function Experiences() { export function Experiences({ onExperienceSelect }) {
return ( return (
<div className="bg-transparent"> <div className="bg-transparent">
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-0 mt-16"> <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-0 mt-16">
@@ -9,50 +9,66 @@ export function Experiences() {
<div className="grid grid-cols-1 gap-4 lg:grid-cols-6 lg:grid-rows-2"> <div className="grid grid-cols-1 gap-4 lg:grid-cols-6 lg:grid-rows-2">
{/* Photo 1 - Left large image */} {/* Photo 1 - Left large image */}
<div className="flex lg:col-span-2 lg:row-span-2"> <div className="flex lg:col-span-2 lg:row-span-2">
<div className="w-full overflow-hidden relative"> <div className="w-full overflow-hidden relative cursor-pointer group" onClick={() => onExperienceSelect('community')}>
<img <img
alt="" alt=""
src="/images/activities/community.jpg" src="/images/activities/community.jpg"
className="h-60 lg:h-full w-full object-cover object-center" className="h-60 lg:h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"
/> />
{/* Black overlay */} {/* Black overlay */}
<div className="absolute inset-0 bg-black opacity-30"></div> <div className="absolute inset-0 bg-black opacity-30 group-hover:opacity-20 transition-opacity duration-300"></div>
{/* Text overlay */}
<div className="absolute inset-0 flex items-center justify-center">
<H2 className="text-white text-center font-semibold group-hover:scale-110 transition-transform duration-300">Community Building</H2>
</div>
</div> </div>
</div> </div>
{/* Photo 2 - Top middle */} {/* Photo 2 - Top middle */}
<div className="flex lg:col-span-2"> <div className="flex lg:col-span-2">
<div className="w-full overflow-hidden relative"> <div className="w-full overflow-hidden relative cursor-pointer group" onClick={() => onExperienceSelect('events')}>
<img <img
alt="" alt=""
src="/images/activities/events.jpg" src="/images/activities/events.jpg"
className="h-60 lg:h-full w-full object-cover object-center" className="h-60 lg:h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"
/> />
{/* Black overlay */} {/* Black overlay */}
<div className="absolute inset-0 bg-black opacity-30"></div> <div className="absolute inset-0 bg-black opacity-30 group-hover:opacity-20 transition-opacity duration-300"></div>
{/* Text overlay */}
<div className="absolute inset-0 flex items-center justify-center">
<H2 className="text-white text-center font-semibold group-hover:scale-110 transition-transform duration-300">Events & Conferences</H2>
</div>
</div> </div>
</div> </div>
{/* Photo 4 - Right large image */} {/* Photo 4 - Right large image */}
<div className="flex lg:col-span-2 lg:row-span-2"> <div className="flex lg:col-span-2 lg:row-span-2">
<div className="w-full overflow-hidden relative"> <div className="w-full overflow-hidden relative cursor-pointer group" onClick={() => onExperienceSelect('retreats')}>
<img <img
alt="" alt=""
src="/images/activities/private.jpg" src="/images/activities/private.jpg"
className="h-80 lg:h-full w-full object-cover object-center" className="h-80 lg:h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"
/> />
{/* Black overlay */} {/* Black overlay */}
<div className="absolute inset-0 bg-black opacity-30"></div> <div className="absolute inset-0 bg-black opacity-30 group-hover:opacity-20 transition-opacity duration-300"></div>
{/* Text overlay */}
<div className="absolute inset-0 flex items-center justify-center">
<H2 className="text-white text-center font-semibold group-hover:scale-110 transition-transform duration-300">Private Retreats</H2>
</div>
</div> </div>
</div> </div>
{/* Photo 3 - Bottom middle */} {/* Photo 3 - Bottom middle */}
<div className="flex lg:col-span-2"> <div className="flex lg:col-span-2">
<div className="w-full overflow-hidden relative"> <div className="w-full overflow-hidden relative cursor-pointer group" onClick={() => onExperienceSelect('nomads')}>
<img <img
alt="" alt=""
src="/images/activities/nomad.jpg" src="/images/activities/nomad.jpg"
className="h-60 lg:h-full w-full object-cover object-center" className="h-60 lg:h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"
/> />
{/* Black overlay */} {/* Black overlay */}
<div className="absolute inset-0 bg-black opacity-30"></div> <div className="absolute inset-0 bg-black opacity-30 group-hover:opacity-20 transition-opacity duration-300"></div>
{/* Text overlay */}
<div className="absolute inset-0 flex items-center justify-center">
<H2 className="text-white text-center font-semibold group-hover:scale-110 transition-transform duration-300">Digital Nomad Hub</H2>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,35 +1,11 @@
'use client'
import { Fragment, useState } from 'react'
import { import {
Dialog,
DialogBackdrop,
DialogPanel,
Disclosure,
DisclosureButton,
DisclosurePanel,
Popover,
PopoverButton,
PopoverGroup,
PopoverPanel,
Tab, Tab,
TabGroup, TabGroup,
TabList, TabList,
TabPanel, TabPanel,
TabPanels, TabPanels,
} from '@headlessui/react' } from '@headlessui/react'
import { import { H2, PS } from '@/components/text'
Bars3Icon,
HeartIcon,
MagnifyingGlassIcon,
MinusIcon,
PlusIcon,
ShoppingBagIcon,
UserIcon,
XMarkIcon,
} from '@heroicons/react/24/outline'
import { StarIcon } from '@heroicons/react/20/solid'
const product = { const product = {
name: 'Digital Nomads Hub', name: 'Digital Nomads Hub',
@@ -59,17 +35,10 @@ const product = {
alt: 'Inspiring workspace for digital nomads', alt: 'Inspiring workspace for digital nomads',
}, },
], ],
colors: [ description: 'A haven for remote workers seeking inspiration, focus, and balance. Our spaces combine reliable connectivity, comfortable work areas, and serene surroundings — creating the perfect environment to blend productivity with rejuvenation.',
{ id: 'washed-black', name: 'Washed Black', classes: 'bg-gray-700 checked:outline-gray-700' },
{ id: 'white', name: 'White', classes: 'bg-white checked:outline-gray-400' },
{ id: 'washed-gray', name: 'Washed Gray', classes: 'bg-gray-500 checked:outline-gray-500' },
],
description: `
<p>A haven for remote workers seeking inspiration, focus, and balance. Our spaces combine reliable connectivity, comfortable work areas, and serene surroundings — creating the perfect environment to blend productivity with rejuvenation.</p>
`,
details: [ details: [
{ {
name: 'Unique Features', name: 'Features',
items: [ items: [
'Dedicated co-working areas onboard and ashore, equipped with reliable high-speed internet and comfortable workstations.', 'Dedicated co-working areas onboard and ashore, equipped with reliable high-speed internet and comfortable workstations.',
'Flexible daily schedules that allow guests to balance focused work sessions with leisure, cultural exploration, and wellness activities.', 'Flexible daily schedules that allow guests to balance focused work sessions with leisure, cultural exploration, and wellness activities.',
@@ -77,96 +46,16 @@ const product = {
'Opportunities to network and collaborate with other professionals, fostering creativity and idea exchange in an inspiring setting.', 'Opportunities to network and collaborate with other professionals, fostering creativity and idea exchange in an inspiring setting.',
], ],
}, },
{
name: 'Benefits',
items: [
'The serene backdrop of the Nile enhances focus, productivity, and creative thinking.',
'A harmonious lifestyle that blends professional output with personal rejuvenation and cultural immersion.',
'Connections with like-minded nomads from around the world, building both professional and personal networks.',
'The freedom to work from anywhere while enjoying the comfort, beauty, and inspiration of an extraordinary travel experience.',
],
},
], ],
} }
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export function Nomads() { export function Nomads() {
const [open, setOpen] = useState(false)
return ( return (
<div className="pb-24"> <div className="pb-24">
<main className="mx-auto max-w-7xl sm:px-6 sm:pt-16 lg:px-8"> <main className="mx-auto max-w-7xl sm:px-6 sm:pt-24 lg:px-0">
<div className="mx-auto max-w-2xl lg:max-w-none"> <div className="mx-auto max-w-2xl lg:max-w-none">
{/* Product */} {/* Product */}
<div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8"> <div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8">
{/* Product info */}
<div className="mt-10 px-6 sm:mt-16 sm:px-0 lg:mt-0">
<h1 className="text-3xl font-bold tracking-tight text-gray-900">{product.name}</h1>
<div className="mt-3">
<h2 className="sr-only">Product information</h2>
</div>
{/* Reviews */}
<div className="mt-3">
<h3 className="sr-only">Reviews</h3>
</div>
<div className="mt-6">
<h3 className="sr-only">Description</h3>
<div
dangerouslySetInnerHTML={{ __html: product.description }}
className="space-y-6 text-base text-gray-700"
/>
</div>
<section aria-labelledby="details-heading" className="mt-12">
<h2 id="details-heading" className="sr-only">
Additional details
</h2>
<div className="divide-y divide-gray-200 border-t border-gray-200">
{product.details.map((detail) => (
<Disclosure key={detail.name} as="div">
<h3>
<DisclosureButton className="group relative flex w-full items-center justify-between py-6 text-left">
<span className="text-sm font-medium text-gray-900 group-data-open:text-indigo-600">
{detail.name}
</span>
<span className="ml-6 flex items-center">
<PlusIcon
aria-hidden="true"
className="block size-6 text-gray-400 group-hover:text-gray-500 group-data-open:hidden"
/>
<MinusIcon
aria-hidden="true"
className="hidden size-6 text-indigo-400 group-hover:text-indigo-500 group-data-open:block"
/>
</span>
</DisclosureButton>
</h3>
<DisclosurePanel className="pb-6">
<ul
role="list"
className="list-disc space-y-1 pl-5 text-sm/6 text-gray-700 marker:text-gray-300"
>
{detail.items.map((item) => (
<li key={item} className="pl-2">
{item}
</li>
))}
</ul>
</DisclosurePanel>
</Disclosure>
))}
</div>
</section>
</div>
{/* Image gallery */} {/* Image gallery */}
<TabGroup className="flex flex-col-reverse"> <TabGroup className="flex flex-col-reverse">
{/* Image selector */} {/* Image selector */}
@@ -175,15 +64,15 @@ export function Nomads() {
{product.images.map((image) => ( {product.images.map((image) => (
<Tab <Tab
key={image.id} key={image.id}
className="group relative flex h-24 cursor-pointer items-center justify-center rounded-md bg-white text-sm font-medium text-gray-900 uppercase hover:bg-gray-50 focus:ring-3 focus:ring-indigo-500/50 focus:ring-offset-4 focus:outline-hidden" className="group relative flex h-24 cursor-pointer items-center justify-center rounded-md bg-transparent text-sm font-medium text-gray-900 uppercase hover:bg-gray-50 focus:ring-3 focus:ring-indigo-500/50 focus:ring-offset-4 focus:outline-hidden"
> >
<span className="sr-only">{image.name}</span> <span className="sr-only">{image.name}</span>
<span className="absolute inset-0 overflow-hidden rounded-md"> <span className="absolute inset-0 overflow-hidden ">
<img alt="" src={image.src} className="size-full object-cover" /> <img alt="" src={image.src} className="size-full object-cover" />
</span> </span>
<span <span
aria-hidden="true" aria-hidden="true"
className="pointer-events-none absolute inset-0 rounded-md ring-2 ring-transparent ring-offset-2 group-data-selected:ring-indigo-500" className="pointer-events-none absolute inset-0 ring-1 ring-transparent ring-offset-2 group-data-selected:ring-indigo-500"
/> />
</Tab> </Tab>
))} ))}
@@ -193,11 +82,47 @@ export function Nomads() {
<TabPanels> <TabPanels>
{product.images.map((image) => ( {product.images.map((image) => (
<TabPanel key={image.id}> <TabPanel key={image.id}>
<img alt={image.alt} src={image.src} className="aspect-square w-full object-cover sm:rounded-lg" /> <img alt={image.alt} src={image.src} className="aspect-square w-full object-cover" />
</TabPanel> </TabPanel>
))} ))}
</TabPanels> </TabPanels>
</TabGroup> </TabGroup>
{/* Product info */}
<div className="mt-6 px-6 sm:mt-16 sm:px-0 lg:mt-0">
<H2>{product.name}</H2>
<div className="mt-4">
<h3 className="sr-only">Description</h3>
<div className="space-y-2 text-base text-gray-700">
<PS>{product.description}</PS>
</div>
</div>
<section aria-labelledby="details-heading" className="mt-8">
<div className="space-y-4 border-t border-gray-300 pt-4">
{product.details.map((detail) => (
<div key={detail.name}>
<h3>
<PS className="font-medium text-gray-900 mb-4">
{detail.name}
</PS>
</h3>
<ul
role="list"
className="list-disc space-y-2 pl-5 text-sm/6 text-gray-700 marker:text-gray-300"
>
{detail.items.map((item) => (
<li key={item} className="pl-2 font-light">
{item}
</li>
))}
</ul>
</div>
))}
</div>
</section>
</div>
</div> </div>
</div> </div>
</main> </main>

View File

@@ -52,14 +52,6 @@ const product = {
'Flexible itineraries: Groups can choose their journey stops, allowing for a tailored experience that can include private tours of historical landmarks, meditation in ancient temples, or leisurely sails to less-known Nile locations.', 'Flexible itineraries: Groups can choose their journey stops, allowing for a tailored experience that can include private tours of historical landmarks, meditation in ancient temples, or leisurely sails to less-known Nile locations.',
], ],
}, },
{
name: 'Benefits',
items: [
'The tranquil and culturally rich environment of the Nile encourages reflection, ideation, and personal growth.',
'The fusion of personalized wellness, cultural immersion, and luxury in a private setting ensures a unique journey that aligns with the group\'s interests.',
'Retreats are adaptable in length and activities, allowing for a program that perfectly fits the group\'s schedule and desired outcomes, whether for a few days or an extended period.',
],
},
], ],
} }
@@ -70,7 +62,7 @@ function classNames(...classes) {
export function Retreats() { export function Retreats() {
return ( return (
<div className="pb-24"> <div className="pb-24">
<main className="mx-auto max-w-7xl sm:px-6 sm:pt-12 lg:px-8"> <main className="mx-auto max-w-7xl sm:px-6 sm:pt-12 lg:px-0">
<div className="mx-auto max-w-2xl lg:max-w-none"> <div className="mx-auto max-w-2xl lg:max-w-none">
{/* Product */} {/* Product */}
<div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8"> <div className="lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8">