add program and speaker detail pages with routing

This commit is contained in:
Alisa Cantillo-Olsson 2026-04-27 23:59:54 +02:00
parent 9d5f1fc841
commit 59a03518b5
7 changed files with 489 additions and 28 deletions

View File

@ -1,7 +1,9 @@
import { Routes, Route } from "react-router-dom"; import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home"; import Home from "./pages/Home";
import Programm from "./pages/Programm"; import Programm from "./pages/Programm";
import ProgrammDetail from "./pages/ProgrammDetail";
import Speaker from "./pages/Speaker"; import Speaker from "./pages/Speaker";
import SpeakerDetail from "./pages/SpeakerDetail";
import Tickets from "./pages/Tickets"; import Tickets from "./pages/Tickets";
function App() { function App() {
@ -9,7 +11,9 @@ function App() {
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/programm" element={<Programm />} /> <Route path="/programm" element={<Programm />} />
<Route path="/programm/:id" element={<ProgrammDetail />} />
<Route path="/speaker" element={<Speaker />} /> <Route path="/speaker" element={<Speaker />} />
<Route path="/speaker/:slug" element={<SpeakerDetail />} />
<Route path="/tickets" element={<Tickets />} /> <Route path="/tickets" element={<Tickets />} />
</Routes> </Routes>
); );

View File

@ -8,11 +8,14 @@ export type ProgramEvent = {
time: string; time: string;
image: { src: string; alt: string }; image: { src: string; alt: string };
title: string; title: string;
subtitle?: string;
speaker: string; speaker: string;
speakerSlug?: string;
type: EventType; type: EventType;
level: EventLevel; level: EventLevel;
day: EventDay; day: EventDay;
speakerUrl: string; speakerUrl: string;
description?: string;
}; };
type Props = { type Props = {
@ -34,7 +37,9 @@ const EventRow = ({ event }: { event: ProgramEvent }) => (
</div> </div>
<div> <div>
<h5 className="text-lg font-bold text-tech-navy">{event.title}</h5> <a href={`/programm/${event.id}`} className="hover:underline">
<h5 className="text-lg font-bold text-tech-navy">{event.title}</h5>
</a>
<p className="text-sm text-gray-500">{event.speaker}</p> <p className="text-sm text-gray-500">{event.speaker}</p>
</div> </div>

View File

@ -3,6 +3,7 @@ import speaker2 from "../assets/speakers/speaker2.jpg";
import speaker3 from "../assets/speakers/speaker3.jpg"; import speaker3 from "../assets/speakers/speaker3.jpg";
import speaker4 from "../assets/speakers/speaker4.jpg"; import speaker4 from "../assets/speakers/speaker4.jpg";
import { BiLogoLinkedinSquare } from "react-icons/bi"; import { BiLogoLinkedinSquare } from "react-icons/bi";
import { Link } from "react-router-dom";
type ImageProps = { type ImageProps = {
src: string; src: string;
@ -26,7 +27,10 @@ export type TeamMember = {
company: string; company: string;
companyUrl?: string; companyUrl?: string;
description: string; description: string;
fullBio?: string;
category: string; category: string;
location?: string;
slug: string;
talks: Talk[]; talks: Talk[];
socialLinks: SocialLink[]; socialLinks: SocialLink[];
}; };
@ -45,14 +49,16 @@ const talkBadgeClass = (type: Talk["type"]) => {
const MemberCard = ({ member }: { member: TeamMember }) => ( const MemberCard = ({ member }: { member: TeamMember }) => (
<div className="flex flex-col font-barlow"> <div className="flex flex-col font-barlow">
<div className="relative mb-5 aspect-square w-full overflow-hidden"> <Link to={`/speaker/${member.slug}`} className="relative mb-5 aspect-square w-full overflow-hidden block">
<img <img
src={member.image.src} src={member.image.src}
alt={member.image.alt} alt={member.image.alt}
className="absolute inset-0 size-full object-cover" className="absolute inset-0 size-full object-cover hover:scale-105 transition-transform duration-300"
/> />
</div> </Link>
<h5 className="text-md font-bold md:text-lg">{member.name}</h5> <Link to={`/speaker/${member.slug}`} className="hover:underline">
<h5 className="text-md font-bold md:text-lg">{member.name}</h5>
</Link>
<p className="text-sm text-gray-600">{member.role}</p> <p className="text-sm text-gray-600">{member.role}</p>
<a <a
href={member.companyUrl ?? "#"} href={member.companyUrl ?? "#"}
@ -108,8 +114,12 @@ export const Team4Defaults: Props = {
name: "Jens Riegelsberger", name: "Jens Riegelsberger",
role: "UX Director", role: "UX Director",
company: "Google", company: "Google",
slug: "jens-riegelsberger",
location: "London, Vereinigtes Königreich",
description: description:
"Jens leitet die UX-Teams für Search und Maps sowie die globale UXR-Infrastruktur. Der HCI-Experte lehrte als Gastprofessor an der UdK Berlin und bringt Erfahrung von Stationen bei Microsoft Research, Amazon und Apple mit.", "Jens leitet die UX-Teams für Search und Maps sowie die globale UXR-Infrastruktur. Der HCI-Experte lehrte als Gastprofessor an der UdK Berlin und bringt Erfahrung von Stationen bei Microsoft Research, Amazon und Apple mit.",
fullBio:
"Jens Riegelsberger ist UX Director bei Google und leitet die UX-Teams für die Bereiche Search, Maps und Nutzerkonten sowie das UXR-Infrastruktur-team von Google. Er promovierte an der University College London im Bereich Mensch-Computer-Interaktion und war stellvertretender Herausgeber des IJHCS. Bevor er zu Google kam, arbeitete Jens bei der UX-Beratungsfirma LBi und lehrte als Gastprofessor an der Universität der Künste Berlin; zu seinen früheren beruflichen Stationen zählen Tätigkeiten bei Microsoft Research, Amazon und Apple.",
category: "Research", category: "Research",
talks: [ talks: [
{ title: "Talk: Scaling Research", type: "Talk" }, { title: "Talk: Scaling Research", type: "Talk" },
@ -122,8 +132,12 @@ export const Team4Defaults: Props = {
name: "Marcus J. Low", name: "Marcus J. Low",
role: "Principal Designer", role: "Principal Designer",
company: "Airbnb", company: "Airbnb",
slug: "marcus-j-low",
location: "San Francisco, USA",
description: description:
"Als Mitentwickler des ersten Airbnb Design Systems spricht Marcus über die Balance zwischen Markenästhetik und funktionaler Logik.", "Als Mitentwickler des ersten Airbnb Design Systems spricht Marcus über die Balance zwischen Markenästhetik und funktionaler Logik.",
fullBio:
"Marcus J. Low ist Principal Designer bei Airbnb und war massgeblich an der Entwicklung des ersten Airbnb Design Systems beteiligt. Er spricht über die Balance zwischen Markenästhetik und funktionaler Logik und teilt seine Erfahrungen aus über 10 Jahren in der Produktgestaltung für globale Plattformen.",
category: "Design / UX", category: "Design / UX",
talks: [{ title: "Workshop: The Future of Tokens", type: "Workshop" }], talks: [{ title: "Workshop: The Future of Tokens", type: "Workshop" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -133,8 +147,12 @@ export const Team4Defaults: Props = {
name: "Reto Gwerder", name: "Reto Gwerder",
role: "Head of Product", role: "Head of Product",
company: "Ginetta", company: "Ginetta",
slug: "reto-gwerder",
location: "Zürich, Schweiz",
description: description:
"Reto steht für Schweizer Design-Qualität. Er analysiert, warum Simplizität oft die größte technische Herausforderung ist.", "Reto steht für Schweizer Design-Qualität. Er analysiert, warum Simplizität oft die größte technische Herausforderung ist.",
fullBio:
"Reto Gwerder ist Head of Product bei Ginetta und steht für konsequente Schweizer Design-Qualität. Er analysiert, warum Simplizität oft die größte technische Herausforderung ist und wie man in einem schnellen Produktumfeld trotzdem Qualität bewahrt.",
category: "Strategie", category: "Strategie",
talks: [{ title: "Talk: Simplify or Die", type: "Talk" }], talks: [{ title: "Talk: Simplify or Die", type: "Talk" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -144,8 +162,12 @@ export const Team4Defaults: Props = {
name: "Dr. Elena Rossi", name: "Dr. Elena Rossi",
role: "Cognitive Psychologist", role: "Cognitive Psychologist",
company: "University of Milan", company: "University of Milan",
slug: "dr-elena-rossi",
location: "Mailand, Italien",
description: description:
"Elena verbindet Wissenschaft mit Design. Sie erklärt, wie unser Gehirn auf Micro-Interactions reagiert und wann wir uns manipuliert fühlen.", "Elena verbindet Wissenschaft mit Design. Sie erklärt, wie unser Gehirn auf Micro-Interactions reagiert und wann wir uns manipuliert fühlen.",
fullBio:
"Dr. Elena Rossi ist Kognitionspsychologin an der Universität Mailand und verbindet Wissenschaft mit Design. Sie erklärt, wie unser Gehirn auf Micro-Interactions reagiert und wann wir uns manipuliert fühlen. Elena forscht seit über einem Jahrzehnt zur Schnittstelle von Psychologie und digitaler Produktgestaltung.",
category: "Psychologie", category: "Psychologie",
talks: [{ title: "Deep Dive: Psychological UX", type: "Talk" }], talks: [{ title: "Deep Dive: Psychological UX", type: "Talk" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -155,8 +177,12 @@ export const Team4Defaults: Props = {
name: "Liam O'Connor", name: "Liam O'Connor",
role: "Lead Product Designer", role: "Lead Product Designer",
company: "Spotify", company: "Spotify",
slug: "liam-oconnor",
location: "Stockholm, Schweden",
description: description:
"Liam gibt Einblicke, wie Spotify Personalisierung nutzt, ohne die Privatsphäre der Nutzer zu verletzen.", "Liam gibt Einblicke, wie Spotify Personalisierung nutzt, ohne die Privatsphäre der Nutzer zu verletzen.",
fullBio:
"Liam O'Connor ist Lead Product Designer bei Spotify und gibt Einblicke, wie das Unternehmen Personalisierung nutzt, ohne die Privatsphäre der Nutzer zu verletzen. Er arbeitet an der Schnittstelle von Daten, Design und Ethik.",
category: "AI & Future", category: "AI & Future",
talks: [{ title: "Talk: Trust in AI UX", type: "Talk" }], talks: [{ title: "Talk: Trust in AI UX", type: "Talk" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -166,8 +192,12 @@ export const Team4Defaults: Props = {
name: "Fabienne Keller", name: "Fabienne Keller",
role: "Gründerin", role: "Gründerin",
company: "User-First Agency", company: "User-First Agency",
slug: "fabienne-keller",
location: "Basel, Schweiz",
description: description:
"Fabienne ist Expertin für User Research in komplexen B2B-Umfeldern und wie man Stakeholder von Test-Ergebnissen überzeugt.", "Fabienne ist Expertin für User Research in komplexen B2B-Umfeldern und wie man Stakeholder von Test-Ergebnissen überzeugt.",
fullBio:
"Fabienne Keller ist Gründerin der User-First Agency und Expertin für User Research in komplexen B2B-Umfeldern. Sie zeigt, wie man Stakeholder von Test-Ergebnissen überzeugt und eine nachhaltige Research-Kultur in Unternehmen aufbaut.",
category: "Research", category: "Research",
talks: [{ title: "Workshop: Research Repositories", type: "Workshop" }], talks: [{ title: "Workshop: Research Repositories", type: "Workshop" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -177,8 +207,12 @@ export const Team4Defaults: Props = {
name: 'Thomas "Tom" Meyer', name: 'Thomas "Tom" Meyer',
role: "Creative Director", role: "Creative Director",
company: "Swisscom", company: "Swisscom",
slug: "thomas-meyer",
location: "Bern, Schweiz",
description: description:
"Tom zeigt, wie man in großen Konzernen eine Design-Kultur etabliert, die über das visuelle Layer hinausgeht.", "Tom zeigt, wie man in großen Konzernen eine Design-Kultur etabliert, die über das visuelle Layer hinausgeht.",
fullBio:
'Thomas "Tom" Meyer ist Creative Director bei Swisscom und zeigt, wie man in großen Konzernen eine Design-Kultur etabliert, die über das visuelle Layer hinausgeht. Er bringt über 15 Jahre Erfahrung im Corporate Design Management mit.',
category: "Strategie", category: "Strategie",
talks: [{ title: "Networking: Leading Teams", type: "Networking" }], talks: [{ title: "Networking: Leading Teams", type: "Networking" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],
@ -188,8 +222,12 @@ export const Team4Defaults: Props = {
name: "Sarah M. Widmer", name: "Sarah M. Widmer",
role: "Senior UX Architect", role: "Senior UX Architect",
company: "SBB", company: "SBB",
slug: "sarah-m-widmer",
location: "Bern, Schweiz",
description: description:
"Sarah gestaltet die Mobilität von morgen. Sie zeigt, wie man Millionen von Nutzern barrierefrei durch den digitalen öV-Dschungel leitet.", "Sarah gestaltet die Mobilität von morgen. Sie zeigt, wie man Millionen von Nutzern barrierefrei durch den digitalen öV-Dschungel leitet.",
fullBio:
"Sarah M. Widmer ist Senior UX Architect bei der SBB und gestaltet die Mobilität von morgen. Sie zeigt, wie man Millionen von Nutzern barrierefrei durch den digitalen öV-Dschungel leitet und dabei Accessibility nicht als Pflicht, sondern als Designprinzip versteht.",
category: "Design / UX", category: "Design / UX",
talks: [{ title: "Talk: Inclusive Design at Scale", type: "Talk" }], talks: [{ title: "Talk: Inclusive Design at Scale", type: "Talk" }],
socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }], socialLinks: [{ href: "#", icon: <BiLogoLinkedinSquare className="size-6" /> }],

View File

@ -0,0 +1,175 @@
import spk1 from "../assets/speakers/speaker1.jpg";
import spk2 from "../assets/speakers/speaker2.jpg";
import spk3 from "../assets/speakers/speaker3.jpg";
import spk4 from "../assets/speakers/speaker4.jpg";
import type { ProgramEvent } from "../components/Event33";
export const ALL_EVENTS: ProgramEvent[] = [
// Donnerstag
{
id: "do-1",
time: "10:00 11:30 Uhr",
image: { src: spk1, alt: "Jens Riegelsberger" },
title: "Opening Keynote: The Future of UX",
subtitle: "Wie KI, Ethik und Nutzerzentriertheit die nächste UX-Ära prägen",
speaker: "Jens Riegelsberger",
speakerSlug: "jens-riegelsberger",
type: "Talk",
level: "Senior",
day: "Donnerstag",
speakerUrl: "/speaker/jens-riegelsberger",
description:
"In dieser Keynote zeigt Jens Riegelsberger, wie Google seine UX-Teams für Search und Maps aufgebaut hat und welche Rolle Nutzerzentriertheit, Ethik und KI in der nächsten Designgeneration spielen werden. Ein Muss für alle, die verstehen wollen, wohin sich UX in den nächsten fünf Jahren bewegt.",
},
{
id: "do-2",
time: "12:00 13:00 Uhr",
image: { src: spk2, alt: "Marcus J. Low" },
title: "Workshop: Design Systems at Scale",
subtitle: "Wie Airbnb seine Designsprache global skaliert",
speaker: "Marcus J. Low",
speakerSlug: "marcus-j-low",
type: "Workshop",
level: "Mid-Level",
day: "Donnerstag",
speakerUrl: "/speaker/marcus-j-low",
description:
"Als Mitentwickler des ersten Airbnb Design Systems spricht Marcus über die Balance zwischen Markenästhetik und funktionaler Logik. In diesem Workshop lernst du, wie du ein Design System aufbaust, das wächst ohne zu brechen.",
},
{
id: "do-3",
time: "14:00 15:30 Uhr",
image: { src: spk3, alt: "Reto Gwerder" },
title: "Interaction: Prototyping Fast",
subtitle: "Schnell iterieren ohne Qualitätsverlust",
speaker: "Reto Gwerder",
speakerSlug: "reto-gwerder",
type: "Interaction",
level: "Junior",
day: "Donnerstag",
speakerUrl: "/speaker/reto-gwerder",
description:
"Reto zeigt, wie du mit minimalem Aufwand maximale Erkenntnisse aus Prototypen ziehst. Praktische Methoden für schnelles Iterieren, ohne die Qualität zu opfern.",
},
{
id: "do-4",
time: "16:00 17:30 Uhr",
image: { src: spk4, alt: "Dr. Elena Rossi" },
title: "AI and Future: Intelligence in Design",
subtitle: "Wenn Algorithmen mitgestalten Chancen und Risiken",
speaker: "Dr. Elena Rossi",
speakerSlug: "dr-elena-rossi",
type: "AI and Future",
level: "Senior",
day: "Donnerstag",
speakerUrl: "/speaker/dr-elena-rossi",
description:
"Dr. Elena Rossi untersucht die psychologischen Auswirkungen von KI-gestütztem Design auf Nutzer. Wann erleben wir KI als hilfreich und wann als manipulativ? Ein tiefes Tauchen in die Kognitionspsychologie des digitalen Zeitalters.",
},
{
id: "do-5",
time: "18:00 19:30 Uhr",
image: { src: spk1, alt: "Liam O'Connor" },
title: "Talk: Ethical AI",
subtitle: "Verantwortungsvolles Design in der KI-Ära",
speaker: "Liam O'Connor",
speakerSlug: "liam-oconnor",
type: "Talk",
level: "Mid-Level",
day: "Donnerstag",
speakerUrl: "/speaker/liam-oconnor",
description:
"Liam O'Connor gibt Einblicke, wie Spotify mit ethischen Fragen rund um personalisierte Empfehlungen umgeht. Was bedeutet es, verantwortungsvoll zu gestalten, wenn Algorithmen Entscheidungen treffen?",
},
// Freitag
{
id: "fr-1",
time: "12:00 13:30 Uhr",
image: { src: spk1, alt: "Jens Riegelsberger" },
title: "Scaling Research",
subtitle: "Vom Engpass zum Motor: Scaling Research ohne Qualitätsverlust",
speaker: "Jens Riegelsberger",
speakerSlug: "jens-riegelsberger",
type: "Talk",
level: "Senior",
day: "Freitag",
speakerUrl: "/speaker/jens-riegelsberger",
description:
"Jeder will Insights, aber dein Research-Team wächst nicht so schnell wie der Backlog? Willkommen im Club. Wenn die Nachfrage nach Nutzererkenntnissen explodiert, wird das Research-Team oft zum Flaschenhals. Aber \"Scaling Research\" bedeutet nicht einfach, mehr Überstunden zu machen oder wahllos Tools zu kaufen. Es geht darum, Systeme zu schaffen, die Wissen demokratisieren, ohne die methodische Integrität zu opfern. In diesem interaktiven Workshop räumen wir mit dem Mythos auf, dass Research nur von Researchern gemacht werden kann. Wir zeigen dir, wie du Research Ops sinnvoll aufbaust, Nicht-Researcher befähigst und eine Kultur schaffst, in der Insights fließen statt zu verstauben.",
},
{
id: "fr-2",
time: "12:00 13:00 Uhr",
image: { src: spk2, alt: "Marcus J. Low" },
title: "Workshop: The Future of Tokens",
subtitle: "Design Tokens als Brücke zwischen Design und Entwicklung",
speaker: "Marcus J. Low",
speakerSlug: "marcus-j-low",
type: "Workshop",
level: "Mid-Level",
day: "Freitag",
speakerUrl: "/speaker/marcus-j-low",
description:
"Design Tokens sind mehr als nur Variablen. Marcus zeigt, wie du ein Token-System aufbaust, das Design und Entwicklung wirklich verbindet und auf alle Plattformen skaliert.",
},
{
id: "fr-3",
time: "14:00 15:30 Uhr",
image: { src: spk3, alt: "Reto Gwerder" },
title: "Talk: Simplify or Die",
subtitle: "Warum Simplizität die härteste Designentscheidung ist",
speaker: "Reto Gwerder",
speakerSlug: "reto-gwerder",
type: "Talk",
level: "Junior",
day: "Freitag",
speakerUrl: "/speaker/reto-gwerder",
description:
"Reto Gwerder analysiert, warum Simplizität oft die größte technische und gestalterische Herausforderung ist. Weniger ist mehr aber wie schafft man es, wirklich weniger zu machen?",
},
{
id: "fr-4",
time: "16:00 17:30 Uhr",
image: { src: spk4, alt: "Dr. Elena Rossi" },
title: "Deep Dive: Psychological UX",
subtitle: "Wie unser Gehirn auf Interfaces reagiert",
speaker: "Dr. Elena Rossi",
speakerSlug: "dr-elena-rossi",
type: "Talk",
level: "Senior",
day: "Freitag",
speakerUrl: "/speaker/dr-elena-rossi",
description:
"Elena verbindet Wissenschaft mit Design und erklärt, wie unser Gehirn auf Micro-Interactions reagiert. Wann fühlen wir uns von einem Interface gut geführt und wann manipuliert? Ein wissenschaftlich fundierter Blick auf die Psychologie hinter UX-Entscheidungen.",
},
{
id: "fr-5",
time: "18:00 19:30 Uhr",
image: { src: spk1, alt: "Liam O'Connor" },
title: "Talk: Trust in AI",
subtitle: "Wie wir Vertrauen in algorithmische Systeme aufbauen",
speaker: "Liam O'Connor",
speakerSlug: "liam-oconnor",
type: "Talk",
level: "Mid-Level",
day: "Freitag",
speakerUrl: "/speaker/liam-oconnor",
description:
"Vertrauen ist die Währung der Zukunft. Liam erklärt, wie Spotify transparente und ethische KI-Systeme gestaltet, die Nutzer verstehen und akzeptieren können.",
},
{
id: "fr-6",
time: "20:00 21:30 Uhr",
image: { src: spk2, alt: "Fabienne Keller" },
title: "Workshop: Research Repositories",
subtitle: "Wissen organisieren, das wirklich genutzt wird",
speaker: "Fabienne Keller",
speakerSlug: "fabienne-keller",
type: "Workshop",
level: "Senior",
day: "Freitag",
speakerUrl: "/speaker/fabienne-keller",
description:
"Fabienne zeigt, wie du ein Research Repository aufbaust, das nicht im Regal verstaubt. Praktische Methoden für die Organisation, Pflege und Aktivierung von Research-Wissen in deinem Team.",
},
];

View File

@ -3,30 +3,9 @@ import { Navbar3 } from "../components/Navbar";
import { Header23 } from "../components/Header23"; import { Header23 } from "../components/Header23";
import { Filters5 } from "../components/Filters5"; import { Filters5 } from "../components/Filters5";
import { Event33 } from "../components/Event33"; import { Event33 } from "../components/Event33";
import type { ProgramEvent } from "../components/Event33";
import { Banner15 } from "../components/Banner15"; import { Banner15 } from "../components/Banner15";
import { Footer3 } from "../components/Footer"; import { Footer3 } from "../components/Footer";
import { ALL_EVENTS } from "../data/events";
import spk1 from "../assets/speakers/speaker1.jpg";
import spk2 from "../assets/speakers/speaker2.jpg";
import spk3 from "../assets/speakers/speaker3.jpg";
import spk4 from "../assets/speakers/speaker4.jpg";
const ALL_EVENTS: ProgramEvent[] = [
// Donnerstag
{ id: "do-1", time: "10:00 11:30 Uhr", image: { src: spk1, alt: "Jens Riegelsberger" }, title: "Opening Keynote: The Future of UX", speaker: "Jens Riegelsberger", type: "Talk", level: "Senior", day: "Donnerstag", speakerUrl: "/speaker" },
{ id: "do-2", time: "12:00 13:00 Uhr", image: { src: spk2, alt: "Marcus J. Low" }, title: "Workshop: Design Systems at Scale", speaker: "Marcus J. Low", type: "Workshop", level: "Mid-Level", day: "Donnerstag", speakerUrl: "/speaker" },
{ id: "do-3", time: "14:00 15:30 Uhr", image: { src: spk3, alt: "Reto Gwerder" }, title: "Interaction: Prototyping Fast", speaker: "Reto Gwerder", type: "Interaction", level: "Junior", day: "Donnerstag", speakerUrl: "/speaker" },
{ id: "do-4", time: "16:00 17:30 Uhr", image: { src: spk4, alt: "Dr. Elena Rossi" }, title: "AI and Future: Intelligence in Design", speaker: "Dr. Elena Rossi", type: "AI and Future", level: "Senior", day: "Donnerstag", speakerUrl: "/speaker" },
{ id: "do-5", time: "18:00 19:30 Uhr", image: { src: spk1, alt: "Liam O'Connor" }, title: "Talk: Ethical AI", speaker: "Liam O'Connor", type: "Talk", level: "Mid-Level", day: "Donnerstag", speakerUrl: "/speaker" },
// Freitag
{ id: "fr-1", time: "12:00 13:30 Uhr", image: { src: spk1, alt: "Jens Riegelsberger" }, title: "Scaling Research", speaker: "Jens Riegelsberger", type: "Talk", level: "Senior", day: "Freitag", speakerUrl: "/speaker" },
{ id: "fr-2", time: "12:00 13:00 Uhr", image: { src: spk2, alt: "Marcus J. Low" }, title: "Workshop: The Future of Tokens", speaker: "Marcus J. Low", type: "Workshop", level: "Mid-Level", day: "Freitag", speakerUrl: "/speaker" },
{ id: "fr-3", time: "14:00 15:30 Uhr", image: { src: spk3, alt: "Reto Gwerder" }, title: "Talk: Simplify or Die", speaker: "Reto Gwerder", type: "Talk", level: "Junior", day: "Freitag", speakerUrl: "/speaker" },
{ id: "fr-4", time: "16:00 17:30 Uhr", image: { src: spk4, alt: "Dr. Elena Rossi" }, title: "Deep Dive: Psychological UX", speaker: "Dr. Elena Rossi", type: "Talk", level: "Senior", day: "Freitag", speakerUrl: "/speaker" },
{ id: "fr-5", time: "18:00 19:30 Uhr", image: { src: spk1, alt: "Liam O'Connor" }, title: "Talk: Trust in AI", speaker: "Liam O'Connor", type: "Talk", level: "Mid-Level", day: "Freitag", speakerUrl: "/speaker" },
{ id: "fr-6", time: "20:00 21:30 Uhr", image: { src: spk2, alt: "Fabienne Keller" }, title: "Workshop: Research Repositories", speaker: "Fabienne Keller", type: "Workshop", level: "Senior", day: "Freitag", speakerUrl: "/speaker" },
];
const TYPE_TABS = ["Talk", "Workshop", "Interaction", "AI and Future"]; const TYPE_TABS = ["Talk", "Workshop", "Interaction", "AI and Future"];
const LEVEL_TABS: Record<string, string> = { const LEVEL_TABS: Record<string, string> = {

View File

@ -0,0 +1,149 @@
import { useParams, Navigate, Link } from "react-router-dom";
import { Navbar3 } from "../components/Navbar";
import { Cta30 } from "../components/Cta30";
import { Footer3 } from "../components/Footer";
import { Team4Defaults } from "../components/Team4";
import { ALL_EVENTS } from "../data/events";
import { BiCalendarAlt, BiMap, BiUser } from "react-icons/bi";
import { RxCube } from "react-icons/rx";
const SponsorsSection = () => (
<section className="bg-tech-navy px-[5%] py-16 md:py-24 font-barlow">
<div className="container">
<h2 className="mb-12 text-center text-4xl font-bold text-cloud-white md:text-5xl">
Unsere Sponsoren & Partner
</h2>
<div className="grid grid-cols-3 gap-6 md:grid-cols-5">
{Array(15).fill(null).map((_, i) => (
<div
key={i}
className="flex items-center justify-center rounded-lg border border-white/10 bg-white/5 px-4 py-6"
>
<span className="text-sm font-semibold text-white/50">
{i % 2 === 0 ? "Webflow" : "Relume"}
</span>
</div>
))}
</div>
</div>
</section>
);
const ProgrammDetail = () => {
const { id } = useParams<{ id: string }>();
const event = ALL_EVENTS.find((e) => e.id === id);
if (!event) return <Navigate to="/programm" replace />;
const speaker = Team4Defaults.teamMembers.find((m) => m.slug === event.speakerSlug);
const dateLabel = event.day === "Donnerstag"
? "Donnerstag, 7. Mai 2026"
: "Freitag, 8. Mai 2026";
return (
<div>
<Navbar3 />
{/* Hero section */}
<section className="bg-tech-navy px-[5%] py-16 md:py-24 font-barlow">
<div className="container">
<div className="grid grid-cols-1 items-center gap-12 lg:grid-cols-2 lg:gap-20">
{/* Left: event info */}
<div>
<span className="mb-4 inline-block rounded-full border border-electric-violet px-3 py-1 text-xs font-semibold text-electric-violet">
{event.type}
</span>
<h1 className="mb-4 text-5xl font-bold text-cloud-white md:text-6xl lg:text-7xl">
{event.title}
</h1>
{event.subtitle && (
<p className="mb-8 text-lg text-cloud-white/70">{event.subtitle}</p>
)}
<div className="mb-8 flex flex-col gap-3">
<div className="flex items-center gap-3 text-cloud-white/80">
<BiCalendarAlt className="size-5 shrink-0 text-acid-lime" />
<span className="text-sm">{dateLabel}, {event.time}</span>
</div>
<div className="flex items-center gap-3 text-cloud-white/80">
<BiMap className="size-5 shrink-0 text-acid-lime" />
<span className="text-sm">Location</span>
</div>
<div className="flex items-center gap-3 text-cloud-white/80">
<BiUser className="size-5 shrink-0 text-acid-lime" />
<span className="text-sm">{event.speaker}</span>
</div>
</div>
<Link
to="/tickets"
className="inline-block rounded-2xl bg-acid-lime px-8 py-3 text-base font-bold text-tech-navy hover:opacity-90 transition-opacity"
>
Ticket kaufen
</Link>
</div>
{/* Right: speaker image */}
<div className="aspect-square w-full max-w-md overflow-hidden lg:ml-auto">
<img
src={event.image.src}
alt={event.image.alt}
className="size-full object-cover object-top"
/>
</div>
</div>
</div>
</section>
{/* Speaker bio + event description */}
<section className="bg-tech-navy px-[5%] pb-16 md:pb-24 font-barlow">
<div className="container border-t border-white/10 pt-16">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-2 lg:gap-20">
{/* Left: über den speaker */}
<div>
<RxCube className="mb-4 size-8 text-electric-violet" />
<h2 className="mb-6 text-2xl font-bold text-cloud-white md:text-3xl">
Über den Speaker
</h2>
{speaker ? (
<>
<p className="mb-1 text-lg font-bold text-cloud-white">{speaker.name}</p>
<p className="mb-1 text-sm text-cloud-white/60">{speaker.role}</p>
<p className="mb-6 text-sm text-cloud-white/60">{speaker.company}</p>
<Link
to={`/speaker/${speaker.slug}`}
className="inline-block rounded-2xl border border-acid-lime px-6 py-2.5 text-sm font-semibold text-acid-lime hover:bg-acid-lime hover:text-tech-navy transition-colors"
>
Speaker Details
</Link>
</>
) : (
<p className="text-cloud-white/60">{event.speaker}</p>
)}
</div>
{/* Right: das erwartete dich */}
<div>
<RxCube className="mb-4 size-8 text-electric-violet" />
<h2 className="mb-6 text-2xl font-bold text-cloud-white md:text-3xl">
Das erwartete dich
</h2>
<p className="text-base leading-relaxed text-cloud-white/80">
{event.description ?? "Weitere Informationen folgen in Kürze."}
</p>
</div>
</div>
</div>
</section>
{/* Stay tuned */}
<Cta30 />
{/* Sponsors */}
<SponsorsSection />
<Footer3 />
</div>
);
};
export default ProgrammDetail;

View File

@ -0,0 +1,111 @@
import { useParams, Navigate } from "react-router-dom";
import { Navbar3 } from "../components/Navbar";
import { Team4, Team4Defaults } from "../components/Team4";
import { Footer3 } from "../components/Footer";
import { BiLogoLinkedinSquare, BiGlobe } from "react-icons/bi";
import { FaXTwitter } from "react-icons/fa6";
const ALL_SPEAKERS = Team4Defaults.teamMembers;
const SponsorsSection = () => (
<section className="bg-tech-navy px-[5%] py-16 md:py-24 font-barlow">
<div className="container">
<h2 className="mb-12 text-center text-4xl font-bold text-cloud-white md:text-5xl">
Unsere Sponsoren & Partner
</h2>
<div className="grid grid-cols-3 gap-6 md:grid-cols-5">
{Array(15).fill(null).map((_, i) => (
<div
key={i}
className="flex items-center justify-center rounded-lg border border-white/10 bg-white/5 px-4 py-6"
>
<span className="text-sm font-semibold text-white/50">
{i % 2 === 0 ? "Webflow" : "Relume"}
</span>
</div>
))}
</div>
</div>
</section>
);
const SpeakerDetail = () => {
const { slug } = useParams<{ slug: string }>();
const speaker = ALL_SPEAKERS.find((s) => s.slug === slug);
if (!speaker) return <Navigate to="/speaker" replace />;
const otherSpeakers = ALL_SPEAKERS.filter((s) => s.slug !== slug);
return (
<div>
<Navbar3 />
{/* Hero image */}
<div className="w-full aspect-[16/7] overflow-hidden">
<img
src={speaker.image.src}
alt={speaker.image.alt}
className="size-full object-cover object-top"
/>
</div>
{/* Speaker info */}
<section className="bg-tech-navy px-[5%] py-16 md:py-24 font-barlow">
<div className="container">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-2 lg:gap-20">
{/* Left: badge, name, location */}
<div>
<span className="mb-6 inline-block rounded-full bg-acid-lime px-4 py-1.5 text-sm font-bold text-tech-navy">
{speaker.category}
</span>
<h1 className="mb-4 text-5xl font-bold text-cloud-white md:text-7xl">
{speaker.name}
</h1>
{speaker.location && (
<p className="text-base text-cloud-white/60">{speaker.location}</p>
)}
</div>
{/* Right: bio + social */}
<div className="flex flex-col justify-center gap-6">
<p className="text-base leading-relaxed text-cloud-white/80 md:text-lg">
{speaker.fullBio ?? speaker.description}
</p>
<div className="flex gap-4">
{speaker.socialLinks.map((link, i) => (
<a
key={i}
href={link.href}
className="text-cloud-white/60 hover:text-acid-lime transition-colors"
>
{link.icon}
</a>
))}
<a href="#" className="text-cloud-white/60 hover:text-acid-lime transition-colors">
<FaXTwitter className="size-6 p-0.5" />
</a>
<a href="#" className="text-cloud-white/60 hover:text-acid-lime transition-colors">
<BiGlobe className="size-6" />
</a>
</div>
</div>
</div>
</div>
</section>
{/* Other speakers */}
<section className="bg-cloud-white px-[5%] pt-16 font-barlow">
<div className="container mb-10">
<h2 className="text-3xl font-bold text-tech-navy md:text-4xl">Weitere Speaker</h2>
</div>
</section>
<Team4 teamMembers={otherSpeakers} />
<SponsorsSection />
<Footer3 />
</div>
);
};
export default SpeakerDetail;