Skip to content

Commit bc79107

Browse files
authored
Merge pull request #36 from sinfo/francisca105/home-speakers
Speakers announcement
2 parents 095b939 + c1be278 commit bc79107

File tree

17 files changed

+621
-260
lines changed

17 files changed

+621
-260
lines changed

src/app/(root)/page.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ import SpeakersHighlight from "@/components/Home/SpeakersHighlight";
44
import AboutUs from "@/components/Home/AboutUs";
55
import SponsorsPartners from "@/components/Home/SponsorsPartners";
66
import FAQ from "@/components/Home/FAQ";
7+
import CurrentSpeakersHighlight from "@/components/Home/CurrentSpeakersHighlight";
78

89
export default async function Root() {
910
return (
1011
<main className="flex flex-col">
1112
<HeroSection />
12-
<SpeakersHighlight backgroundClass="bg-white" />
13-
<EventSection backgroundClass="bg-sinfo-light" />
14-
<AboutUs backgroundClass="bg-white" />
15-
<SponsorsPartners backgroundClass="bg-sinfo-light" />
16-
<FAQ backgroundClass="bg-white" />
13+
<CurrentSpeakersHighlight backgroundClass="bg-sinfo-light" />
14+
{/* <SpeakersHighlight backgroundClass="bg-white" /> */}
15+
<EventSection backgroundClass="bg-white" />
16+
<AboutUs backgroundClass="bg-sinfo-light" />
17+
<SponsorsPartners backgroundClass="bg-white" />
18+
<FAQ backgroundClass="bg-sinfo-light" />
1719
</main>
1820
);
1921
}

src/app/speakers/[id]/page.tsx

Lines changed: 117 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import React from "react";
22
import Link from "next/link";
33
import { SpeakerService } from "@/services/SpeakerService";
4-
import {
5-
generateTimeInterval,
6-
getEventDay,
7-
getEventMonth,
8-
} from "@/utils/utils";
4+
import { SessionService } from "@/services/SessionService";
5+
import { generateTimeInterval } from "@/utils/utils";
96
import ImageWithFallback from "@/components/ImageWithFallback";
7+
import { ShowMore } from "@/components/ShowMore";
8+
import { Calendar, Clock, MapPin } from "lucide-react";
109

1110
export const dynamic = "force-dynamic";
1211

@@ -16,22 +15,10 @@ type Props = {
1615
};
1716
};
1817

