feat: add homepage selector
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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/07–25/07/2026
|
||||
<br />
|
||||
27/07–01/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>
|
||||
);
|
||||
}
|
||||
|
||||
24
apps/web/src/routes/open-mic.tsx
Normal file
24
apps/web/src/routes/open-mic.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user