feat: add homepage selector

This commit is contained in:
2026-03-29 16:28:12 +02:00
parent 845624dfd3
commit 56942275b8
4 changed files with 357 additions and 18 deletions

View File

@@ -23,7 +23,7 @@ export function Header({
const handleSignOut = async () => {
await authClient.signOut();
navigate({ to: "/" });
navigate({ to: "/open-mic" });
};
return (
@@ -35,7 +35,7 @@ export function Header({
<div className="mx-auto flex max-w-8xl items-center justify-between px-3 py-2 sm:px-6 sm:py-3">
<nav className="flex items-center gap-3 sm:gap-6">
<Link
to="/"
to="/open-mic"
className="font-['Intro',sans-serif] text-base text-white/80 transition-opacity hover:opacity-100 sm:text-lg"
>
Kunstenkamp

View File

@@ -12,6 +12,7 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as TermsRouteImport } from './routes/terms'
import { Route as ResetPasswordRouteImport } from './routes/reset-password'
import { Route as PrivacyRouteImport } from './routes/privacy'
import { Route as OpenMicRouteImport } from './routes/open-mic'
import { Route as LoginRouteImport } from './routes/login'
import { Route as ForgotPasswordRouteImport } from './routes/forgot-password'
import { Route as DrinkkaartRouteImport } from './routes/drinkkaart'
@@ -41,6 +42,11 @@ const PrivacyRoute = PrivacyRouteImport.update({
path: '/privacy',
getParentRoute: () => rootRouteImport,
} as any)
const OpenMicRoute = OpenMicRouteImport.update({
id: '/open-mic',
path: '/open-mic',
getParentRoute: () => rootRouteImport,
} as any)
const LoginRoute = LoginRouteImport.update({
id: '/login',
path: '/login',
@@ -114,6 +120,7 @@ export interface FileRoutesByFullPath {
'/drinkkaart': typeof DrinkkaartRoute
'/forgot-password': typeof ForgotPasswordRoute
'/login': typeof LoginRoute
'/open-mic': typeof OpenMicRoute
'/privacy': typeof PrivacyRoute
'/reset-password': typeof ResetPasswordRoute
'/terms': typeof TermsRoute
@@ -132,6 +139,7 @@ export interface FileRoutesByTo {
'/drinkkaart': typeof DrinkkaartRoute
'/forgot-password': typeof ForgotPasswordRoute
'/login': typeof LoginRoute
'/open-mic': typeof OpenMicRoute
'/privacy': typeof PrivacyRoute
'/reset-password': typeof ResetPasswordRoute
'/terms': typeof TermsRoute
@@ -151,6 +159,7 @@ export interface FileRoutesById {
'/drinkkaart': typeof DrinkkaartRoute
'/forgot-password': typeof ForgotPasswordRoute
'/login': typeof LoginRoute
'/open-mic': typeof OpenMicRoute
'/privacy': typeof PrivacyRoute
'/reset-password': typeof ResetPasswordRoute
'/terms': typeof TermsRoute
@@ -171,6 +180,7 @@ export interface FileRouteTypes {
| '/drinkkaart'
| '/forgot-password'
| '/login'
| '/open-mic'
| '/privacy'
| '/reset-password'
| '/terms'
@@ -189,6 +199,7 @@ export interface FileRouteTypes {
| '/drinkkaart'
| '/forgot-password'
| '/login'
| '/open-mic'
| '/privacy'
| '/reset-password'
| '/terms'
@@ -207,6 +218,7 @@ export interface FileRouteTypes {
| '/drinkkaart'
| '/forgot-password'
| '/login'
| '/open-mic'
| '/privacy'
| '/reset-password'
| '/terms'
@@ -226,6 +238,7 @@ export interface RootRouteChildren {
DrinkkaartRoute: typeof DrinkkaartRoute
ForgotPasswordRoute: typeof ForgotPasswordRoute
LoginRoute: typeof LoginRoute
OpenMicRoute: typeof OpenMicRoute
PrivacyRoute: typeof PrivacyRoute
ResetPasswordRoute: typeof ResetPasswordRoute
TermsRoute: typeof TermsRoute
@@ -261,6 +274,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PrivacyRouteImport
parentRoute: typeof rootRouteImport
}
'/open-mic': {
id: '/open-mic'
path: '/open-mic'
fullPath: '/open-mic'
preLoaderRoute: typeof OpenMicRouteImport
parentRoute: typeof rootRouteImport
}
'/login': {
id: '/login'
path: '/login'
@@ -362,6 +382,7 @@ const rootRouteChildren: RootRouteChildren = {
DrinkkaartRoute: DrinkkaartRoute,
ForgotPasswordRoute: ForgotPasswordRoute,
LoginRoute: LoginRoute,
OpenMicRoute: OpenMicRoute,
PrivacyRoute: PrivacyRoute,
ResetPasswordRoute: ResetPasswordRoute,
TermsRoute: TermsRoute,

View File

@@ -1,24 +1,318 @@
import { createFileRoute } from "@tanstack/react-router";
import EventRegistrationForm from "@/components/homepage/EventRegistrationForm";
import Footer from "@/components/homepage/Footer";
import Hero from "@/components/homepage/Hero";
import HoeInschrijven from "@/components/homepage/HoeInschrijven";
import Info from "@/components/homepage/Info";
import { createFileRoute, Link } from "@tanstack/react-router";
import { useEffect, useState } from "react";
export const Route = createFileRoute("/")({
component: HomePage,
component: SelectorPage,
});
function HomePage() {
function SelectorPage() {
const [hovered, setHovered] = useState<"kamp" | "openmic" | null>(null);
const [mounted, setMounted] = useState(false);
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const check = () => setIsMobile(window.innerWidth < 640);
check();
window.addEventListener("resize", check, { passive: true });
return () => window.removeEventListener("resize", check);
}, []);
useEffect(() => {
const t = setTimeout(() => setMounted(true), 60);
return () => clearTimeout(t);
}, []);
return (
<div className="relative">
<main className="relative">
<Hero />
<Info />
<HoeInschrijven />
<EventRegistrationForm />
<Footer />
</main>
<div
className="flex h-[100dvh] w-full flex-col sm:flex-row"
style={{ gap: "6px", background: "#0a0a0a" }}
>
{/* ── Kamp Inschrijvingen ───────────────────────────────────────── */}
<a
href="https://ejv.be/jong/kampen/kunstenkamp/"
target="_blank"
rel="noopener noreferrer"
className="group relative flex min-h-0 flex-col overflow-hidden"
style={{
flex: isMobile
? "1 1 50%"
: hovered === "openmic"
? "0 0 30%"
: hovered === "kamp"
? "0 0 70%"
: "1 1 50%",
transition: "flex 0.65s cubic-bezier(0.76, 0, 0.24, 1)",
background: "#214e51",
textDecoration: "none",
}}
onMouseEnter={() => setHovered("kamp")}
onMouseLeave={() => setHovered(null)}
aria-label="Ga naar de kamp inschrijvingen op ejv.be"
>
{/* Diagonal stripe texture */}
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0"
style={{
backgroundImage:
"repeating-linear-gradient(135deg, rgba(255,255,255,0.03) 0px, rgba(255,255,255,0.03) 1px, transparent 1px, transparent 28px)",
}}
/>
{/* Mustard accent bar */}
<div
aria-hidden="true"
className="absolute top-0 left-0 w-[3px]"
style={{
background: "#d09035",
height: hovered === "kamp" ? "100%" : "0%",
transition: "height 0.65s cubic-bezier(0.76, 0, 0.24, 1)",
}}
/>
{/* Content — constrained width, centered */}
<div className="relative z-10 my-auto w-full px-6 py-8 sm:px-10 sm:py-12">
<div className="w-full max-w-sm">
{/* Top eyebrow */}
<p
className="mb-3 font-['DM_Sans',sans-serif] text-[10px] uppercase tracking-[0.25em] sm:mb-4"
style={{
color: "#d09035",
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(-8px)",
transition: "opacity 0.7s ease 0.1s, transform 0.7s ease 0.1s",
}}
>
Kunstenkamp
</p>
<h2
className="font-['Intro',sans-serif] text-white uppercase leading-[0.88]"
style={{
fontSize: "clamp(1.6rem, 3.5vw, 2.8rem)",
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(16px)",
transition: "opacity 0.8s ease 0.2s, transform 0.8s ease 0.2s",
}}
>
<span className="block whitespace-nowrap">Kamp</span>
<span className="block whitespace-nowrap">Inschrijvingen</span>
</h2>
{/* Details */}
<div
className="mt-4 grid grid-cols-2 gap-x-6 gap-y-3 sm:mt-5 sm:gap-y-3"
style={{
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(8px)",
transition: "opacity 0.5s ease 0.3s, transform 0.5s ease 0.3s",
}}
>
<div>
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/40 uppercase tracking-[0.2em]">
Leeftijd
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/80 text-xs leading-snug sm:text-sm">
9<sup>*</sup>18 jaar
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-[9px] text-white/35 italic">
* geboortejaar dat je 10 wordt
</p>
</div>
<div>
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/40 uppercase tracking-[0.2em]">
Data
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/80 text-xs leading-snug sm:text-sm">
20/0725/07/2026
<br />
27/0701/08/2026
</p>
</div>
<div className="col-span-2">
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/40 uppercase tracking-[0.2em]">
Locatie
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/80 text-xs leading-snug sm:text-sm">
Camp de Limauges · Chemin de Bigaumont 2 · 1341 Ceroux-Mousty
</p>
</div>
</div>
{/* CTA */}
<div
className="mt-5 flex items-center gap-3 sm:mt-6"
style={{
opacity: mounted ? 1 : 0,
transition: "opacity 0.8s ease 0.3s",
}}
>
<div
style={{
height: "1px",
background: "#d09035",
width: hovered === "kamp" ? "72px" : "32px",
transition: "width 0.5s cubic-bezier(0.76, 0, 0.24, 1)",
}}
/>
<span
className="font-['DM_Sans',sans-serif] text-[10px] uppercase tracking-[0.2em]"
style={{ color: "#d09035" }}
>
Ga verder
</span>
</div>
</div>
</div>
{/* Corner decoration */}
<div
aria-hidden="true"
className="pointer-events-none absolute right-0 bottom-0"
style={{
width: "clamp(60px, 15%, 140px)",
height: "clamp(60px, 15%, 140px)",
borderTop: "1px solid rgba(208,144,53,0.12)",
borderLeft: "1px solid rgba(208,144,53,0.12)",
transform: "translate(50%, 50%)",
}}
/>
</a>
{/* ── Open Mic Night ────────────────────────────────────────────── */}
<Link
to="/open-mic"
className="group relative flex min-h-0 flex-col overflow-hidden"
style={{
flex: isMobile
? "1 1 50%"
: hovered === "kamp"
? "0 0 30%"
: hovered === "openmic"
? "0 0 70%"
: "1 1 50%",
transition: "flex 0.65s cubic-bezier(0.76, 0, 0.24, 1)",
background: "#d82560",
textDecoration: "none",
}}
onMouseEnter={() => setHovered("openmic")}
onMouseLeave={() => setHovered(null)}
aria-label="Ga naar de Open Mic Night inschrijvingen"
>
{/* Diagonal stripe texture */}
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0"
style={{
backgroundImage:
"repeating-linear-gradient(135deg, rgba(255,255,255,0.05) 0px, rgba(255,255,255,0.05) 1px, transparent 1px, transparent 28px)",
}}
/>
{/* White accent bar */}
<div
aria-hidden="true"
className="absolute top-0 right-0 w-[3px]"
style={{
background: "rgba(255,255,255,0.7)",
height: hovered === "openmic" ? "100%" : "0%",
transition: "height 0.65s cubic-bezier(0.76, 0, 0.24, 1)",
}}
/>
{/* Content — constrained width, centered */}
<div className="relative z-10 my-auto w-full px-6 py-8 sm:px-10 sm:py-12">
<div className="w-full max-w-sm">
{/* Top eyebrow */}
<p
className="mb-3 font-['DM_Sans',sans-serif] text-[10px] text-white/50 uppercase tracking-[0.25em] sm:mb-4"
style={{
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(-8px)",
transition:
"opacity 0.7s ease 0.15s, transform 0.7s ease 0.15s",
}}
>
Ongedesemd Woord
</p>
<h2
className="font-['Intro',sans-serif] text-white uppercase leading-[0.88]"
style={{
fontSize: "clamp(1.6rem, 3.5vw, 2.8rem)",
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(16px)",
transition:
"opacity 0.8s ease 0.25s, transform 0.8s ease 0.25s",
}}
>
<span className="block whitespace-nowrap">Open</span>
<span className="block whitespace-nowrap">Mic Night</span>
</h2>
{/* Details */}
<div
className="mt-4 grid grid-cols-2 gap-x-6 gap-y-3 sm:mt-5"
style={{
opacity: mounted ? 1 : 0,
transform: mounted ? "translateY(0)" : "translateY(8px)",
transition:
"opacity 0.5s ease 0.35s, transform 0.5s ease 0.35s",
}}
>
<div>
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/50 uppercase tracking-[0.2em]">
Datum
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/90 text-xs leading-snug sm:text-sm">
Vrijdag 24 april 2026
<br />
19u30
</p>
</div>
<div>
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/50 uppercase tracking-[0.2em]">
Optreden
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/90 text-xs leading-snug sm:text-sm">
5 min podiumtijd
<br />
Alle kunstvormen
</p>
</div>
<div className="col-span-2">
<p className="font-['DM_Sans',sans-serif] text-[9px] text-white/50 uppercase tracking-[0.2em]">
Locatie
</p>
<p className="mt-0.5 font-['DM_Sans',sans-serif] text-white/90 text-xs leading-snug sm:text-sm">
Lange Winkelstraat 5 · 2000 Antwerpen
</p>
</div>
</div>
{/* CTA */}
<div
className="mt-5 flex items-center gap-3 sm:mt-6"
style={{
opacity: mounted ? 1 : 0,
transition: "opacity 0.8s ease 0.35s",
}}
>
<div
style={{
height: "1px",
background: "rgba(255,255,255,0.7)",
width: hovered === "openmic" ? "72px" : "32px",
transition: "width 0.5s cubic-bezier(0.76, 0, 0.24, 1)",
}}
/>
<span className="font-['DM_Sans',sans-serif] text-[10px] text-white/80 uppercase tracking-[0.2em]">
Ga verder
</span>
</div>
</div>
</div>
</Link>
</div>
);
}

View File

@@ -0,0 +1,24 @@
import { createFileRoute } from "@tanstack/react-router";
import EventRegistrationForm from "@/components/homepage/EventRegistrationForm";
import Footer from "@/components/homepage/Footer";
import Hero from "@/components/homepage/Hero";
import HoeInschrijven from "@/components/homepage/HoeInschrijven";
import Info from "@/components/homepage/Info";
export const Route = createFileRoute("/open-mic")({
component: OpenMicPage,
});
function OpenMicPage() {
return (
<div className="relative">
<main className="relative">
<Hero />
<Info />
<HoeInschrijven />
<EventRegistrationForm />
<Footer />
</main>
</div>
);
}