19-
export async function generateMetadata({ params }: Props) {
20-
const speaker = await SpeakerService.getSpeaker(params.id);
21-
return {
22-
title: speaker ? `${speaker.name} • SINFO` : "Speaker • SINFO",
23-
description: speaker?.description || "Speaker details",
24-
openGraph: speaker
25-
? {
26-
images: speaker.img ? [speaker.img] : undefined,
27-
}
28-
: undefined,
29-
} as any;
30-
}
31-
3218
export default async function Page({ params }: Props) {
3319
const { id } = params;
3420
const speaker = await SpeakerService.getSpeaker(id);
21+
const session = await SessionService.getSessionBySpeaker(id);
3522

3623
if (!speaker) {
3724
return (
@@ -52,197 +39,133 @@ export default async function Page({ params }: Props) {
5239
);
5340
}
5441

55-
const mainSession = speaker.sessions?.[0];
56-
const sessionTitle = mainSession?.name;
57-
const formattedDate = mainSession?.date
58-
? `${getEventMonth(mainSession.date, false)} ${getEventDay(mainSession.date)}`
59-
: undefined;
60-
const timeRange = mainSession?.date
61-
? generateTimeInterval(mainSession.date, mainSession?.duration ?? 0, {
62-
onlyHours: true,
63-
})
64-
: undefined;
65-
const sessionPlace = mainSession?.place || "Main Stage";
66-
67-
const SpeakerPhoto = ({ className = "" }: { className?: string }) => (
68-
<div className={`relative flex justify-center ${className}`}>
69-
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 md:-translate-x-[60%] -translate-y-1/2 w-[340px] h-[340px] md:w-[380px] md:h-[380px] bg-sinfo-quinary rounded-full overflow-hidden shadow-2xl">
70-
<ImageWithFallback
71-
src={speaker.img}
72-
alt={speaker.name}
73-
className="absolute inset-0 w-full h-full object-contain"
74-
sizes="(max-width: 768px) 100vw, 50vw"
75-
width={380}
76-
height={380}
77-
/>
78-
</div>
79-
</div>
80-
);
81-
82-
const SessionInfo = ({ className = "" }: { className?: string }) =>
83-
mainSession ? (
84-
<div className={`text-white ${className}`}>
85-
<p className="font-bold text-xl md:text-2xl">{sessionPlace}</p>
86-
<p className="text-lg md:text-xl">
87-
{formattedDate || "February 17"}{timeRange || "16h30-17h20"}
88-
</p>
89-
</div>
90-
) : null;
91-
92-
const SessionTitleBox = ({ className = "" }: { className?: string }) =>
93-
sessionTitle ? (
94-
<div
95-
className={`bg-sinfo-primary border-4 border-white rounded-lg p-6 shadow-xl w-fit ${className}`}
96-
>
97-
<p className="text-sinfo-quinary font-black uppercase text-2xl md:text-3xl leading-tight">
98-
{sessionTitle}
99-
</p>
100-
</div>
101-
) : null;
102-
10342
return (
104-
<main className="w-full min-h-screen bg-sinfo-primary relative overflow-hidden">
105-
{/* Decorative circles */}
106-
<div className="absolute left-0 bottom-0 w-28 h-28 md:w-40 md:h-40 bg-sinfo-tertiary rounded-tr-full z-10" />
107-
<div className="absolute right-0 bottom-0 w-28 h-28 md:w-40 md:h-40 bg-sinfo-secondary rounded-tl-full z-10" />
108-
109-
{/* Glowing line separator - positioned where circles end */}
110-
<div className="absolute bottom-0 md:bottom-0 left-0 right-0 z-[5]">
111-
<div className="w-full h-[3px] bg-gradient-to-r from-transparent via-white/50 to-transparent animate-pulse shadow-[0_0_10px_rgba(255,255,255,0.5)]" />
112-
</div>
113-
114-
<div className="relative max-w-7xl mx-auto px-6 md:px-10 py-12 md:py-16">
115-
{/* Top decorative elements - only visible on desktop */}
116-
<div className="hidden md:block absolute top-4 right-8 md:top-6 md:right-16 z-20">
117-
<ImageWithFallback
118-
src="/images/decorative-images/redElement.svg"
119-
alt="Decorative element"
120-
width={80}
121-
height={80}
122-
className="w-16 h-16 md:w-20 md:h-20"
123-
/>
43+
<main className="min-h-screen bg-white">
44+
{/* Hero Section */}
45+
<section className="bg-gradient-to-br from-sinfo-primary via-sinfo-primary to-sinfo-secondary py-16 sm:py-20 md:py-24">
46+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
47+
<div className="text-center">
48+
<h1 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-4 sm:mb-6">
49+
Speakers
50+
</h1>
51+
<p className="text-base sm:text-lg md:text-xl text-white/90 max-w-3xl mx-auto">
52+
Meet the global voices that are shaping SINFO&apos;s excellence.
53+
</p>
54+
</div>
12455
</div>
125-
126-
{/* Main grid */}
127-
<div className="flex flex-col md:grid md:grid-cols-2 gap-8 md:gap-12 md:items-start">
128-
{/* Mobile layout - custom order */}
129-
<div className="md:hidden space-y-8 relative">
130-
{/* 1. Name and title */}
131-
<div>
132-
<h1 className="text-6xl font-black uppercase leading-[0.85] tracking-tight text-white">
56+
</section>
57+
58+
{/* Main Content */}
59+
<section className="py-12 sm:py-16 md:py-20">
60+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
61+
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
62+
{/* Left Column - Info */}
63+
<div className="lg:col-span-7 xl:col-span-8 order-2 lg:order-1">
64+
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-2">
13365
{speaker.name}
13466
</h1>
135-
{(speaker.title || speaker.company?.name) && (
136-
<p className="mt-4 text-sinfo-tertiary text-xl font-bold">
137-
{speaker.title}
138-
</p>
139-
)}
140-
</div>
67+
<h2 className="text-xl md:text-2xl text-sinfo-primary font-medium mb-8">
68+
{speaker.title}
69+
{speaker.company?.name && (
70+
<span className="text-gray-500">
71+
, {speaker.company.name}
72+
</span>
73+
)}
74+
</h2>
75+
76+
<div className="prose prose-lg text-gray-600 max-w-none mb-12 whitespace-pre-line">
77+
{speaker.description}
78+
</div>
14179

142-
{/* Red element decoration after title, before photo */}
143-
<div className="flex justify-end -mb-14">
144-
<ImageWithFallback
145-
src="/images/decorative-images/redElement.svg"
146-
alt="Decorative element"
147-
width={56}
148-
height={56}
149-
className="w-16 h-16"
150-
/>
80+
{/* Sessions */}
81+
{speaker.sessions && speaker.sessions.length > 0 && (
82+
<div className="border-t border-gray-200 pt-8">
83+
<h3 className="text-2xl font-bold text-sinfo-primary mb-6">
84+
Sessions
85+
</h3>
86+
<div className="space-y-6">
87+
{speaker.sessions.map((session) => {
88+
const dateStr = session.date
89+
? new Date(session.date).toLocaleDateString("en-GB", {
90+
day: "numeric",
91+
month: "short",
92+
year: "numeric",
93+
})
94+
: "";
95+
const timeStr = session.date
96+
? generateTimeInterval(
97+
session.date,
98+
session.duration || 0,
99+
{ onlyHours: true },
100+
)
101+
: "";
102+
103+
return (
104+
<div
105+
key={session.id}
106+
className="bg-gray-50 rounded-lg p-6 hover:shadow-md transition-shadow"
107+
>
108+
<div className="flex flex-wrap gap-y-2 gap-x-6 text-sm font-semibold text-sinfo-secondary mb-3">
109+
{session.date && (
110+
<div className="flex items-center gap-1.5">
111+
<Calendar className="w-4 h-4" />
112+
<span>{dateStr}</span>
113+
</div>
114+
)}
115+
{timeStr && (
116+
<div className="flex items-center gap-1.5">
117+
<Clock className="w-4 h-4" />
118+
<span>{timeStr}</span>
119+
</div>
120+
)}
121+
{session.place && (
122+
<div className="flex items-center gap-1.5">
123+
<MapPin className="w-4 h-4" />
124+
<span>{session.place}</span>
125+
</div>
126+
)}
127+
</div>
128+
<h4 className="text-xl font-bold text-gray-900">
129+
{session.name}
130+
</h4>
131+
{session.description && (
132+
<ShowMore lines={3} className="mt-2 text-gray-600">
133+
{session.description}
134+
</ShowMore>
135+
)}
136+
</div>
137+
);
138+
})}
139+
</div>
140+
</div>
141+
)}
151142
</div>
152143

153-
{/* 2. Photo with decorative elements */}
154-
<div className="space-y-8 relative -mt-14">
155-
{/* Speaker photo with yellow background */}
156-
<SpeakerPhoto className="h-80" />
157-
158-
{/* Small decorative box */}
159-
<div className="max-w-[180px] -mt-9">
144+
{/* Right Column - Image */}
145+
<div className="lg:col-span-5 xl:col-span-4 order-1 lg:order-2">
146+
<div className="relative aspect-square w-full max-w-md mx-auto rounded-full overflow-hidden shadow-xl bg-gray-200">
160147
<ImageWithFallback
161-
src="/images/decorative-images/star.svg"
162-
alt="Decorative star"
163-
width={100}
164-
height={100}
165-
className="w-20 h-20"
148+
src={speaker.img}
149+
alt={speaker.name}
150+
fill
151+
className="object-cover"
152+
sizes="(max-width: 768px) 100vw, 33vw"
166153
/>
167154
</div>
168155
</div>
169-
170-
{/* 3. Description box */}
171-
<div className="bg-sinfo-light rounded-lg p-8 text-black flex items-center relative">
172-
<p className="text-base font-bold leading-relaxed whitespace-pre-line">
173-
{speaker.description || "Texto texto bla bla"}
174-
</p>
175-
</div>
176-
177-
{/* 4. Session title box */}
178-
<SessionTitleBox />
179-
180-
{/* 5. Session info */}
181-
<SessionInfo />
182156
</div>
183157

184-
{/* Desktop layout - original two columns */}
185-
<div className="hidden md:block space-y-8">
186-
{/* Name */}
187-
<div>
188-
<h1 className="text-7xl lg:text-8xl font-black uppercase leading-[0.85] tracking-tight text-white">
189-
{speaker.name}
190-
</h1>
191-
{(speaker.title || speaker.company?.name) && (
192-
<p className="mt-4 text-sinfo-tertiary text-2xl font-bold">
193-
{speaker.title}
194-
</p>
195-
)}
196-
</div>
197-
198-
{/* Description box with light background */}
199-
<div className="bg-sinfo-light rounded-lg p-10 text-black flex items-center">
200-
<p className="text-lg font-bold leading-relaxed whitespace-pre-line">
201-
{speaker.description || "Texto texto bla bla"}
202-
</p>
203-
</div>
204-
205-
{/* Session info */}
206-
<SessionInfo />
207-
</div>
208-
209-
{/* Desktop right column - Photo and session title */}
210-
<div className="hidden md:block space-y-8 relative">
211-
{/* Speaker photo with yellow background */}
212-
<SpeakerPhoto className="h-[340px]" />
213-
214-
{/* Decorative plus */}
215-
<div className="absolute right-8 top-1/2 w-20 h-20">
216-
<span className="absolute left-1/2 top-0 bottom-0 w-[4px] bg-white -translate-x-1/2" />
217-
<span className="absolute top-1/2 left-0 right-0 h-[4px] bg-white -translate-y-1/2" />
218-
</div>
219-
220-
{/* Small decorative box */}
221-
<div className="max-w-[180px] -mt-9">
222-
<ImageWithFallback
223-
src="/images/decorative-images/star.svg"
224-
alt="Decorative star"
225-
width={100}
226-
height={100}
227-
className="w-24 h-24"
228-
/>
229-
</div>
230-
231-
{/* Session title box */}
232-
<SessionTitleBox />
158+
{/* Back Button */}
159+
<div className="mt-12 text-center">
160+
<Link
161+
href="/speakers"
162+
className="inline-flex items-center px-6 py-3 bg-sinfo-primary text-white rounded-lg font-semibold hover:opacity-95 transition"
163+
>
164+
&larr; Back to all speakers
165+
</Link>
233166
</div>
234167
</div>
235-
236-
{/* Bottom CTA button */}
237-
<div className="mt-12 md:mt-16 flex justify-center relative z-10">
238-
<Link
239-
href="/speakers"
240-
className="bg-sinfo-senary text-white font-black py-5 px-16 md:py-6 md:px-20 rounded-full text-xl md:text-2xl uppercase shadow-2xl hover:opacity-90 transition-opacity"
241-
>
242-
SEE ALL SPEAKERS
243-
</Link>
244-
</div>
245-
</div>
168+
</section>
246169
</main>
247170
);
248171
}

0 commit comments

Comments
 (0)